Skip to content

Commit

Permalink
target/riscv: Mismatch napot when mcontrol.maskmax is not expected
Browse files Browse the repository at this point in the history
Signed-off-by: zhusonghe <[email protected]>
  • Loading branch information
zhusonghe committed Sep 5, 2024
1 parent 909bbb8 commit 2a520d3
Showing 1 changed file with 37 additions and 22 deletions.
59 changes: 37 additions & 22 deletions src/target/riscv/riscv.c
Original file line number Diff line number Diff line change
Expand Up @@ -619,8 +619,17 @@ static int find_first_trigger_by_id(struct target *target, int unique_id)
return -1;
}

static inline uint64_t get_least_significant_zero_index(riscv_reg_t tdata2)
{
for (int i = 0; i < 64; i++) {
if ((1 & (tdata2 >> i)) == 0)
return i;
}
return 64;
}

static int set_trigger(struct target *target, unsigned int idx, riscv_reg_t tdata1, riscv_reg_t tdata2,
riscv_reg_t tdata1_ignore_mask)
riscv_reg_t maskmax)
{
riscv_reg_t tdata1_rb, tdata2_rb;
// Select which trigger to use
Expand All @@ -644,15 +653,21 @@ static int set_trigger(struct target *target, unsigned int idx, riscv_reg_t tdat
return ERROR_FAIL;
if (riscv_reg_get(target, &tdata2_rb, GDB_REGNO_TDATA2) != ERROR_OK)
return ERROR_FAIL;
bool tdata1_config_denied = (tdata1 & ~tdata1_ignore_mask) != (tdata1_rb & ~tdata1_ignore_mask);
bool tdata1_config_denied = (tdata1 & ~maskmax) != (tdata1_rb & ~maskmax);
const uint32_t type = get_field(tdata1, CSR_TDATA1_TYPE(riscv_xlen(target)));
if (type == CSR_TDATA1_TYPE_MCONTROL &&
(get_field(tdata1, CSR_MCONTROL_MATCH) == CSR_MCONTROL_MATCH_NAPOT)) {
tdata1_config_denied |= (get_field(tdata1_rb, CSR_MCONTROL_MASKMAX(riscv_xlen(target)))
< (get_least_significant_zero_index(tdata2) + 1));
}
bool tdata2_config_denied = tdata2 != tdata2_rb;
if (tdata1_config_denied || tdata2_config_denied) {
LOG_TARGET_DEBUG(target, "Trigger %u doesn't support what we need.", idx);

if (tdata1_config_denied)
LOG_TARGET_DEBUG(target,
"After writing 0x%" PRIx64 " to tdata1 it contains 0x%" PRIx64 "; tdata1_ignore_mask=0x%" PRIx64,
tdata1, tdata1_rb, tdata1_ignore_mask);
"After writing 0x%" PRIx64 " to tdata1 it contains 0x%" PRIx64 "; maskmax=0x%" PRIx64,
tdata1, tdata1_rb, maskmax);

if (tdata2_config_denied)
LOG_TARGET_DEBUG(target,
Expand Down Expand Up @@ -716,13 +731,13 @@ static int maybe_add_trigger_t1(struct target *target, struct trigger *trigger)
struct trigger_request_info {
riscv_reg_t tdata1;
riscv_reg_t tdata2;
riscv_reg_t tdata1_ignore_mask;
riscv_reg_t maskmax;
};

static void log_trigger_request_info(struct trigger_request_info trig_info)
{
LOG_DEBUG("tdata1=%" PRIx64 ", tdata2=%" PRIx64 ", tdata1_ignore_mask=%" PRIx64,
trig_info.tdata1, trig_info.tdata2, trig_info.tdata1_ignore_mask);
LOG_DEBUG("tdata1=%" PRIx64 ", tdata2=%" PRIx64 ", maskmax=%" PRIx64,
trig_info.tdata1, trig_info.tdata2, trig_info.maskmax);
};

static struct tdata1_cache *tdata1_cache_alloc(struct list_head *tdata1_cache_head, riscv_reg_t tdata1)
Expand Down Expand Up @@ -805,12 +820,12 @@ static bool wp_triggers_cache_search(struct target *target, unsigned int idx,
}

static int try_use_trigger_and_cache_result(struct target *target, unsigned int idx, riscv_reg_t tdata1,
riscv_reg_t tdata2, riscv_reg_t tdata1_ignore_mask)
riscv_reg_t tdata2, riscv_reg_t maskmax)
{
if (wp_triggers_cache_search(target, idx, tdata1, tdata2))
return ERROR_TARGET_RESOURCE_NOT_AVAILABLE;

int ret = set_trigger(target, idx, tdata1, tdata2, tdata1_ignore_mask);
int ret = set_trigger(target, idx, tdata1, tdata2, maskmax);

/* Add these values to the cache to remember that they are not supported. */
if (ret == ERROR_TARGET_RESOURCE_NOT_AVAILABLE)
Expand All @@ -834,7 +849,7 @@ static int try_setup_single_match_trigger(struct target *target,
find_next_free_trigger(target, trigger_type, false, &idx) == ERROR_OK;
++idx) {
ret = try_use_trigger_and_cache_result(target, idx, trig_info.tdata1, trig_info.tdata2,
trig_info.tdata1_ignore_mask);
trig_info.maskmax);

if (ret == ERROR_OK) {
r->trigger_unique_id[idx] = trigger->unique_id;
Expand Down Expand Up @@ -863,15 +878,15 @@ static int try_setup_chained_match_triggers(struct target *target,
find_next_free_trigger(target, trigger_type, true, &idx) == ERROR_OK;
++idx) {
ret = try_use_trigger_and_cache_result(target, idx, t1.tdata1, t1.tdata2,
t1.tdata1_ignore_mask);
t1.maskmax);

if (ret == ERROR_TARGET_RESOURCE_NOT_AVAILABLE)
continue;
else if (ret != ERROR_OK)
return ret;

ret = try_use_trigger_and_cache_result(target, idx + 1, t2.tdata1, t2.tdata2,
t2.tdata1_ignore_mask);
t2.maskmax);

if (ret == ERROR_OK) {
r->trigger_unique_id[idx] = trigger->unique_id;
Expand Down Expand Up @@ -907,7 +922,7 @@ struct match_triggers_tdata1_fields {
riscv_reg_t ge;
riscv_reg_t eq;
} match;
riscv_reg_t tdata1_ignore_mask;
riscv_reg_t maskmax;
};

static struct match_triggers_tdata1_fields fill_match_triggers_tdata1_fields_t2(struct target *target,
Expand Down Expand Up @@ -941,7 +956,7 @@ static struct match_triggers_tdata1_fields fill_match_triggers_tdata1_fields_t2(
.ge = field_value(CSR_MCONTROL_MATCH, CSR_MCONTROL_MATCH_GE),
.eq = field_value(CSR_MCONTROL_MATCH, CSR_MCONTROL_MATCH_EQUAL)
},
.tdata1_ignore_mask = CSR_MCONTROL_MASKMAX(riscv_xlen(target))
.maskmax = CSR_MCONTROL_MASKMAX(riscv_xlen(target))
};
return result;
}
Expand Down Expand Up @@ -979,7 +994,7 @@ static struct match_triggers_tdata1_fields fill_match_triggers_tdata1_fields_t6(
.ge = field_value(CSR_MCONTROL6_MATCH, CSR_MCONTROL6_MATCH_GE),
.eq = field_value(CSR_MCONTROL6_MATCH, CSR_MCONTROL6_MATCH_EQUAL)
},
.tdata1_ignore_mask = 0
.maskmax = 0
};
return result;
}
Expand All @@ -999,7 +1014,7 @@ static int maybe_add_trigger_t2_t6_for_wp(struct target *target,
.tdata1 = fields.common | fields.size.any |
fields.chain.disable | fields.match.napot,
.tdata2 = trigger->address | ((trigger->length - 1) >> 1),
.tdata1_ignore_mask = fields.tdata1_ignore_mask
.maskmax = fields.maskmax
};
ret = try_setup_single_match_trigger(target, trigger, napot);
if (ret != ERROR_TARGET_RESOURCE_NOT_AVAILABLE)
Expand All @@ -1016,13 +1031,13 @@ static int maybe_add_trigger_t2_t6_for_wp(struct target *target,
.tdata1 = fields.common | fields.size.any | fields.chain.enable |
fields.match.ge,
.tdata2 = trigger->address,
.tdata1_ignore_mask = fields.tdata1_ignore_mask
.maskmax = fields.maskmax
};
struct trigger_request_info lt_2 = {
.tdata1 = fields.common | fields.size.any | fields.chain.disable |
fields.match.lt,
.tdata2 = trigger->address + trigger->length,
.tdata1_ignore_mask = fields.tdata1_ignore_mask
.maskmax = fields.maskmax
};
ret = try_setup_chained_match_triggers(target, trigger, ge_1, lt_2);
if (ret != ERROR_TARGET_RESOURCE_NOT_AVAILABLE)
Expand All @@ -1033,13 +1048,13 @@ static int maybe_add_trigger_t2_t6_for_wp(struct target *target,
.tdata1 = fields.common | fields.size.any | fields.chain.enable |
fields.match.lt,
.tdata2 = trigger->address + trigger->length,
.tdata1_ignore_mask = fields.tdata1_ignore_mask
.maskmax = fields.maskmax
};
struct trigger_request_info ge_2 = {
.tdata1 = fields.common | fields.size.any | fields.chain.disable |
fields.match.ge,
.tdata2 = trigger->address,
.tdata1_ignore_mask = fields.tdata1_ignore_mask
.maskmax = fields.maskmax
};
ret = try_setup_chained_match_triggers(target, trigger, lt_1, ge_2);
if (ret != ERROR_TARGET_RESOURCE_NOT_AVAILABLE)
Expand All @@ -1056,7 +1071,7 @@ static int maybe_add_trigger_t2_t6_for_wp(struct target *target,
.tdata1 = fields.common | fields.size.any | fields.chain.disable |
fields.match.eq,
.tdata2 = trigger->address,
.tdata1_ignore_mask = fields.tdata1_ignore_mask
.maskmax = fields.maskmax
};
ret = try_setup_single_match_trigger(target, trigger, eq);
if (ret != ERROR_OK)
Expand Down Expand Up @@ -1094,7 +1109,7 @@ static int maybe_add_trigger_t2_t6_for_bp(struct target *target,
.tdata1 = fields.common | fields.size.any | fields.chain.disable |
fields.match.eq,
.tdata2 = trigger->address,
.tdata1_ignore_mask = fields.tdata1_ignore_mask
.maskmax = fields.maskmax
};

return try_setup_single_match_trigger(target, trigger, eq);
Expand Down

0 comments on commit 2a520d3

Please sign in to comment.