kgdb,mips: Individual register get/set for mips
authorJason Wessel <jason.wessel@windriver.com>
Thu, 5 Aug 2010 14:22:21 +0000 (09:22 -0500)
committerJason Wessel <jason.wessel@windriver.com>
Thu, 5 Aug 2010 14:22:21 +0000 (09:22 -0500)
Implement the ability to individually get and set registers for kdb
and kgdb for mips.

Signed-off-by: Jason Wessel <jason.wessel@windriver.com>
Acked-by: Ralf Baechle <ralf@linux-mips.org>
CC: linux-mips@linux-mips.org
arch/mips/include/asm/kgdb.h
arch/mips/kernel/kgdb.c

index 19002d605ac45912603b4a94464d8c6cb5583a30..e6c0b0e14ccb989a3f8e0e72a1060222e68941e7 100644 (file)
@@ -8,28 +8,27 @@
 #if (_MIPS_ISA == _MIPS_ISA_MIPS1) || (_MIPS_ISA == _MIPS_ISA_MIPS2) || \
        (_MIPS_ISA == _MIPS_ISA_MIPS32)
 
-#define KGDB_GDB_REG_SIZE 32
+#define KGDB_GDB_REG_SIZE      32
+#define GDB_SIZEOF_REG         sizeof(u32)
 
 #elif (_MIPS_ISA == _MIPS_ISA_MIPS3) || (_MIPS_ISA == _MIPS_ISA_MIPS4) || \
        (_MIPS_ISA == _MIPS_ISA_MIPS64)
 
 #ifdef CONFIG_32BIT
-#define KGDB_GDB_REG_SIZE 32
+#define KGDB_GDB_REG_SIZE      32
+#define GDB_SIZEOF_REG         sizeof(u32)
 #else /* CONFIG_CPU_32BIT */
-#define KGDB_GDB_REG_SIZE 64
+#define KGDB_GDB_REG_SIZE      64
+#define GDB_SIZEOF_REG         sizeof(u64)
 #endif
 #else
 #error "Need to set KGDB_GDB_REG_SIZE for MIPS ISA"
 #endif /* _MIPS_ISA */
 
 #define BUFMAX                 2048
-#if (KGDB_GDB_REG_SIZE == 32)
-#define NUMREGBYTES            (90*sizeof(u32))
-#define NUMCRITREGBYTES                (12*sizeof(u32))
-#else
-#define NUMREGBYTES            (90*sizeof(u64))
-#define NUMCRITREGBYTES                (12*sizeof(u64))
-#endif
+#define DBG_MAX_REG_NUM                72
+#define NUMREGBYTES            (DBG_MAX_REG_NUM * sizeof(GDB_SIZEOF_REG))
+#define NUMCRITREGBYTES                (12 * sizeof(GDB_SIZEOF_REG))
 #define BREAK_INSTR_SIZE       4
 #define CACHE_FLUSH_IS_SAFE    0
 
index 9b78ff6e9b846fadcb135413b1f1ba7aa3c04fe4..5e76c2daa7f4d3b258e558c40aed0fd0182334c7 100644 (file)
@@ -50,6 +50,151 @@ static struct hard_trap_info {
        { 0, 0}                 /* Must be last */
 };
 
