Write to extra (FP, etc) registers from GDB
authorMichael Pratt <michael@pratt.im>
Mon, 9 Jul 2012 05:00:53 +0000 (01:00 -0400)
committerMichael Pratt <michael@pratt.im>
Mon, 9 Jul 2012 05:00:53 +0000 (01:00 -0400)
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.

AUTHORS
gdbserver/gdb-server.c
src/stlink-common.c
src/stlink-common.h
src/stlink-usb.c

diff --git a/AUTHORS b/AUTHORS
index 1096c17355c6c0ce5ab2614e2043362fcfbe1e79..5c52c64f37302996741464b1769429188ca031d2 100644 (file)
--- 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
index 789b609e1b1fd6d80008f20b1d22469507b214b3..ae06952bf83041f633803a7fd01a0b2393c511a4 100644 (file)
@@ -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, &regp);
+                       } else if(reg == 0x1D) {
+                               stlink_write_unsupported_reg(sl, ntohl(value), reg, &regp);
+                       } else if(reg == 0x1E) {
+                               stlink_write_unsupported_reg(sl, ntohl(value), reg, &regp);
+                       } else if(reg == 0x1F) {
+                               stlink_write_unsupported_reg(sl, ntohl(value), reg, &regp);
+            } else if(reg >= 0x20 && reg < 0x40) {
+                stlink_write_unsupported_reg(sl, ntohl(value), reg, &regp);
+                       } else if(reg == 0x40) {
+                stlink_write_unsupported_reg(sl, ntohl(value), reg, &regp);
                        } else {
                                reply = strdup("E00");
                        }
index 1e9c01114ffdbdaafdc90229e08fbb8ed22cf6f2..a86d9854926ecf6928264187538f9ef7b08e618e 100644 (file)
@@ -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);
index 5a82e1f494b444dc2c51b5163a2be3e13d223897..2e30e71c3fd40f9fcc1c58108aea4b9bca37f0ef 100644 (file)
@@ -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);
index fdd636b619d74469a3624a745c1b1a19aa9a03cf..277431a872979c6ef18d512882321701678d6b3f 100644 (file)
@@ -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,