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