aboutsummaryrefslogtreecommitdiffstats
path: root/arch/mips/kernel/kgdb.c
diff options
context:
space:
mode:
Diffstat (limited to 'arch/mips/kernel/kgdb.c')
-rw-r--r--arch/mips/kernel/kgdb.c211
1 files changed, 146 insertions, 65 deletions
diff --git a/arch/mips/kernel/kgdb.c b/arch/mips/kernel/kgdb.c
index 9b78ff6e9b84..1f4e2fa64140 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
53struct 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
129int 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 *)&current->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 *)&current->thread.fpu.fpr[fp_reg], mem,
154 dbg_reg_def[regno].size);
155out_save:
156 restore_fp(current);
157 }
158
159 return 0;
160}
161
162char *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 *)&current->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 *)&current->thread.fpu.fpr[fp_reg],
190 dbg_reg_def[regno].size);
191 }
192
193out:
194 return dbg_reg_def[regno].name;
195
196}
197
53void arch_kgdb_breakpoint(void) 198void 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
87void 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
116void 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.
@@ -242,7 +329,7 @@ static struct notifier_block kgdb_notifier = {
242}; 329};
243 330
244/* 331/*
245 * Handle the 's' and 'c' commands 332 * Handle the 'c' command
246 */ 333 */
247int kgdb_arch_handle_exception(int vector, int signo, int err_code, 334int kgdb_arch_handle_exception(int vector, int signo, int err_code,
248 char *remcom_in_buffer, char *remcom_out_buffer, 335 char *remcom_in_buffer, char *remcom_out_buffer,
@@ -250,20 +337,14 @@ int kgdb_arch_handle_exception(int vector, int signo, int err_code,
250{ 337{
251 char *ptr; 338 char *ptr;
252 unsigned long address; 339 unsigned long address;
253 int cpu = smp_processor_id();
254 340
255 switch (remcom_in_buffer[0]) { 341 switch (remcom_in_buffer[0]) {
256 case 's':
257 case 'c': 342 case 'c':
258 /* handle the optional parameter */ 343 /* handle the optional parameter */
259 ptr = &remcom_in_buffer[1]; 344 ptr = &remcom_in_buffer[1];
260 if (kgdb_hex2long(&ptr, &address)) 345 if (kgdb_hex2long(&ptr, &address))
261 regs->cp0_epc = address; 346 regs->cp0_epc = address;
262 347
263 atomic_set(&kgdb_cpu_doing_single_step, -1);
264 if (remcom_in_buffer[0] == 's')
265 atomic_set(&kgdb_cpu_doing_single_step, cpu);
266
267 return 0; 348 return 0;
268 } 349 }
269 350