~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~

TOMOYO Linux Cross Reference
Linux/arch/blackfin/kernel/kgdb.c

Version: ~ [ linux-5.14-rc1 ] ~ [ linux-5.13.1 ] ~ [ linux-5.12.16 ] ~ [ linux-5.11.22 ] ~ [ linux-5.10.49 ] ~ [ linux-5.9.16 ] ~ [ linux-5.8.18 ] ~ [ linux-5.7.19 ] ~ [ linux-5.6.19 ] ~ [ linux-5.5.19 ] ~ [ linux-5.4.131 ] ~ [ linux-5.3.18 ] ~ [ linux-5.2.21 ] ~ [ linux-5.1.21 ] ~ [ linux-5.0.21 ] ~ [ linux-4.20.17 ] ~ [ linux-4.19.197 ] ~ [ linux-4.18.20 ] ~ [ linux-4.17.19 ] ~ [ linux-4.16.18 ] ~ [ linux-4.15.18 ] ~ [ linux-4.14.239 ] ~ [ linux-4.13.16 ] ~ [ linux-4.12.14 ] ~ [ linux-4.11.12 ] ~ [ linux-4.10.17 ] ~ [ linux-4.9.275 ] ~ [ linux-4.8.17 ] ~ [ linux-4.7.10 ] ~ [ linux-4.6.7 ] ~ [ linux-4.5.7 ] ~ [ linux-4.4.275 ] ~ [ linux-4.3.6 ] ~ [ linux-4.2.8 ] ~ [ linux-4.1.52 ] ~ [ linux-4.0.9 ] ~ [ linux-3.18.140 ] ~ [ linux-3.16.85 ] ~ [ linux-3.14.79 ] ~ [ linux-3.12.74 ] ~ [ linux-3.10.108 ] ~ [ linux-2.6.32.71 ] ~ [ linux-2.6.0 ] ~ [ linux-2.4.37.11 ] ~ [ unix-v6-master ] ~ [ ccs-tools-1.8.5 ] ~ [ policy-sample ] ~
Architecture: ~ [ i386 ] ~ [ alpha ] ~ [ m68k ] ~ [ mips ] ~ [ ppc ] ~ [ sparc ] ~ [ sparc64 ] ~

  1 /*
  2  * arch/blackfin/kernel/kgdb.c - Blackfin kgdb pieces
  3  *
  4  * Copyright 2005-2008 Analog Devices Inc.
  5  *
  6  * Licensed under the GPL-2 or later.
  7  */
  8 
  9 #include <linux/ptrace.h>               /* for linux pt_regs struct */
 10 #include <linux/kgdb.h>
 11 #include <linux/uaccess.h>
 12 #include <asm/irq_regs.h>
 13 
 14 void pt_regs_to_gdb_regs(unsigned long *gdb_regs, struct pt_regs *regs)
 15 {
 16         gdb_regs[BFIN_R0] = regs->r0;
 17         gdb_regs[BFIN_R1] = regs->r1;
 18         gdb_regs[BFIN_R2] = regs->r2;
 19         gdb_regs[BFIN_R3] = regs->r3;
 20         gdb_regs[BFIN_R4] = regs->r4;
 21         gdb_regs[BFIN_R5] = regs->r5;
 22         gdb_regs[BFIN_R6] = regs->r6;
 23         gdb_regs[BFIN_R7] = regs->r7;
 24         gdb_regs[BFIN_P0] = regs->p0;
 25         gdb_regs[BFIN_P1] = regs->p1;
 26         gdb_regs[BFIN_P2] = regs->p2;
 27         gdb_regs[BFIN_P3] = regs->p3;
 28         gdb_regs[BFIN_P4] = regs->p4;
 29         gdb_regs[BFIN_P5] = regs->p5;
 30         gdb_regs[BFIN_SP] = regs->reserved;
 31         gdb_regs[BFIN_FP] = regs->fp;
 32         gdb_regs[BFIN_I0] = regs->i0;
 33         gdb_regs[BFIN_I1] = regs->i1;
 34         gdb_regs[BFIN_I2] = regs->i2;
 35         gdb_regs[BFIN_I3] = regs->i3;
 36         gdb_regs[BFIN_M0] = regs->m0;
 37         gdb_regs[BFIN_M1] = regs->m1;
 38         gdb_regs[BFIN_M2] = regs->m2;
 39         gdb_regs[BFIN_M3] = regs->m3;
 40         gdb_regs[BFIN_B0] = regs->b0;
 41         gdb_regs[BFIN_B1] = regs->b1;
 42         gdb_regs[BFIN_B2] = regs->b2;
 43         gdb_regs[BFIN_B3] = regs->b3;
 44         gdb_regs[BFIN_L0] = regs->l0;
 45         gdb_regs[BFIN_L1] = regs->l1;
 46         gdb_regs[BFIN_L2] = regs->l2;
 47         gdb_regs[BFIN_L3] = regs->l3;
 48         gdb_regs[BFIN_A0_DOT_X] = regs->a0x;
 49         gdb_regs[BFIN_A0_DOT_W] = regs->a0w;
 50         gdb_regs[BFIN_A1_DOT_X] = regs->a1x;
 51         gdb_regs[BFIN_A1_DOT_W] = regs->a1w;
 52         gdb_regs[BFIN_ASTAT] = regs->astat;
 53         gdb_regs[BFIN_RETS] = regs->rets;
 54         gdb_regs[BFIN_LC0] = regs->lc0;
 55         gdb_regs[BFIN_LT0] = regs->lt0;
 56         gdb_regs[BFIN_LB0] = regs->lb0;
 57         gdb_regs[BFIN_LC1] = regs->lc1;
 58         gdb_regs[BFIN_LT1] = regs->lt1;
 59         gdb_regs[BFIN_LB1] = regs->lb1;
 60         gdb_regs[BFIN_CYCLES] = 0;
 61         gdb_regs[BFIN_CYCLES2] = 0;
 62         gdb_regs[BFIN_USP] = regs->usp;
 63         gdb_regs[BFIN_SEQSTAT] = regs->seqstat;
 64         gdb_regs[BFIN_SYSCFG] = regs->syscfg;
 65         gdb_regs[BFIN_RETI] = regs->pc;
 66         gdb_regs[BFIN_RETX] = regs->retx;
 67         gdb_regs[BFIN_RETN] = regs->retn;
 68         gdb_regs[BFIN_RETE] = regs->rete;
 69         gdb_regs[BFIN_PC] = regs->pc;
 70         gdb_regs[BFIN_CC] = (regs->astat >> 5) & 1;
 71         gdb_regs[BFIN_EXTRA1] = 0;
 72         gdb_regs[BFIN_EXTRA2] = 0;
 73         gdb_regs[BFIN_EXTRA3] = 0;
 74         gdb_regs[BFIN_IPEND] = regs->ipend;
 75 }
 76 
 77 /*
 78  * Extracts ebp, esp and eip values understandable by gdb from the values
 79  * saved by switch_to.
 80  * thread.esp points to ebp. flags and ebp are pushed in switch_to hence esp
 81  * prior to entering switch_to is 8 greater than the value that is saved.
 82  * If switch_to changes, change following code appropriately.
 83  */
 84 void sleeping_thread_to_gdb_regs(unsigned long *gdb_regs, struct task_struct *p)
 85 {
 86         gdb_regs[BFIN_SP] = p->thread.ksp;
 87         gdb_regs[BFIN_PC] = p->thread.pc;
 88         gdb_regs[BFIN_SEQSTAT] = p->thread.seqstat;
 89 }
 90 
 91 void gdb_regs_to_pt_regs(unsigned long *gdb_regs, struct pt_regs *regs)
 92 {
 93         regs->r0 = gdb_regs[BFIN_R0];
 94         regs->r1 = gdb_regs[BFIN_R1];
 95         regs->r2 = gdb_regs[BFIN_R2];
 96         regs->r3 = gdb_regs[BFIN_R3];
 97         regs->r4 = gdb_regs[BFIN_R4];
 98         regs->r5 = gdb_regs[BFIN_R5];
 99         regs->r6 = gdb_regs[BFIN_R6];
100         regs->r7 = gdb_regs[BFIN_R7];
101         regs->p0 = gdb_regs[BFIN_P0];
102         regs->p1 = gdb_regs[BFIN_P1];
103         regs->p2 = gdb_regs[BFIN_P2];
104         regs->p3 = gdb_regs[BFIN_P3];
105         regs->p4 = gdb_regs[BFIN_P4];
106         regs->p5 = gdb_regs[BFIN_P5];
107         regs->fp = gdb_regs[BFIN_FP];
108         regs->i0 = gdb_regs[BFIN_I0];
109         regs->i1 = gdb_regs[BFIN_I1];
110         regs->i2 = gdb_regs[BFIN_I2];
111         regs->i3 = gdb_regs[BFIN_I3];
112         regs->m0 = gdb_regs[BFIN_M0];
113         regs->m1 = gdb_regs[BFIN_M1];
114         regs->m2 = gdb_regs[BFIN_M2];
115         regs->m3 = gdb_regs[BFIN_M3];
116         regs->b0 = gdb_regs[BFIN_B0];
117         regs->b1 = gdb_regs[BFIN_B1];
118         regs->b2 = gdb_regs[BFIN_B2];
119         regs->b3 = gdb_regs[BFIN_B3];
120         regs->l0 = gdb_regs[BFIN_L0];
121         regs->l1 = gdb_regs[BFIN_L1];
122         regs->l2 = gdb_regs[BFIN_L2];
123         regs->l3 = gdb_regs[BFIN_L3];
124         regs->a0x = gdb_regs[BFIN_A0_DOT_X];
125         regs->a0w = gdb_regs[BFIN_A0_DOT_W];
126         regs->a1x = gdb_regs[BFIN_A1_DOT_X];
127         regs->a1w = gdb_regs[BFIN_A1_DOT_W];
128         regs->rets = gdb_regs[BFIN_RETS];
129         regs->lc0 = gdb_regs[BFIN_LC0];
130         regs->lt0 = gdb_regs[BFIN_LT0];
131         regs->lb0 = gdb_regs[BFIN_LB0];
132         regs->lc1 = gdb_regs[BFIN_LC1];
133         regs->lt1 = gdb_regs[BFIN_LT1];
134         regs->lb1 = gdb_regs[BFIN_LB1];
135         regs->usp = gdb_regs[BFIN_USP];
136         regs->syscfg = gdb_regs[BFIN_SYSCFG];
137         regs->retx = gdb_regs[BFIN_RETX];
138         regs->retn = gdb_regs[BFIN_RETN];
139         regs->rete = gdb_regs[BFIN_RETE];
140         regs->pc = gdb_regs[BFIN_PC];
141 
142 #if 0                           /* can't change these */
143         regs->astat = gdb_regs[BFIN_ASTAT];
144         regs->seqstat = gdb_regs[BFIN_SEQSTAT];
145         regs->ipend = gdb_regs[BFIN_IPEND];
146 #endif
147 }
148 
149 static struct hw_breakpoint {
150         unsigned int occupied:1;
151         unsigned int skip:1;
152         unsigned int enabled:1;
153         unsigned int type:1;
154         unsigned int dataacc:2;
155         unsigned short count;
156         unsigned int addr;
157 } breakinfo[HW_WATCHPOINT_NUM];
158 
159 static int bfin_set_hw_break(unsigned long addr, int len, enum kgdb_bptype type)
160 {
161         int breakno;
162         int bfin_type;
163         int dataacc = 0;
164 
165         switch (type) {
166         case BP_HARDWARE_BREAKPOINT:
167                 bfin_type = TYPE_INST_WATCHPOINT;
168                 break;
169         case BP_WRITE_WATCHPOINT:
170                 dataacc = 1;
171                 bfin_type = TYPE_DATA_WATCHPOINT;
172                 break;
173         case BP_READ_WATCHPOINT:
174                 dataacc = 2;
175                 bfin_type = TYPE_DATA_WATCHPOINT;
176                 break;
177         case BP_ACCESS_WATCHPOINT:
178                 dataacc = 3;
179                 bfin_type = TYPE_DATA_WATCHPOINT;
180                 break;
181         default:
182                 return -ENOSPC;
183         }
184 
185         /* Because hardware data watchpoint impelemented in current
186          * Blackfin can not trigger an exception event as the hardware
187          * instrction watchpoint does, we ignaore all data watch point here.
188          * They can be turned on easily after future blackfin design
189          * supports this feature.
190          */
191         for (breakno = 0; breakno < HW_INST_WATCHPOINT_NUM; breakno++)
192                 if (bfin_type == breakinfo[breakno].type
193                         && !breakinfo[breakno].occupied) {
194                         breakinfo[breakno].occupied = 1;
195                         breakinfo[breakno].skip = 0;
196                         breakinfo[breakno].enabled = 1;
197                         breakinfo[breakno].addr = addr;
198                         breakinfo[breakno].dataacc = dataacc;
199                         breakinfo[breakno].count = 0;
200                         return 0;
201                 }
202 
203         return -ENOSPC;
204 }
205 
206 static int bfin_remove_hw_break(unsigned long addr, int len, enum kgdb_bptype type)
207 {
208         int breakno;
209         int bfin_type;
210 
211         switch (type) {
212         case BP_HARDWARE_BREAKPOINT:
213                 bfin_type = TYPE_INST_WATCHPOINT;
214                 break;
215         case BP_WRITE_WATCHPOINT:
216         case BP_READ_WATCHPOINT:
217         case BP_ACCESS_WATCHPOINT:
218                 bfin_type = TYPE_DATA_WATCHPOINT;
219                 break;
220         default:
221                 return 0;
222         }
223         for (breakno = 0; breakno < HW_WATCHPOINT_NUM; breakno++)
224                 if (bfin_type == breakinfo[breakno].type
225                         && breakinfo[breakno].occupied
226                         && breakinfo[breakno].addr == addr) {
227                         breakinfo[breakno].occupied = 0;
228                         breakinfo[breakno].enabled = 0;
229                 }
230 
231         return 0;
232 }
233 
234 static void bfin_remove_all_hw_break(void)
235 {
236         int breakno;
237 
238         memset(breakinfo, 0, sizeof(struct hw_breakpoint)*HW_WATCHPOINT_NUM);
239 
240         for (breakno = 0; breakno < HW_INST_WATCHPOINT_NUM; breakno++)
241                 breakinfo[breakno].type = TYPE_INST_WATCHPOINT;
242         for (; breakno < HW_WATCHPOINT_NUM; breakno++)
243                 breakinfo[breakno].type = TYPE_DATA_WATCHPOINT;
244 }
245 
246 static void bfin_correct_hw_break(void)
247 {
248         int breakno;
249         unsigned int wpiactl = 0;
250         unsigned int wpdactl = 0;
251         int enable_wp = 0;
252 
253         for (breakno = 0; breakno < HW_WATCHPOINT_NUM; breakno++)
254                 if (breakinfo[breakno].enabled) {
255                         enable_wp = 1;
256 
257                         switch (breakno) {
258                         case 0:
259                                 wpiactl |= WPIAEN0|WPICNTEN0;
260                                 bfin_write_WPIA0(breakinfo[breakno].addr);
261                                 bfin_write_WPIACNT0(breakinfo[breakno].count
262                                         + breakinfo->skip);
263                                 break;
264                         case 1:
265                                 wpiactl |= WPIAEN1|WPICNTEN1;
266                                 bfin_write_WPIA1(breakinfo[breakno].addr);
267                                 bfin_write_WPIACNT1(breakinfo[breakno].count
268                                         + breakinfo->skip);
269                                 break;
270                         case 2:
271                                 wpiactl |= WPIAEN2|WPICNTEN2;
272                                 bfin_write_WPIA2(breakinfo[breakno].addr);
273                                 bfin_write_WPIACNT2(breakinfo[breakno].count
274                                         + breakinfo->skip);
275                                 break;
276                         case 3:
277                                 wpiactl |= WPIAEN3|WPICNTEN3;
278                                 bfin_write_WPIA3(breakinfo[breakno].addr);
279                                 bfin_write_WPIACNT3(breakinfo[breakno].count
280                                         + breakinfo->skip);
281                                 break;
282                         case 4:
283                                 wpiactl |= WPIAEN4|WPICNTEN4;
284                                 bfin_write_WPIA4(breakinfo[breakno].addr);
285                                 bfin_write_WPIACNT4(breakinfo[breakno].count
286                                         + breakinfo->skip);
287                                 break;
288                         case 5:
289                                 wpiactl |= WPIAEN5|WPICNTEN5;
290                                 bfin_write_WPIA5(breakinfo[breakno].addr);
291                                 bfin_write_WPIACNT5(breakinfo[breakno].count
292                                         + breakinfo->skip);
293                                 break;
294                         case 6:
295                                 wpdactl |= WPDAEN0|WPDCNTEN0|WPDSRC0;
296                                 wpdactl |= breakinfo[breakno].dataacc
297                                         << WPDACC0_OFFSET;
298                                 bfin_write_WPDA0(breakinfo[breakno].addr);
299                                 bfin_write_WPDACNT0(breakinfo[breakno].count
300                                         + breakinfo->skip);
301                                 break;
302                         case 7:
303                                 wpdactl |= WPDAEN1|WPDCNTEN1|WPDSRC1;
304                                 wpdactl |= breakinfo[breakno].dataacc
305                                         << WPDACC1_OFFSET;
306                                 bfin_write_WPDA1(breakinfo[breakno].addr);
307                                 bfin_write_WPDACNT1(breakinfo[breakno].count
308                                         + breakinfo->skip);
309                                 break;
310                         }
311                 }
312 
313         /* Should enable WPPWR bit first before set any other
314          * WPIACTL and WPDACTL bits */
315         if (enable_wp) {
316                 bfin_write_WPIACTL(WPPWR);
317                 CSYNC();
318                 bfin_write_WPIACTL(wpiactl|WPPWR);
319                 bfin_write_WPDACTL(wpdactl);
320                 CSYNC();
321         }
322 }
323 
324 static void bfin_disable_hw_debug(struct pt_regs *regs)
325 {
326         /* Disable hardware debugging while we are in kgdb */
327         bfin_write_WPIACTL(0);
328         bfin_write_WPDACTL(0);
329         CSYNC();
330 }
331 
332 #ifdef CONFIG_SMP
333 extern void generic_exec_single(int cpu, struct call_single_data *data, int wait);
334 static struct call_single_data kgdb_smp_ipi_data[NR_CPUS];
335 
336 void kgdb_passive_cpu_callback(void *info)
337 {
338         kgdb_nmicallback(raw_smp_processor_id(), get_irq_regs());
339 }
340 
341 void kgdb_roundup_cpus(unsigned long flags)
342 {
343         unsigned int cpu;
344 
345         for (cpu = cpumask_first(cpu_online_mask); cpu < nr_cpu_ids;
346                 cpu = cpumask_next(cpu, cpu_online_mask)) {
347                 kgdb_smp_ipi_data[cpu].func = kgdb_passive_cpu_callback;
348                 generic_exec_single(cpu, &kgdb_smp_ipi_data[cpu], 0);
349         }
350 }
351 
352 void kgdb_roundup_cpu(int cpu, unsigned long flags)
353 {
354         generic_exec_single(cpu, &kgdb_smp_ipi_data[cpu], 0);
355 }
356 #endif
357 
358 #ifdef CONFIG_IPIPE
359 static unsigned long kgdb_arch_imask;
360 #endif
361 
362 void kgdb_post_primary_code(struct pt_regs *regs, int e_vector, int err_code)
363 {
364         if (kgdb_single_step)
365                 preempt_enable();
366 
367 #ifdef CONFIG_IPIPE
368         if (kgdb_arch_imask) {
369                 cpu_pda[raw_smp_processor_id()].ex_imask = kgdb_arch_imask;
370                 kgdb_arch_imask = 0;
371         }
372 #endif
373 }
374 
375 int kgdb_arch_handle_exception(int vector, int signo,
376                                int err_code, char *remcom_in_buffer,
377                                char *remcom_out_buffer,
378                                struct pt_regs *regs)
379 {
380         long addr;
381         char *ptr;
382         int newPC;
383         int i;
384 
385         switch (remcom_in_buffer[0]) {
386         case 'c':
387         case 's':
388                 if (kgdb_contthread && kgdb_contthread != current) {
389                         strcpy(remcom_out_buffer, "E00");
390                         break;
391                 }
392 
393                 kgdb_contthread = NULL;
394 
395                 /* try to read optional parameter, pc unchanged if no parm */
396                 ptr = &remcom_in_buffer[1];
397                 if (kgdb_hex2long(&ptr, &addr)) {
398                         regs->retx = addr;
399                 }
400                 newPC = regs->retx;
401 
402                 /* clear the trace bit */
403                 regs->syscfg &= 0xfffffffe;
404 
405                 /* set the trace bit if we're stepping */
406                 if (remcom_in_buffer[0] == 's') {
407                         regs->syscfg |= 0x1;
408                         kgdb_single_step = regs->ipend;
409                         kgdb_single_step >>= 6;
410                         for (i = 10; i > 0; i--, kgdb_single_step >>= 1)
411                                 if (kgdb_single_step & 1)
412                                         break;
413                         /* i indicate event priority of current stopped instruction
414                          * user space instruction is 0, IVG15 is 1, IVTMR is 10.
415                          * kgdb_single_step > 0 means in single step mode
416                          */
417                         kgdb_single_step = i + 1;
418 
419                         preempt_disable();
420 #ifdef CONFIG_IPIPE
421                         kgdb_arch_imask = cpu_pda[raw_smp_processor_id()].ex_imask;
422                         cpu_pda[raw_smp_processor_id()].ex_imask = 0;
423 #endif
424                 }
425 
426                 bfin_correct_hw_break();
427 
428                 return 0;
429         }                       /* switch */
430         return -1;              /* this means that we do not want to exit from the handler */
431 }
432 
433 struct kgdb_arch arch_kgdb_ops = {
434         .gdb_bpt_instr = {0xa1},
435         .flags = KGDB_HW_BREAKPOINT,
436         .set_hw_breakpoint = bfin_set_hw_break,
437         .remove_hw_breakpoint = bfin_remove_hw_break,
438         .disable_hw_break = bfin_disable_hw_debug,
439         .remove_all_hw_break = bfin_remove_all_hw_break,
440         .correct_hw_break = bfin_correct_hw_break,
441 };
442 
443 #define IN_MEM(addr, size, l1_addr, l1_size) \
444 ({ \
445         unsigned long __addr = (unsigned long)(addr); \
446         (l1_size && __addr >= l1_addr && __addr + (size) <= l1_addr + l1_size); \
447 })
448 #define ASYNC_BANK_SIZE \
449         (ASYNC_BANK0_SIZE + ASYNC_BANK1_SIZE + \
450          ASYNC_BANK2_SIZE + ASYNC_BANK3_SIZE)
451 
452 int kgdb_validate_break_address(unsigned long addr)
453 {
454         int cpu = raw_smp_processor_id();
455 
456         if (addr >= 0x1000 && (addr + BREAK_INSTR_SIZE) <= physical_mem_end)
457                 return 0;
458         if (IN_MEM(addr, BREAK_INSTR_SIZE, ASYNC_BANK0_BASE, ASYNC_BANK_SIZE))
459                 return 0;
460         if (cpu == 0 && IN_MEM(addr, BREAK_INSTR_SIZE, L1_CODE_START, L1_CODE_LENGTH))
461                 return 0;
462 #ifdef CONFIG_SMP
463         else if (cpu == 1 && IN_MEM(addr, BREAK_INSTR_SIZE, COREB_L1_CODE_START, L1_CODE_LENGTH))
464                 return 0;
465 #endif
466         if (IN_MEM(addr, BREAK_INSTR_SIZE, L2_START, L2_LENGTH))
467                 return 0;
468 
469         return -EFAULT;
470 }
471 
472 void kgdb_arch_set_pc(struct pt_regs *regs, unsigned long ip)
473 {
474         regs->retx = ip;
475 }
476 
477 int kgdb_arch_init(void)
478 {
479         kgdb_single_step = 0;
480 #ifdef CONFIG_IPIPE
481         kgdb_arch_imask = 0;
482 #endif
483 
484         bfin_remove_all_hw_break();
485         return 0;
486 }
487 
488 void kgdb_arch_exit(void)
489 {
490 }
491 

~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~

kernel.org | git.kernel.org | LWN.net | Project Home | Wiki (Japanese) | Wiki (English) | SVN repository | Mail admin

Linux® is a registered trademark of Linus Torvalds in the United States and other countries.
TOMOYO® is a registered trademark of NTT DATA CORPORATION.

osdn.jp