+struct dbg_reg_def_t dbg_reg_def[DBG_MAX_REG_NUM] =
+{
+       { "zero", GDB_SIZEOF_REG, offsetof(struct pt_regs, regs[0]) },
+       { "at", GDB_SIZEOF_REG, offsetof(struct pt_regs, regs[1]) },
+       { "v0", GDB_SIZEOF_REG, offsetof(struct pt_regs, regs[2]) },
+       { "v1", GDB_SIZEOF_REG, offsetof(struct pt_regs, regs[3]) },
+       { "a0", GDB_SIZEOF_REG, offsetof(struct pt_regs, regs[4]) },
+       { "a1", GDB_SIZEOF_REG, offsetof(struct pt_regs, regs[5]) },
+       { "a2", GDB_SIZEOF_REG, offsetof(struct pt_regs, regs[6]) },
+       { "a3", GDB_SIZEOF_REG, offsetof(struct pt_regs, regs[7]) },
+       { "t0", GDB_SIZEOF_REG, offsetof(struct pt_regs, regs[8]) },
+       { "t1", GDB_SIZEOF_REG, offsetof(struct pt_regs, regs[9]) },
+       { "t2", GDB_SIZEOF_REG, offsetof(struct pt_regs, regs[10]) },
+       { "t3", GDB_SIZEOF_REG, offsetof(struct pt_regs, regs[11]) },
+       { "t4", GDB_SIZEOF_REG, offsetof(struct pt_regs, regs[12]) },
+       { "t5", GDB_SIZEOF_REG, offsetof(struct pt_regs, regs[13]) },
+       { "t6", GDB_SIZEOF_REG, offsetof(struct pt_regs, regs[14]) },
+       { "t7", GDB_SIZEOF_REG, offsetof(struct pt_regs, regs[15]) },
+       { "s0", GDB_SIZEOF_REG, offsetof(struct pt_regs, regs[16]) },
+       { "s1", GDB_SIZEOF_REG, offsetof(struct pt_regs, regs[17]) },
+       { "s2", GDB_SIZEOF_REG, offsetof(struct pt_regs, regs[18]) },
+       { "s3", GDB_SIZEOF_REG, offsetof(struct pt_regs, regs[19]) },
+       { "s4", GDB_SIZEOF_REG, offsetof(struct pt_regs, regs[20]) },
+       { "s5", GDB_SIZEOF_REG, offsetof(struct pt_regs, regs[21]) },
+       { "s6", GDB_SIZEOF_REG, offsetof(struct pt_regs, regs[22]) },
+       { "s7", GDB_SIZEOF_REG, offsetof(struct pt_regs, regs[23]) },
+       { "t8", GDB_SIZEOF_REG, offsetof(struct pt_regs, regs[24]) },
+       { "t9", GDB_SIZEOF_REG, offsetof(struct pt_regs, regs[25]) },
+       { "k0", GDB_SIZEOF_REG, offsetof(struct pt_regs, regs[26]) },
+       { "k1", GDB_SIZEOF_REG, offsetof(struct pt_regs, regs[27]) },
+       { "gp", GDB_SIZEOF_REG, offsetof(struct pt_regs, regs[28]) },
+       { "sp", GDB_SIZEOF_REG, offsetof(struct pt_regs, regs[29]) },
+       { "s8", GDB_SIZEOF_REG, offsetof(struct pt_regs, regs[30]) },
+       { "ra", GDB_SIZEOF_REG, offsetof(struct pt_regs, regs[31]) },
+       { "sr", GDB_SIZEOF_REG, offsetof(struct pt_regs, cp0_status) },
+       { "lo", GDB_SIZEOF_REG, offsetof(struct pt_regs, lo) },
+       { "hi", GDB_SIZEOF_REG, offsetof(struct pt_regs, hi) },
+       { "bad", GDB_SIZEOF_REG, offsetof(struct pt_regs, cp0_badvaddr) },
+       { "cause", GDB_SIZEOF_REG, offsetof(struct pt_regs, cp0_cause) },
+       { "pc", GDB_SIZEOF_REG, offsetof(struct pt_regs, cp0_epc) },
+       { "f0", GDB_SIZEOF_REG, 0 },
+       { "f1", GDB_SIZEOF_REG, 1 },
+       { "f2", GDB_SIZEOF_REG, 2 },
+       { "f3", GDB_SIZEOF_REG, 3 },
+       { "f4", GDB_SIZEOF_REG, 4 },
+       { "f5", GDB_SIZEOF_REG, 5 },
+       { "f6", GDB_SIZEOF_REG, 6 },
+       { "f7", GDB_SIZEOF_REG, 7 },
+       { "f8", GDB_SIZEOF_REG, 8 },
+       { "f9", GDB_SIZEOF_REG, 9 },
+       { "f10", GDB_SIZEOF_REG, 10 },
+       { "f11", GDB_SIZEOF_REG, 11 },
+       { "f12", GDB_SIZEOF_REG, 12 },
+       { "f13", GDB_SIZEOF_REG, 13 },
+       { "f14", GDB_SIZEOF_REG, 14 },
+       { "f15", GDB_SIZEOF_REG, 15 },
+       { "f16", GDB_SIZEOF_REG, 16 },
+       { "f17", GDB_SIZEOF_REG, 17 },
+       { "f18", GDB_SIZEOF_REG, 18 },
+       { "f19", GDB_SIZEOF_REG, 19 },
+       { "f20", GDB_SIZEOF_REG, 20 },
+       { "f21", GDB_SIZEOF_REG, 21 },
+       { "f22", GDB_SIZEOF_REG, 22 },
+       { "f23", GDB_SIZEOF_REG, 23 },
+       { "f24", GDB_SIZEOF_REG, 24 },
+       { "f25", GDB_SIZEOF_REG, 25 },
+       { "f26", GDB_SIZEOF_REG, 26 },
+       { "f27", GDB_SIZEOF_REG, 27 },
+       { "f28", GDB_SIZEOF_REG, 28 },
+       { "f29", GDB_SIZEOF_REG, 29 },
+       { "f30", GDB_SIZEOF_REG, 30 },
+       { "f31", GDB_SIZEOF_REG, 31 },
+       { "fsr", GDB_SIZEOF_REG, 0 },
+       { "fir", GDB_SIZEOF_REG, 0 },
+};
+
+int dbg_set_reg(int regno, void *mem, struct pt_regs *regs)
+{
+       int fp_reg;
+
+       if (regno < 0 || regno >= DBG_MAX_REG_NUM)
+               return -EINVAL;
+
+       if (dbg_reg_def[regno].offset != -1 && regno < 38) {
+               memcpy((void *)regs + dbg_reg_def[regno].offset, mem,
+                      dbg_reg_def[regno].size);
+       } else if (current && dbg_reg_def[regno].offset != -1 && regno < 72) {
+               /* FP registers 38 -> 69 */
+               if (!(regs->cp0_status & ST0_CU1))
+                       return 0;
+               if (regno == 70) {
+                       /* Process the fcr31/fsr (register 70) */
+                       memcpy((void *)&current->thread.fpu.fcr31, mem,
+                              dbg_reg_def[regno].size);
+                       goto out_save;
+               } else if (regno == 71) {
+                       /* Ignore the fir (register 71) */
+                       goto out_save;
+               }
+               fp_reg = dbg_reg_def[regno].offset;
+               memcpy((void *)&current->thread.fpu.fpr[fp_reg], mem,
+                      dbg_reg_def[regno].size);
+out_save:
+               restore_fp(current);
+       }
+
+       return 0;
+}
+
+char *dbg_get_reg(int regno, void *mem, struct pt_regs *regs)
+{
+       int fp_reg;
+
+       if (regno >= DBG_MAX_REG_NUM || regno < 0)
+               return NULL;
+
+       if (dbg_reg_def[regno].offset != -1 && regno < 38) {
+               /* First 38 registers */
+               memcpy(mem, (void *)regs + dbg_reg_def[regno].offset,
+                      dbg_reg_def[regno].size);
+       } else if (current && dbg_reg_def[regno].offset != -1 && regno < 72) {
+               /* FP registers 38 -> 69 */
+               if (!(regs->cp0_status & ST0_CU1))
+                       goto out;
+               save_fp(current);
+               if (regno == 70) {
+                       /* Process the fcr31/fsr (register 70) */
+                       memcpy(mem, (void *)&current->thread.fpu.fcr31,
+                              dbg_reg_def[regno].size);
+                       goto out;
+               } else if (regno == 71) {
+                       /* Ignore the fir (register 71) */
+                       memset(mem, 0, dbg_reg_def[regno].size);
+                       goto out;
+               }
+               fp_reg = dbg_reg_def[regno].offset;
+               memcpy(mem, (void *)&current->thread.fpu.fpr[fp_reg],
+                      dbg_reg_def[regno].size);
+       }
+
+out:
+       return dbg_reg_def[regno].name;
+
+}
+
 void arch_kgdb_breakpoint(void)
 {
        __asm__ __volatile__(
@@ -84,64 +229,6 @@ static int compute_signal(int tt)
        return SIGHUP;          /* default for things we don't know about */
 }
 
-void pt_regs_to_gdb_regs(unsigned long *gdb_regs, struct pt_regs *regs)
-{
-       int reg;
-
-#if (KGDB_GDB_REG_SIZE == 32)
-       u32 *ptr = (u32 *)gdb_regs;
-#else
-       u64 *ptr = (u64 *)gdb_regs;
-#endif
-
-       for (reg = 0; reg < 32; reg++)
-               *(ptr++) = regs->regs[reg];
-
-       *(ptr++) = regs->cp0_status;
-       *(ptr++) = regs->lo;
-       *(ptr++) = regs->hi;
-       *(ptr++) = regs->cp0_badvaddr;
-       *(ptr++) = regs->cp0_cause;
-       *(ptr++) = regs->cp0_epc;
-
-       /* FP REGS */
-       if (!(current && (regs->cp0_status & ST0_CU1)))
-               return;
-
-       save_fp(current);
-       for (reg = 0; reg < 32; reg++)
-               *(ptr++) = current->thread.fpu.fpr[reg];
-}
-
-void gdb_regs_to_pt_regs(unsigned long *gdb_regs, struct pt_regs *regs)
-{
-       int reg;
-
-#if (KGDB_GDB_REG_SIZE == 32)
-       const u32 *ptr = (u32 *)gdb_regs;
-#else
-       const u64 *ptr = (u64 *)gdb_regs;
-#endif
-
-       for (reg = 0; reg < 32; reg++)
-               regs->regs[reg] = *(ptr++);
-
-       regs->cp0_status = *(ptr++);
-       regs->lo = *(ptr++);
-       regs->hi = *(ptr++);
-       regs->cp0_badvaddr = *(ptr++);
-       regs->cp0_cause = *(ptr++);
-       regs->cp0_epc = *(ptr++);
-
-       /* FP REGS from current */
-       if (!(current && (regs->cp0_status & ST0_CU1)))
-               return;
-
-       for (reg = 0; reg < 32; reg++)
-               current->thread.fpu.fpr[reg] = *(ptr++);
-       restore_fp(current);
-}
-
 /*
  * Similar to regs_to_gdb_regs() except that process is sleeping and so
  * we may not be able to get all the info.