diff options
| -rw-r--r-- | arch/mips/include/asm/kgdb.h | 19 | ||||
| -rw-r--r-- | arch/mips/kernel/kgdb.c | 203 |
2 files changed, 154 insertions, 68 deletions
diff --git a/arch/mips/include/asm/kgdb.h b/arch/mips/include/asm/kgdb.h index 19002d605ac4..e6c0b0e14ccb 100644 --- a/arch/mips/include/asm/kgdb.h +++ b/arch/mips/include/asm/kgdb.h | |||
| @@ -8,28 +8,27 @@ | |||
| 8 | #if (_MIPS_ISA == _MIPS_ISA_MIPS1) || (_MIPS_ISA == _MIPS_ISA_MIPS2) || \ | 8 | #if (_MIPS_ISA == _MIPS_ISA_MIPS1) || (_MIPS_ISA == _MIPS_ISA_MIPS2) || \ |
| 9 | (_MIPS_ISA == _MIPS_ISA_MIPS32) | 9 | (_MIPS_ISA == _MIPS_ISA_MIPS32) |
| 10 | 10 | ||
| 11 | #define KGDB_GDB_REG_SIZE 32 | 11 | #define KGDB_GDB_REG_SIZE 32 |
| 12 | #define GDB_SIZEOF_REG sizeof(u32) | ||
| 12 | 13 | ||
| 13 | #elif (_MIPS_ISA == _MIPS_ISA_MIPS3) || (_MIPS_ISA == _MIPS_ISA_MIPS4) || \ | 14 | #elif (_MIPS_ISA == _MIPS_ISA_MIPS3) || (_MIPS_ISA == _MIPS_ISA_MIPS4) || \ |
| 14 | (_MIPS_ISA == _MIPS_ISA_MIPS64) | 15 | (_MIPS_ISA == _MIPS_ISA_MIPS64) |
| 15 | 16 | ||
| 16 | #ifdef CONFIG_32BIT | 17 | #ifdef CONFIG_32BIT |
| 17 | #define KGDB_GDB_REG_SIZE 32 | 18 | #define KGDB_GDB_REG_SIZE 32 |
| 19 | #define GDB_SIZEOF_REG sizeof(u32) | ||
| 18 | #else /* CONFIG_CPU_32BIT */ | 20 | #else /* CONFIG_CPU_32BIT */ |
| 19 | #define KGDB_GDB_REG_SIZE 64 | 21 | #define KGDB_GDB_REG_SIZE 64 |
| 22 | #define GDB_SIZEOF_REG sizeof(u64) | ||
| 20 | #endif | 23 | #endif |
| 21 | #else | 24 | #else |
| 22 | #error "Need to set KGDB_GDB_REG_SIZE for MIPS ISA" | 25 | #error "Need to set KGDB_GDB_REG_SIZE for MIPS ISA" |
| 23 | #endif /* _MIPS_ISA */ | 26 | #endif /* _MIPS_ISA */ |
| 24 | 27 | ||
| 25 | #define BUFMAX 2048 | 28 | #define BUFMAX 2048 |
| 26 | #if (KGDB_GDB_REG_SIZE == 32) | 29 | #define DBG_MAX_REG_NUM 72 |
| 27 | #define NUMREGBYTES (90*sizeof(u32)) | 30 | #define NUMREGBYTES (DBG_MAX_REG_NUM * sizeof(GDB_SIZEOF_REG)) |
| 28 | #define NUMCRITREGBYTES (12*sizeof(u32)) | 31 | #define NUMCRITREGBYTES (12 * sizeof(GDB_SIZEOF_REG)) |
| 29 | #else | ||
| 30 | #define NUMREGBYTES (90*sizeof(u64)) | ||
| 31 | #define NUMCRITREGBYTES (12*sizeof(u64)) | ||
| 32 | #endif | ||
| 33 | #define BREAK_INSTR_SIZE 4 | 32 | #define BREAK_INSTR_SIZE 4 |
| 34 | #define CACHE_FLUSH_IS_SAFE 0 | 33 | #define CACHE_FLUSH_IS_SAFE 0 |
| 35 | 34 | ||
diff --git a/arch/mips/kernel/kgdb.c b/arch/mips/kernel/kgdb.c index 9b78ff6e9b84..5e76c2daa7f4 100644 --- a/arch/mips/kernel/kgdb.c +++ b/arch/mips/kernel/kgdb.c | |||
| @@ -50,6 +50,151 @@ static struct hard_trap_info { | |||
| 50 | { 0, 0} /* Must be last */ | 50 | { 0, 0} /* Must be last */ |
| 51 | }; | 51 | }; |
| 52 | 52 | ||
| 53 | struct dbg_reg_def_t dbg_reg_def[DBG_MAX_REG_NUM] = | ||
| 54 | { | ||
| 55 | { "zero", GDB_SIZEOF_REG, offsetof(struct pt_regs, regs[0]) }, | ||
| 56 | { "at", GDB_SIZEOF_REG, offsetof(struct pt_regs, regs[1]) }, | ||
| 57 | { "v0", GDB_SIZEOF_REG, offsetof(struct pt_regs, regs[2]) }, | ||
| 58 | { "v1", GDB_SIZEOF_REG, offsetof(struct pt_regs, regs[3]) }, | ||
| 59 | { "a0", GDB_SIZEOF_REG, offsetof(struct pt_regs, regs[4]) }, | ||
| 60 | { "a1", GDB_SIZEOF_REG, offsetof(struct pt_regs, regs[5]) }, | ||
| 61 | { "a2", GDB_SIZEOF_REG, offsetof(struct pt_regs, regs[6]) }, | ||
| 62 | { "a3", GDB_SIZEOF_REG, offsetof(struct pt_regs, regs[7]) }, | ||
| 63 | { "t0", GDB_SIZEOF_REG, offsetof(struct pt_regs, regs[8]) }, | ||
| 64 | { "t1", GDB_SIZEOF_REG, offsetof(struct pt_regs, regs[9]) }, | ||
| 65 | { "t2", GDB_SIZEOF_REG, offsetof(struct pt_regs, regs[10]) }, | ||
| 66 | { "t3", GDB_SIZEOF_REG, offsetof(struct pt_regs, regs[11]) }, | ||
| 67 | { "t4", GDB_SIZEOF_REG, offsetof(struct pt_regs, regs[12]) }, | ||
| 68 | { "t5", GDB_SIZEOF_REG, offsetof(struct pt_regs, regs[13]) }, | ||
| 69 | { "t6", GDB_SIZEOF_REG, offsetof(struct pt_regs, regs[14]) }, | ||
| 70 | { "t7", GDB_SIZEOF_REG, offsetof(struct pt_regs, regs[15]) }, | ||
| 71 | { "s0", GDB_SIZEOF_REG, offsetof(struct pt_regs, regs[16]) }, | ||
| 72 | { "s1", GDB_SIZEOF_REG, offsetof(struct pt_regs, regs[17]) }, | ||
| 73 | { "s2", GDB_SIZEOF_REG, offsetof(struct pt_regs, regs[18]) }, | ||
| 74 | { "s3", GDB_SIZEOF_REG, offsetof(struct pt_regs, regs[19]) }, | ||
| 75 | { "s4", GDB_SIZEOF_REG, offsetof(struct pt_regs, regs[20]) }, | ||
| 76 | { "s5", GDB_SIZEOF_REG, offsetof(struct pt_regs, regs[21]) }, | ||
| 77 | { "s6", GDB_SIZEOF_REG, offsetof(struct pt_regs, regs[22]) }, | ||
| 78 | { "s7", GDB_SIZEOF_REG, offsetof(struct pt_regs, regs[23]) }, | ||
| 79 | { "t8", GDB_SIZEOF_REG, offsetof(struct pt_regs, regs[24]) }, | ||
| 80 | { "t9", GDB_SIZEOF_REG, offsetof(struct pt_regs, regs[25]) }, | ||
| 81 | { "k0", GDB_SIZEOF_REG, offsetof(struct pt_regs, regs[26]) }, | ||
| 82 | { "k1", GDB_SIZEOF_REG, offsetof(struct pt_regs, regs[27]) }, | ||
| 83 | { "gp", GDB_SIZEOF_REG, offsetof(struct pt_regs, regs[28]) }, | ||
| 84 | { "sp", GDB_SIZEOF_REG, offsetof(struct pt_regs, regs[29]) }, | ||
| 85 | { "s8", GDB_SIZEOF_REG, offsetof(struct pt_regs, regs[30]) }, | ||
| 86 | { "ra", GDB_SIZEOF_REG, offsetof(struct pt_regs, regs[31]) }, | ||
| 87 | { "sr", GDB_SIZEOF_REG, offsetof(struct pt_regs, cp0_status) }, | ||
| 88 | { "lo", GDB_SIZEOF_REG, offsetof(struct pt_regs, lo) }, | ||
| 89 | { "hi", GDB_SIZEOF_REG, offsetof(struct pt_regs, hi) }, | ||
| 90 | { "bad", GDB_SIZEOF_REG, offsetof(struct pt_regs, cp0_badvaddr) }, | ||
| 91 | { "cause", GDB_SIZEOF_REG, offsetof(struct pt_regs, cp0_cause) }, | ||
| 92 | { "pc", GDB_SIZEOF_REG, offsetof(struct pt_regs, cp0_epc) }, | ||
| 93 | { "f0", GDB_SIZEOF_REG, 0 }, | ||
| 94 | { "f1", GDB_SIZEOF_REG, 1 }, | ||
| 95 | { "f2", GDB_SIZEOF_REG, 2 }, | ||
| 96 | { "f3", GDB_SIZEOF_REG, 3 }, | ||
| 97 | { "f4", GDB_SIZEOF_REG, 4 }, | ||
| 98 | { "f5", GDB_SIZEOF_REG, 5 }, | ||
| 99 | { "f6", GDB_SIZEOF_REG, 6 }, | ||
| 100 | { "f7", GDB_SIZEOF_REG, 7 }, | ||
| 101 | { "f8", GDB_SIZEOF_REG, 8 }, | ||
| 102 | { "f9", GDB_SIZEOF_REG, 9 }, | ||
| 103 | { "f10", GDB_SIZEOF_REG, 10 }, | ||
| 104 | { "f11", GDB_SIZEOF_REG, 11 }, | ||
| 105 | { "f12", GDB_SIZEOF_REG, 12 }, | ||
| 106 | { "f13", GDB_SIZEOF_REG, 13 }, | ||
| 107 | { "f14", GDB_SIZEOF_REG, 14 }, | ||
| 108 | { "f15", GDB_SIZEOF_REG, 15 }, | ||
| 109 | { "f16", GDB_SIZEOF_REG, 16 }, | ||
| 110 | { "f17", GDB_SIZEOF_REG, 17 }, | ||
| 111 | { "f18", GDB_SIZEOF_REG, 18 }, | ||
| 112 | { "f19", GDB_SIZEOF_REG, 19 }, | ||
| 113 | { "f20", GDB_SIZEOF_REG, 20 }, | ||
| 114 | { "f21", GDB_SIZEOF_REG, 21 }, | ||
| 115 | { "f22", GDB_SIZEOF_REG, 22 }, | ||
| 116 | { "f23", GDB_SIZEOF_REG, 23 }, | ||
| 117 | { "f24", GDB_SIZEOF_REG, 24 }, | ||
| 118 | { "f25", GDB_SIZEOF_REG, 25 }, | ||
| 119 | { "f26", GDB_SIZEOF_REG, 26 }, | ||
| 120 | { "f27", GDB_SIZEOF_REG, 27 }, | ||
| 121 | { "f28", GDB_SIZEOF_REG, 28 }, | ||
| 122 | { "f29", GDB_SIZEOF_REG, 29 }, | ||
| 123 | { "f30", GDB_SIZEOF_REG, 30 }, | ||
| 124 | { "f31", GDB_SIZEOF_REG, 31 }, | ||
| 125 | { "fsr", GDB_SIZEOF_REG, 0 }, | ||
| 126 | { "fir", GDB_SIZEOF_REG, 0 }, | ||
| 127 | }; | ||
| 128 | |||
| 129 | int dbg_set_reg(int regno, void *mem, struct pt_regs *regs) | ||
| 130 | { | ||
| 131 | int fp_reg; | ||
| 132 | |||
| 133 | if (regno < 0 || regno >= DBG_MAX_REG_NUM) | ||
| 134 | return -EINVAL; | ||
| 135 | |||
| 136 | if (dbg_reg_def[regno].offset != -1 && regno < 38) { | ||
| 137 | memcpy((void *)regs + dbg_reg_def[regno].offset, mem, | ||
| 138 | dbg_reg_def[regno].size); | ||
| 139 | } else if (current && dbg_reg_def[regno].offset != -1 && regno < 72) { | ||
| 140 | /* FP registers 38 -> 69 */ | ||
| 141 | if (!(regs->cp0_status & ST0_CU1)) | ||
| 142 | return 0; | ||
| 143 | if (regno == 70) { | ||
| 144 | /* Process the fcr31/fsr (register 70) */ | ||
| 145 | memcpy((void *)¤t->thread.fpu.fcr31, mem, | ||
| 146 | dbg_reg_def[regno].size); | ||
| 147 | goto out_save; | ||
| 148 | } else if (regno == 71) { | ||
| 149 | /* Ignore the fir (register 71) */ | ||
| 150 | goto out_save; | ||
| 151 | } | ||
| 152 | fp_reg = dbg_reg_def[regno].offset; | ||
| 153 | memcpy((void *)¤t->thread.fpu.fpr[fp_reg], mem, | ||
| 154 | dbg_reg_def[regno].size); | ||
| 155 | out_save: | ||
| 156 | restore_fp(current); | ||
| 157 | } | ||
| 158 | |||
| 159 | return 0; | ||
| 160 | } | ||
| 161 | |||
| 162 | char *dbg_get_reg(int regno, void *mem, struct pt_regs *regs) | ||
| 163 | { | ||
| 164 | int fp_reg; | ||
| 165 | |||
| 166 | if (regno >= DBG_MAX_REG_NUM || regno < 0) | ||
| 167 | return NULL; | ||
| 168 | |||
| 169 | if (dbg_reg_def[regno].offset != -1 && regno < 38) { | ||
| 170 | /* First 38 registers */ | ||
| 171 | memcpy(mem, (void *)regs + dbg_reg_def[regno].offset, | ||
| 172 | dbg_reg_def[regno].size); | ||
| 173 | } else if (current && dbg_reg_def[regno].offset != -1 && regno < 72) { | ||
| 174 | /* FP registers 38 -> 69 */ | ||
| 175 | if (!(regs->cp0_status & ST0_CU1)) | ||
| 176 | goto out; | ||
| 177 | save_fp(current); | ||
| 178 | if (regno == 70) { | ||
| 179 | /* Process the fcr31/fsr (register 70) */ | ||
| 180 | memcpy(mem, (void *)¤t->thread.fpu.fcr31, | ||
| 181 | dbg_reg_def[regno].size); | ||
| 182 | goto out; | ||
| 183 | } else if (regno == 71) { | ||
| 184 | /* Ignore the fir (register 71) */ | ||
| 185 | memset(mem, 0, dbg_reg_def[regno].size); | ||
| 186 | goto out; | ||
| 187 | } | ||
| 188 | fp_reg = dbg_reg_def[regno].offset; | ||
| 189 | memcpy(mem, (void *)¤t->thread.fpu.fpr[fp_reg], | ||
| 190 | dbg_reg_def[regno].size); | ||
| 191 | } | ||
| 192 | |||
| 193 | out: | ||
| 194 | return dbg_reg_def[regno].name; | ||
| 195 | |||
| 196 | } | ||
| 197 | |||
| 53 | void arch_kgdb_breakpoint(void) | 198 | void arch_kgdb_breakpoint(void) |
| 54 | { | 199 | { |
| 55 | __asm__ __volatile__( | 200 | __asm__ __volatile__( |
| @@ -84,64 +229,6 @@ static int compute_signal(int tt) | |||
| 84 | return SIGHUP; /* default for things we don't know about */ | 229 | return SIGHUP; /* default for things we don't know about */ |
| 85 | } | 230 | } |
| 86 | 231 | ||
| 87 | void pt_regs_to_gdb_regs(unsigned long *gdb_regs, struct pt_regs *regs) | ||
| 88 | { | ||
| 89 | int reg; | ||
| 90 | |||
| 91 | #if (KGDB_GDB_REG_SIZE == 32) | ||
| 92 | u32 *ptr = (u32 *)gdb_regs; | ||
| 93 | #else | ||
| 94 | u64 *ptr = (u64 *)gdb_regs; | ||
| 95 | #endif | ||
| 96 | |||
| 97 | for (reg = 0; reg < 32; reg++) | ||
| 98 | *(ptr++) = regs->regs[reg]; | ||
| 99 | |||
| 100 | *(ptr++) = regs->cp0_status; | ||
| 101 | *(ptr++) = regs->lo; | ||
| 102 | *(ptr++) = regs->hi; | ||
| 103 | *(ptr++) = regs->cp0_badvaddr; | ||
| 104 | *(ptr++) = regs->cp0_cause; | ||
| 105 | *(ptr++) = regs->cp0_epc; | ||
| 106 | |||
| 107 | /* FP REGS */ | ||
| 108 | if (!(current && (regs->cp0_status & ST0_CU1))) | ||
| 109 | return; | ||
| 110 | |||
| 111 | save_fp(current); | ||
| 112 | for (reg = 0; reg < 32; reg++) | ||
| 113 | *(ptr++) = current->thread.fpu.fpr[reg]; | ||
| 114 | } | ||
| 115 | |||
| 116 | void gdb_regs_to_pt_regs(unsigned long *gdb_regs, struct pt_regs *regs) | ||
| 117 | { | ||
| 118 | int reg; | ||
| 119 | |||
| 120 | #if (KGDB_GDB_REG_SIZE == 32) | ||
| 121 | const u32 *ptr = (u32 *)gdb_regs; | ||
| 122 | #else | ||
| 123 | const u64 *ptr = (u64 *)gdb_regs; | ||
| 124 | #endif | ||
| 125 | |||
| 126 | for (reg = 0; reg < 32; reg++) | ||
| 127 | regs->regs[reg] = *(ptr++); | ||
| 128 | |||
| 129 | regs->cp0_status = *(ptr++); | ||
| 130 | regs->lo = *(ptr++); | ||
| 131 | regs->hi = *(ptr++); | ||
| 132 | regs->cp0_badvaddr = *(ptr++); | ||
| 133 | regs->cp0_cause = *(ptr++); | ||
| 134 | regs->cp0_epc = *(ptr++); | ||
| 135 | |||
| 136 | /* FP REGS from current */ | ||
| 137 | if (!(current && (regs->cp0_status & ST0_CU1))) | ||
| 138 | return; | ||
| 139 | |||
| 140 | for (reg = 0; reg < 32; reg++) | ||
| 141 | current->thread.fpu.fpr[reg] = *(ptr++); | ||
| 142 | restore_fp(current); | ||
| 143 | } | ||
| 144 | |||
| 145 | /* | 232 | /* |
| 146 | * Similar to regs_to_gdb_regs() except that process is sleeping and so | 233 | * Similar to regs_to_gdb_regs() except that process is sleeping and so |
| 147 | * we may not be able to get all the info. | 234 | * we may not be able to get all the info. |
