David Howells | e460d64 | 2011-03-18 16:54:31 +0000 | [diff] [blame^] | 1 | /* kgdb support for MN10300 |
| 2 | * |
| 3 | * Copyright (C) 2010 Red Hat, Inc. All Rights Reserved. |
| 4 | * Written by David Howells (dhowells@redhat.com) |
| 5 | * |
| 6 | * This program is free software; you can redistribute it and/or |
| 7 | * modify it under the terms of the GNU General Public Licence |
| 8 | * as published by the Free Software Foundation; either version |
| 9 | * 2 of the Licence, or (at your option) any later version. |
| 10 | */ |
| 11 | |
| 12 | #include <linux/ptrace.h> |
| 13 | #include <linux/kgdb.h> |
| 14 | #include <linux/uaccess.h> |
| 15 | #include <unit/leds.h> |
| 16 | #include <unit/serial.h> |
| 17 | #include <asm/debugger.h> |
| 18 | #include <asm/serial-regs.h> |
| 19 | #include "internal.h" |
| 20 | |
| 21 | /* |
| 22 | * Copy kernel exception frame registers to the GDB register file |
| 23 | */ |
| 24 | void pt_regs_to_gdb_regs(unsigned long *gdb_regs, struct pt_regs *regs) |
| 25 | { |
| 26 | unsigned long ssp = (unsigned long) (regs + 1); |
| 27 | |
| 28 | gdb_regs[GDB_FR_D0] = regs->d0; |
| 29 | gdb_regs[GDB_FR_D1] = regs->d1; |
| 30 | gdb_regs[GDB_FR_D2] = regs->d2; |
| 31 | gdb_regs[GDB_FR_D3] = regs->d3; |
| 32 | gdb_regs[GDB_FR_A0] = regs->a0; |
| 33 | gdb_regs[GDB_FR_A1] = regs->a1; |
| 34 | gdb_regs[GDB_FR_A2] = regs->a2; |
| 35 | gdb_regs[GDB_FR_A3] = regs->a3; |
| 36 | gdb_regs[GDB_FR_SP] = (regs->epsw & EPSW_nSL) ? regs->sp : ssp; |
| 37 | gdb_regs[GDB_FR_PC] = regs->pc; |
| 38 | gdb_regs[GDB_FR_MDR] = regs->mdr; |
| 39 | gdb_regs[GDB_FR_EPSW] = regs->epsw; |
| 40 | gdb_regs[GDB_FR_LIR] = regs->lir; |
| 41 | gdb_regs[GDB_FR_LAR] = regs->lar; |
| 42 | gdb_regs[GDB_FR_MDRQ] = regs->mdrq; |
| 43 | gdb_regs[GDB_FR_E0] = regs->e0; |
| 44 | gdb_regs[GDB_FR_E1] = regs->e1; |
| 45 | gdb_regs[GDB_FR_E2] = regs->e2; |
| 46 | gdb_regs[GDB_FR_E3] = regs->e3; |
| 47 | gdb_regs[GDB_FR_E4] = regs->e4; |
| 48 | gdb_regs[GDB_FR_E5] = regs->e5; |
| 49 | gdb_regs[GDB_FR_E6] = regs->e6; |
| 50 | gdb_regs[GDB_FR_E7] = regs->e7; |
| 51 | gdb_regs[GDB_FR_SSP] = ssp; |
| 52 | gdb_regs[GDB_FR_MSP] = 0; |
| 53 | gdb_regs[GDB_FR_USP] = regs->sp; |
| 54 | gdb_regs[GDB_FR_MCRH] = regs->mcrh; |
| 55 | gdb_regs[GDB_FR_MCRL] = regs->mcrl; |
| 56 | gdb_regs[GDB_FR_MCVF] = regs->mcvf; |
| 57 | gdb_regs[GDB_FR_DUMMY0] = 0; |
| 58 | gdb_regs[GDB_FR_DUMMY1] = 0; |
| 59 | gdb_regs[GDB_FR_FS0] = 0; |
| 60 | } |
| 61 | |
| 62 | /* |
| 63 | * Extracts kernel SP/PC values understandable by gdb from the values |
| 64 | * saved by switch_to(). |
| 65 | */ |
| 66 | void sleeping_thread_to_gdb_regs(unsigned long *gdb_regs, struct task_struct *p) |
| 67 | { |
| 68 | gdb_regs[GDB_FR_SSP] = p->thread.sp; |
| 69 | gdb_regs[GDB_FR_PC] = p->thread.pc; |
| 70 | gdb_regs[GDB_FR_A3] = p->thread.a3; |
| 71 | gdb_regs[GDB_FR_USP] = p->thread.usp; |
| 72 | gdb_regs[GDB_FR_FPCR] = p->thread.fpu_state.fpcr; |
| 73 | } |
| 74 | |
| 75 | /* |
| 76 | * Fill kernel exception frame registers from the GDB register file |
| 77 | */ |
| 78 | void gdb_regs_to_pt_regs(unsigned long *gdb_regs, struct pt_regs *regs) |
| 79 | { |
| 80 | regs->d0 = gdb_regs[GDB_FR_D0]; |
| 81 | regs->d1 = gdb_regs[GDB_FR_D1]; |
| 82 | regs->d2 = gdb_regs[GDB_FR_D2]; |
| 83 | regs->d3 = gdb_regs[GDB_FR_D3]; |
| 84 | regs->a0 = gdb_regs[GDB_FR_A0]; |
| 85 | regs->a1 = gdb_regs[GDB_FR_A1]; |
| 86 | regs->a2 = gdb_regs[GDB_FR_A2]; |
| 87 | regs->a3 = gdb_regs[GDB_FR_A3]; |
| 88 | regs->sp = gdb_regs[GDB_FR_SP]; |
| 89 | regs->pc = gdb_regs[GDB_FR_PC]; |
| 90 | regs->mdr = gdb_regs[GDB_FR_MDR]; |
| 91 | regs->epsw = gdb_regs[GDB_FR_EPSW]; |
| 92 | regs->lir = gdb_regs[GDB_FR_LIR]; |
| 93 | regs->lar = gdb_regs[GDB_FR_LAR]; |
| 94 | regs->mdrq = gdb_regs[GDB_FR_MDRQ]; |
| 95 | regs->e0 = gdb_regs[GDB_FR_E0]; |
| 96 | regs->e1 = gdb_regs[GDB_FR_E1]; |
| 97 | regs->e2 = gdb_regs[GDB_FR_E2]; |
| 98 | regs->e3 = gdb_regs[GDB_FR_E3]; |
| 99 | regs->e4 = gdb_regs[GDB_FR_E4]; |
| 100 | regs->e5 = gdb_regs[GDB_FR_E5]; |
| 101 | regs->e6 = gdb_regs[GDB_FR_E6]; |
| 102 | regs->e7 = gdb_regs[GDB_FR_E7]; |
| 103 | regs->sp = gdb_regs[GDB_FR_SSP]; |
| 104 | /* gdb_regs[GDB_FR_MSP]; */ |
| 105 | // regs->usp = gdb_regs[GDB_FR_USP]; |
| 106 | regs->mcrh = gdb_regs[GDB_FR_MCRH]; |
| 107 | regs->mcrl = gdb_regs[GDB_FR_MCRL]; |
| 108 | regs->mcvf = gdb_regs[GDB_FR_MCVF]; |
| 109 | /* gdb_regs[GDB_FR_DUMMY0]; */ |
| 110 | /* gdb_regs[GDB_FR_DUMMY1]; */ |
| 111 | |
| 112 | // regs->fpcr = gdb_regs[GDB_FR_FPCR]; |
| 113 | // regs->fs0 = gdb_regs[GDB_FR_FS0]; |
| 114 | } |
| 115 | |
| 116 | struct kgdb_arch arch_kgdb_ops = { |
| 117 | .gdb_bpt_instr = { 0xff }, |
| 118 | .flags = KGDB_HW_BREAKPOINT, |
| 119 | }; |
| 120 | |
| 121 | /* |
| 122 | * Handle unknown packets and [Ccs] packets |
| 123 | */ |
| 124 | int kgdb_arch_handle_exception(int vector, int signo, int err_code, |
| 125 | char *remcom_in_buffer, char *remcom_out_buffer, |
| 126 | struct pt_regs *regs) |
| 127 | { |
| 128 | long addr; |
| 129 | char *ptr; |
| 130 | |
| 131 | switch (remcom_in_buffer[0]) { |
| 132 | case 'c': |
| 133 | if (kgdb_contthread && kgdb_contthread != current) { |
| 134 | strcpy(remcom_out_buffer, "E00"); |
| 135 | break; |
| 136 | } |
| 137 | |
| 138 | kgdb_contthread = NULL; |
| 139 | |
| 140 | /* try to read optional parameter, pc unchanged if no parm */ |
| 141 | ptr = &remcom_in_buffer[1]; |
| 142 | if (kgdb_hex2long(&ptr, &addr)) |
| 143 | regs->pc = addr; |
| 144 | return 0; |
| 145 | |
| 146 | case 's': |
| 147 | break; /* we don't do hardware single stepping */ |
| 148 | } |
| 149 | return -1; /* this means that we do not want to exit from the handler */ |
| 150 | } |
| 151 | |
| 152 | /* |
| 153 | * Handle event interception |
| 154 | * - returns 0 if the exception should be skipped, -ERROR otherwise. |
| 155 | */ |
| 156 | int debugger_intercept(enum exception_code excep, int signo, int si_code, |
| 157 | struct pt_regs *regs) |
| 158 | { |
| 159 | int ret; |
| 160 | |
| 161 | ret = kgdb_handle_exception(excep, signo, si_code, regs); |
| 162 | |
| 163 | debugger_local_cache_flushinv(); |
| 164 | |
| 165 | return ret; |
| 166 | } |
| 167 | |
| 168 | /* |
| 169 | * Determine if we've hit a debugger special breakpoint |
| 170 | */ |
| 171 | int at_debugger_breakpoint(struct pt_regs *regs) |
| 172 | { |
| 173 | return regs->pc == (unsigned long)&__arch_kgdb_breakpoint; |
| 174 | } |
| 175 | |
| 176 | /* |
| 177 | * Initialise kgdb |
| 178 | */ |
| 179 | int kgdb_arch_init(void) |
| 180 | { |
| 181 | return 0; |
| 182 | } |
| 183 | |
| 184 | /* |
| 185 | * Do something, perhaps, but don't know what. |
| 186 | */ |
| 187 | void kgdb_arch_exit(void) |
| 188 | { |
| 189 | } |
| 190 | |
| 191 | #ifdef CONFIG_SMP |
| 192 | void debugger_nmi_interrupt(struct pt_regs *regs, enum exception_code code) |
| 193 | { |
| 194 | kgdb_nmicallback(arch_smp_processor_id(), regs); |
| 195 | debugger_local_cache_flushinv(); |
| 196 | } |
| 197 | |
| 198 | void kgdb_roundup_cpus(unsigned long flags) |
| 199 | { |
| 200 | smp_jump_to_debugger(); |
| 201 | } |
| 202 | #endif |