Commit 0896a9becdea36b2da21709b5e73ba47ae6481ea
1 parent
12bfa3de63
Exists in
master
and in
7 other branches
kgdb,mips: Individual register get/set for mips
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
Showing 2 changed files with 154 additions and 68 deletions Side-by-side Diff
arch/mips/include/asm/kgdb.h
... | ... | @@ -8,28 +8,27 @@ |
8 | 8 | #if (_MIPS_ISA == _MIPS_ISA_MIPS1) || (_MIPS_ISA == _MIPS_ISA_MIPS2) || \ |
9 | 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 | 14 | #elif (_MIPS_ISA == _MIPS_ISA_MIPS3) || (_MIPS_ISA == _MIPS_ISA_MIPS4) || \ |
14 | 15 | (_MIPS_ISA == _MIPS_ISA_MIPS64) |
15 | 16 | |
16 | 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 | 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 | 23 | #endif |
21 | 24 | #else |
22 | 25 | #error "Need to set KGDB_GDB_REG_SIZE for MIPS ISA" |
23 | 26 | #endif /* _MIPS_ISA */ |
24 | 27 | |
25 | 28 | #define BUFMAX 2048 |
26 | -#if (KGDB_GDB_REG_SIZE == 32) | |
27 | -#define NUMREGBYTES (90*sizeof(u32)) | |
28 | -#define NUMCRITREGBYTES (12*sizeof(u32)) | |
29 | -#else | |
30 | -#define NUMREGBYTES (90*sizeof(u64)) | |
31 | -#define NUMCRITREGBYTES (12*sizeof(u64)) | |
32 | -#endif | |
29 | +#define DBG_MAX_REG_NUM 72 | |
30 | +#define NUMREGBYTES (DBG_MAX_REG_NUM * sizeof(GDB_SIZEOF_REG)) | |
31 | +#define NUMCRITREGBYTES (12 * sizeof(GDB_SIZEOF_REG)) | |
33 | 32 | #define BREAK_INSTR_SIZE 4 |
34 | 33 | #define CACHE_FLUSH_IS_SAFE 0 |
35 | 34 |
arch/mips/kernel/kgdb.c
... | ... | @@ -50,6 +50,151 @@ |
50 | 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 | 198 | void arch_kgdb_breakpoint(void) |
54 | 199 | { |
55 | 200 | __asm__ __volatile__( |
... | ... | @@ -82,64 +227,6 @@ |
82 | 227 | return ht->signo; |
83 | 228 | |
84 | 229 | return SIGHUP; /* default for things we don't know about */ |
85 | -} | |
86 | - | |
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 | 230 | } |
144 | 231 | |
145 | 232 | /* |