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:
Tim Newsome 2021-07-23 14:42:05 -07:00 committed by GitHub
parent f260fb8753
commit 90d1d490c1
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 802 additions and 125 deletions

File diff suppressed because it is too large Load Diff

View File

@ -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);

View File

@ -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;