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(®s);
740*4882a593Smuzhiyun excp = ®s;
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, ®s, 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(®s)));
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 = ®s;
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(®no);
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(®no);
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