blob: a34172ddc4683064c818608b86fb506ba59e4c2f [file] [log] [blame]
Linus Torvalds1da177e2005-04-16 15:20:36 -07001/*
2 * Routines providing a simple monitor for use on the PowerMac.
3 *
Paul Mackerrasfca5dcd2005-11-08 22:55:08 +11004 * Copyright (C) 1996-2005 Paul Mackerras.
Michael Ellerman476792832006-10-03 14:12:08 +10005 * Copyright (C) 2001 PPC64 Team, IBM Corp
6 * Copyrignt (C) 2006 Michael Ellerman, IBM Corp
Linus Torvalds1da177e2005-04-16 15:20:36 -07007 *
8 * This program is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU General Public License
10 * as published by the Free Software Foundation; either version
11 * 2 of the License, or (at your option) any later version.
12 */
Linus Torvalds1da177e2005-04-16 15:20:36 -070013#include <linux/errno.h>
14#include <linux/sched.h>
15#include <linux/smp.h>
16#include <linux/mm.h>
17#include <linux/reboot.h>
18#include <linux/delay.h>
19#include <linux/kallsyms.h>
20#include <linux/cpumask.h>
Paul Mackerrasf78541d2005-10-28 22:53:37 +100021#include <linux/module.h>
Paul Mackerrasfca5dcd2005-11-08 22:55:08 +110022#include <linux/sysrq.h>
Andrew Morton4694ca02005-11-13 16:06:50 -080023#include <linux/interrupt.h>
David Howells7d12e782006-10-05 14:55:46 +010024#include <linux/irq.h>
Jeremy Fitzhardinge73c9cea2006-12-08 03:30:41 -080025#include <linux/bug.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070026
27#include <asm/ptrace.h>
28#include <asm/string.h>
29#include <asm/prom.h>
30#include <asm/machdep.h>
Paul Mackerrasf78541d2005-10-28 22:53:37 +100031#include <asm/xmon.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070032#include <asm/processor.h>
33#include <asm/pgtable.h>
34#include <asm/mmu.h>
35#include <asm/mmu_context.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070036#include <asm/cputable.h>
37#include <asm/rtas.h>
38#include <asm/sstep.h>
Paul Mackerrasf583ffc2006-10-10 11:47:07 +100039#include <asm/irq_regs.h>
Michael Ellermanff8a8f22006-10-24 18:31:27 +020040#include <asm/spu.h>
41#include <asm/spu_priv1.h>
Stephen Rothwell1d135812006-11-13 14:50:28 +110042#include <asm/firmware.h>
Michael Neulingc3b75bd2008-01-18 15:50:30 +110043#include <asm/setjmp.h>
Paul Mackerrasf78541d2005-10-28 22:53:37 +100044
45#ifdef CONFIG_PPC64
Linus Torvalds1da177e2005-04-16 15:20:36 -070046#include <asm/hvcall.h>
Paul Mackerrasf78541d2005-10-28 22:53:37 +100047#include <asm/paca.h>
Stephen Rothwellbbb68172006-11-30 11:44:09 +110048#include <asm/iseries/it_lp_reg_save.h>
Paul Mackerrasf78541d2005-10-28 22:53:37 +100049#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -070050
51#include "nonstdio.h"
Michael Ellermane0426042006-11-23 00:46:45 +010052#include "dis-asm.h"
Linus Torvalds1da177e2005-04-16 15:20:36 -070053
54#define scanhex xmon_scanhex
55#define skipbl xmon_skipbl
56
57#ifdef CONFIG_SMP
58cpumask_t cpus_in_xmon = CPU_MASK_NONE;
59static unsigned long xmon_taken = 1;
60static int xmon_owner;
61static int xmon_gate;
62#endif /* CONFIG_SMP */
63
64static unsigned long in_xmon = 0;
65
66static unsigned long adrs;
67static int size = 1;
68#define MAX_DUMP (128 * 1024)
69static unsigned long ndump = 64;
70static unsigned long nidump = 16;
71static unsigned long ncsum = 4096;
72static int termch;
73static char tmpstr[128];
74
Linus Torvalds1da177e2005-04-16 15:20:36 -070075static long bus_error_jmp[JMP_BUF_LEN];
76static int catch_memory_errors;
77static long *xmon_fault_jmp[NR_CPUS];
Linus Torvalds1da177e2005-04-16 15:20:36 -070078
79/* Breakpoint stuff */
80struct bpt {
81 unsigned long address;
82 unsigned int instr[2];
83 atomic_t ref_count;
84 int enabled;
85 unsigned long pad;
86};
87
88/* Bits in bpt.enabled */
89#define BP_IABR_TE 1 /* IABR translation enabled */
90#define BP_IABR 2
91#define BP_TRAP 8
92#define BP_DABR 0x10
93
94#define NBPTS 256
95static struct bpt bpts[NBPTS];
96static struct bpt dabr;
97static struct bpt *iabr;
98static unsigned bpinstr = 0x7fe00008; /* trap */
99
100#define BP_NUM(bp) ((bp) - bpts + 1)
101
102/* Prototypes */
103static int cmds(struct pt_regs *);
104static int mread(unsigned long, void *, int);
105static int mwrite(unsigned long, void *, int);
106static int handle_fault(struct pt_regs *);
107static void byterev(unsigned char *, int);
108static void memex(void);
109static int bsesc(void);
110static void dump(void);
111static void prdump(unsigned long, long);
112static int ppc_inst_dump(unsigned long, long, int);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700113static void backtrace(struct pt_regs *);
114static void excprint(struct pt_regs *);
115static void prregs(struct pt_regs *);
116static void memops(int);
117static void memlocate(void);
118static void memzcan(void);
119static void memdiffs(unsigned char *, unsigned char *, unsigned, unsigned);
120int skipbl(void);
121int scanhex(unsigned long *valp);
122static void scannl(void);
123static int hexdigit(int);
124void getstring(char *, int);
125static void flush_input(void);
126static int inchar(void);
127static void take_input(char *);
128static unsigned long read_spr(int);
129static void write_spr(int, unsigned long);
130static void super_regs(void);
131static void remove_bpts(void);
132static void insert_bpts(void);
133static void remove_cpu_bpts(void);
134static void insert_cpu_bpts(void);
135static struct bpt *at_breakpoint(unsigned long pc);
136static struct bpt *in_breakpoint_table(unsigned long pc, unsigned long *offp);
137static int do_step(struct pt_regs *);
138static void bpt_cmds(void);
139static void cacheflush(void);
140static int cpu_cmd(void);
141static void csum(void);
142static void bootcmds(void);
Paul Mackerrasf78541d2005-10-28 22:53:37 +1000143static void proccall(void);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700144void dump_segments(void);
145static void symbol_lookup(void);
Olaf Hering26c8af52006-09-08 16:29:21 +0200146static void xmon_show_stack(unsigned long sp, unsigned long lr,
147 unsigned long pc);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700148static void xmon_print_symbol(unsigned long address, const char *mid,
149 const char *after);
150static const char *getvecname(unsigned long vec);
151
Michael Ellermanff8a8f22006-10-24 18:31:27 +0200152static int do_spu_cmd(void);
153
Benjamin Herrenschmidt5a8a1a22007-11-16 18:23:33 +1100154#ifdef CONFIG_44x
155static void dump_tlb_44x(void);
156#endif
157
Olaf Hering26c8af52006-09-08 16:29:21 +0200158int xmon_no_auto_backtrace;
159
Paul Mackerrasf78541d2005-10-28 22:53:37 +1000160extern void xmon_enter(void);
161extern void xmon_leave(void);
162
Paul Mackerrasf78541d2005-10-28 22:53:37 +1000163extern void xmon_save_regs(struct pt_regs *);
164
165#ifdef CONFIG_PPC64
166#define REG "%.16lx"
167#define REGS_PER_LINE 4
168#define LAST_VOLATILE 13
169#else
170#define REG "%.8lx"
171#define REGS_PER_LINE 8
172#define LAST_VOLATILE 12
173#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -0700174
175#define GETWORD(v) (((v)[0] << 24) + ((v)[1] << 16) + ((v)[2] << 8) + (v)[3])
176
177#define isxdigit(c) (('0' <= (c) && (c) <= '9') \
178 || ('a' <= (c) && (c) <= 'f') \
179 || ('A' <= (c) && (c) <= 'F'))
180#define isalnum(c) (('0' <= (c) && (c) <= '9') \
181 || ('a' <= (c) && (c) <= 'z') \
182 || ('A' <= (c) && (c) <= 'Z'))
183#define isspace(c) (c == ' ' || c == '\t' || c == 10 || c == 13 || c == 0)
184
185static char *help_string = "\
186Commands:\n\
187 b show breakpoints\n\
188 bd set data breakpoint\n\
189 bi set instruction breakpoint\n\
190 bc clear breakpoint\n"
191#ifdef CONFIG_SMP
192 "\
193 c print cpus stopped in xmon\n\
194 c# try to switch to cpu number h (in hex)\n"
195#endif
196 "\
197 C checksum\n\
198 d dump bytes\n\
199 di dump instructions\n\
200 df dump float values\n\
201 dd dump double values\n\
Olaf Hering7e5b5932006-03-08 20:40:28 +0100202 dr dump stream of raw bytes\n\
Linus Torvalds1da177e2005-04-16 15:20:36 -0700203 e print exception information\n\
204 f flush cache\n\
205 la lookup symbol+offset of specified address\n\
206 ls lookup address of specified symbol\n\
207 m examine/change memory\n\
208 mm move a block of memory\n\
209 ms set a block of memory\n\
210 md compare two blocks of memory\n\
211 ml locate a block of memory\n\
212 mz zero a block of memory\n\
213 mi show information about memory allocation\n\
Paul Mackerrasf78541d2005-10-28 22:53:37 +1000214 p call a procedure\n\
Linus Torvalds1da177e2005-04-16 15:20:36 -0700215 r print registers\n\
Michael Ellermanff8a8f22006-10-24 18:31:27 +0200216 s single step\n"
Arnd Bergmanne0555952006-11-27 19:18:55 +0100217#ifdef CONFIG_SPU_BASE
Michael Ellermanff8a8f22006-10-24 18:31:27 +0200218" ss stop execution on all spus\n\
Michael Ellermana8984972006-10-24 18:31:28 +0200219 sr restore execution on stopped spus\n\
Michael Ellerman24a24c82006-11-23 00:46:41 +0100220 sf # dump spu fields for spu # (in hex)\n\
Michael Ellermanc99176a2007-02-26 18:14:06 +0900221 sd # dump spu local store for spu # (in hex)\n\
Michael Ellermanaf89fb82006-11-23 00:46:44 +0100222 sdi # disassemble spu local store for spu # (in hex)\n"
Michael Ellermanff8a8f22006-10-24 18:31:27 +0200223#endif
224" S print special registers\n\
Linus Torvalds1da177e2005-04-16 15:20:36 -0700225 t print backtrace\n\
Linus Torvalds1da177e2005-04-16 15:20:36 -0700226 x exit monitor and recover\n\
Paul Mackerrasf78541d2005-10-28 22:53:37 +1000227 X exit monitor and dont recover\n"
228#ifdef CONFIG_PPC64
229" u dump segment table or SLB\n"
230#endif
231#ifdef CONFIG_PPC_STD_MMU_32
232" u dump segment registers\n"
233#endif
Benjamin Herrenschmidt5a8a1a22007-11-16 18:23:33 +1100234#ifdef CONFIG_44x
235" u dump TLB\n"
236#endif
Paul Mackerrasf78541d2005-10-28 22:53:37 +1000237" ? help\n"
238" zr reboot\n\
Linus Torvalds1da177e2005-04-16 15:20:36 -0700239 zh halt\n"
240;
241
242static struct pt_regs *xmon_regs;
243
Paul Mackerrasf78541d2005-10-28 22:53:37 +1000244static inline void sync(void)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700245{
246 asm volatile("sync; isync");
247}
248
Paul Mackerrasf78541d2005-10-28 22:53:37 +1000249static inline void store_inst(void *p)
250{
251 asm volatile ("dcbst 0,%0; sync; icbi 0,%0; isync" : : "r" (p));
252}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700253
Paul Mackerrasf78541d2005-10-28 22:53:37 +1000254static inline void cflush(void *p)
255{
256 asm volatile ("dcbf 0,%0; icbi 0,%0" : : "r" (p));
257}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700258
Paul Mackerrasf78541d2005-10-28 22:53:37 +1000259static inline void cinval(void *p)
260{
261 asm volatile ("dcbi 0,%0; icbi 0,%0" : : "r" (p));
262}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700263
264/*
265 * Disable surveillance (the service processor watchdog function)
266 * while we are in xmon.
267 * XXX we should re-enable it when we leave. :)
268 */
269#define SURVEILLANCE_TOKEN 9000
270
271static inline void disable_surveillance(void)
272{
273#ifdef CONFIG_PPC_PSERIES
274 /* Since this can't be a module, args should end up below 4GB. */
275 static struct rtas_args args;
276
277 /*
278 * At this point we have got all the cpus we can into
279 * xmon, so there is hopefully no other cpu calling RTAS
280 * at the moment, even though we don't take rtas.lock.
281 * If we did try to take rtas.lock there would be a
282 * real possibility of deadlock.
283 */
284 args.token = rtas_token("set-indicator");
285 if (args.token == RTAS_UNKNOWN_SERVICE)
286 return;
287 args.nargs = 3;
288 args.nret = 1;
289 args.rets = &args.args[3];
290 args.args[0] = SURVEILLANCE_TOKEN;
291 args.args[1] = 0;
292 args.args[2] = 0;
293 enter_rtas(__pa(&args));
294#endif /* CONFIG_PPC_PSERIES */
295}
296
297#ifdef CONFIG_SMP
298static int xmon_speaker;
299
300static void get_output_lock(void)
301{
302 int me = smp_processor_id() + 0x100;
303 int last_speaker = 0, prev;
304 long timeout;
305
306 if (xmon_speaker == me)
307 return;
308 for (;;) {
309 if (xmon_speaker == 0) {
310 last_speaker = cmpxchg(&xmon_speaker, 0, me);
311 if (last_speaker == 0)
312 return;
313 }
314 timeout = 10000000;
315 while (xmon_speaker == last_speaker) {
316 if (--timeout > 0)
317 continue;
318 /* hostile takeover */
319 prev = cmpxchg(&xmon_speaker, last_speaker, me);
320 if (prev == last_speaker)
321 return;
322 break;
323 }
324 }
325}
326
327static void release_output_lock(void)
328{
329 xmon_speaker = 0;
330}
331#endif
332
Arnd Bergmannb0da9852006-01-11 00:00:05 +0000333static int xmon_core(struct pt_regs *regs, int fromipi)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700334{
335 int cmd = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700336 struct bpt *bp;
337 long recurse_jmp[JMP_BUF_LEN];
338 unsigned long offset;
Anton Blanchardf13659e2007-03-21 01:48:34 +1100339 unsigned long flags;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700340#ifdef CONFIG_SMP
341 int cpu;
342 int secondary;
343 unsigned long timeout;
344#endif
345
Anton Blanchardf13659e2007-03-21 01:48:34 +1100346 local_irq_save(flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700347
348 bp = in_breakpoint_table(regs->nip, &offset);
349 if (bp != NULL) {
350 regs->nip = bp->address + offset;
351 atomic_dec(&bp->ref_count);
352 }
353
354 remove_cpu_bpts();
355
356#ifdef CONFIG_SMP
357 cpu = smp_processor_id();
358 if (cpu_isset(cpu, cpus_in_xmon)) {
359 get_output_lock();
360 excprint(regs);
361 printf("cpu 0x%x: Exception %lx %s in xmon, "
362 "returning to main loop\n",
363 cpu, regs->trap, getvecname(TRAP(regs)));
Haren Myneni5cb4cc02005-08-03 15:08:18 +1000364 release_output_lock();
Linus Torvalds1da177e2005-04-16 15:20:36 -0700365 longjmp(xmon_fault_jmp[cpu], 1);
366 }
367
368 if (setjmp(recurse_jmp) != 0) {
369 if (!in_xmon || !xmon_gate) {
Haren Myneni5cb4cc02005-08-03 15:08:18 +1000370 get_output_lock();
Linus Torvalds1da177e2005-04-16 15:20:36 -0700371 printf("xmon: WARNING: bad recursive fault "
372 "on cpu 0x%x\n", cpu);
Haren Myneni5cb4cc02005-08-03 15:08:18 +1000373 release_output_lock();
Linus Torvalds1da177e2005-04-16 15:20:36 -0700374 goto waiting;
375 }
376 secondary = !(xmon_taken && cpu == xmon_owner);
377 goto cmdloop;
378 }
379
380 xmon_fault_jmp[cpu] = recurse_jmp;
381 cpu_set(cpu, cpus_in_xmon);
382
383 bp = NULL;
384 if ((regs->msr & (MSR_IR|MSR_PR|MSR_SF)) == (MSR_IR|MSR_SF))
385 bp = at_breakpoint(regs->nip);
386 if (bp || (regs->msr & MSR_RI) == 0)
387 fromipi = 0;
388
389 if (!fromipi) {
390 get_output_lock();
391 excprint(regs);
392 if (bp) {
393 printf("cpu 0x%x stopped at breakpoint 0x%x (",
394 cpu, BP_NUM(bp));
395 xmon_print_symbol(regs->nip, " ", ")\n");
396 }
397 if ((regs->msr & MSR_RI) == 0)
398 printf("WARNING: exception is not recoverable, "
399 "can't continue\n");
400 release_output_lock();
401 }
402
403 waiting:
404 secondary = 1;
405 while (secondary && !xmon_gate) {
406 if (in_xmon == 0) {
407 if (fromipi)
408 goto leave;
409 secondary = test_and_set_bit(0, &in_xmon);
410 }
411 barrier();
412 }
413
414 if (!secondary && !xmon_gate) {
415 /* we are the first cpu to come in */
416 /* interrupt other cpu(s) */
417 int ncpus = num_online_cpus();
418
419 xmon_owner = cpu;
420 mb();
421 if (ncpus > 1) {
422 smp_send_debugger_break(MSG_ALL_BUT_SELF);
423 /* wait for other cpus to come in */
424 for (timeout = 100000000; timeout != 0; --timeout) {
425 if (cpus_weight(cpus_in_xmon) >= ncpus)
426 break;
427 barrier();
428 }
429 }
430 remove_bpts();
431 disable_surveillance();
432 /* for breakpoint or single step, print the current instr. */
433 if (bp || TRAP(regs) == 0xd00)
434 ppc_inst_dump(regs->nip, 1, 0);
435 printf("enter ? for help\n");
436 mb();
437 xmon_gate = 1;
438 barrier();
439 }
440
441 cmdloop:
442 while (in_xmon) {
443 if (secondary) {
444 if (cpu == xmon_owner) {
445 if (!test_and_set_bit(0, &xmon_taken)) {
446 secondary = 0;
447 continue;
448 }
449 /* missed it */
450 while (cpu == xmon_owner)
451 barrier();
452 }
453 barrier();
454 } else {
455 cmd = cmds(regs);
456 if (cmd != 0) {
457 /* exiting xmon */
458 insert_bpts();
459 xmon_gate = 0;
460 wmb();
461 in_xmon = 0;
462 break;
463 }
464 /* have switched to some other cpu */
465 secondary = 1;
466 }
467 }
468 leave:
469 cpu_clear(cpu, cpus_in_xmon);
470 xmon_fault_jmp[cpu] = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700471#else
472 /* UP is simple... */
473 if (in_xmon) {
474 printf("Exception %lx %s in xmon, returning to main loop\n",
475 regs->trap, getvecname(TRAP(regs)));
476 longjmp(xmon_fault_jmp[0], 1);
477 }
478 if (setjmp(recurse_jmp) == 0) {
479 xmon_fault_jmp[0] = recurse_jmp;
480 in_xmon = 1;
481
482 excprint(regs);
483 bp = at_breakpoint(regs->nip);
484 if (bp) {
485 printf("Stopped at breakpoint %x (", BP_NUM(bp));
486 xmon_print_symbol(regs->nip, " ", ")\n");
487 }
488 if ((regs->msr & MSR_RI) == 0)
489 printf("WARNING: exception is not recoverable, "
490 "can't continue\n");
491 remove_bpts();
492 disable_surveillance();
493 /* for breakpoint or single step, print the current instr. */
494 if (bp || TRAP(regs) == 0xd00)
495 ppc_inst_dump(regs->nip, 1, 0);
496 printf("enter ? for help\n");
497 }
498
499 cmd = cmds(regs);
500
501 insert_bpts();
502 in_xmon = 0;
503#endif
504
505 if ((regs->msr & (MSR_IR|MSR_PR|MSR_SF)) == (MSR_IR|MSR_SF)) {
506 bp = at_breakpoint(regs->nip);
507 if (bp != NULL) {
508 int stepped = emulate_step(regs, bp->instr[0]);
509 if (stepped == 0) {
510 regs->nip = (unsigned long) &bp->instr[0];
511 atomic_inc(&bp->ref_count);
512 } else if (stepped < 0) {
513 printf("Couldn't single-step %s instruction\n",
514 (IS_RFID(bp->instr[0])? "rfid": "mtmsrd"));
515 }
516 }
517 }
518
519 insert_cpu_bpts();
520
Anton Blanchardf13659e2007-03-21 01:48:34 +1100521 local_irq_restore(flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700522
Paul Mackerras0a730ae2006-10-03 21:32:49 +1000523 return cmd != 'X' && cmd != EOF;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700524}
525
526int xmon(struct pt_regs *excp)
527{
528 struct pt_regs regs;
529
530 if (excp == NULL) {
Paul Mackerrasf78541d2005-10-28 22:53:37 +1000531 xmon_save_regs(&regs);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700532 excp = &regs;
533 }
Michael Ellermanff8a8f22006-10-24 18:31:27 +0200534
Linus Torvalds1da177e2005-04-16 15:20:36 -0700535 return xmon_core(excp, 0);
536}
Paul Mackerrasf78541d2005-10-28 22:53:37 +1000537EXPORT_SYMBOL(xmon);
538
Paul Mackerrasf583ffc2006-10-10 11:47:07 +1000539irqreturn_t xmon_irq(int irq, void *d)
Paul Mackerrasf78541d2005-10-28 22:53:37 +1000540{
541 unsigned long flags;
542 local_irq_save(flags);
543 printf("Keyboard interrupt\n");
Paul Mackerrasf583ffc2006-10-10 11:47:07 +1000544 xmon(get_irq_regs());
Paul Mackerrasf78541d2005-10-28 22:53:37 +1000545 local_irq_restore(flags);
546 return IRQ_HANDLED;
547}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700548
Arnd Bergmannb0da9852006-01-11 00:00:05 +0000549static int xmon_bpt(struct pt_regs *regs)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700550{
551 struct bpt *bp;
552 unsigned long offset;
553
554 if ((regs->msr & (MSR_IR|MSR_PR|MSR_SF)) != (MSR_IR|MSR_SF))
555 return 0;
556
557 /* Are we at the trap at bp->instr[1] for some bp? */
558 bp = in_breakpoint_table(regs->nip, &offset);
559 if (bp != NULL && offset == 4) {
560 regs->nip = bp->address + 4;
561 atomic_dec(&bp->ref_count);
562 return 1;
563 }
564
565 /* Are we at a breakpoint? */
566 bp = at_breakpoint(regs->nip);
567 if (!bp)
568 return 0;
569
570 xmon_core(regs, 0);
571
572 return 1;
573}
574
Arnd Bergmannb0da9852006-01-11 00:00:05 +0000575static int xmon_sstep(struct pt_regs *regs)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700576{
577 if (user_mode(regs))
578 return 0;
579 xmon_core(regs, 0);
580 return 1;
581}
582
Arnd Bergmannb0da9852006-01-11 00:00:05 +0000583static int xmon_dabr_match(struct pt_regs *regs)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700584{
585 if ((regs->msr & (MSR_IR|MSR_PR|MSR_SF)) != (MSR_IR|MSR_SF))
586 return 0;
Anton Blanchardfd9648d2005-09-10 16:01:11 +1000587 if (dabr.enabled == 0)
588 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700589 xmon_core(regs, 0);
590 return 1;
591}
592
Arnd Bergmannb0da9852006-01-11 00:00:05 +0000593static int xmon_iabr_match(struct pt_regs *regs)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700594{
595 if ((regs->msr & (MSR_IR|MSR_PR|MSR_SF)) != (MSR_IR|MSR_SF))
596 return 0;
597 if (iabr == 0)
598 return 0;
599 xmon_core(regs, 0);
600 return 1;
601}
602
Arnd Bergmannb0da9852006-01-11 00:00:05 +0000603static int xmon_ipi(struct pt_regs *regs)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700604{
605#ifdef CONFIG_SMP
606 if (in_xmon && !cpu_isset(smp_processor_id(), cpus_in_xmon))
607 xmon_core(regs, 1);
608#endif
609 return 0;
610}
611
Arnd Bergmannb0da9852006-01-11 00:00:05 +0000612static int xmon_fault_handler(struct pt_regs *regs)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700613{
614 struct bpt *bp;
615 unsigned long offset;
616
617 if (in_xmon && catch_memory_errors)
618 handle_fault(regs); /* doesn't return */
619
620 if ((regs->msr & (MSR_IR|MSR_PR|MSR_SF)) == (MSR_IR|MSR_SF)) {
621 bp = in_breakpoint_table(regs->nip, &offset);
622 if (bp != NULL) {
623 regs->nip = bp->address + offset;
624 atomic_dec(&bp->ref_count);
625 }
626 }
627
628 return 0;
629}
630
Linus Torvalds1da177e2005-04-16 15:20:36 -0700631static struct bpt *at_breakpoint(unsigned long pc)
632{
633 int i;
634 struct bpt *bp;
635
636 bp = bpts;
637 for (i = 0; i < NBPTS; ++i, ++bp)
638 if (bp->enabled && pc == bp->address)
639 return bp;
640 return NULL;
641}
642
643static struct bpt *in_breakpoint_table(unsigned long nip, unsigned long *offp)
644{
645 unsigned long off;
646
647 off = nip - (unsigned long) bpts;
648 if (off >= sizeof(bpts))
649 return NULL;
650 off %= sizeof(struct bpt);
651 if (off != offsetof(struct bpt, instr[0])
652 && off != offsetof(struct bpt, instr[1]))
653 return NULL;
654 *offp = off - offsetof(struct bpt, instr[0]);
655 return (struct bpt *) (nip - off);
656}
657
658static struct bpt *new_breakpoint(unsigned long a)
659{
660 struct bpt *bp;
661
662 a &= ~3UL;
663 bp = at_breakpoint(a);
664 if (bp)
665 return bp;
666
667 for (bp = bpts; bp < &bpts[NBPTS]; ++bp) {
668 if (!bp->enabled && atomic_read(&bp->ref_count) == 0) {
669 bp->address = a;
670 bp->instr[1] = bpinstr;
671 store_inst(&bp->instr[1]);
672 return bp;
673 }
674 }
675
676 printf("Sorry, no free breakpoints. Please clear one first.\n");
677 return NULL;
678}
679
680static void insert_bpts(void)
681{
682 int i;
683 struct bpt *bp;
684
685 bp = bpts;
686 for (i = 0; i < NBPTS; ++i, ++bp) {
687 if ((bp->enabled & (BP_TRAP|BP_IABR)) == 0)
688 continue;
689 if (mread(bp->address, &bp->instr[0], 4) != 4) {
690 printf("Couldn't read instruction at %lx, "
691 "disabling breakpoint there\n", bp->address);
692 bp->enabled = 0;
693 continue;
694 }
695 if (IS_MTMSRD(bp->instr[0]) || IS_RFID(bp->instr[0])) {
696 printf("Breakpoint at %lx is on an mtmsrd or rfid "
697 "instruction, disabling it\n", bp->address);
698 bp->enabled = 0;
699 continue;
700 }
701 store_inst(&bp->instr[0]);
702 if (bp->enabled & BP_IABR)
703 continue;
704 if (mwrite(bp->address, &bpinstr, 4) != 4) {
705 printf("Couldn't write instruction at %lx, "
706 "disabling breakpoint there\n", bp->address);
707 bp->enabled &= ~BP_TRAP;
708 continue;
709 }
710 store_inst((void *)bp->address);
711 }
712}
713
714static void insert_cpu_bpts(void)
715{
716 if (dabr.enabled)
Anton Blanchardfd9648d2005-09-10 16:01:11 +1000717 set_dabr(dabr.address | (dabr.enabled & 7));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700718 if (iabr && cpu_has_feature(CPU_FTR_IABR))
Paul Mackerrasf78541d2005-10-28 22:53:37 +1000719 mtspr(SPRN_IABR, iabr->address
Linus Torvalds1da177e2005-04-16 15:20:36 -0700720 | (iabr->enabled & (BP_IABR|BP_IABR_TE)));
721}
722
723static void remove_bpts(void)
724{
725 int i;
726 struct bpt *bp;
727 unsigned instr;
728
729 bp = bpts;
730 for (i = 0; i < NBPTS; ++i, ++bp) {
731 if ((bp->enabled & (BP_TRAP|BP_IABR)) != BP_TRAP)
732 continue;
733 if (mread(bp->address, &instr, 4) == 4
734 && instr == bpinstr
735 && mwrite(bp->address, &bp->instr, 4) != 4)
736 printf("Couldn't remove breakpoint at %lx\n",
737 bp->address);
738 else
739 store_inst((void *)bp->address);
740 }
741}
742
743static void remove_cpu_bpts(void)
744{
Anton Blanchardfd9648d2005-09-10 16:01:11 +1000745 set_dabr(0);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700746 if (cpu_has_feature(CPU_FTR_IABR))
Paul Mackerrasf78541d2005-10-28 22:53:37 +1000747 mtspr(SPRN_IABR, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700748}
749
750/* Command interpreting routine */
751static char *last_cmd;
752
753static int
754cmds(struct pt_regs *excp)
755{
756 int cmd = 0;
757
758 last_cmd = NULL;
759 xmon_regs = excp;
Olaf Hering26c8af52006-09-08 16:29:21 +0200760
761 if (!xmon_no_auto_backtrace) {
762 xmon_no_auto_backtrace = 1;
763 xmon_show_stack(excp->gpr[1], excp->link, excp->nip);
764 }
765
Linus Torvalds1da177e2005-04-16 15:20:36 -0700766 for(;;) {
767#ifdef CONFIG_SMP
768 printf("%x:", smp_processor_id());
769#endif /* CONFIG_SMP */
770 printf("mon> ");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700771 flush_input();
772 termch = 0;
773 cmd = skipbl();
774 if( cmd == '\n' ) {
775 if (last_cmd == NULL)
776 continue;
777 take_input(last_cmd);
778 last_cmd = NULL;
779 cmd = inchar();
780 }
781 switch (cmd) {
782 case 'm':
783 cmd = inchar();
784 switch (cmd) {
785 case 'm':
786 case 's':
787 case 'd':
788 memops(cmd);
789 break;
790 case 'l':
791 memlocate();
792 break;
793 case 'z':
794 memzcan();
795 break;
796 case 'i':
797 show_mem();
798 break;
799 default:
800 termch = cmd;
801 memex();
802 }
803 break;
804 case 'd':
805 dump();
806 break;
807 case 'l':
808 symbol_lookup();
809 break;
810 case 'r':
811 prregs(excp); /* print regs */
812 break;
813 case 'e':
814 excprint(excp);
815 break;
816 case 'S':
817 super_regs();
818 break;
819 case 't':
820 backtrace(excp);
821 break;
822 case 'f':
823 cacheflush();
824 break;
825 case 's':
Michael Ellermanff8a8f22006-10-24 18:31:27 +0200826 if (do_spu_cmd() == 0)
827 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700828 if (do_step(excp))
829 return cmd;
830 break;
831 case 'x':
832 case 'X':
Benjamin Herrenschmidtbb6b9b22005-11-30 16:54:12 +1100833 return cmd;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700834 case EOF:
Benjamin Herrenschmidtbb6b9b22005-11-30 16:54:12 +1100835 printf(" <no input ...>\n");
836 mdelay(2000);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700837 return cmd;
838 case '?':
Ishizaki Kou4d404ed2007-07-18 19:26:40 +1000839 xmon_puts(help_string);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700840 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700841 case 'b':
842 bpt_cmds();
843 break;
844 case 'C':
845 csum();
846 break;
847 case 'c':
848 if (cpu_cmd())
849 return 0;
850 break;
851 case 'z':
852 bootcmds();
853 break;
Paul Mackerrasf78541d2005-10-28 22:53:37 +1000854 case 'p':
855 proccall();
Linus Torvalds1da177e2005-04-16 15:20:36 -0700856 break;
Paul Mackerrasf78541d2005-10-28 22:53:37 +1000857#ifdef CONFIG_PPC_STD_MMU
Linus Torvalds1da177e2005-04-16 15:20:36 -0700858 case 'u':
859 dump_segments();
860 break;
Paul Mackerrasf78541d2005-10-28 22:53:37 +1000861#endif
Benjamin Herrenschmidt5a8a1a22007-11-16 18:23:33 +1100862#ifdef CONFIG_4xx
863 case 'u':
864 dump_tlb_44x();
865 break;
866#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -0700867 default:
868 printf("Unrecognized command: ");
869 do {
870 if (' ' < cmd && cmd <= '~')
871 putchar(cmd);
872 else
873 printf("\\x%x", cmd);
874 cmd = inchar();
875 } while (cmd != '\n');
876 printf(" (type ? for help)\n");
877 break;
878 }
879 }
880}
881
882/*
883 * Step a single instruction.
884 * Some instructions we emulate, others we execute with MSR_SE set.
885 */
886static int do_step(struct pt_regs *regs)
887{
888 unsigned int instr;
889 int stepped;
890
891 /* check we are in 64-bit kernel mode, translation enabled */
892 if ((regs->msr & (MSR_SF|MSR_PR|MSR_IR)) == (MSR_SF|MSR_IR)) {
893 if (mread(regs->nip, &instr, 4) == 4) {
894 stepped = emulate_step(regs, instr);
895 if (stepped < 0) {
896 printf("Couldn't single-step %s instruction\n",
897 (IS_RFID(instr)? "rfid": "mtmsrd"));
898 return 0;
899 }
900 if (stepped > 0) {
901 regs->trap = 0xd00 | (regs->trap & 1);
902 printf("stepped to ");
903 xmon_print_symbol(regs->nip, " ", "\n");
904 ppc_inst_dump(regs->nip, 1, 0);
905 return 0;
906 }
907 }
908 }
909 regs->msr |= MSR_SE;
910 return 1;
911}
912
913static void bootcmds(void)
914{
915 int cmd;
916
917 cmd = inchar();
918 if (cmd == 'r')
919 ppc_md.restart(NULL);
920 else if (cmd == 'h')
921 ppc_md.halt();
922 else if (cmd == 'p')
923 ppc_md.power_off();
924}
925
926static int cpu_cmd(void)
927{
928#ifdef CONFIG_SMP
929 unsigned long cpu;
930 int timeout;
931 int count;
932
933 if (!scanhex(&cpu)) {
934 /* print cpus waiting or in xmon */
935 printf("cpus stopped:");
936 count = 0;
937 for (cpu = 0; cpu < NR_CPUS; ++cpu) {
938 if (cpu_isset(cpu, cpus_in_xmon)) {
939 if (count == 0)
940 printf(" %x", cpu);
941 ++count;
942 } else {
943 if (count > 1)
944 printf("-%x", cpu - 1);
945 count = 0;
946 }
947 }
948 if (count > 1)
949 printf("-%x", NR_CPUS - 1);
950 printf("\n");
951 return 0;
952 }
953 /* try to switch to cpu specified */
954 if (!cpu_isset(cpu, cpus_in_xmon)) {
955 printf("cpu 0x%x isn't in xmon\n", cpu);
956 return 0;
957 }
958 xmon_taken = 0;
959 mb();
960 xmon_owner = cpu;
961 timeout = 10000000;
962 while (!xmon_taken) {
963 if (--timeout == 0) {
964 if (test_and_set_bit(0, &xmon_taken))
965 break;
966 /* take control back */
967 mb();
968 xmon_owner = smp_processor_id();
969 printf("cpu %u didn't take control\n", cpu);
970 return 0;
971 }
972 barrier();
973 }
974 return 1;
975#else
976 return 0;
977#endif /* CONFIG_SMP */
978}
979
980static unsigned short fcstab[256] = {
981 0x0000, 0x1189, 0x2312, 0x329b, 0x4624, 0x57ad, 0x6536, 0x74bf,
982 0x8c48, 0x9dc1, 0xaf5a, 0xbed3, 0xca6c, 0xdbe5, 0xe97e, 0xf8f7,
983 0x1081, 0x0108, 0x3393, 0x221a, 0x56a5, 0x472c, 0x75b7, 0x643e,
984 0x9cc9, 0x8d40, 0xbfdb, 0xae52, 0xdaed, 0xcb64, 0xf9ff, 0xe876,
985 0x2102, 0x308b, 0x0210, 0x1399, 0x6726, 0x76af, 0x4434, 0x55bd,
986 0xad4a, 0xbcc3, 0x8e58, 0x9fd1, 0xeb6e, 0xfae7, 0xc87c, 0xd9f5,
987 0x3183, 0x200a, 0x1291, 0x0318, 0x77a7, 0x662e, 0x54b5, 0x453c,
988 0xbdcb, 0xac42, 0x9ed9, 0x8f50, 0xfbef, 0xea66, 0xd8fd, 0xc974,
989 0x4204, 0x538d, 0x6116, 0x709f, 0x0420, 0x15a9, 0x2732, 0x36bb,
990 0xce4c, 0xdfc5, 0xed5e, 0xfcd7, 0x8868, 0x99e1, 0xab7a, 0xbaf3,
991 0x5285, 0x430c, 0x7197, 0x601e, 0x14a1, 0x0528, 0x37b3, 0x263a,
992 0xdecd, 0xcf44, 0xfddf, 0xec56, 0x98e9, 0x8960, 0xbbfb, 0xaa72,
993 0x6306, 0x728f, 0x4014, 0x519d, 0x2522, 0x34ab, 0x0630, 0x17b9,
994 0xef4e, 0xfec7, 0xcc5c, 0xddd5, 0xa96a, 0xb8e3, 0x8a78, 0x9bf1,
995 0x7387, 0x620e, 0x5095, 0x411c, 0x35a3, 0x242a, 0x16b1, 0x0738,
996 0xffcf, 0xee46, 0xdcdd, 0xcd54, 0xb9eb, 0xa862, 0x9af9, 0x8b70,
997 0x8408, 0x9581, 0xa71a, 0xb693, 0xc22c, 0xd3a5, 0xe13e, 0xf0b7,
998 0x0840, 0x19c9, 0x2b52, 0x3adb, 0x4e64, 0x5fed, 0x6d76, 0x7cff,
999 0x9489, 0x8500, 0xb79b, 0xa612, 0xd2ad, 0xc324, 0xf1bf, 0xe036,
1000 0x18c1, 0x0948, 0x3bd3, 0x2a5a, 0x5ee5, 0x4f6c, 0x7df7, 0x6c7e,
1001 0xa50a, 0xb483, 0x8618, 0x9791, 0xe32e, 0xf2a7, 0xc03c, 0xd1b5,
1002 0x2942, 0x38cb, 0x0a50, 0x1bd9, 0x6f66, 0x7eef, 0x4c74, 0x5dfd,
1003 0xb58b, 0xa402, 0x9699, 0x8710, 0xf3af, 0xe226, 0xd0bd, 0xc134,
1004 0x39c3, 0x284a, 0x1ad1, 0x0b58, 0x7fe7, 0x6e6e, 0x5cf5, 0x4d7c,
1005 0xc60c, 0xd785, 0xe51e, 0xf497, 0x8028, 0x91a1, 0xa33a, 0xb2b3,
1006 0x4a44, 0x5bcd, 0x6956, 0x78df, 0x0c60, 0x1de9, 0x2f72, 0x3efb,
1007 0xd68d, 0xc704, 0xf59f, 0xe416, 0x90a9, 0x8120, 0xb3bb, 0xa232,
1008 0x5ac5, 0x4b4c, 0x79d7, 0x685e, 0x1ce1, 0x0d68, 0x3ff3, 0x2e7a,
1009 0xe70e, 0xf687, 0xc41c, 0xd595, 0xa12a, 0xb0a3, 0x8238, 0x93b1,
1010 0x6b46, 0x7acf, 0x4854, 0x59dd, 0x2d62, 0x3ceb, 0x0e70, 0x1ff9,
1011 0xf78f, 0xe606, 0xd49d, 0xc514, 0xb1ab, 0xa022, 0x92b9, 0x8330,
1012 0x7bc7, 0x6a4e, 0x58d5, 0x495c, 0x3de3, 0x2c6a, 0x1ef1, 0x0f78
1013};
1014
1015#define FCS(fcs, c) (((fcs) >> 8) ^ fcstab[((fcs) ^ (c)) & 0xff])
1016
1017static void
1018csum(void)
1019{
1020 unsigned int i;
1021 unsigned short fcs;
1022 unsigned char v;
1023
1024 if (!scanhex(&adrs))
1025 return;
1026 if (!scanhex(&ncsum))
1027 return;
1028 fcs = 0xffff;
1029 for (i = 0; i < ncsum; ++i) {
1030 if (mread(adrs+i, &v, 1) == 0) {
1031 printf("csum stopped at %x\n", adrs+i);
1032 break;
1033 }
1034 fcs = FCS(fcs, v);
1035 }
1036 printf("%x\n", fcs);
1037}
1038
1039/*
1040 * Check if this is a suitable place to put a breakpoint.
1041 */
1042static long check_bp_loc(unsigned long addr)
1043{
1044 unsigned int instr;
1045
1046 addr &= ~3;
Michael Ellerman51fae6de2005-12-04 18:39:15 +11001047 if (!is_kernel_addr(addr)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001048 printf("Breakpoints may only be placed at kernel addresses\n");
1049 return 0;
1050 }
1051 if (!mread(addr, &instr, sizeof(instr))) {
1052 printf("Can't read instruction at address %lx\n", addr);
1053 return 0;
1054 }
1055 if (IS_MTMSRD(instr) || IS_RFID(instr)) {
1056 printf("Breakpoints may not be placed on mtmsrd or rfid "
1057 "instructions\n");
1058 return 0;
1059 }
1060 return 1;
1061}
1062
1063static char *breakpoint_help_string =
1064 "Breakpoint command usage:\n"
1065 "b show breakpoints\n"
1066 "b <addr> [cnt] set breakpoint at given instr addr\n"
1067 "bc clear all breakpoints\n"
1068 "bc <n/addr> clear breakpoint number n or at addr\n"
1069 "bi <addr> [cnt] set hardware instr breakpoint (POWER3/RS64 only)\n"
1070 "bd <addr> [cnt] set hardware data breakpoint\n"
1071 "";
1072
1073static void
1074bpt_cmds(void)
1075{
1076 int cmd;
1077 unsigned long a;
1078 int mode, i;
1079 struct bpt *bp;
1080 const char badaddr[] = "Only kernel addresses are permitted "
1081 "for breakpoints\n";
1082
1083 cmd = inchar();
1084 switch (cmd) {
Paul Mackerrasf78541d2005-10-28 22:53:37 +10001085#ifndef CONFIG_8xx
Linus Torvalds1da177e2005-04-16 15:20:36 -07001086 case 'd': /* bd - hardware data breakpoint */
1087 mode = 7;
1088 cmd = inchar();
1089 if (cmd == 'r')
1090 mode = 5;
1091 else if (cmd == 'w')
1092 mode = 6;
1093 else
1094 termch = cmd;
1095 dabr.address = 0;
1096 dabr.enabled = 0;
1097 if (scanhex(&dabr.address)) {
Michael Ellerman51fae6de2005-12-04 18:39:15 +11001098 if (!is_kernel_addr(dabr.address)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001099 printf(badaddr);
1100 break;
1101 }
1102 dabr.address &= ~7;
1103 dabr.enabled = mode | BP_DABR;
1104 }
1105 break;
1106
1107 case 'i': /* bi - hardware instr breakpoint */
1108 if (!cpu_has_feature(CPU_FTR_IABR)) {
1109 printf("Hardware instruction breakpoint "
1110 "not supported on this cpu\n");
1111 break;
1112 }
1113 if (iabr) {
1114 iabr->enabled &= ~(BP_IABR | BP_IABR_TE);
1115 iabr = NULL;
1116 }
1117 if (!scanhex(&a))
1118 break;
1119 if (!check_bp_loc(a))
1120 break;
1121 bp = new_breakpoint(a);
1122 if (bp != NULL) {
1123 bp->enabled |= BP_IABR | BP_IABR_TE;
1124 iabr = bp;
1125 }
1126 break;
Paul Mackerrasf78541d2005-10-28 22:53:37 +10001127#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -07001128
1129 case 'c':
1130 if (!scanhex(&a)) {
1131 /* clear all breakpoints */
1132 for (i = 0; i < NBPTS; ++i)
1133 bpts[i].enabled = 0;
1134 iabr = NULL;
1135 dabr.enabled = 0;
1136 printf("All breakpoints cleared\n");
1137 break;
1138 }
1139
1140 if (a <= NBPTS && a >= 1) {
1141 /* assume a breakpoint number */
1142 bp = &bpts[a-1]; /* bp nums are 1 based */
1143 } else {
1144 /* assume a breakpoint address */
1145 bp = at_breakpoint(a);
1146 if (bp == 0) {
1147 printf("No breakpoint at %x\n", a);
1148 break;
1149 }
1150 }
1151
1152 printf("Cleared breakpoint %x (", BP_NUM(bp));
1153 xmon_print_symbol(bp->address, " ", ")\n");
1154 bp->enabled = 0;
1155 break;
1156
1157 default:
1158 termch = cmd;
1159 cmd = skipbl();
1160 if (cmd == '?') {
1161 printf(breakpoint_help_string);
1162 break;
1163 }
1164 termch = cmd;
1165 if (!scanhex(&a)) {
1166 /* print all breakpoints */
1167 printf(" type address\n");
1168 if (dabr.enabled) {
Paul Mackerrasf78541d2005-10-28 22:53:37 +10001169 printf(" data "REG" [", dabr.address);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001170 if (dabr.enabled & 1)
1171 printf("r");
1172 if (dabr.enabled & 2)
1173 printf("w");
1174 printf("]\n");
1175 }
1176 for (bp = bpts; bp < &bpts[NBPTS]; ++bp) {
1177 if (!bp->enabled)
1178 continue;
1179 printf("%2x %s ", BP_NUM(bp),
1180 (bp->enabled & BP_IABR)? "inst": "trap");
1181 xmon_print_symbol(bp->address, " ", "\n");
1182 }
1183 break;
1184 }
1185
1186 if (!check_bp_loc(a))
1187 break;
1188 bp = new_breakpoint(a);
1189 if (bp != NULL)
1190 bp->enabled |= BP_TRAP;
1191 break;
1192 }
1193}
1194
1195/* Very cheap human name for vector lookup. */
1196static
1197const char *getvecname(unsigned long vec)
1198{
1199 char *ret;
1200
1201 switch (vec) {
1202 case 0x100: ret = "(System Reset)"; break;
1203 case 0x200: ret = "(Machine Check)"; break;
1204 case 0x300: ret = "(Data Access)"; break;
1205 case 0x380: ret = "(Data SLB Access)"; break;
1206 case 0x400: ret = "(Instruction Access)"; break;
1207 case 0x480: ret = "(Instruction SLB Access)"; break;
1208 case 0x500: ret = "(Hardware Interrupt)"; break;
1209 case 0x600: ret = "(Alignment)"; break;
1210 case 0x700: ret = "(Program Check)"; break;
1211 case 0x800: ret = "(FPU Unavailable)"; break;
1212 case 0x900: ret = "(Decrementer)"; break;
1213 case 0xc00: ret = "(System Call)"; break;
1214 case 0xd00: ret = "(Single Step)"; break;
1215 case 0xf00: ret = "(Performance Monitor)"; break;
1216 case 0xf20: ret = "(Altivec Unavailable)"; break;
1217 case 0x1300: ret = "(Instruction Breakpoint)"; break;
1218 default: ret = "";
1219 }
1220 return ret;
1221}
1222
1223static void get_function_bounds(unsigned long pc, unsigned long *startp,
1224 unsigned long *endp)
1225{
1226 unsigned long size, offset;
1227 const char *name;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001228
1229 *startp = *endp = 0;
1230 if (pc == 0)
1231 return;
1232 if (setjmp(bus_error_jmp) == 0) {
1233 catch_memory_errors = 1;
1234 sync();
Alexey Dobriyanffb45122007-05-08 00:28:41 -07001235 name = kallsyms_lookup(pc, &size, &offset, NULL, tmpstr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001236 if (name != NULL) {
1237 *startp = pc - offset;
1238 *endp = pc - offset + size;
1239 }
1240 sync();
1241 }
1242 catch_memory_errors = 0;
1243}
1244
1245static int xmon_depth_to_print = 64;
1246
Paul Mackerrasf78541d2005-10-28 22:53:37 +10001247#ifdef CONFIG_PPC64
1248#define LRSAVE_OFFSET 0x10
1249#define REG_FRAME_MARKER 0x7265677368657265ul /* "regshere" */
1250#define MARKER_OFFSET 0x60
1251#define REGS_OFFSET 0x70
1252#else
1253#define LRSAVE_OFFSET 4
1254#define REG_FRAME_MARKER 0x72656773
1255#define MARKER_OFFSET 8
1256#define REGS_OFFSET 16
1257#endif
1258
Linus Torvalds1da177e2005-04-16 15:20:36 -07001259static void xmon_show_stack(unsigned long sp, unsigned long lr,
1260 unsigned long pc)
1261{
1262 unsigned long ip;
1263 unsigned long newsp;
1264 unsigned long marker;
1265 int count = 0;
1266 struct pt_regs regs;
1267
1268 do {
1269 if (sp < PAGE_OFFSET) {
1270 if (sp != 0)
1271 printf("SP (%lx) is in userspace\n", sp);
1272 break;
1273 }
1274
Paul Mackerrasf78541d2005-10-28 22:53:37 +10001275 if (!mread(sp + LRSAVE_OFFSET, &ip, sizeof(unsigned long))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001276 || !mread(sp, &newsp, sizeof(unsigned long))) {
1277 printf("Couldn't read stack frame at %lx\n", sp);
1278 break;
1279 }
1280
1281 /*
1282 * For the first stack frame, try to work out if
1283 * LR and/or the saved LR value in the bottommost
1284 * stack frame are valid.
1285 */
1286 if ((pc | lr) != 0) {
1287 unsigned long fnstart, fnend;
1288 unsigned long nextip;
1289 int printip = 1;
1290
1291 get_function_bounds(pc, &fnstart, &fnend);
1292 nextip = 0;
1293 if (newsp > sp)
Paul Mackerrasf78541d2005-10-28 22:53:37 +10001294 mread(newsp + LRSAVE_OFFSET, &nextip,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001295 sizeof(unsigned long));
1296 if (lr == ip) {
1297 if (lr < PAGE_OFFSET
1298 || (fnstart <= lr && lr < fnend))
1299 printip = 0;
1300 } else if (lr == nextip) {
1301 printip = 0;
1302 } else if (lr >= PAGE_OFFSET
1303 && !(fnstart <= lr && lr < fnend)) {
1304 printf("[link register ] ");
1305 xmon_print_symbol(lr, " ", "\n");
1306 }
1307 if (printip) {
Paul Mackerrasf78541d2005-10-28 22:53:37 +10001308 printf("["REG"] ", sp);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001309 xmon_print_symbol(ip, " ", " (unreliable)\n");
1310 }
1311 pc = lr = 0;
1312
1313 } else {
Paul Mackerrasf78541d2005-10-28 22:53:37 +10001314 printf("["REG"] ", sp);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001315 xmon_print_symbol(ip, " ", "\n");
1316 }
1317
1318 /* Look for "regshere" marker to see if this is
1319 an exception frame. */
Paul Mackerrasf78541d2005-10-28 22:53:37 +10001320 if (mread(sp + MARKER_OFFSET, &marker, sizeof(unsigned long))
1321 && marker == REG_FRAME_MARKER) {
1322 if (mread(sp + REGS_OFFSET, &regs, sizeof(regs))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001323 != sizeof(regs)) {
1324 printf("Couldn't read registers at %lx\n",
Paul Mackerrasf78541d2005-10-28 22:53:37 +10001325 sp + REGS_OFFSET);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001326 break;
1327 }
1328 printf("--- Exception: %lx %s at ", regs.trap,
1329 getvecname(TRAP(&regs)));
1330 pc = regs.nip;
1331 lr = regs.link;
1332 xmon_print_symbol(pc, " ", "\n");
1333 }
1334
1335 if (newsp == 0)
1336 break;
1337
1338 sp = newsp;
1339 } while (count++ < xmon_depth_to_print);
1340}
1341
1342static void backtrace(struct pt_regs *excp)
1343{
1344 unsigned long sp;
1345
1346 if (scanhex(&sp))
1347 xmon_show_stack(sp, 0, 0);
1348 else
1349 xmon_show_stack(excp->gpr[1], excp->link, excp->nip);
1350 scannl();
1351}
1352
1353static void print_bug_trap(struct pt_regs *regs)
1354{
Jeremy Fitzhardinge73c9cea2006-12-08 03:30:41 -08001355 const struct bug_entry *bug;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001356 unsigned long addr;
1357
1358 if (regs->msr & MSR_PR)
1359 return; /* not in kernel */
1360 addr = regs->nip; /* address of trap instruction */
1361 if (addr < PAGE_OFFSET)
1362 return;
1363 bug = find_bug(regs->nip);
1364 if (bug == NULL)
1365 return;
Jeremy Fitzhardinge73c9cea2006-12-08 03:30:41 -08001366 if (is_warning_bug(bug))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001367 return;
1368
Stephen Rothwell0a7c7ef2007-03-04 17:05:34 +11001369#ifdef CONFIG_DEBUG_BUGVERBOSE
Jeremy Fitzhardinge73c9cea2006-12-08 03:30:41 -08001370 printf("kernel BUG at %s:%u!\n",
1371 bug->file, bug->line);
Stephen Rothwell0a7c7ef2007-03-04 17:05:34 +11001372#else
1373 printf("kernel BUG at %p!\n", (void *)bug->bug_addr);
1374#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -07001375}
1376
1377void excprint(struct pt_regs *fp)
1378{
1379 unsigned long trap;
1380
1381#ifdef CONFIG_SMP
1382 printf("cpu 0x%x: ", smp_processor_id());
1383#endif /* CONFIG_SMP */
1384
1385 trap = TRAP(fp);
1386 printf("Vector: %lx %s at [%lx]\n", fp->trap, getvecname(trap), fp);
1387 printf(" pc: ");
1388 xmon_print_symbol(fp->nip, ": ", "\n");
1389
1390 printf(" lr: ", fp->link);
1391 xmon_print_symbol(fp->link, ": ", "\n");
1392
1393 printf(" sp: %lx\n", fp->gpr[1]);
1394 printf(" msr: %lx\n", fp->msr);
1395
1396 if (trap == 0x300 || trap == 0x380 || trap == 0x600) {
1397 printf(" dar: %lx\n", fp->dar);
1398 if (trap != 0x380)
1399 printf(" dsisr: %lx\n", fp->dsisr);
1400 }
1401
1402 printf(" current = 0x%lx\n", current);
Paul Mackerrasf78541d2005-10-28 22:53:37 +10001403#ifdef CONFIG_PPC64
Linus Torvalds1da177e2005-04-16 15:20:36 -07001404 printf(" paca = 0x%lx\n", get_paca());
Paul Mackerrasf78541d2005-10-28 22:53:37 +10001405#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -07001406 if (current) {
1407 printf(" pid = %ld, comm = %s\n",
1408 current->pid, current->comm);
1409 }
1410
1411 if (trap == 0x700)
1412 print_bug_trap(fp);
1413}
1414
1415void prregs(struct pt_regs *fp)
1416{
Paul Mackerrasf78541d2005-10-28 22:53:37 +10001417 int n, trap;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001418 unsigned long base;
1419 struct pt_regs regs;
1420
1421 if (scanhex(&base)) {
1422 if (setjmp(bus_error_jmp) == 0) {
1423 catch_memory_errors = 1;
1424 sync();
1425 regs = *(struct pt_regs *)base;
1426 sync();
1427 __delay(200);
1428 } else {
1429 catch_memory_errors = 0;
Paul Mackerrasf78541d2005-10-28 22:53:37 +10001430 printf("*** Error reading registers from "REG"\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07001431 base);
1432 return;
1433 }
1434 catch_memory_errors = 0;
1435 fp = &regs;
1436 }
1437
Paul Mackerrasf78541d2005-10-28 22:53:37 +10001438#ifdef CONFIG_PPC64
Linus Torvalds1da177e2005-04-16 15:20:36 -07001439 if (FULL_REGS(fp)) {
1440 for (n = 0; n < 16; ++n)
Paul Mackerrasf78541d2005-10-28 22:53:37 +10001441 printf("R%.2ld = "REG" R%.2ld = "REG"\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07001442 n, fp->gpr[n], n+16, fp->gpr[n+16]);
1443 } else {
1444 for (n = 0; n < 7; ++n)
Paul Mackerrasf78541d2005-10-28 22:53:37 +10001445 printf("R%.2ld = "REG" R%.2ld = "REG"\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07001446 n, fp->gpr[n], n+7, fp->gpr[n+7]);
1447 }
Paul Mackerrasf78541d2005-10-28 22:53:37 +10001448#else
1449 for (n = 0; n < 32; ++n) {
1450 printf("R%.2d = %.8x%s", n, fp->gpr[n],
1451 (n & 3) == 3? "\n": " ");
1452 if (n == 12 && !FULL_REGS(fp)) {
1453 printf("\n");
1454 break;
1455 }
1456 }
1457#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -07001458 printf("pc = ");
1459 xmon_print_symbol(fp->nip, " ", "\n");
1460 printf("lr = ");
1461 xmon_print_symbol(fp->link, " ", "\n");
Paul Mackerrasf78541d2005-10-28 22:53:37 +10001462 printf("msr = "REG" cr = %.8lx\n", fp->msr, fp->ccr);
1463 printf("ctr = "REG" xer = "REG" trap = %4lx\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07001464 fp->ctr, fp->xer, fp->trap);
Paul Mackerrasf78541d2005-10-28 22:53:37 +10001465 trap = TRAP(fp);
1466 if (trap == 0x300 || trap == 0x380 || trap == 0x600)
1467 printf("dar = "REG" dsisr = %.8lx\n", fp->dar, fp->dsisr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001468}
1469
1470void cacheflush(void)
1471{
1472 int cmd;
1473 unsigned long nflush;
1474
1475 cmd = inchar();
1476 if (cmd != 'i')
1477 termch = cmd;
1478 scanhex((void *)&adrs);
1479 if (termch != '\n')
1480 termch = 0;
1481 nflush = 1;
1482 scanhex(&nflush);
1483 nflush = (nflush + L1_CACHE_BYTES - 1) / L1_CACHE_BYTES;
1484 if (setjmp(bus_error_jmp) == 0) {
1485 catch_memory_errors = 1;
1486 sync();
1487
1488 if (cmd != 'i') {
1489 for (; nflush > 0; --nflush, adrs += L1_CACHE_BYTES)
1490 cflush((void *) adrs);
1491 } else {
1492 for (; nflush > 0; --nflush, adrs += L1_CACHE_BYTES)
1493 cinval((void *) adrs);
1494 }
1495 sync();
1496 /* wait a little while to see if we get a machine check */
1497 __delay(200);
1498 }
1499 catch_memory_errors = 0;
1500}
1501
1502unsigned long
1503read_spr(int n)
1504{
1505 unsigned int instrs[2];
1506 unsigned long (*code)(void);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001507 unsigned long ret = -1UL;
Paul Mackerras548cceb2005-11-11 22:36:34 +11001508#ifdef CONFIG_PPC64
1509 unsigned long opd[3];
Linus Torvalds1da177e2005-04-16 15:20:36 -07001510
Linus Torvalds1da177e2005-04-16 15:20:36 -07001511 opd[0] = (unsigned long)instrs;
1512 opd[1] = 0;
1513 opd[2] = 0;
Paul Mackerras548cceb2005-11-11 22:36:34 +11001514 code = (unsigned long (*)(void)) opd;
1515#else
1516 code = (unsigned long (*)(void)) instrs;
1517#endif
1518
1519 /* mfspr r3,n; blr */
1520 instrs[0] = 0x7c6002a6 + ((n & 0x1F) << 16) + ((n & 0x3e0) << 6);
1521 instrs[1] = 0x4e800020;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001522 store_inst(instrs);
1523 store_inst(instrs+1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001524
1525 if (setjmp(bus_error_jmp) == 0) {
1526 catch_memory_errors = 1;
1527 sync();
1528
1529 ret = code();
1530
1531 sync();
1532 /* wait a little while to see if we get a machine check */
1533 __delay(200);
1534 n = size;
1535 }
1536
1537 return ret;
1538}
1539
1540void
1541write_spr(int n, unsigned long val)
1542{
1543 unsigned int instrs[2];
1544 unsigned long (*code)(unsigned long);
Paul Mackerras548cceb2005-11-11 22:36:34 +11001545#ifdef CONFIG_PPC64
Linus Torvalds1da177e2005-04-16 15:20:36 -07001546 unsigned long opd[3];
1547
Linus Torvalds1da177e2005-04-16 15:20:36 -07001548 opd[0] = (unsigned long)instrs;
1549 opd[1] = 0;
1550 opd[2] = 0;
Paul Mackerras548cceb2005-11-11 22:36:34 +11001551 code = (unsigned long (*)(unsigned long)) opd;
1552#else
1553 code = (unsigned long (*)(unsigned long)) instrs;
1554#endif
1555
1556 instrs[0] = 0x7c6003a6 + ((n & 0x1F) << 16) + ((n & 0x3e0) << 6);
1557 instrs[1] = 0x4e800020;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001558 store_inst(instrs);
1559 store_inst(instrs+1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001560
1561 if (setjmp(bus_error_jmp) == 0) {
1562 catch_memory_errors = 1;
1563 sync();
1564
1565 code(val);
1566
1567 sync();
1568 /* wait a little while to see if we get a machine check */
1569 __delay(200);
1570 n = size;
1571 }
1572}
1573
1574static unsigned long regno;
1575extern char exc_prolog;
1576extern char dec_exc;
1577
Paul Mackerrasf78541d2005-10-28 22:53:37 +10001578void super_regs(void)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001579{
1580 int cmd;
1581 unsigned long val;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001582
1583 cmd = skipbl();
1584 if (cmd == '\n') {
1585 unsigned long sp, toc;
1586 asm("mr %0,1" : "=r" (sp) :);
1587 asm("mr %0,2" : "=r" (toc) :);
1588
Paul Mackerrasf78541d2005-10-28 22:53:37 +10001589 printf("msr = "REG" sprg0= "REG"\n",
1590 mfmsr(), mfspr(SPRN_SPRG0));
1591 printf("pvr = "REG" sprg1= "REG"\n",
1592 mfspr(SPRN_PVR), mfspr(SPRN_SPRG1));
1593 printf("dec = "REG" sprg2= "REG"\n",
1594 mfspr(SPRN_DEC), mfspr(SPRN_SPRG2));
1595 printf("sp = "REG" sprg3= "REG"\n", sp, mfspr(SPRN_SPRG3));
1596 printf("toc = "REG" dar = "REG"\n", toc, mfspr(SPRN_DAR));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001597#ifdef CONFIG_PPC_ISERIES
Stephen Rothwell1d135812006-11-13 14:50:28 +11001598 if (firmware_has_feature(FW_FEATURE_ISERIES)) {
1599 struct paca_struct *ptrPaca;
1600 struct lppaca *ptrLpPaca;
1601 struct ItLpRegSave *ptrLpRegSave;
1602
1603 /* Dump out relevant Paca data areas. */
1604 printf("Paca: \n");
1605 ptrPaca = get_paca();
1606
1607 printf(" Local Processor Control Area (LpPaca): \n");
1608 ptrLpPaca = ptrPaca->lppaca_ptr;
1609 printf(" Saved Srr0=%.16lx Saved Srr1=%.16lx \n",
1610 ptrLpPaca->saved_srr0, ptrLpPaca->saved_srr1);
1611 printf(" Saved Gpr3=%.16lx Saved Gpr4=%.16lx \n",
1612 ptrLpPaca->saved_gpr3, ptrLpPaca->saved_gpr4);
1613 printf(" Saved Gpr5=%.16lx \n", ptrLpPaca->saved_gpr5);
1614
1615 printf(" Local Processor Register Save Area (LpRegSave): \n");
1616 ptrLpRegSave = ptrPaca->reg_save_ptr;
1617 printf(" Saved Sprg0=%.16lx Saved Sprg1=%.16lx \n",
1618 ptrLpRegSave->xSPRG0, ptrLpRegSave->xSPRG0);
1619 printf(" Saved Sprg2=%.16lx Saved Sprg3=%.16lx \n",
1620 ptrLpRegSave->xSPRG2, ptrLpRegSave->xSPRG3);
1621 printf(" Saved Msr =%.16lx Saved Nia =%.16lx \n",
1622 ptrLpRegSave->xMSR, ptrLpRegSave->xNIA);
1623 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001624#endif
1625
1626 return;
1627 }
1628
1629 scanhex(&regno);
1630 switch (cmd) {
1631 case 'w':
1632 val = read_spr(regno);
1633 scanhex(&val);
1634 write_spr(regno, val);
1635 /* fall through */
1636 case 'r':
1637 printf("spr %lx = %lx\n", regno, read_spr(regno));
1638 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001639 }
1640 scannl();
1641}
1642
1643/*
1644 * Stuff for reading and writing memory safely
1645 */
1646int
1647mread(unsigned long adrs, void *buf, int size)
1648{
1649 volatile int n;
1650 char *p, *q;
1651
1652 n = 0;
1653 if (setjmp(bus_error_jmp) == 0) {
1654 catch_memory_errors = 1;
1655 sync();
1656 p = (char *)adrs;
1657 q = (char *)buf;
1658 switch (size) {
1659 case 2:
Paul Mackerrasf78541d2005-10-28 22:53:37 +10001660 *(u16 *)q = *(u16 *)p;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001661 break;
1662 case 4:
Paul Mackerrasf78541d2005-10-28 22:53:37 +10001663 *(u32 *)q = *(u32 *)p;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001664 break;
1665 case 8:
Paul Mackerrasf78541d2005-10-28 22:53:37 +10001666 *(u64 *)q = *(u64 *)p;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001667 break;
1668 default:
1669 for( ; n < size; ++n) {
1670 *q++ = *p++;
1671 sync();
1672 }
1673 }
1674 sync();
1675 /* wait a little while to see if we get a machine check */
1676 __delay(200);
1677 n = size;
1678 }
1679 catch_memory_errors = 0;
1680 return n;
1681}
1682
1683int
1684mwrite(unsigned long adrs, void *buf, int size)
1685{
1686 volatile int n;
1687 char *p, *q;
1688
1689 n = 0;
1690 if (setjmp(bus_error_jmp) == 0) {
1691 catch_memory_errors = 1;
1692 sync();
1693 p = (char *) adrs;
1694 q = (char *) buf;
1695 switch (size) {
1696 case 2:
Paul Mackerrasf78541d2005-10-28 22:53:37 +10001697 *(u16 *)p = *(u16 *)q;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001698 break;
1699 case 4:
Paul Mackerrasf78541d2005-10-28 22:53:37 +10001700 *(u32 *)p = *(u32 *)q;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001701 break;
1702 case 8:
Paul Mackerrasf78541d2005-10-28 22:53:37 +10001703 *(u64 *)p = *(u64 *)q;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001704 break;
1705 default:
1706 for ( ; n < size; ++n) {
1707 *p++ = *q++;
1708 sync();
1709 }
1710 }
1711 sync();
1712 /* wait a little while to see if we get a machine check */
1713 __delay(200);
1714 n = size;
1715 } else {
1716 printf("*** Error writing address %x\n", adrs + n);
1717 }
1718 catch_memory_errors = 0;
1719 return n;
1720}
1721
1722static int fault_type;
Paul Mackerrasf78541d2005-10-28 22:53:37 +10001723static int fault_except;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001724static char *fault_chars[] = { "--", "**", "##" };
1725
Paul Mackerrasf78541d2005-10-28 22:53:37 +10001726static int handle_fault(struct pt_regs *regs)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001727{
Paul Mackerrasf78541d2005-10-28 22:53:37 +10001728 fault_except = TRAP(regs);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001729 switch (TRAP(regs)) {
1730 case 0x200:
1731 fault_type = 0;
1732 break;
1733 case 0x300:
1734 case 0x380:
1735 fault_type = 1;
1736 break;
1737 default:
1738 fault_type = 2;
1739 }
1740
1741 longjmp(bus_error_jmp, 1);
1742
1743 return 0;
1744}
1745
1746#define SWAP(a, b, t) ((t) = (a), (a) = (b), (b) = (t))
1747
1748void
1749byterev(unsigned char *val, int size)
1750{
1751 int t;
1752
1753 switch (size) {
1754 case 2:
1755 SWAP(val[0], val[1], t);
1756 break;
1757 case 4:
1758 SWAP(val[0], val[3], t);
1759 SWAP(val[1], val[2], t);
1760 break;
1761 case 8: /* is there really any use for this? */
1762 SWAP(val[0], val[7], t);
1763 SWAP(val[1], val[6], t);
1764 SWAP(val[2], val[5], t);
1765 SWAP(val[3], val[4], t);
1766 break;
1767 }
1768}
1769
1770static int brev;
1771static int mnoread;
1772
1773static char *memex_help_string =
1774 "Memory examine command usage:\n"
1775 "m [addr] [flags] examine/change memory\n"
1776 " addr is optional. will start where left off.\n"
1777 " flags may include chars from this set:\n"
1778 " b modify by bytes (default)\n"
1779 " w modify by words (2 byte)\n"
1780 " l modify by longs (4 byte)\n"
1781 " d modify by doubleword (8 byte)\n"
1782 " r toggle reverse byte order mode\n"
1783 " n do not read memory (for i/o spaces)\n"
1784 " . ok to read (default)\n"
1785 "NOTE: flags are saved as defaults\n"
1786 "";
1787
1788static char *memex_subcmd_help_string =
1789 "Memory examine subcommands:\n"
1790 " hexval write this val to current location\n"
1791 " 'string' write chars from string to this location\n"
1792 " ' increment address\n"
1793 " ^ decrement address\n"
1794 " / increment addr by 0x10. //=0x100, ///=0x1000, etc\n"
1795 " \\ decrement addr by 0x10. \\\\=0x100, \\\\\\=0x1000, etc\n"
1796 " ` clear no-read flag\n"
1797 " ; stay at this addr\n"
1798 " v change to byte mode\n"
1799 " w change to word (2 byte) mode\n"
1800 " l change to long (4 byte) mode\n"
1801 " u change to doubleword (8 byte) mode\n"
1802 " m addr change current addr\n"
1803 " n toggle no-read flag\n"
1804 " r toggle byte reverse flag\n"
1805 " < count back up count bytes\n"
1806 " > count skip forward count bytes\n"
1807 " x exit this mode\n"
1808 "";
1809
1810void
1811memex(void)
1812{
1813 int cmd, inc, i, nslash;
1814 unsigned long n;
1815 unsigned char val[16];
1816
1817 scanhex((void *)&adrs);
1818 cmd = skipbl();
1819 if (cmd == '?') {
1820 printf(memex_help_string);
1821 return;
1822 } else {
1823 termch = cmd;
1824 }
1825 last_cmd = "m\n";
1826 while ((cmd = skipbl()) != '\n') {
1827 switch( cmd ){
1828 case 'b': size = 1; break;
1829 case 'w': size = 2; break;
1830 case 'l': size = 4; break;
1831 case 'd': size = 8; break;
1832 case 'r': brev = !brev; break;
1833 case 'n': mnoread = 1; break;
1834 case '.': mnoread = 0; break;
1835 }
1836 }
1837 if( size <= 0 )
1838 size = 1;
1839 else if( size > 8 )
1840 size = 8;
1841 for(;;){
1842 if (!mnoread)
1843 n = mread(adrs, val, size);
Paul Mackerrase1449ed2005-11-10 14:30:20 +11001844 printf(REG"%c", adrs, brev? 'r': ' ');
Linus Torvalds1da177e2005-04-16 15:20:36 -07001845 if (!mnoread) {
1846 if (brev)
1847 byterev(val, size);
1848 putchar(' ');
1849 for (i = 0; i < n; ++i)
1850 printf("%.2x", val[i]);
1851 for (; i < size; ++i)
1852 printf("%s", fault_chars[fault_type]);
1853 }
1854 putchar(' ');
1855 inc = size;
1856 nslash = 0;
1857 for(;;){
1858 if( scanhex(&n) ){
1859 for (i = 0; i < size; ++i)
1860 val[i] = n >> (i * 8);
1861 if (!brev)
1862 byterev(val, size);
1863 mwrite(adrs, val, size);
1864 inc = size;
1865 }
1866 cmd = skipbl();
1867 if (cmd == '\n')
1868 break;
1869 inc = 0;
1870 switch (cmd) {
1871 case '\'':
1872 for(;;){
1873 n = inchar();
1874 if( n == '\\' )
1875 n = bsesc();
1876 else if( n == '\'' )
1877 break;
1878 for (i = 0; i < size; ++i)
1879 val[i] = n >> (i * 8);
1880 if (!brev)
1881 byterev(val, size);
1882 mwrite(adrs, val, size);
1883 adrs += size;
1884 }
1885 adrs -= size;
1886 inc = size;
1887 break;
1888 case ',':
1889 adrs += size;
1890 break;
1891 case '.':
1892 mnoread = 0;
1893 break;
1894 case ';':
1895 break;
1896 case 'x':
1897 case EOF:
1898 scannl();
1899 return;
1900 case 'b':
1901 case 'v':
1902 size = 1;
1903 break;
1904 case 'w':
1905 size = 2;
1906 break;
1907 case 'l':
1908 size = 4;
1909 break;
1910 case 'u':
1911 size = 8;
1912 break;
1913 case '^':
1914 adrs -= size;
1915 break;
1916 break;
1917 case '/':
1918 if (nslash > 0)
1919 adrs -= 1 << nslash;
1920 else
1921 nslash = 0;
1922 nslash += 4;
1923 adrs += 1 << nslash;
1924 break;
1925 case '\\':
1926 if (nslash < 0)
1927 adrs += 1 << -nslash;
1928 else
1929 nslash = 0;
1930 nslash -= 4;
1931 adrs -= 1 << -nslash;
1932 break;
1933 case 'm':
1934 scanhex((void *)&adrs);
1935 break;
1936 case 'n':
1937 mnoread = 1;
1938 break;
1939 case 'r':
1940 brev = !brev;
1941 break;
1942 case '<':
1943 n = size;
1944 scanhex(&n);
1945 adrs -= n;
1946 break;
1947 case '>':
1948 n = size;
1949 scanhex(&n);
1950 adrs += n;
1951 break;
1952 case '?':
1953 printf(memex_subcmd_help_string);
1954 break;
1955 }
1956 }
1957 adrs += inc;
1958 }
1959}
1960
1961int
1962bsesc(void)
1963{
1964 int c;
1965
1966 c = inchar();
1967 switch( c ){
1968 case 'n': c = '\n'; break;
1969 case 'r': c = '\r'; break;
1970 case 'b': c = '\b'; break;
1971 case 't': c = '\t'; break;
1972 }
1973 return c;
1974}
1975
Olaf Hering7e5b5932006-03-08 20:40:28 +01001976static void xmon_rawdump (unsigned long adrs, long ndump)
1977{
1978 long n, m, r, nr;
1979 unsigned char temp[16];
1980
1981 for (n = ndump; n > 0;) {
1982 r = n < 16? n: 16;
1983 nr = mread(adrs, temp, r);
1984 adrs += nr;
1985 for (m = 0; m < r; ++m) {
1986 if (m < nr)
1987 printf("%.2x", temp[m]);
1988 else
1989 printf("%s", fault_chars[fault_type]);
1990 }
1991 n -= r;
1992 if (nr < r)
1993 break;
1994 }
1995 printf("\n");
1996}
1997
Linus Torvalds1da177e2005-04-16 15:20:36 -07001998#define isxdigit(c) (('0' <= (c) && (c) <= '9') \
1999 || ('a' <= (c) && (c) <= 'f') \
2000 || ('A' <= (c) && (c) <= 'F'))
2001void
2002dump(void)
2003{
2004 int c;
2005
2006 c = inchar();
2007 if ((isxdigit(c) && c != 'f' && c != 'd') || c == '\n')
2008 termch = c;
2009 scanhex((void *)&adrs);
2010 if (termch != '\n')
2011 termch = 0;
2012 if (c == 'i') {
2013 scanhex(&nidump);
2014 if (nidump == 0)
2015 nidump = 16;
2016 else if (nidump > MAX_DUMP)
2017 nidump = MAX_DUMP;
2018 adrs += ppc_inst_dump(adrs, nidump, 1);
2019 last_cmd = "di\n";
Olaf Hering7e5b5932006-03-08 20:40:28 +01002020 } else if (c == 'r') {
2021 scanhex(&ndump);
2022 if (ndump == 0)
2023 ndump = 64;
2024 xmon_rawdump(adrs, ndump);
2025 adrs += ndump;
2026 last_cmd = "dr\n";
Linus Torvalds1da177e2005-04-16 15:20:36 -07002027 } else {
2028 scanhex(&ndump);
2029 if (ndump == 0)
2030 ndump = 64;
2031 else if (ndump > MAX_DUMP)
2032 ndump = MAX_DUMP;
2033 prdump(adrs, ndump);
2034 adrs += ndump;
2035 last_cmd = "d\n";
2036 }
2037}
2038
2039void
2040prdump(unsigned long adrs, long ndump)
2041{
2042 long n, m, c, r, nr;
2043 unsigned char temp[16];
2044
2045 for (n = ndump; n > 0;) {
Paul Mackerrasf78541d2005-10-28 22:53:37 +10002046 printf(REG, adrs);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002047 putchar(' ');
2048 r = n < 16? n: 16;
2049 nr = mread(adrs, temp, r);
2050 adrs += nr;
2051 for (m = 0; m < r; ++m) {
Paul Mackerrase1449ed2005-11-10 14:30:20 +11002052 if ((m & (sizeof(long) - 1)) == 0 && m > 0)
2053 putchar(' ');
Linus Torvalds1da177e2005-04-16 15:20:36 -07002054 if (m < nr)
2055 printf("%.2x", temp[m]);
2056 else
2057 printf("%s", fault_chars[fault_type]);
2058 }
Paul Mackerrase1449ed2005-11-10 14:30:20 +11002059 for (; m < 16; ++m) {
2060 if ((m & (sizeof(long) - 1)) == 0)
2061 putchar(' ');
Linus Torvalds1da177e2005-04-16 15:20:36 -07002062 printf(" ");
Paul Mackerrase1449ed2005-11-10 14:30:20 +11002063 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002064 printf(" |");
2065 for (m = 0; m < r; ++m) {
2066 if (m < nr) {
2067 c = temp[m];
2068 putchar(' ' <= c && c <= '~'? c: '.');
2069 } else
2070 putchar(' ');
2071 }
2072 n -= r;
2073 for (; m < 16; ++m)
2074 putchar(' ');
2075 printf("|\n");
2076 if (nr < r)
2077 break;
2078 }
2079}
2080
Michael Ellerman4c4c8722006-11-23 00:46:42 +01002081typedef int (*instruction_dump_func)(unsigned long inst, unsigned long addr);
2082
Linus Torvalds1da177e2005-04-16 15:20:36 -07002083int
Michael Ellerman4c4c8722006-11-23 00:46:42 +01002084generic_inst_dump(unsigned long adr, long count, int praddr,
2085 instruction_dump_func dump_func)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002086{
2087 int nr, dotted;
2088 unsigned long first_adr;
2089 unsigned long inst, last_inst = 0;
2090 unsigned char val[4];
2091
2092 dotted = 0;
2093 for (first_adr = adr; count > 0; --count, adr += 4) {
2094 nr = mread(adr, val, 4);
2095 if (nr == 0) {
2096 if (praddr) {
2097 const char *x = fault_chars[fault_type];
Paul Mackerrasf78541d2005-10-28 22:53:37 +10002098 printf(REG" %s%s%s%s\n", adr, x, x, x, x);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002099 }
2100 break;
2101 }
2102 inst = GETWORD(val);
2103 if (adr > first_adr && inst == last_inst) {
2104 if (!dotted) {
2105 printf(" ...\n");
2106 dotted = 1;
2107 }
2108 continue;
2109 }
2110 dotted = 0;
2111 last_inst = inst;
2112 if (praddr)
Paul Mackerrasf78541d2005-10-28 22:53:37 +10002113 printf(REG" %.8x", adr, inst);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002114 printf("\t");
Michael Ellerman4c4c8722006-11-23 00:46:42 +01002115 dump_func(inst, adr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002116 printf("\n");
2117 }
2118 return adr - first_adr;
2119}
2120
Michael Ellerman4c4c8722006-11-23 00:46:42 +01002121int
2122ppc_inst_dump(unsigned long adr, long count, int praddr)
2123{
2124 return generic_inst_dump(adr, count, praddr, print_insn_powerpc);
2125}
2126
Linus Torvalds1da177e2005-04-16 15:20:36 -07002127void
2128print_address(unsigned long addr)
2129{
2130 xmon_print_symbol(addr, "\t# ", "");
2131}
2132
2133
2134/*
2135 * Memory operations - move, set, print differences
2136 */
2137static unsigned long mdest; /* destination address */
2138static unsigned long msrc; /* source address */
2139static unsigned long mval; /* byte value to set memory to */
2140static unsigned long mcount; /* # bytes to affect */
2141static unsigned long mdiffs; /* max # differences to print */
2142
2143void
2144memops(int cmd)
2145{
2146 scanhex((void *)&mdest);
2147 if( termch != '\n' )
2148 termch = 0;
2149 scanhex((void *)(cmd == 's'? &mval: &msrc));
2150 if( termch != '\n' )
2151 termch = 0;
2152 scanhex((void *)&mcount);
2153 switch( cmd ){
2154 case 'm':
2155 memmove((void *)mdest, (void *)msrc, mcount);
2156 break;
2157 case 's':
2158 memset((void *)mdest, mval, mcount);
2159 break;
2160 case 'd':
2161 if( termch != '\n' )
2162 termch = 0;
2163 scanhex((void *)&mdiffs);
2164 memdiffs((unsigned char *)mdest, (unsigned char *)msrc, mcount, mdiffs);
2165 break;
2166 }
2167}
2168
2169void
2170memdiffs(unsigned char *p1, unsigned char *p2, unsigned nb, unsigned maxpr)
2171{
2172 unsigned n, prt;
2173
2174 prt = 0;
2175 for( n = nb; n > 0; --n )
2176 if( *p1++ != *p2++ )
2177 if( ++prt <= maxpr )
2178 printf("%.16x %.2x # %.16x %.2x\n", p1 - 1,
2179 p1[-1], p2 - 1, p2[-1]);
2180 if( prt > maxpr )
2181 printf("Total of %d differences\n", prt);
2182}
2183
2184static unsigned mend;
2185static unsigned mask;
2186
2187void
2188memlocate(void)
2189{
2190 unsigned a, n;
2191 unsigned char val[4];
2192
2193 last_cmd = "ml";
2194 scanhex((void *)&mdest);
2195 if (termch != '\n') {
2196 termch = 0;
2197 scanhex((void *)&mend);
2198 if (termch != '\n') {
2199 termch = 0;
2200 scanhex((void *)&mval);
2201 mask = ~0;
2202 if (termch != '\n') termch = 0;
2203 scanhex((void *)&mask);
2204 }
2205 }
2206 n = 0;
2207 for (a = mdest; a < mend; a += 4) {
2208 if (mread(a, val, 4) == 4
2209 && ((GETWORD(val) ^ mval) & mask) == 0) {
2210 printf("%.16x: %.16x\n", a, GETWORD(val));
2211 if (++n >= 10)
2212 break;
2213 }
2214 }
2215}
2216
2217static unsigned long mskip = 0x1000;
2218static unsigned long mlim = 0xffffffff;
2219
2220void
2221memzcan(void)
2222{
2223 unsigned char v;
2224 unsigned a;
2225 int ok, ook;
2226
2227 scanhex(&mdest);
2228 if (termch != '\n') termch = 0;
2229 scanhex(&mskip);
2230 if (termch != '\n') termch = 0;
2231 scanhex(&mlim);
2232 ook = 0;
2233 for (a = mdest; a < mlim; a += mskip) {
2234 ok = mread(a, &v, 1);
2235 if (ok && !ook) {
2236 printf("%.8x .. ", a);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002237 } else if (!ok && ook)
2238 printf("%.8x\n", a - mskip);
2239 ook = ok;
2240 if (a + mskip < a)
2241 break;
2242 }
2243 if (ook)
2244 printf("%.8x\n", a - mskip);
2245}
2246
Paul Mackerrasf78541d2005-10-28 22:53:37 +10002247void proccall(void)
2248{
2249 unsigned long args[8];
2250 unsigned long ret;
2251 int i;
2252 typedef unsigned long (*callfunc_t)(unsigned long, unsigned long,
2253 unsigned long, unsigned long, unsigned long,
2254 unsigned long, unsigned long, unsigned long);
2255 callfunc_t func;
2256
2257 if (!scanhex(&adrs))
2258 return;
2259 if (termch != '\n')
2260 termch = 0;
2261 for (i = 0; i < 8; ++i)
2262 args[i] = 0;
2263 for (i = 0; i < 8; ++i) {
2264 if (!scanhex(&args[i]) || termch == '\n')
2265 break;
2266 termch = 0;
2267 }
2268 func = (callfunc_t) adrs;
2269 ret = 0;
2270 if (setjmp(bus_error_jmp) == 0) {
2271 catch_memory_errors = 1;
2272 sync();
2273 ret = func(args[0], args[1], args[2], args[3],
2274 args[4], args[5], args[6], args[7]);
2275 sync();
2276 printf("return value is %x\n", ret);
2277 } else {
2278 printf("*** %x exception occurred\n", fault_except);
2279 }
2280 catch_memory_errors = 0;
2281}
2282
Linus Torvalds1da177e2005-04-16 15:20:36 -07002283/* Input scanning routines */
2284int
2285skipbl(void)
2286{
2287 int c;
2288
2289 if( termch != 0 ){
2290 c = termch;
2291 termch = 0;
2292 } else
2293 c = inchar();
2294 while( c == ' ' || c == '\t' )
2295 c = inchar();
2296 return c;
2297}
2298
2299#define N_PTREGS 44
2300static char *regnames[N_PTREGS] = {
2301 "r0", "r1", "r2", "r3", "r4", "r5", "r6", "r7",
2302 "r8", "r9", "r10", "r11", "r12", "r13", "r14", "r15",
2303 "r16", "r17", "r18", "r19", "r20", "r21", "r22", "r23",
2304 "r24", "r25", "r26", "r27", "r28", "r29", "r30", "r31",
Paul Mackerrasf78541d2005-10-28 22:53:37 +10002305 "pc", "msr", "or3", "ctr", "lr", "xer", "ccr",
2306#ifdef CONFIG_PPC64
2307 "softe",
2308#else
2309 "mq",
2310#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -07002311 "trap", "dar", "dsisr", "res"
2312};
2313
2314int
2315scanhex(unsigned long *vp)
2316{
2317 int c, d;
2318 unsigned long v;
2319
2320 c = skipbl();
2321 if (c == '%') {
2322 /* parse register name */
2323 char regname[8];
2324 int i;
2325
2326 for (i = 0; i < sizeof(regname) - 1; ++i) {
2327 c = inchar();
2328 if (!isalnum(c)) {
2329 termch = c;
2330 break;
2331 }
2332 regname[i] = c;
2333 }
2334 regname[i] = 0;
2335 for (i = 0; i < N_PTREGS; ++i) {
2336 if (strcmp(regnames[i], regname) == 0) {
2337 if (xmon_regs == NULL) {
2338 printf("regs not available\n");
2339 return 0;
2340 }
2341 *vp = ((unsigned long *)xmon_regs)[i];
2342 return 1;
2343 }
2344 }
2345 printf("invalid register name '%%%s'\n", regname);
2346 return 0;
2347 }
2348
2349 /* skip leading "0x" if any */
2350
2351 if (c == '0') {
2352 c = inchar();
2353 if (c == 'x') {
2354 c = inchar();
2355 } else {
2356 d = hexdigit(c);
2357 if (d == EOF) {
2358 termch = c;
2359 *vp = 0;
2360 return 1;
2361 }
2362 }
2363 } else if (c == '$') {
2364 int i;
2365 for (i=0; i<63; i++) {
2366 c = inchar();
2367 if (isspace(c)) {
2368 termch = c;
2369 break;
2370 }
2371 tmpstr[i] = c;
2372 }
2373 tmpstr[i++] = 0;
Benjamin Herrenschmidt6879dc12005-06-21 17:15:30 -07002374 *vp = 0;
2375 if (setjmp(bus_error_jmp) == 0) {
2376 catch_memory_errors = 1;
2377 sync();
2378 *vp = kallsyms_lookup_name(tmpstr);
2379 sync();
2380 }
2381 catch_memory_errors = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002382 if (!(*vp)) {
2383 printf("unknown symbol '%s'\n", tmpstr);
2384 return 0;
2385 }
2386 return 1;
2387 }
2388
2389 d = hexdigit(c);
2390 if (d == EOF) {
2391 termch = c;
2392 return 0;
2393 }
2394 v = 0;
2395 do {
2396 v = (v << 4) + d;
2397 c = inchar();
2398 d = hexdigit(c);
2399 } while (d != EOF);
2400 termch = c;
2401 *vp = v;
2402 return 1;
2403}
2404
2405void
2406scannl(void)
2407{
2408 int c;
2409
2410 c = termch;
2411 termch = 0;
2412 while( c != '\n' )
2413 c = inchar();
2414}
2415
Paul Mackerrasf78541d2005-10-28 22:53:37 +10002416int hexdigit(int c)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002417{
2418 if( '0' <= c && c <= '9' )
2419 return c - '0';
2420 if( 'A' <= c && c <= 'F' )
2421 return c - ('A' - 10);
2422 if( 'a' <= c && c <= 'f' )
2423 return c - ('a' - 10);
2424 return EOF;
2425}
2426
2427void
2428getstring(char *s, int size)
2429{
2430 int c;
2431
2432 c = skipbl();
2433 do {
2434 if( size > 1 ){
2435 *s++ = c;
2436 --size;
2437 }
2438 c = inchar();
2439 } while( c != ' ' && c != '\t' && c != '\n' );
2440 termch = c;
2441 *s = 0;
2442}
2443
2444static char line[256];
2445static char *lineptr;
2446
2447void
2448flush_input(void)
2449{
2450 lineptr = NULL;
2451}
2452
2453int
2454inchar(void)
2455{
2456 if (lineptr == NULL || *lineptr == 0) {
Paul Mackerrasfca5dcd2005-11-08 22:55:08 +11002457 if (xmon_gets(line, sizeof(line)) == NULL) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002458 lineptr = NULL;
2459 return EOF;
2460 }
2461 lineptr = line;
2462 }
2463 return *lineptr++;
2464}
2465
2466void
2467take_input(char *str)
2468{
2469 lineptr = str;
2470}
2471
2472
2473static void
2474symbol_lookup(void)
2475{
2476 int type = inchar();
2477 unsigned long addr;
2478 static char tmp[64];
2479
2480 switch (type) {
2481 case 'a':
2482 if (scanhex(&addr))
2483 xmon_print_symbol(addr, ": ", "\n");
2484 termch = 0;
2485 break;
2486 case 's':
2487 getstring(tmp, 64);
2488 if (setjmp(bus_error_jmp) == 0) {
2489 catch_memory_errors = 1;
2490 sync();
2491 addr = kallsyms_lookup_name(tmp);
2492 if (addr)
2493 printf("%s: %lx\n", tmp, addr);
2494 else
2495 printf("Symbol '%s' not found.\n", tmp);
2496 sync();
2497 }
2498 catch_memory_errors = 0;
2499 termch = 0;
2500 break;
2501 }
2502}
2503
2504
2505/* Print an address in numeric and symbolic form (if possible) */
2506static void xmon_print_symbol(unsigned long address, const char *mid,
2507 const char *after)
2508{
2509 char *modname;
2510 const char *name = NULL;
2511 unsigned long offset, size;
2512
Paul Mackerrasf78541d2005-10-28 22:53:37 +10002513 printf(REG, address);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002514 if (setjmp(bus_error_jmp) == 0) {
2515 catch_memory_errors = 1;
2516 sync();
2517 name = kallsyms_lookup(address, &size, &offset, &modname,
2518 tmpstr);
2519 sync();
2520 /* wait a little while to see if we get a machine check */
2521 __delay(200);
2522 }
2523
2524 catch_memory_errors = 0;
2525
2526 if (name) {
2527 printf("%s%s+%#lx/%#lx", mid, name, offset, size);
2528 if (modname)
2529 printf(" [%s]", modname);
2530 }
2531 printf("%s", after);
2532}
2533
Paul Mackerrasf78541d2005-10-28 22:53:37 +10002534#ifdef CONFIG_PPC64
Linus Torvalds1da177e2005-04-16 15:20:36 -07002535static void dump_slb(void)
2536{
2537 int i;
will schmidtb3b95952007-12-07 08:22:23 +11002538 unsigned long esid,vsid,valid;
2539 unsigned long llp;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002540
2541 printf("SLB contents of cpu %x\n", smp_processor_id());
2542
Michael Neuling584f8b72007-12-06 17:24:48 +11002543 for (i = 0; i < mmu_slb_size; i++) {
will schmidtb3b95952007-12-07 08:22:23 +11002544 asm volatile("slbmfee %0,%1" : "=r" (esid) : "r" (i));
2545 asm volatile("slbmfev %0,%1" : "=r" (vsid) : "r" (i));
2546 valid = (esid & SLB_ESID_V);
2547 if (valid | esid | vsid) {
2548 printf("%02d %016lx %016lx", i, esid, vsid);
2549 if (valid) {
2550 llp = vsid & SLB_VSID_LLP;
2551 if (vsid & SLB_VSID_B_1T) {
2552 printf(" 1T ESID=%9lx VSID=%13lx LLP:%3lx \n",
2553 GET_ESID_1T(esid),
2554 (vsid & ~SLB_VSID_B) >> SLB_VSID_SHIFT_1T,
2555 llp);
2556 } else {
2557 printf(" 256M ESID=%9lx VSID=%13lx LLP:%3lx \n",
2558 GET_ESID(esid),
2559 (vsid & ~SLB_VSID_B) >> SLB_VSID_SHIFT,
2560 llp);
2561 }
2562 } else
2563 printf("\n");
2564 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002565 }
2566}
2567
2568static void dump_stab(void)
2569{
2570 int i;
2571 unsigned long *tmp = (unsigned long *)get_paca()->stab_addr;
2572
2573 printf("Segment table contents of cpu %x\n", smp_processor_id());
2574
2575 for (i = 0; i < PAGE_SIZE/16; i++) {
2576 unsigned long a, b;
2577
2578 a = *tmp++;
2579 b = *tmp++;
2580
2581 if (a || b) {
2582 printf("%03d %016lx ", i, a);
2583 printf("%016lx\n", b);
2584 }
2585 }
2586}
2587
Paul Mackerrasf78541d2005-10-28 22:53:37 +10002588void dump_segments(void)
2589{
2590 if (cpu_has_feature(CPU_FTR_SLB))
2591 dump_slb();
2592 else
2593 dump_stab();
2594}
2595#endif
2596
2597#ifdef CONFIG_PPC_STD_MMU_32
2598void dump_segments(void)
2599{
2600 int i;
2601
2602 printf("sr0-15 =");
2603 for (i = 0; i < 16; ++i)
2604 printf(" %x", mfsrin(i));
2605 printf("\n");
2606}
2607#endif
2608
Benjamin Herrenschmidt5a8a1a22007-11-16 18:23:33 +11002609#ifdef CONFIG_44x
2610static void dump_tlb_44x(void)
2611{
2612 int i;
2613
2614 for (i = 0; i < PPC44x_TLB_SIZE; i++) {
2615 unsigned long w0,w1,w2;
2616 asm volatile("tlbre %0,%1,0" : "=r" (w0) : "r" (i));
2617 asm volatile("tlbre %0,%1,1" : "=r" (w1) : "r" (i));
2618 asm volatile("tlbre %0,%1,2" : "=r" (w2) : "r" (i));
2619 printf("[%02x] %08x %08x %08x ", i, w0, w1, w2);
2620 if (w0 & PPC44x_TLB_VALID) {
2621 printf("V %08x -> %01x%08x %c%c%c%c%c",
2622 w0 & PPC44x_TLB_EPN_MASK,
2623 w1 & PPC44x_TLB_ERPN_MASK,
2624 w1 & PPC44x_TLB_RPN_MASK,
2625 (w2 & PPC44x_TLB_W) ? 'W' : 'w',
2626 (w2 & PPC44x_TLB_I) ? 'I' : 'i',
2627 (w2 & PPC44x_TLB_M) ? 'M' : 'm',
2628 (w2 & PPC44x_TLB_G) ? 'G' : 'g',
2629 (w2 & PPC44x_TLB_E) ? 'E' : 'e');
2630 }
2631 printf("\n");
2632 }
2633}
2634#endif /* CONFIG_44x */
Olaf Heringb13cfd172005-08-04 19:26:42 +02002635void xmon_init(int enable)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002636{
Stephen Rothwellbbb68172006-11-30 11:44:09 +11002637#ifdef CONFIG_PPC_ISERIES
2638 if (firmware_has_feature(FW_FEATURE_ISERIES))
2639 return;
2640#endif
Olaf Heringb13cfd172005-08-04 19:26:42 +02002641 if (enable) {
2642 __debugger = xmon;
2643 __debugger_ipi = xmon_ipi;
2644 __debugger_bpt = xmon_bpt;
2645 __debugger_sstep = xmon_sstep;
2646 __debugger_iabr_match = xmon_iabr_match;
2647 __debugger_dabr_match = xmon_dabr_match;
2648 __debugger_fault_handler = xmon_fault_handler;
2649 } else {
2650 __debugger = NULL;
2651 __debugger_ipi = NULL;
2652 __debugger_bpt = NULL;
2653 __debugger_sstep = NULL;
2654 __debugger_iabr_match = NULL;
2655 __debugger_dabr_match = NULL;
2656 __debugger_fault_handler = NULL;
2657 }
Paul Mackerrasfca5dcd2005-11-08 22:55:08 +11002658 xmon_map_scc();
Linus Torvalds1da177e2005-04-16 15:20:36 -07002659}
Paul Mackerrasfca5dcd2005-11-08 22:55:08 +11002660
2661#ifdef CONFIG_MAGIC_SYSRQ
David Howells7d12e782006-10-05 14:55:46 +01002662static void sysrq_handle_xmon(int key, struct tty_struct *tty)
Paul Mackerrasfca5dcd2005-11-08 22:55:08 +11002663{
2664 /* ensure xmon is enabled */
2665 xmon_init(1);
David Howells7d12e782006-10-05 14:55:46 +01002666 debugger(get_irq_regs());
Paul Mackerrasfca5dcd2005-11-08 22:55:08 +11002667}
2668
2669static struct sysrq_key_op sysrq_xmon_op =
2670{
2671 .handler = sysrq_handle_xmon,
2672 .help_msg = "Xmon",
2673 .action_msg = "Entering xmon",
2674};
2675
2676static int __init setup_xmon_sysrq(void)
2677{
Stephen Rothwellbbb68172006-11-30 11:44:09 +11002678#ifdef CONFIG_PPC_ISERIES
2679 if (firmware_has_feature(FW_FEATURE_ISERIES))
2680 return 0;
2681#endif
Paul Mackerrasfca5dcd2005-11-08 22:55:08 +11002682 register_sysrq_key('x', &sysrq_xmon_op);
2683 return 0;
2684}
2685__initcall(setup_xmon_sysrq);
2686#endif /* CONFIG_MAGIC_SYSRQ */
Michael Ellerman476792832006-10-03 14:12:08 +10002687
Olaf Heringf5e6a282007-06-24 16:57:08 +10002688static int __initdata xmon_early, xmon_off;
Michael Ellerman476792832006-10-03 14:12:08 +10002689
2690static int __init early_parse_xmon(char *p)
2691{
2692 if (!p || strncmp(p, "early", 5) == 0) {
2693 /* just "xmon" is equivalent to "xmon=early" */
2694 xmon_init(1);
2695 xmon_early = 1;
2696 } else if (strncmp(p, "on", 2) == 0)
2697 xmon_init(1);
2698 else if (strncmp(p, "off", 3) == 0)
2699 xmon_off = 1;
2700 else if (strncmp(p, "nobt", 4) == 0)
2701 xmon_no_auto_backtrace = 1;
2702 else
2703 return 1;
2704
2705 return 0;
2706}
2707early_param("xmon", early_parse_xmon);
2708
2709void __init xmon_setup(void)
2710{
2711#ifdef CONFIG_XMON_DEFAULT
2712 if (!xmon_off)
2713 xmon_init(1);
2714#endif
2715 if (xmon_early)
2716 debugger(NULL);
2717}
Michael Ellermanff8a8f22006-10-24 18:31:27 +02002718
Arnd Bergmanne0555952006-11-27 19:18:55 +01002719#ifdef CONFIG_SPU_BASE
Michael Ellermanff8a8f22006-10-24 18:31:27 +02002720
2721struct spu_info {
2722 struct spu *spu;
2723 u64 saved_mfc_sr1_RW;
2724 u32 saved_spu_runcntl_RW;
Michael Ellerman24a24c82006-11-23 00:46:41 +01002725 unsigned long dump_addr;
Michael Ellermanff8a8f22006-10-24 18:31:27 +02002726 u8 stopped_ok;
2727};
2728
2729#define XMON_NUM_SPUS 16 /* Enough for current hardware */
2730
2731static struct spu_info spu_info[XMON_NUM_SPUS];
2732
2733void xmon_register_spus(struct list_head *list)
2734{
2735 struct spu *spu;
2736
2737 list_for_each_entry(spu, list, full_list) {
2738 if (spu->number >= XMON_NUM_SPUS) {
2739 WARN_ON(1);
2740 continue;
2741 }
2742
2743 spu_info[spu->number].spu = spu;
2744 spu_info[spu->number].stopped_ok = 0;
Michael Ellerman24a24c82006-11-23 00:46:41 +01002745 spu_info[spu->number].dump_addr = (unsigned long)
2746 spu_info[spu->number].spu->local_store;
Michael Ellermanff8a8f22006-10-24 18:31:27 +02002747 }
2748}
2749
2750static void stop_spus(void)
2751{
2752 struct spu *spu;
2753 int i;
2754 u64 tmp;
2755
2756 for (i = 0; i < XMON_NUM_SPUS; i++) {
2757 if (!spu_info[i].spu)
2758 continue;
2759
2760 if (setjmp(bus_error_jmp) == 0) {
2761 catch_memory_errors = 1;
2762 sync();
2763
2764 spu = spu_info[i].spu;
2765
2766 spu_info[i].saved_spu_runcntl_RW =
2767 in_be32(&spu->problem->spu_runcntl_RW);
2768
2769 tmp = spu_mfc_sr1_get(spu);
2770 spu_info[i].saved_mfc_sr1_RW = tmp;
2771
2772 tmp &= ~MFC_STATE1_MASTER_RUN_CONTROL_MASK;
2773 spu_mfc_sr1_set(spu, tmp);
2774
2775 sync();
2776 __delay(200);
2777
2778 spu_info[i].stopped_ok = 1;
Michael Ellerman2a144422006-11-23 00:46:40 +01002779
2780 printf("Stopped spu %.2d (was %s)\n", i,
2781 spu_info[i].saved_spu_runcntl_RW ?
2782 "running" : "stopped");
Michael Ellermanff8a8f22006-10-24 18:31:27 +02002783 } else {
2784 catch_memory_errors = 0;
2785 printf("*** Error stopping spu %.2d\n", i);
2786 }
2787 catch_memory_errors = 0;
2788 }
2789}
2790
2791static void restart_spus(void)
2792{
2793 struct spu *spu;
2794 int i;
2795
2796 for (i = 0; i < XMON_NUM_SPUS; i++) {
2797 if (!spu_info[i].spu)
2798 continue;
2799
2800 if (!spu_info[i].stopped_ok) {
2801 printf("*** Error, spu %d was not successfully stopped"
2802 ", not restarting\n", i);
2803 continue;
2804 }
2805
2806 if (setjmp(bus_error_jmp) == 0) {
2807 catch_memory_errors = 1;
2808 sync();
2809
2810 spu = spu_info[i].spu;
2811 spu_mfc_sr1_set(spu, spu_info[i].saved_mfc_sr1_RW);
2812 out_be32(&spu->problem->spu_runcntl_RW,
2813 spu_info[i].saved_spu_runcntl_RW);
2814
2815 sync();
2816 __delay(200);
2817
2818 printf("Restarted spu %.2d\n", i);
2819 } else {
2820 catch_memory_errors = 0;
2821 printf("*** Error restarting spu %.2d\n", i);
2822 }
2823 catch_memory_errors = 0;
2824 }
2825}
2826
Michael Ellermana8984972006-10-24 18:31:28 +02002827#define DUMP_WIDTH 23
Michael Ellerman437a0702006-11-23 00:46:39 +01002828#define DUMP_VALUE(format, field, value) \
Michael Ellermana8984972006-10-24 18:31:28 +02002829do { \
2830 if (setjmp(bus_error_jmp) == 0) { \
2831 catch_memory_errors = 1; \
2832 sync(); \
2833 printf(" %-*s = "format"\n", DUMP_WIDTH, \
Michael Ellerman437a0702006-11-23 00:46:39 +01002834 #field, value); \
Michael Ellermana8984972006-10-24 18:31:28 +02002835 sync(); \
2836 __delay(200); \
2837 } else { \
2838 catch_memory_errors = 0; \
2839 printf(" %-*s = *** Error reading field.\n", \
2840 DUMP_WIDTH, #field); \
2841 } \
2842 catch_memory_errors = 0; \
2843} while (0)
2844
Michael Ellerman437a0702006-11-23 00:46:39 +01002845#define DUMP_FIELD(obj, format, field) \
2846 DUMP_VALUE(format, field, obj->field)
2847
Michael Ellermana8984972006-10-24 18:31:28 +02002848static void dump_spu_fields(struct spu *spu)
2849{
2850 printf("Dumping spu fields at address %p:\n", spu);
2851
2852 DUMP_FIELD(spu, "0x%x", number);
2853 DUMP_FIELD(spu, "%s", name);
Michael Ellermana8984972006-10-24 18:31:28 +02002854 DUMP_FIELD(spu, "0x%lx", local_store_phys);
2855 DUMP_FIELD(spu, "0x%p", local_store);
2856 DUMP_FIELD(spu, "0x%lx", ls_size);
2857 DUMP_FIELD(spu, "0x%x", node);
2858 DUMP_FIELD(spu, "0x%lx", flags);
2859 DUMP_FIELD(spu, "0x%lx", dar);
2860 DUMP_FIELD(spu, "0x%lx", dsisr);
2861 DUMP_FIELD(spu, "%d", class_0_pending);
2862 DUMP_FIELD(spu, "0x%lx", irqs[0]);
2863 DUMP_FIELD(spu, "0x%lx", irqs[1]);
2864 DUMP_FIELD(spu, "0x%lx", irqs[2]);
2865 DUMP_FIELD(spu, "0x%x", slb_replace);
2866 DUMP_FIELD(spu, "%d", pid);
Michael Ellermana8984972006-10-24 18:31:28 +02002867 DUMP_FIELD(spu, "0x%p", mm);
2868 DUMP_FIELD(spu, "0x%p", ctx);
2869 DUMP_FIELD(spu, "0x%p", rq);
2870 DUMP_FIELD(spu, "0x%p", timestamp);
2871 DUMP_FIELD(spu, "0x%lx", problem_phys);
2872 DUMP_FIELD(spu, "0x%p", problem);
Michael Ellerman437a0702006-11-23 00:46:39 +01002873 DUMP_VALUE("0x%x", problem->spu_runcntl_RW,
2874 in_be32(&spu->problem->spu_runcntl_RW));
2875 DUMP_VALUE("0x%x", problem->spu_status_R,
2876 in_be32(&spu->problem->spu_status_R));
2877 DUMP_VALUE("0x%x", problem->spu_npc_RW,
2878 in_be32(&spu->problem->spu_npc_RW));
Michael Ellermana8984972006-10-24 18:31:28 +02002879 DUMP_FIELD(spu, "0x%p", priv2);
Michael Ellermana9852392006-11-23 00:46:50 +01002880 DUMP_FIELD(spu, "0x%p", pdata);
Michael Ellermana8984972006-10-24 18:31:28 +02002881}
2882
Michael Ellermanaf89fb82006-11-23 00:46:44 +01002883int
2884spu_inst_dump(unsigned long adr, long count, int praddr)
2885{
2886 return generic_inst_dump(adr, count, praddr, print_insn_spu);
2887}
2888
2889static void dump_spu_ls(unsigned long num, int subcmd)
Michael Ellerman24a24c82006-11-23 00:46:41 +01002890{
2891 unsigned long offset, addr, ls_addr;
2892
2893 if (setjmp(bus_error_jmp) == 0) {
2894 catch_memory_errors = 1;
2895 sync();
2896 ls_addr = (unsigned long)spu_info[num].spu->local_store;
2897 sync();
2898 __delay(200);
2899 } else {
2900 catch_memory_errors = 0;
2901 printf("*** Error: accessing spu info for spu %d\n", num);
2902 return;
2903 }
2904 catch_memory_errors = 0;
2905
2906 if (scanhex(&offset))
2907 addr = ls_addr + offset;
2908 else
2909 addr = spu_info[num].dump_addr;
2910
2911 if (addr >= ls_addr + LS_SIZE) {
2912 printf("*** Error: address outside of local store\n");
2913 return;
2914 }
2915
Michael Ellermanaf89fb82006-11-23 00:46:44 +01002916 switch (subcmd) {
2917 case 'i':
2918 addr += spu_inst_dump(addr, 16, 1);
2919 last_cmd = "sdi\n";
2920 break;
2921 default:
2922 prdump(addr, 64);
2923 addr += 64;
2924 last_cmd = "sd\n";
2925 break;
2926 }
Michael Ellerman24a24c82006-11-23 00:46:41 +01002927
2928 spu_info[num].dump_addr = addr;
2929}
2930
Michael Ellermanff8a8f22006-10-24 18:31:27 +02002931static int do_spu_cmd(void)
2932{
Michael Ellerman24a24c82006-11-23 00:46:41 +01002933 static unsigned long num = 0;
Michael Ellermanaf89fb82006-11-23 00:46:44 +01002934 int cmd, subcmd = 0;
Michael Ellermanff8a8f22006-10-24 18:31:27 +02002935
2936 cmd = inchar();
2937 switch (cmd) {
2938 case 's':
2939 stop_spus();
2940 break;
2941 case 'r':
2942 restart_spus();
2943 break;
Michael Ellerman24a24c82006-11-23 00:46:41 +01002944 case 'd':
Michael Ellermanaf89fb82006-11-23 00:46:44 +01002945 subcmd = inchar();
2946 if (isxdigit(subcmd) || subcmd == '\n')
2947 termch = subcmd;
2948 case 'f':
Michael Ellerman24a24c82006-11-23 00:46:41 +01002949 scanhex(&num);
2950 if (num >= XMON_NUM_SPUS || !spu_info[num].spu) {
Michael Ellermana8984972006-10-24 18:31:28 +02002951 printf("*** Error: invalid spu number\n");
Michael Ellerman24a24c82006-11-23 00:46:41 +01002952 return 0;
2953 }
2954
2955 switch (cmd) {
2956 case 'f':
2957 dump_spu_fields(spu_info[num].spu);
2958 break;
2959 default:
Michael Ellermanaf89fb82006-11-23 00:46:44 +01002960 dump_spu_ls(num, subcmd);
Michael Ellerman24a24c82006-11-23 00:46:41 +01002961 break;
2962 }
2963
Michael Ellermana8984972006-10-24 18:31:28 +02002964 break;
Michael Ellermanff8a8f22006-10-24 18:31:27 +02002965 default:
2966 return -1;
2967 }
2968
2969 return 0;
2970}
Arnd Bergmanne0555952006-11-27 19:18:55 +01002971#else /* ! CONFIG_SPU_BASE */
Michael Ellermanff8a8f22006-10-24 18:31:27 +02002972static int do_spu_cmd(void)
2973{
2974 return -1;
2975}
2976#endif