jtagonizer

yet another JTAG tool
git clone http://frotz.net/git/jtagonizer.git
Log | Files | Refs | README

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 }