Skip to content

Commit 9cd9805

Browse files
committed
Set hardware triggers on all harts.
Right now we're using "threads" to represent harts. gdb/OpenOCD assume there's only one set of hardware breakpoints among all threads. Make it so.
1 parent 1051835 commit 9cd9805

File tree

1 file changed

+69
-33
lines changed

1 file changed

+69
-33
lines changed

src/target/riscv/riscv-013.c

Lines changed: 69 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -579,6 +579,10 @@ static int register_write_direct(struct target *target, unsigned number,
579579
uint64_t value)
580580
{
581581
struct riscv_program program;
582+
583+
LOG_DEBUG("[%d] reg[0x%x] <- 0x%" PRIx64, riscv_current_hartid(target),
584+
number, value);
585+
582586
riscv_program_init(&program, target);
583587

584588
riscv_addr_t input = riscv_program_alloc_d(&program);
@@ -641,7 +645,8 @@ static int register_read_direct(struct target *target, uint64_t *value, uint32_t
641645
*value = 0;
642646
*value |= ((uint64_t)(riscv_program_read_ram(&program, output + 4))) << 32;
643647
*value |= riscv_program_read_ram(&program, output);
644-
LOG_DEBUG("register 0x%x = 0x%" PRIx64, number, *value);
648+
LOG_DEBUG("[%d] reg[0x%x] = 0x%" PRIx64, riscv_current_hartid(target),
649+
number, *value);
645650
return ERROR_OK;
646651
}
647652

@@ -794,6 +799,14 @@ static void deinit_target(struct target *target)
794799
static int add_trigger(struct target *target, struct trigger *trigger)
795800
{
796801
riscv013_info_t *info = get_info(target);
802+
803+
// While we're using threads to fake harts, both gdb and OpenOCD assume
804+
// that hardware breakpoints are shared among threads. Make this true by
805+
// setting the same breakpoints on all harts.
806+
807+
// Assume that all triggers are configured the same on all harts.
808+
riscv_set_current_hartid(target, 0);
809+
797810
maybe_read_tselect(target);
798811

799812
int i;
@@ -817,42 +830,59 @@ static int add_trigger(struct target *target, struct trigger *trigger)
817830
continue;
818831
}
819832

820-
// address/data match trigger
821-
tdata1 |= MCONTROL_DMODE(riscv_xlen(target));
822-
tdata1 = set_field(tdata1, MCONTROL_ACTION,
823-
MCONTROL_ACTION_DEBUG_MODE);
824-
tdata1 = set_field(tdata1, MCONTROL_MATCH, MCONTROL_MATCH_EQUAL);
825-
tdata1 |= MCONTROL_M;
826-
if (info->misa & (1 << ('H' - 'A')))
827-
tdata1 |= MCONTROL_H;
828-
if (info->misa & (1 << ('S' - 'A')))
829-
tdata1 |= MCONTROL_S;
830-
if (info->misa & (1 << ('U' - 'A')))
831-
tdata1 |= MCONTROL_U;
832-
833-
if (trigger->execute)
834-
tdata1 |= MCONTROL_EXECUTE;
835-
if (trigger->read)
836-
tdata1 |= MCONTROL_LOAD;
837-
if (trigger->write)
838-
tdata1 |= MCONTROL_STORE;
839-
840-
register_write_direct(target, GDB_REGNO_TDATA1, tdata1);
841-
842833
uint64_t tdata1_rb;
843-
register_read_direct(target, &tdata1_rb, GDB_REGNO_TDATA1);
844-
LOG_DEBUG("tdata1=0x%" PRIx64, tdata1_rb);
834+
for (int hartid = 0; hartid < riscv_count_harts(target); ++hartid) {
835+
riscv_set_current_hartid(target, hartid);
836+
837+
if (hartid > 0) {
838+
register_write_direct(target, GDB_REGNO_TSELECT, i);
839+
}
840+
841+
// address/data match trigger
842+
tdata1 |= MCONTROL_DMODE(riscv_xlen(target));
843+
tdata1 = set_field(tdata1, MCONTROL_ACTION,
844+
MCONTROL_ACTION_DEBUG_MODE);
845+
tdata1 = set_field(tdata1, MCONTROL_MATCH, MCONTROL_MATCH_EQUAL);
846+
tdata1 |= MCONTROL_M;
847+
if (info->misa & (1 << ('H' - 'A')))
848+
tdata1 |= MCONTROL_H;
849+
if (info->misa & (1 << ('S' - 'A')))
850+
tdata1 |= MCONTROL_S;
851+
if (info->misa & (1 << ('U' - 'A')))
852+
tdata1 |= MCONTROL_U;
853+
854+
if (trigger->execute)
855+
tdata1 |= MCONTROL_EXECUTE;
856+
if (trigger->read)
857+
tdata1 |= MCONTROL_LOAD;
858+
if (trigger->write)
859+
tdata1 |= MCONTROL_STORE;
860+
861+
register_write_direct(target, GDB_REGNO_TDATA1, tdata1);
862+
863+
register_read_direct(target, &tdata1_rb, GDB_REGNO_TDATA1);
864+
LOG_DEBUG("tdata1=0x%" PRIx64, tdata1_rb);
865+
866+
if (tdata1 != tdata1_rb) {
867+
LOG_DEBUG("Trigger %d doesn't support what we need; After writing 0x%"
868+
PRIx64 " to tdata1 it contains 0x%" PRIx64,
869+
i, tdata1, tdata1_rb);
870+
register_write_direct(target, GDB_REGNO_TDATA1, 0);
871+
if (hartid > 0) {
872+
LOG_ERROR("Setting hardware breakpoints requires "
873+
"homogeneous harts.");
874+
return ERROR_FAIL;
875+
}
876+
break;
877+
}
878+
879+
register_write_direct(target, GDB_REGNO_TDATA2, trigger->address);
880+
}
845881

846882
if (tdata1 != tdata1_rb) {
847-
LOG_DEBUG("Trigger %d doesn't support what we need; After writing 0x%"
848-
PRIx64 " to tdata1 it contains 0x%" PRIx64,
849-
i, tdata1, tdata1_rb);
850-
register_write_direct(target, GDB_REGNO_TDATA1, 0);
851883
continue;
852884
}
853885

854-
register_write_direct(target, GDB_REGNO_TDATA2, trigger->address);
855-
856886
LOG_DEBUG("Using resource %d for bp %d", i,
857887
trigger->unique_id);
858888
info->trigger_unique_id[i] = trigger->unique_id;
@@ -870,6 +900,9 @@ static int remove_trigger(struct target *target, struct trigger *trigger)
870900
{
871901
riscv013_info_t *info = get_info(target);
872902

903+
// Assume that all triggers are configured the same on all harts.
904+
riscv_set_current_hartid(target, 0);
905+
873906
maybe_read_tselect(target);
874907

875908
int i;
@@ -884,8 +917,11 @@ static int remove_trigger(struct target *target, struct trigger *trigger)
884917
return ERROR_FAIL;
885918
}
886919
LOG_DEBUG("Stop using resource %d for bp %d", i, trigger->unique_id);
887-
register_write_direct(target, GDB_REGNO_TSELECT, i);
888-
register_write_direct(target, GDB_REGNO_TDATA1, 0);
920+
for (int hartid = 0; hartid < riscv_count_harts(target); ++hartid) {
921+
riscv_set_current_hartid(target, hartid);
922+
register_write_direct(target, GDB_REGNO_TSELECT, i);
923+
register_write_direct(target, GDB_REGNO_TDATA1, 0);
924+
}
889925
info->trigger_unique_id[i] = -1;
890926

891927
return ERROR_OK;

0 commit comments

Comments
 (0)