jtagonizer

Unnamed repository; edit this file 'description' to name the repository.
Log | Files | Refs | README

commit b09e4e8c9582bae629676d64a56b7c58e925bf01
parent a68ce9fc2fcc10bd6aeb54afcfd9c814e5a40492
Author: Brian Swetland <swetland@frotz.net>
Date:   Mon, 29 Sep 2014 18:04:21 -0700

v7debug: basic halt and restart working

Diffstat:
Mv7debug.c | 230+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++----------
1 file changed, 202 insertions(+), 28 deletions(-)

diff --git a/v7debug.c b/v7debug.c @@ -16,16 +16,55 @@ #include <stdlib.h> #include <string.h> +#include <unistd.h> +#include <fcntl.h> + #include "jtag.h" #include "dap.h" #include "v7debug.h" +// CPSR bits +#define ARM_N (1 << 31) +#define ARM_Z (1 << 30) +#define ARM_C (1 << 29) +#define ARM_V (1 << 28) +#define ARM_Q (1 << 27) +#define ARM_J (1 << 24) +#define ARM_E (1 << 9) +#define ARM_A (1 << 8) +#define ARM_I (1 << 7) +#define ARM_F (1 << 6) +#define ARM_T (1 << 5) +#define ARM_M_MASK 0x1F +#define ARM_M_USR 0x10 +#define ARM_M_FIQ 0x11 +#define ARM_M_IRQ 0x12 +#define ARM_M_SVC 0x13 +#define ARM_M_MON 0x16 +#define ARM_M_ABT 0x17 +#define ARM_M_UND 0x1B +#define ARM_M_SYS 0x1F + typedef struct V7DEBUG V7DEBUG; +#define STATE_IDLE 0 +#define STATE_HALTED 1 +#define STATE_RUNNING 2 + struct V7DEBUG { DAP *dap; + unsigned state; u32 apnum; u32 base; + + // saved state while halted + u32 save_r0; + u32 save_r1; + u32 save_pc; + u32 save_cpsr; + + // cached cpsr + u32 cpsr; }; static inline int dwr(V7DEBUG *debug, u32 off, u32 val) { @@ -48,10 +87,7 @@ V7DEBUG *debug_init(DAP *dap, u32 apnum, u32 base) { return debug; } - -#define P(n) do { u32 x; if (!drd(debug, n, &x)) printf("%s: %08x\n", #n, x); } while(0) - -int dccrd(V7DEBUG *debug, u32 *val) { +static int dccrd(V7DEBUG *debug, u32 *val) { u32 x; int n; for (n = 0; n < 10; n++) { @@ -64,7 +100,20 @@ int dccrd(V7DEBUG *debug, u32 *val) { return -1; } -int dexec(V7DEBUG *debug, u32 instr) { +static int dccwr(V7DEBUG *debug, u32 val) { + u32 x; + int n; + for (n = 0; n < 10; n++) { + if (drd(debug, DBGDSCR, &x)) return -1; + if (!(x & DSCR_RXFULL)) { + return dwr(debug, DBGDTRRX, val); + } + } + fprintf(stderr, "v7debug: dcc write timed out\n"); + return -1; +} + +static int dexec(V7DEBUG *debug, u32 instr) { u32 x; int n; dwr(debug, DBGITR, instr); @@ -76,26 +125,67 @@ int dexec(V7DEBUG *debug, u32 instr) { return -1; } -#define ARM_DSB 0xE57FF040 +#define ARM_DSB 0xEE070F9A #define ARM_MOV_DCC_Rx(x) (0xEE000E15 | ((x) << 12)) // Rx -> DCC #define ARM_MOV_Rx_DCC(x) (0xEE100E15 | ((x) << 12)) // DCC -> Rx #define ARM_MOV_R0_PC 0xE1A0000F -#define ARM_MOV_CPSR_R0 0xE12FF000 // R0 -> CPSR +#define ARM_MOV_PC_R0 0xE1A0F000 +//#define ARM_MOV_CPSR_R0 0xE12FF000 // R0 -> CPSR +#define ARM_MOV_CPSR_R0 0xE129F000 // R0 -> CPSR #define ARM_MOV_R0_CPSR 0xE10F0000 // CPSR -> R0 +int debug_reg_rd(V7DEBUG *debug, unsigned n, u32 *val) { + if (debug->state != STATE_HALTED) { + return -1; + } + switch (n) { + case 0: { *val = debug->save_r0; return 0; } + case 1: { *val = debug->save_r1; return 0; } + case 15: { *val = debug->save_pc; return 0; } + case 16: { *val = debug->save_cpsr; return 0; } + } + if (n > 15) { + return -1; + } + if (dexec(debug, ARM_MOV_DCC_Rx(n))) return -1; + return dccrd(debug, val); +} + +int debug_reg_wr(V7DEBUG *debug, unsigned n, u32 val) { + if (debug->state != STATE_HALTED) { + return -1; + } + switch (n) { + case 0: { debug->save_r0 = val; return 0; } + case 1: { debug->save_r1 = val; return 0; } + case 15: { debug->save_pc = val; return 0; } + case 16: { debug->save_cpsr = val; return 0; } + } + if (n > 15) { + return -1; + } + if (dccwr(debug, val)) return -1; + return dexec(debug, ARM_MOV_Rx_DCC(n)); +} + int debug_attach(V7DEBUG *debug) { u32 x; - u32 r[16]; - u32 cpsr; int n; - if (dap_attach(debug->dap)) return -1; - P(DBGDIDR); - P(DBGDEVID); - P(DBGDEVTYPE); - P(DBGLSR); - P(DBGDSCCR); - P(DBGDSCR); + if (debug->state == STATE_HALTED) { + return -1; + } + + if (dap_attach(debug->dap)) { + return -1; + } + + drd(debug, DBGDSCR, &x); + if (x & DSCR_HALTED) { + fprintf(stderr, "debug: warning, processor already halted\n"); + } + + dwr(debug, DBGDSCR, DSCR_H_DBG_EN | DSCR_RESTARTED | DSCR_HALTED); dwr(debug, DBGDRCR, DRCR_HALT_REQ); for (n = 0; n < 100; n++) { @@ -103,25 +193,79 @@ int debug_attach(V7DEBUG *debug) { if (x & DSCR_HALTED) goto halted; } fprintf(stderr, "v7debug: halt timed out\n"); + return -1; halted: - dwr(debug, DBGDSCR, DSCR_ITR_EN); + dwr(debug, DBGDSCR, DSCR_H_DBG_EN | DSCR_ITR_EN | DSCR_RESTARTED | DSCR_HALTED); - dexec(debug, ARM_DSB); // dsb - for (n = 0; n < 15; n++) { - dexec(debug, ARM_MOV_DCC_Rx(n)); - dccrd(debug, r + n); - } + // save essential state + // we need r0/r1 to shuffle data in/out of memory and dcc + // pc will be corrupted on cpsr writes + // cpsr needs to be written to access other modes + dexec(debug, ARM_DSB); + dexec(debug, ARM_MOV_DCC_Rx(0)); + dccrd(debug, &debug->save_r0); + dexec(debug, ARM_MOV_DCC_Rx(1)); + dccrd(debug, &debug->save_r1); dexec(debug, ARM_MOV_R0_PC); dexec(debug, ARM_MOV_DCC_Rx(0)); - dccrd(debug, r + 15); + dccrd(debug, &debug->save_pc); dexec(debug, ARM_MOV_R0_CPSR); dexec(debug, ARM_MOV_DCC_Rx(0)); - dccrd(debug, &cpsr); - for (n = 0; n < 16; n++) { - fprintf(stderr,"R%d %08x ", n, r[n]); + dccrd(debug, &debug->save_cpsr); + if (debug->save_cpsr & ARM_T) { + debug->save_pc -= 4; + } else { + debug->save_pc -= 8; } - fprintf(stderr, "CPSR %08x\n", cpsr); + debug->cpsr = debug->save_cpsr; + debug->state = STATE_HALTED; + return 0; +} + +int debug_detach(V7DEBUG *debug) { + if (debug->state != STATE_HALTED) { + return -1; + } + + dccwr(debug, debug->save_cpsr); + dexec(debug, ARM_MOV_Rx_DCC(0)); + dexec(debug, ARM_MOV_CPSR_R0); + + dccwr(debug, debug->save_pc); + dexec(debug, ARM_MOV_Rx_DCC(0)); + dexec(debug, ARM_MOV_PC_R0); + + dccwr(debug, debug->save_r0); + dexec(debug, ARM_MOV_Rx_DCC(0)); + + dccwr(debug, debug->save_r1); + dexec(debug, ARM_MOV_Rx_DCC(1)); + + dwr(debug, DBGDSCR, 0); + dwr(debug, DBGDRCR, DRCR_CLR_EXC); + dwr(debug, DBGDRCR, DRCR_START_REQ); + + debug->state = STATE_RUNNING; + return 0; +} + +int debug_reg_dump(V7DEBUG *debug) { + int n; + u32 r[17]; + for (n = 0; n < 17; n++) { + if (debug_reg_rd(debug, n, r + n)) return -1; + } + + printf(" r0: %08x r1: %08x r2: %08x r3: %08x\n", + r[0], r[1], r[2], r[3]); + printf(" r4: %08x r5: %08x r6: %08x r7: %08x\n", + r[4], r[5], r[6], r[7]); + printf(" r8: %08x r9: %08x r10: %08x r11: %08x\n", + r[8], r[9], r[10], r[11]); + printf(" r12: %08x sp: %08x lr: %08x pc: %08x\n", + r[12], r[13], r[14], r[15]); + printf("cpsr: %08x\n", r[16]); return 0; } @@ -130,17 +274,47 @@ halted: #define ZYNQ_DEBUG1_APN 1 #define ZYNQ_DEBUG1_BASE 0x80092000 +void *loadfile(const char *fn, u32 *sz) { + int fd; + off_t end; + void *data = NULL; + if ((fd = open(fn, O_RDONLY)) < 0) return NULL; + if ((end = lseek(fd, 0, SEEK_END)) < 0) goto oops; + if (lseek(fd, 0, SEEK_SET) < 0) goto oops; + if ((data = malloc(end + 4)) == NULL) goto oops; + if (read(fd, data, end) != end) goto oops; + close(fd); + *sz = end; + return data; + +oops: + free(data); + close(fd); + return NULL; +} + int main(int argc, char **argv) { JTAG *jtag; DAP *dap; V7DEBUG *debug; + void *data; + u32 sz; if (jtag_mpsse_open(&jtag)) return -1; if ((dap = dap_init(jtag, 0x4ba00477)) == NULL) return -1; if ((debug = debug_init(dap, ZYNQ_DEBUG0_APN, ZYNQ_DEBUG0_BASE)) == NULL) return -1; if (debug_attach(debug)) return -1; - fprintf(stderr, "whee!\n"); + debug_reg_dump(debug); + + if (argc == 2) { + if ((data = loadfile(argv[1], &sz))) { + dap_mem_write(dap, 0, 0, data, sz); + debug_reg_wr(debug, 15, 0); + } + } + + debug_detach(debug); return 0; }