Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

gdb: Expose CHERI SCRs via the GDB stub #261

Open
wants to merge 4 commits into
base: dev
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion target/cheri-common/cheri-translate-utils.h
Original file line number Diff line number Diff line change
Expand Up @@ -128,7 +128,7 @@ TCGv_i64 cpu_reg(DisasContext *s, int reg);

#elif defined(TARGET_RISCV)

#define DDC_ENV_OFFSET offsetof(CPUArchState, DDC)
#define DDC_ENV_OFFSET offsetof(CPUArchState, ddc)
#define target_get_gpr_global(ctx, reg) (assert(0), (TCGv)NULL)
#define target_get_gpr(ctx, t, reg) gen_get_gpr((TCGv)t, reg)
static inline void _gen_set_gpr(DisasContext *ctx, int reg_num_dst, TCGv t,
Expand Down
8 changes: 4 additions & 4 deletions target/riscv/cheri-archspecific-early.h
Original file line number Diff line number Diff line change
Expand Up @@ -117,14 +117,14 @@ enum CheriSCR {
#define CINVOKE_DATA_REGNUM 31

static inline const cap_register_t *cheri_get_ddc(CPURISCVState *env) {
cheri_debug_assert(env->DDC.cr_extra == CREG_FULLY_DECOMPRESSED);
return &env->DDC;
cheri_debug_assert(env->ddc.cr_extra == CREG_FULLY_DECOMPRESSED);
return &env->ddc;
}

static inline const cap_register_t *_cheri_get_pcc_unchecked(CPURISCVState *env)
{
cheri_debug_assert(env->PCC.cr_extra == CREG_FULLY_DECOMPRESSED);
return &env->PCC;
cheri_debug_assert(env->pcc.cr_extra == CREG_FULLY_DECOMPRESSED);
return &env->pcc;
}

static inline GPCapRegs *cheri_get_gpcrs(CPUArchState *env) {
Expand Down
4 changes: 2 additions & 2 deletions target/riscv/cheri-archspecific.h
Original file line number Diff line number Diff line change
Expand Up @@ -119,8 +119,8 @@ static inline void update_next_pcc_for_tcg(CPUArchState *env,
uint32_t cjalr_flags)
{
assert_valid_jump_target(target);
// On return to TCG we will jump there immediately, so update env->PCC now.
env->PCC = *target;
// On return to TCG we will jump there immediately, so update env->pcc now.
env->pcc = *target;
#ifdef CONFIG_DEBUG_TCG
env->_pc_is_current = true; // PCC.cursor is up-to-date again.
#endif
Expand Down
59 changes: 32 additions & 27 deletions target/riscv/cpu.c
Original file line number Diff line number Diff line change
Expand Up @@ -288,7 +288,7 @@ static void riscv_cpu_dump_state(CPUState *cs, FILE *f, int flags)
#endif
qemu_fprintf(f, " %s " TARGET_FMT_lx "\n", "pc ", PC_ADDR(env));
#ifdef TARGET_CHERI
qemu_fprintf(f, " %s " TARGET_FMT_lx "\n", "pc (offset) ", GET_SPECIAL_REG_ARCH(env, pc, PCC));
qemu_fprintf(f, " %s " TARGET_FMT_lx "\n", "pc (offset) ", GET_SPECIAL_REG_ARCH(env, pc, pcc));
#endif
#ifndef CONFIG_USER_ONLY
qemu_fprintf(f, " %s " TARGET_FMT_lx "\n", "mhartid ", env->mhartid);
Expand All @@ -312,15 +312,15 @@ static void riscv_cpu_dump_state(CPUState *cs, FILE *f, int flags)
if (riscv_has_ext(env, RVH)) {
qemu_fprintf(f, " %s " TARGET_FMT_lx "\n", "hedeleg ", env->hedeleg);
}
qemu_fprintf(f, " %s " TARGET_FMT_lx "\n", "mtvec ", GET_SPECIAL_REG_ARCH(env, mtvec, MTCC));
qemu_fprintf(f, " %s " TARGET_FMT_lx "\n", "stvec ", GET_SPECIAL_REG_ARCH(env, stvec, STCC));
qemu_fprintf(f, " %s " TARGET_FMT_lx "\n", "mtvec ", GET_SPECIAL_REG_ARCH(env, mtvec, mtcc));
qemu_fprintf(f, " %s " TARGET_FMT_lx "\n", "stvec ", GET_SPECIAL_REG_ARCH(env, stvec, stcc));
if (riscv_has_ext(env, RVH)) {
qemu_fprintf(f, " %s " TARGET_FMT_lx "\n", "vstvec ", GET_SPECIAL_REG_ARCH(env, vstvec, VSTCC));
qemu_fprintf(f, " %s " TARGET_FMT_lx "\n", "vstvec ", GET_SPECIAL_REG_ARCH(env, vstvec, vstcc));
}
qemu_fprintf(f, " %s " TARGET_FMT_lx "\n", "mepc ", GET_SPECIAL_REG_ARCH(env, mepc, MEPCC));
qemu_fprintf(f, " %s " TARGET_FMT_lx "\n", "sepc ", GET_SPECIAL_REG_ARCH(env, sepc, SEPCC));
qemu_fprintf(f, " %s " TARGET_FMT_lx "\n", "mepc ", GET_SPECIAL_REG_ARCH(env, mepc, mepcc));
qemu_fprintf(f, " %s " TARGET_FMT_lx "\n", "sepc ", GET_SPECIAL_REG_ARCH(env, sepc, sepcc));
if (riscv_has_ext(env, RVH)) {
qemu_fprintf(f, " %s " TARGET_FMT_lx "\n", "vsepc ", GET_SPECIAL_REG_ARCH(env, vsepc, VSEPCC));
qemu_fprintf(f, " %s " TARGET_FMT_lx "\n", "vsepc ", GET_SPECIAL_REG_ARCH(env, vsepc, vsepcc));
}
qemu_fprintf(f, " %s " TARGET_FMT_lx "\n", "mcause ", env->mcause);
qemu_fprintf(f, " %s " TARGET_FMT_lx "\n", "scause ", env->scause);
Expand Down Expand Up @@ -358,7 +358,7 @@ static void riscv_cpu_set_pc(CPUState *cs, vaddr value)
RISCVCPU *cpu = RISCV_CPU(cs);
CPURISCVState *env = &cpu->env;
#ifdef TARGET_CHERI
cheri_update_pcc(&env->PCC, value, /*can_be_unrepresentable=*/true);
cheri_update_pcc(&env->pcc, value, /*can_be_unrepresentable=*/true);
#else
env->pc = value;
#endif
Expand Down Expand Up @@ -397,11 +397,11 @@ void restore_state_to_opc(CPURISCVState *env, TranslationBlock *tb,
target_ulong *data)
{
#ifdef TARGET_CHERI
assert(cap_is_in_bounds(&env->PCC, data[0], 1));
if (unlikely(env->PCC._cr_cursor != data[0])) {
assert(cap_is_in_bounds(&env->pcc, data[0], 1));
if (unlikely(env->pcc._cr_cursor != data[0])) {
qemu_log_instr_or_mask_msg(env, CPU_LOG_INT,
"%s: Updating pc from TB: " TARGET_FMT_lx " -> " TARGET_FMT_lx "\n",
__func__, (target_ulong)env->PCC._cr_cursor, data[0]);
__func__, (target_ulong)env->pcc._cr_cursor, data[0]);
}
#endif
riscv_update_pc(env, data[0], /*can_be_unrepresentable=*/false);
Expand Down Expand Up @@ -522,7 +522,7 @@ void rvfi_dii_communicate(CPUState* cs, CPURISCVState* env, bool was_trap) {
static bool rvfi_dii_started = false;
static unsigned rvfi_dii_version = 1;
// Single-step completed -> update PC in the trace buffer
env->rvfi_dii_trace.PC.rvfi_pc_wdata = GET_SPECIAL_REG_ARCH(env, pc, PCC);
env->rvfi_dii_trace.PC.rvfi_pc_wdata = GET_SPECIAL_REG_ARCH(env, pc, pcc);
env->rvfi_dii_trace.INST.rvfi_order++;

// TestRIG expects a zero $pc after a trap:
Expand Down Expand Up @@ -658,7 +658,7 @@ void rvfi_dii_communicate(CPUState* cs, CPURISCVState* env, bool was_trap) {
tb_flush(cs); // flush TCG state
env->rvfi_dii_injected_insn = cmd_buf.rvfi_dii_insn;
env->rvfi_dii_have_injected_insn = true;
env->rvfi_dii_trace.PC.rvfi_pc_rdata = GET_SPECIAL_REG_ARCH(env, pc, PCC);
env->rvfi_dii_trace.PC.rvfi_pc_rdata = GET_SPECIAL_REG_ARCH(env, pc, pcc);
env->rvfi_dii_trace.INST.rvfi_mode = env->priv;
env->rvfi_dii_trace.INST.rvfi_ixl = get_field(env->misa, MISA_MXL);
resume_all_vcpus();
Expand Down Expand Up @@ -736,23 +736,23 @@ static void riscv_cpu_reset(DeviceState *dev)
/*
* See Table 5.2: Special Capability Registers (SCRs) in the CHERI ISA spec
*/
set_max_perms_capability(&env->PCC, env->resetvec);
set_max_perms_capability(&env->DDC, 0);
set_max_perms_capability(&env->pcc, env->resetvec);
set_max_perms_capability(&env->ddc, 0);
// User mode trap handling:
set_max_perms_capability(&env->UTCC, 0);
null_capability(&env->UTDC);
null_capability(&env->UScratchC);
set_max_perms_capability(&env->UEPCC, 0);
set_max_perms_capability(&env->utcc, 0);
null_capability(&env->utdc);
null_capability(&env->uscratchc);
set_max_perms_capability(&env->uepcc, 0);
// Supervisor mode trap handling
set_max_perms_capability(&env->STCC, 0);
null_capability(&env->STDC);
null_capability(&env->SScratchC);
set_max_perms_capability(&env->SEPCC, 0);
set_max_perms_capability(&env->stcc, 0);
null_capability(&env->stdc);
null_capability(&env->sscratchc);
set_max_perms_capability(&env->sepcc, 0);
// Machine mode trap handling
set_max_perms_capability(&env->MTCC, 0);
null_capability(&env->MTDC);
null_capability(&env->MScratchC);
set_max_perms_capability(&env->MEPCC, 0);
set_max_perms_capability(&env->mtcc, 0);
null_capability(&env->mtdc);
null_capability(&env->mscratchc);
set_max_perms_capability(&env->mepcc, 0);
#endif /* TARGET_CHERI */
#ifdef CONFIG_DEBUG_TCG
env->_pc_is_current = true;
Expand Down Expand Up @@ -999,6 +999,11 @@ static const char *riscv_gdb_get_dynamic_xml(CPUState *cs, const char *xmlname)
if (strcmp(xmlname, "riscv-csr.xml") == 0) {
return cpu->dyn_csr_xml;
}
#ifdef TARGET_CHERI
if (strcmp(xmlname, "riscv-scr.xml") == 0) {
return cpu->dyn_scr_xml;
}
#endif

return NULL;
}
Expand Down
79 changes: 56 additions & 23 deletions target/riscv/cpu.h
Original file line number Diff line number Diff line change
Expand Up @@ -136,8 +136,8 @@ struct CPURISCVState {
target_ulong vtype;

#ifdef TARGET_CHERI
cap_register_t PCC; // SCR 0 Program counter cap. (PCC) TODO: implement this properly
cap_register_t DDC; // SCR 1 Default data cap. (DDC)
cap_register_t pcc; // SCR 0 Program counter cap. (PCC) TODO: implement this properly
cap_register_t ddc; // SCR 1 Default data cap. (DDC)
#else
target_ulong pc;
#endif
Expand Down Expand Up @@ -200,28 +200,28 @@ struct CPURISCVState {

#ifdef TARGET_CHERI
// XXX: not implemented properly
cap_register_t UTCC; // SCR 4 User trap code cap. (UTCC)
cap_register_t UTDC; // SCR 5 User trap data cap. (UTDC)
cap_register_t UScratchC; // SCR 6 User scratch cap. (UScratchC)
cap_register_t UEPCC; // SCR 7 User exception PC cap. (UEPCC)
cap_register_t utcc; // SCR 4 User trap code cap. (UTCC)
cap_register_t utdc; // SCR 5 User trap data cap. (UTDC)
cap_register_t uscratchc; // SCR 6 User scratch cap. (UScratchC)
cap_register_t uepcc; // SCR 7 User exception PC cap. (UEPCC)
#endif

#ifdef TARGET_CHERI
cap_register_t STCC; // SCR 12 Supervisor trap code cap. (STCC)
cap_register_t STDC; // SCR 13 Supervisor trap data cap. (STDC)
cap_register_t SScratchC; // SCR 14 Supervisor scratch cap. (SScratchC)
cap_register_t SEPCC; // SCR 15 Supervisor exception PC cap. (SEPCC)
cap_register_t stcc; // SCR 12 Supervisor trap code cap. (STCC)
cap_register_t stdc; // SCR 13 Supervisor trap data cap. (STDC)
cap_register_t sscratchc; // SCR 14 Supervisor scratch cap. (SScratchC)
cap_register_t sepcc; // SCR 15 Supervisor exception PC cap. (SEPCC)
#else
target_ulong stvec;
target_ulong sepc;
#endif
target_ulong scause;

#ifdef TARGET_CHERI
cap_register_t MTCC; // SCR 28 Machine trap code cap. (MTCC)
cap_register_t MTDC; // SCR 29 Machine trap data cap. (MTDC)
cap_register_t MScratchC; // SCR 30 Machine scratch cap. (MScratchC)
cap_register_t MEPCC; // SCR 31 Machine exception PC cap. (MEPCC)
cap_register_t mtcc; // SCR 28 Machine trap code cap. (MTCC)
cap_register_t mtdc; // SCR 29 Machine trap data cap. (MTDC)
cap_register_t mscratchc; // SCR 30 Machine scratch cap. (MScratchC)
cap_register_t mepcc; // SCR 31 Machine exception PC cap. (MEPCC)
#else
target_ulong mtvec;
target_ulong mepc;
Expand All @@ -241,10 +241,10 @@ struct CPURISCVState {

/* Virtual CSRs */
#ifdef TARGET_CHERI
cap_register_t VSTCC;
cap_register_t VSTDC;
cap_register_t VSScratchC;
cap_register_t VSEPCC;
cap_register_t vstcc;
cap_register_t vstdc;
cap_register_t vsscratchc;
cap_register_t vsepcc;
#else
target_ulong vstvec;
target_ulong vsepc;
Expand All @@ -264,8 +264,8 @@ struct CPURISCVState {

/* HS Backup CSRs */
#ifdef TARGET_CHERI
cap_register_t STCC_HS;
cap_register_t SEPCC_HS;
cap_register_t stcc_hs;
cap_register_t sepcc_hs;
#else
target_ulong stvec_hs;
target_ulong sepc_hs;
Expand Down Expand Up @@ -372,7 +372,7 @@ static inline bool pc_is_current(CPURISCVState *env)
// that shouldn't really matter.
static inline target_ulong cpu_get_recent_pc(CPURISCVState *env) {
#ifdef TARGET_CHERI
return env->PCC._cr_cursor;
return env->pcc._cr_cursor;
#else
return env->pc;
#endif
Expand Down Expand Up @@ -410,6 +410,9 @@ struct RISCVCPU {
CPURISCVState env;

char *dyn_csr_xml;
#ifdef TARGET_CHERI
char *dyn_scr_xml;
#endif

/* Configuration Settings */
struct {
Expand Down Expand Up @@ -712,7 +715,7 @@ riscv_cpu_get_tb_cpu_state(CPURISCVState *env, target_ulong *pc,
uint32_t flags = 0;
*pc = PC_ADDR(env); // We want the full virtual address here (no offset)
#ifdef TARGET_CHERI
cheri_cpu_get_tb_cpu_state(&env->PCC, &env->DDC, cs_base, cs_top,
cheri_cpu_get_tb_cpu_state(&env->pcc, &env->ddc, cs_base, cs_top,
cheri_flags);
#else
*cs_base = 0;
Expand Down Expand Up @@ -814,7 +817,6 @@ typedef struct {
riscv_csr_write_fn write;
riscv_csr_op_fn op;
riscv_csr_log_update_fn log_update;
const char *csr_name;
} riscv_csr_operations;

/* CSR function table constants */
Expand All @@ -828,6 +830,37 @@ extern riscv_csr_operations csr_ops[CSR_TABLE_SIZE];
void riscv_get_csr_ops(int csrno, riscv_csr_operations *ops);
void riscv_set_csr_ops(int csrno, riscv_csr_operations *ops);

#ifdef TARGET_CHERI
static inline cap_register_t *riscv_get_scr(CPUArchState *env, uint32_t index)
{
switch (index) {
case CheriSCR_PCC: return &env->pcc;
case CheriSCR_DDC: return &env->ddc;

case CheriSCR_UTCC: return &env->utcc;
case CheriSCR_UTDC: return &env->utdc;
case CheriSCR_UScratchC: return &env->uscratchc;
case CheriSCR_UEPCC: return &env->uepcc;

case CheriSCR_STCC: return &env->stcc;
case CheriSCR_STDC: return &env->stdc;
case CheriSCR_SScratchC: return &env->sscratchc;
case CheriSCR_SEPCC: return &env->sepcc;

case CheriSCR_MTCC: return &env->mtcc;
case CheriSCR_MTDC: return &env->mtdc;
case CheriSCR_MScratchC: return &env->mscratchc;
case CheriSCR_MEPCC: return &env->mepcc;

case CheriSCR_BSTCC: return &env->vstcc;
case CheriSCR_BSTDC: return &env->vstdc;
case CheriSCR_BSScratchC: return &env->vsscratchc;
case CheriSCR_BSEPCC: return &env->vsepcc;
default: assert(false && "Should have raised an invalid inst trap!");
}
}
#endif

void riscv_cpu_register_gdb_regs_for_features(CPUState *cs);

#endif /* RISCV_CPU_H */
Loading
Loading