uboot/arch/powerpc/lib/kgdb.c
<<
>>
Prefs
   1#include <common.h>
   2#include <command.h>
   3#include <kgdb.h>
   4#include <asm/ptrace.h>
   5#include <asm/signal.h>
   6#include <asm/processor.h>
   7
   8#define PC_REGNUM 64
   9#define SP_REGNUM 1
  10
  11void breakinst(void);
  12
  13int
  14kgdb_setjmp(long *buf)
  15{
  16        unsigned long temp;
  17
  18        asm volatile("mflr %0; stw %0,0(%1);"
  19             "stw %%r1,4(%1); stw %%r2,8(%1);"
  20             "mfcr %0; stw %0,12(%1);"
  21             "stmw %%r13,16(%1)"
  22             : "=&r"(temp) : "r" (buf));
  23        /* XXX should save fp regs as well */
  24        return 0;
  25}
  26
  27void
  28kgdb_longjmp(long *buf, int val)
  29{
  30        unsigned long temp;
  31
  32        if (val == 0)
  33                val = 1;
  34
  35        asm volatile("lmw %%r13,16(%1);"
  36             "lwz %0,12(%1); mtcrf 0x38,%0;"
  37             "lwz %0,0(%1); lwz %%r1,4(%1); lwz %%r2,8(%1);"
  38             "mtlr %0; mr %%r3,%2"
  39             : "=&r"(temp) : "r" (buf), "r" (val));
  40}
  41
  42/* Convert the SPARC hardware trap type code to a unix signal number. */
  43/*
  44 * This table contains the mapping between PowerPC hardware trap types, and
  45 * signals, which are primarily what GDB understands.
  46 */
  47static struct hard_trap_info
  48{
  49        unsigned int tt;                /* Trap type code for powerpc */
  50        unsigned char signo;            /* Signal that we map this trap into */
  51} hard_trap_info[] = {
  52        { 0x200, SIGSEGV },                     /* machine check */
  53        { 0x300, SIGSEGV },                     /* address error (store) */
  54        { 0x400, SIGBUS },                      /* instruction bus error */
  55        { 0x500, SIGINT },                      /* interrupt */
  56        { 0x600, SIGBUS },                      /* alignment */
  57        { 0x700, SIGTRAP },                     /* breakpoint trap */
  58        { 0x800, SIGFPE },                      /* fpu unavail */
  59        { 0x900, SIGALRM },                     /* decrementer */
  60        { 0xa00, SIGILL },                      /* reserved */
  61        { 0xb00, SIGILL },                      /* reserved */
  62        { 0xc00, SIGCHLD },                     /* syscall */
  63        { 0xd00, SIGTRAP },                     /* single-step/watch */
  64        { 0xe00, SIGFPE },                      /* fp assist */
  65        { 0, 0}                         /* Must be last */
  66};
  67
  68static int
  69computeSignal(unsigned int tt)
  70{
  71        struct hard_trap_info *ht;
  72
  73        for (ht = hard_trap_info; ht->tt && ht->signo; ht++)
  74                if (ht->tt == tt)
  75                        return ht->signo;
  76
  77        return SIGHUP;         /* default for things we don't know about */
  78}
  79
  80void
  81kgdb_enter(struct pt_regs *regs, kgdb_data *kdp)
  82{
  83        unsigned long msr;
  84
  85        kdp->private[0] = msr = get_msr();
  86        set_msr(msr & ~MSR_EE); /* disable interrupts */
  87
  88        if (regs->nip == (unsigned long)breakinst) {
  89                /* Skip over breakpoint trap insn */
  90                regs->nip += 4;
  91        }
  92        regs->msr &= ~MSR_SE;
  93
  94        /* reply to host that an exception has occurred */
  95        kdp->sigval = computeSignal(regs->trap);
  96
  97        kdp->nregs = 2;
  98
  99        kdp->regs[0].num = PC_REGNUM;
 100        kdp->regs[0].val = regs->nip;
 101
 102        kdp->regs[1].num = SP_REGNUM;
 103        kdp->regs[1].val = regs->gpr[SP_REGNUM];
 104}
 105
 106void
 107kgdb_exit(struct pt_regs *regs, kgdb_data *kdp)
 108{
 109        unsigned long msr = kdp->private[0];
 110
 111        if (kdp->extype & KGDBEXIT_WITHADDR)
 112                regs->nip = kdp->exaddr;
 113
 114        switch (kdp->extype & KGDBEXIT_TYPEMASK) {
 115
 116        case KGDBEXIT_KILL:
 117        case KGDBEXIT_CONTINUE:
 118                set_msr(msr);
 119                break;
 120
 121        case KGDBEXIT_SINGLE:
 122                regs->msr |= MSR_SE;
 123#if 0
 124                set_msr(msr | MSR_SE);
 125#endif
 126                break;
 127        }
 128}
 129
 130int
 131kgdb_trap(struct pt_regs *regs)
 132{
 133        return (regs->trap);
 134}
 135
 136/* return the value of the CPU registers.
 137 * some of them are non-PowerPC names :(
 138 * they are stored in gdb like:
 139 * struct {
 140 *     u32 gpr[32];
 141 *     f64 fpr[32];
 142 *     u32 pc, ps, cnd, lr; (ps=msr)
 143 *     u32 cnt, xer, mq;
 144 * }
 145 */
 146
 147#define SPACE_REQUIRED  ((32*4)+(32*8)+(6*4))
 148
 149int
 150kgdb_getregs(struct pt_regs *regs, char *buf, int max)
 151{
 152        int i;
 153        unsigned long *ptr = (unsigned long *)buf;
 154
 155        if (max < SPACE_REQUIRED)
 156                kgdb_error(KGDBERR_NOSPACE);
 157
 158        if ((unsigned long)ptr & 3)
 159                kgdb_error(KGDBERR_ALIGNFAULT);
 160
 161        /* General Purpose Regs */
 162        for (i = 0; i < 32; i++)
 163                *ptr++ = regs->gpr[i];
 164
 165        /* Floating Point Regs */
 166        for (i = 0; i < 32; i++) {
 167                *ptr++ = 0;
 168                *ptr++ = 0;
 169        }
 170
 171        /* pc, msr, cr, lr, ctr, xer, (mq is unused) */
 172        *ptr++ = regs->nip;
 173        *ptr++ = regs->msr;
 174        *ptr++ = regs->ccr;
 175        *ptr++ = regs->link;
 176        *ptr++ = regs->ctr;
 177        *ptr++ = regs->xer;
 178
 179        return (SPACE_REQUIRED);
 180}
 181
 182/* set the value of the CPU registers */
 183void
 184kgdb_putreg(struct pt_regs *regs, int regno, char *buf, int length)
 185{
 186        unsigned long *ptr = (unsigned long *)buf;
 187
 188        if (regno < 0 || regno >= 70)
 189                kgdb_error(KGDBERR_BADPARAMS);
 190        else if (regno >= 32 && regno < 64) {
 191                if (length < 8)
 192                        kgdb_error(KGDBERR_NOSPACE);
 193        }
 194        else {
 195                if (length < 4)
 196                        kgdb_error(KGDBERR_NOSPACE);
 197        }
 198
 199        if ((unsigned long)ptr & 3)
 200                kgdb_error(KGDBERR_ALIGNFAULT);
 201
 202        if (regno >= 0 && regno < 32)
 203                regs->gpr[regno] = *ptr;
 204        else switch (regno) {
 205        case 64:        regs->nip = *ptr;       break;
 206        case 65:        regs->msr = *ptr;       break;
 207        case 66:        regs->ccr = *ptr;       break;
 208        case 67:        regs->link = *ptr;      break;
 209        case 68:        regs->ctr = *ptr;       break;
 210        case 69:        regs->ctr = *ptr;       break;
 211
 212        default:
 213                kgdb_error(KGDBERR_BADPARAMS);
 214        }
 215}
 216
 217void
 218kgdb_putregs(struct pt_regs *regs, char *buf, int length)
 219{
 220        int i;
 221        unsigned long *ptr = (unsigned long *)buf;
 222
 223        if (length < SPACE_REQUIRED)
 224                kgdb_error(KGDBERR_NOSPACE);
 225
 226        if ((unsigned long)ptr & 3)
 227                kgdb_error(KGDBERR_ALIGNFAULT);
 228
 229        /*
 230         * If the stack pointer has moved, you should pray.
 231         * (cause only god can help you).
 232         */
 233
 234        /* General Purpose Regs */
 235        for (i = 0; i < 32; i++)
 236                regs->gpr[i] = *ptr++;
 237
 238        /* Floating Point Regs */
 239        ptr += 32*2;
 240
 241        /* pc, msr, cr, lr, ctr, xer, (mq is unused) */
 242        regs->nip = *ptr++;
 243        regs->msr = *ptr++;
 244        regs->ccr = *ptr++;
 245        regs->link = *ptr++;
 246        regs->ctr = *ptr++;
 247        regs->xer = *ptr++;
 248}
 249
 250/* This function will generate a breakpoint exception.  It is used at the
 251   beginning of a program to sync up with a debugger and can be used
 252   otherwise as a quick means to stop program execution and "break" into
 253   the debugger. */
 254
 255void
 256kgdb_breakpoint(int argc, char *const argv[])
 257{
 258        asm("   .globl breakinst\n\
 259             breakinst: .long 0x7d821008\n\
 260            ");
 261}
 262