v7debug.c (6536B)
1 // Copyright 2014 Brian Swetland <swetland@frotz.net> 2 // 3 // Licensed under the Apache License, Version 2.0 (the "License"); 4 // you may not use this file except in compliance with the License. 5 // You may obtain a copy of the License at 6 // 7 // http://www.apache.org/licenses/LICENSE-2.0 8 // 9 // Unless required by applicable law or agreed to in writing, software 10 // distributed under the License is distributed on an "AS IS" BASIS, 11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 // See the License for the specific language governing permissions and 13 // limitations under the License. 14 15 #include <stdio.h> 16 #include <stdlib.h> 17 #include <string.h> 18 19 #include "jtag.h" 20 #include "dap.h" 21 #include "v7debug.h" 22 23 #include "v7debug-registers.h" 24 25 // CPSR bits 26 #define ARM_N (1 << 31) 27 #define ARM_Z (1 << 30) 28 #define ARM_C (1 << 29) 29 #define ARM_V (1 << 28) 30 #define ARM_Q (1 << 27) 31 #define ARM_J (1 << 24) 32 #define ARM_E (1 << 9) 33 #define ARM_A (1 << 8) 34 #define ARM_I (1 << 7) 35 #define ARM_F (1 << 6) 36 #define ARM_T (1 << 5) 37 #define ARM_M_MASK 0x1F 38 #define ARM_M_USR 0x10 39 #define ARM_M_FIQ 0x11 40 #define ARM_M_IRQ 0x12 41 #define ARM_M_SVC 0x13 42 #define ARM_M_MON 0x16 43 #define ARM_M_ABT 0x17 44 #define ARM_M_UND 0x1B 45 #define ARM_M_SYS 0x1F 46 47 #define STATE_IDLE 0 48 #define STATE_HALTED 1 49 #define STATE_RUNNING 2 50 51 struct V7DEBUG { 52 DAP *dap; 53 unsigned state; 54 u32 apnum; 55 u32 base; 56 57 // saved state while halted 58 u32 save_r0; 59 u32 save_r1; 60 u32 save_pc; 61 u32 save_cpsr; 62 63 // cached cpsr 64 u32 cpsr; 65 }; 66 67 static inline int dwr(V7DEBUG *debug, u32 off, u32 val) { 68 return dap_mem_wr32(debug->dap, debug->apnum, debug->base + off, val); 69 } 70 71 static inline int drd(V7DEBUG *debug, u32 off, u32 *val) { 72 return dap_mem_rd32(debug->dap, debug->apnum, debug->base + off, val); 73 } 74 75 V7DEBUG *debug_init(DAP *dap, u32 apnum, u32 base) { 76 V7DEBUG *debug = malloc(sizeof(V7DEBUG)); 77 if (debug == NULL) { 78 return NULL; 79 } 80 memset(debug, 0, sizeof(V7DEBUG)); 81 debug->dap = dap; 82 debug->apnum = apnum; 83 debug->base = base; 84 return debug; 85 } 86 87 static int dccrd(V7DEBUG *debug, u32 *val) { 88 u32 x; 89 int n; 90 for (n = 0; n < 10; n++) { 91 if (drd(debug, DBGDSCR, &x)) return -1; 92 if (x & DSCR_TXFULL) { 93 return drd(debug, DBGDTRTX, val); 94 } 95 } 96 fprintf(stderr, "v7debug: dcc read timed out\n"); 97 return -1; 98 } 99 100 static int dccwr(V7DEBUG *debug, u32 val) { 101 u32 x; 102 int n; 103 for (n = 0; n < 10; n++) { 104 if (drd(debug, DBGDSCR, &x)) return -1; 105 if (!(x & DSCR_RXFULL)) { 106 return dwr(debug, DBGDTRRX, val); 107 } 108 } 109 fprintf(stderr, "v7debug: dcc write timed out\n"); 110 return -1; 111 } 112 113 static int dexec(V7DEBUG *debug, u32 instr) { 114 u32 x; 115 int n; 116 dwr(debug, DBGITR, instr); 117 for (n = 0; n < 10; n++) { 118 if (drd(debug, DBGDSCR, &x)) return -1; 119 if (x & DSCR_INSTRCOMPL) return 0; 120 } 121 fprintf(stderr, "v7debug: instruction timed out\n"); 122 return -1; 123 } 124 125 #define ARM_DSB 0xEE070F9A 126 #define ARM_ICIALLU 0xEE070F15 127 #define ARM_ISB 0xEE070F95 128 #define ARM_MOV_DCC_Rx(x) (0xEE000E15 | ((x) << 12)) // Rx -> DCC 129 #define ARM_MOV_Rx_DCC(x) (0xEE100E15 | ((x) << 12)) // DCC -> Rx 130 #define ARM_MOV_R0_PC 0xE1A0000F 131 #define ARM_MOV_PC_R0 0xE1A0F000 132 //#define ARM_MOV_CPSR_R0 0xE12FF000 // R0 -> CPSR 133 #define ARM_MOV_CPSR_R0 0xE129F000 // R0 -> CPSR 134 #define ARM_MOV_R0_CPSR 0xE10F0000 // CPSR -> R0 135 136 int debug_reg_rd(V7DEBUG *debug, unsigned n, u32 *val) { 137 if (debug->state != STATE_HALTED) { 138 return -1; 139 } 140 switch (n) { 141 case 0: { *val = debug->save_r0; return 0; } 142 case 1: { *val = debug->save_r1; return 0; } 143 case 15: { *val = debug->save_pc; return 0; } 144 case 16: { *val = debug->save_cpsr; return 0; } 145 } 146 if (n > 15) { 147 return -1; 148 } 149 if (dexec(debug, ARM_MOV_DCC_Rx(n))) return -1; 150 return dccrd(debug, val); 151 } 152 153 int debug_reg_wr(V7DEBUG *debug, unsigned n, u32 val) { 154 if (debug->state != STATE_HALTED) { 155 return -1; 156 } 157 switch (n) { 158 case 0: { debug->save_r0 = val; return 0; } 159 case 1: { debug->save_r1 = val; return 0; } 160 case 15: { debug->save_pc = val; return 0; } 161 case 16: { debug->save_cpsr = val; return 0; } 162 } 163 if (n > 15) { 164 return -1; 165 } 166 if (dccwr(debug, val)) return -1; 167 return dexec(debug, ARM_MOV_Rx_DCC(n)); 168 } 169 170 int debug_attach(V7DEBUG *debug) { 171 u32 x; 172 int n; 173 174 if (debug->state == STATE_HALTED) { 175 return -1; 176 } 177 178 drd(debug, DBGDSCR, &x); 179 if (x & DSCR_HALTED) { 180 fprintf(stderr, "debug: warning, processor already halted\n"); 181 } 182 183 dwr(debug, DBGDSCR, DSCR_H_DBG_EN | DSCR_RESTARTED | DSCR_HALTED); 184 185 dwr(debug, DBGDRCR, DRCR_HALT_REQ); 186 for (n = 0; n < 100; n++) { 187 if (drd(debug, DBGDSCR, &x)) return -1; 188 if (x & DSCR_HALTED) goto halted; 189 } 190 fprintf(stderr, "v7debug: halt timed out\n"); 191 return -1; 192 193 halted: 194 dwr(debug, DBGDSCR, DSCR_H_DBG_EN | DSCR_ITR_EN | DSCR_RESTARTED | DSCR_HALTED); 195 196 // save essential state 197 // we need r0/r1 to shuffle data in/out of memory and dcc 198 // pc will be corrupted on cpsr writes 199 // cpsr needs to be written to access other modes 200 dexec(debug, ARM_DSB); 201 dexec(debug, ARM_MOV_DCC_Rx(0)); 202 dccrd(debug, &debug->save_r0); 203 dexec(debug, ARM_MOV_DCC_Rx(1)); 204 dccrd(debug, &debug->save_r1); 205 dexec(debug, ARM_MOV_R0_PC); 206 dexec(debug, ARM_MOV_DCC_Rx(0)); 207 dccrd(debug, &debug->save_pc); 208 dexec(debug, ARM_MOV_R0_CPSR); 209 dexec(debug, ARM_MOV_DCC_Rx(0)); 210 dccrd(debug, &debug->save_cpsr); 211 if (debug->save_cpsr & ARM_T) { 212 debug->save_pc -= 4; 213 } else { 214 debug->save_pc -= 8; 215 } 216 debug->cpsr = debug->save_cpsr; 217 debug->state = STATE_HALTED; 218 return 0; 219 } 220 221 int debug_detach(V7DEBUG *debug) { 222 if (debug->state != STATE_HALTED) { 223 return -1; 224 } 225 226 dccwr(debug, debug->save_cpsr); 227 dexec(debug, ARM_MOV_Rx_DCC(0)); 228 dexec(debug, ARM_MOV_CPSR_R0); 229 230 dccwr(debug, debug->save_pc); 231 dexec(debug, ARM_MOV_Rx_DCC(0)); 232 dexec(debug, ARM_MOV_PC_R0); 233 234 dccwr(debug, debug->save_r0); 235 dexec(debug, ARM_MOV_Rx_DCC(0)); 236 237 dccwr(debug, debug->save_r1); 238 dexec(debug, ARM_MOV_Rx_DCC(1)); 239 240 dexec(debug, ARM_ICIALLU); 241 dexec(debug, ARM_ISB); 242 243 dwr(debug, DBGDSCR, 0); 244 dwr(debug, DBGDRCR, DRCR_CLR_EXC); 245 dwr(debug, DBGDRCR, DRCR_START_REQ); 246 247 debug->state = STATE_RUNNING; 248 return 0; 249 } 250 251 int debug_reg_dump(V7DEBUG *debug) { 252 int n; 253 u32 r[17]; 254 for (n = 0; n < 17; n++) { 255 if (debug_reg_rd(debug, n, r + n)) return -1; 256 } 257 258 printf(" r0: %08x r1: %08x r2: %08x r3: %08x\n", 259 r[0], r[1], r[2], r[3]); 260 printf(" r4: %08x r5: %08x r6: %08x r7: %08x\n", 261 r[4], r[5], r[6], r[7]); 262 printf(" r8: %08x r9: %08x r10: %08x r11: %08x\n", 263 r[8], r[9], r[10], r[11]); 264 printf(" r12: %08x sp: %08x lr: %08x pc: %08x\n", 265 r[12], r[13], r[14], r[15]); 266 printf("cpsr: %08x\n", r[16]); 267 return 0; 268 }