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