Skip to content

Commit c2e204d

Browse files
author
zhusonghe
committed
target/riscv:Perform single step before resume if necessary
Two cases where single step is needed before resume: 1. ebreak used in software breakpoint; 2. a trigger that is taken just before the instruction that triggered it is retired. Signed-off-by: Songhe Zhu <[email protected]> Co-developed-by: Fei Gao <[email protected]> Co-developed-by: xiatianyi <[email protected]>
1 parent a4020f1 commit c2e204d

File tree

2 files changed

+35
-7
lines changed

2 files changed

+35
-7
lines changed

src/target/riscv/riscv.c

+32-7
Original file line numberDiff line numberDiff line change
@@ -623,12 +623,12 @@ static int find_first_trigger_by_id(struct target *target, int unique_id)
623623

624624
static unsigned int count_trailing_ones(riscv_reg_t reg)
625625
{
626-
assert(sizeof(riscv_reg_t) * 8 == 64);
627-
for (unsigned int i = 0; i < 64; i++) {
626+
const unsigned int riscv_reg_bits = sizeof(riscv_reg_t) * CHAR_BIT;
627+
for (unsigned int i = 0; i < riscv_reg_bits; i++) {
628628
if ((1 & (reg >> i)) == 0)
629629
return i;
630630
}
631-
return 64;
631+
return riscv_reg_bits;
632632
}
633633

634634
static int set_trigger(struct target *target, unsigned int idx, riscv_reg_t tdata1, riscv_reg_t tdata2)
@@ -1576,6 +1576,7 @@ static int riscv_trigger_detect_hit_bits(struct target *target, int64_t *unique_
15761576

15771577
// FIXME: Add hit bits support detection and caching
15781578
RISCV_INFO(r);
1579+
r->need_single_step = true;
15791580

15801581
riscv_reg_t tselect;
15811582
if (riscv_reg_get(target, &tselect, GDB_REGNO_TSELECT) != ERROR_OK)
@@ -1601,18 +1602,29 @@ static int riscv_trigger_detect_hit_bits(struct target *target, int64_t *unique_
16011602
break;
16021603
case CSR_TDATA1_TYPE_MCONTROL:
16031604
hit_mask = CSR_MCONTROL_HIT;
1605+
if (get_field(tdata1, CSR_MCONTROL_TIMING) == CSR_MCONTROL_TIMING_AFTER)
1606+
r->need_single_step = false;
16041607
break;
16051608
case CSR_TDATA1_TYPE_MCONTROL6:
16061609
hit_mask = CSR_MCONTROL6_HIT0 | CSR_MCONTROL6_HIT1;
1610+
int hit0 = get_field(tdata1, CSR_MCONTROL6_HIT0);
1611+
int hit1 = get_field(tdata1, CSR_MCONTROL6_HIT1);
1612+
int trigger_retired_info = (hit1 << 1) | hit0;
1613+
if (trigger_retired_info == CSR_MCONTROL6_HIT0_AFTER
1614+
|| trigger_retired_info == CSR_MCONTROL6_HIT0_IMMEDIATELY_AFTER)
1615+
r->need_single_step = false;
16071616
break;
16081617
case CSR_TDATA1_TYPE_ICOUNT:
16091618
hit_mask = CSR_ICOUNT_HIT;
1619+
r->need_single_step = false;
16101620
break;
16111621
case CSR_TDATA1_TYPE_ITRIGGER:
16121622
hit_mask = CSR_ITRIGGER_HIT(riscv_xlen(target));
1623+
r->need_single_step = false;
16131624
break;
16141625
case CSR_TDATA1_TYPE_ETRIGGER:
16151626
hit_mask = CSR_ETRIGGER_HIT(riscv_xlen(target));
1627+
r->need_single_step = false;
16161628
break;
16171629
default:
16181630
LOG_TARGET_DEBUG(target, "Trigger %u has unknown type %d", i, type);
@@ -2547,16 +2559,29 @@ static int resume_prep(struct target *target, int current,
25472559
assert(target->state == TARGET_HALTED);
25482560
RISCV_INFO(r);
25492561

2562+
riscv_reg_t dcsr;
2563+
if (riscv_reg_get(target, &dcsr, GDB_REGNO_DCSR) != ERROR_OK)
2564+
return ERROR_FAIL;
2565+
25502566
if (!current && riscv_reg_set(target, GDB_REGNO_PC, address) != ERROR_OK)
25512567
return ERROR_FAIL;
25522568

25532569
if (handle_breakpoints) {
25542570
/* To be able to run off a trigger, we perform a step operation and then
25552571
* resume. If handle_breakpoints is true then step temporarily disables
2556-
* pending breakpoints so we can safely perform the step. */
2557-
if (old_or_new_riscv_step_impl(target, current, address, handle_breakpoints,
2558-
false /* callbacks are not called */) != ERROR_OK)
2559-
return ERROR_FAIL;
2572+
* pending breakpoints so we can safely perform the step.
2573+
*
2574+
* Two cases where single step is needed before resuming:
2575+
* 1. ebreak used in software breakpoint;
2576+
* 2. a trigger that is taken just before the instruction that triggered it is retired.
2577+
*/
2578+
if (get_field(dcsr, CSR_DCSR_CAUSE) == CSR_DCSR_CAUSE_EBREAK
2579+
|| (get_field(dcsr, CSR_DCSR_CAUSE) == CSR_DCSR_CAUSE_TRIGGER
2580+
&& r->need_single_step)) {
2581+
if (old_or_new_riscv_step_impl(target, current, address, handle_breakpoints,
2582+
false /* callbacks are not called */) != ERROR_OK)
2583+
return ERROR_FAIL;
2584+
}
25602585
}
25612586

25622587
if (r->get_hart_state) {

src/target/riscv/riscv.h

+3
Original file line numberDiff line numberDiff line change
@@ -152,6 +152,9 @@ struct riscv_info {
152152
/* record the tinfo of each trigger */
153153
unsigned int trigger_tinfo[RISCV_MAX_TRIGGERS];
154154

155+
/* record the dpc that triggered it is retired. */
156+
bool need_single_step;
157+
155158
/* For each physical trigger contains:
156159
* -1: the hwbp is available
157160
* -4: The trigger is used by the itrigger command

0 commit comments

Comments
 (0)