Skip to content

Commit 2c4dfd9

Browse files
MarekVCodasipen-sc
authored andcommitted
[CHERRY PICK] target: Fix force-reading of registers and add flush capability
Cherrry-picked form https://review.openocd.org/c/openocd/+/8070/21 1) OpenOCD has the capability to 'force' a register read from the target. This functionality however silently breaks the register cache: During 'get_reg force' or 'reg <name> force', reg->type->get() is called which will silently overwrite dirty items in the register cache, causing a loss of unwritten register values. This patch fixes that by adding a flush callback for registers, and by using it when it is needed. 2) The register write commands did not have the 'force' flag; this was present for register read commands only. This patch adds it. 3) This patch also introduces the flush_reg_cache command. It flushes all registers and can optionally invalidate the register cache after the flush. For targets which implement the register cache, the flush() callback in struct reg_arch_type should be implemented (in separate patches, by the maintainers of each of the target type). This functionality is also useful for test purposes. Example: - In RISC-V, some registers are WARL (write any read legal) and this command allows to check this behavior. We plan to implement the corresponding callback in the RISC-V target. Change-Id: I9537a5f05b46330f70aad17f77b2b80dedad068a Signed-off-by: Marek Vrbka <[email protected]> Signed-off-by: Jan Matyas <[email protected]>
1 parent fa7e235 commit 2c4dfd9

24 files changed

+280
-24
lines changed

doc/openocd.texi

Lines changed: 19 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -9271,7 +9271,7 @@ various operations. The current target may be changed
92719271
by using @command{targets} command with the name of the
92729272
target which should become current.
92739273

9274-
@deffn {Command} {reg} [(number|name) [(value|'force')]]
9274+
@deffn {Command} {reg} [(number|name)] [value] ['force']
92759275
Access a single register by @var{number} or by its @var{name}.
92769276
The target must generally be halted before access to CPU core
92779277
registers is allowed. Depending on the hardware, some other
@@ -9285,15 +9285,17 @@ which are also dirty (and will be written back later)
92859285
are flagged as such.
92869286

