Use match field for trigger (#725)

* Use match field for trigger

The watchpoint cannot capture all data modifications only through the
trigger of ANY SIZE and EQUAL, and an error will occur. This patch
accommodates watchpoints by adding more types of matches

Change-Id: I5c3c908dbd49ca47755b06f5cdbe451be3a81c8b
Signed-off-by: Xiang W <wxjstz@126.com>
Signed-off-by: Tim Newsome <tim@sifive.com>

* Update src/target/riscv/riscv.c

Co-authored-by: Jan Matyas <50193733+JanMatCodasip@users.noreply.github.com>
Signed-off-by: Xiang W <wxjstz@126.com>

* Update src/target/riscv/riscv.c

Co-authored-by: Jan Matyas <50193733+JanMatCodasip@users.noreply.github.com>
Signed-off-by: Xiang W <wxjstz@126.com>

* Update src/target/riscv/riscv.c

Co-authored-by: Jan Matyas <50193733+JanMatCodasip@users.noreply.github.com>
Signed-off-by: Xiang W <wxjstz@126.com>

* Update src/target/riscv/riscv.c

Co-authored-by: Jan Matyas <50193733+JanMatCodasip@users.noreply.github.com>
Signed-off-by: Xiang W <wxjstz@126.com>

* Update src/target/riscv/riscv.c

Co-authored-by: Jan Matyas <50193733+JanMatCodasip@users.noreply.github.com>
Signed-off-by: Xiang W <wxjstz@126.com>

* Update src/target/riscv/riscv.c

Co-authored-by: Jan Matyas <50193733+JanMatCodasip@users.noreply.github.com>
Signed-off-by: Xiang W <wxjstz@126.com>

* Update src/target/riscv/riscv.c

Change-Id: I3670347c4b00bf508373f7cc2f4950cbc09d6e2a
Signed-off-by: Xiang W <wxjstz@126.com>

* Add variable type trigger support

Change-Id: I60922c5f98574040b9a160e2aa0355871a581fe1
Signed-off-by: Xiang W <wxjstz@126.com>

* remove trailing whitespace

Change-Id: I168812e12b459ae3c4b3017c27a9b897e65d9f84
Signed-off-by: Xiang W <wxjstz@126.com>

* update triggers enumerate

Change-Id: I23a66afb0f772934b8911b522d0e4f116917519f
Signed-off-by: Xiang W <wxjstz@126.com>

Signed-off-by: Xiang W <wxjstz@126.com>
Signed-off-by: Tim Newsome <tim@sifive.com>
Co-authored-by: Jan Matyas <50193733+JanMatCodasip@users.noreply.github.com>
This commit is contained in:
Xiang W 2022-11-10 06:48:31 +08:00 committed by GitHub
parent ae3ad22311
commit 61f183fb25
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 307 additions and 195 deletions

View File

@ -87,6 +87,8 @@ enum gdb_regno {
GDB_REGNO_TSELECT = CSR_TSELECT + GDB_REGNO_CSR0,
GDB_REGNO_TDATA1 = CSR_TDATA1 + GDB_REGNO_CSR0,
GDB_REGNO_TDATA2 = CSR_TDATA2 + GDB_REGNO_CSR0,
GDB_REGNO_TDATA3 = CSR_TDATA3 + GDB_REGNO_CSR0,
GDB_REGNO_TINFO = CSR_TINFO + GDB_REGNO_CSR0,
GDB_REGNO_MISA = CSR_MISA + GDB_REGNO_CSR0,
GDB_REGNO_DPC = CSR_DPC + GDB_REGNO_CSR0,
GDB_REGNO_DCSR = CSR_DCSR + GDB_REGNO_CSR0,

View File

@ -462,9 +462,77 @@ static void trigger_from_breakpoint(struct trigger *trigger,
trigger->unique_id = breakpoint->unique_id;
}
static int maybe_add_trigger_t1(struct target *target,
struct trigger *trigger, uint64_t tdata1)
static bool can_use_napot_match(struct trigger *trigger, riscv_reg_t *tdata2)
{
riscv_reg_t addr = trigger->address;
riscv_reg_t size = trigger->length;
bool sizePowerOf2 = (size & (size - 1)) == 0;
bool addrAligned = (addr & (size - 1)) == 0;
if (size > 1 && sizePowerOf2 && addrAligned) {
if (tdata2)
*tdata2 = addr | ((size - 1) >> 1);
return true;
}
return false;
}
static int find_trigger(struct target *target, int type, bool chained, int *idx)
{
RISCV_INFO(r);
unsigned int num_found = 0;
unsigned int num_required = chained ? 2 : 1;
for (unsigned i = 0; i < r->trigger_count; i++) {
if (r->trigger_unique_id[i] == -1) {
if (r->trigger_tinfo[i] & (1 << type)) {
num_found++;
bool done = (num_required == num_found);
if (done) {
/* Found num_required consecutive free triggers - success, done. */
if (idx)
*idx = i - (num_required - 1);
return ERROR_OK;
}
/* Found a trigger but need more consecutive ones */
continue;
}
}
/* Trigger already occupied or incompatible type.
* Reset the counter of found consecutive triggers */
num_found = 0;
}
return ERROR_FAIL;
}
static int set_trigger(struct target *target, int idx, riscv_reg_t tdata1, riscv_reg_t tdata2)
{
riscv_reg_t tdata1_rb;
if (riscv_set_register(target, GDB_REGNO_TSELECT, idx) != ERROR_OK)
return ERROR_FAIL;
if (riscv_set_register(target, GDB_REGNO_TDATA1, tdata1) != ERROR_OK)
return ERROR_FAIL;
if (riscv_get_register(target, &tdata1_rb, GDB_REGNO_TDATA1) != ERROR_OK)
return ERROR_FAIL;
if (tdata1 != tdata1_rb) {
LOG_DEBUG("Trigger doesn't support what we need; After writing 0x%"
PRIx64 " to tdata1 it contains 0x%" PRIx64,
tdata1, tdata1_rb);
riscv_set_register(target, GDB_REGNO_TDATA1, 0);
return ERROR_TARGET_RESOURCE_NOT_AVAILABLE;
}
LOG_DEBUG("tdata1=0x%" PRIx64, tdata1_rb);
if (riscv_set_register(target, GDB_REGNO_TDATA2, tdata2) != ERROR_OK)
return ERROR_FAIL;
return ERROR_OK;
}
static int maybe_add_trigger_t1(struct target *target, struct trigger *trigger)
{
int idx, ret;
riscv_reg_t tdata1, tdata2;
RISCV_INFO(r);
const uint32_t bpcontrol_x = 1<<0;
@ -477,203 +545,227 @@ static int maybe_add_trigger_t1(struct target *target,
const uint32_t bpcontrol_bpmatch = 0xf << 7;
const uint32_t bpcontrol_bpaction = 0xff << 11;
ret = find_trigger(target, CSR_TDATA1_TYPE_LEGACY, false, &idx);
if (ret != ERROR_OK)
return ret;
if (riscv_get_register(target, &tdata1, GDB_REGNO_TDATA1) != ERROR_OK)
return ERROR_FAIL;
if (tdata1 & (bpcontrol_r | bpcontrol_w | bpcontrol_x)) {
/* Trigger is already in use, presumably by user code. */
return ERROR_TARGET_RESOURCE_NOT_AVAILABLE;
}
tdata1 = 0;
tdata1 = set_field(tdata1, bpcontrol_r, trigger->read);
tdata1 = set_field(tdata1, bpcontrol_w, trigger->write);
tdata1 = set_field(tdata1, bpcontrol_x, trigger->execute);
tdata1 = set_field(tdata1, bpcontrol_u,
!!(r->misa & BIT('U' - 'A')));
tdata1 = set_field(tdata1, bpcontrol_s,
!!(r->misa & BIT('S' - 'A')));
tdata1 = set_field(tdata1, bpcontrol_h,
!!(r->misa & BIT('H' - 'A')));
tdata1 |= bpcontrol_m;
tdata1 = set_field(tdata1, bpcontrol_bpmatch, 0); /* exact match */
tdata1 = set_field(tdata1, bpcontrol_u, !!(r->misa & BIT('U' - 'A')));
tdata1 = set_field(tdata1, bpcontrol_s, !!(r->misa & BIT('S' - 'A')));
tdata1 = set_field(tdata1, bpcontrol_h, !!(r->misa & BIT('H' - 'A')));
tdata1 = set_field(tdata1, bpcontrol_m, 1);
tdata1 = set_field(tdata1, bpcontrol_bpaction, 0); /* cause bp exception */
riscv_set_register(target, GDB_REGNO_TDATA1, tdata1);
riscv_reg_t tdata1_rb;
if (riscv_get_register(target, &tdata1_rb, GDB_REGNO_TDATA1) != ERROR_OK)
return ERROR_FAIL;
LOG_DEBUG("tdata1=0x%" PRIx64, tdata1_rb);
if (tdata1 != tdata1_rb) {
LOG_DEBUG("Trigger doesn't support what we need; After writing 0x%"
PRIx64 " to tdata1 it contains 0x%" PRIx64,
tdata1, tdata1_rb);
riscv_set_register(target, GDB_REGNO_TDATA1, 0);
return ERROR_TARGET_RESOURCE_NOT_AVAILABLE;
}
riscv_set_register(target, GDB_REGNO_TDATA2, trigger->address);
tdata1 = set_field(tdata1, bpcontrol_bpmatch, 0); /* exact match */
tdata2 = trigger->address;
ret = set_trigger(target, idx, tdata1, tdata2);
if (ret != ERROR_OK)
return ret;
r->trigger_unique_id[idx] = trigger->unique_id;
return ERROR_OK;
}
static int maybe_add_trigger_t2(struct target *target,
struct trigger *trigger, uint64_t tdata1)
static int maybe_add_trigger_t2(struct target *target, struct trigger *trigger)
{
int idx, ret;
riscv_reg_t tdata1, tdata2;
RISCV_INFO(r);
/* tselect is already set */
if (tdata1 & (CSR_MCONTROL_EXECUTE | CSR_MCONTROL_STORE | CSR_MCONTROL_LOAD)) {
/* Trigger is already in use, presumably by user code. */
return ERROR_TARGET_RESOURCE_NOT_AVAILABLE;
}
tdata1 = 0;
tdata1 = set_field(tdata1, CSR_MCONTROL_TYPE(riscv_xlen(target)), 2);
tdata1 = set_field(tdata1, CSR_MCONTROL_DMODE(riscv_xlen(target)), 1);
tdata1 = set_field(tdata1, CSR_MCONTROL_ACTION, CSR_MCONTROL_ACTION_DEBUG_MODE);
tdata1 = set_field(tdata1, CSR_MCONTROL_M, 1);
tdata1 = set_field(tdata1, CSR_MCONTROL_S, !!(r->misa & (1 << ('S' - 'A'))));
tdata1 = set_field(tdata1, CSR_MCONTROL_U, !!(r->misa & (1 << ('U' - 'A'))));
tdata1 = set_field(tdata1, CSR_MCONTROL_EXECUTE, trigger->execute);
tdata1 = set_field(tdata1, CSR_MCONTROL_LOAD, trigger->read);
tdata1 = set_field(tdata1, CSR_MCONTROL_STORE, trigger->write);
tdata1 = set_field(tdata1, CSR_MCONTROL_SIZELO, CSR_MCONTROL_SIZELO_ANY & 3);
tdata1 = set_field(tdata1, CSR_MCONTROL_SIZEHI, (CSR_MCONTROL_SIZELO_ANY >> 2) & 3);
/* address/data match trigger */
tdata1 |= CSR_MCONTROL_DMODE(riscv_xlen(target));
tdata1 = set_field(tdata1, CSR_MCONTROL_ACTION,
CSR_MCONTROL_ACTION_DEBUG_MODE);
if (trigger->execute || trigger->length == 1)
goto MATCH_EQUAL;
if (!can_use_napot_match(trigger, &tdata2))
goto MATCH_GE_LT;
ret = find_trigger(target, CSR_TDATA1_TYPE_MCONTROL, false, &idx);
if (ret != ERROR_OK)
return ret;
tdata1 = set_field(tdata1, CSR_MCONTROL_MATCH, CSR_MCONTROL_MATCH_NAPOT);
tdata1 = set_field(tdata1, CSR_MCONTROL_CHAIN, CSR_MCONTROL_CHAIN_DISABLED);
ret = set_trigger(target, idx, tdata1, tdata2);
if (ret != ERROR_OK) {
if (ret == ERROR_TARGET_RESOURCE_NOT_AVAILABLE)
goto MATCH_GE_LT; /* Fallback to chained MATCH using GT and LE */
return ret;
}
r->trigger_unique_id[idx] = trigger->unique_id;
return ERROR_OK;
MATCH_GE_LT:
ret = find_trigger(target, CSR_TDATA1_TYPE_MCONTROL, true, &idx);
if (ret != ERROR_OK)
return ret;
tdata1 = set_field(tdata1, CSR_MCONTROL_MATCH, CSR_MCONTROL_MATCH_GE);
tdata1 = set_field(tdata1, CSR_MCONTROL_CHAIN, CSR_MCONTROL_CHAIN_ENABLED);
tdata2 = trigger->address;
ret = set_trigger(target, idx, tdata1, tdata2);
if (ret != ERROR_OK) {
if (ret == ERROR_TARGET_RESOURCE_NOT_AVAILABLE)
goto MATCH_EQUAL; /* Fallback to EQUAL MATCH */
return ret;
}
tdata1 = set_field(tdata1, CSR_MCONTROL_MATCH, CSR_MCONTROL_MATCH_LT);
tdata1 = set_field(tdata1, CSR_MCONTROL_CHAIN, CSR_MCONTROL_CHAIN_DISABLED);
tdata2 = trigger->address + trigger->length;
ret = set_trigger(target, idx + 1, tdata1, tdata2);
if (ret != ERROR_OK) {
set_trigger(target, idx, 0, 0); /* Undo the setting of the previous trigger*/
if (ret == ERROR_TARGET_RESOURCE_NOT_AVAILABLE)
goto MATCH_EQUAL; /* Fallback to EQUAL MATCH */
return ret;
}
r->trigger_unique_id[idx] = trigger->unique_id;
r->trigger_unique_id[idx + 1] = trigger->unique_id;
return ERROR_OK;
MATCH_EQUAL:
ret = find_trigger(target, CSR_TDATA1_TYPE_MCONTROL, false, &idx);
if (ret != ERROR_OK)
return ret;
tdata1 = set_field(tdata1, CSR_MCONTROL_MATCH, CSR_MCONTROL_MATCH_EQUAL);
tdata1 |= CSR_MCONTROL_M;
if (r->misa & (1 << ('S' - 'A')))
tdata1 |= CSR_MCONTROL_S;
if (r->misa & (1 << ('U' - 'A')))
tdata1 |= CSR_MCONTROL_U;
if (trigger->execute)
tdata1 |= CSR_MCONTROL_EXECUTE;
if (trigger->read)
tdata1 |= CSR_MCONTROL_LOAD;
if (trigger->write)
tdata1 |= CSR_MCONTROL_STORE;
riscv_set_register(target, GDB_REGNO_TDATA1, tdata1);
uint64_t tdata1_rb;
int result = riscv_get_register(target, &tdata1_rb, GDB_REGNO_TDATA1);
if (result != ERROR_OK)
return result;
LOG_DEBUG("tdata1=0x%" PRIx64, tdata1_rb);
if (tdata1 != tdata1_rb) {
LOG_DEBUG("Trigger doesn't support what we need; After writing 0x%"
PRIx64 " to tdata1 it contains 0x%" PRIx64,
tdata1, tdata1_rb);
riscv_set_register(target, GDB_REGNO_TDATA1, 0);
return ERROR_TARGET_RESOURCE_NOT_AVAILABLE;
if (trigger->length == 1) {
tdata1 = set_field(tdata1, CSR_MCONTROL_SIZELO, CSR_MCONTROL_SIZELO_8BIT & 3);
tdata1 = set_field(tdata1, CSR_MCONTROL_SIZEHI, (CSR_MCONTROL_SIZELO_8BIT >> 2) & 3);
}
riscv_set_register(target, GDB_REGNO_TDATA2, trigger->address);
tdata1 = set_field(tdata1, CSR_MCONTROL_CHAIN, CSR_MCONTROL_CHAIN_DISABLED);
tdata2 = trigger->address;
ret = set_trigger(target, idx, tdata1, tdata2);
if (ret != ERROR_OK)
return ret;
r->trigger_unique_id[idx] = trigger->unique_id;
return ERROR_OK;
}
static int maybe_add_trigger_t6(struct target *target,
struct trigger *trigger, uint64_t tdata1)
static int maybe_add_trigger_t6(struct target *target, struct trigger *trigger)
{
int idx, ret;
riscv_reg_t tdata1, tdata2;
RISCV_INFO(r);
/* tselect is already set */
if (tdata1 & (CSR_MCONTROL6_EXECUTE | CSR_MCONTROL6_STORE | CSR_MCONTROL6_LOAD)) {
/* Trigger is already in use, presumably by user code. */
return ERROR_TARGET_RESOURCE_NOT_AVAILABLE;
}
tdata1 = 0;
tdata1 = set_field(tdata1, CSR_MCONTROL6_TYPE(riscv_xlen(target)), 6);
tdata1 = set_field(tdata1, CSR_MCONTROL6_DMODE(riscv_xlen(target)), 1);
tdata1 = set_field(tdata1, CSR_MCONTROL6_ACTION, CSR_MCONTROL6_ACTION_DEBUG_MODE);
tdata1 = set_field(tdata1, CSR_MCONTROL6_M, 1);
tdata1 = set_field(tdata1, CSR_MCONTROL6_S, !!(r->misa & (1 << ('S' - 'A'))));
tdata1 = set_field(tdata1, CSR_MCONTROL6_U, !!(r->misa & (1 << ('U' - 'A'))));
tdata1 = set_field(tdata1, CSR_MCONTROL6_EXECUTE, trigger->execute);
tdata1 = set_field(tdata1, CSR_MCONTROL6_LOAD, trigger->read);
tdata1 = set_field(tdata1, CSR_MCONTROL6_STORE, trigger->write);
tdata1 = set_field(tdata1, CSR_MCONTROL6_SIZE, CSR_MCONTROL6_SIZE_ANY);
/* address/data match trigger */
tdata1 |= CSR_MCONTROL6_DMODE(riscv_xlen(target));
tdata1 = set_field(tdata1, CSR_MCONTROL6_ACTION,
CSR_MCONTROL6_ACTION_DEBUG_MODE);
if (trigger->execute || trigger->length == 1)
goto MATCH_EQUAL;
if (!can_use_napot_match(trigger, &tdata2))
goto MATCH_GE_LT;
ret = find_trigger(target, CSR_TDATA1_TYPE_MCONTROL6, false, &idx);
if (ret != ERROR_OK)
return ret;
tdata1 = set_field(tdata1, CSR_MCONTROL6_MATCH, CSR_MCONTROL6_MATCH_NAPOT);
tdata1 = set_field(tdata1, CSR_MCONTROL6_CHAIN, CSR_MCONTROL6_CHAIN_DISABLED);
ret = set_trigger(target, idx, tdata1, tdata2);
if (ret != ERROR_OK) {
if (ret == ERROR_TARGET_RESOURCE_NOT_AVAILABLE)
goto MATCH_GE_LT; /* Fallback to chained MATCH using GT and LE */
return ret;
}
r->trigger_unique_id[idx] = trigger->unique_id;
return ERROR_OK;
MATCH_GE_LT:
ret = find_trigger(target, CSR_TDATA1_TYPE_MCONTROL6, true, &idx);
if (ret != ERROR_OK)
return ret;
tdata1 = set_field(tdata1, CSR_MCONTROL6_MATCH, CSR_MCONTROL6_MATCH_GE);
tdata1 = set_field(tdata1, CSR_MCONTROL6_CHAIN, CSR_MCONTROL6_CHAIN_ENABLED);
tdata2 = trigger->address;
ret = set_trigger(target, idx, tdata1, tdata2);
if (ret != ERROR_OK) {
if (ret == ERROR_TARGET_RESOURCE_NOT_AVAILABLE)
goto MATCH_EQUAL; /* Fallback to EQUAL MATCH */
return ret;
}
tdata1 = set_field(tdata1, CSR_MCONTROL6_MATCH, CSR_MCONTROL6_MATCH_LT);
tdata1 = set_field(tdata1, CSR_MCONTROL6_CHAIN, CSR_MCONTROL6_CHAIN_DISABLED);
tdata2 = trigger->address + trigger->length;
ret = set_trigger(target, idx + 1, tdata1, tdata2);
if (ret != ERROR_OK) {
set_trigger(target, idx, 0, 0); /* Undo the setting of the previous trigger*/
if (ret == ERROR_TARGET_RESOURCE_NOT_AVAILABLE)
goto MATCH_EQUAL; /* Fallback to EQUAL MATCH */
return ret;
}
r->trigger_unique_id[idx] = trigger->unique_id;
r->trigger_unique_id[idx + 1] = trigger->unique_id;
return ERROR_OK;
MATCH_EQUAL:
ret = find_trigger(target, CSR_TDATA1_TYPE_MCONTROL6, false, &idx);
if (ret != ERROR_OK)
return ret;
tdata1 = set_field(tdata1, CSR_MCONTROL6_MATCH, CSR_MCONTROL6_MATCH_EQUAL);
tdata1 |= CSR_MCONTROL6_M;
if (r->misa & (1 << ('H' - 'A')))
tdata1 |= CSR_MCONTROL6_VS | CSR_MCONTROL6_VU;
if (r->misa & (1 << ('S' - 'A')))
tdata1 |= CSR_MCONTROL6_S;
if (r->misa & (1 << ('U' - 'A')))
tdata1 |= CSR_MCONTROL6_U;
if (trigger->execute)
tdata1 |= CSR_MCONTROL6_EXECUTE;
if (trigger->read)
tdata1 |= CSR_MCONTROL6_LOAD;
if (trigger->write)
tdata1 |= CSR_MCONTROL6_STORE;
riscv_set_register(target, GDB_REGNO_TDATA1, tdata1);
uint64_t tdata1_rb;
int result = riscv_get_register(target, &tdata1_rb, GDB_REGNO_TDATA1);
if (result != ERROR_OK)
return result;
LOG_DEBUG("tdata1=0x%" PRIx64, tdata1_rb);
if (tdata1 != tdata1_rb) {
LOG_DEBUG("Trigger doesn't support what we need; After writing 0x%"
PRIx64 " to tdata1 it contains 0x%" PRIx64,
tdata1, tdata1_rb);
riscv_set_register(target, GDB_REGNO_TDATA1, 0);
return ERROR_TARGET_RESOURCE_NOT_AVAILABLE;
}
riscv_set_register(target, GDB_REGNO_TDATA2, trigger->address);
if (trigger->length == 1)
tdata1 = set_field(tdata1, CSR_MCONTROL6_SIZE, CSR_MCONTROL6_SIZE_8BIT);
tdata1 = set_field(tdata1, CSR_MCONTROL6_CHAIN, CSR_MCONTROL6_CHAIN_DISABLED);
tdata2 = trigger->address;
ret = set_trigger(target, idx, tdata1, tdata2);
if (ret != ERROR_OK)
return ret;
r->trigger_unique_id[idx] = trigger->unique_id;
return ERROR_OK;
}
static int add_trigger(struct target *target, struct trigger *trigger)
{
RISCV_INFO(r);
int ret;
riscv_reg_t tselect;
if (riscv_enumerate_triggers(target) != ERROR_OK)
return ERROR_FAIL;
riscv_reg_t tselect;
if (riscv_get_register(target, &tselect, GDB_REGNO_TSELECT) != ERROR_OK)
return ERROR_FAIL;
int result = riscv_get_register(target, &tselect, GDB_REGNO_TSELECT);
if (result != ERROR_OK)
return result;
unsigned int i;
for (i = 0; i < r->trigger_count; i++) {
if (r->trigger_unique_id[i] != -1)
continue;
riscv_set_register(target, GDB_REGNO_TSELECT, i);
uint64_t tdata1;
int result = riscv_get_register(target, &tdata1, GDB_REGNO_TDATA1);
if (result != ERROR_OK)
return result;
int type = get_field(tdata1, CSR_TDATA1_TYPE(riscv_xlen(target)));
result = ERROR_OK;
switch (type) {
case 1:
result = maybe_add_trigger_t1(target, trigger, tdata1);
break;
case 2:
result = maybe_add_trigger_t2(target, trigger, tdata1);
break;
case 6:
result = maybe_add_trigger_t6(target, trigger, tdata1);
break;
default:
LOG_DEBUG("trigger %d has unknown type %d", i, type);
continue;
}
if (result != ERROR_OK)
continue;
LOG_DEBUG("[%d] Using trigger %d (type %d) for bp %d", target->coreid,
i, type, trigger->unique_id);
r->trigger_unique_id[i] = trigger->unique_id;
break;
}
do {
ret = maybe_add_trigger_t1(target, trigger);
if (ret == ERROR_OK)
break;
ret = maybe_add_trigger_t2(target, trigger);
if (ret == ERROR_OK)
break;
ret = maybe_add_trigger_t6(target, trigger);
if (ret == ERROR_OK)
break;
} while (0);
riscv_set_register(target, GDB_REGNO_TSELECT, tselect);
if (i >= r->trigger_count) {
LOG_ERROR("Couldn't find an available hardware trigger.");
return ERROR_TARGET_RESOURCE_NOT_AVAILABLE;
}
return ERROR_OK;
return ret;
}
/**
@ -849,27 +941,29 @@ static int remove_trigger(struct target *target, struct trigger *trigger)
if (riscv_enumerate_triggers(target) != ERROR_OK)
return ERROR_FAIL;
unsigned int i;
for (i = 0; i < r->trigger_count; i++) {
if (r->trigger_unique_id[i] == trigger->unique_id)
break;
}
if (i >= r->trigger_count) {
LOG_ERROR("Couldn't find the hardware resources used by hardware "
"trigger.");
return ERROR_TARGET_RESOURCE_NOT_AVAILABLE;
}
LOG_DEBUG("[%d] Stop using resource %d for bp %d", target->coreid, i,
trigger->unique_id);
riscv_reg_t tselect;
int result = riscv_get_register(target, &tselect, GDB_REGNO_TSELECT);
if (result != ERROR_OK)
return result;
riscv_set_register(target, GDB_REGNO_TSELECT, i);
riscv_set_register(target, GDB_REGNO_TDATA1, 0);
bool done = false;
for (unsigned int i = 0; i < r->trigger_count; i++) {
if (r->trigger_unique_id[i] == trigger->unique_id) {
riscv_set_register(target, GDB_REGNO_TSELECT, i);
riscv_set_register(target, GDB_REGNO_TDATA1, 0);
r->trigger_unique_id[i] = -1;
LOG_TARGET_DEBUG(target, "Stop using resource %d for bp %d",
i, trigger->unique_id);
done = true;
}
}
if (!done) {
LOG_ERROR("Couldn't find the hardware resources used by hardware "
"trigger.");
return ERROR_TARGET_RESOURCE_NOT_AVAILABLE;
}
riscv_set_register(target, GDB_REGNO_TSELECT, tselect);
r->trigger_unique_id[i] = -1;
return ERROR_OK;
}
@ -3912,29 +4006,42 @@ int riscv_enumerate_triggers(struct target *target)
tselect_rb &= ~(1ULL << (riscv_xlen(target) - 1));
if (tselect_rb != t)
break;
uint64_t tdata1;
result = riscv_get_register(target, &tdata1, GDB_REGNO_TDATA1);
if (result != ERROR_OK)
return result;
int type = get_field(tdata1, CSR_TDATA1_TYPE(riscv_xlen(target)));
if (type == 0)
break;
switch (type) {
case 1:
/* On these older cores we don't support software using
* triggers. */
riscv_set_register(target, GDB_REGNO_TDATA1, 0);
uint64_t tinfo;
result = riscv_get_register(target, &tinfo, GDB_REGNO_TINFO);
if (result == ERROR_OK) {
/* tinfo == 0 invalid tinfo
* tinfo == 1 trigger doesnt exist */
if (tinfo == 0 || tinfo == 1)
break;
case 2:
if (tdata1 & CSR_MCONTROL_DMODE(riscv_xlen(target)))
r->trigger_tinfo[t] = tinfo;
} else {
uint64_t tdata1;
result = riscv_get_register(target, &tdata1, GDB_REGNO_TDATA1);
if (result != ERROR_OK)
return result;
int type = get_field(tdata1, CSR_TDATA1_TYPE(riscv_xlen(target)));
if (type == 0)
break;
switch (type) {
case 1:
/* On these older cores we don't support software using
* triggers. */
riscv_set_register(target, GDB_REGNO_TDATA1, 0);
break;
case 6:
if (tdata1 & CSR_MCONTROL6_DMODE(riscv_xlen(target)))
riscv_set_register(target, GDB_REGNO_TDATA1, 0);
break;
break;
case 2:
if (tdata1 & CSR_MCONTROL_DMODE(riscv_xlen(target)))
riscv_set_register(target, GDB_REGNO_TDATA1, 0);
break;
case 6:
if (tdata1 & CSR_MCONTROL6_DMODE(riscv_xlen(target)))
riscv_set_register(target, GDB_REGNO_TDATA1, 0);
break;
}
r->trigger_tinfo[t] = 1 << type;
}
LOG_TARGET_DEBUG(target, "Trigger %u: supported types (mask) = 0x%08x", t, r->trigger_tinfo[t]);
}
riscv_set_register(target, GDB_REGNO_TSELECT, tselect);

View File

@ -112,6 +112,9 @@ typedef struct {
/* The number of triggers per hart. */
unsigned int trigger_count;
/* record the tinfo of each trigger */
unsigned int trigger_tinfo[RISCV_MAX_TRIGGERS];
/* For each physical trigger, contains -1 if the hwbp is available, or the
* unique_id of the breakpoint/watchpoint that is using it.
* Note that in RTOS mode the triggers are the same across all harts the