From 2a520d39135870d352d9a768d8c81a254de7617d Mon Sep 17 00:00:00 2001 From: zhusonghe Date: Thu, 5 Sep 2024 21:27:26 +0800 Subject: [PATCH] target/riscv: Mismatch napot when mcontrol.maskmax is not expected Signed-off-by: zhusonghe --- src/target/riscv/riscv.c | 59 +++++++++++++++++++++++++--------------- 1 file changed, 37 insertions(+), 22 deletions(-) diff --git a/src/target/riscv/riscv.c b/src/target/riscv/riscv.c index f52ee00d2..39681a076 100644 --- a/src/target/riscv/riscv.c +++ b/src/target/riscv/riscv.c @@ -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 @@ -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, @@ -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) @@ -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) @@ -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; @@ -863,7 +878,7 @@ 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; @@ -871,7 +886,7 @@ static int try_setup_chained_match_triggers(struct target *target, 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; @@ -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, @@ -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; } @@ -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; } @@ -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) @@ -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) @@ -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) @@ -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) @@ -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);