diff options
author | Evgeniy Naydanov <evgeniy.naydanov@syntacore.com> | 2024-02-20 18:17:49 +0300 |
---|---|---|
committer | Evgeniy Naydanov <evgeniy.naydanov@syntacore.com> | 2024-04-10 13:10:19 +0300 |
commit | 67b2a5a955c5330dab2fb9ad92fac5afeacd32ca (patch) | |
tree | 7f4c88fb585092eb36e624b5d063844970ee4aee | |
parent | 722cef1ae0ec55ee7aa47e60acafaa787be16b32 (diff) | |
download | riscv-openocd-67b2a5a955c5330dab2fb9ad92fac5afeacd32ca.zip riscv-openocd-67b2a5a955c5330dab2fb9ad92fac5afeacd32ca.tar.gz riscv-openocd-67b2a5a955c5330dab2fb9ad92fac5afeacd32ca.tar.bz2 |
target/riscv: cache `abstractcs.busy` in `dm013_info_t`
According to the RISC-V Debug Spec (1.0.0-rc1)[3.7 Abstract Commands]:
> While an abstract command is executing (busy in abstractcs is high), a
debugger must not change hartsel, and must not write 1 to haltreq,
resumereq, ackhavereset, setresethaltreq, or clrresethaltreq.
Tracking `abstractcs.busy` allows to enforce this rule.
Change-Id: If5975b48cf9fd379033268145c79103c36fb8134
Signed-off-by: Evgeniy Naydanov <evgeniy.naydanov@syntacore.com>
-rw-r--r-- | src/target/riscv/riscv-013.c | 38 |
1 files changed, 36 insertions, 2 deletions
diff --git a/src/target/riscv/riscv-013.c b/src/target/riscv/riscv-013.c index 0134548..c4609e6 100644 --- a/src/target/riscv/riscv-013.c +++ b/src/target/riscv/riscv-013.c @@ -140,6 +140,12 @@ typedef struct { /* The program buffer stores executable code. 0 is an illegal instruction, * so we use 0 to mean the cached value is invalid. */ uint32_t progbuf_cache[16]; + + /* Some operations are illegal when an abstract command is running. + * The field is used to track whether the last command timed out, and + * abstractcs.busy may have remained set. In that case we may need to + * re-check the busy state before executing these operations. */ + bool abstract_cmd_maybe_busy; } dm013_info_t; typedef struct { @@ -763,6 +769,7 @@ static int dm_read_exec(struct target *target, uint32_t *value, uint32_t address dm013_info_t *dm = get_dm(target); if (!dm) return ERROR_FAIL; + dm->abstract_cmd_maybe_busy = true; return dmi_read_exec(target, value, address + dm->base); } @@ -780,6 +787,7 @@ static int dm_write_exec(struct target *target, uint32_t address, dm013_info_t *dm = get_dm(target); if (!dm) return ERROR_FAIL; + dm->abstract_cmd_maybe_busy = true; return dmi_write_exec(target, address + dm->base, value, ensure_success); } @@ -874,6 +882,14 @@ static int wait_for_idle(struct target *target, uint32_t *abstractcs) assert(target); assert(abstractcs); + dm013_info_t *dm = get_dm(target); + if (!dm) { + LOG_ERROR("BUG: Target %s is not assigned to any RISC-V debug module", + target_name(target)); + *abstractcs = 0; + return ERROR_FAIL; + } + time_t start = time(NULL); do { if (dm_read(target, abstractcs, DM_ABSTRACTCS) != ERROR_OK) { @@ -885,9 +901,10 @@ static int wait_for_idle(struct target *target, uint32_t *abstractcs) return ERROR_FAIL; } - if (get_field(*abstractcs, DM_ABSTRACTCS_BUSY) == 0) + if (get_field(*abstractcs, DM_ABSTRACTCS_BUSY) == 0) { + dm->abstract_cmd_maybe_busy = false; return ERROR_OK; - + } } while ((time(NULL) - start) < riscv_command_timeout_sec); LOG_TARGET_ERROR(target, @@ -896,6 +913,11 @@ static int wait_for_idle(struct target *target, uint32_t *abstractcs) riscv_command_timeout_sec, *abstractcs); + if (!dm->abstract_cmd_maybe_busy) + LOG_TARGET_ERROR(target, + "BUG: dm->abstract_cmd_maybe_busy had not been set when starting an abstract command."); + dm->abstract_cmd_maybe_busy = true; + return ERROR_TIMEOUT_REACHED; } @@ -3900,6 +3922,12 @@ static int read_memory_progbuf_inner_run_and_process_batch(struct target *target struct riscv_batch *batch, struct memory_access_info access, uint32_t start_index, uint32_t elements_to_read, uint32_t *elements_read) { + dm013_info_t *dm = get_dm(target); + if (!dm) + return ERROR_FAIL; + + /* Abstract commands are executed while running the batch. */ + dm->abstract_cmd_maybe_busy = true; if (batch_run(target, batch) != ERROR_OK) return ERROR_FAIL; @@ -4624,6 +4652,12 @@ static int write_memory_progbuf_run_batch(struct target *target, struct riscv_ba target_addr_t *address_p, target_addr_t end_address, uint32_t size, const uint8_t *buffer) { + dm013_info_t *dm = get_dm(target); + if (!dm) + return ERROR_FAIL; + + /* Abstract commands are executed while running the batch. */ + dm->abstract_cmd_maybe_busy = true; if (batch_run(target, batch) != ERROR_OK) return ERROR_FAIL; |