Add support for hypervisor bits. (#631)
Expose them in the virtual priv register, and set them on mcontrol6 hardware triggers. I have no good way to test this right now, so it's all untested. But this change doesn't break anything, at least. Change-Id: I0343a6169a0b2b1f0cc0abf687c6bdc560d99b1b Signed-off-by: Tim Newsome <tim@sifive.com>
This commit is contained in:
parent
f260fb8753
commit
90d1d490c1
File diff suppressed because it is too large
Load Diff
|
@ -29,9 +29,6 @@
|
|||
#include "asm.h"
|
||||
#include "batch.h"
|
||||
|
||||
#define DM_DATA1 (DM_DATA0 + 1)
|
||||
#define DM_PROGBUF1 (DM_PROGBUF0 + 1)
|
||||
|
||||
static int riscv013_on_step_or_resume(struct target *target, bool step);
|
||||
static int riscv013_step_or_resume_current_hart(struct target *target,
|
||||
bool step, bool use_hasel);
|
||||
|
@ -4088,7 +4085,8 @@ static int riscv013_get_register(struct target *target,
|
|||
uint64_t dcsr;
|
||||
/* TODO: move this into riscv.c. */
|
||||
result = register_read(target, &dcsr, GDB_REGNO_DCSR);
|
||||
*value = get_field(dcsr, CSR_DCSR_PRV);
|
||||
*value = set_field(0, VIRT_PRIV_V, get_field(dcsr, CSR_DCSR_V));
|
||||
*value = set_field(*value, VIRT_PRIV_PRV, get_field(dcsr, CSR_DCSR_PRV));
|
||||
} else {
|
||||
result = register_read(target, value, rid);
|
||||
if (result != ERROR_OK)
|
||||
|
@ -4120,7 +4118,8 @@ static int riscv013_set_register(struct target *target, int rid, uint64_t value)
|
|||
} else if (rid == GDB_REGNO_PRIV) {
|
||||
uint64_t dcsr;
|
||||
register_read(target, &dcsr, GDB_REGNO_DCSR);
|
||||
dcsr = set_field(dcsr, CSR_DCSR_PRV, value);
|
||||
dcsr = set_field(dcsr, CSR_DCSR_PRV, get_field(value, VIRT_PRIV_PRV));
|
||||
dcsr = set_field(dcsr, CSR_DCSR_V, get_field(value, VIRT_PRIV_V));
|
||||
return register_write_direct(target, GDB_REGNO_DCSR, dcsr);
|
||||
} else {
|
||||
return register_write_direct(target, rid, value);
|
||||
|
|
|
@ -20,6 +20,7 @@
|
|||
#include "riscv.h"
|
||||
#include "gdb_regs.h"
|
||||
#include "rtos/rtos.h"
|
||||
#include "debug_defines.h"
|
||||
|
||||
#define get_field(reg, mask) (((reg) & (mask)) / ((mask) & ~((mask) << 1)))
|
||||
#define set_field(reg, mask, val) (((reg) & ~(mask)) | (((val) * ((mask) & ~((mask) << 1))) & (mask)))
|
||||
|
@ -591,8 +592,6 @@ static int maybe_add_trigger_t2(struct target *target,
|
|||
MCONTROL_ACTION_DEBUG_MODE);
|
||||
tdata1 = set_field(tdata1, MCONTROL_MATCH, MCONTROL_MATCH_EQUAL);
|
||||
tdata1 |= MCONTROL_M;
|
||||
if (r->misa & (1 << ('H' - 'A')))
|
||||
tdata1 |= MCONTROL_H;
|
||||
if (r->misa & (1 << ('S' - 'A')))
|
||||
tdata1 |= MCONTROL_S;
|
||||
if (r->misa & (1 << ('U' - 'A')))
|
||||
|
@ -626,6 +625,58 @@ static int maybe_add_trigger_t2(struct target *target,
|
|||
return ERROR_OK;
|
||||
}
|
||||
|
||||
static int maybe_add_trigger_t6(struct target *target,
|
||||
struct trigger *trigger, uint64_t tdata1)
|
||||
{
|
||||
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;
|
||||
}
|
||||
|
||||
/* address/data match trigger */
|
||||
tdata1 |= MCONTROL_DMODE(riscv_xlen(target));
|
||||
tdata1 = set_field(tdata1, CSR_MCONTROL6_ACTION,
|
||||
MCONTROL_ACTION_DEBUG_MODE);
|
||||
tdata1 = set_field(tdata1, CSR_MCONTROL6_MATCH, MCONTROL_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);
|
||||
|
||||
return ERROR_OK;
|
||||
}
|
||||
|
||||
static int add_trigger(struct target *target, struct trigger *trigger)
|
||||
{
|
||||
RISCV_INFO(r);
|
||||
|
@ -658,6 +709,9 @@ static int add_trigger(struct target *target, struct trigger *trigger)
|
|||
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;
|
||||
|
|
Loading…
Reference in New Issue