linux-old/arch/ppc64/xmon/xmon.c
<<
>>
Prefs
   1/*
   2 * Routines providing a simple monitor for use on the PowerMac.
   3 *
   4 * Copyright (C) 1996 Paul Mackerras.
   5 *
   6 *      This program is free software; you can redistribute it and/or
   7 *      modify it under the terms of the GNU General Public License
   8 *      as published by the Free Software Foundation; either version
   9 *      2 of the License, or (at your option) any later version.
  10 */
  11#include <linux/config.h>
  12#include <linux/errno.h>
  13#include <linux/sched.h>
  14#include <linux/smp.h>
  15#include <linux/mm.h>
  16#include <linux/reboot.h>
  17#include <linux/delay.h>
  18#include <asm/ptrace.h>
  19#include <asm/string.h>
  20#include <asm/prom.h>
  21#include <asm/machdep.h>
  22#include <asm/processor.h>
  23#include <asm/pgtable.h>
  24#include <asm/mmu.h>
  25#include <asm/mmu_context.h>
  26#include <asm/naca.h>
  27#include <asm/paca.h>
  28#include <asm/ppcdebug.h>
  29#include <asm/cputable.h>
  30#include "nonstdio.h"
  31#include "privinst.h"
  32
  33#define scanhex xmon_scanhex
  34#define skipbl  xmon_skipbl
  35
  36#ifdef CONFIG_SMP
  37static volatile unsigned long cpus_in_xmon = 0;
  38static volatile unsigned long got_xmon = 0;
  39static volatile int take_xmon = -1;
  40static volatile int leaving_xmon = 0;
  41
  42#endif /* CONFIG_SMP */
  43
  44static unsigned long adrs;
  45static int size = 1;
  46static unsigned long ndump = 64;
  47static unsigned long nidump = 16;
  48static unsigned long ncsum = 4096;
  49static int termch;
  50
  51static u_int bus_error_jmp[100];
  52#define setjmp xmon_setjmp
  53#define longjmp xmon_longjmp
  54
  55/* Max number of stack frames we are willing to produce on a backtrace. */
  56#define MAXFRAMECOUNT 50
  57
  58/* Breakpoint stuff */
  59struct bpt {
  60        unsigned long address;
  61        unsigned instr;
  62        unsigned long count;
  63        unsigned char enabled;
  64        char funcname[64];      /* function name for humans */
  65};
  66
  67#define NBPTS   16
  68static struct bpt bpts[NBPTS];
  69static struct bpt dabr;
  70static struct bpt iabr;
  71static unsigned bpinstr = 0x7fe00008;   /* trap */
  72
  73/* Prototypes */
  74extern void (*debugger_fault_handler)(struct pt_regs *);
  75static int cmds(struct pt_regs *);
  76static int mread(unsigned long, void *, int);
  77static int mwrite(unsigned long, void *, int);
  78static void handle_fault(struct pt_regs *);
  79static void byterev(unsigned char *, int);
  80static void memex(void);
  81static int bsesc(void);
  82static void dump(void);
  83static void prdump(unsigned long, long);
  84#ifdef __MWERKS__
  85static void prndump(unsigned, int);
  86static int nvreadb(unsigned);
  87#endif
  88static int ppc_inst_dump(unsigned long, long);
  89void print_address(unsigned long);
  90static int getsp(void);
  91static void dump_hash_table(void);
  92static void backtrace(struct pt_regs *);
  93static void excprint(struct pt_regs *);
  94static void prregs(struct pt_regs *);
  95static void memops(int);
  96static void memlocate(void);
  97static void memzcan(void);
  98static void memdiffs(unsigned char *, unsigned char *, unsigned, unsigned);
  99int skipbl(void);
 100int scanhex(unsigned long *valp);
 101static void scannl(void);
 102static int hexdigit(int);
 103void getstring(char *, int);
 104static void flush_input(void);
 105static int inchar(void);
 106static void take_input(char *);
 107/* static void openforth(void); */
 108static unsigned long read_spr(int);
 109static void write_spr(int, unsigned long);
 110static void super_regs(void);
 111static void print_sysmap(void);
 112static void remove_bpts(void);
 113static void insert_bpts(void);
 114static struct bpt *at_breakpoint(unsigned long pc);
 115static void bpt_cmds(void);
 116static void cacheflush(void);
 117#ifdef CONFIG_SMP
 118static void cpu_cmd(void);
 119#endif /* CONFIG_SMP */
 120static void csum(void);
 121static void bootcmds(void);
 122static void mem_translate(void);
 123static void mem_check(void);
 124static void mem_find_real(void);
 125static void mem_find_vsid(void);
 126
 127static void debug_trace(void);
 128
 129extern int print_insn_big_powerpc(FILE *, unsigned long, unsigned long);
 130extern void printf(const char *fmt, ...);
 131extern void xmon_vfprintf(void *f, const char *fmt, va_list ap);
 132extern int xmon_putc(int c, void *f);
 133extern int putchar(int ch);
 134extern int xmon_read_poll(void);
 135extern int setjmp(u_int *);
 136extern void longjmp(u_int *, int);
 137extern unsigned long _ASR;
 138
 139pte_t *find_linux_pte(pgd_t *pgdir, unsigned long va);  /* from htab.c */
 140
 141#define GETWORD(v)      (((v)[0] << 24) + ((v)[1] << 16) + ((v)[2] << 8) + (v)[3])
 142
 143#define isxdigit(c)     (('0' <= (c) && (c) <= '9') \
 144                         || ('a' <= (c) && (c) <= 'f') \
 145                         || ('A' <= (c) && (c) <= 'F'))
 146#define isalnum(c)      (('0' <= (c) && (c) <= '9') \
 147                         || ('a' <= (c) && (c) <= 'z') \
 148                         || ('A' <= (c) && (c) <= 'Z'))
 149#define isspace(c)      (c == ' ' || c == '\t' || c == 10 || c == 13 || c == 0)
 150
 151static char *help_string = "\
 152Commands:\n\
 153  b     show breakpoints\n\
 154  bd    set data breakpoint\n\
 155  bi    set instruction breakpoint\n\
 156  bc    clear breakpoint\n\
 157  d     dump bytes\n\
 158  di    dump instructions\n\
 159  df    dump float values\n\
 160  dd    dump double values\n\
 161  e     print exception information\n\
 162  f     flush cache\n\
 163  h     dump hash table\n\
 164  m     examine/change memory\n\
 165  mm    move a block of memory\n\
 166  ms    set a block of memory\n\
 167  md    compare two blocks of memory\n\
 168  ml    locate a block of memory\n\
 169  mz    zero a block of memory\n\
 170  mx    translation information for an effective address\n\
 171  mi    show information about memory allocation\n\
 172  M     print System.map\n\
 173  p     show the task list\n\
 174  r     print registers\n\
 175  s     single step\n\
 176  S     print special registers\n\
 177  t     print backtrace\n\
 178  T     Enable/Disable PPCDBG flags\n\
 179  x     exit monitor\n\
 180";
 181
 182static int xmon_trace[NR_CPUS];
 183#define SSTEP   1               /* stepping because of 's' command */
 184#define BRSTEP  2               /* stepping over breakpoint */
 185
 186static struct pt_regs *xmon_regs[NR_CPUS];
 187
 188/*
 189 * Stuff for reading and writing memory safely
 190 */
 191extern inline void sync(void)
 192{
 193        asm volatile("sync; isync");
 194}
 195
 196/* (Ref: 64-bit PowerPC ELF ABI Supplement; Ian Lance Taylor, Zembu Labs).
 197 A PPC stack frame looks like this:
 198
 199 High Address
 200    Back Chain
 201    FP reg save area
 202    GP reg save area
 203    Local var space
 204    Parameter save area         (SP+48)
 205    TOC save area               (SP+40)
 206    link editor doubleword      (SP+32)
 207    compiler doubleword         (SP+24)
 208    LR save                     (SP+16)
 209    CR save                     (SP+8)
 210    Back Chain                  (SP+0)
 211
 212 Note that the LR (ret addr) may not be saved in the current frame if
 213 no functions have been called from the current function.
 214 */
 215
 216/*
 217 A traceback table typically follows each function.
 218 The find_tb_table() func will fill in this struct.  Note that the struct
 219 is not an exact match with the encoded table defined by the ABI.  It is
 220 defined here more for programming convenience.
 221 */
 222struct tbtable {
 223        unsigned long   flags;          /* flags: */
 224#define TBTAB_FLAGSGLOBALLINK   (1L<<47)
 225#define TBTAB_FLAGSISEPROL      (1L<<46)
 226#define TBTAB_FLAGSHASTBOFF     (1L<<45)
 227#define TBTAB_FLAGSINTPROC      (1L<<44)
 228#define TBTAB_FLAGSHASCTL       (1L<<43)
 229#define TBTAB_FLAGSTOCLESS      (1L<<42)
 230#define TBTAB_FLAGSFPPRESENT    (1L<<41)
 231#define TBTAB_FLAGSNAMEPRESENT  (1L<<38)
 232#define TBTAB_FLAGSUSESALLOCA   (1L<<37)
 233#define TBTAB_FLAGSSAVESCR      (1L<<33)
 234#define TBTAB_FLAGSSAVESLR      (1L<<32)
 235#define TBTAB_FLAGSSTORESBC     (1L<<31)
 236#define TBTAB_FLAGSFIXUP        (1L<<30)
 237#define TBTAB_FLAGSPARMSONSTK   (1L<<0)
 238        unsigned char   fp_saved;       /* num fp regs saved f(32-n)..f31 */
 239        unsigned char   gpr_saved;      /* num gpr's saved */
 240        unsigned char   fixedparms;     /* num fixed point parms */
 241        unsigned char   floatparms;     /* num float parms */
 242        unsigned char   parminfo[32];   /* types of args.  null terminated */
 243#define TBTAB_PARMFIXED 1
 244#define TBTAB_PARMSFLOAT 2
 245#define TBTAB_PARMDFLOAT 3
 246        unsigned int    tb_offset;      /* offset from start of func */
 247        unsigned long   funcstart;      /* addr of start of function */
 248        char            name[64];       /* name of function (null terminated)*/
 249};
 250static int find_tb_table(unsigned long codeaddr, struct tbtable *tab);
 251
 252void
 253xmon(struct pt_regs *excp)
 254{
 255        struct pt_regs regs;
 256        int cmd = 0;
 257        unsigned long msr;
 258
 259        if (excp == NULL) {
 260                /* Ok, grab regs as they are now.
 261                 This won't do a particularly good job because the
 262                 prologue has already been executed.
 263                 ToDo: We could reach back into the callers save
 264                 area to do a better job of representing the
 265                 caller's state.
 266                 */
 267                asm volatile ("std      0,0(%0)\n\
 268                        std     1,8(%0)\n\
 269                        std     2,16(%0)\n\
 270                        std     3,24(%0)\n\
 271                        std     4,32(%0)\n\
 272                        std     5,40(%0)\n\
 273                        std     6,48(%0)\n\
 274                        std     7,56(%0)\n\
 275                        std     8,64(%0)\n\
 276                        std     9,72(%0)\n\
 277                        std     10,80(%0)\n\
 278                        std     11,88(%0)\n\
 279                        std     12,96(%0)\n\
 280                        std     13,104(%0)\n\
 281                        std     14,112(%0)\n\
 282                        std     15,120(%0)\n\
 283                        std     16,128(%0)\n\
 284                        std     17,136(%0)\n\
 285                        std     18,144(%0)\n\
 286                        std     19,152(%0)\n\
 287                        std     20,160(%0)\n\
 288                        std     21,168(%0)\n\
 289                        std     22,176(%0)\n\
 290                        std     23,184(%0)\n\
 291                        std     24,192(%0)\n\
 292                        std     25,200(%0)\n\
 293                        std     26,208(%0)\n\
 294                        std     27,216(%0)\n\
 295                        std     28,224(%0)\n\
 296                        std     29,232(%0)\n\
 297                        std     30,240(%0)\n\
 298                        std     31,248(%0)" : : "b" (&regs));
 299                /* Fetch the link reg for this stack frame.
 300                 NOTE: the prev printf fills in the lr. */
 301                regs.nip = regs.link = ((unsigned long *)(regs.gpr[1]))[2];
 302                regs.msr = get_msr();
 303                regs.ctr = get_ctr();
 304                regs.xer = get_xer();
 305                regs.ccr = get_cr();
 306                regs.trap = 0;
 307                excp = &regs;
 308        }
 309
 310        msr = get_msr();
 311        set_msrd(msr & ~MSR_EE);        /* disable interrupts */
 312        xmon_regs[smp_processor_id()] = excp;
 313        excprint(excp);
 314#ifdef CONFIG_SMP
 315        /* possible race condition here if a CPU is held up and gets
 316         * here while we are exiting */
 317        leaving_xmon = 0;
 318        if (test_and_set_bit(smp_processor_id(), &cpus_in_xmon)) {
 319                /* xmon probably caused an exception itself */
 320                printf("We are already in xmon\n");
 321                for (;;)
 322                        ;
 323        }
 324        while (test_and_set_bit(0, &got_xmon)) {
 325                if (take_xmon == smp_processor_id()) {
 326                        take_xmon = -1;
 327                        break;
 328                }
 329        }
 330        /*
 331         * XXX: breakpoints are removed while any cpu is in xmon
 332         */
 333#endif /* CONFIG_SMP */
 334        remove_bpts();
 335        cmd = cmds(excp);
 336        if (cmd == 's') {
 337                xmon_trace[smp_processor_id()] = SSTEP;
 338                excp->msr |= MSR_SE;
 339#ifdef CONFIG_SMP               
 340                take_xmon = smp_processor_id();
 341#endif          
 342        } else if (at_breakpoint(excp->nip)) {
 343                xmon_trace[smp_processor_id()] = BRSTEP;
 344                excp->msr |= MSR_SE;
 345        } else {
 346                xmon_trace[smp_processor_id()] = 0;
 347                insert_bpts();
 348        }
 349        xmon_regs[smp_processor_id()] = 0;
 350#ifdef CONFIG_SMP
 351        leaving_xmon = 1;
 352        if (cmd != 's')
 353                clear_bit(0, &got_xmon);
 354        clear_bit(smp_processor_id(), &cpus_in_xmon);
 355#endif /* CONFIG_SMP */
 356        set_msrd(msr);          /* restore interrupt enable */
 357}
 358
 359void
 360xmon_irq(int irq, void *d, struct pt_regs *regs)
 361{
 362        unsigned long flags;
 363        __save_flags(flags);
 364        __cli();
 365        printf("Keyboard interrupt\n");
 366        xmon(regs);
 367        __restore_flags(flags);
 368}
 369
 370int
 371xmon_bpt(struct pt_regs *regs)
 372{
 373        struct bpt *bp;
 374
 375        bp = at_breakpoint(regs->nip);
 376        if (!bp)
 377                return 0;
 378        if (bp->count) {
 379                --bp->count;
 380                remove_bpts();
 381                excprint(regs);
 382                xmon_trace[smp_processor_id()] = BRSTEP;
 383                regs->msr |= MSR_SE;
 384        } else {
 385                printf("Stopped at breakpoint %x (%lx %s)\n", (bp - bpts)+1, bp->address, bp->funcname);
 386                xmon(regs);
 387        }
 388        return 1;
 389}
 390
 391int
 392xmon_sstep(struct pt_regs *regs)
 393{
 394        if (!xmon_trace[smp_processor_id()])
 395                return 0;
 396        if (xmon_trace[smp_processor_id()] == BRSTEP) {
 397                xmon_trace[smp_processor_id()] = 0;
 398                insert_bpts();
 399        } else {
 400                xmon(regs);
 401        }
 402        return 1;
 403}
 404
 405int
 406xmon_dabr_match(struct pt_regs *regs)
 407{
 408        if (dabr.enabled && dabr.count) {
 409                --dabr.count;
 410                remove_bpts();
 411                excprint(regs);
 412                xmon_trace[smp_processor_id()] = BRSTEP;
 413                regs->msr |= MSR_SE;
 414        } else {
 415                dabr.instr = regs->nip;
 416                xmon(regs);
 417        }
 418        return 1;
 419}
 420
 421int
 422xmon_iabr_match(struct pt_regs *regs)
 423{
 424        if (iabr.enabled && iabr.count) {
 425                --iabr.count;
 426                remove_bpts();
 427                excprint(regs);
 428                xmon_trace[smp_processor_id()] = BRSTEP;
 429                regs->msr |= MSR_SE;
 430        } else {
 431                xmon(regs);
 432        }
 433        return 1;
 434}
 435
 436static struct bpt *
 437at_breakpoint(unsigned long pc)
 438{
 439        int i;
 440        struct bpt *bp;
 441
 442        if (dabr.enabled && pc == dabr.instr)
 443                return &dabr;
 444        if (iabr.enabled && pc == iabr.address)
 445                return &iabr;
 446        bp = bpts;
 447        for (i = 0; i < NBPTS; ++i, ++bp)
 448                if (bp->enabled && pc == bp->address)
 449                        return bp;
 450        return 0;
 451}
 452
 453static void
 454insert_bpts()
 455{
 456        int i;
 457        struct bpt *bp;
 458
 459        if (!(systemcfg->platform & PLATFORM_PSERIES))
 460                return;
 461        bp = bpts;
 462        for (i = 0; i < NBPTS; ++i, ++bp) {
 463                if (!bp->enabled)
 464                        continue;
 465                if (mread(bp->address, &bp->instr, 4) != 4
 466                    || mwrite(bp->address, &bpinstr, 4) != 4) {
 467                        printf("Couldn't insert breakpoint at %x, disabling\n",
 468                               bp->address);
 469                        bp->enabled = 0;
 470                } else {
 471                        store_inst((void *)bp->address);
 472                }
 473        }
 474
 475        if (!(cur_cpu_spec->cpu_features & CPU_FTR_SLB)) {
 476                if (dabr.enabled)
 477                        set_dabr(dabr.address);
 478                if (iabr.enabled)
 479                        set_iabr(iabr.address);
 480        }
 481}
 482
 483static void
 484remove_bpts()
 485{
 486        int i;
 487        struct bpt *bp;
 488        unsigned instr;
 489
 490        if (!(systemcfg->platform & PLATFORM_PSERIES))
 491                return;
 492        if (!(cur_cpu_spec->cpu_features & CPU_FTR_SLB)) {
 493                if (dabr.enabled)
 494                        set_dabr(0);
 495                if (iabr.enabled)
 496                        set_iabr(0);
 497        }
 498
 499        bp = bpts;
 500        for (i = 0; i < NBPTS; ++i, ++bp) {
 501                if (!bp->enabled)
 502                        continue;
 503                if (mread(bp->address, &instr, 4) == 4
 504                    && instr == bpinstr
 505                    && mwrite(bp->address, &bp->instr, 4) != 4)
 506                        printf("Couldn't remove breakpoint at %x\n",
 507                               bp->address);
 508                else
 509                        store_inst((void *)bp->address);
 510        }
 511}
 512
 513static char *last_cmd;
 514
 515/* Command interpreting routine */
 516static int
 517cmds(struct pt_regs *excp)
 518{
 519        int cmd = 0;
 520
 521        last_cmd = NULL;
 522        for(;;) {
 523#ifdef CONFIG_SMP
 524                /* Need to check if we should take any commands on
 525                   this CPU. */
 526                if (leaving_xmon)
 527                        return cmd;
 528                printf("%d:", smp_processor_id());
 529#endif /* CONFIG_SMP */
 530                printf("mon> ");
 531                fflush(stdout);
 532                flush_input();
 533                termch = 0;
 534                cmd = skipbl();
 535                if( cmd == '\n' ) {
 536                        if (last_cmd == NULL)
 537                                continue;
 538                        take_input(last_cmd);
 539                        last_cmd = NULL;
 540                        cmd = inchar();
 541                }
 542                switch (cmd) {
 543                case 'm':
 544                        cmd = inchar();
 545                        switch (cmd) {
 546                        case 'm':
 547                        case 's':
 548                        case 'd':
 549                                memops(cmd);
 550                                break;
 551                        case 'l':
 552                                memlocate();
 553                                break;
 554                        case 'z':
 555                                memzcan();
 556                                break;
 557                        case 'x':
 558                                mem_translate();
 559                                break;
 560                        case 'c':
 561                                mem_check();
 562                                break;
 563                        case 'f':
 564                                mem_find_real();
 565                                break;
 566                        case 'e':
 567                                mem_find_vsid();
 568                                break;
 569                        case 'i':
 570                                show_mem();
 571                                break;
 572                        default:
 573                                termch = cmd;
 574                                memex();
 575                        }
 576                        break;
 577                case 'd':
 578                        dump();
 579                        break;
 580                case 'r':
 581                        if (excp != NULL)
 582                                prregs(excp);   /* print regs */
 583                        break;
 584                case 'e':
 585                        if (excp == NULL)
 586                                printf("No exception information\n");
 587                        else
 588                                excprint(excp);
 589                        break;
 590                case 'M':
 591                        print_sysmap();
 592                        break;
 593                case 'S':
 594                        super_regs();
 595                        break;
 596                case 't':
 597                        backtrace(excp);
 598                        break;
 599                case 'f':
 600                        cacheflush();
 601                        break;
 602                case 'h':
 603                        dump_hash_table();
 604                        break;
 605                case 's':
 606                case 'x':
 607                case EOF:
 608                        return cmd;
 609                case '?':
 610                        printf(help_string);
 611                        break;
 612                case 'p':
 613                        show_state();
 614                        break;
 615                case 'b':
 616                        bpt_cmds();
 617                        break;
 618                case 'C':
 619                        csum();
 620                        break;
 621#ifdef CONFIG_SMP
 622                case 'c':
 623                        cpu_cmd();
 624                        break;
 625#endif /* CONFIG_SMP */
 626                case 'z':
 627                        bootcmds();
 628                case 'T':
 629                        debug_trace();
 630                        break;
 631                default:
 632                        printf("Unrecognized command: ");
 633                        do {
 634                                if( ' ' < cmd && cmd <= '~' )
 635                                        putchar(cmd);
 636                                else
 637                                        printf("\\x%x", cmd);
 638                                cmd = inchar();
 639                        } while (cmd != '\n'); 
 640                        printf(" (type ? for help)\n");
 641                        break;
 642                }
 643        }
 644}
 645
 646static void bootcmds(void)
 647{
 648        int cmd;
 649
 650        cmd = inchar();
 651        if (cmd == 'r')
 652                ppc_md.restart(NULL);
 653        else if (cmd == 'h')
 654                ppc_md.halt();
 655        else if (cmd == 'p')
 656                ppc_md.power_off();
 657}
 658
 659#ifdef CONFIG_SMP
 660static void cpu_cmd(void)
 661{
 662        unsigned long cpu;
 663        int timeout;
 664        int cmd;
 665
 666        cmd = inchar();
 667        if (cmd == 'i') {
 668                printf("stopping all cpus\n");
 669                /* interrupt other cpu(s) */
 670                cpu = MSG_ALL_BUT_SELF;
 671                smp_send_xmon_break(cpu);
 672                return;
 673        }
 674        termch = cmd;
 675        if (!scanhex(&cpu)) {
 676                /* print cpus waiting or in xmon */
 677                printf("cpus stopped:");
 678                for (cpu = 0; cpu < NR_CPUS; ++cpu) {
 679                        if (test_bit(cpu, &cpus_in_xmon)) {
 680                                printf(" %x", cpu);
 681                                if (cpu == smp_processor_id())
 682                                        printf("*", cpu);
 683                        }
 684                }
 685                printf("\n");
 686                return;
 687        }
 688        /* try to switch to cpu specified */
 689        take_xmon = cpu;
 690        timeout = 10000000;
 691        while (take_xmon >= 0) {
 692                if (--timeout == 0) {
 693                        /* yes there's a race here */
 694                        take_xmon = -1;
 695                        printf("cpu %u didn't take control\n", cpu);
 696                        return;
 697                }
 698        }
 699        /* now have to wait to be given control back */
 700        while (test_and_set_bit(0, &got_xmon)) {
 701                if (take_xmon == smp_processor_id()) {
 702                        take_xmon = -1;
 703                        break;
 704                }
 705        }
 706}
 707#endif /* CONFIG_SMP */
 708
 709static unsigned short fcstab[256] = {
 710        0x0000, 0x1189, 0x2312, 0x329b, 0x4624, 0x57ad, 0x6536, 0x74bf,
 711        0x8c48, 0x9dc1, 0xaf5a, 0xbed3, 0xca6c, 0xdbe5, 0xe97e, 0xf8f7,
 712        0x1081, 0x0108, 0x3393, 0x221a, 0x56a5, 0x472c, 0x75b7, 0x643e,
 713        0x9cc9, 0x8d40, 0xbfdb, 0xae52, 0xdaed, 0xcb64, 0xf9ff, 0xe876,
 714        0x2102, 0x308b, 0x0210, 0x1399, 0x6726, 0x76af, 0x4434, 0x55bd,
 715        0xad4a, 0xbcc3, 0x8e58, 0x9fd1, 0xeb6e, 0xfae7, 0xc87c, 0xd9f5,
 716        0x3183, 0x200a, 0x1291, 0x0318, 0x77a7, 0x662e, 0x54b5, 0x453c,
 717        0xbdcb, 0xac42, 0x9ed9, 0x8f50, 0xfbef, 0xea66, 0xd8fd, 0xc974,
 718        0x4204, 0x538d, 0x6116, 0x709f, 0x0420, 0x15a9, 0x2732, 0x36bb,
 719        0xce4c, 0xdfc5, 0xed5e, 0xfcd7, 0x8868, 0x99e1, 0xab7a, 0xbaf3,
 720        0x5285, 0x430c, 0x7197, 0x601e, 0x14a1, 0x0528, 0x37b3, 0x263a,
 721        0xdecd, 0xcf44, 0xfddf, 0xec56, 0x98e9, 0x8960, 0xbbfb, 0xaa72,
 722        0x6306, 0x728f, 0x4014, 0x519d, 0x2522, 0x34ab, 0x0630, 0x17b9,
 723        0xef4e, 0xfec7, 0xcc5c, 0xddd5, 0xa96a, 0xb8e3, 0x8a78, 0x9bf1,
 724        0x7387, 0x620e, 0x5095, 0x411c, 0x35a3, 0x242a, 0x16b1, 0x0738,
 725        0xffcf, 0xee46, 0xdcdd, 0xcd54, 0xb9eb, 0xa862, 0x9af9, 0x8b70,
 726        0x8408, 0x9581, 0xa71a, 0xb693, 0xc22c, 0xd3a5, 0xe13e, 0xf0b7,
 727        0x0840, 0x19c9, 0x2b52, 0x3adb, 0x4e64, 0x5fed, 0x6d76, 0x7cff,
 728        0x9489, 0x8500, 0xb79b, 0xa612, 0xd2ad, 0xc324, 0xf1bf, 0xe036,
 729        0x18c1, 0x0948, 0x3bd3, 0x2a5a, 0x5ee5, 0x4f6c, 0x7df7, 0x6c7e,
 730        0xa50a, 0xb483, 0x8618, 0x9791, 0xe32e, 0xf2a7, 0xc03c, 0xd1b5,
 731        0x2942, 0x38cb, 0x0a50, 0x1bd9, 0x6f66, 0x7eef, 0x4c74, 0x5dfd,
 732        0xb58b, 0xa402, 0x9699, 0x8710, 0xf3af, 0xe226, 0xd0bd, 0xc134,
 733        0x39c3, 0x284a, 0x1ad1, 0x0b58, 0x7fe7, 0x6e6e, 0x5cf5, 0x4d7c,
 734        0xc60c, 0xd785, 0xe51e, 0xf497, 0x8028, 0x91a1, 0xa33a, 0xb2b3,
 735        0x4a44, 0x5bcd, 0x6956, 0x78df, 0x0c60, 0x1de9, 0x2f72, 0x3efb,
 736        0xd68d, 0xc704, 0xf59f, 0xe416, 0x90a9, 0x8120, 0xb3bb, 0xa232,
 737        0x5ac5, 0x4b4c, 0x79d7, 0x685e, 0x1ce1, 0x0d68, 0x3ff3, 0x2e7a,
 738        0xe70e, 0xf687, 0xc41c, 0xd595, 0xa12a, 0xb0a3, 0x8238, 0x93b1,
 739        0x6b46, 0x7acf, 0x4854, 0x59dd, 0x2d62, 0x3ceb, 0x0e70, 0x1ff9,
 740        0xf78f, 0xe606, 0xd49d, 0xc514, 0xb1ab, 0xa022, 0x92b9, 0x8330,
 741        0x7bc7, 0x6a4e, 0x58d5, 0x495c, 0x3de3, 0x2c6a, 0x1ef1, 0x0f78
 742};
 743
 744#define FCS(fcs, c)     (((fcs) >> 8) ^ fcstab[((fcs) ^ (c)) & 0xff])
 745
 746static void
 747csum(void)
 748{
 749        unsigned int i;
 750        unsigned short fcs;
 751        unsigned char v;
 752
 753        if (!scanhex(&adrs))
 754                return;
 755        if (!scanhex(&ncsum))
 756                return;
 757        fcs = 0xffff;
 758        for (i = 0; i < ncsum; ++i) {
 759                if (mread(adrs+i, &v, 1) == 0) {
 760                        printf("csum stopped at %x\n", adrs+i);
 761                        break;
 762                }
 763                fcs = FCS(fcs, v);
 764        }
 765        printf("%x\n", fcs);
 766}
 767
 768static char *breakpoint_help_string = 
 769    "Breakpoint command usage:\n"
 770    "b                show breakpoints\n"
 771    "b <addr> [cnt]   set breakpoint at given instr addr\n"
 772    "bc               clear all breakpoints\n"
 773    "bc <n/addr>      clear breakpoint number n or at addr\n"
 774    "bi <addr> [cnt]  set hardware instr breakpoint (broken?)\n"
 775    "bd <addr> [cnt]  set hardware data breakpoint (broken?)\n"
 776    "";
 777
 778static void
 779bpt_cmds(void)
 780{
 781        int cmd;
 782        unsigned long a;
 783        int mode, i;
 784        struct bpt *bp;
 785        struct tbtable tab;
 786
 787        cmd = inchar();
 788        switch (cmd) {
 789        case 'd':       /* bd - hardware data breakpoint */
 790                if (cur_cpu_spec->cpu_features & CPU_FTR_SLB) {
 791                        printf("Not implemented on POWER4\n");
 792                        break;
 793                }
 794                        
 795                mode = 7;
 796                cmd = inchar();
 797                if (cmd == 'r')
 798                        mode = 5;
 799                else if (cmd == 'w')
 800                        mode = 6;
 801                else
 802                        termch = cmd;
 803                dabr.address = 0;
 804                dabr.count = 0;
 805                dabr.enabled = scanhex(&dabr.address);
 806                scanhex(&dabr.count);
 807                if (dabr.enabled)
 808                        dabr.address = (dabr.address & ~7) | mode;
 809                break;
 810        case 'i':       /* bi - hardware instr breakpoint */
 811                if (cur_cpu_spec->cpu_features & CPU_FTR_SLB) {
 812                        printf("Not implemented on POWER4\n");
 813                        break;
 814                }
 815                iabr.address = 0;
 816                iabr.count = 0;
 817                iabr.enabled = scanhex(&iabr.address);
 818                if (iabr.enabled)
 819                        iabr.address |= 3;
 820                scanhex(&iabr.count);
 821                break;
 822        case 'c':
 823                if (!scanhex(&a)) {
 824                        /* clear all breakpoints */
 825                        for (i = 0; i < NBPTS; ++i)
 826                                bpts[i].enabled = 0;
 827                        iabr.enabled = 0;
 828                        dabr.enabled = 0;
 829                        printf("All breakpoints cleared\n");
 830                } else {
 831                        if (a <= NBPTS && a >= 1) {
 832                                /* assume a breakpoint number */
 833                                --a;    /* bp nums are 1 based */
 834                                bp = &bpts[a];
 835                        } else {
 836                                /* assume a breakpoint address */
 837                                bp = at_breakpoint(a);
 838                        }
 839                        if (bp == 0) {
 840                                printf("No breakpoint at %x\n", a);
 841                        } else {
 842                                printf("Cleared breakpoint %x (%lx %s)\n", (bp - bpts)+1, bp->address, bp->funcname);
 843                                bp->enabled = 0;
 844                        }
 845                }
 846                break;
 847        case '?':
 848                printf(breakpoint_help_string);
 849                break;
 850        default:
 851                termch = cmd;
 852                cmd = skipbl();
 853                if (cmd == '?') {
 854                        printf(breakpoint_help_string);
 855                        break;
 856                }
 857                termch = cmd;
 858                if (!scanhex(&a)) {
 859                        /* print all breakpoints */
 860                        int bpnum;
 861
 862                        printf("   type            address    count\n");
 863                        if (dabr.enabled) {
 864                                printf("   data   %.16lx %8x [", dabr.address & ~7,
 865                                       dabr.count);
 866                                if (dabr.address & 1)
 867                                        printf("r");
 868                                if (dabr.address & 2)
 869                                        printf("w");
 870                                printf("]\n");
 871                        }
 872                        if (iabr.enabled)
 873                                printf("   inst   %.16lx %8x\n", iabr.address & ~3,
 874                                       iabr.count);
 875                        for (bp = bpts, bpnum = 1; bp < &bpts[NBPTS]; ++bp, ++bpnum)
 876                                if (bp->enabled)
 877                                        printf("%2x trap   %.16lx %8x  %s\n", bpnum, bp->address, bp->count, bp->funcname);
 878                        break;
 879                }
 880                bp = at_breakpoint(a);
 881                if (bp == 0) {
 882                        for (bp = bpts; bp < &bpts[NBPTS]; ++bp)
 883                                if (!bp->enabled)
 884                                        break;
 885                        if (bp >= &bpts[NBPTS]) {
 886                                printf("Sorry, no free breakpoints.  Please clear one first.\n");
 887                                break;
 888                        }
 889                }
 890                bp->enabled = 1;
 891                bp->address = a;
 892                bp->count = 0;
 893                scanhex(&bp->count);
 894                /* Find the function name just once. */
 895                bp->funcname[0] = '\0';
 896                if (find_tb_table(bp->address, &tab) && tab.name[0]) {
 897                        /* Got a nice name for it. */
 898                        int delta = bp->address - tab.funcstart;
 899                        sprintf(bp->funcname, "%s+0x%x", tab.name, delta);
 900                }
 901                printf("Set breakpoint %2x trap   %.16lx %8x  %s\n", (bp-bpts)+1, bp->address, bp->count, bp->funcname);
 902                break;
 903        }
 904}
 905
 906/* Very cheap human name for vector lookup. */
 907static
 908const char *getvecname(unsigned long vec)
 909{
 910        char *ret;
 911        switch (vec) {
 912        case 0x100:     ret = "(System Reset)"; break; 
 913        case 0x200:     ret = "(Machine Check)"; break; 
 914        case 0x300:     ret = "(Data Access)"; break; 
 915        case 0x380:     ret = "(Data SLB Access)"; break;
 916        case 0x400:     ret = "(Instruction Access)"; break; 
 917        case 0x480:     ret = "(Instruction SLB Access)"; break;
 918        case 0x500:     ret = "(Hardware Interrupt)"; break; 
 919        case 0x600:     ret = "(Alignment)"; break; 
 920        case 0x700:     ret = "(Program Check)"; break; 
 921        case 0x800:     ret = "(FPU Unavailable)"; break; 
 922        case 0x900:     ret = "(Decrementer)"; break; 
 923        case 0xc00:     ret = "(System Call)"; break; 
 924        case 0xd00:     ret = "(Single Step)"; break; 
 925        case 0xf00:     ret = "(Performance Monitor)"; break; 
 926        default: ret = "";
 927        }
 928        return ret;
 929}
 930
 931static void
 932backtrace(struct pt_regs *excp)
 933{
 934        unsigned long sp;
 935        unsigned long lr;
 936        unsigned long stack[3];
 937        struct pt_regs regs;
 938        struct tbtable tab;
 939        int framecount;
 940        char *funcname;
 941        /* declare these as raw ptrs so we don't get func descriptors */
 942        extern void *ret_from_except, *ret_from_syscall_1;
 943
 944        if (excp != NULL) {
 945                lr = excp->link;
 946                sp = excp->gpr[1];
 947        } else {
 948                /* Use care not to call any function before this point
 949                 so the saved lr has a chance of being good. */
 950                asm volatile ("mflr %0" : "=r" (lr) :);
 951                sp = getsp();
 952        }
 953        scanhex(&sp);
 954        scannl();
 955        for (framecount = 0;
 956             sp != 0 && framecount < MAXFRAMECOUNT;
 957             sp = stack[0], framecount++) {
 958                if (mread(sp, stack, sizeof(stack)) != sizeof(stack))
 959                        break;
 960#if 0
 961                if (lr != 0) {
 962                    stack[2] = lr;      /* fake out the first saved lr.  It may not be saved yet. */
 963                    lr = 0;
 964                }
 965#endif
 966                printf("%.16lx  %.16lx", sp, stack[2]);
 967                /* TAI -- for now only the ones cast to unsigned long will match.
 968                 * Need to test the rest...
 969                 */
 970                if ((stack[2] == (unsigned long)ret_from_except &&
 971                            (funcname = "ret_from_except"))
 972                    || (stack[2] == (unsigned long)ret_from_syscall_1 &&
 973                            (funcname = "ret_from_syscall_1"))
 974#if 0
 975                    || stack[2] == (unsigned) &ret_from_syscall_2
 976                    || stack[2] == (unsigned) &do_signal_ret
 977#endif
 978                    ) {
 979                        printf("  %s\n", funcname);
 980                        if (mread(sp+112, &regs, sizeof(regs)) != sizeof(regs))
 981                                break;
 982                        printf("exception: %lx %s regs %lx\n", regs.trap, getvecname(regs.trap), sp+112);
 983                        printf("                  %.16lx", regs.nip);
 984                        if ((regs.nip & 0xffffffff00000000UL) &&
 985                            find_tb_table(regs.nip, &tab)) {
 986                                int delta = regs.nip-tab.funcstart;
 987                                if (delta < 0)
 988                                        printf("  <unknown code>");
 989                                else
 990                                        printf("  %s+0x%x", tab.name, delta);
 991                        }
 992                        printf("\n");
 993                        if (regs.gpr[1] < sp) {
 994                            printf("<Stack drops into 32-bit userspace %.16lx>\n", regs.gpr[1]);
 995                            break;
 996                        }
 997
 998                        sp = regs.gpr[1];
 999                        if (mread(sp, stack, sizeof(stack)) != sizeof(stack))
1000                                break;
1001                } else {
1002                        if (stack[2] && find_tb_table(stack[2], &tab)) {
1003                                int delta = stack[2]-tab.funcstart;
1004                                if (delta < 0)
1005                                        printf("  <unknown code>");
1006                                else
1007                                        printf("  %s+0x%x", tab.name, delta);
1008                        }
1009                        printf("\n");
1010                }
1011                if (stack[0] && stack[0] <= sp) {
1012                        if ((stack[0] & 0xffffffff00000000UL) == 0)
1013                                printf("<Stack drops into 32-bit userspace %.16lx>\n", stack[0]);
1014                        else
1015                                printf("<Corrupt stack.  Next backchain is %.16lx>\n", stack[0]);
1016                        break;
1017                }
1018        }
1019        if (framecount >= MAXFRAMECOUNT)
1020                printf("<Punt. Too many stack frames>\n");
1021}
1022
1023int
1024getsp()
1025{
1026        int x;
1027
1028        asm("mr %0,1" : "=r" (x) :);
1029        return x;
1030}
1031
1032spinlock_t exception_print_lock = SPIN_LOCK_UNLOCKED;
1033
1034void
1035excprint(struct pt_regs *fp)
1036{
1037        struct task_struct *c;
1038        struct tbtable tab;
1039        unsigned long flags;
1040
1041        spin_lock_irqsave(&exception_print_lock, flags);
1042
1043#ifdef CONFIG_SMP
1044        printf("cpu %d: ", smp_processor_id());
1045#endif /* CONFIG_SMP */
1046
1047        printf("Vector: %lx %s at  [%lx]\n", fp->trap, getvecname(fp->trap), fp);
1048        printf("    pc: %lx", fp->nip);
1049        if (find_tb_table(fp->nip, &tab) && tab.name[0]) {
1050                /* Got a nice name for it */
1051                int delta = fp->nip - tab.funcstart;
1052                printf(" (%s+0x%x)", tab.name, delta);
1053        }
1054        printf("\n");
1055        printf("    lr: %lx", fp->link);
1056        if (find_tb_table(fp->link, &tab) && tab.name[0]) {
1057                /* Got a nice name for it */
1058                int delta = fp->link - tab.funcstart;
1059                printf(" (%s+0x%x)", tab.name, delta);
1060        }
1061        printf("\n");
1062        printf("    sp: %lx\n", fp->gpr[1]);
1063        printf("   msr: %lx\n", fp->msr);
1064
1065        if (fp->trap == 0x300 || fp->trap == 0x380 || fp->trap == 0x600) {
1066                printf("   dar: %lx\n", fp->dar);
1067                printf(" dsisr: %lx\n", fp->dsisr);
1068        }
1069
1070        /* XXX: need to copy current or we die.  Why? */
1071        c = current;
1072        printf("  current = 0x%lx\n", c);
1073        printf("  paca    = 0x%lx\n", get_paca());
1074        if (c) {
1075                printf("  current = %lx, pid = %ld, comm = %s\n",
1076                       c, c->pid, c->comm);
1077        }
1078
1079        spin_unlock_irqrestore(&exception_print_lock, flags);
1080}
1081
1082void
1083prregs(struct pt_regs *fp)
1084{
1085        int n;
1086        unsigned long base;
1087
1088        if (scanhex((void *)&base))
1089                fp = (struct pt_regs *) base;
1090        for (n = 0; n < 16; ++n)
1091                printf("R%.2ld = %.16lx   R%.2ld = %.16lx\n", n, fp->gpr[n],
1092                       n+16, fp->gpr[n+16]);
1093        printf("pc  = %.16lx   msr = %.16lx\nlr  = %.16lx   cr  = %.16lx\n",
1094               fp->nip, fp->msr, fp->link, fp->ccr);
1095        printf("ctr = %.16lx   xer = %.16lx   trap = %8lx\n",
1096               fp->ctr, fp->xer, fp->trap);
1097}
1098
1099void
1100cacheflush(void)
1101{
1102        int cmd;
1103        unsigned long nflush;
1104
1105        cmd = inchar();
1106        if (cmd != 'i')
1107                termch = cmd;
1108        scanhex((void *)&adrs);
1109        if (termch != '\n')
1110                termch = 0;
1111        nflush = 1;
1112        scanhex(&nflush);
1113        nflush = (nflush + 31) / 32;
1114        if (cmd != 'i') {
1115                for (; nflush > 0; --nflush, adrs += 0x20)
1116                        cflush((void *) adrs);
1117        } else {
1118                for (; nflush > 0; --nflush, adrs += 0x20)
1119                        cinval((void *) adrs);
1120        }
1121}
1122
1123unsigned long
1124read_spr(int n)
1125{
1126        unsigned int instrs[2];
1127        unsigned long (*code)(void);
1128        unsigned long opd[3];
1129
1130        instrs[0] = 0x7c6002a6 + ((n & 0x1F) << 16) + ((n & 0x3e0) << 6);
1131        instrs[1] = 0x4e800020;
1132        opd[0] = (unsigned long)instrs;
1133        opd[1] = 0;
1134        opd[2] = 0;
1135        store_inst(instrs);
1136        store_inst(instrs+1);
1137        code = (unsigned long (*)(void)) opd;
1138
1139        return code();
1140}
1141
1142void
1143write_spr(int n, unsigned long val)
1144{
1145        unsigned int instrs[2];
1146        unsigned long (*code)(unsigned long);
1147        unsigned long opd[3];
1148
1149        instrs[0] = 0x7c6003a6 + ((n & 0x1F) << 16) + ((n & 0x3e0) << 6);
1150        instrs[1] = 0x4e800020;
1151        opd[0] = (unsigned long)instrs;
1152        opd[1] = 0;
1153        opd[2] = 0;
1154        store_inst(instrs);
1155        store_inst(instrs+1);
1156        code = (unsigned long (*)(unsigned long)) opd;
1157
1158        code(val);
1159}
1160
1161static unsigned long regno;
1162extern char exc_prolog;
1163extern char dec_exc;
1164
1165void
1166print_sysmap(void)
1167{
1168        extern char *sysmap;
1169        if ( sysmap )
1170                printf("System.map: \n%s", sysmap);
1171}
1172
1173void
1174super_regs()
1175{
1176        int i, cmd;
1177        unsigned long val;
1178        struct paca_struct*  ptrPaca = NULL;
1179        struct ItLpPaca*  ptrLpPaca = NULL;
1180        struct ItLpRegSave*  ptrLpRegSave = NULL;
1181
1182        cmd = skipbl();
1183        if (cmd == '\n') {
1184                unsigned long sp, toc;
1185                asm("mr %0,1" : "=r" (sp) :);
1186                asm("mr %0,2" : "=r" (toc) :);
1187
1188                printf("msr  = %.16lx  sprg0= %.16lx\n", get_msr(), get_sprg0());
1189                printf("pvr  = %.16lx  sprg1= %.16lx\n", get_pvr(), get_sprg1()); 
1190                printf("dec  = %.16lx  sprg2= %.16lx\n", get_dec(), get_sprg2());
1191                printf("sp   = %.16lx  sprg3= %.16lx\n", sp, get_sprg3());
1192                printf("toc  = %.16lx  dar  = %.16lx\n", toc, get_dar());
1193                printf("srr0 = %.16lx  srr1 = %.16lx\n", get_srr0(), get_srr1());
1194                printf("asr  = %.16lx\n", mfasr());
1195                for (i = 0; i < 8; ++i)
1196                        printf("sr%.2ld = %.16lx  sr%.2ld = %.16lx\n", i, get_sr(i), i+8, get_sr(i+8));
1197
1198                // Dump out relevant Paca data areas.
1199                printf("Paca: \n");
1200                ptrPaca = get_paca();
1201    
1202                printf("  Local Processor Control Area (LpPaca): \n");
1203                ptrLpPaca = ptrPaca->xLpPacaPtr;
1204                printf("    Saved Srr0=%.16lx  Saved Srr1=%.16lx \n", ptrLpPaca->xSavedSrr0, ptrLpPaca->xSavedSrr1);
1205                printf("    Saved Gpr3=%.16lx  Saved Gpr4=%.16lx \n", ptrLpPaca->xSavedGpr3, ptrLpPaca->xSavedGpr4);
1206                printf("    Saved Gpr5=%.16lx \n", ptrLpPaca->xSavedGpr5);
1207    
1208                printf("  Local Processor Register Save Area (LpRegSave): \n");
1209                ptrLpRegSave = ptrPaca->xLpRegSavePtr;
1210                printf("    Saved Sprg0=%.16lx  Saved Sprg1=%.16lx \n", ptrLpRegSave->xSPRG0, ptrLpRegSave->xSPRG0);
1211                printf("    Saved Sprg2=%.16lx  Saved Sprg3=%.16lx \n", ptrLpRegSave->xSPRG2, ptrLpRegSave->xSPRG3);
1212                printf("    Saved Msr  =%.16lx  Saved Nia  =%.16lx \n", ptrLpRegSave->xMSR, ptrLpRegSave->xNIA);
1213    
1214                return;
1215        }
1216
1217        scanhex(&regno);
1218        switch (cmd) {
1219        case 'w':
1220                val = read_spr(regno);
1221                scanhex(&val);
1222                write_spr(regno, val);
1223                /* fall through */
1224        case 'r':
1225                printf("spr %lx = %lx\n", regno, read_spr(regno));
1226                break;
1227        case 's':
1228                val = get_sr(regno);
1229                scanhex(&val);
1230                set_sr(regno, val);
1231                break;
1232        case 'm':
1233                val = get_msr();
1234                scanhex(&val);
1235                set_msrd(val);
1236                break;
1237        }
1238        scannl();
1239}
1240
1241#ifndef CONFIG_PPC64BRIDGE
1242static void
1243dump_hash_table_seg(unsigned seg, unsigned start, unsigned end)
1244{
1245        extern void *Hash;
1246        extern unsigned long Hash_size;
1247        unsigned *htab = Hash;
1248        unsigned hsize = Hash_size;
1249        unsigned v, hmask, va, last_va;
1250        int found, last_found, i;
1251        unsigned *hg, w1, last_w2, last_va0;
1252
1253        last_found = 0;
1254        hmask = hsize / 64 - 1;
1255        va = start;
1256        start = (start >> 12) & 0xffff;
1257        end = (end >> 12) & 0xffff;
1258        for (v = start; v < end; ++v) {
1259                found = 0;
1260                hg = htab + (((v ^ seg) & hmask) * 16);
1261                w1 = 0x80000000 | (seg << 7) | (v >> 10);
1262                for (i = 0; i < 8; ++i, hg += 2) {
1263                        if (*hg == w1) {
1264                                found = 1;
1265                                break;
1266                        }
1267                }
1268                if (!found) {
1269                        w1 ^= 0x40;
1270                        hg = htab + ((~(v ^ seg) & hmask) * 16);
1271                        for (i = 0; i < 8; ++i, hg += 2) {
1272                                if (*hg == w1) {
1273                                        found = 1;
1274                                        break;
1275                                }
1276                        }
1277                }
1278                if (!(last_found && found && (hg[1] & ~0x180) == last_w2 + 4096)) {
1279                        if (last_found) {
1280                                if (last_va != last_va0)
1281                                        printf(" ... %x", last_va);
1282                                printf("\n");
1283                        }
1284                        if (found) {
1285                                printf("%x to %x", va, hg[1]);
1286                                last_va0 = va;
1287                        }
1288                        last_found = found;
1289                }
1290                if (found) {
1291                        last_w2 = hg[1] & ~0x180;
1292                        last_va = va;
1293                }
1294                va += 4096;
1295        }
1296        if (last_found)
1297                printf(" ... %x\n", last_va);
1298}
1299
1300#else /* CONFIG_PPC64BRIDGE */
1301static void
1302dump_hash_table_seg(unsigned seg, unsigned start, unsigned end)
1303{
1304        extern void *Hash;
1305        extern unsigned long Hash_size;
1306        unsigned *htab = Hash;
1307        unsigned hsize = Hash_size;
1308        unsigned v, hmask, va, last_va;
1309        int found, last_found, i;
1310        unsigned *hg, w1, last_w2, last_va0;
1311
1312        last_found = 0;
1313        hmask = hsize / 128 - 1;
1314        va = start;
1315        start = (start >> 12) & 0xffff;
1316        end = (end >> 12) & 0xffff;
1317        for (v = start; v < end; ++v) {
1318                found = 0;
1319                hg = htab + (((v ^ seg) & hmask) * 32);
1320                w1 = 1 | (seg << 12) | ((v & 0xf800) >> 4);
1321                for (i = 0; i < 8; ++i, hg += 4) {
1322                        if (hg[1] == w1) {
1323                                found = 1;
1324                                break;
1325                        }
1326                }
1327                if (!found) {
1328                        w1 ^= 2;
1329                        hg = htab + ((~(v ^ seg) & hmask) * 32);
1330                        for (i = 0; i < 8; ++i, hg += 4) {
1331                                if (hg[1] == w1) {
1332                                        found = 1;
1333                                        break;
1334                                }
1335                        }
1336                }
1337                if (!(last_found && found && (hg[3] & ~0x180) == last_w2 + 4096)) {
1338                        if (last_found) {
1339                                if (last_va != last_va0)
1340                                        printf(" ... %x", last_va);
1341                                printf("\n");
1342                        }
1343                        if (found) {
1344                                printf("%x to %x", va, hg[3]);
1345                                last_va0 = va;
1346                        }
1347                        last_found = found;
1348                }
1349                if (found) {
1350                        last_w2 = hg[3] & ~0x180;
1351                        last_va = va;
1352                }
1353                va += 4096;
1354        }
1355        if (last_found)
1356                printf(" ... %x\n", last_va);
1357}
1358#endif /* CONFIG_PPC64BRIDGE */
1359
1360static unsigned long hash_ctx;
1361static unsigned long hash_start;
1362static unsigned long hash_end;
1363
1364static void
1365dump_hash_table()
1366{
1367        int seg;
1368        unsigned seg_start, seg_end;
1369
1370        hash_ctx = 0;
1371        hash_start = 0;
1372        hash_end = 0xfffff000;
1373        scanhex(&hash_ctx);
1374        scanhex(&hash_start);
1375        scanhex(&hash_end);
1376        printf("Mappings for context %x\n", hash_ctx);
1377        seg_start = hash_start;
1378        for (seg = hash_start >> 28; seg <= hash_end >> 28; ++seg) {
1379                seg_end = (seg << 28) | 0x0ffff000;
1380                if (seg_end > hash_end)
1381                        seg_end = hash_end;
1382                dump_hash_table_seg((hash_ctx << 4) + seg, seg_start, seg_end);
1383                seg_start = seg_end + 0x1000;
1384        }
1385}
1386
1387int
1388mread(unsigned long adrs, void *buf, int size)
1389{
1390        volatile int n;
1391        char *p, *q;
1392
1393        n = 0;
1394        if( setjmp(bus_error_jmp) == 0 ){
1395                debugger_fault_handler = handle_fault;
1396                sync();
1397                p = (char *) adrs;
1398                q = (char *) buf;
1399                switch (size) {
1400                case 2: *(short *)q = *(short *)p;      break;
1401                case 4: *(int *)q = *(int *)p;          break;
1402                default:
1403                        for( ; n < size; ++n ) {
1404                                *q++ = *p++;
1405                                sync();
1406                        }
1407                }
1408                sync();
1409                /* wait a little while to see if we get a machine check */
1410                __delay(200);
1411                n = size;
1412        }
1413        debugger_fault_handler = 0;
1414        return n;
1415}
1416
1417int
1418mwrite(unsigned long adrs, void *buf, int size)
1419{
1420        volatile int n;
1421        char *p, *q;
1422
1423        n = 0;
1424        if( setjmp(bus_error_jmp) == 0 ){
1425                debugger_fault_handler = handle_fault;
1426                sync();
1427                p = (char *) adrs;
1428                q = (char *) buf;
1429                switch (size) {
1430                case 2: *(short *)p = *(short *)q;      break;
1431                case 4: *(int *)p = *(int *)q;          break;
1432                default:
1433                        for( ; n < size; ++n ) {
1434                                *p++ = *q++;
1435                                sync();
1436                        }
1437                }
1438                sync();
1439                /* wait a little while to see if we get a machine check */
1440                __delay(200);
1441                n = size;
1442        } else {
1443                printf("*** Error writing address %x\n", adrs + n);
1444        }
1445        debugger_fault_handler = 0;
1446        return n;
1447}
1448
1449static int fault_type;
1450static char *fault_chars[] = { "--", "**", "##" };
1451
1452static void
1453handle_fault(struct pt_regs *regs)
1454{
1455        switch (regs->trap) {
1456        case 0x200:
1457                fault_type = 0;
1458                break;
1459        case 0x300:
1460        case 0x380:
1461                fault_type = 1;
1462                break;
1463        default:
1464                fault_type = 2;
1465        }
1466
1467        longjmp(bus_error_jmp, 1);
1468}
1469
1470#define SWAP(a, b, t)   ((t) = (a), (a) = (b), (b) = (t))
1471
1472void
1473byterev(unsigned char *val, int size)
1474{
1475        int t;
1476        
1477        switch (size) {
1478        case 2:
1479                SWAP(val[0], val[1], t);
1480                break;
1481        case 4:
1482                SWAP(val[0], val[3], t);
1483                SWAP(val[1], val[2], t);
1484                break;
1485        case 8: /* is there really any use for this? */
1486                SWAP(val[0], val[7], t);
1487                SWAP(val[1], val[6], t);
1488                SWAP(val[2], val[5], t);
1489                SWAP(val[3], val[4], t);
1490                break;
1491        }
1492}
1493
1494static int brev;
1495static int mnoread;
1496
1497static char *memex_help_string = 
1498    "Memory examine command usage:\n"
1499    "m [addr] [flags] examine/change memory\n"
1500    "  addr is optional.  will start where left off.\n"
1501    "  flags may include chars from this set:\n"
1502    "    b   modify by bytes (default)\n"
1503    "    w   modify by words (2 byte)\n"
1504    "    l   modify by longs (4 byte)\n"
1505    "    d   modify by doubleword (8 byte)\n"
1506    "    r   toggle reverse byte order mode\n"
1507    "    n   do not read memory (for i/o spaces)\n"
1508    "    .   ok to read (default)\n"
1509    "NOTE: flags are saved as defaults\n"
1510    "";
1511
1512static char *memex_subcmd_help_string = 
1513    "Memory examine subcommands:\n"
1514    "  hexval   write this val to current location\n"
1515    "  'string' write chars from string to this location\n"
1516    "  '        increment address\n"
1517    "  ^        decrement address\n"
1518    "  /        increment addr by 0x10.  //=0x100, ///=0x1000, etc\n"
1519    "  \\        decrement addr by 0x10.  \\\\=0x100, \\\\\\=0x1000, etc\n"
1520    "  `        clear no-read flag\n"
1521    "  ;        stay at this addr\n"
1522    "  v        change to byte mode\n"
1523    "  w        change to word (2 byte) mode\n"
1524    "  l        change to long (4 byte) mode\n"
1525    "  u        change to doubleword (8 byte) mode\n"
1526    "  m addr   change current addr\n"
1527    "  n        toggle no-read flag\n"
1528    "  r        toggle byte reverse flag\n"
1529    "  < count  back up count bytes\n"
1530    "  > count  skip forward count bytes\n"
1531    "  x        exit this mode\n"
1532    "";
1533
1534void
1535memex()
1536{
1537        int cmd, inc, i, nslash;
1538        unsigned long n;
1539        unsigned char val[16];
1540
1541        scanhex((void *)&adrs);
1542        cmd = skipbl();
1543        if (cmd == '?') {
1544                printf(memex_help_string);
1545                return;
1546        } else {
1547                termch = cmd;
1548        }
1549        last_cmd = "m\n";
1550        while ((cmd = skipbl()) != '\n') {
1551                switch( cmd ){
1552                case 'b':       size = 1;       break;
1553                case 'w':       size = 2;       break;
1554                case 'l':       size = 4;       break;
1555                case 'd':       size = 8;       break;
1556                case 'r':       brev = !brev;   break;
1557                case 'n':       mnoread = 1;    break;
1558                case '.':       mnoread = 0;    break;
1559                }
1560        }
1561        if( size <= 0 )
1562                size = 1;
1563        else if( size > 8 )
1564                size = 8;
1565        for(;;){
1566                if (!mnoread)
1567                        n = mread(adrs, val, size);
1568                printf("%.16x%c", adrs, brev? 'r': ' ');
1569                if (!mnoread) {
1570                        if (brev)
1571                                byterev(val, size);
1572                        putchar(' ');
1573                        for (i = 0; i < n; ++i)
1574                                printf("%.2x", val[i]);
1575                        for (; i < size; ++i)
1576                                printf("%s", fault_chars[fault_type]);
1577                }
1578                putchar(' ');
1579                inc = size;
1580                nslash = 0;
1581                for(;;){
1582                        if( scanhex(&n) ){
1583                                for (i = 0; i < size; ++i)
1584                                        val[i] = n >> (i * 8);
1585                                if (!brev)
1586                                        byterev(val, size);
1587                                mwrite(adrs, val, size);
1588                                inc = size;
1589                        }
1590                        cmd = skipbl();
1591                        if (cmd == '\n')
1592                                break;
1593                        inc = 0;
1594                        switch (cmd) {
1595                        case '\'':
1596                                for(;;){
1597                                        n = inchar();
1598                                        if( n == '\\' )
1599                                                n = bsesc();
1600                                        else if( n == '\'' )
1601                                                break;
1602                                        for (i = 0; i < size; ++i)
1603                                                val[i] = n >> (i * 8);
1604                                        if (!brev)
1605                                                byterev(val, size);
1606                                        mwrite(adrs, val, size);
1607                                        adrs += size;
1608                                }
1609                                adrs -= size;
1610                                inc = size;
1611                                break;
1612                        case ',':
1613                                adrs += size;
1614                                break;
1615                        case '.':
1616                                mnoread = 0;
1617                                break;
1618                        case ';':
1619                                break;
1620                        case 'x':
1621                        case EOF:
1622                                scannl();
1623                                return;
1624                        case 'b':
1625                        case 'v':
1626                                size = 1;
1627                                break;
1628                        case 'w':
1629                                size = 2;
1630                                break;
1631                        case 'l':
1632                                size = 4;
1633                                break;
1634                        case 'u':
1635                                size = 8;
1636                                break;
1637                        case '^':
1638                                adrs -= size;
1639                                break;
1640                                break;
1641                        case '/':
1642                                if (nslash > 0)
1643                                        adrs -= 1 << nslash;
1644                                else
1645                                        nslash = 0;
1646                                nslash += 4;
1647                                adrs += 1 << nslash;
1648                                break;
1649                        case '\\':
1650                                if (nslash < 0)
1651                                        adrs += 1 << -nslash;
1652                                else
1653                                        nslash = 0;
1654                                nslash -= 4;
1655                                adrs -= 1 << -nslash;
1656                                break;
1657                        case 'm':
1658                                scanhex((void *)&adrs);
1659                                break;
1660                        case 'n':
1661                                mnoread = 1;
1662                                break;
1663                        case 'r':
1664                                brev = !brev;
1665                                break;
1666                        case '<':
1667                                n = size;
1668                                scanhex(&n);
1669                                adrs -= n;
1670                                break;
1671                        case '>':
1672                                n = size;
1673                                scanhex(&n);
1674                                adrs += n;
1675                                break;
1676                        case '?':
1677                                printf(memex_subcmd_help_string);
1678                                break;
1679                        }
1680                }
1681                adrs += inc;
1682        }
1683}
1684
1685int
1686bsesc()
1687{
1688        int c;
1689
1690        c = inchar();
1691        switch( c ){
1692        case 'n':       c = '\n';       break;
1693        case 'r':       c = '\r';       break;
1694        case 'b':       c = '\b';       break;
1695        case 't':       c = '\t';       break;
1696        }
1697        return c;
1698}
1699
1700#define isxdigit(c)     (('0' <= (c) && (c) <= '9') \
1701                         || ('a' <= (c) && (c) <= 'f') \
1702                         || ('A' <= (c) && (c) <= 'F'))
1703void
1704dump()
1705{
1706        int c;
1707
1708        c = inchar();
1709        if ((isxdigit(c) && c != 'f' && c != 'd') || c == '\n')
1710                termch = c;
1711        scanhex((void *)&adrs);
1712        if( termch != '\n')
1713                termch = 0;
1714        if( c == 'i' ){
1715                scanhex(&nidump);
1716                if( nidump == 0 )
1717                        nidump = 16;
1718                adrs += ppc_inst_dump(adrs, nidump);
1719                last_cmd = "di\n";
1720        } else {
1721                scanhex(&ndump);
1722                if( ndump == 0 )
1723                        ndump = 64;
1724                prdump(adrs, ndump);
1725                adrs += ndump;
1726                last_cmd = "d\n";
1727        }
1728}
1729
1730void
1731prdump(unsigned long adrs, long ndump)
1732{
1733        long n, m, c, r, nr;
1734        unsigned char temp[16];
1735
1736        for( n = ndump; n > 0; ){
1737                printf("%.16lx", adrs);
1738                putchar(' ');
1739                r = n < 16? n: 16;
1740                nr = mread(adrs, temp, r);
1741                adrs += nr;
1742                for( m = 0; m < r; ++m ){
1743                        if ((m & 7) == 0 && m > 0)
1744                            putchar(' ');
1745                        if( m < nr )
1746                                printf("%.2x", temp[m]);
1747                        else
1748                                printf("%s", fault_chars[fault_type]);
1749                }
1750                for(; m < 16; ++m )
1751                        printf("   ");
1752                printf("  |");
1753                for( m = 0; m < r; ++m ){
1754                        if( m < nr ){
1755                                c = temp[m];
1756                                putchar(' ' <= c && c <= '~'? c: '.');
1757                        } else
1758                                putchar(' ');
1759                }
1760                n -= r;
1761                for(; m < 16; ++m )
1762                        putchar(' ');
1763                printf("|\n");
1764                if( nr < r )
1765                        break;
1766        }
1767}
1768
1769int
1770ppc_inst_dump(unsigned long adr, long count)
1771{
1772        int nr, dotted;
1773        unsigned long first_adr;
1774        unsigned long inst, last_inst;
1775        unsigned char val[4];
1776
1777        dotted = 0;
1778        for (first_adr = adr; count > 0; --count, adr += 4){
1779                nr = mread(adr, val, 4);
1780                if( nr == 0 ){
1781                        const char *x = fault_chars[fault_type];
1782                        printf("%.16lx  %s%s%s%s\n", adr, x, x, x, x);
1783                        break;
1784                }
1785                inst = GETWORD(val);
1786                if (adr > first_adr && inst == last_inst) {
1787                        if (!dotted) {
1788                                printf(" ...\n");
1789                                dotted = 1;
1790                        }
1791                        continue;
1792                }
1793                dotted = 0;
1794                last_inst = inst;
1795                printf("%.16lx  ", adr);
1796                printf("%.8x\t", inst);
1797                print_insn_big_powerpc(stdout, inst, adr);      /* always returns 4 */
1798                printf("\n");
1799        }
1800        return adr - first_adr;
1801}
1802
1803void
1804print_address(unsigned long addr)
1805{
1806        printf("0x%lx", addr);
1807}
1808
1809/*
1810 * Memory operations - move, set, print differences
1811 */
1812static unsigned long mdest;             /* destination address */
1813static unsigned long msrc;              /* source address */
1814static unsigned long mval;              /* byte value to set memory to */
1815static unsigned long mcount;            /* # bytes to affect */
1816static unsigned long mdiffs;            /* max # differences to print */
1817
1818void
1819memops(int cmd)
1820{
1821        scanhex((void *)&mdest);
1822        if( termch != '\n' )
1823                termch = 0;
1824        scanhex((void *)(cmd == 's'? &mval: &msrc));
1825        if( termch != '\n' )
1826                termch = 0;
1827        scanhex((void *)&mcount);
1828        switch( cmd ){
1829        case 'm':
1830                memmove((void *)mdest, (void *)msrc, mcount);
1831                break;
1832        case 's':
1833                memset((void *)mdest, mval, mcount);
1834                break;
1835        case 'd':
1836                if( termch != '\n' )
1837                        termch = 0;
1838                scanhex((void *)&mdiffs);
1839                memdiffs((unsigned char *)mdest, (unsigned char *)msrc, mcount, mdiffs);
1840                break;
1841        }
1842}
1843
1844void
1845memdiffs(unsigned char *p1, unsigned char *p2, unsigned nb, unsigned maxpr)
1846{
1847        unsigned n, prt;
1848
1849        prt = 0;
1850        for( n = nb; n > 0; --n )
1851                if( *p1++ != *p2++ )
1852                        if( ++prt <= maxpr )
1853                                printf("%.16x %.2x # %.16x %.2x\n", p1 - 1,
1854                                        p1[-1], p2 - 1, p2[-1]);
1855        if( prt > maxpr )
1856                printf("Total of %d differences\n", prt);
1857}
1858
1859static unsigned mend;
1860static unsigned mask;
1861
1862void
1863memlocate()
1864{
1865        unsigned a, n;
1866        unsigned char val[4];
1867
1868        last_cmd = "ml";
1869        scanhex((void *)&mdest);
1870        if (termch != '\n') {
1871                termch = 0;
1872                scanhex((void *)&mend);
1873                if (termch != '\n') {
1874                        termch = 0;
1875                        scanhex((void *)&mval);
1876                        mask = ~0;
1877                        if (termch != '\n') termch = 0;
1878                        scanhex((void *)&mask);
1879                }
1880        }
1881        n = 0;
1882        for (a = mdest; a < mend; a += 4) {
1883                if (mread(a, val, 4) == 4
1884                        && ((GETWORD(val) ^ mval) & mask) == 0) {
1885                        printf("%.16x:  %.16x\n", a, GETWORD(val));
1886                        if (++n >= 10)
1887                                break;
1888                }
1889        }
1890}
1891
1892static unsigned long mskip = 0x1000;
1893static unsigned long mlim = 0xffffffff;
1894
1895void
1896memzcan()
1897{
1898        unsigned char v;
1899        unsigned a;
1900        int ok, ook;
1901
1902        scanhex(&mdest);
1903        if (termch != '\n') termch = 0;
1904        scanhex(&mskip);
1905        if (termch != '\n') termch = 0;
1906        scanhex(&mlim);
1907        ook = 0;
1908        for (a = mdest; a < mlim; a += mskip) {
1909                ok = mread(a, &v, 1);
1910                if (ok && !ook) {
1911                        printf("%.8x .. ", a);
1912                        fflush(stdout);
1913                } else if (!ok && ook)
1914                        printf("%.8x\n", a - mskip);
1915                ook = ok;
1916                if (a + mskip < a)
1917                        break;
1918        }
1919        if (ook)
1920                printf("%.8x\n", a - mskip);
1921}
1922
1923/* Input scanning routines */
1924int
1925skipbl()
1926{
1927        int c;
1928
1929        if( termch != 0 ){
1930                c = termch;
1931                termch = 0;
1932        } else
1933                c = inchar();
1934        while( c == ' ' || c == '\t' )
1935                c = inchar();
1936        return c;
1937}
1938
1939#define N_PTREGS        44
1940static char *regnames[N_PTREGS] = {
1941        "r0", "r1", "r2", "r3", "r4", "r5", "r6", "r7",
1942        "r8", "r9", "r10", "r11", "r12", "r13", "r14", "r15",
1943        "r16", "r17", "r18", "r19", "r20", "r21", "r22", "r23",
1944        "r24", "r25", "r26", "r27", "r28", "r29", "r30", "r31",
1945        "pc", "msr", "or3", "ctr", "lr", "xer", "ccr", "mq",
1946        "trap", "dar", "dsisr", "res"
1947};
1948
1949int
1950scanhex(vp)
1951unsigned long *vp;
1952{
1953        int c, d;
1954        unsigned long v;
1955
1956        c = skipbl();
1957        if (c == '%') {
1958                /* parse register name */
1959                char regname[8];
1960                int i;
1961
1962                for (i = 0; i < sizeof(regname) - 1; ++i) {
1963                        c = inchar();
1964                        if (!isalnum(c)) {
1965                                termch = c;
1966                                break;
1967                        }
1968                        regname[i] = c;
1969                }
1970                regname[i] = 0;
1971                for (i = 0; i < N_PTREGS; ++i) {
1972                        if (strcmp(regnames[i], regname) == 0) {
1973                                unsigned long *rp = (unsigned long *)
1974                                        xmon_regs[smp_processor_id()];
1975                                if (rp == NULL) {
1976                                        printf("regs not available\n");
1977                                        return 0;
1978                                }
1979                                *vp = rp[i];
1980                                return 1;
1981                        }
1982                }
1983                printf("invalid register name '%%%s'\n", regname);
1984                return 0;
1985        }
1986
1987        d = hexdigit(c);
1988        if( d == EOF ){
1989                termch = c;
1990                return 0;
1991        }
1992        v = 0;
1993        do {
1994                v = (v << 4) + d;
1995                c = inchar();
1996                d = hexdigit(c);
1997        } while( d != EOF );
1998        termch = c;
1999        *vp = v;
2000        return 1;
2001}
2002
2003void
2004scannl()
2005{
2006        int c;
2007
2008        c = termch;
2009        termch = 0;
2010        while( c != '\n' )
2011                c = inchar();
2012}
2013
2014int
2015hexdigit(int c)
2016{
2017        if( '0' <= c && c <= '9' )
2018                return c - '0';
2019        if( 'A' <= c && c <= 'F' )
2020                return c - ('A' - 10);
2021        if( 'a' <= c && c <= 'f' )
2022                return c - ('a' - 10);
2023        return EOF;
2024}
2025
2026void
2027getstring(char *s, int size)
2028{
2029        int c;
2030
2031        c = skipbl();
2032        do {
2033                if( size > 1 ){
2034                        *s++ = c;
2035                        --size;
2036                }
2037                c = inchar();
2038        } while( c != ' ' && c != '\t' && c != '\n' );
2039        termch = c;
2040        *s = 0;
2041}
2042
2043static char line[256];
2044static char *lineptr;
2045
2046void
2047flush_input()
2048{
2049        lineptr = NULL;
2050}
2051
2052int
2053inchar()
2054{
2055        if (lineptr == NULL || *lineptr == 0) {
2056                if (fgets(line, sizeof(line), stdin) == NULL) {
2057                        lineptr = NULL;
2058                        return EOF;
2059                }
2060                lineptr = line;
2061        }
2062        return *lineptr++;
2063}
2064
2065void
2066take_input(str)
2067char *str;
2068{
2069        lineptr = str;
2070}
2071
2072
2073/* Starting at codeaddr scan forward for a tbtable and fill in the
2074 given table.  Return non-zero if successful at doing something.
2075 */
2076static int
2077find_tb_table(unsigned long codeaddr, struct tbtable *tab)
2078{
2079        unsigned long codeaddr_max;
2080        unsigned long tbtab_start;
2081        int nr;
2082        int instr;
2083        int num_parms;
2084
2085        if (tab == NULL)
2086                return 0;
2087        memset(tab, 0, sizeof(tab));
2088
2089        /* Scan instructions starting at codeaddr for 128k max */
2090        for (codeaddr_max = codeaddr + 128*1024*4;
2091             codeaddr < codeaddr_max;
2092             codeaddr += 4) {
2093                nr = mread(codeaddr, &instr, 4);
2094                if (nr != 4)
2095                        return 0;       /* Bad read.  Give up promptly. */
2096                if (instr == 0) {
2097                        /* table should follow. */
2098                        int version;
2099                        unsigned long flags;
2100                        tbtab_start = codeaddr; /* save it to compute func start addr */
2101                        codeaddr += 4;
2102                        nr = mread(codeaddr, &flags, 8);
2103                        if (nr != 8)
2104                                return 0;       /* Bad read or no tb table. */
2105                        tab->flags = flags;
2106                        version = (flags >> 56) & 0xff;
2107                        if (version != 0)
2108                                continue;       /* No tb table here. */
2109                        /* Now, like the version, some of the flags are values
2110                         that are more conveniently extracted... */
2111                        tab->fp_saved = (flags >> 24) & 0x3f;
2112                        tab->gpr_saved = (flags >> 16) & 0x3f;
2113                        tab->fixedparms = (flags >> 8) & 0xff;
2114                        tab->floatparms = (flags >> 1) & 0x7f;
2115                        codeaddr += 8;
2116                        num_parms = tab->fixedparms + tab->floatparms;
2117                        if (num_parms) {
2118                                unsigned int parminfo;
2119                                int parm;
2120                                if (num_parms > 32)
2121                                        return 1;       /* incomplete */
2122                                nr = mread(codeaddr, &parminfo, 4);
2123                                if (nr != 4)
2124                                        return 1;       /* incomplete */
2125                                /* decode parminfo...32 bits.
2126                                 A zero means fixed.  A one means float and the
2127                                 following bit determines single (0) or double (1).
2128                                 */
2129                                for (parm = 0; parm < num_parms; parm++) {
2130                                        if (parminfo & 0x80000000) {
2131                                                parminfo <<= 1;
2132                                                if (parminfo & 0x80000000)
2133                                                        tab->parminfo[parm] = TBTAB_PARMDFLOAT;
2134                                                else
2135                                                        tab->parminfo[parm] = TBTAB_PARMSFLOAT;
2136                                        } else {
2137                                                tab->parminfo[parm] = TBTAB_PARMFIXED;
2138                                        }
2139                                        parminfo <<= 1;
2140                                }
2141                                codeaddr += 4;
2142                        }
2143                        if (flags & TBTAB_FLAGSHASTBOFF) {
2144                                nr = mread(codeaddr, &tab->tb_offset, 4);
2145                                if (nr != 4)
2146                                        return 1;       /* incomplete */
2147                                if (tab->tb_offset > 0) {
2148                                        tab->funcstart = tbtab_start - tab->tb_offset;
2149                                }
2150                                codeaddr += 4;
2151                        }
2152                        /* hand_mask appears to be always be omitted. */
2153                        if (flags & TBTAB_FLAGSHASCTL) {
2154                                /* Assume this will never happen for C or asm */
2155                                return 1;       /* incomplete */
2156                        }
2157                        if (flags & TBTAB_FLAGSNAMEPRESENT) {
2158                                short namlen;
2159                                nr = mread(codeaddr, &namlen, 2);
2160                                if (nr != 2)
2161                                        return 1;       /* incomplete */
2162                                if (namlen >= sizeof(tab->name))
2163                                        namlen = sizeof(tab->name)-1;
2164                                codeaddr += 2;
2165                                nr = mread(codeaddr, tab->name, namlen);
2166                                tab->name[namlen] = '\0';
2167                                codeaddr += namlen;
2168                        }
2169                        return 1;
2170                }
2171        }
2172        return 0;       /* hit max...sorry. */
2173}
2174
2175void
2176mem_translate()
2177{
2178        int c;
2179        unsigned long ea, va, vsid, vpn, page, hpteg_slot_primary, hpteg_slot_secondary, primary_hash, i, *steg, esid, stabl;
2180        HPTE *  hpte;
2181        struct mm_struct * mm;
2182        pte_t  *ptep = NULL;
2183        void * pgdir;
2184 
2185        c = inchar();
2186        if ((isxdigit(c) && c != 'f' && c != 'd') || c == '\n')
2187                termch = c;
2188        scanhex((void *)&ea);
2189  
2190        if ((ea >= KRANGE_START) && (ea <= (KRANGE_START + (1UL<<60)))) {
2191                ptep = 0;
2192                vsid = get_kernel_vsid(ea);
2193                va = ( vsid << 28 ) | ( ea & 0x0fffffff );
2194        } else {
2195                // if in vmalloc range, use the vmalloc page directory
2196                if ( ( ea >= VMALLOC_START ) && ( ea <= VMALLOC_END ) ) {
2197                        mm = &init_mm;
2198                        vsid = get_kernel_vsid( ea );
2199                }
2200                // if in ioremap range, use the ioremap page directory
2201                else if ( ( ea >= IMALLOC_START ) && ( ea <= IMALLOC_END ) ) {
2202                        mm = &ioremap_mm;
2203                        vsid = get_kernel_vsid( ea );
2204                }
2205                // if in user range, use the current task's page directory
2206                else if ( ( ea >= USER_START ) && ( ea <= USER_END ) ) {
2207                        mm = current->mm;
2208                        vsid = get_vsid(mm->context, ea );
2209                }
2210                pgdir = mm->pgd;
2211                va = ( vsid << 28 ) | ( ea & 0x0fffffff );
2212                ptep = find_linux_pte( pgdir, ea );
2213        }
2214
2215        vpn = ((vsid << 28) | (((ea) & 0xFFFF000))) >> 12;
2216        page = vpn & 0xffff;
2217        esid = (ea >> 28)  & 0xFFFFFFFFF;
2218
2219  // Search the primary group for an available slot
2220        primary_hash = ( vsid & 0x7fffffffff ) ^ page;
2221        hpteg_slot_primary = ( primary_hash & htab_data.htab_hash_mask ) * HPTES_PER_GROUP;
2222        hpteg_slot_secondary = ( ~primary_hash & htab_data.htab_hash_mask ) * HPTES_PER_GROUP;
2223
2224        printf("ea             : %.16lx\n", ea);
2225        printf("esid           : %.16lx\n", esid);
2226        printf("vsid           : %.16lx\n", vsid);
2227
2228        printf("\nSoftware Page Table\n-------------------\n");
2229        printf("ptep           : %.16lx\n", ((unsigned long *)ptep));
2230        if(ptep) {
2231                printf("*ptep          : %.16lx\n", *((unsigned long *)ptep));
2232        }
2233
2234        hpte  = htab_data.htab  + hpteg_slot_primary;
2235        printf("\nHardware Page Table\n-------------------\n");
2236        printf("htab base      : %.16lx\n", htab_data.htab);
2237        printf("slot primary   : %.16lx\n", hpteg_slot_primary);
2238        printf("slot secondary : %.16lx\n", hpteg_slot_secondary);
2239        printf("\nPrimary Group\n");
2240        for (i=0; i<8; ++i) {
2241                if ( hpte->dw0.dw0.v != 0 ) {
2242                        printf("%d: (hpte)%.16lx %.16lx\n", i, hpte->dw0.dword0, hpte->dw1.dword1);
2243                        printf("          vsid: %.13lx   api: %.2lx  hash: %.1lx\n", 
2244                               (hpte->dw0.dw0.avpn)>>5, 
2245                               (hpte->dw0.dw0.avpn) & 0x1f,
2246                               (hpte->dw0.dw0.h));
2247                        printf("          rpn: %.13lx \n", (hpte->dw1.dw1.rpn));
2248                        printf("           pp: %.1lx \n", 
2249                               ((hpte->dw1.dw1.pp0)<<2)|(hpte->dw1.dw1.pp));
2250                        printf("        wimgn: %.2lx  reference: %.1lx  change: %.1lx\n", 
2251                               ((hpte->dw1.dw1.w)<<4)|
2252                               ((hpte->dw1.dw1.i)<<3)|
2253                               ((hpte->dw1.dw1.m)<<2)|
2254                               ((hpte->dw1.dw1.g)<<1)|
2255                               ((hpte->dw1.dw1.n)<<0),
2256                               hpte->dw1.dw1.r, hpte->dw1.dw1.c);
2257                }
2258                hpte++;
2259        }
2260
2261        printf("\nSecondary Group\n");
2262        // Search the secondary group
2263        hpte  = htab_data.htab  + hpteg_slot_secondary;
2264        for (i=0; i<8; ++i) {
2265                if(hpte->dw0.dw0.v) {
2266                        printf("%d: (hpte)%.16lx %.16lx\n", i, hpte->dw0.dword0, hpte->dw1.dword1);
2267                        printf("          vsid: %.13lx   api: %.2lx  hash: %.1lx\n", 
2268                               (hpte->dw0.dw0.avpn)>>5, 
2269                               (hpte->dw0.dw0.avpn) & 0x1f,
2270                               (hpte->dw0.dw0.h));
2271                        printf("          rpn: %.13lx \n", (hpte->dw1.dw1.rpn));
2272                        printf("           pp: %.1lx \n", 
2273                               ((hpte->dw1.dw1.pp0)<<2)|(hpte->dw1.dw1.pp));
2274                        printf("        wimgn: %.2lx  reference: %.1lx  change: %.1lx\n", 
2275                               ((hpte->dw1.dw1.w)<<4)|
2276                               ((hpte->dw1.dw1.i)<<3)|
2277                               ((hpte->dw1.dw1.m)<<2)|
2278                               ((hpte->dw1.dw1.g)<<1)|
2279                               ((hpte->dw1.dw1.n)<<0),
2280                               hpte->dw1.dw1.r, hpte->dw1.dw1.c);
2281                }
2282                hpte++;
2283        }
2284
2285        printf("\nHardware Segment Table\n-----------------------\n");
2286        stabl = (unsigned long)(KERNELBASE+(_ASR&0xFFFFFFFFFFFFFFFE));
2287        steg = (unsigned long *)((stabl) | ((esid & 0x1f) << 7));
2288
2289        printf("stab base      : %.16lx\n", stabl);
2290        printf("slot           : %.16lx\n", steg);
2291
2292        for (i=0; i<8; ++i) {
2293                printf("%d: (ste) %.16lx %.16lx\n", i,
2294                       *((unsigned long *)(steg+i*2)),*((unsigned long *)(steg+i*2+1)) );
2295        }
2296}
2297
2298void mem_check()
2299{
2300        unsigned long htab_size_bytes;
2301        unsigned long htab_end;
2302        unsigned long last_rpn;
2303        HPTE *hpte1, *hpte2;
2304
2305        htab_size_bytes = htab_data.htab_num_ptegs * 128; // 128B / PTEG
2306        htab_end = (unsigned long)htab_data.htab + htab_size_bytes;
2307        // last_rpn = (naca->physicalMemorySize-1) >> PAGE_SHIFT;
2308        last_rpn = 0xfffff;
2309
2310        printf("\nHardware Page Table Check\n-------------------\n");
2311        printf("htab base      : %.16lx\n", htab_data.htab);
2312        printf("htab size      : %.16lx\n", htab_size_bytes);
2313
2314#if 1
2315        for(hpte1 = htab_data.htab; hpte1 < (HPTE *)htab_end; hpte1++) {
2316                if ( hpte1->dw0.dw0.v != 0 ) {
2317                        if ( hpte1->dw1.dw1.rpn <= last_rpn ) {
2318                                for(hpte2 = hpte1+1; hpte2 < (HPTE *)htab_end; hpte2++) {
2319                                        if ( hpte2->dw0.dw0.v != 0 ) {
2320                                                if(hpte1->dw1.dw1.rpn == hpte2->dw1.dw1.rpn) {
2321                                                        printf(" Duplicate rpn: %.13lx \n", (hpte1->dw1.dw1.rpn));
2322                                                        printf("   hpte1: %16.16lx  *hpte1: %16.16lx %16.16lx\n",
2323                                                               hpte1, hpte1->dw0.dword0, hpte1->dw1.dword1);
2324                                                        printf("   hpte2: %16.16lx  *hpte2: %16.16lx %16.16lx\n",
2325                                                               hpte2, hpte2->dw0.dword0, hpte2->dw1.dword1);
2326                                                }
2327                                        }
2328                                }
2329                        } else {
2330                                printf(" Bogus rpn: %.13lx \n", (hpte1->dw1.dw1.rpn));
2331                                printf("   hpte: %16.16lx  *hpte: %16.16lx %16.16lx\n",
2332                                       hpte1, hpte1->dw0.dword0, hpte1->dw1.dword1);
2333                        }
2334                }
2335        }
2336#endif
2337        printf("\nDone -------------------\n");
2338}
2339
2340void mem_find_real()
2341{
2342        unsigned long htab_size_bytes;
2343        unsigned long htab_end;
2344        unsigned long last_rpn;
2345        HPTE *hpte1;
2346        unsigned long pa, rpn;
2347        int c;
2348
2349        c = inchar();
2350        if ((isxdigit(c) && c != 'f' && c != 'd') || c == '\n')
2351                termch = c;
2352        scanhex((void *)&pa);
2353        rpn = pa >> 12;
2354  
2355        htab_size_bytes = htab_data.htab_num_ptegs * 128; // 128B / PTEG
2356        htab_end = (unsigned long)htab_data.htab + htab_size_bytes;
2357        // last_rpn = (naca->physicalMemorySize-1) >> PAGE_SHIFT;
2358        last_rpn = 0xfffff;
2359
2360        printf("\nMem Find RPN\n-------------------\n");
2361        printf("htab base      : %.16lx\n", htab_data.htab);
2362        printf("htab size      : %.16lx\n", htab_size_bytes);
2363
2364        for(hpte1 = htab_data.htab; hpte1 < (HPTE *)htab_end; hpte1++) {
2365                if ( hpte1->dw0.dw0.v != 0 ) {
2366                        if ( hpte1->dw1.dw1.rpn == rpn ) {
2367                                printf(" Found rpn: %.13lx \n", (hpte1->dw1.dw1.rpn));
2368                                printf("      hpte: %16.16lx  *hpte1: %16.16lx %16.16lx\n",
2369                                       hpte1, hpte1->dw0.dword0, hpte1->dw1.dword1);
2370                        }
2371                }
2372        }
2373        printf("\nDone -------------------\n");
2374}
2375
2376void mem_find_vsid()
2377{
2378        unsigned long htab_size_bytes;
2379        unsigned long htab_end;
2380        HPTE *hpte1;
2381        unsigned long vsid;
2382        int c;
2383
2384        c = inchar();
2385        if ((isxdigit(c) && c != 'f' && c != 'd') || c == '\n')
2386                termch = c;
2387        scanhex((void *)&vsid);
2388  
2389        htab_size_bytes = htab_data.htab_num_ptegs * 128; // 128B / PTEG
2390        htab_end = (unsigned long)htab_data.htab + htab_size_bytes;
2391
2392        printf("\nMem Find VSID\n-------------------\n");
2393        printf("htab base      : %.16lx\n", htab_data.htab);
2394        printf("htab size      : %.16lx\n", htab_size_bytes);
2395
2396        for(hpte1 = htab_data.htab; hpte1 < (HPTE *)htab_end; hpte1++) {
2397                if ( hpte1->dw0.dw0.v != 0 ) {
2398                        if ( ((hpte1->dw0.dw0.avpn)>>5) == vsid ) {
2399                                printf(" Found vsid: %.16lx \n", ((hpte1->dw0.dw0.avpn) >> 5));
2400                                printf("       hpte: %16.16lx  *hpte1: %16.16lx %16.16lx\n",
2401                                       hpte1, hpte1->dw0.dword0, hpte1->dw1.dword1);
2402                        }
2403                }
2404        }
2405        printf("\nDone -------------------\n");
2406}
2407
2408static void debug_trace(void) {
2409        unsigned long val, cmd, on;
2410
2411        cmd = skipbl();
2412        if (cmd == '\n') {
2413                /* show current state */
2414                unsigned long i;
2415                printf("naca->debug_switch = 0x%lx\n", naca->debug_switch);
2416                for (i = 0; i < PPCDBG_NUM_FLAGS ;i++) {
2417                        on = PPCDBG_BITVAL(i) & naca->debug_switch;
2418                        printf("%02x %s %12s   ", i, on ? "on " : "off",  trace_names[i] ? trace_names[i] : "");
2419                        if (((i+1) % 3) == 0)
2420                                printf("\n");
2421                }
2422                printf("\n");
2423                return;
2424        }
2425        while (cmd != '\n') {
2426                on = 1; /* default if no sign given */
2427                while (cmd == '+' || cmd == '-') {
2428                        on = (cmd == '+');
2429                        cmd = inchar();
2430                        if (cmd == ' ' || cmd == '\n') {  /* Turn on or off based on + or - */
2431                                naca->debug_switch = on ? PPCDBG_ALL:PPCDBG_NONE;
2432                                printf("Setting all values to %s...\n", on ? "on" : "off");
2433                                if (cmd == '\n') return;
2434                                else cmd = skipbl(); 
2435                        }
2436                        else
2437                                termch = cmd;
2438                }
2439                termch = cmd;   /* not +/- ... let scanhex see it */
2440                scanhex((void *)&val);
2441                if (val >= 64) {
2442                        printf("Value %x out of range:\n", val);
2443                        return;
2444                }
2445                if (on) {
2446                        naca->debug_switch |= PPCDBG_BITVAL(val);
2447                        printf("enable debug %x %s\n", val, trace_names[val] ? trace_names[val] : "");
2448                } else {
2449                        naca->debug_switch &= ~PPCDBG_BITVAL(val);
2450                        printf("disable debug %x %s\n", val, trace_names[val] ? trace_names[val] : "");
2451                }
2452                cmd = skipbl();
2453        }
2454}
2455
lxr.linux.no kindly hosted by Redpill Linpro AS, provider of Linux consulting and operations services since 1995.