Skip to content

Commit 1062402

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 1062402

File tree

2 files changed

+125
-7
lines changed

2 files changed

+125
-7
lines changed

src/target/riscv/riscv.c

+122-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)
@@ -1561,6 +1561,100 @@ int riscv_remove_watchpoint(struct target *target,
15611561
return ERROR_OK;
15621562
}
15631563

1564+
typedef enum {
1565+
M_HIT_ERROR,
1566+
M_HIT_NOT_SUPPORTED,
1567+
M_NOT_HIT,
1568+
M_HIT
1569+
} mctrlhitstatus;
1570+
1571+
static mctrlhitstatus check_mcontrol_hit_status(struct target *target, riscv_reg_t tdata1,
1572+
uint64_t hit_mask)
1573+
{
1574+
if (tdata1 & hit_mask)
1575+
return M_HIT;
1576+
const riscv_reg_t tdata1_test = set_field(tdata1, CSR_MCONTROL_HIT, 1);
1577+
if (riscv_reg_set(target, GDB_REGNO_TDATA1, tdata1_test) != ERROR_OK)
1578+
return M_HIT_ERROR;
1579+
riscv_reg_t tdata1_test_rb;
1580+
if (riscv_reg_get(target, &tdata1_test_rb, GDB_REGNO_TDATA1) != ERROR_OK)
1581+
return M_HIT_ERROR;
1582+
int tdata1_test_hit = get_field(tdata1_test, CSR_MCONTROL_HIT);
1583+
int tdata1_test_rb_hit = get_field(tdata1_test_rb, CSR_MCONTROL_HIT);
1584+
if (tdata1_test_rb_hit != tdata1_test_hit)
1585+
return M_HIT_NOT_SUPPORTED;
1586+
1587+
if (riscv_reg_set(target, GDB_REGNO_TDATA1, tdata1_test_rb & ~hit_mask) != ERROR_OK)
1588+
return M_HIT_ERROR;
1589+
return M_NOT_HIT;
1590+
}
1591+
1592+
typedef enum {
1593+
M6_HIT_ERROR,
1594+
M6_HIT_NOT_SUPPORTED,
1595+
M6_NOT_HIT,
1596+
M6_HIT_BEFORE,
1597+
M6_HIT_AFTER,
1598+
M6_HIT_IMM_AFTER
1599+
} mctrl6hitstatus;
1600+
1601+
static mctrl6hitstatus check_mcontrol6_hit_status(struct target *target,
1602+
riscv_reg_t tdata1, uint64_t hit_mask)
1603+
{
1604+
int hit0 = get_field(tdata1, CSR_MCONTROL6_HIT0);
1605+
int hit1 = get_field(tdata1, CSR_MCONTROL6_HIT1);
1606+
int hit_info = (hit1 << 1) | hit0;
1607+
if (hit_info == CSR_MCONTROL6_HIT0_BEFORE)
1608+
return M6_HIT_BEFORE;
1609+
1610+
if (hit_info == CSR_MCONTROL6_HIT0_AFTER)
1611+
return M6_HIT_AFTER;
1612+
1613+
if (hit_info == CSR_MCONTROL6_HIT0_IMMEDIATELY_AFTER)
1614+
return M6_HIT_IMM_AFTER;
1615+
1616+
if (hit_info == CSR_MCONTROL6_HIT0_FALSE) {
1617+
/* Check timing "before" support. */
1618+
riscv_reg_t tdata1_hit_before_test = set_field(tdata1, CSR_MCONTROL6_HIT0, 1);
1619+
if (riscv_reg_set(target, GDB_REGNO_TDATA1, tdata1_hit_before_test) != ERROR_OK)
1620+
return M6_HIT_ERROR;
1621+
riscv_reg_t tdata1_test_rb;
1622+
if (riscv_reg_get(target, &tdata1_test_rb, GDB_REGNO_TDATA1) != ERROR_OK)
1623+
return M6_HIT_ERROR;
1624+
if (tdata1_test_rb == tdata1_hit_before_test) {
1625+
if (riscv_reg_set(target, GDB_REGNO_TDATA1, tdata1_test_rb & ~hit_mask) != ERROR_OK)
1626+
return M6_HIT_ERROR;
1627+
return M6_NOT_HIT;
1628+
}
1629+
1630+
/* Check timing "after" support. */
1631+
riscv_reg_t tdata1_hit_after_test = set_field(tdata1, CSR_MCONTROL6_HIT1, 1);
1632+
if (riscv_reg_set(target, GDB_REGNO_TDATA1, tdata1_hit_after_test) != ERROR_OK)
1633+
return M6_HIT_ERROR;
1634+
if (riscv_reg_get(target, &tdata1_test_rb, GDB_REGNO_TDATA1) != ERROR_OK)
1635+
return M6_HIT_ERROR;
1636+
if (tdata1_test_rb == tdata1_hit_after_test) {
1637+
if (riscv_reg_set(target, GDB_REGNO_TDATA1, tdata1_test_rb & ~hit_mask) != ERROR_OK)
1638+
return M6_HIT_ERROR;
1639+
return M6_NOT_HIT;
1640+
}
1641+
1642+
/* Check timing "imm after" support. */
1643+
riscv_reg_t tdata1_hit_imm_after_test = tdata1_hit_before_test | tdata1_hit_after_test;
1644+
if (riscv_reg_set(target, GDB_REGNO_TDATA1, tdata1_hit_imm_after_test) != ERROR_OK)
1645+
return M6_HIT_ERROR;
1646+
if (riscv_reg_get(target, &tdata1_test_rb, GDB_REGNO_TDATA1) != ERROR_OK)
1647+
return M6_HIT_ERROR;
1648+
if (tdata1_test_rb == tdata1_hit_imm_after_test) {
1649+
if (riscv_reg_set(target, GDB_REGNO_TDATA1, tdata1_test_rb & ~hit_mask) != ERROR_OK)
1650+
return M6_HIT_ERROR;
1651+
return M6_NOT_HIT;
1652+
}
1653+
}
1654+
return M6_HIT_NOT_SUPPORTED;
1655+
}
1656+
1657+
15641658
/**
15651659
* Look at the trigger hit bits to find out which trigger is the reason we're
15661660
* halted. Sets *unique_id to the unique ID of that trigger. If *unique_id is
@@ -1576,6 +1670,7 @@ static int riscv_trigger_detect_hit_bits(struct target *target, int64_t *unique_
15761670

15771671
// FIXME: Add hit bits support detection and caching
15781672
RISCV_INFO(r);
1673+
r->need_single_step = false;
15791674

15801675
riscv_reg_t tselect;
15811676
if (riscv_reg_get(target, &tselect, GDB_REGNO_TSELECT) != ERROR_OK)
@@ -1601,9 +1696,20 @@ static int riscv_trigger_detect_hit_bits(struct target *target, int64_t *unique_
16011696
break;
16021697
case CSR_TDATA1_TYPE_MCONTROL:
16031698
hit_mask = CSR_MCONTROL_HIT;
1699+
mctrlhitstatus hit_status = check_mcontrol_hit_status(target, tdata1, hit_mask);
1700+
if (hit_status == M_HIT_ERROR)
1701+
return ERROR_FAIL;
1702+
if (get_field(tdata1, CSR_MCONTROL_TIMING) == CSR_MCONTROL_TIMING_BEFORE
1703+
&& (hit_status == M_HIT_NOT_SUPPORTED || hit_status == M_HIT))
1704+
r->need_single_step = true;
16041705
break;
16051706
case CSR_TDATA1_TYPE_MCONTROL6:
16061707
hit_mask = CSR_MCONTROL6_HIT0 | CSR_MCONTROL6_HIT1;
1708+
mctrl6hitstatus hit12_status = check_mcontrol6_hit_status(target, tdata1, hit_mask);
1709+
if (hit12_status == M6_HIT_ERROR)
1710+
return ERROR_FAIL;
1711+
if (hit12_status == M6_HIT_BEFORE || hit12_status == M6_HIT_NOT_SUPPORTED)
1712+
r->need_single_step = true;
16071713
break;
16081714
case CSR_TDATA1_TYPE_ICOUNT:
16091715
hit_mask = CSR_ICOUNT_HIT;
@@ -2553,10 +2659,19 @@ static int resume_prep(struct target *target, int current,
25532659
if (handle_breakpoints) {
25542660
/* To be able to run off a trigger, we perform a step operation and then
25552661
* 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;
2662+
* pending breakpoints so we can safely perform the step.
2663+
*
2664+
* Two cases where single step is needed before resuming:
2665+
* 1. ebreak used in software breakpoint;
2666+
* 2. a trigger that is taken just before the instruction that triggered it is retired.
2667+
*/
2668+
if (target->debug_reason == DBG_REASON_BREAKPOINT
2669+
|| (target->debug_reason == DBG_REASON_WATCHPOINT
2670+
&& r->need_single_step)) {
2671+
if (old_or_new_riscv_step_impl(target, current, address, handle_breakpoints,
2672+
false /* callbacks are not called */) != ERROR_OK)
2673+
return ERROR_FAIL;
2674+
}
25602675
}
25612676

25622677
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)