92879287
@emph{With number/name}: display that register's value.
9288-
Use @var{force} argument to read directly from the target,
9289-
bypassing any internal cache.
9288+
Use @var{force} argument to read directly from the target
9289+
(as opposed to OpenOCD's internal register cache).
92909290

92919291
@emph{With both number/name and value}: set register's value.
92929292
Writes may be held in a writeback cache internal to OpenOCD,
92939293
so that setting the value marks the register as dirty instead
92949294
of immediately flushing that value. Resuming CPU execution
92959295
(including by single stepping) or otherwise activating the
9296-
relevant module will flush such values.
9296+
relevant module will flush such values. The use of @var{force}
9297+
causes the register value to be written to the target
9298+
immediately.
92979299

92989300
Cores may have surprisingly many registers in their
92999301
Debug and trace infrastructure:
@@ -9310,10 +9312,13 @@ Debug and trace infrastructure:
93109312
@end example
93119313
@end deffn
93129314

9313-
@deffn {Command} {set_reg} dict
9314-
Set register values of the target.
9315+
@deffn {Command} {set_reg} ['-force'] dict
9316+
Set register values of the target. The new register values may be
9317+
kept in OpenOCD's cache and not written to the target immediately
9318+
(unless @var{-force} is used).
93159319

93169320
@itemize
9321+
@item @option{-force} ... Force immediate write of the new register values.
93179322
@item @var{dict} ... Tcl dictionary with pairs of register names and values.
93189323
@end itemize
93199324

@@ -9329,7 +9334,7 @@ set_reg @{pc 0 sp 0x1000@}
93299334
Get register values from the target and return them as Tcl dictionary with pairs
93309335
of register names and values.
93319336
If option "-force" is set, the register values are read directly from the
9332-
target, bypassing any caching.
9337+
target, not from OpenOCD's internal cache.
93339338

93349339
@itemize
93359340
@item @var{list} ... List of register names
@@ -9343,6 +9348,13 @@ get_reg @{pc sp@}
93439348
@end example
93449349
@end deffn
93459350

9351+
@deffn {Command} {flush_reg_cache} [-invalidate]
9352+
Flush the internal OpenOCD's register cache - write back the dirty register values to the target.
9353+
If @option{-invalidate} is set, also invalidate (forget) the OpenOCD's cached register values;
9354+
therefore the next call to get_reg is guaranteed to read the fresh register value directly
9355+
from the target.
9356+
@end deffn
9357+
93469358
@deffn {Command} {write_memory} address width data ['phys']
93479359
This function provides an efficient way to write to the target memory from a Tcl
93489360
script.

src/target/arc.c

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -293,6 +293,7 @@ static int arc_set_register(struct reg *reg, uint8_t *buf)
293293
static const struct reg_arch_type arc_reg_type = {
294294
.get = arc_get_register,
295295
.set = arc_set_register,
296+
.flush = NULL,
296297
};
297298

298299
/* GDB register groups. For now we support only general and "empty" */

src/target/armv4_5.c

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -655,6 +655,7 @@ static int armv4_5_set_core_reg(struct reg *reg, uint8_t *buf)
655655
static const struct reg_arch_type arm_reg_type = {
656656
.get = armv4_5_get_core_reg,
657657
.set = armv4_5_set_core_reg,
658+
.flush = NULL,
658659
};
659660

660661
struct reg_cache *arm_build_reg_cache(struct target *target, struct arm *arm)

src/target/armv7m.c

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -786,6 +786,7 @@ int armv7m_arch_state(struct target *target)
786786
static const struct reg_arch_type armv7m_reg_type = {
787787
.get = armv7m_get_core_reg,
788788
.set = armv7m_set_core_reg,
789+
.flush = NULL,
789790
};
790791

791792
/** Builds cache of architecturally defined registers. */

src/target/armv8.c

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1714,6 +1714,7 @@ static int armv8_set_core_reg(struct reg *reg, uint8_t *buf)
17141714
static const struct reg_arch_type armv8_reg_type = {
17151715
.get = armv8_get_core_reg,
17161716
.set = armv8_set_core_reg,
1717+
.flush = NULL,
17171718
};
17181719

17191720
static int armv8_get_core_reg32(struct reg *reg)
@@ -1775,6 +1776,7 @@ static int armv8_set_core_reg32(struct reg *reg, uint8_t *buf)
17751776
static const struct reg_arch_type armv8_reg32_type = {
17761777
.get = armv8_get_core_reg32,
17771778
.set = armv8_set_core_reg32,
1779+
.flush = NULL,
17781780
};
17791781

17801782
/** Builds cache of architecturally defined registers. */

src/target/avr32_ap7k.c

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -157,6 +157,7 @@ static int avr32_set_core_reg(struct reg *reg, uint8_t *buf)
157157
static const struct reg_arch_type avr32_reg_type = {
158158
.get = avr32_get_core_reg,
159159
.set = avr32_set_core_reg,
160+
.flush = NULL,
160161
};
161162

162163
static struct reg_cache *avr32_build_reg_cache(struct target *target)

src/target/cortex_m.c

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2431,6 +2431,7 @@ static const struct dwt_reg dwt_comp[] = {
24312431
static const struct reg_arch_type dwt_reg_type = {
24322432
.get = cortex_m_dwt_get_reg,
24332433
.set = cortex_m_dwt_set_reg,
2434+
.flush = NULL,
24342435
};
24352436

24362437
static void cortex_m_dwt_addreg(struct target *t, struct reg *r, const struct dwt_reg *d)

src/target/dsp563xx.c

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -430,6 +430,7 @@ static int dsp563xx_set_core_reg(struct reg *reg, uint8_t *buf)
430430
static const struct reg_arch_type dsp563xx_reg_type = {
431431
.get = dsp563xx_get_core_reg,
432432
.set = dsp563xx_set_core_reg,
433+
.flush = NULL,
433434
};
434435

435436
static void dsp563xx_build_reg_cache(struct target *target)

src/target/embeddedice.c

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -152,6 +152,7 @@ static int embeddedice_get_reg(struct reg *reg)
152152
static const struct reg_arch_type eice_reg_type = {
153153
.get = embeddedice_get_reg,
154154
.set = embeddedice_set_reg_w_exec,
155+
.flush = NULL,
155156
};
156157

157158
/**

src/target/esirisc.c

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1419,6 +1419,7 @@ static int esirisc_set_reg(struct reg *reg, uint8_t *buf)
14191419
static const struct reg_arch_type esirisc_reg_type = {
14201420
.get = esirisc_get_reg,
14211421
.set = esirisc_set_reg,
1422+
.flush = NULL,
14221423
};
14231424

14241425
static struct reg_cache *esirisc_build_reg_cache(struct target *target)

src/target/etb.c

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -108,6 +108,7 @@ static int etb_get_reg(struct reg *reg)
108108
static const struct reg_arch_type etb_reg_type = {
109109
.get = etb_get_reg,
110110
.set = etb_set_reg_w_exec,
111+
.flush = NULL,
111112
};
112113

113114
struct reg_cache *etb_build_reg_cache(struct etb *etb)

src/target/etm.c

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -215,6 +215,7 @@ static int etm_write_reg(struct reg *reg, uint32_t value);
215215
static const struct reg_arch_type etm_scan6_type = {
216216
.get = etm_get_reg,
217217
.set = etm_set_reg_w_exec,
218+
.flush = NULL,
218219
};
219220

220221
/* Look up register by ID ... most ETM instances only

src/target/lakemont.c

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -357,6 +357,7 @@ static const struct reg_arch_type lakemont_reg_type = {
357357
*/
358358
.get = lakemont_get_core_reg,
359359
.set = lakemont_set_core_reg,
360+
.flush = NULL,
360361
};
361362

362363
struct reg_cache *lakemont_build_reg_cache(struct target *t)

src/target/mem_ap.c

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -179,6 +179,7 @@ static int mem_ap_reg_set(struct reg *reg, uint8_t *buf)
179179
static struct reg_arch_type mem_ap_reg_arch_type = {
180180
.get = mem_ap_reg_get,
181181
.set = mem_ap_reg_set,
182+
.flush = NULL,
182183
};
183184

184185
static const char *mem_ap_get_gdb_arch(const struct target *target)

src/target/mips32.c

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -496,6 +496,7 @@ int mips32_arch_state(struct target *target)
496496
static const struct reg_arch_type mips32_reg_type = {
497497
.get = mips32_get_core_reg,
498498
.set = mips32_set_core_reg,
499+
.flush = NULL,
499500
};
500501

501502
struct reg_cache *mips32_build_reg_cache(struct target *target)

src/target/mips64.c

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -370,6 +370,7 @@ int mips64_arch_state(struct target *target)
370370
static const struct reg_arch_type mips64_reg_type = {
371371
.get = mips64_get_core_reg,
372372
.set = mips64_set_core_reg,
373+
.flush = NULL,
373374
};
374375

375376
int mips64_build_reg_cache(struct target *target)

src/target/openrisc/or1k.c

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -494,6 +494,7 @@ static int or1k_set_core_reg(struct reg *reg, uint8_t *buf)
494494
static const struct reg_arch_type or1k_reg_type = {
495495
.get = or1k_get_core_reg,
496496
.set = or1k_set_core_reg,
497+
.flush = NULL,
497498
};
498499

499500
static struct reg_cache *or1k_build_reg_cache(struct target *target)

src/target/register.c

Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,8 @@
1414

1515
#include "register.h"
1616
#include <helper/log.h>
17+
#include <target/target.h>
18+
#include <target/target_type.h>
1719

1820
/**
1921
* @file
@@ -115,12 +117,72 @@ static int register_set_dummy_core_reg(struct reg *reg, uint8_t *buf)
115117
return ERROR_OK;
116118
}
117119

120+
static int register_flush_dummy(struct reg *reg)
121+
{
122+
reg->dirty = false;
123+
124+
return ERROR_OK;
125+
}
126+
118127
static const struct reg_arch_type dummy_type = {
119128
.get = register_get_dummy_core_reg,
120129
.set = register_set_dummy_core_reg,
130+
.flush = register_flush_dummy,
121131
};
122132

123133
void register_init_dummy(struct reg *reg)
124134
{
125135
reg->type = &dummy_type;
126136
}
137+
138+
int register_flush(const struct target *target, struct reg *reg, bool invalidate)
139+
{
140+
if (!reg) {
141+
LOG_ERROR("BUG: %s called with NULL", __func__);
142+
return ERROR_FAIL;
143+
}
144+
145+
if (!reg->exist) {
146+
LOG_ERROR("BUG: %s called with non-existent register", __func__);
147+
return ERROR_FAIL;
148+
}
149+
150+
if (!reg->dirty) {
151+
LOG_TARGET_DEBUG(target, "Register '%s' is not dirty, nothing to flush", reg->name);
152+
if (reg->valid && invalidate) {
153+
LOG_TARGET_DEBUG(target, "Invalidating register '%s'", reg->name);
154+
reg->valid = false;
155+
}
156+
return ERROR_OK;
157+
}
158+
159+
if (!reg->type->flush) {
160+
LOG_TARGET_ERROR(target, "Unable to flush dirty register '%s' - operation not yet supported "
161+
"by %s implementation in OpenOCD", reg->name, target->type->name);
162+
return ERROR_NOT_IMPLEMENTED;
163+
}
164+
165+
if (!reg->valid) {
166+
LOG_ERROR("BUG: Register '%s' is not valid, but flush attempted", reg->name);
167+
return ERROR_FAIL;
168+
}
169+
170+
LOG_TARGET_DEBUG(target, "Flushing register '%s'", reg->name);
171+
172+
int result = reg->type->flush(reg);
173+
if (result != ERROR_OK) {
174+
LOG_TARGET_ERROR(target, "Failed to flush register '%s'", reg->name);
175+
return result;
176+
}
177+
178+
if (reg->dirty) {
179+
LOG_ERROR("BUG: Register '%s' remained dirty after flushing", reg->name);
180+
return ERROR_FAIL;
181+
}
182+
if (reg->valid && invalidate) {
183+
LOG_TARGET_DEBUG(target, "Invalidating register '%s' after flush", reg->name);
184+
reg->valid = false;
185+
}
186+
187+
return ERROR_OK;
188+
}

src/target/register.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -151,6 +151,7 @@ struct reg_cache {
151151
struct reg_arch_type {
152152
int (*get)(struct reg *reg);
153153
int (*set)(struct reg *reg, uint8_t *buf);
154+
int (*flush)(struct reg *reg);
154155
};
155156

156157
struct reg *register_get_by_number(struct reg_cache *first,
@@ -163,4 +164,7 @@ void register_cache_invalidate(struct reg_cache *cache);
163164

164165
void register_init_dummy(struct reg *reg);
165166

167+
/* Flushes the register. Also invalidates the cached register value if invalidate == true */
168+
int register_flush(const struct target *target, struct reg *reg, bool invalidate);
169+
166170
#endif /* OPENOCD_TARGET_REGISTER_H */

src/target/stm8.c

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1180,6 +1180,7 @@ static int stm8_get_gdb_reg_list(struct target *target, struct reg **reg_list[],
11801180
static const struct reg_arch_type stm8_reg_type = {
11811181
.get = stm8_get_core_reg,
11821182
.set = stm8_set_core_reg,
1183+
.flush = NULL,
11831184
};
11841185

11851186
static struct reg_cache *stm8_build_reg_cache(struct target *target)

0 commit comments

Comments
 (0)