xref: /OK3568_Linux_fs/kernel/arch/powerpc/xmon/xmon.c (revision 4882a59341e53eb6f0b4789bf948001014eff981)
1*4882a593Smuzhiyun // SPDX-License-Identifier: GPL-2.0-or-later
2*4882a593Smuzhiyun /*
3*4882a593Smuzhiyun  * Routines providing a simple monitor for use on the PowerMac.
4*4882a593Smuzhiyun  *
5*4882a593Smuzhiyun  * Copyright (C) 1996-2005 Paul Mackerras.
6*4882a593Smuzhiyun  * Copyright (C) 2001 PPC64 Team, IBM Corp
7*4882a593Smuzhiyun  * Copyrignt (C) 2006 Michael Ellerman, IBM Corp
8*4882a593Smuzhiyun  */
9*4882a593Smuzhiyun 
10*4882a593Smuzhiyun #include <linux/kernel.h>
11*4882a593Smuzhiyun #include <linux/errno.h>
12*4882a593Smuzhiyun #include <linux/sched/signal.h>
13*4882a593Smuzhiyun #include <linux/smp.h>
14*4882a593Smuzhiyun #include <linux/mm.h>
15*4882a593Smuzhiyun #include <linux/reboot.h>
16*4882a593Smuzhiyun #include <linux/delay.h>
17*4882a593Smuzhiyun #include <linux/kallsyms.h>
18*4882a593Smuzhiyun #include <linux/kmsg_dump.h>
19*4882a593Smuzhiyun #include <linux/cpumask.h>
20*4882a593Smuzhiyun #include <linux/export.h>
21*4882a593Smuzhiyun #include <linux/sysrq.h>
22*4882a593Smuzhiyun #include <linux/interrupt.h>
23*4882a593Smuzhiyun #include <linux/irq.h>
24*4882a593Smuzhiyun #include <linux/bug.h>
25*4882a593Smuzhiyun #include <linux/nmi.h>
26*4882a593Smuzhiyun #include <linux/ctype.h>
27*4882a593Smuzhiyun #include <linux/highmem.h>
28*4882a593Smuzhiyun #include <linux/security.h>
29*4882a593Smuzhiyun 
30*4882a593Smuzhiyun #include <asm/debugfs.h>
31*4882a593Smuzhiyun #include <asm/ptrace.h>
32*4882a593Smuzhiyun #include <asm/smp.h>
33*4882a593Smuzhiyun #include <asm/string.h>
34*4882a593Smuzhiyun #include <asm/prom.h>
35*4882a593Smuzhiyun #include <asm/machdep.h>
36*4882a593Smuzhiyun #include <asm/xmon.h>
37*4882a593Smuzhiyun #include <asm/processor.h>
38*4882a593Smuzhiyun #include <asm/mmu.h>
39*4882a593Smuzhiyun #include <asm/mmu_context.h>
40*4882a593Smuzhiyun #include <asm/plpar_wrappers.h>
41*4882a593Smuzhiyun #include <asm/cputable.h>
42*4882a593Smuzhiyun #include <asm/rtas.h>
43*4882a593Smuzhiyun #include <asm/sstep.h>
44*4882a593Smuzhiyun #include <asm/irq_regs.h>
45*4882a593Smuzhiyun #include <asm/spu.h>
46*4882a593Smuzhiyun #include <asm/spu_priv1.h>
47*4882a593Smuzhiyun #include <asm/setjmp.h>
48*4882a593Smuzhiyun #include <asm/reg.h>
49*4882a593Smuzhiyun #include <asm/debug.h>
50*4882a593Smuzhiyun #include <asm/hw_breakpoint.h>
51*4882a593Smuzhiyun #include <asm/xive.h>
52*4882a593Smuzhiyun #include <asm/opal.h>
53*4882a593Smuzhiyun #include <asm/firmware.h>
54*4882a593Smuzhiyun #include <asm/code-patching.h>
55*4882a593Smuzhiyun #include <asm/sections.h>
56*4882a593Smuzhiyun #include <asm/inst.h>
57*4882a593Smuzhiyun 
58*4882a593Smuzhiyun #ifdef CONFIG_PPC64
59*4882a593Smuzhiyun #include <asm/hvcall.h>
60*4882a593Smuzhiyun #include <asm/paca.h>
61*4882a593Smuzhiyun #endif
62*4882a593Smuzhiyun 
63*4882a593Smuzhiyun #include "nonstdio.h"
64*4882a593Smuzhiyun #include "dis-asm.h"
65*4882a593Smuzhiyun #include "xmon_bpts.h"
66*4882a593Smuzhiyun 
67*4882a593Smuzhiyun #ifdef CONFIG_SMP
68*4882a593Smuzhiyun static cpumask_t cpus_in_xmon = CPU_MASK_NONE;
69*4882a593Smuzhiyun static unsigned long xmon_taken = 1;
70*4882a593Smuzhiyun static int xmon_owner;
71*4882a593Smuzhiyun static int xmon_gate;
72*4882a593Smuzhiyun #else
73*4882a593Smuzhiyun #define xmon_owner 0
74*4882a593Smuzhiyun #endif /* CONFIG_SMP */
75*4882a593Smuzhiyun 
76*4882a593Smuzhiyun #ifdef CONFIG_PPC_PSERIES
77*4882a593Smuzhiyun static int set_indicator_token = RTAS_UNKNOWN_SERVICE;
78*4882a593Smuzhiyun #endif
79*4882a593Smuzhiyun static unsigned long in_xmon __read_mostly = 0;
80*4882a593Smuzhiyun static int xmon_on = IS_ENABLED(CONFIG_XMON_DEFAULT);
81*4882a593Smuzhiyun static bool xmon_is_ro = IS_ENABLED(CONFIG_XMON_DEFAULT_RO_MODE);
82*4882a593Smuzhiyun 
83*4882a593Smuzhiyun static unsigned long adrs;
84*4882a593Smuzhiyun static int size = 1;
85*4882a593Smuzhiyun #define MAX_DUMP (64 * 1024)
86*4882a593Smuzhiyun static unsigned long ndump = 64;
87*4882a593Smuzhiyun #define MAX_IDUMP (MAX_DUMP >> 2)
88*4882a593Smuzhiyun static unsigned long nidump = 16;
89*4882a593Smuzhiyun static unsigned long ncsum = 4096;
90*4882a593Smuzhiyun static int termch;
91*4882a593Smuzhiyun static char tmpstr[128];
92*4882a593Smuzhiyun static int tracing_enabled;
93*4882a593Smuzhiyun 
94*4882a593Smuzhiyun static long bus_error_jmp[JMP_BUF_LEN];
95*4882a593Smuzhiyun static int catch_memory_errors;
96*4882a593Smuzhiyun static int catch_spr_faults;
97*4882a593Smuzhiyun static long *xmon_fault_jmp[NR_CPUS];
98*4882a593Smuzhiyun 
99*4882a593Smuzhiyun /* Breakpoint stuff */
100*4882a593Smuzhiyun struct bpt {
101*4882a593Smuzhiyun 	unsigned long	address;
102*4882a593Smuzhiyun 	struct ppc_inst	*instr;
103*4882a593Smuzhiyun 	atomic_t	ref_count;
104*4882a593Smuzhiyun 	int		enabled;
105*4882a593Smuzhiyun 	unsigned long	pad;
106*4882a593Smuzhiyun };
107*4882a593Smuzhiyun 
108*4882a593Smuzhiyun /* Bits in bpt.enabled */
109*4882a593Smuzhiyun #define BP_CIABR	1
110*4882a593Smuzhiyun #define BP_TRAP		2
111*4882a593Smuzhiyun #define BP_DABR		4
112*4882a593Smuzhiyun 
113*4882a593Smuzhiyun static struct bpt bpts[NBPTS];
114*4882a593Smuzhiyun static struct bpt dabr[HBP_NUM_MAX];
115*4882a593Smuzhiyun static struct bpt *iabr;
116*4882a593Smuzhiyun static unsigned bpinstr = 0x7fe00008;	/* trap */
117*4882a593Smuzhiyun 
118*4882a593Smuzhiyun #define BP_NUM(bp)	((bp) - bpts + 1)
119*4882a593Smuzhiyun 
120*4882a593Smuzhiyun /* Prototypes */
121*4882a593Smuzhiyun static int cmds(struct pt_regs *);
122*4882a593Smuzhiyun static int mread(unsigned long, void *, int);
123*4882a593Smuzhiyun static int mwrite(unsigned long, void *, int);
124*4882a593Smuzhiyun static int mread_instr(unsigned long, struct ppc_inst *);
125*4882a593Smuzhiyun static int handle_fault(struct pt_regs *);
126*4882a593Smuzhiyun static void byterev(unsigned char *, int);
127*4882a593Smuzhiyun static void memex(void);
128*4882a593Smuzhiyun static int bsesc(void);
129*4882a593Smuzhiyun static void dump(void);
130*4882a593Smuzhiyun static void show_pte(unsigned long);
131*4882a593Smuzhiyun static void prdump(unsigned long, long);
132*4882a593Smuzhiyun static int ppc_inst_dump(unsigned long, long, int);
133*4882a593Smuzhiyun static void dump_log_buf(void);
134*4882a593Smuzhiyun 
135*4882a593Smuzhiyun #ifdef CONFIG_PPC_POWERNV
136*4882a593Smuzhiyun static void dump_opal_msglog(void);
137*4882a593Smuzhiyun #else
dump_opal_msglog(void)138*4882a593Smuzhiyun static inline void dump_opal_msglog(void)
139*4882a593Smuzhiyun {
140*4882a593Smuzhiyun 	printf("Machine is not running OPAL firmware.\n");
141*4882a593Smuzhiyun }
142*4882a593Smuzhiyun #endif
143*4882a593Smuzhiyun 
144*4882a593Smuzhiyun static void backtrace(struct pt_regs *);
145*4882a593Smuzhiyun static void excprint(struct pt_regs *);
146*4882a593Smuzhiyun static void prregs(struct pt_regs *);
147*4882a593Smuzhiyun static void memops(int);
148*4882a593Smuzhiyun static void memlocate(void);
149*4882a593Smuzhiyun static void memzcan(void);
150*4882a593Smuzhiyun static void memdiffs(unsigned char *, unsigned char *, unsigned, unsigned);
151*4882a593Smuzhiyun int skipbl(void);
152*4882a593Smuzhiyun int scanhex(unsigned long *valp);
153*4882a593Smuzhiyun static void scannl(void);
154*4882a593Smuzhiyun static int hexdigit(int);
155*4882a593Smuzhiyun void getstring(char *, int);
156*4882a593Smuzhiyun static void flush_input(void);
157*4882a593Smuzhiyun static int inchar(void);
158*4882a593Smuzhiyun static void take_input(char *);
159*4882a593Smuzhiyun static int  read_spr(int, unsigned long *);
160*4882a593Smuzhiyun static void write_spr(int, unsigned long);
161*4882a593Smuzhiyun static void super_regs(void);
162*4882a593Smuzhiyun static void remove_bpts(void);
163*4882a593Smuzhiyun static void insert_bpts(void);
164*4882a593Smuzhiyun static void remove_cpu_bpts(void);
165*4882a593Smuzhiyun static void insert_cpu_bpts(void);
166*4882a593Smuzhiyun static struct bpt *at_breakpoint(unsigned long pc);
167*4882a593Smuzhiyun static struct bpt *in_breakpoint_table(unsigned long pc, unsigned long *offp);
168*4882a593Smuzhiyun static int  do_step(struct pt_regs *);
169*4882a593Smuzhiyun static void bpt_cmds(void);
170*4882a593Smuzhiyun static void cacheflush(void);
171*4882a593Smuzhiyun static int  cpu_cmd(void);
172*4882a593Smuzhiyun static void csum(void);
173*4882a593Smuzhiyun static void bootcmds(void);
174*4882a593Smuzhiyun static void proccall(void);
175*4882a593Smuzhiyun static void show_tasks(void);
176*4882a593Smuzhiyun void dump_segments(void);
177*4882a593Smuzhiyun static void symbol_lookup(void);
178*4882a593Smuzhiyun static void xmon_show_stack(unsigned long sp, unsigned long lr,
179*4882a593Smuzhiyun 			    unsigned long pc);
180*4882a593Smuzhiyun static void xmon_print_symbol(unsigned long address, const char *mid,
181*4882a593Smuzhiyun 			      const char *after);
182*4882a593Smuzhiyun static const char *getvecname(unsigned long vec);
183*4882a593Smuzhiyun 
184*4882a593Smuzhiyun static int do_spu_cmd(void);
185*4882a593Smuzhiyun 
186*4882a593Smuzhiyun #ifdef CONFIG_44x
187*4882a593Smuzhiyun static void dump_tlb_44x(void);
188*4882a593Smuzhiyun #endif
189*4882a593Smuzhiyun #ifdef CONFIG_PPC_BOOK3E
190*4882a593Smuzhiyun static void dump_tlb_book3e(void);
191*4882a593Smuzhiyun #endif
192*4882a593Smuzhiyun 
193*4882a593Smuzhiyun static void clear_all_bpt(void);
194*4882a593Smuzhiyun 
195*4882a593Smuzhiyun #ifdef CONFIG_PPC64
196*4882a593Smuzhiyun #define REG		"%.16lx"
197*4882a593Smuzhiyun #else
198*4882a593Smuzhiyun #define REG		"%.8lx"
199*4882a593Smuzhiyun #endif
200*4882a593Smuzhiyun 
201*4882a593Smuzhiyun #ifdef __LITTLE_ENDIAN__
202*4882a593Smuzhiyun #define GETWORD(v)	(((v)[3] << 24) + ((v)[2] << 16) + ((v)[1] << 8) + (v)[0])
203*4882a593Smuzhiyun #else
204*4882a593Smuzhiyun #define GETWORD(v)	(((v)[0] << 24) + ((v)[1] << 16) + ((v)[2] << 8) + (v)[3])
205*4882a593Smuzhiyun #endif
206*4882a593Smuzhiyun 
207*4882a593Smuzhiyun static const char *xmon_ro_msg = "Operation disabled: xmon in read-only mode\n";
208*4882a593Smuzhiyun 
209*4882a593Smuzhiyun static char *help_string = "\
210*4882a593Smuzhiyun Commands:\n\
211*4882a593Smuzhiyun   b	show breakpoints\n\
212*4882a593Smuzhiyun   bd	set data breakpoint\n\
213*4882a593Smuzhiyun   bi	set instruction breakpoint\n\
214*4882a593Smuzhiyun   bc	clear breakpoint\n"
215*4882a593Smuzhiyun #ifdef CONFIG_SMP
216*4882a593Smuzhiyun   "\
217*4882a593Smuzhiyun   c	print cpus stopped in xmon\n\
218*4882a593Smuzhiyun   c#	try to switch to cpu number h (in hex)\n"
219*4882a593Smuzhiyun #endif
220*4882a593Smuzhiyun   "\
221*4882a593Smuzhiyun   C	checksum\n\
222*4882a593Smuzhiyun   d	dump bytes\n\
223*4882a593Smuzhiyun   d1	dump 1 byte values\n\
224*4882a593Smuzhiyun   d2	dump 2 byte values\n\
225*4882a593Smuzhiyun   d4	dump 4 byte values\n\
226*4882a593Smuzhiyun   d8	dump 8 byte values\n\
227*4882a593Smuzhiyun   di	dump instructions\n\
228*4882a593Smuzhiyun   df	dump float values\n\
229*4882a593Smuzhiyun   dd	dump double values\n\
230*4882a593Smuzhiyun   dl    dump the kernel log buffer\n"
231*4882a593Smuzhiyun #ifdef CONFIG_PPC_POWERNV
232*4882a593Smuzhiyun   "\
233*4882a593Smuzhiyun   do    dump the OPAL message log\n"
234*4882a593Smuzhiyun #endif
235*4882a593Smuzhiyun #ifdef CONFIG_PPC64
236*4882a593Smuzhiyun   "\
237*4882a593Smuzhiyun   dp[#]	dump paca for current cpu, or cpu #\n\
238*4882a593Smuzhiyun   dpa	dump paca for all possible cpus\n"
239*4882a593Smuzhiyun #endif
240*4882a593Smuzhiyun   "\
241*4882a593Smuzhiyun   dr	dump stream of raw bytes\n\
242*4882a593Smuzhiyun   dv	dump virtual address translation \n\
243*4882a593Smuzhiyun   dt	dump the tracing buffers (uses printk)\n\
244*4882a593Smuzhiyun   dtc	dump the tracing buffers for current CPU (uses printk)\n\
245*4882a593Smuzhiyun "
246*4882a593Smuzhiyun #ifdef CONFIG_PPC_POWERNV
247*4882a593Smuzhiyun "  dx#   dump xive on CPU #\n\
248*4882a593Smuzhiyun   dxi#  dump xive irq state #\n\
249*4882a593Smuzhiyun   dxa   dump xive on all CPUs\n"
250*4882a593Smuzhiyun #endif
251*4882a593Smuzhiyun "  e	print exception information\n\
252*4882a593Smuzhiyun   f	flush cache\n\
253*4882a593Smuzhiyun   la	lookup symbol+offset of specified address\n\
254*4882a593Smuzhiyun   ls	lookup address of specified symbol\n\
255*4882a593Smuzhiyun   lp s [#]	lookup address of percpu symbol s for current cpu, or cpu #\n\
256*4882a593Smuzhiyun   m	examine/change memory\n\
257*4882a593Smuzhiyun   mm	move a block of memory\n\
258*4882a593Smuzhiyun   ms	set a block of memory\n\
259*4882a593Smuzhiyun   md	compare two blocks of memory\n\
260*4882a593Smuzhiyun   ml	locate a block of memory\n\
261*4882a593Smuzhiyun   mz	zero a block of memory\n\
262*4882a593Smuzhiyun   mi	show information about memory allocation\n\
263*4882a593Smuzhiyun   p 	call a procedure\n\
264*4882a593Smuzhiyun   P 	list processes/tasks\n\
265*4882a593Smuzhiyun   r	print registers\n\
266*4882a593Smuzhiyun   s	single step\n"
267*4882a593Smuzhiyun #ifdef CONFIG_SPU_BASE
268*4882a593Smuzhiyun "  ss	stop execution on all spus\n\
269*4882a593Smuzhiyun   sr	restore execution on stopped spus\n\
270*4882a593Smuzhiyun   sf  #	dump spu fields for spu # (in hex)\n\
271*4882a593Smuzhiyun   sd  #	dump spu local store for spu # (in hex)\n\
272*4882a593Smuzhiyun   sdi #	disassemble spu local store for spu # (in hex)\n"
273*4882a593Smuzhiyun #endif
274*4882a593Smuzhiyun "  S	print special registers\n\
275*4882a593Smuzhiyun   Sa    print all SPRs\n\
276*4882a593Smuzhiyun   Sr #	read SPR #\n\
277*4882a593Smuzhiyun   Sw #v write v to SPR #\n\
278*4882a593Smuzhiyun   t	print backtrace\n\
279*4882a593Smuzhiyun   x	exit monitor and recover\n\
280*4882a593Smuzhiyun   X	exit monitor and don't recover\n"
281*4882a593Smuzhiyun #if defined(CONFIG_PPC64) && !defined(CONFIG_PPC_BOOK3E)
282*4882a593Smuzhiyun "  u	dump segment table or SLB\n"
283*4882a593Smuzhiyun #elif defined(CONFIG_PPC_BOOK3S_32)
284*4882a593Smuzhiyun "  u	dump segment registers\n"
285*4882a593Smuzhiyun #elif defined(CONFIG_44x) || defined(CONFIG_PPC_BOOK3E)
286*4882a593Smuzhiyun "  u	dump TLB\n"
287*4882a593Smuzhiyun #endif
288*4882a593Smuzhiyun "  U	show uptime information\n"
289*4882a593Smuzhiyun "  ?	help\n"
290*4882a593Smuzhiyun "  # n	limit output to n lines per page (for dp, dpa, dl)\n"
291*4882a593Smuzhiyun "  zr	reboot\n"
292*4882a593Smuzhiyun "  zh	halt\n"
293*4882a593Smuzhiyun ;
294*4882a593Smuzhiyun 
295*4882a593Smuzhiyun #ifdef CONFIG_SECURITY
xmon_is_locked_down(void)296*4882a593Smuzhiyun static bool xmon_is_locked_down(void)
297*4882a593Smuzhiyun {
298*4882a593Smuzhiyun 	static bool lockdown;
299*4882a593Smuzhiyun 
300*4882a593Smuzhiyun 	if (!lockdown) {
301*4882a593Smuzhiyun 		lockdown = !!security_locked_down(LOCKDOWN_XMON_RW);
302*4882a593Smuzhiyun 		if (lockdown) {
303*4882a593Smuzhiyun 			printf("xmon: Disabled due to kernel lockdown\n");
304*4882a593Smuzhiyun 			xmon_is_ro = true;
305*4882a593Smuzhiyun 		}
306*4882a593Smuzhiyun 	}
307*4882a593Smuzhiyun 
308*4882a593Smuzhiyun 	if (!xmon_is_ro) {
309*4882a593Smuzhiyun 		xmon_is_ro = !!security_locked_down(LOCKDOWN_XMON_WR);
310*4882a593Smuzhiyun 		if (xmon_is_ro)
311*4882a593Smuzhiyun 			printf("xmon: Read-only due to kernel lockdown\n");
312*4882a593Smuzhiyun 	}
313*4882a593Smuzhiyun 
314*4882a593Smuzhiyun 	return lockdown;
315*4882a593Smuzhiyun }
316*4882a593Smuzhiyun #else /* CONFIG_SECURITY */
xmon_is_locked_down(void)317*4882a593Smuzhiyun static inline bool xmon_is_locked_down(void)
318*4882a593Smuzhiyun {
319*4882a593Smuzhiyun 	return false;
320*4882a593Smuzhiyun }
321*4882a593Smuzhiyun #endif
322*4882a593Smuzhiyun 
323*4882a593Smuzhiyun static struct pt_regs *xmon_regs;
324*4882a593Smuzhiyun 
sync(void)325*4882a593Smuzhiyun static inline void sync(void)
326*4882a593Smuzhiyun {
327*4882a593Smuzhiyun 	asm volatile("sync; isync");
328*4882a593Smuzhiyun }
329*4882a593Smuzhiyun 
cflush(void * p)330*4882a593Smuzhiyun static inline void cflush(void *p)
331*4882a593Smuzhiyun {
332*4882a593Smuzhiyun 	asm volatile ("dcbf 0,%0; icbi 0,%0" : : "r" (p));
333*4882a593Smuzhiyun }
334*4882a593Smuzhiyun 
cinval(void * p)335*4882a593Smuzhiyun static inline void cinval(void *p)
336*4882a593Smuzhiyun {
337*4882a593Smuzhiyun 	asm volatile ("dcbi 0,%0; icbi 0,%0" : : "r" (p));
338*4882a593Smuzhiyun }
339*4882a593Smuzhiyun 
340*4882a593Smuzhiyun /**
341*4882a593Smuzhiyun  * write_ciabr() - write the CIABR SPR
342*4882a593Smuzhiyun  * @ciabr:	The value to write.
343*4882a593Smuzhiyun  *
344*4882a593Smuzhiyun  * This function writes a value to the CIARB register either directly
345*4882a593Smuzhiyun  * through mtspr instruction if the kernel is in HV privilege mode or
346*4882a593Smuzhiyun  * call a hypervisor function to achieve the same in case the kernel
347*4882a593Smuzhiyun  * is in supervisor privilege mode.
348*4882a593Smuzhiyun  */
write_ciabr(unsigned long ciabr)349*4882a593Smuzhiyun static void write_ciabr(unsigned long ciabr)
350*4882a593Smuzhiyun {
351*4882a593Smuzhiyun 	if (!cpu_has_feature(CPU_FTR_ARCH_207S))
352*4882a593Smuzhiyun 		return;
353*4882a593Smuzhiyun 
354*4882a593Smuzhiyun 	if (cpu_has_feature(CPU_FTR_HVMODE)) {
355*4882a593Smuzhiyun 		mtspr(SPRN_CIABR, ciabr);
356*4882a593Smuzhiyun 		return;
357*4882a593Smuzhiyun 	}
358*4882a593Smuzhiyun 	plpar_set_ciabr(ciabr);
359*4882a593Smuzhiyun }
360*4882a593Smuzhiyun 
361*4882a593Smuzhiyun /**
362*4882a593Smuzhiyun  * set_ciabr() - set the CIABR
363*4882a593Smuzhiyun  * @addr:	The value to set.
364*4882a593Smuzhiyun  *
365*4882a593Smuzhiyun  * This function sets the correct privilege value into the the HW
366*4882a593Smuzhiyun  * breakpoint address before writing it up in the CIABR register.
367*4882a593Smuzhiyun  */
set_ciabr(unsigned long addr)368*4882a593Smuzhiyun static void set_ciabr(unsigned long addr)
369*4882a593Smuzhiyun {
370*4882a593Smuzhiyun 	addr &= ~CIABR_PRIV;
371*4882a593Smuzhiyun 
372*4882a593Smuzhiyun 	if (cpu_has_feature(CPU_FTR_HVMODE))
373*4882a593Smuzhiyun 		addr |= CIABR_PRIV_HYPER;
374*4882a593Smuzhiyun 	else
375*4882a593Smuzhiyun 		addr |= CIABR_PRIV_SUPER;
376*4882a593Smuzhiyun 	write_ciabr(addr);
377*4882a593Smuzhiyun }
378*4882a593Smuzhiyun 
379*4882a593Smuzhiyun /*
380*4882a593Smuzhiyun  * Disable surveillance (the service processor watchdog function)
381*4882a593Smuzhiyun  * while we are in xmon.
382*4882a593Smuzhiyun  * XXX we should re-enable it when we leave. :)
383*4882a593Smuzhiyun  */
384*4882a593Smuzhiyun #define SURVEILLANCE_TOKEN	9000
385*4882a593Smuzhiyun 
disable_surveillance(void)386*4882a593Smuzhiyun static inline void disable_surveillance(void)
387*4882a593Smuzhiyun {
388*4882a593Smuzhiyun #ifdef CONFIG_PPC_PSERIES
389*4882a593Smuzhiyun 	/* Since this can't be a module, args should end up below 4GB. */
390*4882a593Smuzhiyun 	static struct rtas_args args;
391*4882a593Smuzhiyun 
392*4882a593Smuzhiyun 	/*
393*4882a593Smuzhiyun 	 * At this point we have got all the cpus we can into
394*4882a593Smuzhiyun 	 * xmon, so there is hopefully no other cpu calling RTAS
395*4882a593Smuzhiyun 	 * at the moment, even though we don't take rtas.lock.
396*4882a593Smuzhiyun 	 * If we did try to take rtas.lock there would be a
397*4882a593Smuzhiyun 	 * real possibility of deadlock.
398*4882a593Smuzhiyun 	 */
399*4882a593Smuzhiyun 	if (set_indicator_token == RTAS_UNKNOWN_SERVICE)
400*4882a593Smuzhiyun 		return;
401*4882a593Smuzhiyun 
402*4882a593Smuzhiyun 	rtas_call_unlocked(&args, set_indicator_token, 3, 1, NULL,
403*4882a593Smuzhiyun 			   SURVEILLANCE_TOKEN, 0, 0);
404*4882a593Smuzhiyun 
405*4882a593Smuzhiyun #endif /* CONFIG_PPC_PSERIES */
406*4882a593Smuzhiyun }
407*4882a593Smuzhiyun 
408*4882a593Smuzhiyun #ifdef CONFIG_SMP
409*4882a593Smuzhiyun static int xmon_speaker;
410*4882a593Smuzhiyun 
get_output_lock(void)411*4882a593Smuzhiyun static void get_output_lock(void)
412*4882a593Smuzhiyun {
413*4882a593Smuzhiyun 	int me = smp_processor_id() + 0x100;
414*4882a593Smuzhiyun 	int last_speaker = 0, prev;
415*4882a593Smuzhiyun 	long timeout;
416*4882a593Smuzhiyun 
417*4882a593Smuzhiyun 	if (xmon_speaker == me)
418*4882a593Smuzhiyun 		return;
419*4882a593Smuzhiyun 
420*4882a593Smuzhiyun 	for (;;) {
421*4882a593Smuzhiyun 		last_speaker = cmpxchg(&xmon_speaker, 0, me);
422*4882a593Smuzhiyun 		if (last_speaker == 0)
423*4882a593Smuzhiyun 			return;
424*4882a593Smuzhiyun 
425*4882a593Smuzhiyun 		/*
426*4882a593Smuzhiyun 		 * Wait a full second for the lock, we might be on a slow
427*4882a593Smuzhiyun 		 * console, but check every 100us.
428*4882a593Smuzhiyun 		 */
429*4882a593Smuzhiyun 		timeout = 10000;
430*4882a593Smuzhiyun 		while (xmon_speaker == last_speaker) {
431*4882a593Smuzhiyun 			if (--timeout > 0) {
432*4882a593Smuzhiyun 				udelay(100);
433*4882a593Smuzhiyun 				continue;
434*4882a593Smuzhiyun 			}
435*4882a593Smuzhiyun 
436*4882a593Smuzhiyun 			/* hostile takeover */
437*4882a593Smuzhiyun 			prev = cmpxchg(&xmon_speaker, last_speaker, me);
438*4882a593Smuzhiyun 			if (prev == last_speaker)
439*4882a593Smuzhiyun 				return;
440*4882a593Smuzhiyun 			break;
441*4882a593Smuzhiyun 		}
442*4882a593Smuzhiyun 	}
443*4882a593Smuzhiyun }
444*4882a593Smuzhiyun 
release_output_lock(void)445*4882a593Smuzhiyun static void release_output_lock(void)
446*4882a593Smuzhiyun {
447*4882a593Smuzhiyun 	xmon_speaker = 0;
448*4882a593Smuzhiyun }
449*4882a593Smuzhiyun 
cpus_are_in_xmon(void)450*4882a593Smuzhiyun int cpus_are_in_xmon(void)
451*4882a593Smuzhiyun {
452*4882a593Smuzhiyun 	return !cpumask_empty(&cpus_in_xmon);
453*4882a593Smuzhiyun }
454*4882a593Smuzhiyun 
wait_for_other_cpus(int ncpus)455*4882a593Smuzhiyun static bool wait_for_other_cpus(int ncpus)
456*4882a593Smuzhiyun {
457*4882a593Smuzhiyun 	unsigned long timeout;
458*4882a593Smuzhiyun 
459*4882a593Smuzhiyun 	/* We wait for 2s, which is a metric "little while" */
460*4882a593Smuzhiyun 	for (timeout = 20000; timeout != 0; --timeout) {
461*4882a593Smuzhiyun 		if (cpumask_weight(&cpus_in_xmon) >= ncpus)
462*4882a593Smuzhiyun 			return true;
463*4882a593Smuzhiyun 		udelay(100);
464*4882a593Smuzhiyun 		barrier();
465*4882a593Smuzhiyun 	}
466*4882a593Smuzhiyun 
467*4882a593Smuzhiyun 	return false;
468*4882a593Smuzhiyun }
469*4882a593Smuzhiyun #else /* CONFIG_SMP */
get_output_lock(void)470*4882a593Smuzhiyun static inline void get_output_lock(void) {}
release_output_lock(void)471*4882a593Smuzhiyun static inline void release_output_lock(void) {}
472*4882a593Smuzhiyun #endif
473*4882a593Smuzhiyun 
unrecoverable_excp(struct pt_regs * regs)474*4882a593Smuzhiyun static inline int unrecoverable_excp(struct pt_regs *regs)
475*4882a593Smuzhiyun {
476*4882a593Smuzhiyun #if defined(CONFIG_4xx) || defined(CONFIG_PPC_BOOK3E)
477*4882a593Smuzhiyun 	/* We have no MSR_RI bit on 4xx or Book3e, so we simply return false */
478*4882a593Smuzhiyun 	return 0;
479*4882a593Smuzhiyun #else
480*4882a593Smuzhiyun 	return ((regs->msr & MSR_RI) == 0);
481*4882a593Smuzhiyun #endif
482*4882a593Smuzhiyun }
483*4882a593Smuzhiyun 
xmon_touch_watchdogs(void)484*4882a593Smuzhiyun static void xmon_touch_watchdogs(void)
485*4882a593Smuzhiyun {
486*4882a593Smuzhiyun 	touch_softlockup_watchdog_sync();
487*4882a593Smuzhiyun 	rcu_cpu_stall_reset();
488*4882a593Smuzhiyun 	touch_nmi_watchdog();
489*4882a593Smuzhiyun }
490*4882a593Smuzhiyun 
xmon_core(struct pt_regs * regs,int fromipi)491*4882a593Smuzhiyun static int xmon_core(struct pt_regs *regs, int fromipi)
492*4882a593Smuzhiyun {
493*4882a593Smuzhiyun 	int cmd = 0;
494*4882a593Smuzhiyun 	struct bpt *bp;
495*4882a593Smuzhiyun 	long recurse_jmp[JMP_BUF_LEN];
496*4882a593Smuzhiyun 	bool locked_down;
497*4882a593Smuzhiyun 	unsigned long offset;
498*4882a593Smuzhiyun 	unsigned long flags;
499*4882a593Smuzhiyun #ifdef CONFIG_SMP
500*4882a593Smuzhiyun 	int cpu;
501*4882a593Smuzhiyun 	int secondary;
502*4882a593Smuzhiyun #endif
503*4882a593Smuzhiyun 
504*4882a593Smuzhiyun 	local_irq_save(flags);
505*4882a593Smuzhiyun 	hard_irq_disable();
506*4882a593Smuzhiyun 
507*4882a593Smuzhiyun 	locked_down = xmon_is_locked_down();
508*4882a593Smuzhiyun 
509*4882a593Smuzhiyun 	if (!fromipi) {
510*4882a593Smuzhiyun 		tracing_enabled = tracing_is_on();
511*4882a593Smuzhiyun 		tracing_off();
512*4882a593Smuzhiyun 	}
513*4882a593Smuzhiyun 
514*4882a593Smuzhiyun 	bp = in_breakpoint_table(regs->nip, &offset);
515*4882a593Smuzhiyun 	if (bp != NULL) {
516*4882a593Smuzhiyun 		regs->nip = bp->address + offset;
517*4882a593Smuzhiyun 		atomic_dec(&bp->ref_count);
518*4882a593Smuzhiyun 	}
519*4882a593Smuzhiyun 
520*4882a593Smuzhiyun 	remove_cpu_bpts();
521*4882a593Smuzhiyun 
522*4882a593Smuzhiyun #ifdef CONFIG_SMP
523*4882a593Smuzhiyun 	cpu = smp_processor_id();
524*4882a593Smuzhiyun 	if (cpumask_test_cpu(cpu, &cpus_in_xmon)) {
525*4882a593Smuzhiyun 		/*
526*4882a593Smuzhiyun 		 * We catch SPR read/write faults here because the 0x700, 0xf60
527*4882a593Smuzhiyun 		 * etc. handlers don't call debugger_fault_handler().
528*4882a593Smuzhiyun 		 */
529*4882a593Smuzhiyun 		if (catch_spr_faults)
530*4882a593Smuzhiyun 			longjmp(bus_error_jmp, 1);
531*4882a593Smuzhiyun 		get_output_lock();
532*4882a593Smuzhiyun 		excprint(regs);
533*4882a593Smuzhiyun 		printf("cpu 0x%x: Exception %lx %s in xmon, "
534*4882a593Smuzhiyun 		       "returning to main loop\n",
535*4882a593Smuzhiyun 		       cpu, regs->trap, getvecname(TRAP(regs)));
536*4882a593Smuzhiyun 		release_output_lock();
537*4882a593Smuzhiyun 		longjmp(xmon_fault_jmp[cpu], 1);
538*4882a593Smuzhiyun 	}
539*4882a593Smuzhiyun 
540*4882a593Smuzhiyun 	if (setjmp(recurse_jmp) != 0) {
541*4882a593Smuzhiyun 		if (!in_xmon || !xmon_gate) {
542*4882a593Smuzhiyun 			get_output_lock();
543*4882a593Smuzhiyun 			printf("xmon: WARNING: bad recursive fault "
544*4882a593Smuzhiyun 			       "on cpu 0x%x\n", cpu);
545*4882a593Smuzhiyun 			release_output_lock();
546*4882a593Smuzhiyun 			goto waiting;
547*4882a593Smuzhiyun 		}
548*4882a593Smuzhiyun 		secondary = !(xmon_taken && cpu == xmon_owner);
549*4882a593Smuzhiyun 		goto cmdloop;
550*4882a593Smuzhiyun 	}
551*4882a593Smuzhiyun 
552*4882a593Smuzhiyun 	xmon_fault_jmp[cpu] = recurse_jmp;
553*4882a593Smuzhiyun 
554*4882a593Smuzhiyun 	bp = NULL;
555*4882a593Smuzhiyun 	if ((regs->msr & (MSR_IR|MSR_PR|MSR_64BIT)) == (MSR_IR|MSR_64BIT))
556*4882a593Smuzhiyun 		bp = at_breakpoint(regs->nip);
557*4882a593Smuzhiyun 	if (bp || unrecoverable_excp(regs))
558*4882a593Smuzhiyun 		fromipi = 0;
559*4882a593Smuzhiyun 
560*4882a593Smuzhiyun 	if (!fromipi) {
561*4882a593Smuzhiyun 		get_output_lock();
562*4882a593Smuzhiyun 		if (!locked_down)
563*4882a593Smuzhiyun 			excprint(regs);
564*4882a593Smuzhiyun 		if (bp) {
565*4882a593Smuzhiyun 			printf("cpu 0x%x stopped at breakpoint 0x%tx (",
566*4882a593Smuzhiyun 			       cpu, BP_NUM(bp));
567*4882a593Smuzhiyun 			xmon_print_symbol(regs->nip, " ", ")\n");
568*4882a593Smuzhiyun 		}
569*4882a593Smuzhiyun 		if (unrecoverable_excp(regs))
570*4882a593Smuzhiyun 			printf("WARNING: exception is not recoverable, "
571*4882a593Smuzhiyun 			       "can't continue\n");
572*4882a593Smuzhiyun 		release_output_lock();
573*4882a593Smuzhiyun 	}
574*4882a593Smuzhiyun 
575*4882a593Smuzhiyun 	cpumask_set_cpu(cpu, &cpus_in_xmon);
576*4882a593Smuzhiyun 
577*4882a593Smuzhiyun  waiting:
578*4882a593Smuzhiyun 	secondary = 1;
579*4882a593Smuzhiyun 	spin_begin();
580*4882a593Smuzhiyun 	while (secondary && !xmon_gate) {
581*4882a593Smuzhiyun 		if (in_xmon == 0) {
582*4882a593Smuzhiyun 			if (fromipi) {
583*4882a593Smuzhiyun 				spin_end();
584*4882a593Smuzhiyun 				goto leave;
585*4882a593Smuzhiyun 			}
586*4882a593Smuzhiyun 			secondary = test_and_set_bit(0, &in_xmon);
587*4882a593Smuzhiyun 		}
588*4882a593Smuzhiyun 		spin_cpu_relax();
589*4882a593Smuzhiyun 		touch_nmi_watchdog();
590*4882a593Smuzhiyun 	}
591*4882a593Smuzhiyun 	spin_end();
592*4882a593Smuzhiyun 
593*4882a593Smuzhiyun 	if (!secondary && !xmon_gate) {
594*4882a593Smuzhiyun 		/* we are the first cpu to come in */
595*4882a593Smuzhiyun 		/* interrupt other cpu(s) */
596*4882a593Smuzhiyun 		int ncpus = num_online_cpus();
597*4882a593Smuzhiyun 
598*4882a593Smuzhiyun 		xmon_owner = cpu;
599*4882a593Smuzhiyun 		mb();
600*4882a593Smuzhiyun 		if (ncpus > 1) {
601*4882a593Smuzhiyun 			/*
602*4882a593Smuzhiyun 			 * A system reset (trap == 0x100) can be triggered on
603*4882a593Smuzhiyun 			 * all CPUs, so when we come in via 0x100 try waiting
604*4882a593Smuzhiyun 			 * for the other CPUs to come in before we send the
605*4882a593Smuzhiyun 			 * debugger break (IPI). This is similar to
606*4882a593Smuzhiyun 			 * crash_kexec_secondary().
607*4882a593Smuzhiyun 			 */
608*4882a593Smuzhiyun 			if (TRAP(regs) != 0x100 || !wait_for_other_cpus(ncpus))
609*4882a593Smuzhiyun 				smp_send_debugger_break();
610*4882a593Smuzhiyun 
611*4882a593Smuzhiyun 			wait_for_other_cpus(ncpus);
612*4882a593Smuzhiyun 		}
613*4882a593Smuzhiyun 		remove_bpts();
614*4882a593Smuzhiyun 		disable_surveillance();
615*4882a593Smuzhiyun 
616*4882a593Smuzhiyun 		if (!locked_down) {
617*4882a593Smuzhiyun 			/* for breakpoint or single step, print curr insn */
618*4882a593Smuzhiyun 			if (bp || TRAP(regs) == 0xd00)
619*4882a593Smuzhiyun 				ppc_inst_dump(regs->nip, 1, 0);
620*4882a593Smuzhiyun 			printf("enter ? for help\n");
621*4882a593Smuzhiyun 		}
622*4882a593Smuzhiyun 
623*4882a593Smuzhiyun 		mb();
624*4882a593Smuzhiyun 		xmon_gate = 1;
625*4882a593Smuzhiyun 		barrier();
626*4882a593Smuzhiyun 		touch_nmi_watchdog();
627*4882a593Smuzhiyun 	}
628*4882a593Smuzhiyun 
629*4882a593Smuzhiyun  cmdloop:
630*4882a593Smuzhiyun 	while (in_xmon) {
631*4882a593Smuzhiyun 		if (secondary) {
632*4882a593Smuzhiyun 			spin_begin();
633*4882a593Smuzhiyun 			if (cpu == xmon_owner) {
634*4882a593Smuzhiyun 				if (!test_and_set_bit(0, &xmon_taken)) {
635*4882a593Smuzhiyun 					secondary = 0;
636*4882a593Smuzhiyun 					spin_end();
637*4882a593Smuzhiyun 					continue;
638*4882a593Smuzhiyun 				}
639*4882a593Smuzhiyun 				/* missed it */
640*4882a593Smuzhiyun 				while (cpu == xmon_owner)
641*4882a593Smuzhiyun 					spin_cpu_relax();
642*4882a593Smuzhiyun 			}
643*4882a593Smuzhiyun 			spin_cpu_relax();
644*4882a593Smuzhiyun 			touch_nmi_watchdog();
645*4882a593Smuzhiyun 		} else {
646*4882a593Smuzhiyun 			if (!locked_down)
647*4882a593Smuzhiyun 				cmd = cmds(regs);
648*4882a593Smuzhiyun 			if (locked_down || cmd != 0) {
649*4882a593Smuzhiyun 				/* exiting xmon */
650*4882a593Smuzhiyun 				insert_bpts();
651*4882a593Smuzhiyun 				xmon_gate = 0;
652*4882a593Smuzhiyun 				wmb();
653*4882a593Smuzhiyun 				in_xmon = 0;
654*4882a593Smuzhiyun 				break;
655*4882a593Smuzhiyun 			}
656*4882a593Smuzhiyun 			/* have switched to some other cpu */
657*4882a593Smuzhiyun 			secondary = 1;
658*4882a593Smuzhiyun 		}
659*4882a593Smuzhiyun 	}
660*4882a593Smuzhiyun  leave:
661*4882a593Smuzhiyun 	cpumask_clear_cpu(cpu, &cpus_in_xmon);
662*4882a593Smuzhiyun 	xmon_fault_jmp[cpu] = NULL;
663*4882a593Smuzhiyun #else
664*4882a593Smuzhiyun 	/* UP is simple... */
665*4882a593Smuzhiyun 	if (in_xmon) {
666*4882a593Smuzhiyun 		printf("Exception %lx %s in xmon, returning to main loop\n",
667*4882a593Smuzhiyun 		       regs->trap, getvecname(TRAP(regs)));
668*4882a593Smuzhiyun 		longjmp(xmon_fault_jmp[0], 1);
669*4882a593Smuzhiyun 	}
670*4882a593Smuzhiyun 	if (setjmp(recurse_jmp) == 0) {
671*4882a593Smuzhiyun 		xmon_fault_jmp[0] = recurse_jmp;
672*4882a593Smuzhiyun 		in_xmon = 1;
673*4882a593Smuzhiyun 
674*4882a593Smuzhiyun 		excprint(regs);
675*4882a593Smuzhiyun 		bp = at_breakpoint(regs->nip);
676*4882a593Smuzhiyun 		if (bp) {
677*4882a593Smuzhiyun 			printf("Stopped at breakpoint %tx (", BP_NUM(bp));
678*4882a593Smuzhiyun 			xmon_print_symbol(regs->nip, " ", ")\n");
679*4882a593Smuzhiyun 		}
680*4882a593Smuzhiyun 		if (unrecoverable_excp(regs))
681*4882a593Smuzhiyun 			printf("WARNING: exception is not recoverable, "
682*4882a593Smuzhiyun 			       "can't continue\n");
683*4882a593Smuzhiyun 		remove_bpts();
684*4882a593Smuzhiyun 		disable_surveillance();
685*4882a593Smuzhiyun 		if (!locked_down) {
686*4882a593Smuzhiyun 			/* for breakpoint or single step, print current insn */
687*4882a593Smuzhiyun 			if (bp || TRAP(regs) == 0xd00)
688*4882a593Smuzhiyun 				ppc_inst_dump(regs->nip, 1, 0);
689*4882a593Smuzhiyun 			printf("enter ? for help\n");
690*4882a593Smuzhiyun 		}
691*4882a593Smuzhiyun 	}
692*4882a593Smuzhiyun 
693*4882a593Smuzhiyun 	if (!locked_down)
694*4882a593Smuzhiyun 		cmd = cmds(regs);
695*4882a593Smuzhiyun 
696*4882a593Smuzhiyun 	insert_bpts();
697*4882a593Smuzhiyun 	in_xmon = 0;
698*4882a593Smuzhiyun #endif
699*4882a593Smuzhiyun 
700*4882a593Smuzhiyun #ifdef CONFIG_BOOKE
701*4882a593Smuzhiyun 	if (regs->msr & MSR_DE) {
702*4882a593Smuzhiyun 		bp = at_breakpoint(regs->nip);
703*4882a593Smuzhiyun 		if (bp != NULL) {
704*4882a593Smuzhiyun 			regs->nip = (unsigned long) &bp->instr[0];
705*4882a593Smuzhiyun 			atomic_inc(&bp->ref_count);
706*4882a593Smuzhiyun 		}
707*4882a593Smuzhiyun 	}
708*4882a593Smuzhiyun #else
709*4882a593Smuzhiyun 	if ((regs->msr & (MSR_IR|MSR_PR|MSR_64BIT)) == (MSR_IR|MSR_64BIT)) {
710*4882a593Smuzhiyun 		bp = at_breakpoint(regs->nip);
711*4882a593Smuzhiyun 		if (bp != NULL) {
712*4882a593Smuzhiyun 			int stepped = emulate_step(regs, ppc_inst_read(bp->instr));
713*4882a593Smuzhiyun 			if (stepped == 0) {
714*4882a593Smuzhiyun 				regs->nip = (unsigned long) &bp->instr[0];
715*4882a593Smuzhiyun 				atomic_inc(&bp->ref_count);
716*4882a593Smuzhiyun 			} else if (stepped < 0) {
717*4882a593Smuzhiyun 				printf("Couldn't single-step %s instruction\n",
718*4882a593Smuzhiyun 				    IS_RFID(ppc_inst_read(bp->instr))? "rfid": "mtmsrd");
719*4882a593Smuzhiyun 			}
720*4882a593Smuzhiyun 		}
721*4882a593Smuzhiyun 	}
722*4882a593Smuzhiyun #endif
723*4882a593Smuzhiyun 	if (locked_down)
724*4882a593Smuzhiyun 		clear_all_bpt();
725*4882a593Smuzhiyun 	else
726*4882a593Smuzhiyun 		insert_cpu_bpts();
727*4882a593Smuzhiyun 
728*4882a593Smuzhiyun 	xmon_touch_watchdogs();
729*4882a593Smuzhiyun 	local_irq_restore(flags);
730*4882a593Smuzhiyun 
731*4882a593Smuzhiyun 	return cmd != 'X' && cmd != EOF;
732*4882a593Smuzhiyun }
733*4882a593Smuzhiyun 
xmon(struct pt_regs * excp)734*4882a593Smuzhiyun int xmon(struct pt_regs *excp)
735*4882a593Smuzhiyun {
736*4882a593Smuzhiyun 	struct pt_regs regs;
737*4882a593Smuzhiyun 
738*4882a593Smuzhiyun 	if (excp == NULL) {
739*4882a593Smuzhiyun 		ppc_save_regs(&regs);
740*4882a593Smuzhiyun 		excp = &regs;
741*4882a593Smuzhiyun 	}
742*4882a593Smuzhiyun 
743*4882a593Smuzhiyun 	return xmon_core(excp, 0);
744*4882a593Smuzhiyun }
745*4882a593Smuzhiyun EXPORT_SYMBOL(xmon);
746*4882a593Smuzhiyun 
xmon_irq(int irq,void * d)747*4882a593Smuzhiyun irqreturn_t xmon_irq(int irq, void *d)
748*4882a593Smuzhiyun {
749*4882a593Smuzhiyun 	unsigned long flags;
750*4882a593Smuzhiyun 	local_irq_save(flags);
751*4882a593Smuzhiyun 	printf("Keyboard interrupt\n");
752*4882a593Smuzhiyun 	xmon(get_irq_regs());
753*4882a593Smuzhiyun 	local_irq_restore(flags);
754*4882a593Smuzhiyun 	return IRQ_HANDLED;
755*4882a593Smuzhiyun }
756*4882a593Smuzhiyun 
xmon_bpt(struct pt_regs * regs)757*4882a593Smuzhiyun static int xmon_bpt(struct pt_regs *regs)
758*4882a593Smuzhiyun {
759*4882a593Smuzhiyun 	struct bpt *bp;
760*4882a593Smuzhiyun 	unsigned long offset;
761*4882a593Smuzhiyun 
762*4882a593Smuzhiyun 	if ((regs->msr & (MSR_IR|MSR_PR|MSR_64BIT)) != (MSR_IR|MSR_64BIT))
763*4882a593Smuzhiyun 		return 0;
764*4882a593Smuzhiyun 
765*4882a593Smuzhiyun 	/* Are we at the trap at bp->instr[1] for some bp? */
766*4882a593Smuzhiyun 	bp = in_breakpoint_table(regs->nip, &offset);
767*4882a593Smuzhiyun 	if (bp != NULL && (offset == 4 || offset == 8)) {
768*4882a593Smuzhiyun 		regs->nip = bp->address + offset;
769*4882a593Smuzhiyun 		atomic_dec(&bp->ref_count);
770*4882a593Smuzhiyun 		return 1;
771*4882a593Smuzhiyun 	}
772*4882a593Smuzhiyun 
773*4882a593Smuzhiyun 	/* Are we at a breakpoint? */
774*4882a593Smuzhiyun 	bp = at_breakpoint(regs->nip);
775*4882a593Smuzhiyun 	if (!bp)
776*4882a593Smuzhiyun 		return 0;
777*4882a593Smuzhiyun 
778*4882a593Smuzhiyun 	xmon_core(regs, 0);
779*4882a593Smuzhiyun 
780*4882a593Smuzhiyun 	return 1;
781*4882a593Smuzhiyun }
782*4882a593Smuzhiyun 
xmon_sstep(struct pt_regs * regs)783*4882a593Smuzhiyun static int xmon_sstep(struct pt_regs *regs)
784*4882a593Smuzhiyun {
785*4882a593Smuzhiyun 	if (user_mode(regs))
786*4882a593Smuzhiyun 		return 0;
787*4882a593Smuzhiyun 	xmon_core(regs, 0);
788*4882a593Smuzhiyun 	return 1;
789*4882a593Smuzhiyun }
790*4882a593Smuzhiyun 
xmon_break_match(struct pt_regs * regs)791*4882a593Smuzhiyun static int xmon_break_match(struct pt_regs *regs)
792*4882a593Smuzhiyun {
793*4882a593Smuzhiyun 	int i;
794*4882a593Smuzhiyun 
795*4882a593Smuzhiyun 	if ((regs->msr & (MSR_IR|MSR_PR|MSR_64BIT)) != (MSR_IR|MSR_64BIT))
796*4882a593Smuzhiyun 		return 0;
797*4882a593Smuzhiyun 	for (i = 0; i < nr_wp_slots(); i++) {
798*4882a593Smuzhiyun 		if (dabr[i].enabled)
799*4882a593Smuzhiyun 			goto found;
800*4882a593Smuzhiyun 	}
801*4882a593Smuzhiyun 	return 0;
802*4882a593Smuzhiyun 
803*4882a593Smuzhiyun found:
804*4882a593Smuzhiyun 	xmon_core(regs, 0);
805*4882a593Smuzhiyun 	return 1;
806*4882a593Smuzhiyun }
807*4882a593Smuzhiyun 
xmon_iabr_match(struct pt_regs * regs)808*4882a593Smuzhiyun static int xmon_iabr_match(struct pt_regs *regs)
809*4882a593Smuzhiyun {
810*4882a593Smuzhiyun 	if ((regs->msr & (MSR_IR|MSR_PR|MSR_64BIT)) != (MSR_IR|MSR_64BIT))
811*4882a593Smuzhiyun 		return 0;
812*4882a593Smuzhiyun 	if (iabr == NULL)
813*4882a593Smuzhiyun 		return 0;
814*4882a593Smuzhiyun 	xmon_core(regs, 0);
815*4882a593Smuzhiyun 	return 1;
816*4882a593Smuzhiyun }
817*4882a593Smuzhiyun 
xmon_ipi(struct pt_regs * regs)818*4882a593Smuzhiyun static int xmon_ipi(struct pt_regs *regs)
819*4882a593Smuzhiyun {
820*4882a593Smuzhiyun #ifdef CONFIG_SMP
821*4882a593Smuzhiyun 	if (in_xmon && !cpumask_test_cpu(smp_processor_id(), &cpus_in_xmon))
822*4882a593Smuzhiyun 		xmon_core(regs, 1);
823*4882a593Smuzhiyun #endif
824*4882a593Smuzhiyun 	return 0;
825*4882a593Smuzhiyun }
826*4882a593Smuzhiyun 
xmon_fault_handler(struct pt_regs * regs)827*4882a593Smuzhiyun static int xmon_fault_handler(struct pt_regs *regs)
828*4882a593Smuzhiyun {
829*4882a593Smuzhiyun 	struct bpt *bp;
830*4882a593Smuzhiyun 	unsigned long offset;
831*4882a593Smuzhiyun 
832*4882a593Smuzhiyun 	if (in_xmon && catch_memory_errors)
833*4882a593Smuzhiyun 		handle_fault(regs);	/* doesn't return */
834*4882a593Smuzhiyun 
835*4882a593Smuzhiyun 	if ((regs->msr & (MSR_IR|MSR_PR|MSR_64BIT)) == (MSR_IR|MSR_64BIT)) {
836*4882a593Smuzhiyun 		bp = in_breakpoint_table(regs->nip, &offset);
837*4882a593Smuzhiyun 		if (bp != NULL) {
838*4882a593Smuzhiyun 			regs->nip = bp->address + offset;
839*4882a593Smuzhiyun 			atomic_dec(&bp->ref_count);
840*4882a593Smuzhiyun 		}
841*4882a593Smuzhiyun 	}
842*4882a593Smuzhiyun 
843*4882a593Smuzhiyun 	return 0;
844*4882a593Smuzhiyun }
845*4882a593Smuzhiyun 
846*4882a593Smuzhiyun /* Force enable xmon if not already enabled */
force_enable_xmon(void)847*4882a593Smuzhiyun static inline void force_enable_xmon(void)
848*4882a593Smuzhiyun {
849*4882a593Smuzhiyun 	/* Enable xmon hooks if needed */
850*4882a593Smuzhiyun 	if (!xmon_on) {
851*4882a593Smuzhiyun 		printf("xmon: Enabling debugger hooks\n");
852*4882a593Smuzhiyun 		xmon_on = 1;
853*4882a593Smuzhiyun 	}
854*4882a593Smuzhiyun }
855*4882a593Smuzhiyun 
at_breakpoint(unsigned long pc)856*4882a593Smuzhiyun static struct bpt *at_breakpoint(unsigned long pc)
857*4882a593Smuzhiyun {
858*4882a593Smuzhiyun 	int i;
859*4882a593Smuzhiyun 	struct bpt *bp;
860*4882a593Smuzhiyun 
861*4882a593Smuzhiyun 	bp = bpts;
862*4882a593Smuzhiyun 	for (i = 0; i < NBPTS; ++i, ++bp)
863*4882a593Smuzhiyun 		if (bp->enabled && pc == bp->address)
864*4882a593Smuzhiyun 			return bp;
865*4882a593Smuzhiyun 	return NULL;
866*4882a593Smuzhiyun }
867*4882a593Smuzhiyun 
in_breakpoint_table(unsigned long nip,unsigned long * offp)868*4882a593Smuzhiyun static struct bpt *in_breakpoint_table(unsigned long nip, unsigned long *offp)
869*4882a593Smuzhiyun {
870*4882a593Smuzhiyun 	unsigned long off;
871*4882a593Smuzhiyun 
872*4882a593Smuzhiyun 	off = nip - (unsigned long)bpt_table;
873*4882a593Smuzhiyun 	if (off >= sizeof(bpt_table))
874*4882a593Smuzhiyun 		return NULL;
875*4882a593Smuzhiyun 	*offp = off & (BPT_SIZE - 1);
876*4882a593Smuzhiyun 	if (off & 3)
877*4882a593Smuzhiyun 		return NULL;
878*4882a593Smuzhiyun 	return bpts + (off / BPT_SIZE);
879*4882a593Smuzhiyun }
880*4882a593Smuzhiyun 
new_breakpoint(unsigned long a)881*4882a593Smuzhiyun static struct bpt *new_breakpoint(unsigned long a)
882*4882a593Smuzhiyun {
883*4882a593Smuzhiyun 	struct bpt *bp;
884*4882a593Smuzhiyun 
885*4882a593Smuzhiyun 	a &= ~3UL;
886*4882a593Smuzhiyun 	bp = at_breakpoint(a);
887*4882a593Smuzhiyun 	if (bp)
888*4882a593Smuzhiyun 		return bp;
889*4882a593Smuzhiyun 
890*4882a593Smuzhiyun 	for (bp = bpts; bp < &bpts[NBPTS]; ++bp) {
891*4882a593Smuzhiyun 		if (!bp->enabled && atomic_read(&bp->ref_count) == 0) {
892*4882a593Smuzhiyun 			bp->address = a;
893*4882a593Smuzhiyun 			bp->instr = (void *)(bpt_table + ((bp - bpts) * BPT_WORDS));
894*4882a593Smuzhiyun 			return bp;
895*4882a593Smuzhiyun 		}
896*4882a593Smuzhiyun 	}
897*4882a593Smuzhiyun 
898*4882a593Smuzhiyun 	printf("Sorry, no free breakpoints.  Please clear one first.\n");
899*4882a593Smuzhiyun 	return NULL;
900*4882a593Smuzhiyun }
901*4882a593Smuzhiyun 
insert_bpts(void)902*4882a593Smuzhiyun static void insert_bpts(void)
903*4882a593Smuzhiyun {
904*4882a593Smuzhiyun 	int i;
905*4882a593Smuzhiyun 	struct ppc_inst instr, instr2;
906*4882a593Smuzhiyun 	struct bpt *bp, *bp2;
907*4882a593Smuzhiyun 
908*4882a593Smuzhiyun 	bp = bpts;
909*4882a593Smuzhiyun 	for (i = 0; i < NBPTS; ++i, ++bp) {
910*4882a593Smuzhiyun 		if ((bp->enabled & (BP_TRAP|BP_CIABR)) == 0)
911*4882a593Smuzhiyun 			continue;
912*4882a593Smuzhiyun 		if (!mread_instr(bp->address, &instr)) {
913*4882a593Smuzhiyun 			printf("Couldn't read instruction at %lx, "
914*4882a593Smuzhiyun 			       "disabling breakpoint there\n", bp->address);
915*4882a593Smuzhiyun 			bp->enabled = 0;
916*4882a593Smuzhiyun 			continue;
917*4882a593Smuzhiyun 		}
918*4882a593Smuzhiyun 		if (IS_MTMSRD(instr) || IS_RFID(instr)) {
919*4882a593Smuzhiyun 			printf("Breakpoint at %lx is on an mtmsrd or rfid "
920*4882a593Smuzhiyun 			       "instruction, disabling it\n", bp->address);
921*4882a593Smuzhiyun 			bp->enabled = 0;
922*4882a593Smuzhiyun 			continue;
923*4882a593Smuzhiyun 		}
924*4882a593Smuzhiyun 		/*
925*4882a593Smuzhiyun 		 * Check the address is not a suffix by looking for a prefix in
926*4882a593Smuzhiyun 		 * front of it.
927*4882a593Smuzhiyun 		 */
928*4882a593Smuzhiyun 		if (mread_instr(bp->address - 4, &instr2) == 8) {
929*4882a593Smuzhiyun 			printf("Breakpoint at %lx is on the second word of a prefixed instruction, disabling it\n",
930*4882a593Smuzhiyun 			       bp->address);
931*4882a593Smuzhiyun 			bp->enabled = 0;
932*4882a593Smuzhiyun 			continue;
933*4882a593Smuzhiyun 		}
934*4882a593Smuzhiyun 		/*
935*4882a593Smuzhiyun 		 * We might still be a suffix - if the prefix has already been
936*4882a593Smuzhiyun 		 * replaced by a breakpoint we won't catch it with the above
937*4882a593Smuzhiyun 		 * test.
938*4882a593Smuzhiyun 		 */
939*4882a593Smuzhiyun 		bp2 = at_breakpoint(bp->address - 4);
940*4882a593Smuzhiyun 		if (bp2 && ppc_inst_prefixed(ppc_inst_read(bp2->instr))) {
941*4882a593Smuzhiyun 			printf("Breakpoint at %lx is on the second word of a prefixed instruction, disabling it\n",
942*4882a593Smuzhiyun 			       bp->address);
943*4882a593Smuzhiyun 			bp->enabled = 0;
944*4882a593Smuzhiyun 			continue;
945*4882a593Smuzhiyun 		}
946*4882a593Smuzhiyun 
947*4882a593Smuzhiyun 		patch_instruction(bp->instr, instr);
948*4882a593Smuzhiyun 		patch_instruction(ppc_inst_next(bp->instr, &instr),
949*4882a593Smuzhiyun 				  ppc_inst(bpinstr));
950*4882a593Smuzhiyun 		if (bp->enabled & BP_CIABR)
951*4882a593Smuzhiyun 			continue;
952*4882a593Smuzhiyun 		if (patch_instruction((struct ppc_inst *)bp->address,
953*4882a593Smuzhiyun 				      ppc_inst(bpinstr)) != 0) {
954*4882a593Smuzhiyun 			printf("Couldn't write instruction at %lx, "
955*4882a593Smuzhiyun 			       "disabling breakpoint there\n", bp->address);
956*4882a593Smuzhiyun 			bp->enabled &= ~BP_TRAP;
957*4882a593Smuzhiyun 			continue;
958*4882a593Smuzhiyun 		}
959*4882a593Smuzhiyun 	}
960*4882a593Smuzhiyun }
961*4882a593Smuzhiyun 
insert_cpu_bpts(void)962*4882a593Smuzhiyun static void insert_cpu_bpts(void)
963*4882a593Smuzhiyun {
964*4882a593Smuzhiyun 	int i;
965*4882a593Smuzhiyun 	struct arch_hw_breakpoint brk;
966*4882a593Smuzhiyun 
967*4882a593Smuzhiyun 	for (i = 0; i < nr_wp_slots(); i++) {
968*4882a593Smuzhiyun 		if (dabr[i].enabled) {
969*4882a593Smuzhiyun 			brk.address = dabr[i].address;
970*4882a593Smuzhiyun 			brk.type = (dabr[i].enabled & HW_BRK_TYPE_DABR) | HW_BRK_TYPE_PRIV_ALL;
971*4882a593Smuzhiyun 			brk.len = 8;
972*4882a593Smuzhiyun 			brk.hw_len = 8;
973*4882a593Smuzhiyun 			__set_breakpoint(i, &brk);
974*4882a593Smuzhiyun 		}
975*4882a593Smuzhiyun 	}
976*4882a593Smuzhiyun 
977*4882a593Smuzhiyun 	if (iabr)
978*4882a593Smuzhiyun 		set_ciabr(iabr->address);
979*4882a593Smuzhiyun }
980*4882a593Smuzhiyun 
remove_bpts(void)981*4882a593Smuzhiyun static void remove_bpts(void)
982*4882a593Smuzhiyun {
983*4882a593Smuzhiyun 	int i;
984*4882a593Smuzhiyun 	struct bpt *bp;
985*4882a593Smuzhiyun 	struct ppc_inst instr;
986*4882a593Smuzhiyun 
987*4882a593Smuzhiyun 	bp = bpts;
988*4882a593Smuzhiyun 	for (i = 0; i < NBPTS; ++i, ++bp) {
989*4882a593Smuzhiyun 		if ((bp->enabled & (BP_TRAP|BP_CIABR)) != BP_TRAP)
990*4882a593Smuzhiyun 			continue;
991*4882a593Smuzhiyun 		if (mread_instr(bp->address, &instr)
992*4882a593Smuzhiyun 		    && ppc_inst_equal(instr, ppc_inst(bpinstr))
993*4882a593Smuzhiyun 		    && patch_instruction(
994*4882a593Smuzhiyun 			(struct ppc_inst *)bp->address, ppc_inst_read(bp->instr)) != 0)
995*4882a593Smuzhiyun 			printf("Couldn't remove breakpoint at %lx\n",
996*4882a593Smuzhiyun 			       bp->address);
997*4882a593Smuzhiyun 	}
998*4882a593Smuzhiyun }
999*4882a593Smuzhiyun 
remove_cpu_bpts(void)1000*4882a593Smuzhiyun static void remove_cpu_bpts(void)
1001*4882a593Smuzhiyun {
1002*4882a593Smuzhiyun 	hw_breakpoint_disable();
1003*4882a593Smuzhiyun 	write_ciabr(0);
1004*4882a593Smuzhiyun }
1005*4882a593Smuzhiyun 
1006*4882a593Smuzhiyun /* Based on uptime_proc_show(). */
1007*4882a593Smuzhiyun static void
show_uptime(void)1008*4882a593Smuzhiyun show_uptime(void)
1009*4882a593Smuzhiyun {
1010*4882a593Smuzhiyun 	struct timespec64 uptime;
1011*4882a593Smuzhiyun 
1012*4882a593Smuzhiyun 	if (setjmp(bus_error_jmp) == 0) {
1013*4882a593Smuzhiyun 		catch_memory_errors = 1;
1014*4882a593Smuzhiyun 		sync();
1015*4882a593Smuzhiyun 
1016*4882a593Smuzhiyun 		ktime_get_coarse_boottime_ts64(&uptime);
1017*4882a593Smuzhiyun 		printf("Uptime: %lu.%.2lu seconds\n", (unsigned long)uptime.tv_sec,
1018*4882a593Smuzhiyun 			((unsigned long)uptime.tv_nsec / (NSEC_PER_SEC/100)));
1019*4882a593Smuzhiyun 
1020*4882a593Smuzhiyun 		sync();
1021*4882a593Smuzhiyun 		__delay(200);						\
1022*4882a593Smuzhiyun 	}
1023*4882a593Smuzhiyun 	catch_memory_errors = 0;
1024*4882a593Smuzhiyun }
1025*4882a593Smuzhiyun 
set_lpp_cmd(void)1026*4882a593Smuzhiyun static void set_lpp_cmd(void)
1027*4882a593Smuzhiyun {
1028*4882a593Smuzhiyun 	unsigned long lpp;
1029*4882a593Smuzhiyun 
1030*4882a593Smuzhiyun 	if (!scanhex(&lpp)) {
1031*4882a593Smuzhiyun 		printf("Invalid number.\n");
1032*4882a593Smuzhiyun 		lpp = 0;
1033*4882a593Smuzhiyun 	}
1034*4882a593Smuzhiyun 	xmon_set_pagination_lpp(lpp);
1035*4882a593Smuzhiyun }
1036*4882a593Smuzhiyun /* Command interpreting routine */
1037*4882a593Smuzhiyun static char *last_cmd;
1038*4882a593Smuzhiyun 
1039*4882a593Smuzhiyun static int
cmds(struct pt_regs * excp)1040*4882a593Smuzhiyun cmds(struct pt_regs *excp)
1041*4882a593Smuzhiyun {
1042*4882a593Smuzhiyun 	int cmd = 0;
1043*4882a593Smuzhiyun 
1044*4882a593Smuzhiyun 	last_cmd = NULL;
1045*4882a593Smuzhiyun 	xmon_regs = excp;
1046*4882a593Smuzhiyun 
1047*4882a593Smuzhiyun 	xmon_show_stack(excp->gpr[1], excp->link, excp->nip);
1048*4882a593Smuzhiyun 
1049*4882a593Smuzhiyun 	for(;;) {
1050*4882a593Smuzhiyun #ifdef CONFIG_SMP
1051*4882a593Smuzhiyun 		printf("%x:", smp_processor_id());
1052*4882a593Smuzhiyun #endif /* CONFIG_SMP */
1053*4882a593Smuzhiyun 		printf("mon> ");
1054*4882a593Smuzhiyun 		flush_input();
1055*4882a593Smuzhiyun 		termch = 0;
1056*4882a593Smuzhiyun 		cmd = skipbl();
1057*4882a593Smuzhiyun 		if( cmd == '\n' ) {
1058*4882a593Smuzhiyun 			if (last_cmd == NULL)
1059*4882a593Smuzhiyun 				continue;
1060*4882a593Smuzhiyun 			take_input(last_cmd);
1061*4882a593Smuzhiyun 			last_cmd = NULL;
1062*4882a593Smuzhiyun 			cmd = inchar();
1063*4882a593Smuzhiyun 		}
1064*4882a593Smuzhiyun 		switch (cmd) {
1065*4882a593Smuzhiyun 		case 'm':
1066*4882a593Smuzhiyun 			cmd = inchar();
1067*4882a593Smuzhiyun 			switch (cmd) {
1068*4882a593Smuzhiyun 			case 'm':
1069*4882a593Smuzhiyun 			case 's':
1070*4882a593Smuzhiyun 			case 'd':
1071*4882a593Smuzhiyun 				memops(cmd);
1072*4882a593Smuzhiyun 				break;
1073*4882a593Smuzhiyun 			case 'l':
1074*4882a593Smuzhiyun 				memlocate();
1075*4882a593Smuzhiyun 				break;
1076*4882a593Smuzhiyun 			case 'z':
1077*4882a593Smuzhiyun 				if (xmon_is_ro) {
1078*4882a593Smuzhiyun 					printf(xmon_ro_msg);
1079*4882a593Smuzhiyun 					break;
1080*4882a593Smuzhiyun 				}
1081*4882a593Smuzhiyun 				memzcan();
1082*4882a593Smuzhiyun 				break;
1083*4882a593Smuzhiyun 			case 'i':
1084*4882a593Smuzhiyun 				show_mem(0, NULL);
1085*4882a593Smuzhiyun 				break;
1086*4882a593Smuzhiyun 			default:
1087*4882a593Smuzhiyun 				termch = cmd;
1088*4882a593Smuzhiyun 				memex();
1089*4882a593Smuzhiyun 			}
1090*4882a593Smuzhiyun 			break;
1091*4882a593Smuzhiyun 		case 'd':
1092*4882a593Smuzhiyun 			dump();
1093*4882a593Smuzhiyun 			break;
1094*4882a593Smuzhiyun 		case 'l':
1095*4882a593Smuzhiyun 			symbol_lookup();
1096*4882a593Smuzhiyun 			break;
1097*4882a593Smuzhiyun 		case 'r':
1098*4882a593Smuzhiyun 			prregs(excp);	/* print regs */
1099*4882a593Smuzhiyun 			break;
1100*4882a593Smuzhiyun 		case 'e':
1101*4882a593Smuzhiyun 			excprint(excp);
1102*4882a593Smuzhiyun 			break;
1103*4882a593Smuzhiyun 		case 'S':
1104*4882a593Smuzhiyun 			super_regs();
1105*4882a593Smuzhiyun 			break;
1106*4882a593Smuzhiyun 		case 't':
1107*4882a593Smuzhiyun 			backtrace(excp);
1108*4882a593Smuzhiyun 			break;
1109*4882a593Smuzhiyun 		case 'f':
1110*4882a593Smuzhiyun 			cacheflush();
1111*4882a593Smuzhiyun 			break;
1112*4882a593Smuzhiyun 		case 's':
1113*4882a593Smuzhiyun 			if (do_spu_cmd() == 0)
1114*4882a593Smuzhiyun 				break;
1115*4882a593Smuzhiyun 			if (do_step(excp))
1116*4882a593Smuzhiyun 				return cmd;
1117*4882a593Smuzhiyun 			break;
1118*4882a593Smuzhiyun 		case 'x':
1119*4882a593Smuzhiyun 		case 'X':
1120*4882a593Smuzhiyun 			if (tracing_enabled)
1121*4882a593Smuzhiyun 				tracing_on();
1122*4882a593Smuzhiyun 			return cmd;
1123*4882a593Smuzhiyun 		case EOF:
1124*4882a593Smuzhiyun 			printf(" <no input ...>\n");
1125*4882a593Smuzhiyun 			mdelay(2000);
1126*4882a593Smuzhiyun 			return cmd;
1127*4882a593Smuzhiyun 		case '?':
1128*4882a593Smuzhiyun 			xmon_puts(help_string);
1129*4882a593Smuzhiyun 			break;
1130*4882a593Smuzhiyun 		case '#':
1131*4882a593Smuzhiyun 			set_lpp_cmd();
1132*4882a593Smuzhiyun 			break;
1133*4882a593Smuzhiyun 		case 'b':
1134*4882a593Smuzhiyun 			bpt_cmds();
1135*4882a593Smuzhiyun 			break;
1136*4882a593Smuzhiyun 		case 'C':
1137*4882a593Smuzhiyun 			csum();
1138*4882a593Smuzhiyun 			break;
1139*4882a593Smuzhiyun 		case 'c':
1140*4882a593Smuzhiyun 			if (cpu_cmd())
1141*4882a593Smuzhiyun 				return 0;
1142*4882a593Smuzhiyun 			break;
1143*4882a593Smuzhiyun 		case 'z':
1144*4882a593Smuzhiyun 			bootcmds();
1145*4882a593Smuzhiyun 			break;
1146*4882a593Smuzhiyun 		case 'p':
1147*4882a593Smuzhiyun 			if (xmon_is_ro) {
1148*4882a593Smuzhiyun 				printf(xmon_ro_msg);
1149*4882a593Smuzhiyun 				break;
1150*4882a593Smuzhiyun 			}
1151*4882a593Smuzhiyun 			proccall();
1152*4882a593Smuzhiyun 			break;
1153*4882a593Smuzhiyun 		case 'P':
1154*4882a593Smuzhiyun 			show_tasks();
1155*4882a593Smuzhiyun 			break;
1156*4882a593Smuzhiyun #ifdef CONFIG_PPC_BOOK3S
1157*4882a593Smuzhiyun 		case 'u':
1158*4882a593Smuzhiyun 			dump_segments();
1159*4882a593Smuzhiyun 			break;
1160*4882a593Smuzhiyun #elif defined(CONFIG_44x)
1161*4882a593Smuzhiyun 		case 'u':
1162*4882a593Smuzhiyun 			dump_tlb_44x();
1163*4882a593Smuzhiyun 			break;
1164*4882a593Smuzhiyun #elif defined(CONFIG_PPC_BOOK3E)
1165*4882a593Smuzhiyun 		case 'u':
1166*4882a593Smuzhiyun 			dump_tlb_book3e();
1167*4882a593Smuzhiyun 			break;
1168*4882a593Smuzhiyun #endif
1169*4882a593Smuzhiyun 		case 'U':
1170*4882a593Smuzhiyun 			show_uptime();
1171*4882a593Smuzhiyun 			break;
1172*4882a593Smuzhiyun 		default:
1173*4882a593Smuzhiyun 			printf("Unrecognized command: ");
1174*4882a593Smuzhiyun 			do {
1175*4882a593Smuzhiyun 				if (' ' < cmd && cmd <= '~')
1176*4882a593Smuzhiyun 					putchar(cmd);
1177*4882a593Smuzhiyun 				else
1178*4882a593Smuzhiyun 					printf("\\x%x", cmd);
1179*4882a593Smuzhiyun 				cmd = inchar();
1180*4882a593Smuzhiyun 			} while (cmd != '\n');
1181*4882a593Smuzhiyun 			printf(" (type ? for help)\n");
1182*4882a593Smuzhiyun 			break;
1183*4882a593Smuzhiyun 		}
1184*4882a593Smuzhiyun 	}
1185*4882a593Smuzhiyun }
1186*4882a593Smuzhiyun 
1187*4882a593Smuzhiyun #ifdef CONFIG_BOOKE
do_step(struct pt_regs * regs)1188*4882a593Smuzhiyun static int do_step(struct pt_regs *regs)
1189*4882a593Smuzhiyun {
1190*4882a593Smuzhiyun 	regs->msr |= MSR_DE;
1191*4882a593Smuzhiyun 	mtspr(SPRN_DBCR0, mfspr(SPRN_DBCR0) | DBCR0_IC | DBCR0_IDM);
1192*4882a593Smuzhiyun 	return 1;
1193*4882a593Smuzhiyun }
1194*4882a593Smuzhiyun #else
1195*4882a593Smuzhiyun /*
1196*4882a593Smuzhiyun  * Step a single instruction.
1197*4882a593Smuzhiyun  * Some instructions we emulate, others we execute with MSR_SE set.
1198*4882a593Smuzhiyun  */
do_step(struct pt_regs * regs)1199*4882a593Smuzhiyun static int do_step(struct pt_regs *regs)
1200*4882a593Smuzhiyun {
1201*4882a593Smuzhiyun 	struct ppc_inst instr;
1202*4882a593Smuzhiyun 	int stepped;
1203*4882a593Smuzhiyun 
1204*4882a593Smuzhiyun 	force_enable_xmon();
1205*4882a593Smuzhiyun 	/* check we are in 64-bit kernel mode, translation enabled */
1206*4882a593Smuzhiyun 	if ((regs->msr & (MSR_64BIT|MSR_PR|MSR_IR)) == (MSR_64BIT|MSR_IR)) {
1207*4882a593Smuzhiyun 		if (mread_instr(regs->nip, &instr)) {
1208*4882a593Smuzhiyun 			stepped = emulate_step(regs, instr);
1209*4882a593Smuzhiyun 			if (stepped < 0) {
1210*4882a593Smuzhiyun 				printf("Couldn't single-step %s instruction\n",
1211*4882a593Smuzhiyun 				       (IS_RFID(instr)? "rfid": "mtmsrd"));
1212*4882a593Smuzhiyun 				return 0;
1213*4882a593Smuzhiyun 			}
1214*4882a593Smuzhiyun 			if (stepped > 0) {
1215*4882a593Smuzhiyun 				set_trap(regs, 0xd00);
1216*4882a593Smuzhiyun 				printf("stepped to ");
1217*4882a593Smuzhiyun 				xmon_print_symbol(regs->nip, " ", "\n");
1218*4882a593Smuzhiyun 				ppc_inst_dump(regs->nip, 1, 0);
1219*4882a593Smuzhiyun 				return 0;
1220*4882a593Smuzhiyun 			}
1221*4882a593Smuzhiyun 		}
1222*4882a593Smuzhiyun 	}
1223*4882a593Smuzhiyun 	regs->msr |= MSR_SE;
1224*4882a593Smuzhiyun 	return 1;
1225*4882a593Smuzhiyun }
1226*4882a593Smuzhiyun #endif
1227*4882a593Smuzhiyun 
bootcmds(void)1228*4882a593Smuzhiyun static void bootcmds(void)
1229*4882a593Smuzhiyun {
1230*4882a593Smuzhiyun 	char tmp[64];
1231*4882a593Smuzhiyun 	int cmd;
1232*4882a593Smuzhiyun 
1233*4882a593Smuzhiyun 	cmd = inchar();
1234*4882a593Smuzhiyun 	if (cmd == 'r') {
1235*4882a593Smuzhiyun 		getstring(tmp, 64);
1236*4882a593Smuzhiyun 		ppc_md.restart(tmp);
1237*4882a593Smuzhiyun 	} else if (cmd == 'h') {
1238*4882a593Smuzhiyun 		ppc_md.halt();
1239*4882a593Smuzhiyun 	} else if (cmd == 'p') {
1240*4882a593Smuzhiyun 		if (pm_power_off)
1241*4882a593Smuzhiyun 			pm_power_off();
1242*4882a593Smuzhiyun 	}
1243*4882a593Smuzhiyun }
1244*4882a593Smuzhiyun 
cpu_cmd(void)1245*4882a593Smuzhiyun static int cpu_cmd(void)
1246*4882a593Smuzhiyun {
1247*4882a593Smuzhiyun #ifdef CONFIG_SMP
1248*4882a593Smuzhiyun 	unsigned long cpu, first_cpu, last_cpu;
1249*4882a593Smuzhiyun 	int timeout;
1250*4882a593Smuzhiyun 
1251*4882a593Smuzhiyun 	if (!scanhex(&cpu)) {
1252*4882a593Smuzhiyun 		/* print cpus waiting or in xmon */
1253*4882a593Smuzhiyun 		printf("cpus stopped:");
1254*4882a593Smuzhiyun 		last_cpu = first_cpu = NR_CPUS;
1255*4882a593Smuzhiyun 		for_each_possible_cpu(cpu) {
1256*4882a593Smuzhiyun 			if (cpumask_test_cpu(cpu, &cpus_in_xmon)) {
1257*4882a593Smuzhiyun 				if (cpu == last_cpu + 1) {
1258*4882a593Smuzhiyun 					last_cpu = cpu;
1259*4882a593Smuzhiyun 				} else {
1260*4882a593Smuzhiyun 					if (last_cpu != first_cpu)
1261*4882a593Smuzhiyun 						printf("-0x%lx", last_cpu);
1262*4882a593Smuzhiyun 					last_cpu = first_cpu = cpu;
1263*4882a593Smuzhiyun 					printf(" 0x%lx", cpu);
1264*4882a593Smuzhiyun 				}
1265*4882a593Smuzhiyun 			}
1266*4882a593Smuzhiyun 		}
1267*4882a593Smuzhiyun 		if (last_cpu != first_cpu)
1268*4882a593Smuzhiyun 			printf("-0x%lx", last_cpu);
1269*4882a593Smuzhiyun 		printf("\n");
1270*4882a593Smuzhiyun 		return 0;
1271*4882a593Smuzhiyun 	}
1272*4882a593Smuzhiyun 	/* try to switch to cpu specified */
1273*4882a593Smuzhiyun 	if (!cpumask_test_cpu(cpu, &cpus_in_xmon)) {
1274*4882a593Smuzhiyun 		printf("cpu 0x%lx isn't in xmon\n", cpu);
1275*4882a593Smuzhiyun #ifdef CONFIG_PPC64
1276*4882a593Smuzhiyun 		printf("backtrace of paca[0x%lx].saved_r1 (possibly stale):\n", cpu);
1277*4882a593Smuzhiyun 		xmon_show_stack(paca_ptrs[cpu]->saved_r1, 0, 0);
1278*4882a593Smuzhiyun #endif
1279*4882a593Smuzhiyun 		return 0;
1280*4882a593Smuzhiyun 	}
1281*4882a593Smuzhiyun 	xmon_taken = 0;
1282*4882a593Smuzhiyun 	mb();
1283*4882a593Smuzhiyun 	xmon_owner = cpu;
1284*4882a593Smuzhiyun 	timeout = 10000000;
1285*4882a593Smuzhiyun 	while (!xmon_taken) {
1286*4882a593Smuzhiyun 		if (--timeout == 0) {
1287*4882a593Smuzhiyun 			if (test_and_set_bit(0, &xmon_taken))
1288*4882a593Smuzhiyun 				break;
1289*4882a593Smuzhiyun 			/* take control back */
1290*4882a593Smuzhiyun 			mb();
1291*4882a593Smuzhiyun 			xmon_owner = smp_processor_id();
1292*4882a593Smuzhiyun 			printf("cpu 0x%lx didn't take control\n", cpu);
1293*4882a593Smuzhiyun 			return 0;
1294*4882a593Smuzhiyun 		}
1295*4882a593Smuzhiyun 		barrier();
1296*4882a593Smuzhiyun 	}
1297*4882a593Smuzhiyun 	return 1;
1298*4882a593Smuzhiyun #else
1299*4882a593Smuzhiyun 	return 0;
1300*4882a593Smuzhiyun #endif /* CONFIG_SMP */
1301*4882a593Smuzhiyun }
1302*4882a593Smuzhiyun 
1303*4882a593Smuzhiyun static unsigned short fcstab[256] = {
1304*4882a593Smuzhiyun 	0x0000, 0x1189, 0x2312, 0x329b, 0x4624, 0x57ad, 0x6536, 0x74bf,
1305*4882a593Smuzhiyun 	0x8c48, 0x9dc1, 0xaf5a, 0xbed3, 0xca6c, 0xdbe5, 0xe97e, 0xf8f7,
1306*4882a593Smuzhiyun 	0x1081, 0x0108, 0x3393, 0x221a, 0x56a5, 0x472c, 0x75b7, 0x643e,
1307*4882a593Smuzhiyun 	0x9cc9, 0x8d40, 0xbfdb, 0xae52, 0xdaed, 0xcb64, 0xf9ff, 0xe876,
1308*4882a593Smuzhiyun 	0x2102, 0x308b, 0x0210, 0x1399, 0x6726, 0x76af, 0x4434, 0x55bd,
1309*4882a593Smuzhiyun 	0xad4a, 0xbcc3, 0x8e58, 0x9fd1, 0xeb6e, 0xfae7, 0xc87c, 0xd9f5,
1310*4882a593Smuzhiyun 	0x3183, 0x200a, 0x1291, 0x0318, 0x77a7, 0x662e, 0x54b5, 0x453c,
1311*4882a593Smuzhiyun 	0xbdcb, 0xac42, 0x9ed9, 0x8f50, 0xfbef, 0xea66, 0xd8fd, 0xc974,
1312*4882a593Smuzhiyun 	0x4204, 0x538d, 0x6116, 0x709f, 0x0420, 0x15a9, 0x2732, 0x36bb,
1313*4882a593Smuzhiyun 	0xce4c, 0xdfc5, 0xed5e, 0xfcd7, 0x8868, 0x99e1, 0xab7a, 0xbaf3,
1314*4882a593Smuzhiyun 	0x5285, 0x430c, 0x7197, 0x601e, 0x14a1, 0x0528, 0x37b3, 0x263a,
1315*4882a593Smuzhiyun 	0xdecd, 0xcf44, 0xfddf, 0xec56, 0x98e9, 0x8960, 0xbbfb, 0xaa72,
1316*4882a593Smuzhiyun 	0x6306, 0x728f, 0x4014, 0x519d, 0x2522, 0x34ab, 0x0630, 0x17b9,
1317*4882a593Smuzhiyun 	0xef4e, 0xfec7, 0xcc5c, 0xddd5, 0xa96a, 0xb8e3, 0x8a78, 0x9bf1,
1318*4882a593Smuzhiyun 	0x7387, 0x620e, 0x5095, 0x411c, 0x35a3, 0x242a, 0x16b1, 0x0738,
1319*4882a593Smuzhiyun 	0xffcf, 0xee46, 0xdcdd, 0xcd54, 0xb9eb, 0xa862, 0x9af9, 0x8b70,
1320*4882a593Smuzhiyun 	0x8408, 0x9581, 0xa71a, 0xb693, 0xc22c, 0xd3a5, 0xe13e, 0xf0b7,
1321*4882a593Smuzhiyun 	0x0840, 0x19c9, 0x2b52, 0x3adb, 0x4e64, 0x5fed, 0x6d76, 0x7cff,
1322*4882a593Smuzhiyun 	0x9489, 0x8500, 0xb79b, 0xa612, 0xd2ad, 0xc324, 0xf1bf, 0xe036,
1323*4882a593Smuzhiyun 	0x18c1, 0x0948, 0x3bd3, 0x2a5a, 0x5ee5, 0x4f6c, 0x7df7, 0x6c7e,
1324*4882a593Smuzhiyun 	0xa50a, 0xb483, 0x8618, 0x9791, 0xe32e, 0xf2a7, 0xc03c, 0xd1b5,
1325*4882a593Smuzhiyun 	0x2942, 0x38cb, 0x0a50, 0x1bd9, 0x6f66, 0x7eef, 0x4c74, 0x5dfd,
1326*4882a593Smuzhiyun 	0xb58b, 0xa402, 0x9699, 0x8710, 0xf3af, 0xe226, 0xd0bd, 0xc134,
1327*4882a593Smuzhiyun 	0x39c3, 0x284a, 0x1ad1, 0x0b58, 0x7fe7, 0x6e6e, 0x5cf5, 0x4d7c,
1328*4882a593Smuzhiyun 	0xc60c, 0xd785, 0xe51e, 0xf497, 0x8028, 0x91a1, 0xa33a, 0xb2b3,
1329*4882a593Smuzhiyun 	0x4a44, 0x5bcd, 0x6956, 0x78df, 0x0c60, 0x1de9, 0x2f72, 0x3efb,
1330*4882a593Smuzhiyun 	0xd68d, 0xc704, 0xf59f, 0xe416, 0x90a9, 0x8120, 0xb3bb, 0xa232,
1331*4882a593Smuzhiyun 	0x5ac5, 0x4b4c, 0x79d7, 0x685e, 0x1ce1, 0x0d68, 0x3ff3, 0x2e7a,
1332*4882a593Smuzhiyun 	0xe70e, 0xf687, 0xc41c, 0xd595, 0xa12a, 0xb0a3, 0x8238, 0x93b1,
1333*4882a593Smuzhiyun 	0x6b46, 0x7acf, 0x4854, 0x59dd, 0x2d62, 0x3ceb, 0x0e70, 0x1ff9,
1334*4882a593Smuzhiyun 	0xf78f, 0xe606, 0xd49d, 0xc514, 0xb1ab, 0xa022, 0x92b9, 0x8330,
1335*4882a593Smuzhiyun 	0x7bc7, 0x6a4e, 0x58d5, 0x495c, 0x3de3, 0x2c6a, 0x1ef1, 0x0f78
1336*4882a593Smuzhiyun };
1337*4882a593Smuzhiyun 
1338*4882a593Smuzhiyun #define FCS(fcs, c)	(((fcs) >> 8) ^ fcstab[((fcs) ^ (c)) & 0xff])
1339*4882a593Smuzhiyun 
1340*4882a593Smuzhiyun static void
csum(void)1341*4882a593Smuzhiyun csum(void)
1342*4882a593Smuzhiyun {
1343*4882a593Smuzhiyun 	unsigned int i;
1344*4882a593Smuzhiyun 	unsigned short fcs;
1345*4882a593Smuzhiyun 	unsigned char v;
1346*4882a593Smuzhiyun 
1347*4882a593Smuzhiyun 	if (!scanhex(&adrs))
1348*4882a593Smuzhiyun 		return;
1349*4882a593Smuzhiyun 	if (!scanhex(&ncsum))
1350*4882a593Smuzhiyun 		return;
1351*4882a593Smuzhiyun 	fcs = 0xffff;
1352*4882a593Smuzhiyun 	for (i = 0; i < ncsum; ++i) {
1353*4882a593Smuzhiyun 		if (mread(adrs+i, &v, 1) == 0) {
1354*4882a593Smuzhiyun 			printf("csum stopped at "REG"\n", adrs+i);
1355*4882a593Smuzhiyun 			break;
1356*4882a593Smuzhiyun 		}
1357*4882a593Smuzhiyun 		fcs = FCS(fcs, v);
1358*4882a593Smuzhiyun 	}
1359*4882a593Smuzhiyun 	printf("%x\n", fcs);
1360*4882a593Smuzhiyun }
1361*4882a593Smuzhiyun 
1362*4882a593Smuzhiyun /*
1363*4882a593Smuzhiyun  * Check if this is a suitable place to put a breakpoint.
1364*4882a593Smuzhiyun  */
check_bp_loc(unsigned long addr)1365*4882a593Smuzhiyun static long check_bp_loc(unsigned long addr)
1366*4882a593Smuzhiyun {
1367*4882a593Smuzhiyun 	struct ppc_inst instr;
1368*4882a593Smuzhiyun 
1369*4882a593Smuzhiyun 	addr &= ~3;
1370*4882a593Smuzhiyun 	if (!is_kernel_addr(addr)) {
1371*4882a593Smuzhiyun 		printf("Breakpoints may only be placed at kernel addresses\n");
1372*4882a593Smuzhiyun 		return 0;
1373*4882a593Smuzhiyun 	}
1374*4882a593Smuzhiyun 	if (!mread_instr(addr, &instr)) {
1375*4882a593Smuzhiyun 		printf("Can't read instruction at address %lx\n", addr);
1376*4882a593Smuzhiyun 		return 0;
1377*4882a593Smuzhiyun 	}
1378*4882a593Smuzhiyun 	if (IS_MTMSRD(instr) || IS_RFID(instr)) {
1379*4882a593Smuzhiyun 		printf("Breakpoints may not be placed on mtmsrd or rfid "
1380*4882a593Smuzhiyun 		       "instructions\n");
1381*4882a593Smuzhiyun 		return 0;
1382*4882a593Smuzhiyun 	}
1383*4882a593Smuzhiyun 	return 1;
1384*4882a593Smuzhiyun }
1385*4882a593Smuzhiyun 
1386*4882a593Smuzhiyun #ifndef CONFIG_PPC_8xx
find_free_data_bpt(void)1387*4882a593Smuzhiyun static int find_free_data_bpt(void)
1388*4882a593Smuzhiyun {
1389*4882a593Smuzhiyun 	int i;
1390*4882a593Smuzhiyun 
1391*4882a593Smuzhiyun 	for (i = 0; i < nr_wp_slots(); i++) {
1392*4882a593Smuzhiyun 		if (!dabr[i].enabled)
1393*4882a593Smuzhiyun 			return i;
1394*4882a593Smuzhiyun 	}
1395*4882a593Smuzhiyun 	printf("Couldn't find free breakpoint register\n");
1396*4882a593Smuzhiyun 	return -1;
1397*4882a593Smuzhiyun }
1398*4882a593Smuzhiyun #endif
1399*4882a593Smuzhiyun 
print_data_bpts(void)1400*4882a593Smuzhiyun static void print_data_bpts(void)
1401*4882a593Smuzhiyun {
1402*4882a593Smuzhiyun 	int i;
1403*4882a593Smuzhiyun 
1404*4882a593Smuzhiyun 	for (i = 0; i < nr_wp_slots(); i++) {
1405*4882a593Smuzhiyun 		if (!dabr[i].enabled)
1406*4882a593Smuzhiyun 			continue;
1407*4882a593Smuzhiyun 
1408*4882a593Smuzhiyun 		printf("   data   "REG"  [", dabr[i].address);
1409*4882a593Smuzhiyun 		if (dabr[i].enabled & 1)
1410*4882a593Smuzhiyun 			printf("r");
1411*4882a593Smuzhiyun 		if (dabr[i].enabled & 2)
1412*4882a593Smuzhiyun 			printf("w");
1413*4882a593Smuzhiyun 		printf("]\n");
1414*4882a593Smuzhiyun 	}
1415*4882a593Smuzhiyun }
1416*4882a593Smuzhiyun 
1417*4882a593Smuzhiyun static char *breakpoint_help_string =
1418*4882a593Smuzhiyun     "Breakpoint command usage:\n"
1419*4882a593Smuzhiyun     "b                show breakpoints\n"
1420*4882a593Smuzhiyun     "b <addr> [cnt]   set breakpoint at given instr addr\n"
1421*4882a593Smuzhiyun     "bc               clear all breakpoints\n"
1422*4882a593Smuzhiyun     "bc <n/addr>      clear breakpoint number n or at addr\n"
1423*4882a593Smuzhiyun     "bi <addr> [cnt]  set hardware instr breakpoint (POWER8 only)\n"
1424*4882a593Smuzhiyun     "bd <addr> [cnt]  set hardware data breakpoint\n"
1425*4882a593Smuzhiyun     "";
1426*4882a593Smuzhiyun 
1427*4882a593Smuzhiyun static void
bpt_cmds(void)1428*4882a593Smuzhiyun bpt_cmds(void)
1429*4882a593Smuzhiyun {
1430*4882a593Smuzhiyun 	int cmd;
1431*4882a593Smuzhiyun 	unsigned long a;
1432*4882a593Smuzhiyun 	int i;
1433*4882a593Smuzhiyun 	struct bpt *bp;
1434*4882a593Smuzhiyun 
1435*4882a593Smuzhiyun 	cmd = inchar();
1436*4882a593Smuzhiyun 
1437*4882a593Smuzhiyun 	switch (cmd) {
1438*4882a593Smuzhiyun #ifndef CONFIG_PPC_8xx
1439*4882a593Smuzhiyun 	static const char badaddr[] = "Only kernel addresses are permitted for breakpoints\n";
1440*4882a593Smuzhiyun 	int mode;
1441*4882a593Smuzhiyun 	case 'd':	/* bd - hardware data breakpoint */
1442*4882a593Smuzhiyun 		if (xmon_is_ro) {
1443*4882a593Smuzhiyun 			printf(xmon_ro_msg);
1444*4882a593Smuzhiyun 			break;
1445*4882a593Smuzhiyun 		}
1446*4882a593Smuzhiyun 		if (!ppc_breakpoint_available()) {
1447*4882a593Smuzhiyun 			printf("Hardware data breakpoint not supported on this cpu\n");
1448*4882a593Smuzhiyun 			break;
1449*4882a593Smuzhiyun 		}
1450*4882a593Smuzhiyun 		i = find_free_data_bpt();
1451*4882a593Smuzhiyun 		if (i < 0)
1452*4882a593Smuzhiyun 			break;
1453*4882a593Smuzhiyun 		mode = 7;
1454*4882a593Smuzhiyun 		cmd = inchar();
1455*4882a593Smuzhiyun 		if (cmd == 'r')
1456*4882a593Smuzhiyun 			mode = 5;
1457*4882a593Smuzhiyun 		else if (cmd == 'w')
1458*4882a593Smuzhiyun 			mode = 6;
1459*4882a593Smuzhiyun 		else
1460*4882a593Smuzhiyun 			termch = cmd;
1461*4882a593Smuzhiyun 		dabr[i].address = 0;
1462*4882a593Smuzhiyun 		dabr[i].enabled = 0;
1463*4882a593Smuzhiyun 		if (scanhex(&dabr[i].address)) {
1464*4882a593Smuzhiyun 			if (!is_kernel_addr(dabr[i].address)) {
1465*4882a593Smuzhiyun 				printf(badaddr);
1466*4882a593Smuzhiyun 				break;
1467*4882a593Smuzhiyun 			}
1468*4882a593Smuzhiyun 			dabr[i].address &= ~HW_BRK_TYPE_DABR;
1469*4882a593Smuzhiyun 			dabr[i].enabled = mode | BP_DABR;
1470*4882a593Smuzhiyun 		}
1471*4882a593Smuzhiyun 
1472*4882a593Smuzhiyun 		force_enable_xmon();
1473*4882a593Smuzhiyun 		break;
1474*4882a593Smuzhiyun 
1475*4882a593Smuzhiyun 	case 'i':	/* bi - hardware instr breakpoint */
1476*4882a593Smuzhiyun 		if (xmon_is_ro) {
1477*4882a593Smuzhiyun 			printf(xmon_ro_msg);
1478*4882a593Smuzhiyun 			break;
1479*4882a593Smuzhiyun 		}
1480*4882a593Smuzhiyun 		if (!cpu_has_feature(CPU_FTR_ARCH_207S)) {
1481*4882a593Smuzhiyun 			printf("Hardware instruction breakpoint "
1482*4882a593Smuzhiyun 			       "not supported on this cpu\n");
1483*4882a593Smuzhiyun 			break;
1484*4882a593Smuzhiyun 		}
1485*4882a593Smuzhiyun 		if (iabr) {
1486*4882a593Smuzhiyun 			iabr->enabled &= ~BP_CIABR;
1487*4882a593Smuzhiyun 			iabr = NULL;
1488*4882a593Smuzhiyun 		}
1489*4882a593Smuzhiyun 		if (!scanhex(&a))
1490*4882a593Smuzhiyun 			break;
1491*4882a593Smuzhiyun 		if (!check_bp_loc(a))
1492*4882a593Smuzhiyun 			break;
1493*4882a593Smuzhiyun 		bp = new_breakpoint(a);
1494*4882a593Smuzhiyun 		if (bp != NULL) {
1495*4882a593Smuzhiyun 			bp->enabled |= BP_CIABR;
1496*4882a593Smuzhiyun 			iabr = bp;
1497*4882a593Smuzhiyun 			force_enable_xmon();
1498*4882a593Smuzhiyun 		}
1499*4882a593Smuzhiyun 		break;
1500*4882a593Smuzhiyun #endif
1501*4882a593Smuzhiyun 
1502*4882a593Smuzhiyun 	case 'c':
1503*4882a593Smuzhiyun 		if (!scanhex(&a)) {
1504*4882a593Smuzhiyun 			/* clear all breakpoints */
1505*4882a593Smuzhiyun 			for (i = 0; i < NBPTS; ++i)
1506*4882a593Smuzhiyun 				bpts[i].enabled = 0;
1507*4882a593Smuzhiyun 			iabr = NULL;
1508*4882a593Smuzhiyun 			for (i = 0; i < nr_wp_slots(); i++)
1509*4882a593Smuzhiyun 				dabr[i].enabled = 0;
1510*4882a593Smuzhiyun 
1511*4882a593Smuzhiyun 			printf("All breakpoints cleared\n");
1512*4882a593Smuzhiyun 			break;
1513*4882a593Smuzhiyun 		}
1514*4882a593Smuzhiyun 
1515*4882a593Smuzhiyun 		if (a <= NBPTS && a >= 1) {
1516*4882a593Smuzhiyun 			/* assume a breakpoint number */
1517*4882a593Smuzhiyun 			bp = &bpts[a-1];	/* bp nums are 1 based */
1518*4882a593Smuzhiyun 		} else {
1519*4882a593Smuzhiyun 			/* assume a breakpoint address */
1520*4882a593Smuzhiyun 			bp = at_breakpoint(a);
1521*4882a593Smuzhiyun 			if (bp == NULL) {
1522*4882a593Smuzhiyun 				printf("No breakpoint at %lx\n", a);
1523*4882a593Smuzhiyun 				break;
1524*4882a593Smuzhiyun 			}
1525*4882a593Smuzhiyun 		}
1526*4882a593Smuzhiyun 
1527*4882a593Smuzhiyun 		printf("Cleared breakpoint %tx (", BP_NUM(bp));
1528*4882a593Smuzhiyun 		xmon_print_symbol(bp->address, " ", ")\n");
1529*4882a593Smuzhiyun 		bp->enabled = 0;
1530*4882a593Smuzhiyun 		break;
1531*4882a593Smuzhiyun 
1532*4882a593Smuzhiyun 	default:
1533*4882a593Smuzhiyun 		termch = cmd;
1534*4882a593Smuzhiyun 		cmd = skipbl();
1535*4882a593Smuzhiyun 		if (cmd == '?') {
1536*4882a593Smuzhiyun 			printf(breakpoint_help_string);
1537*4882a593Smuzhiyun 			break;
1538*4882a593Smuzhiyun 		}
1539*4882a593Smuzhiyun 		termch = cmd;
1540*4882a593Smuzhiyun 
1541*4882a593Smuzhiyun 		if (xmon_is_ro || !scanhex(&a)) {
1542*4882a593Smuzhiyun 			/* print all breakpoints */
1543*4882a593Smuzhiyun 			printf("   type            address\n");
1544*4882a593Smuzhiyun 			print_data_bpts();
1545*4882a593Smuzhiyun 			for (bp = bpts; bp < &bpts[NBPTS]; ++bp) {
1546*4882a593Smuzhiyun 				if (!bp->enabled)
1547*4882a593Smuzhiyun 					continue;
1548*4882a593Smuzhiyun 				printf("%tx %s   ", BP_NUM(bp),
1549*4882a593Smuzhiyun 				    (bp->enabled & BP_CIABR) ? "inst": "trap");
1550*4882a593Smuzhiyun 				xmon_print_symbol(bp->address, "  ", "\n");
1551*4882a593Smuzhiyun 			}
1552*4882a593Smuzhiyun 			break;
1553*4882a593Smuzhiyun 		}
1554*4882a593Smuzhiyun 
1555*4882a593Smuzhiyun 		if (!check_bp_loc(a))
1556*4882a593Smuzhiyun 			break;
1557*4882a593Smuzhiyun 		bp = new_breakpoint(a);
1558*4882a593Smuzhiyun 		if (bp != NULL) {
1559*4882a593Smuzhiyun 			bp->enabled |= BP_TRAP;
1560*4882a593Smuzhiyun 			force_enable_xmon();
1561*4882a593Smuzhiyun 		}
1562*4882a593Smuzhiyun 		break;
1563*4882a593Smuzhiyun 	}
1564*4882a593Smuzhiyun }
1565*4882a593Smuzhiyun 
1566*4882a593Smuzhiyun /* Very cheap human name for vector lookup. */
1567*4882a593Smuzhiyun static
getvecname(unsigned long vec)1568*4882a593Smuzhiyun const char *getvecname(unsigned long vec)
1569*4882a593Smuzhiyun {
1570*4882a593Smuzhiyun 	char *ret;
1571*4882a593Smuzhiyun 
1572*4882a593Smuzhiyun 	switch (vec) {
1573*4882a593Smuzhiyun 	case 0x100:	ret = "(System Reset)"; break;
1574*4882a593Smuzhiyun 	case 0x200:	ret = "(Machine Check)"; break;
1575*4882a593Smuzhiyun 	case 0x300:	ret = "(Data Access)"; break;
1576*4882a593Smuzhiyun 	case 0x380:
1577*4882a593Smuzhiyun 		if (radix_enabled())
1578*4882a593Smuzhiyun 			ret = "(Data Access Out of Range)";
1579*4882a593Smuzhiyun 		else
1580*4882a593Smuzhiyun 			ret = "(Data SLB Access)";
1581*4882a593Smuzhiyun 		break;
1582*4882a593Smuzhiyun 	case 0x400:	ret = "(Instruction Access)"; break;
1583*4882a593Smuzhiyun 	case 0x480:
1584*4882a593Smuzhiyun 		if (radix_enabled())
1585*4882a593Smuzhiyun 			ret = "(Instruction Access Out of Range)";
1586*4882a593Smuzhiyun 		else
1587*4882a593Smuzhiyun 			ret = "(Instruction SLB Access)";
1588*4882a593Smuzhiyun 		break;
1589*4882a593Smuzhiyun 	case 0x500:	ret = "(Hardware Interrupt)"; break;
1590*4882a593Smuzhiyun 	case 0x600:	ret = "(Alignment)"; break;
1591*4882a593Smuzhiyun 	case 0x700:	ret = "(Program Check)"; break;
1592*4882a593Smuzhiyun 	case 0x800:	ret = "(FPU Unavailable)"; break;
1593*4882a593Smuzhiyun 	case 0x900:	ret = "(Decrementer)"; break;
1594*4882a593Smuzhiyun 	case 0x980:	ret = "(Hypervisor Decrementer)"; break;
1595*4882a593Smuzhiyun 	case 0xa00:	ret = "(Doorbell)"; break;
1596*4882a593Smuzhiyun 	case 0xc00:	ret = "(System Call)"; break;
1597*4882a593Smuzhiyun 	case 0xd00:	ret = "(Single Step)"; break;
1598*4882a593Smuzhiyun 	case 0xe40:	ret = "(Emulation Assist)"; break;
1599*4882a593Smuzhiyun 	case 0xe60:	ret = "(HMI)"; break;
1600*4882a593Smuzhiyun 	case 0xe80:	ret = "(Hypervisor Doorbell)"; break;
1601*4882a593Smuzhiyun 	case 0xf00:	ret = "(Performance Monitor)"; break;
1602*4882a593Smuzhiyun 	case 0xf20:	ret = "(Altivec Unavailable)"; break;
1603*4882a593Smuzhiyun 	case 0x1300:	ret = "(Instruction Breakpoint)"; break;
1604*4882a593Smuzhiyun 	case 0x1500:	ret = "(Denormalisation)"; break;
1605*4882a593Smuzhiyun 	case 0x1700:	ret = "(Altivec Assist)"; break;
1606*4882a593Smuzhiyun 	case 0x3000:	ret = "(System Call Vectored)"; break;
1607*4882a593Smuzhiyun 	default: ret = "";
1608*4882a593Smuzhiyun 	}
1609*4882a593Smuzhiyun 	return ret;
1610*4882a593Smuzhiyun }
1611*4882a593Smuzhiyun 
get_function_bounds(unsigned long pc,unsigned long * startp,unsigned long * endp)1612*4882a593Smuzhiyun static void get_function_bounds(unsigned long pc, unsigned long *startp,
1613*4882a593Smuzhiyun 				unsigned long *endp)
1614*4882a593Smuzhiyun {
1615*4882a593Smuzhiyun 	unsigned long size, offset;
1616*4882a593Smuzhiyun 	const char *name;
1617*4882a593Smuzhiyun 
1618*4882a593Smuzhiyun 	*startp = *endp = 0;
1619*4882a593Smuzhiyun 	if (pc == 0)
1620*4882a593Smuzhiyun 		return;
1621*4882a593Smuzhiyun 	if (setjmp(bus_error_jmp) == 0) {
1622*4882a593Smuzhiyun 		catch_memory_errors = 1;
1623*4882a593Smuzhiyun 		sync();
1624*4882a593Smuzhiyun 		name = kallsyms_lookup(pc, &size, &offset, NULL, tmpstr);
1625*4882a593Smuzhiyun 		if (name != NULL) {
1626*4882a593Smuzhiyun 			*startp = pc - offset;
1627*4882a593Smuzhiyun 			*endp = pc - offset + size;
1628*4882a593Smuzhiyun 		}
1629*4882a593Smuzhiyun 		sync();
1630*4882a593Smuzhiyun 	}
1631*4882a593Smuzhiyun 	catch_memory_errors = 0;
1632*4882a593Smuzhiyun }
1633*4882a593Smuzhiyun 
1634*4882a593Smuzhiyun #define LRSAVE_OFFSET		(STACK_FRAME_LR_SAVE * sizeof(unsigned long))
1635*4882a593Smuzhiyun #define MARKER_OFFSET		(STACK_FRAME_MARKER * sizeof(unsigned long))
1636*4882a593Smuzhiyun 
xmon_show_stack(unsigned long sp,unsigned long lr,unsigned long pc)1637*4882a593Smuzhiyun static void xmon_show_stack(unsigned long sp, unsigned long lr,
1638*4882a593Smuzhiyun 			    unsigned long pc)
1639*4882a593Smuzhiyun {
1640*4882a593Smuzhiyun 	int max_to_print = 64;
1641*4882a593Smuzhiyun 	unsigned long ip;
1642*4882a593Smuzhiyun 	unsigned long newsp;
1643*4882a593Smuzhiyun 	unsigned long marker;
1644*4882a593Smuzhiyun 	struct pt_regs regs;
1645*4882a593Smuzhiyun 
1646*4882a593Smuzhiyun 	while (max_to_print--) {
1647*4882a593Smuzhiyun 		if (!is_kernel_addr(sp)) {
1648*4882a593Smuzhiyun 			if (sp != 0)
1649*4882a593Smuzhiyun 				printf("SP (%lx) is in userspace\n", sp);
1650*4882a593Smuzhiyun 			break;
1651*4882a593Smuzhiyun 		}
1652*4882a593Smuzhiyun 
1653*4882a593Smuzhiyun 		if (!mread(sp + LRSAVE_OFFSET, &ip, sizeof(unsigned long))
1654*4882a593Smuzhiyun 		    || !mread(sp, &newsp, sizeof(unsigned long))) {
1655*4882a593Smuzhiyun 			printf("Couldn't read stack frame at %lx\n", sp);
1656*4882a593Smuzhiyun 			break;
1657*4882a593Smuzhiyun 		}
1658*4882a593Smuzhiyun 
1659*4882a593Smuzhiyun 		/*
1660*4882a593Smuzhiyun 		 * For the first stack frame, try to work out if
1661*4882a593Smuzhiyun 		 * LR and/or the saved LR value in the bottommost
1662*4882a593Smuzhiyun 		 * stack frame are valid.
1663*4882a593Smuzhiyun 		 */
1664*4882a593Smuzhiyun 		if ((pc | lr) != 0) {
1665*4882a593Smuzhiyun 			unsigned long fnstart, fnend;
1666*4882a593Smuzhiyun 			unsigned long nextip;
1667*4882a593Smuzhiyun 			int printip = 1;
1668*4882a593Smuzhiyun 
1669*4882a593Smuzhiyun 			get_function_bounds(pc, &fnstart, &fnend);
1670*4882a593Smuzhiyun 			nextip = 0;
1671*4882a593Smuzhiyun 			if (newsp > sp)
1672*4882a593Smuzhiyun 				mread(newsp + LRSAVE_OFFSET, &nextip,
1673*4882a593Smuzhiyun 				      sizeof(unsigned long));
1674*4882a593Smuzhiyun 			if (lr == ip) {
1675*4882a593Smuzhiyun 				if (!is_kernel_addr(lr)
1676*4882a593Smuzhiyun 				    || (fnstart <= lr && lr < fnend))
1677*4882a593Smuzhiyun 					printip = 0;
1678*4882a593Smuzhiyun 			} else if (lr == nextip) {
1679*4882a593Smuzhiyun 				printip = 0;
1680*4882a593Smuzhiyun 			} else if (is_kernel_addr(lr)
1681*4882a593Smuzhiyun 				   && !(fnstart <= lr && lr < fnend)) {
1682*4882a593Smuzhiyun 				printf("[link register   ] ");
1683*4882a593Smuzhiyun 				xmon_print_symbol(lr, " ", "\n");
1684*4882a593Smuzhiyun 			}
1685*4882a593Smuzhiyun 			if (printip) {
1686*4882a593Smuzhiyun 				printf("["REG"] ", sp);
1687*4882a593Smuzhiyun 				xmon_print_symbol(ip, " ", " (unreliable)\n");
1688*4882a593Smuzhiyun 			}
1689*4882a593Smuzhiyun 			pc = lr = 0;
1690*4882a593Smuzhiyun 
1691*4882a593Smuzhiyun 		} else {
1692*4882a593Smuzhiyun 			printf("["REG"] ", sp);
1693*4882a593Smuzhiyun 			xmon_print_symbol(ip, " ", "\n");
1694*4882a593Smuzhiyun 		}
1695*4882a593Smuzhiyun 
1696*4882a593Smuzhiyun 		/* Look for "regshere" marker to see if this is
1697*4882a593Smuzhiyun 		   an exception frame. */
1698*4882a593Smuzhiyun 		if (mread(sp + MARKER_OFFSET, &marker, sizeof(unsigned long))
1699*4882a593Smuzhiyun 		    && marker == STACK_FRAME_REGS_MARKER) {
1700*4882a593Smuzhiyun 			if (mread(sp + STACK_FRAME_OVERHEAD, &regs, sizeof(regs))
1701*4882a593Smuzhiyun 			    != sizeof(regs)) {
1702*4882a593Smuzhiyun 				printf("Couldn't read registers at %lx\n",
1703*4882a593Smuzhiyun 				       sp + STACK_FRAME_OVERHEAD);
1704*4882a593Smuzhiyun 				break;
1705*4882a593Smuzhiyun 			}
1706*4882a593Smuzhiyun 			printf("--- Exception: %lx %s at ", regs.trap,
1707*4882a593Smuzhiyun 			       getvecname(TRAP(&regs)));
1708*4882a593Smuzhiyun 			pc = regs.nip;
1709*4882a593Smuzhiyun 			lr = regs.link;
1710*4882a593Smuzhiyun 			xmon_print_symbol(pc, " ", "\n");
1711*4882a593Smuzhiyun 		}
1712*4882a593Smuzhiyun 
1713*4882a593Smuzhiyun 		if (newsp == 0)
1714*4882a593Smuzhiyun 			break;
1715*4882a593Smuzhiyun 
1716*4882a593Smuzhiyun 		sp = newsp;
1717*4882a593Smuzhiyun 	}
1718*4882a593Smuzhiyun }
1719*4882a593Smuzhiyun 
backtrace(struct pt_regs * excp)1720*4882a593Smuzhiyun static void backtrace(struct pt_regs *excp)
1721*4882a593Smuzhiyun {
1722*4882a593Smuzhiyun 	unsigned long sp;
1723*4882a593Smuzhiyun 
1724*4882a593Smuzhiyun 	if (scanhex(&sp))
1725*4882a593Smuzhiyun 		xmon_show_stack(sp, 0, 0);
1726*4882a593Smuzhiyun 	else
1727*4882a593Smuzhiyun 		xmon_show_stack(excp->gpr[1], excp->link, excp->nip);
1728*4882a593Smuzhiyun 	scannl();
1729*4882a593Smuzhiyun }
1730*4882a593Smuzhiyun 
print_bug_trap(struct pt_regs * regs)1731*4882a593Smuzhiyun static void print_bug_trap(struct pt_regs *regs)
1732*4882a593Smuzhiyun {
1733*4882a593Smuzhiyun #ifdef CONFIG_BUG
1734*4882a593Smuzhiyun 	const struct bug_entry *bug;
1735*4882a593Smuzhiyun 	unsigned long addr;
1736*4882a593Smuzhiyun 
1737*4882a593Smuzhiyun 	if (regs->msr & MSR_PR)
1738*4882a593Smuzhiyun 		return;		/* not in kernel */
1739*4882a593Smuzhiyun 	addr = regs->nip;	/* address of trap instruction */
1740*4882a593Smuzhiyun 	if (!is_kernel_addr(addr))
1741*4882a593Smuzhiyun 		return;
1742*4882a593Smuzhiyun 	bug = find_bug(regs->nip);
1743*4882a593Smuzhiyun 	if (bug == NULL)
1744*4882a593Smuzhiyun 		return;
1745*4882a593Smuzhiyun 	if (is_warning_bug(bug))
1746*4882a593Smuzhiyun 		return;
1747*4882a593Smuzhiyun 
1748*4882a593Smuzhiyun #ifdef CONFIG_DEBUG_BUGVERBOSE
1749*4882a593Smuzhiyun 	printf("kernel BUG at %s:%u!\n",
1750*4882a593Smuzhiyun 	       bug->file, bug->line);
1751*4882a593Smuzhiyun #else
1752*4882a593Smuzhiyun 	printf("kernel BUG at %px!\n", (void *)bug->bug_addr);
1753*4882a593Smuzhiyun #endif
1754*4882a593Smuzhiyun #endif /* CONFIG_BUG */
1755*4882a593Smuzhiyun }
1756*4882a593Smuzhiyun 
excprint(struct pt_regs * fp)1757*4882a593Smuzhiyun static void excprint(struct pt_regs *fp)
1758*4882a593Smuzhiyun {
1759*4882a593Smuzhiyun 	unsigned long trap;
1760*4882a593Smuzhiyun 
1761*4882a593Smuzhiyun #ifdef CONFIG_SMP
1762*4882a593Smuzhiyun 	printf("cpu 0x%x: ", smp_processor_id());
1763*4882a593Smuzhiyun #endif /* CONFIG_SMP */
1764*4882a593Smuzhiyun 
1765*4882a593Smuzhiyun 	trap = TRAP(fp);
1766*4882a593Smuzhiyun 	printf("Vector: %lx %s at [%px]\n", fp->trap, getvecname(trap), fp);
1767*4882a593Smuzhiyun 	printf("    pc: ");
1768*4882a593Smuzhiyun 	xmon_print_symbol(fp->nip, ": ", "\n");
1769*4882a593Smuzhiyun 
1770*4882a593Smuzhiyun 	printf("    lr: ");
1771*4882a593Smuzhiyun 	xmon_print_symbol(fp->link, ": ", "\n");
1772*4882a593Smuzhiyun 
1773*4882a593Smuzhiyun 	printf("    sp: %lx\n", fp->gpr[1]);
1774*4882a593Smuzhiyun 	printf("   msr: %lx\n", fp->msr);
1775*4882a593Smuzhiyun 
1776*4882a593Smuzhiyun 	if (trap == 0x300 || trap == 0x380 || trap == 0x600 || trap == 0x200) {
1777*4882a593Smuzhiyun 		printf("   dar: %lx\n", fp->dar);
1778*4882a593Smuzhiyun 		if (trap != 0x380)
1779*4882a593Smuzhiyun 			printf(" dsisr: %lx\n", fp->dsisr);
1780*4882a593Smuzhiyun 	}
1781*4882a593Smuzhiyun 
1782*4882a593Smuzhiyun 	printf("  current = 0x%px\n", current);
1783*4882a593Smuzhiyun #ifdef CONFIG_PPC64
1784*4882a593Smuzhiyun 	printf("  paca    = 0x%px\t irqmask: 0x%02x\t irq_happened: 0x%02x\n",
1785*4882a593Smuzhiyun 	       local_paca, local_paca->irq_soft_mask, local_paca->irq_happened);
1786*4882a593Smuzhiyun #endif
1787*4882a593Smuzhiyun 	if (current) {
1788*4882a593Smuzhiyun 		printf("    pid   = %d, comm = %s\n",
1789*4882a593Smuzhiyun 		       current->pid, current->comm);
1790*4882a593Smuzhiyun 	}
1791*4882a593Smuzhiyun 
1792*4882a593Smuzhiyun 	if (trap == 0x700)
1793*4882a593Smuzhiyun 		print_bug_trap(fp);
1794*4882a593Smuzhiyun 
1795*4882a593Smuzhiyun 	printf(linux_banner);
1796*4882a593Smuzhiyun }
1797*4882a593Smuzhiyun 
prregs(struct pt_regs * fp)1798*4882a593Smuzhiyun static void prregs(struct pt_regs *fp)
1799*4882a593Smuzhiyun {
1800*4882a593Smuzhiyun 	int n, trap;
1801*4882a593Smuzhiyun 	unsigned long base;
1802*4882a593Smuzhiyun 	struct pt_regs regs;
1803*4882a593Smuzhiyun 
1804*4882a593Smuzhiyun 	if (scanhex(&base)) {
1805*4882a593Smuzhiyun 		if (setjmp(bus_error_jmp) == 0) {
1806*4882a593Smuzhiyun 			catch_memory_errors = 1;
1807*4882a593Smuzhiyun 			sync();
1808*4882a593Smuzhiyun 			regs = *(struct pt_regs *)base;
1809*4882a593Smuzhiyun 			sync();
1810*4882a593Smuzhiyun 			__delay(200);
1811*4882a593Smuzhiyun 		} else {
1812*4882a593Smuzhiyun 			catch_memory_errors = 0;
1813*4882a593Smuzhiyun 			printf("*** Error reading registers from "REG"\n",
1814*4882a593Smuzhiyun 			       base);
1815*4882a593Smuzhiyun 			return;
1816*4882a593Smuzhiyun 		}
1817*4882a593Smuzhiyun 		catch_memory_errors = 0;
1818*4882a593Smuzhiyun 		fp = &regs;
1819*4882a593Smuzhiyun 	}
1820*4882a593Smuzhiyun 
1821*4882a593Smuzhiyun #ifdef CONFIG_PPC64
1822*4882a593Smuzhiyun 	if (FULL_REGS(fp)) {
1823*4882a593Smuzhiyun 		for (n = 0; n < 16; ++n)
1824*4882a593Smuzhiyun 			printf("R%.2d = "REG"   R%.2d = "REG"\n",
1825*4882a593Smuzhiyun 			       n, fp->gpr[n], n+16, fp->gpr[n+16]);
1826*4882a593Smuzhiyun 	} else {
1827*4882a593Smuzhiyun 		for (n = 0; n < 7; ++n)
1828*4882a593Smuzhiyun 			printf("R%.2d = "REG"   R%.2d = "REG"\n",
1829*4882a593Smuzhiyun 			       n, fp->gpr[n], n+7, fp->gpr[n+7]);
1830*4882a593Smuzhiyun 	}
1831*4882a593Smuzhiyun #else
1832*4882a593Smuzhiyun 	for (n = 0; n < 32; ++n) {
1833*4882a593Smuzhiyun 		printf("R%.2d = %.8lx%s", n, fp->gpr[n],
1834*4882a593Smuzhiyun 		       (n & 3) == 3? "\n": "   ");
1835*4882a593Smuzhiyun 		if (n == 12 && !FULL_REGS(fp)) {
1836*4882a593Smuzhiyun 			printf("\n");
1837*4882a593Smuzhiyun 			break;
1838*4882a593Smuzhiyun 		}
1839*4882a593Smuzhiyun 	}
1840*4882a593Smuzhiyun #endif
1841*4882a593Smuzhiyun 	printf("pc  = ");
1842*4882a593Smuzhiyun 	xmon_print_symbol(fp->nip, " ", "\n");
1843*4882a593Smuzhiyun 	if (!trap_is_syscall(fp) && cpu_has_feature(CPU_FTR_CFAR)) {
1844*4882a593Smuzhiyun 		printf("cfar= ");
1845*4882a593Smuzhiyun 		xmon_print_symbol(fp->orig_gpr3, " ", "\n");
1846*4882a593Smuzhiyun 	}
1847*4882a593Smuzhiyun 	printf("lr  = ");
1848*4882a593Smuzhiyun 	xmon_print_symbol(fp->link, " ", "\n");
1849*4882a593Smuzhiyun 	printf("msr = "REG"   cr  = %.8lx\n", fp->msr, fp->ccr);
1850*4882a593Smuzhiyun 	printf("ctr = "REG"   xer = "REG"   trap = %4lx\n",
1851*4882a593Smuzhiyun 	       fp->ctr, fp->xer, fp->trap);
1852*4882a593Smuzhiyun 	trap = TRAP(fp);
1853*4882a593Smuzhiyun 	if (trap == 0x300 || trap == 0x380 || trap == 0x600)
1854*4882a593Smuzhiyun 		printf("dar = "REG"   dsisr = %.8lx\n", fp->dar, fp->dsisr);
1855*4882a593Smuzhiyun }
1856*4882a593Smuzhiyun 
cacheflush(void)1857*4882a593Smuzhiyun static void cacheflush(void)
1858*4882a593Smuzhiyun {
1859*4882a593Smuzhiyun 	int cmd;
1860*4882a593Smuzhiyun 	unsigned long nflush;
1861*4882a593Smuzhiyun 
1862*4882a593Smuzhiyun 	cmd = inchar();
1863*4882a593Smuzhiyun 	if (cmd != 'i')
1864*4882a593Smuzhiyun 		termch = cmd;
1865*4882a593Smuzhiyun 	scanhex((void *)&adrs);
1866*4882a593Smuzhiyun 	if (termch != '\n')
1867*4882a593Smuzhiyun 		termch = 0;
1868*4882a593Smuzhiyun 	nflush = 1;
1869*4882a593Smuzhiyun 	scanhex(&nflush);
1870*4882a593Smuzhiyun 	nflush = (nflush + L1_CACHE_BYTES - 1) / L1_CACHE_BYTES;
1871*4882a593Smuzhiyun 	if (setjmp(bus_error_jmp) == 0) {
1872*4882a593Smuzhiyun 		catch_memory_errors = 1;
1873*4882a593Smuzhiyun 		sync();
1874*4882a593Smuzhiyun 
1875*4882a593Smuzhiyun 		if (cmd != 'i' || IS_ENABLED(CONFIG_PPC_BOOK3S_64)) {
1876*4882a593Smuzhiyun 			for (; nflush > 0; --nflush, adrs += L1_CACHE_BYTES)
1877*4882a593Smuzhiyun 				cflush((void *) adrs);
1878*4882a593Smuzhiyun 		} else {
1879*4882a593Smuzhiyun 			for (; nflush > 0; --nflush, adrs += L1_CACHE_BYTES)
1880*4882a593Smuzhiyun 				cinval((void *) adrs);
1881*4882a593Smuzhiyun 		}
1882*4882a593Smuzhiyun 		sync();
1883*4882a593Smuzhiyun 		/* wait a little while to see if we get a machine check */
1884*4882a593Smuzhiyun 		__delay(200);
1885*4882a593Smuzhiyun 	}
1886*4882a593Smuzhiyun 	catch_memory_errors = 0;
1887*4882a593Smuzhiyun }
1888*4882a593Smuzhiyun 
1889*4882a593Smuzhiyun extern unsigned long xmon_mfspr(int spr, unsigned long default_value);
1890*4882a593Smuzhiyun extern void xmon_mtspr(int spr, unsigned long value);
1891*4882a593Smuzhiyun 
1892*4882a593Smuzhiyun static int
read_spr(int n,unsigned long * vp)1893*4882a593Smuzhiyun read_spr(int n, unsigned long *vp)
1894*4882a593Smuzhiyun {
1895*4882a593Smuzhiyun 	unsigned long ret = -1UL;
1896*4882a593Smuzhiyun 	int ok = 0;
1897*4882a593Smuzhiyun 
1898*4882a593Smuzhiyun 	if (setjmp(bus_error_jmp) == 0) {
1899*4882a593Smuzhiyun 		catch_spr_faults = 1;
1900*4882a593Smuzhiyun 		sync();
1901*4882a593Smuzhiyun 
1902*4882a593Smuzhiyun 		ret = xmon_mfspr(n, *vp);
1903*4882a593Smuzhiyun 
1904*4882a593Smuzhiyun 		sync();
1905*4882a593Smuzhiyun 		*vp = ret;
1906*4882a593Smuzhiyun 		ok = 1;
1907*4882a593Smuzhiyun 	}
1908*4882a593Smuzhiyun 	catch_spr_faults = 0;
1909*4882a593Smuzhiyun 
1910*4882a593Smuzhiyun 	return ok;
1911*4882a593Smuzhiyun }
1912*4882a593Smuzhiyun 
1913*4882a593Smuzhiyun static void
write_spr(int n,unsigned long val)1914*4882a593Smuzhiyun write_spr(int n, unsigned long val)
1915*4882a593Smuzhiyun {
1916*4882a593Smuzhiyun 	if (xmon_is_ro) {
1917*4882a593Smuzhiyun 		printf(xmon_ro_msg);
1918*4882a593Smuzhiyun 		return;
1919*4882a593Smuzhiyun 	}
1920*4882a593Smuzhiyun 
1921*4882a593Smuzhiyun 	if (setjmp(bus_error_jmp) == 0) {
1922*4882a593Smuzhiyun 		catch_spr_faults = 1;
1923*4882a593Smuzhiyun 		sync();
1924*4882a593Smuzhiyun 
1925*4882a593Smuzhiyun 		xmon_mtspr(n, val);
1926*4882a593Smuzhiyun 
1927*4882a593Smuzhiyun 		sync();
1928*4882a593Smuzhiyun 	} else {
1929*4882a593Smuzhiyun 		printf("SPR 0x%03x (%4d) Faulted during write\n", n, n);
1930*4882a593Smuzhiyun 	}
1931*4882a593Smuzhiyun 	catch_spr_faults = 0;
1932*4882a593Smuzhiyun }
1933*4882a593Smuzhiyun 
dump_206_sprs(void)1934*4882a593Smuzhiyun static void dump_206_sprs(void)
1935*4882a593Smuzhiyun {
1936*4882a593Smuzhiyun #ifdef CONFIG_PPC64
1937*4882a593Smuzhiyun 	if (!cpu_has_feature(CPU_FTR_ARCH_206))
1938*4882a593Smuzhiyun 		return;
1939*4882a593Smuzhiyun 
1940*4882a593Smuzhiyun 	/* Actually some of these pre-date 2.06, but whatevs */
1941*4882a593Smuzhiyun 
1942*4882a593Smuzhiyun 	printf("srr0   = %.16lx  srr1  = %.16lx dsisr  = %.8lx\n",
1943*4882a593Smuzhiyun 		mfspr(SPRN_SRR0), mfspr(SPRN_SRR1), mfspr(SPRN_DSISR));
1944*4882a593Smuzhiyun 	printf("dscr   = %.16lx  ppr   = %.16lx pir    = %.8lx\n",
1945*4882a593Smuzhiyun 		mfspr(SPRN_DSCR), mfspr(SPRN_PPR), mfspr(SPRN_PIR));
1946*4882a593Smuzhiyun 	printf("amr    = %.16lx  uamor = %.16lx\n",
1947*4882a593Smuzhiyun 		mfspr(SPRN_AMR), mfspr(SPRN_UAMOR));
1948*4882a593Smuzhiyun 
1949*4882a593Smuzhiyun 	if (!(mfmsr() & MSR_HV))
1950*4882a593Smuzhiyun 		return;
1951*4882a593Smuzhiyun 
1952*4882a593Smuzhiyun 	printf("sdr1   = %.16lx  hdar  = %.16lx hdsisr = %.8lx\n",
1953*4882a593Smuzhiyun 		mfspr(SPRN_SDR1), mfspr(SPRN_HDAR), mfspr(SPRN_HDSISR));
1954*4882a593Smuzhiyun 	printf("hsrr0  = %.16lx hsrr1  = %.16lx hdec   = %.16lx\n",
1955*4882a593Smuzhiyun 		mfspr(SPRN_HSRR0), mfspr(SPRN_HSRR1), mfspr(SPRN_HDEC));
1956*4882a593Smuzhiyun 	printf("lpcr   = %.16lx  pcr   = %.16lx lpidr  = %.8lx\n",
1957*4882a593Smuzhiyun 		mfspr(SPRN_LPCR), mfspr(SPRN_PCR), mfspr(SPRN_LPID));
1958*4882a593Smuzhiyun 	printf("hsprg0 = %.16lx hsprg1 = %.16lx amor   = %.16lx\n",
1959*4882a593Smuzhiyun 		mfspr(SPRN_HSPRG0), mfspr(SPRN_HSPRG1), mfspr(SPRN_AMOR));
1960*4882a593Smuzhiyun 	printf("dabr   = %.16lx dabrx  = %.16lx\n",
1961*4882a593Smuzhiyun 		mfspr(SPRN_DABR), mfspr(SPRN_DABRX));
1962*4882a593Smuzhiyun #endif
1963*4882a593Smuzhiyun }
1964*4882a593Smuzhiyun 
dump_207_sprs(void)1965*4882a593Smuzhiyun static void dump_207_sprs(void)
1966*4882a593Smuzhiyun {
1967*4882a593Smuzhiyun #ifdef CONFIG_PPC64
1968*4882a593Smuzhiyun 	unsigned long msr;
1969*4882a593Smuzhiyun 
1970*4882a593Smuzhiyun 	if (!cpu_has_feature(CPU_FTR_ARCH_207S))
1971*4882a593Smuzhiyun 		return;
1972*4882a593Smuzhiyun 
1973*4882a593Smuzhiyun 	printf("dpdes  = %.16lx  tir   = %.16lx cir    = %.8lx\n",
1974*4882a593Smuzhiyun 		mfspr(SPRN_DPDES), mfspr(SPRN_TIR), mfspr(SPRN_CIR));
1975*4882a593Smuzhiyun 
1976*4882a593Smuzhiyun 	printf("fscr   = %.16lx  tar   = %.16lx pspb   = %.8lx\n",
1977*4882a593Smuzhiyun 		mfspr(SPRN_FSCR), mfspr(SPRN_TAR), mfspr(SPRN_PSPB));
1978*4882a593Smuzhiyun 
1979*4882a593Smuzhiyun 	msr = mfmsr();
1980*4882a593Smuzhiyun 	if (msr & MSR_TM) {
1981*4882a593Smuzhiyun 		/* Only if TM has been enabled in the kernel */
1982*4882a593Smuzhiyun 		printf("tfhar  = %.16lx  tfiar = %.16lx texasr = %.16lx\n",
1983*4882a593Smuzhiyun 			mfspr(SPRN_TFHAR), mfspr(SPRN_TFIAR),
1984*4882a593Smuzhiyun 			mfspr(SPRN_TEXASR));
1985*4882a593Smuzhiyun 	}
1986*4882a593Smuzhiyun 
1987*4882a593Smuzhiyun 	printf("mmcr0  = %.16lx  mmcr1 = %.16lx mmcr2  = %.16lx\n",
1988*4882a593Smuzhiyun 		mfspr(SPRN_MMCR0), mfspr(SPRN_MMCR1), mfspr(SPRN_MMCR2));
1989*4882a593Smuzhiyun 	printf("pmc1   = %.8lx pmc2 = %.8lx  pmc3 = %.8lx  pmc4   = %.8lx\n",
1990*4882a593Smuzhiyun 		mfspr(SPRN_PMC1), mfspr(SPRN_PMC2),
1991*4882a593Smuzhiyun 		mfspr(SPRN_PMC3), mfspr(SPRN_PMC4));
1992*4882a593Smuzhiyun 	printf("mmcra  = %.16lx   siar = %.16lx pmc5   = %.8lx\n",
1993*4882a593Smuzhiyun 		mfspr(SPRN_MMCRA), mfspr(SPRN_SIAR), mfspr(SPRN_PMC5));
1994*4882a593Smuzhiyun 	printf("sdar   = %.16lx   sier = %.16lx pmc6   = %.8lx\n",
1995*4882a593Smuzhiyun 		mfspr(SPRN_SDAR), mfspr(SPRN_SIER), mfspr(SPRN_PMC6));
1996*4882a593Smuzhiyun 	printf("ebbhr  = %.16lx  ebbrr = %.16lx bescr  = %.16lx\n",
1997*4882a593Smuzhiyun 		mfspr(SPRN_EBBHR), mfspr(SPRN_EBBRR), mfspr(SPRN_BESCR));
1998*4882a593Smuzhiyun 	printf("iamr   = %.16lx\n", mfspr(SPRN_IAMR));
1999*4882a593Smuzhiyun 
2000*4882a593Smuzhiyun 	if (!(msr & MSR_HV))
2001*4882a593Smuzhiyun 		return;
2002*4882a593Smuzhiyun 
2003*4882a593Smuzhiyun 	printf("hfscr  = %.16lx  dhdes = %.16lx rpr    = %.16lx\n",
2004*4882a593Smuzhiyun 		mfspr(SPRN_HFSCR), mfspr(SPRN_DHDES), mfspr(SPRN_RPR));
2005*4882a593Smuzhiyun 	printf("dawr0  = %.16lx dawrx0 = %.16lx\n",
2006*4882a593Smuzhiyun 	       mfspr(SPRN_DAWR0), mfspr(SPRN_DAWRX0));
2007*4882a593Smuzhiyun 	if (nr_wp_slots() > 1) {
2008*4882a593Smuzhiyun 		printf("dawr1  = %.16lx dawrx1 = %.16lx\n",
2009*4882a593Smuzhiyun 		       mfspr(SPRN_DAWR1), mfspr(SPRN_DAWRX1));
2010*4882a593Smuzhiyun 	}
2011*4882a593Smuzhiyun 	printf("ciabr  = %.16lx\n", mfspr(SPRN_CIABR));
2012*4882a593Smuzhiyun #endif
2013*4882a593Smuzhiyun }
2014*4882a593Smuzhiyun 
dump_300_sprs(void)2015*4882a593Smuzhiyun static void dump_300_sprs(void)
2016*4882a593Smuzhiyun {
2017*4882a593Smuzhiyun #ifdef CONFIG_PPC64
2018*4882a593Smuzhiyun 	bool hv = mfmsr() & MSR_HV;
2019*4882a593Smuzhiyun 
2020*4882a593Smuzhiyun 	if (!cpu_has_feature(CPU_FTR_ARCH_300))
2021*4882a593Smuzhiyun 		return;
2022*4882a593Smuzhiyun 
2023*4882a593Smuzhiyun 	printf("pidr   = %.16lx  tidr  = %.16lx\n",
2024*4882a593Smuzhiyun 		mfspr(SPRN_PID), mfspr(SPRN_TIDR));
2025*4882a593Smuzhiyun 	printf("psscr  = %.16lx\n",
2026*4882a593Smuzhiyun 		hv ? mfspr(SPRN_PSSCR) : mfspr(SPRN_PSSCR_PR));
2027*4882a593Smuzhiyun 
2028*4882a593Smuzhiyun 	if (!hv)
2029*4882a593Smuzhiyun 		return;
2030*4882a593Smuzhiyun 
2031*4882a593Smuzhiyun 	printf("ptcr   = %.16lx  asdr  = %.16lx\n",
2032*4882a593Smuzhiyun 		mfspr(SPRN_PTCR), mfspr(SPRN_ASDR));
2033*4882a593Smuzhiyun #endif
2034*4882a593Smuzhiyun }
2035*4882a593Smuzhiyun 
dump_310_sprs(void)2036*4882a593Smuzhiyun static void dump_310_sprs(void)
2037*4882a593Smuzhiyun {
2038*4882a593Smuzhiyun #ifdef CONFIG_PPC64
2039*4882a593Smuzhiyun 	if (!cpu_has_feature(CPU_FTR_ARCH_31))
2040*4882a593Smuzhiyun 		return;
2041*4882a593Smuzhiyun 
2042*4882a593Smuzhiyun 	printf("mmcr3  = %.16lx, sier2  = %.16lx, sier3  = %.16lx\n",
2043*4882a593Smuzhiyun 		mfspr(SPRN_MMCR3), mfspr(SPRN_SIER2), mfspr(SPRN_SIER3));
2044*4882a593Smuzhiyun 
2045*4882a593Smuzhiyun #endif
2046*4882a593Smuzhiyun }
2047*4882a593Smuzhiyun 
dump_one_spr(int spr,bool show_unimplemented)2048*4882a593Smuzhiyun static void dump_one_spr(int spr, bool show_unimplemented)
2049*4882a593Smuzhiyun {
2050*4882a593Smuzhiyun 	unsigned long val;
2051*4882a593Smuzhiyun 
2052*4882a593Smuzhiyun 	val = 0xdeadbeef;
2053*4882a593Smuzhiyun 	if (!read_spr(spr, &val)) {
2054*4882a593Smuzhiyun 		printf("SPR 0x%03x (%4d) Faulted during read\n", spr, spr);
2055*4882a593Smuzhiyun 		return;
2056*4882a593Smuzhiyun 	}
2057*4882a593Smuzhiyun 
2058*4882a593Smuzhiyun 	if (val == 0xdeadbeef) {
2059*4882a593Smuzhiyun 		/* Looks like read was a nop, confirm */
2060*4882a593Smuzhiyun 		val = 0x0badcafe;
2061*4882a593Smuzhiyun 		if (!read_spr(spr, &val)) {
2062*4882a593Smuzhiyun 			printf("SPR 0x%03x (%4d) Faulted during read\n", spr, spr);
2063*4882a593Smuzhiyun 			return;
2064*4882a593Smuzhiyun 		}
2065*4882a593Smuzhiyun 
2066*4882a593Smuzhiyun 		if (val == 0x0badcafe) {
2067*4882a593Smuzhiyun 			if (show_unimplemented)
2068*4882a593Smuzhiyun 				printf("SPR 0x%03x (%4d) Unimplemented\n", spr, spr);
2069*4882a593Smuzhiyun 			return;
2070*4882a593Smuzhiyun 		}
2071*4882a593Smuzhiyun 	}
2072*4882a593Smuzhiyun 
2073*4882a593Smuzhiyun 	printf("SPR 0x%03x (%4d) = 0x%lx\n", spr, spr, val);
2074*4882a593Smuzhiyun }
2075*4882a593Smuzhiyun 
super_regs(void)2076*4882a593Smuzhiyun static void super_regs(void)
2077*4882a593Smuzhiyun {
2078*4882a593Smuzhiyun 	static unsigned long regno;
2079*4882a593Smuzhiyun 	int cmd;
2080*4882a593Smuzhiyun 	int spr;
2081*4882a593Smuzhiyun 
2082*4882a593Smuzhiyun 	cmd = skipbl();
2083*4882a593Smuzhiyun 
2084*4882a593Smuzhiyun 	switch (cmd) {
2085*4882a593Smuzhiyun 	case '\n': {
2086*4882a593Smuzhiyun 		unsigned long sp, toc;
2087*4882a593Smuzhiyun 		asm("mr %0,1" : "=r" (sp) :);
2088*4882a593Smuzhiyun 		asm("mr %0,2" : "=r" (toc) :);
2089*4882a593Smuzhiyun 
2090*4882a593Smuzhiyun 		printf("msr    = "REG"  sprg0 = "REG"\n",
2091*4882a593Smuzhiyun 		       mfmsr(), mfspr(SPRN_SPRG0));
2092*4882a593Smuzhiyun 		printf("pvr    = "REG"  sprg1 = "REG"\n",
2093*4882a593Smuzhiyun 		       mfspr(SPRN_PVR), mfspr(SPRN_SPRG1));
2094*4882a593Smuzhiyun 		printf("dec    = "REG"  sprg2 = "REG"\n",
2095*4882a593Smuzhiyun 		       mfspr(SPRN_DEC), mfspr(SPRN_SPRG2));
2096*4882a593Smuzhiyun 		printf("sp     = "REG"  sprg3 = "REG"\n", sp, mfspr(SPRN_SPRG3));
2097*4882a593Smuzhiyun 		printf("toc    = "REG"  dar   = "REG"\n", toc, mfspr(SPRN_DAR));
2098*4882a593Smuzhiyun 
2099*4882a593Smuzhiyun 		dump_206_sprs();
2100*4882a593Smuzhiyun 		dump_207_sprs();
2101*4882a593Smuzhiyun 		dump_300_sprs();
2102*4882a593Smuzhiyun 		dump_310_sprs();
2103*4882a593Smuzhiyun 
2104*4882a593Smuzhiyun 		return;
2105*4882a593Smuzhiyun 	}
2106*4882a593Smuzhiyun 	case 'w': {
2107*4882a593Smuzhiyun 		unsigned long val;
2108*4882a593Smuzhiyun 		scanhex(&regno);
2109*4882a593Smuzhiyun 		val = 0;
2110*4882a593Smuzhiyun 		read_spr(regno, &val);
2111*4882a593Smuzhiyun 		scanhex(&val);
2112*4882a593Smuzhiyun 		write_spr(regno, val);
2113*4882a593Smuzhiyun 		dump_one_spr(regno, true);
2114*4882a593Smuzhiyun 		break;
2115*4882a593Smuzhiyun 	}
2116*4882a593Smuzhiyun 	case 'r':
2117*4882a593Smuzhiyun 		scanhex(&regno);
2118*4882a593Smuzhiyun 		dump_one_spr(regno, true);
2119*4882a593Smuzhiyun 		break;
2120*4882a593Smuzhiyun 	case 'a':
2121*4882a593Smuzhiyun 		/* dump ALL SPRs */
2122*4882a593Smuzhiyun 		for (spr = 1; spr < 1024; ++spr)
2123*4882a593Smuzhiyun 			dump_one_spr(spr, false);
2124*4882a593Smuzhiyun 		break;
2125*4882a593Smuzhiyun 	}
2126*4882a593Smuzhiyun 
2127*4882a593Smuzhiyun 	scannl();
2128*4882a593Smuzhiyun }
2129*4882a593Smuzhiyun 
2130*4882a593Smuzhiyun /*
2131*4882a593Smuzhiyun  * Stuff for reading and writing memory safely
2132*4882a593Smuzhiyun  */
2133*4882a593Smuzhiyun static int
mread(unsigned long adrs,void * buf,int size)2134*4882a593Smuzhiyun mread(unsigned long adrs, void *buf, int size)
2135*4882a593Smuzhiyun {
2136*4882a593Smuzhiyun 	volatile int n;
2137*4882a593Smuzhiyun 	char *p, *q;
2138*4882a593Smuzhiyun 
2139*4882a593Smuzhiyun 	n = 0;
2140*4882a593Smuzhiyun 	if (setjmp(bus_error_jmp) == 0) {
2141*4882a593Smuzhiyun 		catch_memory_errors = 1;
2142*4882a593Smuzhiyun 		sync();
2143*4882a593Smuzhiyun 		p = (char *)adrs;
2144*4882a593Smuzhiyun 		q = (char *)buf;
2145*4882a593Smuzhiyun 		switch (size) {
2146*4882a593Smuzhiyun 		case 2:
2147*4882a593Smuzhiyun 			*(u16 *)q = *(u16 *)p;
2148*4882a593Smuzhiyun 			break;
2149*4882a593Smuzhiyun 		case 4:
2150*4882a593Smuzhiyun 			*(u32 *)q = *(u32 *)p;
2151*4882a593Smuzhiyun 			break;
2152*4882a593Smuzhiyun 		case 8:
2153*4882a593Smuzhiyun 			*(u64 *)q = *(u64 *)p;
2154*4882a593Smuzhiyun 			break;
2155*4882a593Smuzhiyun 		default:
2156*4882a593Smuzhiyun 			for( ; n < size; ++n) {
2157*4882a593Smuzhiyun 				*q++ = *p++;
2158*4882a593Smuzhiyun 				sync();
2159*4882a593Smuzhiyun 			}
2160*4882a593Smuzhiyun 		}
2161*4882a593Smuzhiyun 		sync();
2162*4882a593Smuzhiyun 		/* wait a little while to see if we get a machine check */
2163*4882a593Smuzhiyun 		__delay(200);
2164*4882a593Smuzhiyun 		n = size;
2165*4882a593Smuzhiyun 	}
2166*4882a593Smuzhiyun 	catch_memory_errors = 0;
2167*4882a593Smuzhiyun 	return n;
2168*4882a593Smuzhiyun }
2169*4882a593Smuzhiyun 
2170*4882a593Smuzhiyun static int
mwrite(unsigned long adrs,void * buf,int size)2171*4882a593Smuzhiyun mwrite(unsigned long adrs, void *buf, int size)
2172*4882a593Smuzhiyun {
2173*4882a593Smuzhiyun 	volatile int n;
2174*4882a593Smuzhiyun 	char *p, *q;
2175*4882a593Smuzhiyun 
2176*4882a593Smuzhiyun 	n = 0;
2177*4882a593Smuzhiyun 
2178*4882a593Smuzhiyun 	if (xmon_is_ro) {
2179*4882a593Smuzhiyun 		printf(xmon_ro_msg);
2180*4882a593Smuzhiyun 		return n;
2181*4882a593Smuzhiyun 	}
2182*4882a593Smuzhiyun 
2183*4882a593Smuzhiyun 	if (setjmp(bus_error_jmp) == 0) {
2184*4882a593Smuzhiyun 		catch_memory_errors = 1;
2185*4882a593Smuzhiyun 		sync();
2186*4882a593Smuzhiyun 		p = (char *) adrs;
2187*4882a593Smuzhiyun 		q = (char *) buf;
2188*4882a593Smuzhiyun 		switch (size) {
2189*4882a593Smuzhiyun 		case 2:
2190*4882a593Smuzhiyun 			*(u16 *)p = *(u16 *)q;
2191*4882a593Smuzhiyun 			break;
2192*4882a593Smuzhiyun 		case 4:
2193*4882a593Smuzhiyun 			*(u32 *)p = *(u32 *)q;
2194*4882a593Smuzhiyun 			break;
2195*4882a593Smuzhiyun 		case 8:
2196*4882a593Smuzhiyun 			*(u64 *)p = *(u64 *)q;
2197*4882a593Smuzhiyun 			break;
2198*4882a593Smuzhiyun 		default:
2199*4882a593Smuzhiyun 			for ( ; n < size; ++n) {
2200*4882a593Smuzhiyun 				*p++ = *q++;
2201*4882a593Smuzhiyun 				sync();
2202*4882a593Smuzhiyun 			}
2203*4882a593Smuzhiyun 		}
2204*4882a593Smuzhiyun 		sync();
2205*4882a593Smuzhiyun 		/* wait a little while to see if we get a machine check */
2206*4882a593Smuzhiyun 		__delay(200);
2207*4882a593Smuzhiyun 		n = size;
2208*4882a593Smuzhiyun 	} else {
2209*4882a593Smuzhiyun 		printf("*** Error writing address "REG"\n", adrs + n);
2210*4882a593Smuzhiyun 	}
2211*4882a593Smuzhiyun 	catch_memory_errors = 0;
2212*4882a593Smuzhiyun 	return n;
2213*4882a593Smuzhiyun }
2214*4882a593Smuzhiyun 
2215*4882a593Smuzhiyun static int
mread_instr(unsigned long adrs,struct ppc_inst * instr)2216*4882a593Smuzhiyun mread_instr(unsigned long adrs, struct ppc_inst *instr)
2217*4882a593Smuzhiyun {
2218*4882a593Smuzhiyun 	volatile int n;
2219*4882a593Smuzhiyun 
2220*4882a593Smuzhiyun 	n = 0;
2221*4882a593Smuzhiyun 	if (setjmp(bus_error_jmp) == 0) {
2222*4882a593Smuzhiyun 		catch_memory_errors = 1;
2223*4882a593Smuzhiyun 		sync();
2224*4882a593Smuzhiyun 		*instr = ppc_inst_read((struct ppc_inst *)adrs);
2225*4882a593Smuzhiyun 		sync();
2226*4882a593Smuzhiyun 		/* wait a little while to see if we get a machine check */
2227*4882a593Smuzhiyun 		__delay(200);
2228*4882a593Smuzhiyun 		n = ppc_inst_len(*instr);
2229*4882a593Smuzhiyun 	}
2230*4882a593Smuzhiyun 	catch_memory_errors = 0;
2231*4882a593Smuzhiyun 	return n;
2232*4882a593Smuzhiyun }
2233*4882a593Smuzhiyun 
2234*4882a593Smuzhiyun static int fault_type;
2235*4882a593Smuzhiyun static int fault_except;
2236*4882a593Smuzhiyun static char *fault_chars[] = { "--", "**", "##" };
2237*4882a593Smuzhiyun 
handle_fault(struct pt_regs * regs)2238*4882a593Smuzhiyun static int handle_fault(struct pt_regs *regs)
2239*4882a593Smuzhiyun {
2240*4882a593Smuzhiyun 	fault_except = TRAP(regs);
2241*4882a593Smuzhiyun 	switch (TRAP(regs)) {
2242*4882a593Smuzhiyun 	case 0x200:
2243*4882a593Smuzhiyun 		fault_type = 0;
2244*4882a593Smuzhiyun 		break;
2245*4882a593Smuzhiyun 	case 0x300:
2246*4882a593Smuzhiyun 	case 0x380:
2247*4882a593Smuzhiyun 		fault_type = 1;
2248*4882a593Smuzhiyun 		break;
2249*4882a593Smuzhiyun 	default:
2250*4882a593Smuzhiyun 		fault_type = 2;
2251*4882a593Smuzhiyun 	}
2252*4882a593Smuzhiyun 
2253*4882a593Smuzhiyun 	longjmp(bus_error_jmp, 1);
2254*4882a593Smuzhiyun 
2255*4882a593Smuzhiyun 	return 0;
2256*4882a593Smuzhiyun }
2257*4882a593Smuzhiyun 
2258*4882a593Smuzhiyun #define SWAP(a, b, t)	((t) = (a), (a) = (b), (b) = (t))
2259*4882a593Smuzhiyun 
2260*4882a593Smuzhiyun static void
byterev(unsigned char * val,int size)2261*4882a593Smuzhiyun byterev(unsigned char *val, int size)
2262*4882a593Smuzhiyun {
2263*4882a593Smuzhiyun 	int t;
2264*4882a593Smuzhiyun 
2265*4882a593Smuzhiyun 	switch (size) {
2266*4882a593Smuzhiyun 	case 2:
2267*4882a593Smuzhiyun 		SWAP(val[0], val[1], t);
2268*4882a593Smuzhiyun 		break;
2269*4882a593Smuzhiyun 	case 4:
2270*4882a593Smuzhiyun 		SWAP(val[0], val[3], t);
2271*4882a593Smuzhiyun 		SWAP(val[1], val[2], t);
2272*4882a593Smuzhiyun 		break;
2273*4882a593Smuzhiyun 	case 8: /* is there really any use for this? */
2274*4882a593Smuzhiyun 		SWAP(val[0], val[7], t);
2275*4882a593Smuzhiyun 		SWAP(val[1], val[6], t);
2276*4882a593Smuzhiyun 		SWAP(val[2], val[5], t);
2277*4882a593Smuzhiyun 		SWAP(val[3], val[4], t);
2278*4882a593Smuzhiyun 		break;
2279*4882a593Smuzhiyun 	}
2280*4882a593Smuzhiyun }
2281*4882a593Smuzhiyun 
2282*4882a593Smuzhiyun static int brev;
2283*4882a593Smuzhiyun static int mnoread;
2284*4882a593Smuzhiyun 
2285*4882a593Smuzhiyun static char *memex_help_string =
2286*4882a593Smuzhiyun     "Memory examine command usage:\n"
2287*4882a593Smuzhiyun     "m [addr] [flags] examine/change memory\n"
2288*4882a593Smuzhiyun     "  addr is optional.  will start where left off.\n"
2289*4882a593Smuzhiyun     "  flags may include chars from this set:\n"
2290*4882a593Smuzhiyun     "    b   modify by bytes (default)\n"
2291*4882a593Smuzhiyun     "    w   modify by words (2 byte)\n"
2292*4882a593Smuzhiyun     "    l   modify by longs (4 byte)\n"
2293*4882a593Smuzhiyun     "    d   modify by doubleword (8 byte)\n"
2294*4882a593Smuzhiyun     "    r   toggle reverse byte order mode\n"
2295*4882a593Smuzhiyun     "    n   do not read memory (for i/o spaces)\n"
2296*4882a593Smuzhiyun     "    .   ok to read (default)\n"
2297*4882a593Smuzhiyun     "NOTE: flags are saved as defaults\n"
2298*4882a593Smuzhiyun     "";
2299*4882a593Smuzhiyun 
2300*4882a593Smuzhiyun static char *memex_subcmd_help_string =
2301*4882a593Smuzhiyun     "Memory examine subcommands:\n"
2302*4882a593Smuzhiyun     "  hexval   write this val to current location\n"
2303*4882a593Smuzhiyun     "  'string' write chars from string to this location\n"
2304*4882a593Smuzhiyun     "  '        increment address\n"
2305*4882a593Smuzhiyun     "  ^        decrement address\n"
2306*4882a593Smuzhiyun     "  /        increment addr by 0x10.  //=0x100, ///=0x1000, etc\n"
2307*4882a593Smuzhiyun     "  \\        decrement addr by 0x10.  \\\\=0x100, \\\\\\=0x1000, etc\n"
2308*4882a593Smuzhiyun     "  `        clear no-read flag\n"
2309*4882a593Smuzhiyun     "  ;        stay at this addr\n"
2310*4882a593Smuzhiyun     "  v        change to byte mode\n"
2311*4882a593Smuzhiyun     "  w        change to word (2 byte) mode\n"
2312*4882a593Smuzhiyun     "  l        change to long (4 byte) mode\n"
2313*4882a593Smuzhiyun     "  u        change to doubleword (8 byte) mode\n"
2314*4882a593Smuzhiyun     "  m addr   change current addr\n"
2315*4882a593Smuzhiyun     "  n        toggle no-read flag\n"
2316*4882a593Smuzhiyun     "  r        toggle byte reverse flag\n"
2317*4882a593Smuzhiyun     "  < count  back up count bytes\n"
2318*4882a593Smuzhiyun     "  > count  skip forward count bytes\n"
2319*4882a593Smuzhiyun     "  x        exit this mode\n"
2320*4882a593Smuzhiyun     "";
2321*4882a593Smuzhiyun 
2322*4882a593Smuzhiyun static void
memex(void)2323*4882a593Smuzhiyun memex(void)
2324*4882a593Smuzhiyun {
2325*4882a593Smuzhiyun 	int cmd, inc, i, nslash;
2326*4882a593Smuzhiyun 	unsigned long n;
2327*4882a593Smuzhiyun 	unsigned char val[16];
2328*4882a593Smuzhiyun 
2329*4882a593Smuzhiyun 	scanhex((void *)&adrs);
2330*4882a593Smuzhiyun 	cmd = skipbl();
2331*4882a593Smuzhiyun 	if (cmd == '?') {
2332*4882a593Smuzhiyun 		printf(memex_help_string);
2333*4882a593Smuzhiyun 		return;
2334*4882a593Smuzhiyun 	} else {
2335*4882a593Smuzhiyun 		termch = cmd;
2336*4882a593Smuzhiyun 	}
2337*4882a593Smuzhiyun 	last_cmd = "m\n";
2338*4882a593Smuzhiyun 	while ((cmd = skipbl()) != '\n') {
2339*4882a593Smuzhiyun 		switch( cmd ){
2340*4882a593Smuzhiyun 		case 'b':	size = 1;	break;
2341*4882a593Smuzhiyun 		case 'w':	size = 2;	break;
2342*4882a593Smuzhiyun 		case 'l':	size = 4;	break;
2343*4882a593Smuzhiyun 		case 'd':	size = 8;	break;
2344*4882a593Smuzhiyun 		case 'r': 	brev = !brev;	break;
2345*4882a593Smuzhiyun 		case 'n':	mnoread = 1;	break;
2346*4882a593Smuzhiyun 		case '.':	mnoread = 0;	break;
2347*4882a593Smuzhiyun 		}
2348*4882a593Smuzhiyun 	}
2349*4882a593Smuzhiyun 	if( size <= 0 )
2350*4882a593Smuzhiyun 		size = 1;
2351*4882a593Smuzhiyun 	else if( size > 8 )
2352*4882a593Smuzhiyun 		size = 8;
2353*4882a593Smuzhiyun 	for(;;){
2354*4882a593Smuzhiyun 		if (!mnoread)
2355*4882a593Smuzhiyun 			n = mread(adrs, val, size);
2356*4882a593Smuzhiyun 		printf(REG"%c", adrs, brev? 'r': ' ');
2357*4882a593Smuzhiyun 		if (!mnoread) {
2358*4882a593Smuzhiyun 			if (brev)
2359*4882a593Smuzhiyun 				byterev(val, size);
2360*4882a593Smuzhiyun 			putchar(' ');
2361*4882a593Smuzhiyun 			for (i = 0; i < n; ++i)
2362*4882a593Smuzhiyun 				printf("%.2x", val[i]);
2363*4882a593Smuzhiyun 			for (; i < size; ++i)
2364*4882a593Smuzhiyun 				printf("%s", fault_chars[fault_type]);
2365*4882a593Smuzhiyun 		}
2366*4882a593Smuzhiyun 		putchar(' ');
2367*4882a593Smuzhiyun 		inc = size;
2368*4882a593Smuzhiyun 		nslash = 0;
2369*4882a593Smuzhiyun 		for(;;){
2370*4882a593Smuzhiyun 			if( scanhex(&n) ){
2371*4882a593Smuzhiyun 				for (i = 0; i < size; ++i)
2372*4882a593Smuzhiyun 					val[i] = n >> (i * 8);
2373*4882a593Smuzhiyun 				if (!brev)
2374*4882a593Smuzhiyun 					byterev(val, size);
2375*4882a593Smuzhiyun 				mwrite(adrs, val, size);
2376*4882a593Smuzhiyun 				inc = size;
2377*4882a593Smuzhiyun 			}
2378*4882a593Smuzhiyun 			cmd = skipbl();
2379*4882a593Smuzhiyun 			if (cmd == '\n')
2380*4882a593Smuzhiyun 				break;
2381*4882a593Smuzhiyun 			inc = 0;
2382*4882a593Smuzhiyun 			switch (cmd) {
2383*4882a593Smuzhiyun 			case '\'':
2384*4882a593Smuzhiyun 				for(;;){
2385*4882a593Smuzhiyun 					n = inchar();
2386*4882a593Smuzhiyun 					if( n == '\\' )
2387*4882a593Smuzhiyun 						n = bsesc();
2388*4882a593Smuzhiyun 					else if( n == '\'' )
2389*4882a593Smuzhiyun 						break;
2390*4882a593Smuzhiyun 					for (i = 0; i < size; ++i)
2391*4882a593Smuzhiyun 						val[i] = n >> (i * 8);
2392*4882a593Smuzhiyun 					if (!brev)
2393*4882a593Smuzhiyun 						byterev(val, size);
2394*4882a593Smuzhiyun 					mwrite(adrs, val, size);
2395*4882a593Smuzhiyun 					adrs += size;
2396*4882a593Smuzhiyun 				}
2397*4882a593Smuzhiyun 				adrs -= size;
2398*4882a593Smuzhiyun 				inc = size;
2399*4882a593Smuzhiyun 				break;
2400*4882a593Smuzhiyun 			case ',':
2401*4882a593Smuzhiyun 				adrs += size;
2402*4882a593Smuzhiyun 				break;
2403*4882a593Smuzhiyun 			case '.':
2404*4882a593Smuzhiyun 				mnoread = 0;
2405*4882a593Smuzhiyun 				break;
2406*4882a593Smuzhiyun 			case ';':
2407*4882a593Smuzhiyun 				break;
2408*4882a593Smuzhiyun 			case 'x':
2409*4882a593Smuzhiyun 			case EOF:
2410*4882a593Smuzhiyun 				scannl();
2411*4882a593Smuzhiyun 				return;
2412*4882a593Smuzhiyun 			case 'b':
2413*4882a593Smuzhiyun 			case 'v':
2414*4882a593Smuzhiyun 				size = 1;
2415*4882a593Smuzhiyun 				break;
2416*4882a593Smuzhiyun 			case 'w':
2417*4882a593Smuzhiyun 				size = 2;
2418*4882a593Smuzhiyun 				break;
2419*4882a593Smuzhiyun 			case 'l':
2420*4882a593Smuzhiyun 				size = 4;
2421*4882a593Smuzhiyun 				break;
2422*4882a593Smuzhiyun 			case 'u':
2423*4882a593Smuzhiyun 				size = 8;
2424*4882a593Smuzhiyun 				break;
2425*4882a593Smuzhiyun 			case '^':
2426*4882a593Smuzhiyun 				adrs -= size;
2427*4882a593Smuzhiyun 				break;
2428*4882a593Smuzhiyun 			case '/':
2429*4882a593Smuzhiyun 				if (nslash > 0)
2430*4882a593Smuzhiyun 					adrs -= 1 << nslash;
2431*4882a593Smuzhiyun 				else
2432*4882a593Smuzhiyun 					nslash = 0;
2433*4882a593Smuzhiyun 				nslash += 4;
2434*4882a593Smuzhiyun 				adrs += 1 << nslash;
2435*4882a593Smuzhiyun 				break;
2436*4882a593Smuzhiyun 			case '\\':
2437*4882a593Smuzhiyun 				if (nslash < 0)
2438*4882a593Smuzhiyun 					adrs += 1 << -nslash;
2439*4882a593Smuzhiyun 				else
2440*4882a593Smuzhiyun 					nslash = 0;
2441*4882a593Smuzhiyun 				nslash -= 4;
2442*4882a593Smuzhiyun 				adrs -= 1 << -nslash;
2443*4882a593Smuzhiyun 				break;
2444*4882a593Smuzhiyun 			case 'm':
2445*4882a593Smuzhiyun 				scanhex((void *)&adrs);
2446*4882a593Smuzhiyun 				break;
2447*4882a593Smuzhiyun 			case 'n':
2448*4882a593Smuzhiyun 				mnoread = 1;
2449*4882a593Smuzhiyun 				break;
2450*4882a593Smuzhiyun 			case 'r':
2451*4882a593Smuzhiyun 				brev = !brev;
2452*4882a593Smuzhiyun 				break;
2453*4882a593Smuzhiyun 			case '<':
2454*4882a593Smuzhiyun 				n = size;
2455*4882a593Smuzhiyun 				scanhex(&n);
2456*4882a593Smuzhiyun 				adrs -= n;
2457*4882a593Smuzhiyun 				break;
2458*4882a593Smuzhiyun 			case '>':
2459*4882a593Smuzhiyun 				n = size;
2460*4882a593Smuzhiyun 				scanhex(&n);
2461*4882a593Smuzhiyun 				adrs += n;
2462*4882a593Smuzhiyun 				break;
2463*4882a593Smuzhiyun 			case '?':
2464*4882a593Smuzhiyun 				printf(memex_subcmd_help_string);
2465*4882a593Smuzhiyun 				break;
2466*4882a593Smuzhiyun 			}
2467*4882a593Smuzhiyun 		}
2468*4882a593Smuzhiyun 		adrs += inc;
2469*4882a593Smuzhiyun 	}
2470*4882a593Smuzhiyun }
2471*4882a593Smuzhiyun 
2472*4882a593Smuzhiyun static int
bsesc(void)2473*4882a593Smuzhiyun bsesc(void)
2474*4882a593Smuzhiyun {
2475*4882a593Smuzhiyun 	int c;
2476*4882a593Smuzhiyun 
2477*4882a593Smuzhiyun 	c = inchar();
2478*4882a593Smuzhiyun 	switch( c ){
2479*4882a593Smuzhiyun 	case 'n':	c = '\n';	break;
2480*4882a593Smuzhiyun 	case 'r':	c = '\r';	break;
2481*4882a593Smuzhiyun 	case 'b':	c = '\b';	break;
2482*4882a593Smuzhiyun 	case 't':	c = '\t';	break;
2483*4882a593Smuzhiyun 	}
2484*4882a593Smuzhiyun 	return c;
2485*4882a593Smuzhiyun }
2486*4882a593Smuzhiyun 
xmon_rawdump(unsigned long adrs,long ndump)2487*4882a593Smuzhiyun static void xmon_rawdump (unsigned long adrs, long ndump)
2488*4882a593Smuzhiyun {
2489*4882a593Smuzhiyun 	long n, m, r, nr;
2490*4882a593Smuzhiyun 	unsigned char temp[16];
2491*4882a593Smuzhiyun 
2492*4882a593Smuzhiyun 	for (n = ndump; n > 0;) {
2493*4882a593Smuzhiyun 		r = n < 16? n: 16;
2494*4882a593Smuzhiyun 		nr = mread(adrs, temp, r);
2495*4882a593Smuzhiyun 		adrs += nr;
2496*4882a593Smuzhiyun 		for (m = 0; m < r; ++m) {
2497*4882a593Smuzhiyun 			if (m < nr)
2498*4882a593Smuzhiyun 				printf("%.2x", temp[m]);
2499*4882a593Smuzhiyun 			else
2500*4882a593Smuzhiyun 				printf("%s", fault_chars[fault_type]);
2501*4882a593Smuzhiyun 		}
2502*4882a593Smuzhiyun 		n -= r;
2503*4882a593Smuzhiyun 		if (nr < r)
2504*4882a593Smuzhiyun 			break;
2505*4882a593Smuzhiyun 	}
2506*4882a593Smuzhiyun 	printf("\n");
2507*4882a593Smuzhiyun }
2508*4882a593Smuzhiyun 
dump_tracing(void)2509*4882a593Smuzhiyun static void dump_tracing(void)
2510*4882a593Smuzhiyun {
2511*4882a593Smuzhiyun 	int c;
2512*4882a593Smuzhiyun 
2513*4882a593Smuzhiyun 	c = inchar();
2514*4882a593Smuzhiyun 	if (c == 'c')
2515*4882a593Smuzhiyun 		ftrace_dump(DUMP_ORIG);
2516*4882a593Smuzhiyun 	else
2517*4882a593Smuzhiyun 		ftrace_dump(DUMP_ALL);
2518*4882a593Smuzhiyun }
2519*4882a593Smuzhiyun 
2520*4882a593Smuzhiyun #ifdef CONFIG_PPC64
dump_one_paca(int cpu)2521*4882a593Smuzhiyun static void dump_one_paca(int cpu)
2522*4882a593Smuzhiyun {
2523*4882a593Smuzhiyun 	struct paca_struct *p;
2524*4882a593Smuzhiyun #ifdef CONFIG_PPC_BOOK3S_64
2525*4882a593Smuzhiyun 	int i = 0;
2526*4882a593Smuzhiyun #endif
2527*4882a593Smuzhiyun 
2528*4882a593Smuzhiyun 	if (setjmp(bus_error_jmp) != 0) {
2529*4882a593Smuzhiyun 		printf("*** Error dumping paca for cpu 0x%x!\n", cpu);
2530*4882a593Smuzhiyun 		return;
2531*4882a593Smuzhiyun 	}
2532*4882a593Smuzhiyun 
2533*4882a593Smuzhiyun 	catch_memory_errors = 1;
2534*4882a593Smuzhiyun 	sync();
2535*4882a593Smuzhiyun 
2536*4882a593Smuzhiyun 	p = paca_ptrs[cpu];
2537*4882a593Smuzhiyun 
2538*4882a593Smuzhiyun 	printf("paca for cpu 0x%x @ %px:\n", cpu, p);
2539*4882a593Smuzhiyun 
2540*4882a593Smuzhiyun 	printf(" %-*s = %s\n", 25, "possible", cpu_possible(cpu) ? "yes" : "no");
2541*4882a593Smuzhiyun 	printf(" %-*s = %s\n", 25, "present", cpu_present(cpu) ? "yes" : "no");
2542*4882a593Smuzhiyun 	printf(" %-*s = %s\n", 25, "online", cpu_online(cpu) ? "yes" : "no");
2543*4882a593Smuzhiyun 
2544*4882a593Smuzhiyun #define DUMP(paca, name, format)				\
2545*4882a593Smuzhiyun 	printf(" %-*s = "format"\t(0x%lx)\n", 25, #name, 18, paca->name, \
2546*4882a593Smuzhiyun 		offsetof(struct paca_struct, name));
2547*4882a593Smuzhiyun 
2548*4882a593Smuzhiyun 	DUMP(p, lock_token, "%#-*x");
2549*4882a593Smuzhiyun 	DUMP(p, paca_index, "%#-*x");
2550*4882a593Smuzhiyun 	DUMP(p, kernel_toc, "%#-*llx");
2551*4882a593Smuzhiyun 	DUMP(p, kernelbase, "%#-*llx");
2552*4882a593Smuzhiyun 	DUMP(p, kernel_msr, "%#-*llx");
2553*4882a593Smuzhiyun 	DUMP(p, emergency_sp, "%-*px");
2554*4882a593Smuzhiyun #ifdef CONFIG_PPC_BOOK3S_64
2555*4882a593Smuzhiyun 	DUMP(p, nmi_emergency_sp, "%-*px");
2556*4882a593Smuzhiyun 	DUMP(p, mc_emergency_sp, "%-*px");
2557*4882a593Smuzhiyun 	DUMP(p, in_nmi, "%#-*x");
2558*4882a593Smuzhiyun 	DUMP(p, in_mce, "%#-*x");
2559*4882a593Smuzhiyun 	DUMP(p, hmi_event_available, "%#-*x");
2560*4882a593Smuzhiyun #endif
2561*4882a593Smuzhiyun 	DUMP(p, data_offset, "%#-*llx");
2562*4882a593Smuzhiyun 	DUMP(p, hw_cpu_id, "%#-*x");
2563*4882a593Smuzhiyun 	DUMP(p, cpu_start, "%#-*x");
2564*4882a593Smuzhiyun 	DUMP(p, kexec_state, "%#-*x");
2565*4882a593Smuzhiyun #ifdef CONFIG_PPC_BOOK3S_64
2566*4882a593Smuzhiyun 	if (!early_radix_enabled()) {
2567*4882a593Smuzhiyun 		for (i = 0; i < SLB_NUM_BOLTED; i++) {
2568*4882a593Smuzhiyun 			u64 esid, vsid;
2569*4882a593Smuzhiyun 
2570*4882a593Smuzhiyun 			if (!p->slb_shadow_ptr)
2571*4882a593Smuzhiyun 				continue;
2572*4882a593Smuzhiyun 
2573*4882a593Smuzhiyun 			esid = be64_to_cpu(p->slb_shadow_ptr->save_area[i].esid);
2574*4882a593Smuzhiyun 			vsid = be64_to_cpu(p->slb_shadow_ptr->save_area[i].vsid);
2575*4882a593Smuzhiyun 
2576*4882a593Smuzhiyun 			if (esid || vsid) {
2577*4882a593Smuzhiyun 				printf(" %-*s[%d] = 0x%016llx 0x%016llx\n",
2578*4882a593Smuzhiyun 				       22, "slb_shadow", i, esid, vsid);
2579*4882a593Smuzhiyun 			}
2580*4882a593Smuzhiyun 		}
2581*4882a593Smuzhiyun 		DUMP(p, vmalloc_sllp, "%#-*x");
2582*4882a593Smuzhiyun 		DUMP(p, stab_rr, "%#-*x");
2583*4882a593Smuzhiyun 		DUMP(p, slb_used_bitmap, "%#-*x");
2584*4882a593Smuzhiyun 		DUMP(p, slb_kern_bitmap, "%#-*x");
2585*4882a593Smuzhiyun 
2586*4882a593Smuzhiyun 		if (!early_cpu_has_feature(CPU_FTR_ARCH_300)) {
2587*4882a593Smuzhiyun 			DUMP(p, slb_cache_ptr, "%#-*x");
2588*4882a593Smuzhiyun 			for (i = 0; i < SLB_CACHE_ENTRIES; i++)
2589*4882a593Smuzhiyun 				printf(" %-*s[%d] = 0x%016x\n",
2590*4882a593Smuzhiyun 				       22, "slb_cache", i, p->slb_cache[i]);
2591*4882a593Smuzhiyun 		}
2592*4882a593Smuzhiyun 	}
2593*4882a593Smuzhiyun 
2594*4882a593Smuzhiyun 	DUMP(p, rfi_flush_fallback_area, "%-*px");
2595*4882a593Smuzhiyun #endif
2596*4882a593Smuzhiyun 	DUMP(p, dscr_default, "%#-*llx");
2597*4882a593Smuzhiyun #ifdef CONFIG_PPC_BOOK3E
2598*4882a593Smuzhiyun 	DUMP(p, pgd, "%-*px");
2599*4882a593Smuzhiyun 	DUMP(p, kernel_pgd, "%-*px");
2600*4882a593Smuzhiyun 	DUMP(p, tcd_ptr, "%-*px");
2601*4882a593Smuzhiyun 	DUMP(p, mc_kstack, "%-*px");
2602*4882a593Smuzhiyun 	DUMP(p, crit_kstack, "%-*px");
2603*4882a593Smuzhiyun 	DUMP(p, dbg_kstack, "%-*px");
2604*4882a593Smuzhiyun #endif
2605*4882a593Smuzhiyun 	DUMP(p, __current, "%-*px");
2606*4882a593Smuzhiyun 	DUMP(p, kstack, "%#-*llx");
2607*4882a593Smuzhiyun 	printf(" %-*s = 0x%016llx\n", 25, "kstack_base", p->kstack & ~(THREAD_SIZE - 1));
2608*4882a593Smuzhiyun #ifdef CONFIG_STACKPROTECTOR
2609*4882a593Smuzhiyun 	DUMP(p, canary, "%#-*lx");
2610*4882a593Smuzhiyun #endif
2611*4882a593Smuzhiyun 	DUMP(p, saved_r1, "%#-*llx");
2612*4882a593Smuzhiyun #ifdef CONFIG_PPC_BOOK3E
2613*4882a593Smuzhiyun 	DUMP(p, trap_save, "%#-*x");
2614*4882a593Smuzhiyun #endif
2615*4882a593Smuzhiyun 	DUMP(p, irq_soft_mask, "%#-*x");
2616*4882a593Smuzhiyun 	DUMP(p, irq_happened, "%#-*x");
2617*4882a593Smuzhiyun #ifdef CONFIG_MMIOWB
2618*4882a593Smuzhiyun 	DUMP(p, mmiowb_state.nesting_count, "%#-*x");
2619*4882a593Smuzhiyun 	DUMP(p, mmiowb_state.mmiowb_pending, "%#-*x");
2620*4882a593Smuzhiyun #endif
2621*4882a593Smuzhiyun 	DUMP(p, irq_work_pending, "%#-*x");
2622*4882a593Smuzhiyun 	DUMP(p, sprg_vdso, "%#-*llx");
2623*4882a593Smuzhiyun 
2624*4882a593Smuzhiyun #ifdef CONFIG_PPC_TRANSACTIONAL_MEM
2625*4882a593Smuzhiyun 	DUMP(p, tm_scratch, "%#-*llx");
2626*4882a593Smuzhiyun #endif
2627*4882a593Smuzhiyun 
2628*4882a593Smuzhiyun #ifdef CONFIG_PPC_POWERNV
2629*4882a593Smuzhiyun 	DUMP(p, idle_state, "%#-*lx");
2630*4882a593Smuzhiyun 	if (!early_cpu_has_feature(CPU_FTR_ARCH_300)) {
2631*4882a593Smuzhiyun 		DUMP(p, thread_idle_state, "%#-*x");
2632*4882a593Smuzhiyun 		DUMP(p, subcore_sibling_mask, "%#-*x");
2633*4882a593Smuzhiyun 	} else {
2634*4882a593Smuzhiyun #ifdef CONFIG_KVM_BOOK3S_HV_POSSIBLE
2635*4882a593Smuzhiyun 		DUMP(p, requested_psscr, "%#-*llx");
2636*4882a593Smuzhiyun 		DUMP(p, dont_stop.counter, "%#-*x");
2637*4882a593Smuzhiyun #endif
2638*4882a593Smuzhiyun 	}
2639*4882a593Smuzhiyun #endif
2640*4882a593Smuzhiyun 
2641*4882a593Smuzhiyun 	DUMP(p, accounting.utime, "%#-*lx");
2642*4882a593Smuzhiyun 	DUMP(p, accounting.stime, "%#-*lx");
2643*4882a593Smuzhiyun #ifdef CONFIG_ARCH_HAS_SCALED_CPUTIME
2644*4882a593Smuzhiyun 	DUMP(p, accounting.utime_scaled, "%#-*lx");
2645*4882a593Smuzhiyun #endif
2646*4882a593Smuzhiyun 	DUMP(p, accounting.starttime, "%#-*lx");
2647*4882a593Smuzhiyun 	DUMP(p, accounting.starttime_user, "%#-*lx");
2648*4882a593Smuzhiyun #ifdef CONFIG_ARCH_HAS_SCALED_CPUTIME
2649*4882a593Smuzhiyun 	DUMP(p, accounting.startspurr, "%#-*lx");
2650*4882a593Smuzhiyun 	DUMP(p, accounting.utime_sspurr, "%#-*lx");
2651*4882a593Smuzhiyun #endif
2652*4882a593Smuzhiyun 	DUMP(p, accounting.steal_time, "%#-*lx");
2653*4882a593Smuzhiyun #undef DUMP
2654*4882a593Smuzhiyun 
2655*4882a593Smuzhiyun 	catch_memory_errors = 0;
2656*4882a593Smuzhiyun 	sync();
2657*4882a593Smuzhiyun }
2658*4882a593Smuzhiyun 
dump_all_pacas(void)2659*4882a593Smuzhiyun static void dump_all_pacas(void)
2660*4882a593Smuzhiyun {
2661*4882a593Smuzhiyun 	int cpu;
2662*4882a593Smuzhiyun 
2663*4882a593Smuzhiyun 	if (num_possible_cpus() == 0) {
2664*4882a593Smuzhiyun 		printf("No possible cpus, use 'dp #' to dump individual cpus\n");
2665*4882a593Smuzhiyun 		return;
2666*4882a593Smuzhiyun 	}
2667*4882a593Smuzhiyun 
2668*4882a593Smuzhiyun 	for_each_possible_cpu(cpu)
2669*4882a593Smuzhiyun 		dump_one_paca(cpu);
2670*4882a593Smuzhiyun }
2671*4882a593Smuzhiyun 
dump_pacas(void)2672*4882a593Smuzhiyun static void dump_pacas(void)
2673*4882a593Smuzhiyun {
2674*4882a593Smuzhiyun 	unsigned long num;
2675*4882a593Smuzhiyun 	int c;
2676*4882a593Smuzhiyun 
2677*4882a593Smuzhiyun 	c = inchar();
2678*4882a593Smuzhiyun 	if (c == 'a') {
2679*4882a593Smuzhiyun 		dump_all_pacas();
2680*4882a593Smuzhiyun 		return;
2681*4882a593Smuzhiyun 	}
2682*4882a593Smuzhiyun 
2683*4882a593Smuzhiyun 	termch = c;	/* Put c back, it wasn't 'a' */
2684*4882a593Smuzhiyun 
2685*4882a593Smuzhiyun 	if (scanhex(&num))
2686*4882a593Smuzhiyun 		dump_one_paca(num);
2687*4882a593Smuzhiyun 	else
2688*4882a593Smuzhiyun 		dump_one_paca(xmon_owner);
2689*4882a593Smuzhiyun }
2690*4882a593Smuzhiyun #endif
2691*4882a593Smuzhiyun 
2692*4882a593Smuzhiyun #ifdef CONFIG_PPC_POWERNV
dump_one_xive(int cpu)2693*4882a593Smuzhiyun static void dump_one_xive(int cpu)
2694*4882a593Smuzhiyun {
2695*4882a593Smuzhiyun 	unsigned int hwid = get_hard_smp_processor_id(cpu);
2696*4882a593Smuzhiyun 	bool hv = cpu_has_feature(CPU_FTR_HVMODE);
2697*4882a593Smuzhiyun 
2698*4882a593Smuzhiyun 	if (hv) {
2699*4882a593Smuzhiyun 		opal_xive_dump(XIVE_DUMP_TM_HYP, hwid);
2700*4882a593Smuzhiyun 		opal_xive_dump(XIVE_DUMP_TM_POOL, hwid);
2701*4882a593Smuzhiyun 		opal_xive_dump(XIVE_DUMP_TM_OS, hwid);
2702*4882a593Smuzhiyun 		opal_xive_dump(XIVE_DUMP_TM_USER, hwid);
2703*4882a593Smuzhiyun 		opal_xive_dump(XIVE_DUMP_VP, hwid);
2704*4882a593Smuzhiyun 		opal_xive_dump(XIVE_DUMP_EMU_STATE, hwid);
2705*4882a593Smuzhiyun 	}
2706*4882a593Smuzhiyun 
2707*4882a593Smuzhiyun 	if (setjmp(bus_error_jmp) != 0) {
2708*4882a593Smuzhiyun 		catch_memory_errors = 0;
2709*4882a593Smuzhiyun 		printf("*** Error dumping xive on cpu %d\n", cpu);
2710*4882a593Smuzhiyun 		return;
2711*4882a593Smuzhiyun 	}
2712*4882a593Smuzhiyun 
2713*4882a593Smuzhiyun 	catch_memory_errors = 1;
2714*4882a593Smuzhiyun 	sync();
2715*4882a593Smuzhiyun 	xmon_xive_do_dump(cpu);
2716*4882a593Smuzhiyun 	sync();
2717*4882a593Smuzhiyun 	__delay(200);
2718*4882a593Smuzhiyun 	catch_memory_errors = 0;
2719*4882a593Smuzhiyun }
2720*4882a593Smuzhiyun 
dump_all_xives(void)2721*4882a593Smuzhiyun static void dump_all_xives(void)
2722*4882a593Smuzhiyun {
2723*4882a593Smuzhiyun 	int cpu;
2724*4882a593Smuzhiyun 
2725*4882a593Smuzhiyun 	if (num_possible_cpus() == 0) {
2726*4882a593Smuzhiyun 		printf("No possible cpus, use 'dx #' to dump individual cpus\n");
2727*4882a593Smuzhiyun 		return;
2728*4882a593Smuzhiyun 	}
2729*4882a593Smuzhiyun 
2730*4882a593Smuzhiyun 	for_each_possible_cpu(cpu)
2731*4882a593Smuzhiyun 		dump_one_xive(cpu);
2732*4882a593Smuzhiyun }
2733*4882a593Smuzhiyun 
dump_one_xive_irq(u32 num,struct irq_data * d)2734*4882a593Smuzhiyun static void dump_one_xive_irq(u32 num, struct irq_data *d)
2735*4882a593Smuzhiyun {
2736*4882a593Smuzhiyun 	xmon_xive_get_irq_config(num, d);
2737*4882a593Smuzhiyun }
2738*4882a593Smuzhiyun 
dump_all_xive_irq(void)2739*4882a593Smuzhiyun static void dump_all_xive_irq(void)
2740*4882a593Smuzhiyun {
2741*4882a593Smuzhiyun 	unsigned int i;
2742*4882a593Smuzhiyun 	struct irq_desc *desc;
2743*4882a593Smuzhiyun 
2744*4882a593Smuzhiyun 	for_each_irq_desc(i, desc) {
2745*4882a593Smuzhiyun 		struct irq_data *d = irq_desc_get_irq_data(desc);
2746*4882a593Smuzhiyun 		unsigned int hwirq;
2747*4882a593Smuzhiyun 
2748*4882a593Smuzhiyun 		if (!d)
2749*4882a593Smuzhiyun 			continue;
2750*4882a593Smuzhiyun 
2751*4882a593Smuzhiyun 		hwirq = (unsigned int)irqd_to_hwirq(d);
2752*4882a593Smuzhiyun 		/* IPIs are special (HW number 0) */
2753*4882a593Smuzhiyun 		if (hwirq)
2754*4882a593Smuzhiyun 			dump_one_xive_irq(hwirq, d);
2755*4882a593Smuzhiyun 	}
2756*4882a593Smuzhiyun }
2757*4882a593Smuzhiyun 
dump_xives(void)2758*4882a593Smuzhiyun static void dump_xives(void)
2759*4882a593Smuzhiyun {
2760*4882a593Smuzhiyun 	unsigned long num;
2761*4882a593Smuzhiyun 	int c;
2762*4882a593Smuzhiyun 
2763*4882a593Smuzhiyun 	if (!xive_enabled()) {
2764*4882a593Smuzhiyun 		printf("Xive disabled on this system\n");
2765*4882a593Smuzhiyun 		return;
2766*4882a593Smuzhiyun 	}
2767*4882a593Smuzhiyun 
2768*4882a593Smuzhiyun 	c = inchar();
2769*4882a593Smuzhiyun 	if (c == 'a') {
2770*4882a593Smuzhiyun 		dump_all_xives();
2771*4882a593Smuzhiyun 		return;
2772*4882a593Smuzhiyun 	} else if (c == 'i') {
2773*4882a593Smuzhiyun 		if (scanhex(&num))
2774*4882a593Smuzhiyun 			dump_one_xive_irq(num, NULL);
2775*4882a593Smuzhiyun 		else
2776*4882a593Smuzhiyun 			dump_all_xive_irq();
2777*4882a593Smuzhiyun 		return;
2778*4882a593Smuzhiyun 	}
2779*4882a593Smuzhiyun 
2780*4882a593Smuzhiyun 	termch = c;	/* Put c back, it wasn't 'a' */
2781*4882a593Smuzhiyun 
2782*4882a593Smuzhiyun 	if (scanhex(&num))
2783*4882a593Smuzhiyun 		dump_one_xive(num);
2784*4882a593Smuzhiyun 	else
2785*4882a593Smuzhiyun 		dump_one_xive(xmon_owner);
2786*4882a593Smuzhiyun }
2787*4882a593Smuzhiyun #endif /* CONFIG_PPC_POWERNV */
2788*4882a593Smuzhiyun 
dump_by_size(unsigned long addr,long count,int size)2789*4882a593Smuzhiyun static void dump_by_size(unsigned long addr, long count, int size)
2790*4882a593Smuzhiyun {
2791*4882a593Smuzhiyun 	unsigned char temp[16];
2792*4882a593Smuzhiyun 	int i, j;
2793*4882a593Smuzhiyun 	u64 val;
2794*4882a593Smuzhiyun 
2795*4882a593Smuzhiyun 	count = ALIGN(count, 16);
2796*4882a593Smuzhiyun 
2797*4882a593Smuzhiyun 	for (i = 0; i < count; i += 16, addr += 16) {
2798*4882a593Smuzhiyun 		printf(REG, addr);
2799*4882a593Smuzhiyun 
2800*4882a593Smuzhiyun 		if (mread(addr, temp, 16) != 16) {
2801*4882a593Smuzhiyun 			printf("\nFaulted reading %d bytes from 0x"REG"\n", 16, addr);
2802*4882a593Smuzhiyun 			return;
2803*4882a593Smuzhiyun 		}
2804*4882a593Smuzhiyun 
2805*4882a593Smuzhiyun 		for (j = 0; j < 16; j += size) {
2806*4882a593Smuzhiyun 			putchar(' ');
2807*4882a593Smuzhiyun 			switch (size) {
2808*4882a593Smuzhiyun 			case 1: val = temp[j]; break;
2809*4882a593Smuzhiyun 			case 2: val = *(u16 *)&temp[j]; break;
2810*4882a593Smuzhiyun 			case 4: val = *(u32 *)&temp[j]; break;
2811*4882a593Smuzhiyun 			case 8: val = *(u64 *)&temp[j]; break;
2812*4882a593Smuzhiyun 			default: val = 0;
2813*4882a593Smuzhiyun 			}
2814*4882a593Smuzhiyun 
2815*4882a593Smuzhiyun 			printf("%0*llx", size * 2, val);
2816*4882a593Smuzhiyun 		}
2817*4882a593Smuzhiyun 		printf("  |");
2818*4882a593Smuzhiyun 		for (j = 0; j < 16; ++j) {
2819*4882a593Smuzhiyun 			val = temp[j];
2820*4882a593Smuzhiyun 			putchar(' ' <= val && val <= '~' ? val : '.');
2821*4882a593Smuzhiyun 		}
2822*4882a593Smuzhiyun 		printf("|\n");
2823*4882a593Smuzhiyun 	}
2824*4882a593Smuzhiyun }
2825*4882a593Smuzhiyun 
2826*4882a593Smuzhiyun static void
dump(void)2827*4882a593Smuzhiyun dump(void)
2828*4882a593Smuzhiyun {
2829*4882a593Smuzhiyun 	static char last[] = { "d?\n" };
2830*4882a593Smuzhiyun 	int c;
2831*4882a593Smuzhiyun 
2832*4882a593Smuzhiyun 	c = inchar();
2833*4882a593Smuzhiyun 
2834*4882a593Smuzhiyun #ifdef CONFIG_PPC64
2835*4882a593Smuzhiyun 	if (c == 'p') {
2836*4882a593Smuzhiyun 		xmon_start_pagination();
2837*4882a593Smuzhiyun 		dump_pacas();
2838*4882a593Smuzhiyun 		xmon_end_pagination();
2839*4882a593Smuzhiyun 		return;
2840*4882a593Smuzhiyun 	}
2841*4882a593Smuzhiyun #endif
2842*4882a593Smuzhiyun #ifdef CONFIG_PPC_POWERNV
2843*4882a593Smuzhiyun 	if (c == 'x') {
2844*4882a593Smuzhiyun 		xmon_start_pagination();
2845*4882a593Smuzhiyun 		dump_xives();
2846*4882a593Smuzhiyun 		xmon_end_pagination();
2847*4882a593Smuzhiyun 		return;
2848*4882a593Smuzhiyun 	}
2849*4882a593Smuzhiyun #endif
2850*4882a593Smuzhiyun 
2851*4882a593Smuzhiyun 	if (c == 't') {
2852*4882a593Smuzhiyun 		dump_tracing();
2853*4882a593Smuzhiyun 		return;
2854*4882a593Smuzhiyun 	}
2855*4882a593Smuzhiyun 
2856*4882a593Smuzhiyun 	if (c == '\n')
2857*4882a593Smuzhiyun 		termch = c;
2858*4882a593Smuzhiyun 
2859*4882a593Smuzhiyun 	scanhex((void *)&adrs);
2860*4882a593Smuzhiyun 	if (termch != '\n')
2861*4882a593Smuzhiyun 		termch = 0;
2862*4882a593Smuzhiyun 	if (c == 'i') {
2863*4882a593Smuzhiyun 		scanhex(&nidump);
2864*4882a593Smuzhiyun 		if (nidump == 0)
2865*4882a593Smuzhiyun 			nidump = 16;
2866*4882a593Smuzhiyun 		else if (nidump > MAX_IDUMP)
2867*4882a593Smuzhiyun 			nidump = MAX_IDUMP;
2868*4882a593Smuzhiyun 		adrs += ppc_inst_dump(adrs, nidump, 1);
2869*4882a593Smuzhiyun 		last_cmd = "di\n";
2870*4882a593Smuzhiyun 	} else if (c == 'l') {
2871*4882a593Smuzhiyun 		dump_log_buf();
2872*4882a593Smuzhiyun 	} else if (c == 'o') {
2873*4882a593Smuzhiyun 		dump_opal_msglog();
2874*4882a593Smuzhiyun 	} else if (c == 'v') {
2875*4882a593Smuzhiyun 		/* dump virtual to physical translation */
2876*4882a593Smuzhiyun 		show_pte(adrs);
2877*4882a593Smuzhiyun 	} else if (c == 'r') {
2878*4882a593Smuzhiyun 		scanhex(&ndump);
2879*4882a593Smuzhiyun 		if (ndump == 0)
2880*4882a593Smuzhiyun 			ndump = 64;
2881*4882a593Smuzhiyun 		xmon_rawdump(adrs, ndump);
2882*4882a593Smuzhiyun 		adrs += ndump;
2883*4882a593Smuzhiyun 		last_cmd = "dr\n";
2884*4882a593Smuzhiyun 	} else {
2885*4882a593Smuzhiyun 		scanhex(&ndump);
2886*4882a593Smuzhiyun 		if (ndump == 0)
2887*4882a593Smuzhiyun 			ndump = 64;
2888*4882a593Smuzhiyun 		else if (ndump > MAX_DUMP)
2889*4882a593Smuzhiyun 			ndump = MAX_DUMP;
2890*4882a593Smuzhiyun 
2891*4882a593Smuzhiyun 		switch (c) {
2892*4882a593Smuzhiyun 		case '8':
2893*4882a593Smuzhiyun 		case '4':
2894*4882a593Smuzhiyun 		case '2':
2895*4882a593Smuzhiyun 		case '1':
2896*4882a593Smuzhiyun 			ndump = ALIGN(ndump, 16);
2897*4882a593Smuzhiyun 			dump_by_size(adrs, ndump, c - '0');
2898*4882a593Smuzhiyun 			last[1] = c;
2899*4882a593Smuzhiyun 			last_cmd = last;
2900*4882a593Smuzhiyun 			break;
2901*4882a593Smuzhiyun 		default:
2902*4882a593Smuzhiyun 			prdump(adrs, ndump);
2903*4882a593Smuzhiyun 			last_cmd = "d\n";
2904*4882a593Smuzhiyun 		}
2905*4882a593Smuzhiyun 
2906*4882a593Smuzhiyun 		adrs += ndump;
2907*4882a593Smuzhiyun 	}
2908*4882a593Smuzhiyun }
2909*4882a593Smuzhiyun 
2910*4882a593Smuzhiyun static void
prdump(unsigned long adrs,long ndump)2911*4882a593Smuzhiyun prdump(unsigned long adrs, long ndump)
2912*4882a593Smuzhiyun {
2913*4882a593Smuzhiyun 	long n, m, c, r, nr;
2914*4882a593Smuzhiyun 	unsigned char temp[16];
2915*4882a593Smuzhiyun 
2916*4882a593Smuzhiyun 	for (n = ndump; n > 0;) {
2917*4882a593Smuzhiyun 		printf(REG, adrs);
2918*4882a593Smuzhiyun 		putchar(' ');
2919*4882a593Smuzhiyun 		r = n < 16? n: 16;
2920*4882a593Smuzhiyun 		nr = mread(adrs, temp, r);
2921*4882a593Smuzhiyun 		adrs += nr;
2922*4882a593Smuzhiyun 		for (m = 0; m < r; ++m) {
2923*4882a593Smuzhiyun 			if ((m & (sizeof(long) - 1)) == 0 && m > 0)
2924*4882a593Smuzhiyun 				putchar(' ');
2925*4882a593Smuzhiyun 			if (m < nr)
2926*4882a593Smuzhiyun 				printf("%.2x", temp[m]);
2927*4882a593Smuzhiyun 			else
2928*4882a593Smuzhiyun 				printf("%s", fault_chars[fault_type]);
2929*4882a593Smuzhiyun 		}
2930*4882a593Smuzhiyun 		for (; m < 16; ++m) {
2931*4882a593Smuzhiyun 			if ((m & (sizeof(long) - 1)) == 0)
2932*4882a593Smuzhiyun 				putchar(' ');
2933*4882a593Smuzhiyun 			printf("  ");
2934*4882a593Smuzhiyun 		}
2935*4882a593Smuzhiyun 		printf("  |");
2936*4882a593Smuzhiyun 		for (m = 0; m < r; ++m) {
2937*4882a593Smuzhiyun 			if (m < nr) {
2938*4882a593Smuzhiyun 				c = temp[m];
2939*4882a593Smuzhiyun 				putchar(' ' <= c && c <= '~'? c: '.');
2940*4882a593Smuzhiyun 			} else
2941*4882a593Smuzhiyun 				putchar(' ');
2942*4882a593Smuzhiyun 		}
2943*4882a593Smuzhiyun 		n -= r;
2944*4882a593Smuzhiyun 		for (; m < 16; ++m)
2945*4882a593Smuzhiyun 			putchar(' ');
2946*4882a593Smuzhiyun 		printf("|\n");
2947*4882a593Smuzhiyun 		if (nr < r)
2948*4882a593Smuzhiyun 			break;
2949*4882a593Smuzhiyun 	}
2950*4882a593Smuzhiyun }
2951*4882a593Smuzhiyun 
2952*4882a593Smuzhiyun typedef int (*instruction_dump_func)(unsigned long inst, unsigned long addr);
2953*4882a593Smuzhiyun 
2954*4882a593Smuzhiyun static int
generic_inst_dump(unsigned long adr,long count,int praddr,instruction_dump_func dump_func)2955*4882a593Smuzhiyun generic_inst_dump(unsigned long adr, long count, int praddr,
2956*4882a593Smuzhiyun 			instruction_dump_func dump_func)
2957*4882a593Smuzhiyun {
2958*4882a593Smuzhiyun 	int nr, dotted;
2959*4882a593Smuzhiyun 	unsigned long first_adr;
2960*4882a593Smuzhiyun 	struct ppc_inst inst, last_inst = ppc_inst(0);
2961*4882a593Smuzhiyun 
2962*4882a593Smuzhiyun 	dotted = 0;
2963*4882a593Smuzhiyun 	for (first_adr = adr; count > 0; --count, adr += ppc_inst_len(inst)) {
2964*4882a593Smuzhiyun 		nr = mread_instr(adr, &inst);
2965*4882a593Smuzhiyun 		if (nr == 0) {
2966*4882a593Smuzhiyun 			if (praddr) {
2967*4882a593Smuzhiyun 				const char *x = fault_chars[fault_type];
2968*4882a593Smuzhiyun 				printf(REG"  %s%s%s%s\n", adr, x, x, x, x);
2969*4882a593Smuzhiyun 			}
2970*4882a593Smuzhiyun 			break;
2971*4882a593Smuzhiyun 		}
2972*4882a593Smuzhiyun 		if (adr > first_adr && ppc_inst_equal(inst, last_inst)) {
2973*4882a593Smuzhiyun 			if (!dotted) {
2974*4882a593Smuzhiyun 				printf(" ...\n");
2975*4882a593Smuzhiyun 				dotted = 1;
2976*4882a593Smuzhiyun 			}
2977*4882a593Smuzhiyun 			continue;
2978*4882a593Smuzhiyun 		}
2979*4882a593Smuzhiyun 		dotted = 0;
2980*4882a593Smuzhiyun 		last_inst = inst;
2981*4882a593Smuzhiyun 		if (praddr)
2982*4882a593Smuzhiyun 			printf(REG"  %s", adr, ppc_inst_as_str(inst));
2983*4882a593Smuzhiyun 		printf("\t");
2984*4882a593Smuzhiyun 		if (!ppc_inst_prefixed(inst))
2985*4882a593Smuzhiyun 			dump_func(ppc_inst_val(inst), adr);
2986*4882a593Smuzhiyun 		else
2987*4882a593Smuzhiyun 			dump_func(ppc_inst_as_u64(inst), adr);
2988*4882a593Smuzhiyun 		printf("\n");
2989*4882a593Smuzhiyun 	}
2990*4882a593Smuzhiyun 	return adr - first_adr;
2991*4882a593Smuzhiyun }
2992*4882a593Smuzhiyun 
2993*4882a593Smuzhiyun static int
ppc_inst_dump(unsigned long adr,long count,int praddr)2994*4882a593Smuzhiyun ppc_inst_dump(unsigned long adr, long count, int praddr)
2995*4882a593Smuzhiyun {
2996*4882a593Smuzhiyun 	return generic_inst_dump(adr, count, praddr, print_insn_powerpc);
2997*4882a593Smuzhiyun }
2998*4882a593Smuzhiyun 
2999*4882a593Smuzhiyun void
print_address(unsigned long addr)3000*4882a593Smuzhiyun print_address(unsigned long addr)
3001*4882a593Smuzhiyun {
3002*4882a593Smuzhiyun 	xmon_print_symbol(addr, "\t# ", "");
3003*4882a593Smuzhiyun }
3004*4882a593Smuzhiyun 
3005*4882a593Smuzhiyun static void
dump_log_buf(void)3006*4882a593Smuzhiyun dump_log_buf(void)
3007*4882a593Smuzhiyun {
3008*4882a593Smuzhiyun 	struct kmsg_dumper dumper = { .active = 1 };
3009*4882a593Smuzhiyun 	unsigned char buf[128];
3010*4882a593Smuzhiyun 	size_t len;
3011*4882a593Smuzhiyun 
3012*4882a593Smuzhiyun 	if (setjmp(bus_error_jmp) != 0) {
3013*4882a593Smuzhiyun 		printf("Error dumping printk buffer!\n");
3014*4882a593Smuzhiyun 		return;
3015*4882a593Smuzhiyun 	}
3016*4882a593Smuzhiyun 
3017*4882a593Smuzhiyun 	catch_memory_errors = 1;
3018*4882a593Smuzhiyun 	sync();
3019*4882a593Smuzhiyun 
3020*4882a593Smuzhiyun 	kmsg_dump_rewind_nolock(&dumper);
3021*4882a593Smuzhiyun 	xmon_start_pagination();
3022*4882a593Smuzhiyun 	while (kmsg_dump_get_line_nolock(&dumper, false, buf, sizeof(buf), &len)) {
3023*4882a593Smuzhiyun 		buf[len] = '\0';
3024*4882a593Smuzhiyun 		printf("%s", buf);
3025*4882a593Smuzhiyun 	}
3026*4882a593Smuzhiyun 	xmon_end_pagination();
3027*4882a593Smuzhiyun 
3028*4882a593Smuzhiyun 	sync();
3029*4882a593Smuzhiyun 	/* wait a little while to see if we get a machine check */
3030*4882a593Smuzhiyun 	__delay(200);
3031*4882a593Smuzhiyun 	catch_memory_errors = 0;
3032*4882a593Smuzhiyun }
3033*4882a593Smuzhiyun 
3034*4882a593Smuzhiyun #ifdef CONFIG_PPC_POWERNV
dump_opal_msglog(void)3035*4882a593Smuzhiyun static void dump_opal_msglog(void)
3036*4882a593Smuzhiyun {
3037*4882a593Smuzhiyun 	unsigned char buf[128];
3038*4882a593Smuzhiyun 	ssize_t res;
3039*4882a593Smuzhiyun 	loff_t pos = 0;
3040*4882a593Smuzhiyun 
3041*4882a593Smuzhiyun 	if (!firmware_has_feature(FW_FEATURE_OPAL)) {
3042*4882a593Smuzhiyun 		printf("Machine is not running OPAL firmware.\n");
3043*4882a593Smuzhiyun 		return;
3044*4882a593Smuzhiyun 	}
3045*4882a593Smuzhiyun 
3046*4882a593Smuzhiyun 	if (setjmp(bus_error_jmp) != 0) {
3047*4882a593Smuzhiyun 		printf("Error dumping OPAL msglog!\n");
3048*4882a593Smuzhiyun 		return;
3049*4882a593Smuzhiyun 	}
3050*4882a593Smuzhiyun 
3051*4882a593Smuzhiyun 	catch_memory_errors = 1;
3052*4882a593Smuzhiyun 	sync();
3053*4882a593Smuzhiyun 
3054*4882a593Smuzhiyun 	xmon_start_pagination();
3055*4882a593Smuzhiyun 	while ((res = opal_msglog_copy(buf, pos, sizeof(buf) - 1))) {
3056*4882a593Smuzhiyun 		if (res < 0) {
3057*4882a593Smuzhiyun 			printf("Error dumping OPAL msglog! Error: %zd\n", res);
3058*4882a593Smuzhiyun 			break;
3059*4882a593Smuzhiyun 		}
3060*4882a593Smuzhiyun 		buf[res] = '\0';
3061*4882a593Smuzhiyun 		printf("%s", buf);
3062*4882a593Smuzhiyun 		pos += res;
3063*4882a593Smuzhiyun 	}
3064*4882a593Smuzhiyun 	xmon_end_pagination();
3065*4882a593Smuzhiyun 
3066*4882a593Smuzhiyun 	sync();
3067*4882a593Smuzhiyun 	/* wait a little while to see if we get a machine check */
3068*4882a593Smuzhiyun 	__delay(200);
3069*4882a593Smuzhiyun 	catch_memory_errors = 0;
3070*4882a593Smuzhiyun }
3071*4882a593Smuzhiyun #endif
3072*4882a593Smuzhiyun 
3073*4882a593Smuzhiyun /*
3074*4882a593Smuzhiyun  * Memory operations - move, set, print differences
3075*4882a593Smuzhiyun  */
3076*4882a593Smuzhiyun static unsigned long mdest;		/* destination address */
3077*4882a593Smuzhiyun static unsigned long msrc;		/* source address */
3078*4882a593Smuzhiyun static unsigned long mval;		/* byte value to set memory to */
3079*4882a593Smuzhiyun static unsigned long mcount;		/* # bytes to affect */
3080*4882a593Smuzhiyun static unsigned long mdiffs;		/* max # differences to print */
3081*4882a593Smuzhiyun 
3082*4882a593Smuzhiyun static void
memops(int cmd)3083*4882a593Smuzhiyun memops(int cmd)
3084*4882a593Smuzhiyun {
3085*4882a593Smuzhiyun 	scanhex((void *)&mdest);
3086*4882a593Smuzhiyun 	if( termch != '\n' )
3087*4882a593Smuzhiyun 		termch = 0;
3088*4882a593Smuzhiyun 	scanhex((void *)(cmd == 's'? &mval: &msrc));
3089*4882a593Smuzhiyun 	if( termch != '\n' )
3090*4882a593Smuzhiyun 		termch = 0;
3091*4882a593Smuzhiyun 	scanhex((void *)&mcount);
3092*4882a593Smuzhiyun 	switch( cmd ){
3093*4882a593Smuzhiyun 	case 'm':
3094*4882a593Smuzhiyun 		if (xmon_is_ro) {
3095*4882a593Smuzhiyun 			printf(xmon_ro_msg);
3096*4882a593Smuzhiyun 			break;
3097*4882a593Smuzhiyun 		}
3098*4882a593Smuzhiyun 		memmove((void *)mdest, (void *)msrc, mcount);
3099*4882a593Smuzhiyun 		break;
3100*4882a593Smuzhiyun 	case 's':
3101*4882a593Smuzhiyun 		if (xmon_is_ro) {
3102*4882a593Smuzhiyun 			printf(xmon_ro_msg);
3103*4882a593Smuzhiyun 			break;
3104*4882a593Smuzhiyun 		}
3105*4882a593Smuzhiyun 		memset((void *)mdest, mval, mcount);
3106*4882a593Smuzhiyun 		break;
3107*4882a593Smuzhiyun 	case 'd':
3108*4882a593Smuzhiyun 		if( termch != '\n' )
3109*4882a593Smuzhiyun 			termch = 0;
3110*4882a593Smuzhiyun 		scanhex((void *)&mdiffs);
3111*4882a593Smuzhiyun 		memdiffs((unsigned char *)mdest, (unsigned char *)msrc, mcount, mdiffs);
3112*4882a593Smuzhiyun 		break;
3113*4882a593Smuzhiyun 	}
3114*4882a593Smuzhiyun }
3115*4882a593Smuzhiyun 
3116*4882a593Smuzhiyun static void
memdiffs(unsigned char * p1,unsigned char * p2,unsigned nb,unsigned maxpr)3117*4882a593Smuzhiyun memdiffs(unsigned char *p1, unsigned char *p2, unsigned nb, unsigned maxpr)
3118*4882a593Smuzhiyun {
3119*4882a593Smuzhiyun 	unsigned n, prt;
3120*4882a593Smuzhiyun 
3121*4882a593Smuzhiyun 	prt = 0;
3122*4882a593Smuzhiyun 	for( n = nb; n > 0; --n )
3123*4882a593Smuzhiyun 		if( *p1++ != *p2++ )
3124*4882a593Smuzhiyun 			if( ++prt <= maxpr )
3125*4882a593Smuzhiyun 				printf("%px %.2x # %px %.2x\n", p1 - 1,
3126*4882a593Smuzhiyun 					p1[-1], p2 - 1, p2[-1]);
3127*4882a593Smuzhiyun 	if( prt > maxpr )
3128*4882a593Smuzhiyun 		printf("Total of %d differences\n", prt);
3129*4882a593Smuzhiyun }
3130*4882a593Smuzhiyun 
3131*4882a593Smuzhiyun static unsigned mend;
3132*4882a593Smuzhiyun static unsigned mask;
3133*4882a593Smuzhiyun 
3134*4882a593Smuzhiyun static void
memlocate(void)3135*4882a593Smuzhiyun memlocate(void)
3136*4882a593Smuzhiyun {
3137*4882a593Smuzhiyun 	unsigned a, n;
3138*4882a593Smuzhiyun 	unsigned char val[4];
3139*4882a593Smuzhiyun 
3140*4882a593Smuzhiyun 	last_cmd = "ml";
3141*4882a593Smuzhiyun 	scanhex((void *)&mdest);
3142*4882a593Smuzhiyun 	if (termch != '\n') {
3143*4882a593Smuzhiyun 		termch = 0;
3144*4882a593Smuzhiyun 		scanhex((void *)&mend);
3145*4882a593Smuzhiyun 		if (termch != '\n') {
3146*4882a593Smuzhiyun 			termch = 0;
3147*4882a593Smuzhiyun 			scanhex((void *)&mval);
3148*4882a593Smuzhiyun 			mask = ~0;
3149*4882a593Smuzhiyun 			if (termch != '\n') termch = 0;
3150*4882a593Smuzhiyun 			scanhex((void *)&mask);
3151*4882a593Smuzhiyun 		}
3152*4882a593Smuzhiyun 	}
3153*4882a593Smuzhiyun 	n = 0;
3154*4882a593Smuzhiyun 	for (a = mdest; a < mend; a += 4) {
3155*4882a593Smuzhiyun 		if (mread(a, val, 4) == 4
3156*4882a593Smuzhiyun 			&& ((GETWORD(val) ^ mval) & mask) == 0) {
3157*4882a593Smuzhiyun 			printf("%.16x:  %.16x\n", a, GETWORD(val));
3158*4882a593Smuzhiyun 			if (++n >= 10)
3159*4882a593Smuzhiyun 				break;
3160*4882a593Smuzhiyun 		}
3161*4882a593Smuzhiyun 	}
3162*4882a593Smuzhiyun }
3163*4882a593Smuzhiyun 
3164*4882a593Smuzhiyun static unsigned long mskip = 0x1000;
3165*4882a593Smuzhiyun static unsigned long mlim = 0xffffffff;
3166*4882a593Smuzhiyun 
3167*4882a593Smuzhiyun static void
memzcan(void)3168*4882a593Smuzhiyun memzcan(void)
3169*4882a593Smuzhiyun {
3170*4882a593Smuzhiyun 	unsigned char v;
3171*4882a593Smuzhiyun 	unsigned a;
3172*4882a593Smuzhiyun 	int ok, ook;
3173*4882a593Smuzhiyun 
3174*4882a593Smuzhiyun 	scanhex(&mdest);
3175*4882a593Smuzhiyun 	if (termch != '\n') termch = 0;
3176*4882a593Smuzhiyun 	scanhex(&mskip);
3177*4882a593Smuzhiyun 	if (termch != '\n') termch = 0;
3178*4882a593Smuzhiyun 	scanhex(&mlim);
3179*4882a593Smuzhiyun 	ook = 0;
3180*4882a593Smuzhiyun 	for (a = mdest; a < mlim; a += mskip) {
3181*4882a593Smuzhiyun 		ok = mread(a, &v, 1);
3182*4882a593Smuzhiyun 		if (ok && !ook) {
3183*4882a593Smuzhiyun 			printf("%.8x .. ", a);
3184*4882a593Smuzhiyun 		} else if (!ok && ook)
3185*4882a593Smuzhiyun 			printf("%.8lx\n", a - mskip);
3186*4882a593Smuzhiyun 		ook = ok;
3187*4882a593Smuzhiyun 		if (a + mskip < a)
3188*4882a593Smuzhiyun 			break;
3189*4882a593Smuzhiyun 	}
3190*4882a593Smuzhiyun 	if (ook)
3191*4882a593Smuzhiyun 		printf("%.8lx\n", a - mskip);
3192*4882a593Smuzhiyun }
3193*4882a593Smuzhiyun 
show_task(struct task_struct * tsk)3194*4882a593Smuzhiyun static void show_task(struct task_struct *tsk)
3195*4882a593Smuzhiyun {
3196*4882a593Smuzhiyun 	char state;
3197*4882a593Smuzhiyun 
3198*4882a593Smuzhiyun 	/*
3199*4882a593Smuzhiyun 	 * Cloned from kdb_task_state_char(), which is not entirely
3200*4882a593Smuzhiyun 	 * appropriate for calling from xmon. This could be moved
3201*4882a593Smuzhiyun 	 * to a common, generic, routine used by both.
3202*4882a593Smuzhiyun 	 */
3203*4882a593Smuzhiyun 	state = (tsk->state == 0) ? 'R' :
3204*4882a593Smuzhiyun 		(tsk->state < 0) ? 'U' :
3205*4882a593Smuzhiyun 		(tsk->state & TASK_UNINTERRUPTIBLE) ? 'D' :
3206*4882a593Smuzhiyun 		(tsk->state & TASK_STOPPED) ? 'T' :
3207*4882a593Smuzhiyun 		(tsk->state & TASK_TRACED) ? 'C' :
3208*4882a593Smuzhiyun 		(tsk->exit_state & EXIT_ZOMBIE) ? 'Z' :
3209*4882a593Smuzhiyun 		(tsk->exit_state & EXIT_DEAD) ? 'E' :
3210*4882a593Smuzhiyun 		(tsk->state & TASK_INTERRUPTIBLE) ? 'S' : '?';
3211*4882a593Smuzhiyun 
3212*4882a593Smuzhiyun 	printf("%16px %16lx %16px %6d %6d %c %2d %s\n", tsk,
3213*4882a593Smuzhiyun 		tsk->thread.ksp, tsk->thread.regs,
3214*4882a593Smuzhiyun 		tsk->pid, rcu_dereference(tsk->parent)->pid,
3215*4882a593Smuzhiyun 		state, task_cpu(tsk),
3216*4882a593Smuzhiyun 		tsk->comm);
3217*4882a593Smuzhiyun }
3218*4882a593Smuzhiyun 
3219*4882a593Smuzhiyun #ifdef CONFIG_PPC_BOOK3S_64
format_pte(void * ptep,unsigned long pte)3220*4882a593Smuzhiyun static void format_pte(void *ptep, unsigned long pte)
3221*4882a593Smuzhiyun {
3222*4882a593Smuzhiyun 	pte_t entry = __pte(pte);
3223*4882a593Smuzhiyun 
3224*4882a593Smuzhiyun 	printf("ptep @ 0x%016lx = 0x%016lx\n", (unsigned long)ptep, pte);
3225*4882a593Smuzhiyun 	printf("Maps physical address = 0x%016lx\n", pte & PTE_RPN_MASK);
3226*4882a593Smuzhiyun 
3227*4882a593Smuzhiyun 	printf("Flags = %s%s%s%s%s\n",
3228*4882a593Smuzhiyun 	       pte_young(entry) ? "Accessed " : "",
3229*4882a593Smuzhiyun 	       pte_dirty(entry) ? "Dirty " : "",
3230*4882a593Smuzhiyun 	       pte_read(entry)  ? "Read " : "",
3231*4882a593Smuzhiyun 	       pte_write(entry) ? "Write " : "",
3232*4882a593Smuzhiyun 	       pte_exec(entry)  ? "Exec " : "");
3233*4882a593Smuzhiyun }
3234*4882a593Smuzhiyun 
show_pte(unsigned long addr)3235*4882a593Smuzhiyun static void show_pte(unsigned long addr)
3236*4882a593Smuzhiyun {
3237*4882a593Smuzhiyun 	unsigned long tskv = 0;
3238*4882a593Smuzhiyun 	struct task_struct *tsk = NULL;
3239*4882a593Smuzhiyun 	struct mm_struct *mm;
3240*4882a593Smuzhiyun 	pgd_t *pgdp;
3241*4882a593Smuzhiyun 	p4d_t *p4dp;
3242*4882a593Smuzhiyun 	pud_t *pudp;
3243*4882a593Smuzhiyun 	pmd_t *pmdp;
3244*4882a593Smuzhiyun 	pte_t *ptep;
3245*4882a593Smuzhiyun 
3246*4882a593Smuzhiyun 	if (!scanhex(&tskv))
3247*4882a593Smuzhiyun 		mm = &init_mm;
3248*4882a593Smuzhiyun 	else
3249*4882a593Smuzhiyun 		tsk = (struct task_struct *)tskv;
3250*4882a593Smuzhiyun 
3251*4882a593Smuzhiyun 	if (tsk == NULL)
3252*4882a593Smuzhiyun 		mm = &init_mm;
3253*4882a593Smuzhiyun 	else
3254*4882a593Smuzhiyun 		mm = tsk->active_mm;
3255*4882a593Smuzhiyun 
3256*4882a593Smuzhiyun 	if (setjmp(bus_error_jmp) != 0) {
3257*4882a593Smuzhiyun 		catch_memory_errors = 0;
3258*4882a593Smuzhiyun 		printf("*** Error dumping pte for task %px\n", tsk);
3259*4882a593Smuzhiyun 		return;
3260*4882a593Smuzhiyun 	}
3261*4882a593Smuzhiyun 
3262*4882a593Smuzhiyun 	catch_memory_errors = 1;
3263*4882a593Smuzhiyun 	sync();
3264*4882a593Smuzhiyun 
3265*4882a593Smuzhiyun 	if (mm == &init_mm)
3266*4882a593Smuzhiyun 		pgdp = pgd_offset_k(addr);
3267*4882a593Smuzhiyun 	else
3268*4882a593Smuzhiyun 		pgdp = pgd_offset(mm, addr);
3269*4882a593Smuzhiyun 
3270*4882a593Smuzhiyun 	p4dp = p4d_offset(pgdp, addr);
3271*4882a593Smuzhiyun 
3272*4882a593Smuzhiyun 	if (p4d_none(*p4dp)) {
3273*4882a593Smuzhiyun 		printf("No valid P4D\n");
3274*4882a593Smuzhiyun 		return;
3275*4882a593Smuzhiyun 	}
3276*4882a593Smuzhiyun 
3277*4882a593Smuzhiyun 	if (p4d_is_leaf(*p4dp)) {
3278*4882a593Smuzhiyun 		format_pte(p4dp, p4d_val(*p4dp));
3279*4882a593Smuzhiyun 		return;
3280*4882a593Smuzhiyun 	}
3281*4882a593Smuzhiyun 
3282*4882a593Smuzhiyun 	printf("p4dp @ 0x%px = 0x%016lx\n", p4dp, p4d_val(*p4dp));
3283*4882a593Smuzhiyun 
3284*4882a593Smuzhiyun 	pudp = pud_offset(p4dp, addr);
3285*4882a593Smuzhiyun 
3286*4882a593Smuzhiyun 	if (pud_none(*pudp)) {
3287*4882a593Smuzhiyun 		printf("No valid PUD\n");
3288*4882a593Smuzhiyun 		return;
3289*4882a593Smuzhiyun 	}
3290*4882a593Smuzhiyun 
3291*4882a593Smuzhiyun 	if (pud_is_leaf(*pudp)) {
3292*4882a593Smuzhiyun 		format_pte(pudp, pud_val(*pudp));
3293*4882a593Smuzhiyun 		return;
3294*4882a593Smuzhiyun 	}
3295*4882a593Smuzhiyun 
3296*4882a593Smuzhiyun 	printf("pudp @ 0x%px = 0x%016lx\n", pudp, pud_val(*pudp));
3297*4882a593Smuzhiyun 
3298*4882a593Smuzhiyun 	pmdp = pmd_offset(pudp, addr);
3299*4882a593Smuzhiyun 
3300*4882a593Smuzhiyun 	if (pmd_none(*pmdp)) {
3301*4882a593Smuzhiyun 		printf("No valid PMD\n");
3302*4882a593Smuzhiyun 		return;
3303*4882a593Smuzhiyun 	}
3304*4882a593Smuzhiyun 
3305*4882a593Smuzhiyun 	if (pmd_is_leaf(*pmdp)) {
3306*4882a593Smuzhiyun 		format_pte(pmdp, pmd_val(*pmdp));
3307*4882a593Smuzhiyun 		return;
3308*4882a593Smuzhiyun 	}
3309*4882a593Smuzhiyun 	printf("pmdp @ 0x%px = 0x%016lx\n", pmdp, pmd_val(*pmdp));
3310*4882a593Smuzhiyun 
3311*4882a593Smuzhiyun 	ptep = pte_offset_map(pmdp, addr);
3312*4882a593Smuzhiyun 	if (pte_none(*ptep)) {
3313*4882a593Smuzhiyun 		printf("no valid PTE\n");
3314*4882a593Smuzhiyun 		return;
3315*4882a593Smuzhiyun 	}
3316*4882a593Smuzhiyun 
3317*4882a593Smuzhiyun 	format_pte(ptep, pte_val(*ptep));
3318*4882a593Smuzhiyun 
3319*4882a593Smuzhiyun 	sync();
3320*4882a593Smuzhiyun 	__delay(200);
3321*4882a593Smuzhiyun 	catch_memory_errors = 0;
3322*4882a593Smuzhiyun }
3323*4882a593Smuzhiyun #else
show_pte(unsigned long addr)3324*4882a593Smuzhiyun static void show_pte(unsigned long addr)
3325*4882a593Smuzhiyun {
3326*4882a593Smuzhiyun 	printf("show_pte not yet implemented\n");
3327*4882a593Smuzhiyun }
3328*4882a593Smuzhiyun #endif /* CONFIG_PPC_BOOK3S_64 */
3329*4882a593Smuzhiyun 
show_tasks(void)3330*4882a593Smuzhiyun static void show_tasks(void)
3331*4882a593Smuzhiyun {
3332*4882a593Smuzhiyun 	unsigned long tskv;
3333*4882a593Smuzhiyun 	struct task_struct *tsk = NULL;
3334*4882a593Smuzhiyun 
3335*4882a593Smuzhiyun 	printf("     task_struct     ->thread.ksp    ->thread.regs    PID   PPID S  P CMD\n");
3336*4882a593Smuzhiyun 
3337*4882a593Smuzhiyun 	if (scanhex(&tskv))
3338*4882a593Smuzhiyun 		tsk = (struct task_struct *)tskv;
3339*4882a593Smuzhiyun 
3340*4882a593Smuzhiyun 	if (setjmp(bus_error_jmp) != 0) {
3341*4882a593Smuzhiyun 		catch_memory_errors = 0;
3342*4882a593Smuzhiyun 		printf("*** Error dumping task %px\n", tsk);
3343*4882a593Smuzhiyun 		return;
3344*4882a593Smuzhiyun 	}
3345*4882a593Smuzhiyun 
3346*4882a593Smuzhiyun 	catch_memory_errors = 1;
3347*4882a593Smuzhiyun 	sync();
3348*4882a593Smuzhiyun 
3349*4882a593Smuzhiyun 	if (tsk)
3350*4882a593Smuzhiyun 		show_task(tsk);
3351*4882a593Smuzhiyun 	else
3352*4882a593Smuzhiyun 		for_each_process(tsk)
3353*4882a593Smuzhiyun 			show_task(tsk);
3354*4882a593Smuzhiyun 
3355*4882a593Smuzhiyun 	sync();
3356*4882a593Smuzhiyun 	__delay(200);
3357*4882a593Smuzhiyun 	catch_memory_errors = 0;
3358*4882a593Smuzhiyun }
3359*4882a593Smuzhiyun 
proccall(void)3360*4882a593Smuzhiyun static void proccall(void)
3361*4882a593Smuzhiyun {
3362*4882a593Smuzhiyun 	unsigned long args[8];
3363*4882a593Smuzhiyun 	unsigned long ret;
3364*4882a593Smuzhiyun 	int i;
3365*4882a593Smuzhiyun 	typedef unsigned long (*callfunc_t)(unsigned long, unsigned long,
3366*4882a593Smuzhiyun 			unsigned long, unsigned long, unsigned long,
3367*4882a593Smuzhiyun 			unsigned long, unsigned long, unsigned long);
3368*4882a593Smuzhiyun 	callfunc_t func;
3369*4882a593Smuzhiyun 
3370*4882a593Smuzhiyun 	if (!scanhex(&adrs))
3371*4882a593Smuzhiyun 		return;
3372*4882a593Smuzhiyun 	if (termch != '\n')
3373*4882a593Smuzhiyun 		termch = 0;
3374*4882a593Smuzhiyun 	for (i = 0; i < 8; ++i)
3375*4882a593Smuzhiyun 		args[i] = 0;
3376*4882a593Smuzhiyun 	for (i = 0; i < 8; ++i) {
3377*4882a593Smuzhiyun 		if (!scanhex(&args[i]) || termch == '\n')
3378*4882a593Smuzhiyun 			break;
3379*4882a593Smuzhiyun 		termch = 0;
3380*4882a593Smuzhiyun 	}
3381*4882a593Smuzhiyun 	func = (callfunc_t) adrs;
3382*4882a593Smuzhiyun 	ret = 0;
3383*4882a593Smuzhiyun 	if (setjmp(bus_error_jmp) == 0) {
3384*4882a593Smuzhiyun 		catch_memory_errors = 1;
3385*4882a593Smuzhiyun 		sync();
3386*4882a593Smuzhiyun 		ret = func(args[0], args[1], args[2], args[3],
3387*4882a593Smuzhiyun 			   args[4], args[5], args[6], args[7]);
3388*4882a593Smuzhiyun 		sync();
3389*4882a593Smuzhiyun 		printf("return value is 0x%lx\n", ret);
3390*4882a593Smuzhiyun 	} else {
3391*4882a593Smuzhiyun 		printf("*** %x exception occurred\n", fault_except);
3392*4882a593Smuzhiyun 	}
3393*4882a593Smuzhiyun 	catch_memory_errors = 0;
3394*4882a593Smuzhiyun }
3395*4882a593Smuzhiyun 
3396*4882a593Smuzhiyun /* Input scanning routines */
3397*4882a593Smuzhiyun int
skipbl(void)3398*4882a593Smuzhiyun skipbl(void)
3399*4882a593Smuzhiyun {
3400*4882a593Smuzhiyun 	int c;
3401*4882a593Smuzhiyun 
3402*4882a593Smuzhiyun 	if( termch != 0 ){
3403*4882a593Smuzhiyun 		c = termch;
3404*4882a593Smuzhiyun 		termch = 0;
3405*4882a593Smuzhiyun 	} else
3406*4882a593Smuzhiyun 		c = inchar();
3407*4882a593Smuzhiyun 	while( c == ' ' || c == '\t' )
3408*4882a593Smuzhiyun 		c = inchar();
3409*4882a593Smuzhiyun 	return c;
3410*4882a593Smuzhiyun }
3411*4882a593Smuzhiyun 
3412*4882a593Smuzhiyun #define N_PTREGS	44
3413*4882a593Smuzhiyun static const char *regnames[N_PTREGS] = {
3414*4882a593Smuzhiyun 	"r0", "r1", "r2", "r3", "r4", "r5", "r6", "r7",
3415*4882a593Smuzhiyun 	"r8", "r9", "r10", "r11", "r12", "r13", "r14", "r15",
3416*4882a593Smuzhiyun 	"r16", "r17", "r18", "r19", "r20", "r21", "r22", "r23",
3417*4882a593Smuzhiyun 	"r24", "r25", "r26", "r27", "r28", "r29", "r30", "r31",
3418*4882a593Smuzhiyun 	"pc", "msr", "or3", "ctr", "lr", "xer", "ccr",
3419*4882a593Smuzhiyun #ifdef CONFIG_PPC64
3420*4882a593Smuzhiyun 	"softe",
3421*4882a593Smuzhiyun #else
3422*4882a593Smuzhiyun 	"mq",
3423*4882a593Smuzhiyun #endif
3424*4882a593Smuzhiyun 	"trap", "dar", "dsisr", "res"
3425*4882a593Smuzhiyun };
3426*4882a593Smuzhiyun 
3427*4882a593Smuzhiyun int
scanhex(unsigned long * vp)3428*4882a593Smuzhiyun scanhex(unsigned long *vp)
3429*4882a593Smuzhiyun {
3430*4882a593Smuzhiyun 	int c, d;
3431*4882a593Smuzhiyun 	unsigned long v;
3432*4882a593Smuzhiyun 
3433*4882a593Smuzhiyun 	c = skipbl();
3434*4882a593Smuzhiyun 	if (c == '%') {
3435*4882a593Smuzhiyun 		/* parse register name */
3436*4882a593Smuzhiyun 		char regname[8];
3437*4882a593Smuzhiyun 		int i;
3438*4882a593Smuzhiyun 
3439*4882a593Smuzhiyun 		for (i = 0; i < sizeof(regname) - 1; ++i) {
3440*4882a593Smuzhiyun 			c = inchar();
3441*4882a593Smuzhiyun 			if (!isalnum(c)) {
3442*4882a593Smuzhiyun 				termch = c;
3443*4882a593Smuzhiyun 				break;
3444*4882a593Smuzhiyun 			}
3445*4882a593Smuzhiyun 			regname[i] = c;
3446*4882a593Smuzhiyun 		}
3447*4882a593Smuzhiyun 		regname[i] = 0;
3448*4882a593Smuzhiyun 		i = match_string(regnames, N_PTREGS, regname);
3449*4882a593Smuzhiyun 		if (i < 0) {
3450*4882a593Smuzhiyun 			printf("invalid register name '%%%s'\n", regname);
3451*4882a593Smuzhiyun 			return 0;
3452*4882a593Smuzhiyun 		}
3453*4882a593Smuzhiyun 		if (xmon_regs == NULL) {
3454*4882a593Smuzhiyun 			printf("regs not available\n");
3455*4882a593Smuzhiyun 			return 0;
3456*4882a593Smuzhiyun 		}
3457*4882a593Smuzhiyun 		*vp = ((unsigned long *)xmon_regs)[i];
3458*4882a593Smuzhiyun 		return 1;
3459*4882a593Smuzhiyun 	}
3460*4882a593Smuzhiyun 
3461*4882a593Smuzhiyun 	/* skip leading "0x" if any */
3462*4882a593Smuzhiyun 
3463*4882a593Smuzhiyun 	if (c == '0') {
3464*4882a593Smuzhiyun 		c = inchar();
3465*4882a593Smuzhiyun 		if (c == 'x') {
3466*4882a593Smuzhiyun 			c = inchar();
3467*4882a593Smuzhiyun 		} else {
3468*4882a593Smuzhiyun 			d = hexdigit(c);
3469*4882a593Smuzhiyun 			if (d == EOF) {
3470*4882a593Smuzhiyun 				termch = c;
3471*4882a593Smuzhiyun 				*vp = 0;
3472*4882a593Smuzhiyun 				return 1;
3473*4882a593Smuzhiyun 			}
3474*4882a593Smuzhiyun 		}
3475*4882a593Smuzhiyun 	} else if (c == '$') {
3476*4882a593Smuzhiyun 		int i;
3477*4882a593Smuzhiyun 		for (i=0; i<63; i++) {
3478*4882a593Smuzhiyun 			c = inchar();
3479*4882a593Smuzhiyun 			if (isspace(c) || c == '\0') {
3480*4882a593Smuzhiyun 				termch = c;
3481*4882a593Smuzhiyun 				break;
3482*4882a593Smuzhiyun 			}
3483*4882a593Smuzhiyun 			tmpstr[i] = c;
3484*4882a593Smuzhiyun 		}
3485*4882a593Smuzhiyun 		tmpstr[i++] = 0;
3486*4882a593Smuzhiyun 		*vp = 0;
3487*4882a593Smuzhiyun 		if (setjmp(bus_error_jmp) == 0) {
3488*4882a593Smuzhiyun 			catch_memory_errors = 1;
3489*4882a593Smuzhiyun 			sync();
3490*4882a593Smuzhiyun 			*vp = kallsyms_lookup_name(tmpstr);
3491*4882a593Smuzhiyun 			sync();
3492*4882a593Smuzhiyun 		}
3493*4882a593Smuzhiyun 		catch_memory_errors = 0;
3494*4882a593Smuzhiyun 		if (!(*vp)) {
3495*4882a593Smuzhiyun 			printf("unknown symbol '%s'\n", tmpstr);
3496*4882a593Smuzhiyun 			return 0;
3497*4882a593Smuzhiyun 		}
3498*4882a593Smuzhiyun 		return 1;
3499*4882a593Smuzhiyun 	}
3500*4882a593Smuzhiyun 
3501*4882a593Smuzhiyun 	d = hexdigit(c);
3502*4882a593Smuzhiyun 	if (d == EOF) {
3503*4882a593Smuzhiyun 		termch = c;
3504*4882a593Smuzhiyun 		return 0;
3505*4882a593Smuzhiyun 	}
3506*4882a593Smuzhiyun 	v = 0;
3507*4882a593Smuzhiyun 	do {
3508*4882a593Smuzhiyun 		v = (v << 4) + d;
3509*4882a593Smuzhiyun 		c = inchar();
3510*4882a593Smuzhiyun 		d = hexdigit(c);
3511*4882a593Smuzhiyun 	} while (d != EOF);
3512*4882a593Smuzhiyun 	termch = c;
3513*4882a593Smuzhiyun 	*vp = v;
3514*4882a593Smuzhiyun 	return 1;
3515*4882a593Smuzhiyun }
3516*4882a593Smuzhiyun 
3517*4882a593Smuzhiyun static void
scannl(void)3518*4882a593Smuzhiyun scannl(void)
3519*4882a593Smuzhiyun {
3520*4882a593Smuzhiyun 	int c;
3521*4882a593Smuzhiyun 
3522*4882a593Smuzhiyun 	c = termch;
3523*4882a593Smuzhiyun 	termch = 0;
3524*4882a593Smuzhiyun 	while( c != '\n' )
3525*4882a593Smuzhiyun 		c = inchar();
3526*4882a593Smuzhiyun }
3527*4882a593Smuzhiyun 
hexdigit(int c)3528*4882a593Smuzhiyun static int hexdigit(int c)
3529*4882a593Smuzhiyun {
3530*4882a593Smuzhiyun 	if( '0' <= c && c <= '9' )
3531*4882a593Smuzhiyun 		return c - '0';
3532*4882a593Smuzhiyun 	if( 'A' <= c && c <= 'F' )
3533*4882a593Smuzhiyun 		return c - ('A' - 10);
3534*4882a593Smuzhiyun 	if( 'a' <= c && c <= 'f' )
3535*4882a593Smuzhiyun 		return c - ('a' - 10);
3536*4882a593Smuzhiyun 	return EOF;
3537*4882a593Smuzhiyun }
3538*4882a593Smuzhiyun 
3539*4882a593Smuzhiyun void
getstring(char * s,int size)3540*4882a593Smuzhiyun getstring(char *s, int size)
3541*4882a593Smuzhiyun {
3542*4882a593Smuzhiyun 	int c;
3543*4882a593Smuzhiyun 
3544*4882a593Smuzhiyun 	c = skipbl();
3545*4882a593Smuzhiyun 	if (c == '\n') {
3546*4882a593Smuzhiyun 		*s = 0;
3547*4882a593Smuzhiyun 		return;
3548*4882a593Smuzhiyun 	}
3549*4882a593Smuzhiyun 
3550*4882a593Smuzhiyun 	do {
3551*4882a593Smuzhiyun 		if( size > 1 ){
3552*4882a593Smuzhiyun 			*s++ = c;
3553*4882a593Smuzhiyun 			--size;
3554*4882a593Smuzhiyun 		}
3555*4882a593Smuzhiyun 		c = inchar();
3556*4882a593Smuzhiyun 	} while( c != ' ' && c != '\t' && c != '\n' );
3557*4882a593Smuzhiyun 	termch = c;
3558*4882a593Smuzhiyun 	*s = 0;
3559*4882a593Smuzhiyun }
3560*4882a593Smuzhiyun 
3561*4882a593Smuzhiyun static char line[256];
3562*4882a593Smuzhiyun static char *lineptr;
3563*4882a593Smuzhiyun 
3564*4882a593Smuzhiyun static void
flush_input(void)3565*4882a593Smuzhiyun flush_input(void)
3566*4882a593Smuzhiyun {
3567*4882a593Smuzhiyun 	lineptr = NULL;
3568*4882a593Smuzhiyun }
3569*4882a593Smuzhiyun 
3570*4882a593Smuzhiyun static int
inchar(void)3571*4882a593Smuzhiyun inchar(void)
3572*4882a593Smuzhiyun {
3573*4882a593Smuzhiyun 	if (lineptr == NULL || *lineptr == 0) {
3574*4882a593Smuzhiyun 		if (xmon_gets(line, sizeof(line)) == NULL) {
3575*4882a593Smuzhiyun 			lineptr = NULL;
3576*4882a593Smuzhiyun 			return EOF;
3577*4882a593Smuzhiyun 		}
3578*4882a593Smuzhiyun 		lineptr = line;
3579*4882a593Smuzhiyun 	}
3580*4882a593Smuzhiyun 	return *lineptr++;
3581*4882a593Smuzhiyun }
3582*4882a593Smuzhiyun 
3583*4882a593Smuzhiyun static void
take_input(char * str)3584*4882a593Smuzhiyun take_input(char *str)
3585*4882a593Smuzhiyun {
3586*4882a593Smuzhiyun 	lineptr = str;
3587*4882a593Smuzhiyun }
3588*4882a593Smuzhiyun 
3589*4882a593Smuzhiyun 
3590*4882a593Smuzhiyun static void
symbol_lookup(void)3591*4882a593Smuzhiyun symbol_lookup(void)
3592*4882a593Smuzhiyun {
3593*4882a593Smuzhiyun 	int type = inchar();
3594*4882a593Smuzhiyun 	unsigned long addr, cpu;
3595*4882a593Smuzhiyun 	void __percpu *ptr = NULL;
3596*4882a593Smuzhiyun 	static char tmp[64];
3597*4882a593Smuzhiyun 
3598*4882a593Smuzhiyun 	switch (type) {
3599*4882a593Smuzhiyun 	case 'a':
3600*4882a593Smuzhiyun 		if (scanhex(&addr))
3601*4882a593Smuzhiyun 			xmon_print_symbol(addr, ": ", "\n");
3602*4882a593Smuzhiyun 		termch = 0;
3603*4882a593Smuzhiyun 		break;
3604*4882a593Smuzhiyun 	case 's':
3605*4882a593Smuzhiyun 		getstring(tmp, 64);
3606*4882a593Smuzhiyun 		if (setjmp(bus_error_jmp) == 0) {
3607*4882a593Smuzhiyun 			catch_memory_errors = 1;
3608*4882a593Smuzhiyun 			sync();
3609*4882a593Smuzhiyun 			addr = kallsyms_lookup_name(tmp);
3610*4882a593Smuzhiyun 			if (addr)
3611*4882a593Smuzhiyun 				printf("%s: %lx\n", tmp, addr);
3612*4882a593Smuzhiyun 			else
3613*4882a593Smuzhiyun 				printf("Symbol '%s' not found.\n", tmp);
3614*4882a593Smuzhiyun 			sync();
3615*4882a593Smuzhiyun 		}
3616*4882a593Smuzhiyun 		catch_memory_errors = 0;
3617*4882a593Smuzhiyun 		termch = 0;
3618*4882a593Smuzhiyun 		break;
3619*4882a593Smuzhiyun 	case 'p':
3620*4882a593Smuzhiyun 		getstring(tmp, 64);
3621*4882a593Smuzhiyun 		if (setjmp(bus_error_jmp) == 0) {
3622*4882a593Smuzhiyun 			catch_memory_errors = 1;
3623*4882a593Smuzhiyun 			sync();
3624*4882a593Smuzhiyun 			ptr = (void __percpu *)kallsyms_lookup_name(tmp);
3625*4882a593Smuzhiyun 			sync();
3626*4882a593Smuzhiyun 		}
3627*4882a593Smuzhiyun 
3628*4882a593Smuzhiyun 		if (ptr &&
3629*4882a593Smuzhiyun 		    ptr >= (void __percpu *)__per_cpu_start &&
3630*4882a593Smuzhiyun 		    ptr < (void __percpu *)__per_cpu_end)
3631*4882a593Smuzhiyun 		{
3632*4882a593Smuzhiyun 			if (scanhex(&cpu) && cpu < num_possible_cpus()) {
3633*4882a593Smuzhiyun 				addr = (unsigned long)per_cpu_ptr(ptr, cpu);
3634*4882a593Smuzhiyun 			} else {
3635*4882a593Smuzhiyun 				cpu = raw_smp_processor_id();
3636*4882a593Smuzhiyun 				addr = (unsigned long)this_cpu_ptr(ptr);
3637*4882a593Smuzhiyun 			}
3638*4882a593Smuzhiyun 
3639*4882a593Smuzhiyun 			printf("%s for cpu 0x%lx: %lx\n", tmp, cpu, addr);
3640*4882a593Smuzhiyun 		} else {
3641*4882a593Smuzhiyun 			printf("Percpu symbol '%s' not found.\n", tmp);
3642*4882a593Smuzhiyun 		}
3643*4882a593Smuzhiyun 
3644*4882a593Smuzhiyun 		catch_memory_errors = 0;
3645*4882a593Smuzhiyun 		termch = 0;
3646*4882a593Smuzhiyun 		break;
3647*4882a593Smuzhiyun 	}
3648*4882a593Smuzhiyun }
3649*4882a593Smuzhiyun 
3650*4882a593Smuzhiyun 
3651*4882a593Smuzhiyun /* Print an address in numeric and symbolic form (if possible) */
xmon_print_symbol(unsigned long address,const char * mid,const char * after)3652*4882a593Smuzhiyun static void xmon_print_symbol(unsigned long address, const char *mid,
3653*4882a593Smuzhiyun 			      const char *after)
3654*4882a593Smuzhiyun {
3655*4882a593Smuzhiyun 	char *modname;
3656*4882a593Smuzhiyun 	const char *name = NULL;
3657*4882a593Smuzhiyun 	unsigned long offset, size;
3658*4882a593Smuzhiyun 
3659*4882a593Smuzhiyun 	printf(REG, address);
3660*4882a593Smuzhiyun 	if (setjmp(bus_error_jmp) == 0) {
3661*4882a593Smuzhiyun 		catch_memory_errors = 1;
3662*4882a593Smuzhiyun 		sync();
3663*4882a593Smuzhiyun 		name = kallsyms_lookup(address, &size, &offset, &modname,
3664*4882a593Smuzhiyun 				       tmpstr);
3665*4882a593Smuzhiyun 		sync();
3666*4882a593Smuzhiyun 		/* wait a little while to see if we get a machine check */
3667*4882a593Smuzhiyun 		__delay(200);
3668*4882a593Smuzhiyun 	}
3669*4882a593Smuzhiyun 
3670*4882a593Smuzhiyun 	catch_memory_errors = 0;
3671*4882a593Smuzhiyun 
3672*4882a593Smuzhiyun 	if (name) {
3673*4882a593Smuzhiyun 		printf("%s%s+%#lx/%#lx", mid, name, offset, size);
3674*4882a593Smuzhiyun 		if (modname)
3675*4882a593Smuzhiyun 			printf(" [%s]", modname);
3676*4882a593Smuzhiyun 	}
3677*4882a593Smuzhiyun 	printf("%s", after);
3678*4882a593Smuzhiyun }
3679*4882a593Smuzhiyun 
3680*4882a593Smuzhiyun #ifdef CONFIG_PPC_BOOK3S_64
dump_segments(void)3681*4882a593Smuzhiyun void dump_segments(void)
3682*4882a593Smuzhiyun {
3683*4882a593Smuzhiyun 	int i;
3684*4882a593Smuzhiyun 	unsigned long esid,vsid;
3685*4882a593Smuzhiyun 	unsigned long llp;
3686*4882a593Smuzhiyun 
3687*4882a593Smuzhiyun 	printf("SLB contents of cpu 0x%x\n", smp_processor_id());
3688*4882a593Smuzhiyun 
3689*4882a593Smuzhiyun 	for (i = 0; i < mmu_slb_size; i++) {
3690*4882a593Smuzhiyun 		asm volatile("slbmfee  %0,%1" : "=r" (esid) : "r" (i));
3691*4882a593Smuzhiyun 		asm volatile("slbmfev  %0,%1" : "=r" (vsid) : "r" (i));
3692*4882a593Smuzhiyun 
3693*4882a593Smuzhiyun 		if (!esid && !vsid)
3694*4882a593Smuzhiyun 			continue;
3695*4882a593Smuzhiyun 
3696*4882a593Smuzhiyun 		printf("%02d %016lx %016lx", i, esid, vsid);
3697*4882a593Smuzhiyun 
3698*4882a593Smuzhiyun 		if (!(esid & SLB_ESID_V)) {
3699*4882a593Smuzhiyun 			printf("\n");
3700*4882a593Smuzhiyun 			continue;
3701*4882a593Smuzhiyun 		}
3702*4882a593Smuzhiyun 
3703*4882a593Smuzhiyun 		llp = vsid & SLB_VSID_LLP;
3704*4882a593Smuzhiyun 		if (vsid & SLB_VSID_B_1T) {
3705*4882a593Smuzhiyun 			printf("  1T  ESID=%9lx  VSID=%13lx LLP:%3lx \n",
3706*4882a593Smuzhiyun 				GET_ESID_1T(esid),
3707*4882a593Smuzhiyun 				(vsid & ~SLB_VSID_B) >> SLB_VSID_SHIFT_1T,
3708*4882a593Smuzhiyun 				llp);
3709*4882a593Smuzhiyun 		} else {
3710*4882a593Smuzhiyun 			printf(" 256M ESID=%9lx  VSID=%13lx LLP:%3lx \n",
3711*4882a593Smuzhiyun 				GET_ESID(esid),
3712*4882a593Smuzhiyun 				(vsid & ~SLB_VSID_B) >> SLB_VSID_SHIFT,
3713*4882a593Smuzhiyun 				llp);
3714*4882a593Smuzhiyun 		}
3715*4882a593Smuzhiyun 	}
3716*4882a593Smuzhiyun }
3717*4882a593Smuzhiyun #endif
3718*4882a593Smuzhiyun 
3719*4882a593Smuzhiyun #ifdef CONFIG_PPC_BOOK3S_32
dump_segments(void)3720*4882a593Smuzhiyun void dump_segments(void)
3721*4882a593Smuzhiyun {
3722*4882a593Smuzhiyun 	int i;
3723*4882a593Smuzhiyun 
3724*4882a593Smuzhiyun 	printf("sr0-15 =");
3725*4882a593Smuzhiyun 	for (i = 0; i < 16; ++i)
3726*4882a593Smuzhiyun 		printf(" %x", mfsrin(i << 28));
3727*4882a593Smuzhiyun 	printf("\n");
3728*4882a593Smuzhiyun }
3729*4882a593Smuzhiyun #endif
3730*4882a593Smuzhiyun 
3731*4882a593Smuzhiyun #ifdef CONFIG_44x
dump_tlb_44x(void)3732*4882a593Smuzhiyun static void dump_tlb_44x(void)
3733*4882a593Smuzhiyun {
3734*4882a593Smuzhiyun 	int i;
3735*4882a593Smuzhiyun 
3736*4882a593Smuzhiyun 	for (i = 0; i < PPC44x_TLB_SIZE; i++) {
3737*4882a593Smuzhiyun 		unsigned long w0,w1,w2;
3738*4882a593Smuzhiyun 		asm volatile("tlbre  %0,%1,0" : "=r" (w0) : "r" (i));
3739*4882a593Smuzhiyun 		asm volatile("tlbre  %0,%1,1" : "=r" (w1) : "r" (i));
3740*4882a593Smuzhiyun 		asm volatile("tlbre  %0,%1,2" : "=r" (w2) : "r" (i));
3741*4882a593Smuzhiyun 		printf("[%02x] %08lx %08lx %08lx ", i, w0, w1, w2);
3742*4882a593Smuzhiyun 		if (w0 & PPC44x_TLB_VALID) {
3743*4882a593Smuzhiyun 			printf("V %08lx -> %01lx%08lx %c%c%c%c%c",
3744*4882a593Smuzhiyun 			       w0 & PPC44x_TLB_EPN_MASK,
3745*4882a593Smuzhiyun 			       w1 & PPC44x_TLB_ERPN_MASK,
3746*4882a593Smuzhiyun 			       w1 & PPC44x_TLB_RPN_MASK,
3747*4882a593Smuzhiyun 			       (w2 & PPC44x_TLB_W) ? 'W' : 'w',
3748*4882a593Smuzhiyun 			       (w2 & PPC44x_TLB_I) ? 'I' : 'i',
3749*4882a593Smuzhiyun 			       (w2 & PPC44x_TLB_M) ? 'M' : 'm',
3750*4882a593Smuzhiyun 			       (w2 & PPC44x_TLB_G) ? 'G' : 'g',
3751*4882a593Smuzhiyun 			       (w2 & PPC44x_TLB_E) ? 'E' : 'e');
3752*4882a593Smuzhiyun 		}
3753*4882a593Smuzhiyun 		printf("\n");
3754*4882a593Smuzhiyun 	}
3755*4882a593Smuzhiyun }
3756*4882a593Smuzhiyun #endif /* CONFIG_44x */
3757*4882a593Smuzhiyun 
3758*4882a593Smuzhiyun #ifdef CONFIG_PPC_BOOK3E
dump_tlb_book3e(void)3759*4882a593Smuzhiyun static void dump_tlb_book3e(void)
3760*4882a593Smuzhiyun {
3761*4882a593Smuzhiyun 	u32 mmucfg, pidmask, lpidmask;
3762*4882a593Smuzhiyun 	u64 ramask;
3763*4882a593Smuzhiyun 	int i, tlb, ntlbs, pidsz, lpidsz, rasz, lrat = 0;
3764*4882a593Smuzhiyun 	int mmu_version;
3765*4882a593Smuzhiyun 	static const char *pgsz_names[] = {
3766*4882a593Smuzhiyun 		"  1K",
3767*4882a593Smuzhiyun 		"  2K",
3768*4882a593Smuzhiyun 		"  4K",
3769*4882a593Smuzhiyun 		"  8K",
3770*4882a593Smuzhiyun 		" 16K",
3771*4882a593Smuzhiyun 		" 32K",
3772*4882a593Smuzhiyun 		" 64K",
3773*4882a593Smuzhiyun 		"128K",
3774*4882a593Smuzhiyun 		"256K",
3775*4882a593Smuzhiyun 		"512K",
3776*4882a593Smuzhiyun 		"  1M",
3777*4882a593Smuzhiyun 		"  2M",
3778*4882a593Smuzhiyun 		"  4M",
3779*4882a593Smuzhiyun 		"  8M",
3780*4882a593Smuzhiyun 		" 16M",
3781*4882a593Smuzhiyun 		" 32M",
3782*4882a593Smuzhiyun 		" 64M",
3783*4882a593Smuzhiyun 		"128M",
3784*4882a593Smuzhiyun 		"256M",
3785*4882a593Smuzhiyun 		"512M",
3786*4882a593Smuzhiyun 		"  1G",
3787*4882a593Smuzhiyun 		"  2G",
3788*4882a593Smuzhiyun 		"  4G",
3789*4882a593Smuzhiyun 		"  8G",
3790*4882a593Smuzhiyun 		" 16G",
3791*4882a593Smuzhiyun 		" 32G",
3792*4882a593Smuzhiyun 		" 64G",
3793*4882a593Smuzhiyun 		"128G",
3794*4882a593Smuzhiyun 		"256G",
3795*4882a593Smuzhiyun 		"512G",
3796*4882a593Smuzhiyun 		"  1T",
3797*4882a593Smuzhiyun 		"  2T",
3798*4882a593Smuzhiyun 	};
3799*4882a593Smuzhiyun 
3800*4882a593Smuzhiyun 	/* Gather some infos about the MMU */
3801*4882a593Smuzhiyun 	mmucfg = mfspr(SPRN_MMUCFG);
3802*4882a593Smuzhiyun 	mmu_version = (mmucfg & 3) + 1;
3803*4882a593Smuzhiyun 	ntlbs = ((mmucfg >> 2) & 3) + 1;
3804*4882a593Smuzhiyun 	pidsz = ((mmucfg >> 6) & 0x1f) + 1;
3805*4882a593Smuzhiyun 	lpidsz = (mmucfg >> 24) & 0xf;
3806*4882a593Smuzhiyun 	rasz = (mmucfg >> 16) & 0x7f;
3807*4882a593Smuzhiyun 	if ((mmu_version > 1) && (mmucfg & 0x10000))
3808*4882a593Smuzhiyun 		lrat = 1;
3809*4882a593Smuzhiyun 	printf("Book3E MMU MAV=%d.0,%d TLBs,%d-bit PID,%d-bit LPID,%d-bit RA\n",
3810*4882a593Smuzhiyun 	       mmu_version, ntlbs, pidsz, lpidsz, rasz);
3811*4882a593Smuzhiyun 	pidmask = (1ul << pidsz) - 1;
3812*4882a593Smuzhiyun 	lpidmask = (1ul << lpidsz) - 1;
3813*4882a593Smuzhiyun 	ramask = (1ull << rasz) - 1;
3814*4882a593Smuzhiyun 
3815*4882a593Smuzhiyun 	for (tlb = 0; tlb < ntlbs; tlb++) {
3816*4882a593Smuzhiyun 		u32 tlbcfg;
3817*4882a593Smuzhiyun 		int nent, assoc, new_cc = 1;
3818*4882a593Smuzhiyun 		printf("TLB %d:\n------\n", tlb);
3819*4882a593Smuzhiyun 		switch(tlb) {
3820*4882a593Smuzhiyun 		case 0:
3821*4882a593Smuzhiyun 			tlbcfg = mfspr(SPRN_TLB0CFG);
3822*4882a593Smuzhiyun 			break;
3823*4882a593Smuzhiyun 		case 1:
3824*4882a593Smuzhiyun 			tlbcfg = mfspr(SPRN_TLB1CFG);
3825*4882a593Smuzhiyun 			break;
3826*4882a593Smuzhiyun 		case 2:
3827*4882a593Smuzhiyun 			tlbcfg = mfspr(SPRN_TLB2CFG);
3828*4882a593Smuzhiyun 			break;
3829*4882a593Smuzhiyun 		case 3:
3830*4882a593Smuzhiyun 			tlbcfg = mfspr(SPRN_TLB3CFG);
3831*4882a593Smuzhiyun 			break;
3832*4882a593Smuzhiyun 		default:
3833*4882a593Smuzhiyun 			printf("Unsupported TLB number !\n");
3834*4882a593Smuzhiyun 			continue;
3835*4882a593Smuzhiyun 		}
3836*4882a593Smuzhiyun 		nent = tlbcfg & 0xfff;
3837*4882a593Smuzhiyun 		assoc = (tlbcfg >> 24) & 0xff;
3838*4882a593Smuzhiyun 		for (i = 0; i < nent; i++) {
3839*4882a593Smuzhiyun 			u32 mas0 = MAS0_TLBSEL(tlb);
3840*4882a593Smuzhiyun 			u32 mas1 = MAS1_TSIZE(BOOK3E_PAGESZ_4K);
3841*4882a593Smuzhiyun 			u64 mas2 = 0;
3842*4882a593Smuzhiyun 			u64 mas7_mas3;
3843*4882a593Smuzhiyun 			int esel = i, cc = i;
3844*4882a593Smuzhiyun 
3845*4882a593Smuzhiyun 			if (assoc != 0) {
3846*4882a593Smuzhiyun 				cc = i / assoc;
3847*4882a593Smuzhiyun 				esel = i % assoc;
3848*4882a593Smuzhiyun 				mas2 = cc * 0x1000;
3849*4882a593Smuzhiyun 			}
3850*4882a593Smuzhiyun 
3851*4882a593Smuzhiyun 			mas0 |= MAS0_ESEL(esel);
3852*4882a593Smuzhiyun 			mtspr(SPRN_MAS0, mas0);
3853*4882a593Smuzhiyun 			mtspr(SPRN_MAS1, mas1);
3854*4882a593Smuzhiyun 			mtspr(SPRN_MAS2, mas2);
3855*4882a593Smuzhiyun 			asm volatile("tlbre  0,0,0" : : : "memory");
3856*4882a593Smuzhiyun 			mas1 = mfspr(SPRN_MAS1);
3857*4882a593Smuzhiyun 			mas2 = mfspr(SPRN_MAS2);
3858*4882a593Smuzhiyun 			mas7_mas3 = mfspr(SPRN_MAS7_MAS3);
3859*4882a593Smuzhiyun 			if (assoc && (i % assoc) == 0)
3860*4882a593Smuzhiyun 				new_cc = 1;
3861*4882a593Smuzhiyun 			if (!(mas1 & MAS1_VALID))
3862*4882a593Smuzhiyun 				continue;
3863*4882a593Smuzhiyun 			if (assoc == 0)
3864*4882a593Smuzhiyun 				printf("%04x- ", i);
3865*4882a593Smuzhiyun 			else if (new_cc)
3866*4882a593Smuzhiyun 				printf("%04x-%c", cc, 'A' + esel);
3867*4882a593Smuzhiyun 			else
3868*4882a593Smuzhiyun 				printf("    |%c", 'A' + esel);
3869*4882a593Smuzhiyun 			new_cc = 0;
3870*4882a593Smuzhiyun 			printf(" %016llx %04x %s %c%c AS%c",
3871*4882a593Smuzhiyun 			       mas2 & ~0x3ffull,
3872*4882a593Smuzhiyun 			       (mas1 >> 16) & 0x3fff,
3873*4882a593Smuzhiyun 			       pgsz_names[(mas1 >> 7) & 0x1f],
3874*4882a593Smuzhiyun 			       mas1 & MAS1_IND ? 'I' : ' ',
3875*4882a593Smuzhiyun 			       mas1 & MAS1_IPROT ? 'P' : ' ',
3876*4882a593Smuzhiyun 			       mas1 & MAS1_TS ? '1' : '0');
3877*4882a593Smuzhiyun 			printf(" %c%c%c%c%c%c%c",
3878*4882a593Smuzhiyun 			       mas2 & MAS2_X0 ? 'a' : ' ',
3879*4882a593Smuzhiyun 			       mas2 & MAS2_X1 ? 'v' : ' ',
3880*4882a593Smuzhiyun 			       mas2 & MAS2_W  ? 'w' : ' ',
3881*4882a593Smuzhiyun 			       mas2 & MAS2_I  ? 'i' : ' ',
3882*4882a593Smuzhiyun 			       mas2 & MAS2_M  ? 'm' : ' ',
3883*4882a593Smuzhiyun 			       mas2 & MAS2_G  ? 'g' : ' ',
3884*4882a593Smuzhiyun 			       mas2 & MAS2_E  ? 'e' : ' ');
3885*4882a593Smuzhiyun 			printf(" %016llx", mas7_mas3 & ramask & ~0x7ffull);
3886*4882a593Smuzhiyun 			if (mas1 & MAS1_IND)
3887*4882a593Smuzhiyun 				printf(" %s\n",
3888*4882a593Smuzhiyun 				       pgsz_names[(mas7_mas3 >> 1) & 0x1f]);
3889*4882a593Smuzhiyun 			else
3890*4882a593Smuzhiyun 				printf(" U%c%c%c S%c%c%c\n",
3891*4882a593Smuzhiyun 				       mas7_mas3 & MAS3_UX ? 'x' : ' ',
3892*4882a593Smuzhiyun 				       mas7_mas3 & MAS3_UW ? 'w' : ' ',
3893*4882a593Smuzhiyun 				       mas7_mas3 & MAS3_UR ? 'r' : ' ',
3894*4882a593Smuzhiyun 				       mas7_mas3 & MAS3_SX ? 'x' : ' ',
3895*4882a593Smuzhiyun 				       mas7_mas3 & MAS3_SW ? 'w' : ' ',
3896*4882a593Smuzhiyun 				       mas7_mas3 & MAS3_SR ? 'r' : ' ');
3897*4882a593Smuzhiyun 		}
3898*4882a593Smuzhiyun 	}
3899*4882a593Smuzhiyun }
3900*4882a593Smuzhiyun #endif /* CONFIG_PPC_BOOK3E */
3901*4882a593Smuzhiyun 
xmon_init(int enable)3902*4882a593Smuzhiyun static void xmon_init(int enable)
3903*4882a593Smuzhiyun {
3904*4882a593Smuzhiyun 	if (enable) {
3905*4882a593Smuzhiyun 		__debugger = xmon;
3906*4882a593Smuzhiyun 		__debugger_ipi = xmon_ipi;
3907*4882a593Smuzhiyun 		__debugger_bpt = xmon_bpt;
3908*4882a593Smuzhiyun 		__debugger_sstep = xmon_sstep;
3909*4882a593Smuzhiyun 		__debugger_iabr_match = xmon_iabr_match;
3910*4882a593Smuzhiyun 		__debugger_break_match = xmon_break_match;
3911*4882a593Smuzhiyun 		__debugger_fault_handler = xmon_fault_handler;
3912*4882a593Smuzhiyun 
3913*4882a593Smuzhiyun #ifdef CONFIG_PPC_PSERIES
3914*4882a593Smuzhiyun 		/*
3915*4882a593Smuzhiyun 		 * Get the token here to avoid trying to get a lock
3916*4882a593Smuzhiyun 		 * during the crash, causing a deadlock.
3917*4882a593Smuzhiyun 		 */
3918*4882a593Smuzhiyun 		set_indicator_token = rtas_token("set-indicator");
3919*4882a593Smuzhiyun #endif
3920*4882a593Smuzhiyun 	} else {
3921*4882a593Smuzhiyun 		__debugger = NULL;
3922*4882a593Smuzhiyun 		__debugger_ipi = NULL;
3923*4882a593Smuzhiyun 		__debugger_bpt = NULL;
3924*4882a593Smuzhiyun 		__debugger_sstep = NULL;
3925*4882a593Smuzhiyun 		__debugger_iabr_match = NULL;
3926*4882a593Smuzhiyun 		__debugger_break_match = NULL;
3927*4882a593Smuzhiyun 		__debugger_fault_handler = NULL;
3928*4882a593Smuzhiyun 	}
3929*4882a593Smuzhiyun }
3930*4882a593Smuzhiyun 
3931*4882a593Smuzhiyun #ifdef CONFIG_MAGIC_SYSRQ
sysrq_handle_xmon(int key)3932*4882a593Smuzhiyun static void sysrq_handle_xmon(int key)
3933*4882a593Smuzhiyun {
3934*4882a593Smuzhiyun 	if (xmon_is_locked_down()) {
3935*4882a593Smuzhiyun 		clear_all_bpt();
3936*4882a593Smuzhiyun 		xmon_init(0);
3937*4882a593Smuzhiyun 		return;
3938*4882a593Smuzhiyun 	}
3939*4882a593Smuzhiyun 	/* ensure xmon is enabled */
3940*4882a593Smuzhiyun 	xmon_init(1);
3941*4882a593Smuzhiyun 	debugger(get_irq_regs());
3942*4882a593Smuzhiyun 	if (!xmon_on)
3943*4882a593Smuzhiyun 		xmon_init(0);
3944*4882a593Smuzhiyun }
3945*4882a593Smuzhiyun 
3946*4882a593Smuzhiyun static const struct sysrq_key_op sysrq_xmon_op = {
3947*4882a593Smuzhiyun 	.handler =	sysrq_handle_xmon,
3948*4882a593Smuzhiyun 	.help_msg =	"xmon(x)",
3949*4882a593Smuzhiyun 	.action_msg =	"Entering xmon",
3950*4882a593Smuzhiyun };
3951*4882a593Smuzhiyun 
setup_xmon_sysrq(void)3952*4882a593Smuzhiyun static int __init setup_xmon_sysrq(void)
3953*4882a593Smuzhiyun {
3954*4882a593Smuzhiyun 	register_sysrq_key('x', &sysrq_xmon_op);
3955*4882a593Smuzhiyun 	return 0;
3956*4882a593Smuzhiyun }
3957*4882a593Smuzhiyun device_initcall(setup_xmon_sysrq);
3958*4882a593Smuzhiyun #endif /* CONFIG_MAGIC_SYSRQ */
3959*4882a593Smuzhiyun 
clear_all_bpt(void)3960*4882a593Smuzhiyun static void clear_all_bpt(void)
3961*4882a593Smuzhiyun {
3962*4882a593Smuzhiyun 	int i;
3963*4882a593Smuzhiyun 
3964*4882a593Smuzhiyun 	/* clear/unpatch all breakpoints */
3965*4882a593Smuzhiyun 	remove_bpts();
3966*4882a593Smuzhiyun 	remove_cpu_bpts();
3967*4882a593Smuzhiyun 
3968*4882a593Smuzhiyun 	/* Disable all breakpoints */
3969*4882a593Smuzhiyun 	for (i = 0; i < NBPTS; ++i)
3970*4882a593Smuzhiyun 		bpts[i].enabled = 0;
3971*4882a593Smuzhiyun 
3972*4882a593Smuzhiyun 	/* Clear any data or iabr breakpoints */
3973*4882a593Smuzhiyun 	iabr = NULL;
3974*4882a593Smuzhiyun 	for (i = 0; i < nr_wp_slots(); i++)
3975*4882a593Smuzhiyun 		dabr[i].enabled = 0;
3976*4882a593Smuzhiyun }
3977*4882a593Smuzhiyun 
3978*4882a593Smuzhiyun #ifdef CONFIG_DEBUG_FS
xmon_dbgfs_set(void * data,u64 val)3979*4882a593Smuzhiyun static int xmon_dbgfs_set(void *data, u64 val)
3980*4882a593Smuzhiyun {
3981*4882a593Smuzhiyun 	xmon_on = !!val;
3982*4882a593Smuzhiyun 	xmon_init(xmon_on);
3983*4882a593Smuzhiyun 
3984*4882a593Smuzhiyun 	/* make sure all breakpoints removed when disabling */
3985*4882a593Smuzhiyun 	if (!xmon_on) {
3986*4882a593Smuzhiyun 		clear_all_bpt();
3987*4882a593Smuzhiyun 		get_output_lock();
3988*4882a593Smuzhiyun 		printf("xmon: All breakpoints cleared\n");
3989*4882a593Smuzhiyun 		release_output_lock();
3990*4882a593Smuzhiyun 	}
3991*4882a593Smuzhiyun 
3992*4882a593Smuzhiyun 	return 0;
3993*4882a593Smuzhiyun }
3994*4882a593Smuzhiyun 
xmon_dbgfs_get(void * data,u64 * val)3995*4882a593Smuzhiyun static int xmon_dbgfs_get(void *data, u64 *val)
3996*4882a593Smuzhiyun {
3997*4882a593Smuzhiyun 	*val = xmon_on;
3998*4882a593Smuzhiyun 	return 0;
3999*4882a593Smuzhiyun }
4000*4882a593Smuzhiyun 
4001*4882a593Smuzhiyun DEFINE_SIMPLE_ATTRIBUTE(xmon_dbgfs_ops, xmon_dbgfs_get,
4002*4882a593Smuzhiyun 			xmon_dbgfs_set, "%llu\n");
4003*4882a593Smuzhiyun 
setup_xmon_dbgfs(void)4004*4882a593Smuzhiyun static int __init setup_xmon_dbgfs(void)
4005*4882a593Smuzhiyun {
4006*4882a593Smuzhiyun 	debugfs_create_file("xmon", 0600, powerpc_debugfs_root, NULL,
4007*4882a593Smuzhiyun 				&xmon_dbgfs_ops);
4008*4882a593Smuzhiyun 	return 0;
4009*4882a593Smuzhiyun }
4010*4882a593Smuzhiyun device_initcall(setup_xmon_dbgfs);
4011*4882a593Smuzhiyun #endif /* CONFIG_DEBUG_FS */
4012*4882a593Smuzhiyun 
4013*4882a593Smuzhiyun static int xmon_early __initdata;
4014*4882a593Smuzhiyun 
early_parse_xmon(char * p)4015*4882a593Smuzhiyun static int __init early_parse_xmon(char *p)
4016*4882a593Smuzhiyun {
4017*4882a593Smuzhiyun 	if (xmon_is_locked_down()) {
4018*4882a593Smuzhiyun 		xmon_init(0);
4019*4882a593Smuzhiyun 		xmon_early = 0;
4020*4882a593Smuzhiyun 		xmon_on = 0;
4021*4882a593Smuzhiyun 	} else if (!p || strncmp(p, "early", 5) == 0) {
4022*4882a593Smuzhiyun 		/* just "xmon" is equivalent to "xmon=early" */
4023*4882a593Smuzhiyun 		xmon_init(1);
4024*4882a593Smuzhiyun 		xmon_early = 1;
4025*4882a593Smuzhiyun 		xmon_on = 1;
4026*4882a593Smuzhiyun 	} else if (strncmp(p, "on", 2) == 0) {
4027*4882a593Smuzhiyun 		xmon_init(1);
4028*4882a593Smuzhiyun 		xmon_on = 1;
4029*4882a593Smuzhiyun 	} else if (strncmp(p, "rw", 2) == 0) {
4030*4882a593Smuzhiyun 		xmon_init(1);
4031*4882a593Smuzhiyun 		xmon_on = 1;
4032*4882a593Smuzhiyun 		xmon_is_ro = false;
4033*4882a593Smuzhiyun 	} else if (strncmp(p, "ro", 2) == 0) {
4034*4882a593Smuzhiyun 		xmon_init(1);
4035*4882a593Smuzhiyun 		xmon_on = 1;
4036*4882a593Smuzhiyun 		xmon_is_ro = true;
4037*4882a593Smuzhiyun 	} else if (strncmp(p, "off", 3) == 0)
4038*4882a593Smuzhiyun 		xmon_on = 0;
4039*4882a593Smuzhiyun 	else
4040*4882a593Smuzhiyun 		return 1;
4041*4882a593Smuzhiyun 
4042*4882a593Smuzhiyun 	return 0;
4043*4882a593Smuzhiyun }
4044*4882a593Smuzhiyun early_param("xmon", early_parse_xmon);
4045*4882a593Smuzhiyun 
xmon_setup(void)4046*4882a593Smuzhiyun void __init xmon_setup(void)
4047*4882a593Smuzhiyun {
4048*4882a593Smuzhiyun 	if (xmon_on)
4049*4882a593Smuzhiyun 		xmon_init(1);
4050*4882a593Smuzhiyun 	if (xmon_early)
4051*4882a593Smuzhiyun 		debugger(NULL);
4052*4882a593Smuzhiyun }
4053*4882a593Smuzhiyun 
4054*4882a593Smuzhiyun #ifdef CONFIG_SPU_BASE
4055*4882a593Smuzhiyun 
4056*4882a593Smuzhiyun struct spu_info {
4057*4882a593Smuzhiyun 	struct spu *spu;
4058*4882a593Smuzhiyun 	u64 saved_mfc_sr1_RW;
4059*4882a593Smuzhiyun 	u32 saved_spu_runcntl_RW;
4060*4882a593Smuzhiyun 	unsigned long dump_addr;
4061*4882a593Smuzhiyun 	u8 stopped_ok;
4062*4882a593Smuzhiyun };
4063*4882a593Smuzhiyun 
4064*4882a593Smuzhiyun #define XMON_NUM_SPUS	16	/* Enough for current hardware */
4065*4882a593Smuzhiyun 
4066*4882a593Smuzhiyun static struct spu_info spu_info[XMON_NUM_SPUS];
4067*4882a593Smuzhiyun 
xmon_register_spus(struct list_head * list)4068*4882a593Smuzhiyun void xmon_register_spus(struct list_head *list)
4069*4882a593Smuzhiyun {
4070*4882a593Smuzhiyun 	struct spu *spu;
4071*4882a593Smuzhiyun 
4072*4882a593Smuzhiyun 	list_for_each_entry(spu, list, full_list) {
4073*4882a593Smuzhiyun 		if (spu->number >= XMON_NUM_SPUS) {
4074*4882a593Smuzhiyun 			WARN_ON(1);
4075*4882a593Smuzhiyun 			continue;
4076*4882a593Smuzhiyun 		}
4077*4882a593Smuzhiyun 
4078*4882a593Smuzhiyun 		spu_info[spu->number].spu = spu;
4079*4882a593Smuzhiyun 		spu_info[spu->number].stopped_ok = 0;
4080*4882a593Smuzhiyun 		spu_info[spu->number].dump_addr = (unsigned long)
4081*4882a593Smuzhiyun 				spu_info[spu->number].spu->local_store;
4082*4882a593Smuzhiyun 	}
4083*4882a593Smuzhiyun }
4084*4882a593Smuzhiyun 
stop_spus(void)4085*4882a593Smuzhiyun static void stop_spus(void)
4086*4882a593Smuzhiyun {
4087*4882a593Smuzhiyun 	struct spu *spu;
4088*4882a593Smuzhiyun 	int i;
4089*4882a593Smuzhiyun 	u64 tmp;
4090*4882a593Smuzhiyun 
4091*4882a593Smuzhiyun 	for (i = 0; i < XMON_NUM_SPUS; i++) {
4092*4882a593Smuzhiyun 		if (!spu_info[i].spu)
4093*4882a593Smuzhiyun 			continue;
4094*4882a593Smuzhiyun 
4095*4882a593Smuzhiyun 		if (setjmp(bus_error_jmp) == 0) {
4096*4882a593Smuzhiyun 			catch_memory_errors = 1;
4097*4882a593Smuzhiyun 			sync();
4098*4882a593Smuzhiyun 
4099*4882a593Smuzhiyun 			spu = spu_info[i].spu;
4100*4882a593Smuzhiyun 
4101*4882a593Smuzhiyun 			spu_info[i].saved_spu_runcntl_RW =
4102*4882a593Smuzhiyun 				in_be32(&spu->problem->spu_runcntl_RW);
4103*4882a593Smuzhiyun 
4104*4882a593Smuzhiyun 			tmp = spu_mfc_sr1_get(spu);
4105*4882a593Smuzhiyun 			spu_info[i].saved_mfc_sr1_RW = tmp;
4106*4882a593Smuzhiyun 
4107*4882a593Smuzhiyun 			tmp &= ~MFC_STATE1_MASTER_RUN_CONTROL_MASK;
4108*4882a593Smuzhiyun 			spu_mfc_sr1_set(spu, tmp);
4109*4882a593Smuzhiyun 
4110*4882a593Smuzhiyun 			sync();
4111*4882a593Smuzhiyun 			__delay(200);
4112*4882a593Smuzhiyun 
4113*4882a593Smuzhiyun 			spu_info[i].stopped_ok = 1;
4114*4882a593Smuzhiyun 
4115*4882a593Smuzhiyun 			printf("Stopped spu %.2d (was %s)\n", i,
4116*4882a593Smuzhiyun 					spu_info[i].saved_spu_runcntl_RW ?
4117*4882a593Smuzhiyun 					"running" : "stopped");
4118*4882a593Smuzhiyun 		} else {
4119*4882a593Smuzhiyun 			catch_memory_errors = 0;
4120*4882a593Smuzhiyun 			printf("*** Error stopping spu %.2d\n", i);
4121*4882a593Smuzhiyun 		}
4122*4882a593Smuzhiyun 		catch_memory_errors = 0;
4123*4882a593Smuzhiyun 	}
4124*4882a593Smuzhiyun }
4125*4882a593Smuzhiyun 
restart_spus(void)4126*4882a593Smuzhiyun static void restart_spus(void)
4127*4882a593Smuzhiyun {
4128*4882a593Smuzhiyun 	struct spu *spu;
4129*4882a593Smuzhiyun 	int i;
4130*4882a593Smuzhiyun 
4131*4882a593Smuzhiyun 	for (i = 0; i < XMON_NUM_SPUS; i++) {
4132*4882a593Smuzhiyun 		if (!spu_info[i].spu)
4133*4882a593Smuzhiyun 			continue;
4134*4882a593Smuzhiyun 
4135*4882a593Smuzhiyun 		if (!spu_info[i].stopped_ok) {
4136*4882a593Smuzhiyun 			printf("*** Error, spu %d was not successfully stopped"
4137*4882a593Smuzhiyun 					", not restarting\n", i);
4138*4882a593Smuzhiyun 			continue;
4139*4882a593Smuzhiyun 		}
4140*4882a593Smuzhiyun 
4141*4882a593Smuzhiyun 		if (setjmp(bus_error_jmp) == 0) {
4142*4882a593Smuzhiyun 			catch_memory_errors = 1;
4143*4882a593Smuzhiyun 			sync();
4144*4882a593Smuzhiyun 
4145*4882a593Smuzhiyun 			spu = spu_info[i].spu;
4146*4882a593Smuzhiyun 			spu_mfc_sr1_set(spu, spu_info[i].saved_mfc_sr1_RW);
4147*4882a593Smuzhiyun 			out_be32(&spu->problem->spu_runcntl_RW,
4148*4882a593Smuzhiyun 					spu_info[i].saved_spu_runcntl_RW);
4149*4882a593Smuzhiyun 
4150*4882a593Smuzhiyun 			sync();
4151*4882a593Smuzhiyun 			__delay(200);
4152*4882a593Smuzhiyun 
4153*4882a593Smuzhiyun 			printf("Restarted spu %.2d\n", i);
4154*4882a593Smuzhiyun 		} else {
4155*4882a593Smuzhiyun 			catch_memory_errors = 0;
4156*4882a593Smuzhiyun 			printf("*** Error restarting spu %.2d\n", i);
4157*4882a593Smuzhiyun 		}
4158*4882a593Smuzhiyun 		catch_memory_errors = 0;
4159*4882a593Smuzhiyun 	}
4160*4882a593Smuzhiyun }
4161*4882a593Smuzhiyun 
4162*4882a593Smuzhiyun #define DUMP_WIDTH	23
4163*4882a593Smuzhiyun #define DUMP_VALUE(format, field, value)				\
4164*4882a593Smuzhiyun do {									\
4165*4882a593Smuzhiyun 	if (setjmp(bus_error_jmp) == 0) {				\
4166*4882a593Smuzhiyun 		catch_memory_errors = 1;				\
4167*4882a593Smuzhiyun 		sync();							\
4168*4882a593Smuzhiyun 		printf("  %-*s = "format"\n", DUMP_WIDTH,		\
4169*4882a593Smuzhiyun 				#field, value);				\
4170*4882a593Smuzhiyun 		sync();							\
4171*4882a593Smuzhiyun 		__delay(200);						\
4172*4882a593Smuzhiyun 	} else {							\
4173*4882a593Smuzhiyun 		catch_memory_errors = 0;				\
4174*4882a593Smuzhiyun 		printf("  %-*s = *** Error reading field.\n",		\
4175*4882a593Smuzhiyun 					DUMP_WIDTH, #field);		\
4176*4882a593Smuzhiyun 	}								\
4177*4882a593Smuzhiyun 	catch_memory_errors = 0;					\
4178*4882a593Smuzhiyun } while (0)
4179*4882a593Smuzhiyun 
4180*4882a593Smuzhiyun #define DUMP_FIELD(obj, format, field)	\
4181*4882a593Smuzhiyun 	DUMP_VALUE(format, field, obj->field)
4182*4882a593Smuzhiyun 
dump_spu_fields(struct spu * spu)4183*4882a593Smuzhiyun static void dump_spu_fields(struct spu *spu)
4184*4882a593Smuzhiyun {
4185*4882a593Smuzhiyun 	printf("Dumping spu fields at address %p:\n", spu);
4186*4882a593Smuzhiyun 
4187*4882a593Smuzhiyun 	DUMP_FIELD(spu, "0x%x", number);
4188*4882a593Smuzhiyun 	DUMP_FIELD(spu, "%s", name);
4189*4882a593Smuzhiyun 	DUMP_FIELD(spu, "0x%lx", local_store_phys);
4190*4882a593Smuzhiyun 	DUMP_FIELD(spu, "0x%p", local_store);
4191*4882a593Smuzhiyun 	DUMP_FIELD(spu, "0x%lx", ls_size);
4192*4882a593Smuzhiyun 	DUMP_FIELD(spu, "0x%x", node);
4193*4882a593Smuzhiyun 	DUMP_FIELD(spu, "0x%lx", flags);
4194*4882a593Smuzhiyun 	DUMP_FIELD(spu, "%llu", class_0_pending);
4195*4882a593Smuzhiyun 	DUMP_FIELD(spu, "0x%llx", class_0_dar);
4196*4882a593Smuzhiyun 	DUMP_FIELD(spu, "0x%llx", class_1_dar);
4197*4882a593Smuzhiyun 	DUMP_FIELD(spu, "0x%llx", class_1_dsisr);
4198*4882a593Smuzhiyun 	DUMP_FIELD(spu, "0x%x", irqs[0]);
4199*4882a593Smuzhiyun 	DUMP_FIELD(spu, "0x%x", irqs[1]);
4200*4882a593Smuzhiyun 	DUMP_FIELD(spu, "0x%x", irqs[2]);
4201*4882a593Smuzhiyun 	DUMP_FIELD(spu, "0x%x", slb_replace);
4202*4882a593Smuzhiyun 	DUMP_FIELD(spu, "%d", pid);
4203*4882a593Smuzhiyun 	DUMP_FIELD(spu, "0x%p", mm);
4204*4882a593Smuzhiyun 	DUMP_FIELD(spu, "0x%p", ctx);
4205*4882a593Smuzhiyun 	DUMP_FIELD(spu, "0x%p", rq);
4206*4882a593Smuzhiyun 	DUMP_FIELD(spu, "0x%llx", timestamp);
4207*4882a593Smuzhiyun 	DUMP_FIELD(spu, "0x%lx", problem_phys);
4208*4882a593Smuzhiyun 	DUMP_FIELD(spu, "0x%p", problem);
4209*4882a593Smuzhiyun 	DUMP_VALUE("0x%x", problem->spu_runcntl_RW,
4210*4882a593Smuzhiyun 			in_be32(&spu->problem->spu_runcntl_RW));
4211*4882a593Smuzhiyun 	DUMP_VALUE("0x%x", problem->spu_status_R,
4212*4882a593Smuzhiyun 			in_be32(&spu->problem->spu_status_R));
4213*4882a593Smuzhiyun 	DUMP_VALUE("0x%x", problem->spu_npc_RW,
4214*4882a593Smuzhiyun 			in_be32(&spu->problem->spu_npc_RW));
4215*4882a593Smuzhiyun 	DUMP_FIELD(spu, "0x%p", priv2);
4216*4882a593Smuzhiyun 	DUMP_FIELD(spu, "0x%p", pdata);
4217*4882a593Smuzhiyun }
4218*4882a593Smuzhiyun 
4219*4882a593Smuzhiyun int
spu_inst_dump(unsigned long adr,long count,int praddr)4220*4882a593Smuzhiyun spu_inst_dump(unsigned long adr, long count, int praddr)
4221*4882a593Smuzhiyun {
4222*4882a593Smuzhiyun 	return generic_inst_dump(adr, count, praddr, print_insn_spu);
4223*4882a593Smuzhiyun }
4224*4882a593Smuzhiyun 
dump_spu_ls(unsigned long num,int subcmd)4225*4882a593Smuzhiyun static void dump_spu_ls(unsigned long num, int subcmd)
4226*4882a593Smuzhiyun {
4227*4882a593Smuzhiyun 	unsigned long offset, addr, ls_addr;
4228*4882a593Smuzhiyun 
4229*4882a593Smuzhiyun 	if (setjmp(bus_error_jmp) == 0) {
4230*4882a593Smuzhiyun 		catch_memory_errors = 1;
4231*4882a593Smuzhiyun 		sync();
4232*4882a593Smuzhiyun 		ls_addr = (unsigned long)spu_info[num].spu->local_store;
4233*4882a593Smuzhiyun 		sync();
4234*4882a593Smuzhiyun 		__delay(200);
4235*4882a593Smuzhiyun 	} else {
4236*4882a593Smuzhiyun 		catch_memory_errors = 0;
4237*4882a593Smuzhiyun 		printf("*** Error: accessing spu info for spu %ld\n", num);
4238*4882a593Smuzhiyun 		return;
4239*4882a593Smuzhiyun 	}
4240*4882a593Smuzhiyun 	catch_memory_errors = 0;
4241*4882a593Smuzhiyun 
4242*4882a593Smuzhiyun 	if (scanhex(&offset))
4243*4882a593Smuzhiyun 		addr = ls_addr + offset;
4244*4882a593Smuzhiyun 	else
4245*4882a593Smuzhiyun 		addr = spu_info[num].dump_addr;
4246*4882a593Smuzhiyun 
4247*4882a593Smuzhiyun 	if (addr >= ls_addr + LS_SIZE) {
4248*4882a593Smuzhiyun 		printf("*** Error: address outside of local store\n");
4249*4882a593Smuzhiyun 		return;
4250*4882a593Smuzhiyun 	}
4251*4882a593Smuzhiyun 
4252*4882a593Smuzhiyun 	switch (subcmd) {
4253*4882a593Smuzhiyun 	case 'i':
4254*4882a593Smuzhiyun 		addr += spu_inst_dump(addr, 16, 1);
4255*4882a593Smuzhiyun 		last_cmd = "sdi\n";
4256*4882a593Smuzhiyun 		break;
4257*4882a593Smuzhiyun 	default:
4258*4882a593Smuzhiyun 		prdump(addr, 64);
4259*4882a593Smuzhiyun 		addr += 64;
4260*4882a593Smuzhiyun 		last_cmd = "sd\n";
4261*4882a593Smuzhiyun 		break;
4262*4882a593Smuzhiyun 	}
4263*4882a593Smuzhiyun 
4264*4882a593Smuzhiyun 	spu_info[num].dump_addr = addr;
4265*4882a593Smuzhiyun }
4266*4882a593Smuzhiyun 
do_spu_cmd(void)4267*4882a593Smuzhiyun static int do_spu_cmd(void)
4268*4882a593Smuzhiyun {
4269*4882a593Smuzhiyun 	static unsigned long num = 0;
4270*4882a593Smuzhiyun 	int cmd, subcmd = 0;
4271*4882a593Smuzhiyun 
4272*4882a593Smuzhiyun 	cmd = inchar();
4273*4882a593Smuzhiyun 	switch (cmd) {
4274*4882a593Smuzhiyun 	case 's':
4275*4882a593Smuzhiyun 		stop_spus();
4276*4882a593Smuzhiyun 		break;
4277*4882a593Smuzhiyun 	case 'r':
4278*4882a593Smuzhiyun 		restart_spus();
4279*4882a593Smuzhiyun 		break;
4280*4882a593Smuzhiyun 	case 'd':
4281*4882a593Smuzhiyun 		subcmd = inchar();
4282*4882a593Smuzhiyun 		if (isxdigit(subcmd) || subcmd == '\n')
4283*4882a593Smuzhiyun 			termch = subcmd;
4284*4882a593Smuzhiyun 		fallthrough;
4285*4882a593Smuzhiyun 	case 'f':
4286*4882a593Smuzhiyun 		scanhex(&num);
4287*4882a593Smuzhiyun 		if (num >= XMON_NUM_SPUS || !spu_info[num].spu) {
4288*4882a593Smuzhiyun 			printf("*** Error: invalid spu number\n");
4289*4882a593Smuzhiyun 			return 0;
4290*4882a593Smuzhiyun 		}
4291*4882a593Smuzhiyun 
4292*4882a593Smuzhiyun 		switch (cmd) {
4293*4882a593Smuzhiyun 		case 'f':
4294*4882a593Smuzhiyun 			dump_spu_fields(spu_info[num].spu);
4295*4882a593Smuzhiyun 			break;
4296*4882a593Smuzhiyun 		default:
4297*4882a593Smuzhiyun 			dump_spu_ls(num, subcmd);
4298*4882a593Smuzhiyun 			break;
4299*4882a593Smuzhiyun 		}
4300*4882a593Smuzhiyun 
4301*4882a593Smuzhiyun 		break;
4302*4882a593Smuzhiyun 	default:
4303*4882a593Smuzhiyun 		return -1;
4304*4882a593Smuzhiyun 	}
4305*4882a593Smuzhiyun 
4306*4882a593Smuzhiyun 	return 0;
4307*4882a593Smuzhiyun }
4308*4882a593Smuzhiyun #else /* ! CONFIG_SPU_BASE */
do_spu_cmd(void)4309*4882a593Smuzhiyun static int do_spu_cmd(void)
4310*4882a593Smuzhiyun {
4311*4882a593Smuzhiyun 	return -1;
4312*4882a593Smuzhiyun }
4313*4882a593Smuzhiyun #endif
4314