Skip to content

Commit d3f46bc

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 8f59570 commit d3f46bc

24 files changed

+280
-24
lines changed

doc/openocd.texi

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

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

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

92229222
@emph{With both number/name and value}: set register's value.
92239223
Writes may be held in a writeback cache internal to OpenOCD,
92249224
so that setting the value marks the register as dirty instead
92259225
of immediately flushing that value. Resuming CPU execution
92269226
(including by single stepping) or otherwise activating the
9227-
relevant module will flush such values.
9227+
relevant module will flush such values. The use of @var{force}
9228+
causes the register value to be written to the target
9229+
immediately.
92289230

92299231
Cores may have surprisingly many registers in their
92309232
Debug and trace infrastructure:
@@ -9241,10 +9243,13 @@ Debug and trace infrastructure:
92419243
@end example
92429244
@end deffn
92439245

9244-
@deffn {Command} {set_reg} dict
9245-
Set register values of the target.
9246+
@deffn {Command} {set_reg} ['-force'] dict
9247+
Set register values of the target. The new register values may be
9248+
kept in OpenOCD's cache and not written to the target immediately
9249+
(unless @var{-force} is used).
92469250

92479251
@itemize
9252+
@item @option{-force} ... Force immediate write of the new register values.
92489253
@item @var{dict} ... Tcl dictionary with pairs of register names and values.
92499254
@end itemize
92509255

@@ -9260,7 +9265,7 @@ set_reg @{pc 0 sp 0x1000@}
92609265
Get register values from the target and return them as Tcl dictionary with pairs
92619266
of register names and values.
92629267
If option "-force" is set, the register values are read directly from the
9263-
target, bypassing any caching.
9268+
target, not from OpenOCD's internal cache.
92649269

92659270
@itemize
92669271
@item @var{list} ... List of register names
@@ -9274,6 +9279,13 @@ get_reg @{pc sp@}
92749279
@end example
92759280
@end deffn
92769281

9282+
@deffn {Command} {flush_reg_cache} [-invalidate]
9283+
Flush the internal OpenOCD's register cache - write back the dirty register values to the target.
9284+
If @option{-invalidate} is set, also invalidate (forget) the OpenOCD's cached register values;
9285+
therefore the next call to get_reg is guaranteed to read the fresh register value directly
9286+
from the target.
9287+
@end deffn
9288+
92779289
@deffn {Command} {write_memory} address width data ['phys']
92789290
This function provides an efficient way to write to the target memory from a Tcl
92799291
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
@@ -2429,6 +2429,7 @@ static const struct dwt_reg dwt_comp[] = {
24292429
static const struct reg_arch_type dwt_reg_type = {
24302430
.get = cortex_m_dwt_get_reg,
24312431
.set = cortex_m_dwt_set_reg,
2432+
.flush = NULL,
24322433
};
24332434

24342435
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)