Skip to content

Commit 272c514

Browse files
committed
target/riscv: implement abstract command cache
Implemented cache of unsupported abstract commands. It's purpose is to replace set of caching variables to one. So this commit provides one ac_not_supported_cache instead of abstract_read_csr_supported, abstract_write_csr_supported, abstract_read_fpr_supported, abstract_write_fpr_supported, has_aampostincrement. Dropped check for buggy aampostincrement Fixes #1232 Change-Id: I75cae1481841f2cd0393d6cc80f0d913fbe34294 Signed-off-by: Farid Khaydari <[email protected]>
1 parent fa7e235 commit 272c514

File tree

1 file changed

+135
-119
lines changed

1 file changed

+135
-119
lines changed

src/target/riscv/riscv-013.c

Lines changed: 135 additions & 119 deletions
Original file line numberDiff line numberDiff line change
@@ -145,6 +145,60 @@ typedef struct {
145145
struct target *target;
146146
} target_list_t;
147147

148+
struct ac_cache {
149+
uint32_t *commands;
150+
size_t size;
151+
};
152+
153+
static int ac_cache_elem_comparator(const void *lhs, const void *rhs)
154+
{
155+
return *(const uint32_t *)rhs - *(const uint32_t *)lhs;
156+
}
157+
158+
static struct ac_cache ac_cache_construct(void)
159+
{
160+
struct ac_cache cache = {
161+
cache.commands = NULL,
162+
cache.size = 0,
163+
};
164+
return cache;
165+
}
166+
167+
static void ac_cache_free(struct ac_cache *cache)
168+
{
169+
free(cache->commands);
170+
cache->commands = NULL;
171+
cache->size = 0;
172+
}
173+
174+
static void ac_cache_insert(struct ac_cache *cache, uint32_t command)
175+
{
176+
assert(cache);
177+
178+
size_t old_size = cache->size;
179+
size_t new_size = old_size + 1;
180+
size_t entry_size = sizeof(*cache->commands);
181+
182+
uint32_t *commands = realloc(cache->commands, new_size * entry_size);
183+
if (!commands) {
184+
LOG_ERROR("Reallocation to %zu bytes failed", new_size);
185+
return;
186+
}
187+
188+
commands[old_size] = command;
189+
cache->commands = commands;
190+
cache->size = new_size;
191+
192+
qsort(cache->commands, cache->size, entry_size,
193+
ac_cache_elem_comparator);
194+
}
195+
196+
static bool ac_cache_contains(const struct ac_cache *cache, uint32_t command)
197+
{
198+
return bsearch(&command, cache->commands, cache->size,
199+
sizeof(*cache->commands), ac_cache_elem_comparator);
200+
}
201+
148202
typedef struct {
149203
/* The indexed used to address this hart in its DM. */
150204
unsigned int index;
@@ -175,12 +229,7 @@ typedef struct {
175229
*/
176230
struct riscv_scan_delays learned_delays;
177231

178-
bool abstract_read_csr_supported;
179-
bool abstract_write_csr_supported;
180-
bool abstract_read_fpr_supported;
181-
bool abstract_write_fpr_supported;
182-
183-
yes_no_maybe_t has_aampostincrement;
232+
struct ac_cache ac_not_supported_cache;
184233

185234
/* Some fields from hartinfo. */
186235
uint8_t datasize;
@@ -651,6 +700,27 @@ static int abstract_cmd_batch_check_and_clear_cmderr(struct target *target,
651700
return res;
652701
}
653702

703+
enum riscv_debug_reg_ordinal get_cmdtype(uint32_t command)
704+
{
705+
enum riscv_debug_reg_ordinal val2cmdtype[4] = {
706+
AC_ACCESS_REGISTER_ORDINAL,
707+
AC_QUICK_ACCESS_ORDINAL,
708+
AC_ACCESS_MEMORY_ORDINAL,
709+
0,
710+
};
711+
712+
return val2cmdtype[get_field(command, DM_COMMAND_CMDTYPE)];
713+
}
714+
715+
static void mark_command_as_unsupported(struct target *target, uint32_t command)
716+
{
717+
LOG_TARGET_DEBUG(target, "Caching the abstract "
718+
"command 0x%" PRIx32 " as not supported", command);
719+
log_debug_reg(target, get_cmdtype(command),
720+
command, __FILE__, __LINE__, __func__);
721+
ac_cache_insert(&get_info(target)->ac_not_supported_cache, command);
722+
}
723+
654724
int riscv013_execute_abstract_command(struct target *target, uint32_t command,
655725
uint32_t *cmderr)
656726
{
@@ -684,6 +754,9 @@ int riscv013_execute_abstract_command(struct target *target, uint32_t command,
684754

685755
res = abstract_cmd_batch_check_and_clear_cmderr(target, batch,
686756
abstractcs_read_key, cmderr);
757+
if (res != ERROR_OK && *cmderr == CMDERR_NOT_SUPPORTED)
758+
mark_command_as_unsupported(target, command);
759+
687760
cleanup:
688761
riscv_batch_free(batch);
689762
return res;
@@ -829,38 +902,35 @@ uint32_t riscv013_access_register_command(struct target *target, uint32_t number
829902
return command;
830903
}
831904

905+
static bool is_command_unsupported(struct target *target, uint32_t command)
906+
{
907+
bool supported = !ac_cache_contains(&get_info(target)->ac_not_supported_cache, command);
908+
if (supported)
909+
return false;
910+
911+
LOG_TARGET_DEBUG(target, "Abstract command 0x%"
912+
PRIx32 " is cached as not supported", command);
913+
log_debug_reg(target, get_cmdtype(command),
914+
command, __FILE__, __LINE__, __func__);
915+
return supported;
916+
}
917+
832918
static int register_read_abstract_with_size(struct target *target,
833919
riscv_reg_t *value, enum gdb_regno number, unsigned int size)
834920
{
835-
RISCV013_INFO(info);
836-
837-
if (number >= GDB_REGNO_FPR0 && number <= GDB_REGNO_FPR31 &&
838-
!info->abstract_read_fpr_supported)
839-
return ERROR_FAIL;
840-
if (number >= GDB_REGNO_CSR0 && number <= GDB_REGNO_CSR4095 &&
841-
!info->abstract_read_csr_supported)
842-
return ERROR_FAIL;
843921
/* The spec doesn't define abstract register numbers for vector registers. */
844922
if (number >= GDB_REGNO_V0 && number <= GDB_REGNO_V31)
845923
return ERROR_FAIL;
846924

847925
uint32_t command = riscv013_access_register_command(target, number, size,
848926
AC_ACCESS_REGISTER_TRANSFER);
927+
if (is_command_unsupported(target, command))
928+
return ERROR_FAIL;
849929

850930
uint32_t cmderr;
851931
int result = riscv013_execute_abstract_command(target, command, &cmderr);
852-
if (result != ERROR_OK) {
853-
if (cmderr == CMDERR_NOT_SUPPORTED) {
854-
if (number >= GDB_REGNO_FPR0 && number <= GDB_REGNO_FPR31) {
855-
info->abstract_read_fpr_supported = false;
856-
LOG_TARGET_INFO(target, "Disabling abstract command reads from FPRs.");
857-
} else if (number >= GDB_REGNO_CSR0 && number <= GDB_REGNO_CSR4095) {
858-
info->abstract_read_csr_supported = false;
859-
LOG_TARGET_INFO(target, "Disabling abstract command reads from CSRs.");
860-
}
861-
}
932+
if (result != ERROR_OK)
862933
return result;
863-
}
864934

865935
if (value)
866936
return read_abstract_arg(target, value, 0, size);
@@ -879,23 +949,17 @@ static int register_read_abstract(struct target *target, riscv_reg_t *value,
879949
static int register_write_abstract(struct target *target, enum gdb_regno number,
880950
riscv_reg_t value)
881951
{
882-
RISCV013_INFO(info);
883-
884952
dm013_info_t *dm = get_dm(target);
885953
if (!dm)
886954
return ERROR_FAIL;
887955

888-
if (number >= GDB_REGNO_FPR0 && number <= GDB_REGNO_FPR31 &&
889-
!info->abstract_write_fpr_supported)
890-
return ERROR_FAIL;
891-
if (number >= GDB_REGNO_CSR0 && number <= GDB_REGNO_CSR4095 &&
892-
!info->abstract_write_csr_supported)
893-
return ERROR_FAIL;
894-
895956
const unsigned int size_bits = register_size(target, number);
896957
const uint32_t command = riscv013_access_register_command(target, number, size_bits,
897958
AC_ACCESS_REGISTER_TRANSFER |
898959
AC_ACCESS_REGISTER_WRITE);
960+
if (is_command_unsupported(target, command))
961+
return ERROR_FAIL;
962+
899963
LOG_DEBUG_REG(target, AC_ACCESS_REGISTER, command);
900964
assert(size_bits % 32 == 0);
901965
const unsigned int size_in_words = size_bits / 32;
@@ -915,18 +979,9 @@ static int register_write_abstract(struct target *target, enum gdb_regno number,
915979
uint32_t cmderr;
916980
res = abstract_cmd_batch_check_and_clear_cmderr(target, batch,
917981
abstractcs_read_key, &cmderr);
982+
if (res != ERROR_OK && cmderr == CMDERR_NOT_SUPPORTED)
983+
mark_command_as_unsupported(target, command);
918984

919-
if (res != ERROR_OK) {
920-
if (cmderr == CMDERR_NOT_SUPPORTED) {
921-
if (number >= GDB_REGNO_FPR0 && number <= GDB_REGNO_FPR31) {
922-
info->abstract_write_fpr_supported = false;
923-
LOG_TARGET_INFO(target, "Disabling abstract command writes to FPRs.");
924-
} else if (number >= GDB_REGNO_CSR0 && number <= GDB_REGNO_CSR4095) {
925-
info->abstract_write_csr_supported = false;
926-
LOG_TARGET_INFO(target, "Disabling abstract command writes to CSRs.");
927-
}
928-
}
929-
}
930985
cleanup:
931986
riscv_batch_free(batch);
932987
return res;
@@ -1709,6 +1764,10 @@ static void deinit_target(struct target *target)
17091764
if (!info)
17101765
return;
17111766

1767+
riscv013_info_t *vsinfo = info->version_specific;
1768+
if (vsinfo)
1769+
ac_cache_free(&vsinfo->ac_not_supported_cache);
1770+
17121771
riscv013_dm_free(target);
17131772

17141773
free(info->version_specific);
@@ -2819,17 +2878,7 @@ static int init_target(struct command_context *cmd_ctx,
28192878
info->progbufsize = -1;
28202879
reset_learned_delays(target);
28212880

2822-
/* Assume all these abstract commands are supported until we learn
2823-
* otherwise.
2824-
* TODO: The spec allows eg. one CSR to be able to be accessed abstractly
2825-
* while another one isn't. We don't track that this closely here, but in
2826-
* the future we probably should. */
2827-
info->abstract_read_csr_supported = true;
2828-
info->abstract_write_csr_supported = true;
2829-
info->abstract_read_fpr_supported = true;
2830-
info->abstract_write_fpr_supported = true;
2831-
2832-
info->has_aampostincrement = YNM_MAYBE;
2881+
info->ac_not_supported_cache = ac_cache_construct();
28332882

28342883
return ERROR_OK;
28352884
}
@@ -3719,16 +3768,17 @@ read_memory_abstract(struct target *target, const riscv_mem_access_args_t args)
37193768
{
37203769
assert(riscv_mem_access_is_read(args));
37213770

3722-
RISCV013_INFO(info);
3723-
bool use_aampostincrement = info->has_aampostincrement != YNM_NO;
3724-
37253771
memset(args.read_buffer, 0, args.count * args.size);
37263772

37273773
/* Convert the size (bytes) to width (bits) */
37283774
unsigned int width = args.size << 3;
37293775

37303776
/* Create the command (physical address, postincrement, read) */
3731-
uint32_t command = access_memory_command(target, false, width, use_aampostincrement, false);
3777+
uint32_t command = access_memory_command(target, false, width,
3778+
/* postincrement = */ true, /* is_write= */ false);
3779+
bool use_aampostincrement = !is_command_unsupported(target, command);
3780+
command = access_memory_command(target, false, width,
3781+
/* postincrement = */ use_aampostincrement, /* is_write = */ false);
37323782

37333783
/* Execute the reads */
37343784
uint8_t *p = args.read_buffer;
@@ -3749,33 +3799,15 @@ read_memory_abstract(struct target *target, const riscv_mem_access_args_t args)
37493799
/* Execute the command */
37503800
uint32_t cmderr;
37513801
result = riscv013_execute_abstract_command(target, command, &cmderr);
3752-
3753-
/* TODO: we need to modify error handling here. */
3754-
/* NOTE: in case of timeout cmderr is set to CMDERR_NONE */
3755-
if (info->has_aampostincrement == YNM_MAYBE) {
3756-
if (result == ERROR_OK) {
3757-
/* Safety: double-check that the address was really auto-incremented */
3758-
riscv_reg_t new_address;
3759-
result = read_abstract_arg(target, &new_address, 1, riscv_xlen(target));
3760-
if (result != ERROR_OK)
3761-
return mem_access_result(MEM_ACCESS_FAILED_DM_ACCESS_FAILED);
3762-
3763-
if (new_address == args.address + args.size) {
3764-
LOG_TARGET_DEBUG(target, "aampostincrement is supported on this target.");
3765-
info->has_aampostincrement = YNM_YES;
3766-
} else {
3767-
LOG_TARGET_WARNING(target, "Buggy aampostincrement! Address not incremented correctly.");
3768-
info->has_aampostincrement = YNM_NO;
3769-
}
3770-
} else {
3771-
/* Try the same access but with postincrement disabled. */
3772-
command = access_memory_command(target, false, width, false, false);
3773-
result = riscv013_execute_abstract_command(target, command, &cmderr);
3774-
if (result == ERROR_OK) {
3775-
LOG_TARGET_DEBUG(target, "aampostincrement is not supported on this target.");
3776-
info->has_aampostincrement = YNM_NO;
3777-
}
3778-
}
3802+
if (use_aampostincrement && result != ERROR_OK &&
3803+
cmderr == CMDERR_NOT_SUPPORTED) {
3804+
LOG_TARGET_DEBUG(target, "Trying the same abstract memory "
3805+
"write command, but without aampostincrement");
3806+
use_aampostincrement = false;
3807+
3808+
/* Try the same access but with postincrement disabled. */
3809+
command = access_memory_command(target, false, width, false, false);
3810+
result = riscv013_execute_abstract_command(target, command, &cmderr);
37793811
}
37803812

37813813
/* TODO:
@@ -3791,7 +3823,7 @@ read_memory_abstract(struct target *target, const riscv_mem_access_args_t args)
37913823
return mem_access_result(MEM_ACCESS_FAILED_DM_ACCESS_FAILED);
37923824
buf_set_u64(p, 0, 8 * args.size, value);
37933825

3794-
if (info->has_aampostincrement == YNM_YES)
3826+
if (use_aampostincrement)
37953827
updateaddr = false;
37963828
p += args.size;
37973829
}
@@ -3809,15 +3841,17 @@ write_memory_abstract(struct target *target, const riscv_mem_access_args_t args)
38093841
{
38103842
assert(riscv_mem_access_is_write(args));
38113843

3812-
RISCV013_INFO(info);
38133844
int result = ERROR_OK;
3814-
bool use_aampostincrement = info->has_aampostincrement != YNM_NO;
38153845

38163846
/* Convert the size (bytes) to width (bits) */
38173847
unsigned int width = args.size << 3;
38183848

38193849
/* Create the command (physical address, postincrement, write) */
3820-
uint32_t command = access_memory_command(target, false, width, use_aampostincrement, true);
3850+
uint32_t command = access_memory_command(target, false, width,
3851+
/* postincrement = */ true, /* is_write = */ true);
3852+
bool use_aampostincrement = !is_command_unsupported(target, command);
3853+
command = access_memory_command(target, false, width,
3854+
/* postincrement = */ use_aampostincrement, /* is_write = */ true);
38213855

38223856
/* Execute the writes */
38233857
const uint8_t *p = args.write_buffer;
@@ -3844,33 +3878,15 @@ write_memory_abstract(struct target *target, const riscv_mem_access_args_t args)
38443878
/* Execute the command */
38453879
uint32_t cmderr;
38463880
result = riscv013_execute_abstract_command(target, command, &cmderr);
3847-
3848-
/* TODO: we need to modify error handling here. */
3849-
/* NOTE: in case of timeout cmderr is set to CMDERR_NONE */
3850-
if (info->has_aampostincrement == YNM_MAYBE) {
3851-
if (result == ERROR_OK) {
3852-
/* Safety: double-check that the address was really auto-incremented */
3853-
riscv_reg_t new_address;
3854-
result = read_abstract_arg(target, &new_address, 1, riscv_xlen(target));
3855-
if (result != ERROR_OK)
3856-
return mem_access_result(MEM_ACCESS_FAILED_DM_ACCESS_FAILED);
3857-
3858-
if (new_address == args.address + args.size) {
3859-
LOG_TARGET_DEBUG(target, "aampostincrement is supported on this target.");
3860-
info->has_aampostincrement = YNM_YES;
3861-
} else {
3862-
LOG_TARGET_WARNING(target, "Buggy aampostincrement! Address not incremented correctly.");
3863-
info->has_aampostincrement = YNM_NO;
3864-
}
3865-
} else {
3866-
/* Try the same access but with postincrement disabled. */
3867-
command = access_memory_command(target, false, width, false, true);
3868-
result = riscv013_execute_abstract_command(target, command, &cmderr);
3869-
if (result == ERROR_OK) {
3870-
LOG_TARGET_DEBUG(target, "aampostincrement is not supported on this target.");
3871-
info->has_aampostincrement = YNM_NO;
3872-
}
3873-
}
3881+
if (use_aampostincrement && result != ERROR_OK &&
3882+
cmderr == CMDERR_NOT_SUPPORTED) {
3883+
LOG_TARGET_DEBUG(target, "Trying the same abstract memory "
3884+
"write command, but without aampostincrement");
3885+
use_aampostincrement = false;
3886+
3887+
/* Try the same access but with postincrement disabled. */
3888+
command = access_memory_command(target, false, width, false, true);
3889+
result = riscv013_execute_abstract_command(target, command, &cmderr);
38743890
}
38753891

38763892
/* TODO:
@@ -3879,7 +3895,7 @@ write_memory_abstract(struct target *target, const riscv_mem_access_args_t args)
38793895
if (result != ERROR_OK)
38803896
return mem_access_result(MEM_ACCESS_SKIPPED_ABSTRACT_ACCESS_CMDERR);
38813897

3882-
if (info->has_aampostincrement == YNM_YES)
3898+
if (use_aampostincrement)
38833899
updateaddr = false;
38843900
p += args.size;
38853901
}

0 commit comments

Comments
 (0)