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