From: Michael Pratt Date: Mon, 9 Jul 2012 05:00:53 +0000 (-0400) Subject: Write to extra (FP, etc) registers from GDB X-Git-Url: https://git.gag.com/?a=commitdiff_plain;h=c6274f026b7848cf45029eccc327f8215738a743;p=fw%2Fstlink Write to extra (FP, etc) registers from GDB The extra registers added in my previous commit can now be modified from within GDB. Since the ST-LINK does not support accessing these registers, a workaround was used from reading an writing to them. That is, the Debug Core Register Selector Register (DCRSR) can be written with the register requested, and it will be read/written to/from the Debug Core Register Data Register (DCRDR). The standard ST-LINK memory access functions are used to make these accesses. A target descriptor XML file is sent to GDB from the server, which tells GDB which registers exist on the target. This is only supported for the STM32F4, and has only been tested on the STM32F4DISCOVERY. I tested st-util on an STM32L-DISCOVERY and my changes did not seem to interfere with its operation. --- diff --git a/AUTHORS b/AUTHORS index 1096c17..5c52c64 100644 --- a/AUTHORS +++ b/AUTHORS @@ -14,4 +14,5 @@ bravikov@gmail.com jnosky - codegrinder69@hotmail.com marpe@mimuw.edu.pl marco.cassinerio@gmail.com -jserv@0xlab.org \ No newline at end of file +jserv@0xlab.org +michael@pratt.im diff --git a/gdbserver/gdb-server.c b/gdbserver/gdb-server.c index 789b609..ae06952 100644 --- a/gdbserver/gdb-server.c +++ b/gdbserver/gdb-server.c @@ -999,6 +999,22 @@ int serve(stlink_t *sl, int port) { stlink_write_reg(sl, ntohl(value), reg); } else if(reg == 0x19) { stlink_write_reg(sl, ntohl(value), 16); + } else if(reg == 0x1A) { + stlink_write_reg(sl, ntohl(value), 17); + } else if(reg == 0x1B) { + stlink_write_reg(sl, ntohl(value), 18); + } else if(reg == 0x1C) { + stlink_write_unsupported_reg(sl, ntohl(value), reg, ®p); + } else if(reg == 0x1D) { + stlink_write_unsupported_reg(sl, ntohl(value), reg, ®p); + } else if(reg == 0x1E) { + stlink_write_unsupported_reg(sl, ntohl(value), reg, ®p); + } else if(reg == 0x1F) { + stlink_write_unsupported_reg(sl, ntohl(value), reg, ®p); + } else if(reg >= 0x20 && reg < 0x40) { + stlink_write_unsupported_reg(sl, ntohl(value), reg, ®p); + } else if(reg == 0x40) { + stlink_write_unsupported_reg(sl, ntohl(value), reg, ®p); } else { reply = strdup("E00"); } diff --git a/src/stlink-common.c b/src/stlink-common.c index 1e9c011..a86d985 100644 --- a/src/stlink-common.c +++ b/src/stlink-common.c @@ -620,6 +620,27 @@ void stlink_read_unsupported_reg(stlink_t *sl, int r_idx, reg *regp) { sl->backend->read_unsupported_reg(sl, r_convert, regp); } +void stlink_write_unsupported_reg(stlink_t *sl, uint32_t val, int r_idx, reg *regp) { + int r_convert; + + DLOG("*** stlink_write_unsupported_reg\n"); + DLOG(" (%d) ***\n", r_idx); + + /* Convert to values used by DCRSR */ + if (r_idx >= 0x1C && r_idx <= 0x1F) { /* primask, basepri, faultmask, or control */ + r_convert = r_idx; /* The backend function handles this */ + } else if (r_idx == 0x40) { /* FPSCR */ + r_convert = 0x21; + } else if (r_idx >= 0x20 && r_idx < 0x40) { + r_convert = 0x40 + (r_idx - 0x20); + } else { + fprintf(stderr, "Error: register address must be in [0x1C..0x40]\n"); + return; + } + + sl->backend->write_unsupported_reg(sl, val, r_convert, regp); +} + unsigned int is_core_halted(stlink_t *sl) { /* return non zero if core is halted */ stlink_status(sl); diff --git a/src/stlink-common.h b/src/stlink-common.h index 5a82e1f..2e30e71 100644 --- a/src/stlink-common.h +++ b/src/stlink-common.h @@ -112,6 +112,8 @@ extern "C" { /* Cortex™-M3 Technical Reference Manual */ /* Debug Halting Control and Status Register */ #define DHCSR 0xe000edf0 +#define DCRSR 0xe000edf4 +#define DCRDR 0xe000edf8 #define DBGKEY 0xa05f0000 /* Enough space to hold both a V2 command or a V1 command packaged as generic scsi*/ @@ -303,6 +305,7 @@ extern "C" { void (*read_reg) (stlink_t *sl, int r_idx, reg * regp); void (*read_all_unsupported_regs) (stlink_t *sl, reg *regp); void (*read_unsupported_reg) (stlink_t *sl, int r_idx, reg *regp); + void (*write_unsupported_reg) (stlink_t *sl, uint32_t value, int idx, reg *regp); void (*write_reg) (stlink_t *sl, uint32_t reg, int idx); void (*step) (stlink_t * stl); int (*current_mode) (stlink_t * stl); @@ -371,6 +374,7 @@ extern "C" { void stlink_read_all_unsupported_regs(stlink_t *sl, reg *regp); void stlink_read_reg(stlink_t *sl, int r_idx, reg *regp); void stlink_read_unsupported_reg(stlink_t *sl, int r_idx, reg *regp); + void stlink_write_unsupported_reg(stlink_t *sl, uint32_t value, int r_idx, reg *regp); void stlink_write_reg(stlink_t *sl, uint32_t reg, int idx); void stlink_step(stlink_t *sl); int stlink_current_mode(stlink_t *sl); diff --git a/src/stlink-usb.c b/src/stlink-usb.c index fdd636b..277431a 100644 --- a/src/stlink-usb.c +++ b/src/stlink-usb.c @@ -585,8 +585,8 @@ void _stlink_usb_read_unsupported_reg(stlink_t *sl, int r_idx, reg *regp) { sl->q_buf[i] = 0; } - _stlink_usb_write_mem32(sl, 0xE000EDF4, 4); - _stlink_usb_read_mem32(sl, 0xE000EDF8, 4); + _stlink_usb_write_mem32(sl, DCRSR, 4); + _stlink_usb_read_mem32(sl, DCRDR, 4); r = read_uint32(sl->q_buf, 0); DLOG("r_idx (%2d) = 0x%08x\n", r_idx, r); @@ -608,6 +608,7 @@ void _stlink_usb_read_unsupported_reg(stlink_t *sl, int r_idx, reg *regp) { } void _stlink_usb_read_all_unsupported_regs(stlink_t *sl, reg *regp) { + _stlink_usb_read_unsupported_reg(sl, 0x14, regp); _stlink_usb_read_unsupported_reg(sl, 0x21, regp); for (int i = 0; i < 32; i++) { @@ -615,6 +616,44 @@ void _stlink_usb_read_all_unsupported_regs(stlink_t *sl, reg *regp) { } } +/* See section C1.6 of the ARMv7-M Architecture Reference Manual */ +void _stlink_usb_write_unsupported_reg(stlink_t *sl, uint32_t val, int r_idx, reg *regp) { + if (r_idx >= 0x1C && r_idx <= 0x1F) { /* primask, basepri, faultmask, or control */ + /* These are held in the same register */ + _stlink_usb_read_unsupported_reg(sl, 0x14, regp); + + val = (uint8_t) (val>>24); + + switch (r_idx) { + case 0x1C: /* control */ + val = (((uint32_t) val) << 24) | (((uint32_t) regp->faultmask) << 16) | (((uint32_t) regp->basepri) << 8) | ((uint32_t) regp->primask); + break; + case 0x1D: /* faultmask */ + val = (((uint32_t) regp->control) << 24) | (((uint32_t) val) << 16) | (((uint32_t) regp->basepri) << 8) | ((uint32_t) regp->primask); + break; + case 0x1E: /* basepri */ + val = (((uint32_t) regp->control) << 24) | (((uint32_t) regp->faultmask) << 16) | (((uint32_t) val) << 8) | ((uint32_t) regp->primask); + break; + case 0x1F: /* primask */ + val = (((uint32_t) regp->control) << 24) | (((uint32_t) regp->faultmask) << 16) | (((uint32_t) regp->basepri) << 8) | ((uint32_t) val); + break; + } + + r_idx = 0x14; + } + + write_uint32(sl->q_buf, val); + + _stlink_usb_write_mem32(sl, DCRDR, 4); + + sl->q_buf[0] = (unsigned char) r_idx; + sl->q_buf[1] = 0; + sl->q_buf[2] = 0x01; + sl->q_buf[3] = 0; + + _stlink_usb_write_mem32(sl, DCRSR, 4); +} + void _stlink_usb_write_reg(stlink_t *sl, uint32_t reg, int idx) { struct stlink_libusb * const slu = sl->backend_data; unsigned char* const data = sl->q_buf; @@ -657,6 +696,7 @@ stlink_backend_t _stlink_usb_backend = { _stlink_usb_read_reg, _stlink_usb_read_all_unsupported_regs, _stlink_usb_read_unsupported_reg, + _stlink_usb_write_unsupported_reg, _stlink_usb_write_reg, _stlink_usb_step, _stlink_usb_current_mode,