aboutsummaryrefslogtreecommitdiff
path: root/target
diff options
context:
space:
mode:
Diffstat (limited to 'target')
-rw-r--r--target/riscv/cpu.c15
-rw-r--r--target/riscv/cpu.h13
-rw-r--r--target/riscv/cpu_bits.h35
-rw-r--r--target/riscv/cpu_helper.c168
-rw-r--r--target/riscv/cpu_user.h3
-rw-r--r--target/riscv/csr.c54
-rw-r--r--target/riscv/gdbstub.c350
-rw-r--r--target/riscv/pmp.c20
-rw-r--r--target/riscv/trace-events2
9 files changed, 514 insertions, 146 deletions
diff --git a/target/riscv/cpu.c b/target/riscv/cpu.c
index cc3ddc0ae4..d61bce6d55 100644
--- a/target/riscv/cpu.c
+++ b/target/riscv/cpu.c
@@ -80,12 +80,6 @@ const char * const riscv_intr_names[] = {
"reserved"
};
-typedef struct RISCVCPUInfo {
- const int bit_widths;
- const char *name;
- void (*initfn)(Object *obj);
-} RISCVCPUInfo;
-
static void set_misa(CPURISCVState *env, target_ulong misa)
{
env->misa_mask = env->misa = misa;
@@ -311,6 +305,8 @@ static void riscv_cpu_realize(DeviceState *dev, Error **errp)
return;
}
+ riscv_cpu_register_gdb_regs_for_features(cs);
+
qemu_init_vcpu(cs);
cpu_reset(cs);
@@ -351,7 +347,12 @@ static void riscv_cpu_class_init(ObjectClass *c, void *data)
cc->synchronize_from_tb = riscv_cpu_synchronize_from_tb;
cc->gdb_read_register = riscv_cpu_gdb_read_register;
cc->gdb_write_register = riscv_cpu_gdb_write_register;
- cc->gdb_num_core_regs = 65;
+ cc->gdb_num_core_regs = 33;
+#if defined(TARGET_RISCV32)
+ cc->gdb_core_xml_file = "riscv-32bit-cpu.xml";
+#elif defined(TARGET_RISCV64)
+ cc->gdb_core_xml_file = "riscv-64bit-cpu.xml";
+#endif
cc->gdb_stop_before_watchpoint = true;
cc->disas_set_info = riscv_cpu_disas_set_info;
#ifdef CONFIG_USER_ONLY
diff --git a/target/riscv/cpu.h b/target/riscv/cpu.h
index 5c2aebf132..20bce8742e 100644
--- a/target/riscv/cpu.h
+++ b/target/riscv/cpu.h
@@ -123,6 +123,10 @@ struct CPURISCVState {
uint32_t features;
+#ifdef CONFIG_USER_ONLY
+ uint32_t elf_flags;
+#endif
+
#ifndef CONFIG_USER_ONLY
target_ulong priv;
target_ulong resetvec;
@@ -140,6 +144,7 @@ struct CPURISCVState {
* mip is 32-bits to allow atomic_read on 32-bit hosts.
*/
uint32_t mip;
+ uint32_t miclaim;
target_ulong mie;
target_ulong mideleg;
@@ -172,6 +177,9 @@ struct CPURISCVState {
/* physical memory protection */
pmp_table_t pmp_state;
+
+ /* True if in debugger mode. */
+ bool debugger;
#endif
float_status fp_status;
@@ -263,6 +271,7 @@ void riscv_cpu_list(FILE *f, fprintf_function cpu_fprintf);
#define cpu_mmu_index riscv_cpu_mmu_index
#ifndef CONFIG_USER_ONLY
+int riscv_cpu_claim_interrupts(RISCVCPU *cpu, uint32_t interrupts);
uint32_t riscv_cpu_update_mip(RISCVCPU *cpu, uint32_t mask, uint32_t value);
#define BOOL_TO_MASK(x) (-!!(x)) /* helper for riscv_cpu_update_mip value */
#endif
@@ -293,6 +302,8 @@ static inline void cpu_get_tb_cpu_state(CPURISCVState *env, target_ulong *pc,
int riscv_csrrw(CPURISCVState *env, int csrno, target_ulong *ret_value,
target_ulong new_value, target_ulong write_mask);
+int riscv_csrrw_debug(CPURISCVState *env, int csrno, target_ulong *ret_value,
+ target_ulong new_value, target_ulong write_mask);
static inline void riscv_csr_write(CPURISCVState *env, int csrno,
target_ulong val)
@@ -325,6 +336,8 @@ typedef struct {
void riscv_get_csr_ops(int csrno, riscv_csr_operations *ops);
void riscv_set_csr_ops(int csrno, riscv_csr_operations *ops);
+void riscv_cpu_register_gdb_regs_for_features(CPUState *cs);
+
#include "exec/cpu-all.h"
#endif /* RISCV_CPU_H */
diff --git a/target/riscv/cpu_bits.h b/target/riscv/cpu_bits.h
index 7afcb2468d..7180fccf54 100644
--- a/target/riscv/cpu_bits.h
+++ b/target/riscv/cpu_bits.h
@@ -135,16 +135,22 @@
/* Legacy Counter Setup (priv v1.9.1) */
#define CSR_MUCOUNTEREN 0x320
#define CSR_MSCOUNTEREN 0x321
+#define CSR_MHCOUNTEREN 0x322
/* Machine Trap Handling */
#define CSR_MSCRATCH 0x340
#define CSR_MEPC 0x341
#define CSR_MCAUSE 0x342
-#define CSR_MBADADDR 0x343
+#define CSR_MTVAL 0x343
#define CSR_MIP 0x344
+/* Legacy Machine Trap Handling (priv v1.9.1) */
+#define CSR_MBADADDR 0x343
+
/* Supervisor Trap Setup */
#define CSR_SSTATUS 0x100
+#define CSR_SEDELEG 0x102
+#define CSR_SIDELEG 0x103
#define CSR_SIE 0x104
#define CSR_STVEC 0x105
#define CSR_SCOUNTEREN 0x106
@@ -153,9 +159,12 @@
#define CSR_SSCRATCH 0x140
#define CSR_SEPC 0x141
#define CSR_SCAUSE 0x142
-#define CSR_SBADADDR 0x143
+#define CSR_STVAL 0x143
#define CSR_SIP 0x144
+/* Legacy Supervisor Trap Handling (priv v1.9.1) */
+#define CSR_SBADADDR 0x143
+
/* Supervisor Protection and Translation */
#define CSR_SPTBR 0x180
#define CSR_SATP 0x180
@@ -282,6 +291,28 @@
#define CSR_MHPMCOUNTER30H 0xb9e
#define CSR_MHPMCOUNTER31H 0xb9f
+/* Legacy Hypervisor Trap Setup (priv v1.9.1) */
+#define CSR_HSTATUS 0x200
+#define CSR_HEDELEG 0x202
+#define CSR_HIDELEG 0x203
+#define CSR_HIE 0x204
+#define CSR_HTVEC 0x205
+
+/* Legacy Hypervisor Trap Handling (priv v1.9.1) */
+#define CSR_HSCRATCH 0x240
+#define CSR_HEPC 0x241
+#define CSR_HCAUSE 0x242
+#define CSR_HBADADDR 0x243
+#define CSR_HIP 0x244
+
+/* Legacy Machine Protection and Translation (priv v1.9.1) */
+#define CSR_MBASE 0x380
+#define CSR_MBOUND 0x381
+#define CSR_MIBASE 0x382
+#define CSR_MIBOUND 0x383
+#define CSR_MDBASE 0x384
+#define CSR_MDBOUND 0x385
+
/* mstatus CSR bits */
#define MSTATUS_UIE 0x00000001
#define MSTATUS_SIE 0x00000002
diff --git a/target/riscv/cpu_helper.c b/target/riscv/cpu_helper.c
index f49e98ed59..b17f169681 100644
--- a/target/riscv/cpu_helper.c
+++ b/target/riscv/cpu_helper.c
@@ -22,8 +22,7 @@
#include "cpu.h"
#include "exec/exec-all.h"
#include "tcg-op.h"
-
-#define RISCV_DEBUG_INTERRUPT 0
+#include "trace.h"
int riscv_cpu_mmu_index(CPURISCVState *env, bool ifetch)
{
@@ -72,6 +71,17 @@ bool riscv_cpu_exec_interrupt(CPUState *cs, int interrupt_request)
#if !defined(CONFIG_USER_ONLY)
+int riscv_cpu_claim_interrupts(RISCVCPU *cpu, uint32_t interrupts)
+{
+ CPURISCVState *env = &cpu->env;
+ if (env->miclaim & interrupts) {
+ return -1;
+ } else {
+ env->miclaim |= interrupts;
+ return 0;
+ }
+}
+
/* iothread_mutex must be held */
uint32_t riscv_cpu_update_mip(RISCVCPU *cpu, uint32_t mask, uint32_t value)
{
@@ -84,9 +94,9 @@ uint32_t riscv_cpu_update_mip(RISCVCPU *cpu, uint32_t mask, uint32_t value)
cmp = atomic_cmpxchg(&env->mip, old, new);
} while (old != cmp);
- if (new && !old) {
+ if (new) {
cpu_interrupt(CPU(cpu), CPU_INTERRUPT_HARD);
- } else if (!new && old) {
+ } else {
cpu_reset_interrupt(CPU(cpu), CPU_INTERRUPT_HARD);
}
@@ -443,121 +453,85 @@ void riscv_cpu_do_interrupt(CPUState *cs)
RISCVCPU *cpu = RISCV_CPU(cs);
CPURISCVState *env = &cpu->env;
- if (RISCV_DEBUG_INTERRUPT) {
- int log_cause = cs->exception_index & RISCV_EXCP_INT_MASK;
- if (cs->exception_index & RISCV_EXCP_INT_FLAG) {
- qemu_log_mask(LOG_TRACE, "core "
- TARGET_FMT_ld ": trap %s, epc 0x" TARGET_FMT_lx "\n",
- env->mhartid, riscv_intr_names[log_cause], env->pc);
- } else {
- qemu_log_mask(LOG_TRACE, "core "
- TARGET_FMT_ld ": intr %s, epc 0x" TARGET_FMT_lx "\n",
- env->mhartid, riscv_excp_names[log_cause], env->pc);
+ /* cs->exception is 32-bits wide unlike mcause which is XLEN-bits wide
+ * so we mask off the MSB and separate into trap type and cause.
+ */
+ bool async = !!(cs->exception_index & RISCV_EXCP_INT_FLAG);
+ target_ulong cause = cs->exception_index & RISCV_EXCP_INT_MASK;
+ target_ulong deleg = async ? env->mideleg : env->medeleg;
+ target_ulong tval = 0;
+
+ static const int ecall_cause_map[] = {
+ [PRV_U] = RISCV_EXCP_U_ECALL,
+ [PRV_S] = RISCV_EXCP_S_ECALL,
+ [PRV_H] = RISCV_EXCP_H_ECALL,
+ [PRV_M] = RISCV_EXCP_M_ECALL
+ };
+
+ if (!async) {
+ /* set tval to badaddr for traps with address information */
+ switch (cause) {
+ case RISCV_EXCP_INST_ADDR_MIS:
+ case RISCV_EXCP_INST_ACCESS_FAULT:
+ case RISCV_EXCP_LOAD_ADDR_MIS:
+ case RISCV_EXCP_STORE_AMO_ADDR_MIS:
+ case RISCV_EXCP_LOAD_ACCESS_FAULT:
+ case RISCV_EXCP_STORE_AMO_ACCESS_FAULT:
+ case RISCV_EXCP_INST_PAGE_FAULT:
+ case RISCV_EXCP_LOAD_PAGE_FAULT:
+ case RISCV_EXCP_STORE_PAGE_FAULT:
+ tval = env->badaddr;
+ break;
+ default:
+ break;
}
- }
-
- target_ulong fixed_cause = 0;
- if (cs->exception_index & (RISCV_EXCP_INT_FLAG)) {
- /* hacky for now. the MSB (bit 63) indicates interrupt but cs->exception
- index is only 32 bits wide */
- fixed_cause = cs->exception_index & RISCV_EXCP_INT_MASK;
- fixed_cause |= ((target_ulong)1) << (TARGET_LONG_BITS - 1);
- } else {
- /* fixup User ECALL -> correct priv ECALL */
- if (cs->exception_index == RISCV_EXCP_U_ECALL) {
- switch (env->priv) {
- case PRV_U:
- fixed_cause = RISCV_EXCP_U_ECALL;
- break;
- case PRV_S:
- fixed_cause = RISCV_EXCP_S_ECALL;
- break;
- case PRV_H:
- fixed_cause = RISCV_EXCP_H_ECALL;
- break;
- case PRV_M:
- fixed_cause = RISCV_EXCP_M_ECALL;
- break;
- }
- } else {
- fixed_cause = cs->exception_index;
+ /* ecall is dispatched as one cause so translate based on mode */
+ if (cause == RISCV_EXCP_U_ECALL) {
+ assert(env->priv <= 3);
+ cause = ecall_cause_map[env->priv];
}
}
- target_ulong backup_epc = env->pc;
-
- target_ulong bit = fixed_cause;
- target_ulong deleg = env->medeleg;
-
- int hasbadaddr =
- (fixed_cause == RISCV_EXCP_INST_ADDR_MIS) ||
- (fixed_cause == RISCV_EXCP_INST_ACCESS_FAULT) ||
- (fixed_cause == RISCV_EXCP_LOAD_ADDR_MIS) ||
- (fixed_cause == RISCV_EXCP_STORE_AMO_ADDR_MIS) ||
- (fixed_cause == RISCV_EXCP_LOAD_ACCESS_FAULT) ||
- (fixed_cause == RISCV_EXCP_STORE_AMO_ACCESS_FAULT) ||
- (fixed_cause == RISCV_EXCP_INST_PAGE_FAULT) ||
- (fixed_cause == RISCV_EXCP_LOAD_PAGE_FAULT) ||
- (fixed_cause == RISCV_EXCP_STORE_PAGE_FAULT);
-
- if (bit & ((target_ulong)1 << (TARGET_LONG_BITS - 1))) {
- deleg = env->mideleg;
- bit &= ~((target_ulong)1 << (TARGET_LONG_BITS - 1));
- }
+ trace_riscv_trap(env->mhartid, async, cause, env->pc, tval, cause < 16 ?
+ (async ? riscv_intr_names : riscv_excp_names)[cause] : "(unknown)");
- if (env->priv <= PRV_S && bit < 64 && ((deleg >> bit) & 1)) {
+ if (env->priv <= PRV_S &&
+ cause < TARGET_LONG_BITS && ((deleg >> cause) & 1)) {
/* handle the trap in S-mode */
- /* No need to check STVEC for misaligned - lower 2 bits cannot be set */
- env->pc = env->stvec;
- env->scause = fixed_cause;
- env->sepc = backup_epc;
-
- if (hasbadaddr) {
- if (RISCV_DEBUG_INTERRUPT) {
- qemu_log_mask(LOG_TRACE, "core " TARGET_FMT_ld ": badaddr 0x"
- TARGET_FMT_lx "\n", env->mhartid, env->badaddr);
- }
- env->sbadaddr = env->badaddr;
- } else {
- /* otherwise we must clear sbadaddr/stval
- * todo: support populating stval on illegal instructions */
- env->sbadaddr = 0;
- }
-
target_ulong s = env->mstatus;
s = set_field(s, MSTATUS_SPIE, env->priv_ver >= PRIV_VERSION_1_10_0 ?
get_field(s, MSTATUS_SIE) : get_field(s, MSTATUS_UIE << env->priv));
s = set_field(s, MSTATUS_SPP, env->priv);
s = set_field(s, MSTATUS_SIE, 0);
env->mstatus = s;
+ env->scause = cause | ~(((target_ulong)-1) >> async);
+ env->sepc = env->pc;
+ env->sbadaddr = tval;
+ env->pc = (env->stvec >> 2 << 2) +
+ ((async && (env->stvec & 3) == 1) ? cause * 4 : 0);
riscv_cpu_set_mode(env, PRV_S);
} else {
- /* No need to check MTVEC for misaligned - lower 2 bits cannot be set */
- env->pc = env->mtvec;
- env->mepc = backup_epc;
- env->mcause = fixed_cause;
-
- if (hasbadaddr) {
- if (RISCV_DEBUG_INTERRUPT) {
- qemu_log_mask(LOG_TRACE, "core " TARGET_FMT_ld ": badaddr 0x"
- TARGET_FMT_lx "\n", env->mhartid, env->badaddr);
- }
- env->mbadaddr = env->badaddr;
- } else {
- /* otherwise we must clear mbadaddr/mtval
- * todo: support populating mtval on illegal instructions */
- env->mbadaddr = 0;
- }
-
+ /* handle the trap in M-mode */
target_ulong s = env->mstatus;
s = set_field(s, MSTATUS_MPIE, env->priv_ver >= PRIV_VERSION_1_10_0 ?
get_field(s, MSTATUS_MIE) : get_field(s, MSTATUS_UIE << env->priv));
s = set_field(s, MSTATUS_MPP, env->priv);
s = set_field(s, MSTATUS_MIE, 0);
env->mstatus = s;
+ env->mcause = cause | ~(((target_ulong)-1) >> async);
+ env->mepc = env->pc;
+ env->mbadaddr = tval;
+ env->pc = (env->mtvec >> 2 << 2) +
+ ((async && (env->mtvec & 3) == 1) ? cause * 4 : 0);
riscv_cpu_set_mode(env, PRV_M);
}
- /* TODO yield load reservation */
+
+ /* NOTE: it is not necessary to yield load reservations here. It is only
+ * necessary for an SC from "another hart" to cause a load reservation
+ * to be yielded. Refer to the memory consistency model section of the
+ * RISC-V ISA Specification.
+ */
+
#endif
cs->exception_index = EXCP_NONE; /* mark handled to qemu */
}
diff --git a/target/riscv/cpu_user.h b/target/riscv/cpu_user.h
index c2199610ab..52d380aa98 100644
--- a/target/riscv/cpu_user.h
+++ b/target/riscv/cpu_user.h
@@ -10,4 +10,5 @@
#define xA4 14
#define xA5 15
#define xA6 16
-#define xA7 17 /* syscall number goes here */
+#define xA7 17 /* syscall number for RVI ABI */
+#define xT0 5 /* syscall number for RVE ABI */
diff --git a/target/riscv/csr.c b/target/riscv/csr.c
index 960d2b0aa9..e1d91b6c60 100644
--- a/target/riscv/csr.c
+++ b/target/riscv/csr.c
@@ -46,7 +46,7 @@ void riscv_set_csr_ops(int csrno, riscv_csr_operations *ops)
static int fs(CPURISCVState *env, int csrno)
{
#if !defined(CONFIG_USER_ONLY)
- if (!(env->mstatus & MSTATUS_FS)) {
+ if (!env->debugger && !(env->mstatus & MSTATUS_FS)) {
return -1;
}
#endif
@@ -92,7 +92,7 @@ static int pmp(CPURISCVState *env, int csrno)
static int read_fflags(CPURISCVState *env, int csrno, target_ulong *val)
{
#if !defined(CONFIG_USER_ONLY)
- if (!(env->mstatus & MSTATUS_FS)) {
+ if (!env->debugger && !(env->mstatus & MSTATUS_FS)) {
return -1;
}
#endif
@@ -103,7 +103,7 @@ static int read_fflags(CPURISCVState *env, int csrno, target_ulong *val)
static int write_fflags(CPURISCVState *env, int csrno, target_ulong val)
{
#if !defined(CONFIG_USER_ONLY)
- if (!(env->mstatus & MSTATUS_FS)) {
+ if (!env->debugger && !(env->mstatus & MSTATUS_FS)) {
return -1;
}
env->mstatus |= MSTATUS_FS;
@@ -115,7 +115,7 @@ static int write_fflags(CPURISCVState *env, int csrno, target_ulong val)
static int read_frm(CPURISCVState *env, int csrno, target_ulong *val)
{
#if !defined(CONFIG_USER_ONLY)
- if (!(env->mstatus & MSTATUS_FS)) {
+ if (!env->debugger && !(env->mstatus & MSTATUS_FS)) {
return -1;
}
#endif
@@ -126,7 +126,7 @@ static int read_frm(CPURISCVState *env, int csrno, target_ulong *val)
static int write_frm(CPURISCVState *env, int csrno, target_ulong val)
{
#if !defined(CONFIG_USER_ONLY)
- if (!(env->mstatus & MSTATUS_FS)) {
+ if (!env->debugger && !(env->mstatus & MSTATUS_FS)) {
return -1;
}
env->mstatus |= MSTATUS_FS;
@@ -138,7 +138,7 @@ static int write_frm(CPURISCVState *env, int csrno, target_ulong val)
static int read_fcsr(CPURISCVState *env, int csrno, target_ulong *val)
{
#if !defined(CONFIG_USER_ONLY)
- if (!(env->mstatus & MSTATUS_FS)) {
+ if (!env->debugger && !(env->mstatus & MSTATUS_FS)) {
return -1;
}
#endif
@@ -150,7 +150,7 @@ static int read_fcsr(CPURISCVState *env, int csrno, target_ulong *val)
static int write_fcsr(CPURISCVState *env, int csrno, target_ulong val)
{
#if !defined(CONFIG_USER_ONLY)
- if (!(env->mstatus & MSTATUS_FS)) {
+ if (!env->debugger && !(env->mstatus & MSTATUS_FS)) {
return -1;
}
env->mstatus |= MSTATUS_FS;
@@ -435,10 +435,10 @@ static int read_mtvec(CPURISCVState *env, int csrno, target_ulong *val)
static int write_mtvec(CPURISCVState *env, int csrno, target_ulong val)
{
/* bits [1:0] encode mode; 0 = direct, 1 = vectored, 2 >= reserved */
- if ((val & 3) == 0) {
- env->mtvec = val >> 2 << 2;
+ if ((val & 3) < 2) {
+ env->mtvec = val;
} else {
- qemu_log_mask(LOG_UNIMP, "CSR_MTVEC: vectored traps not supported");
+ qemu_log_mask(LOG_UNIMP, "CSR_MTVEC: reserved mode not supported\n");
}
return 0;
}
@@ -550,16 +550,10 @@ static int rmw_mip(CPURISCVState *env, int csrno, target_ulong *ret_value,
target_ulong new_value, target_ulong write_mask)
{
RISCVCPU *cpu = riscv_env_get_cpu(env);
- target_ulong mask = write_mask & delegable_ints;
+ /* Allow software control of delegable interrupts not claimed by hardware */
+ target_ulong mask = write_mask & delegable_ints & ~env->miclaim;
uint32_t old_mip;
- /* We can't allow the supervisor to control SEIP as this would allow the
- * supervisor to clear a pending external interrupt which will result in
- * lost a interrupt in the case a PLIC is attached. The SEIP bit must be
- * hardware controlled when a PLIC is attached. This should be an option
- * for CPUs with software-delegated Supervisor External Interrupts. */
- mask &= ~MIP_SEIP;
-
if (mask) {
qemu_mutex_lock_iothread();
old_mip = riscv_cpu_update_mip(cpu, mask, (new_value & mask));
@@ -613,10 +607,10 @@ static int read_stvec(CPURISCVState *env, int csrno, target_ulong *val)
static int write_stvec(CPURISCVState *env, int csrno, target_ulong val)
{
/* bits [1:0] encode mode; 0 = direct, 1 = vectored, 2 >= reserved */
- if ((val & 3) == 0) {
- env->stvec = val >> 2 << 2;
+ if ((val & 3) < 2) {
+ env->stvec = val;
} else {
- qemu_log_mask(LOG_UNIMP, "CSR_STVEC: vectored traps not supported");
+ qemu_log_mask(LOG_UNIMP, "CSR_STVEC: reserved mode not supported\n");
}
return 0;
}
@@ -827,6 +821,24 @@ int riscv_csrrw(CPURISCVState *env, int csrno, target_ulong *ret_value,
return 0;
}
+/*
+ * Debugger support. If not in user mode, set env->debugger before the
+ * riscv_csrrw call and clear it after the call.
+ */
+int riscv_csrrw_debug(CPURISCVState *env, int csrno, target_ulong *ret_value,
+ target_ulong new_value, target_ulong write_mask)
+{
+ int ret;
+#if !defined(CONFIG_USER_ONLY)
+ env->debugger = true;
+#endif
+ ret = riscv_csrrw(env, csrno, ret_value, new_value, write_mask);
+#if !defined(CONFIG_USER_ONLY)
+ env->debugger = false;
+#endif
+ return ret;
+}
+
/* Control and Status Register function table */
static riscv_csr_operations csr_ops[CSR_TABLE_SIZE] = {
/* User Floating-Point CSRs */
diff --git a/target/riscv/gdbstub.c b/target/riscv/gdbstub.c
index 3cabb21cd0..dfcdd834cf 100644
--- a/target/riscv/gdbstub.c
+++ b/target/riscv/gdbstub.c
@@ -21,6 +21,255 @@
#include "exec/gdbstub.h"
#include "cpu.h"
+/*
+ * The GDB CSR xml files list them in documentation order, not numerical order,
+ * and are missing entries for unnamed CSRs. So we need to map the gdb numbers
+ * to the hardware numbers.
+ */
+
+static int csr_register_map[] = {
+ CSR_USTATUS,
+ CSR_UIE,
+ CSR_UTVEC,
+ CSR_USCRATCH,
+ CSR_UEPC,
+ CSR_UCAUSE,
+ CSR_UTVAL,
+ CSR_UIP,
+ CSR_FFLAGS,
+ CSR_FRM,
+ CSR_FCSR,
+ CSR_CYCLE,
+ CSR_TIME,
+ CSR_INSTRET,
+ CSR_HPMCOUNTER3,
+ CSR_HPMCOUNTER4,
+ CSR_HPMCOUNTER5,
+ CSR_HPMCOUNTER6,
+ CSR_HPMCOUNTER7,
+ CSR_HPMCOUNTER8,
+ CSR_HPMCOUNTER9,
+ CSR_HPMCOUNTER10,
+ CSR_HPMCOUNTER11,
+ CSR_HPMCOUNTER12,
+ CSR_HPMCOUNTER13,
+ CSR_HPMCOUNTER14,
+ CSR_HPMCOUNTER15,
+ CSR_HPMCOUNTER16,
+ CSR_HPMCOUNTER17,
+ CSR_HPMCOUNTER18,
+ CSR_HPMCOUNTER19,
+ CSR_HPMCOUNTER20,
+ CSR_HPMCOUNTER21,
+ CSR_HPMCOUNTER22,
+ CSR_HPMCOUNTER23,
+ CSR_HPMCOUNTER24,
+ CSR_HPMCOUNTER25,
+ CSR_HPMCOUNTER26,
+ CSR_HPMCOUNTER27,
+ CSR_HPMCOUNTER28,
+ CSR_HPMCOUNTER29,
+ CSR_HPMCOUNTER30,
+ CSR_HPMCOUNTER31,
+ CSR_CYCLEH,
+ CSR_TIMEH,
+ CSR_INSTRETH,
+ CSR_HPMCOUNTER3H,
+ CSR_HPMCOUNTER4H,
+ CSR_HPMCOUNTER5H,
+ CSR_HPMCOUNTER6H,
+ CSR_HPMCOUNTER7H,
+ CSR_HPMCOUNTER8H,
+ CSR_HPMCOUNTER9H,
+ CSR_HPMCOUNTER10H,
+ CSR_HPMCOUNTER11H,
+ CSR_HPMCOUNTER12H,
+ CSR_HPMCOUNTER13H,
+ CSR_HPMCOUNTER14H,
+ CSR_HPMCOUNTER15H,
+ CSR_HPMCOUNTER16H,
+ CSR_HPMCOUNTER17H,
+ CSR_HPMCOUNTER18H,
+ CSR_HPMCOUNTER19H,
+ CSR_HPMCOUNTER20H,
+ CSR_HPMCOUNTER21H,
+ CSR_HPMCOUNTER22H,
+ CSR_HPMCOUNTER23H,
+ CSR_HPMCOUNTER24H,
+ CSR_HPMCOUNTER25H,
+ CSR_HPMCOUNTER26H,
+ CSR_HPMCOUNTER27H,
+ CSR_HPMCOUNTER28H,
+ CSR_HPMCOUNTER29H,
+ CSR_HPMCOUNTER30H,
+ CSR_HPMCOUNTER31H,
+ CSR_SSTATUS,
+ CSR_SEDELEG,
+ CSR_SIDELEG,
+ CSR_SIE,
+ CSR_STVEC,
+ CSR_SCOUNTEREN,
+ CSR_SSCRATCH,
+ CSR_SEPC,
+ CSR_SCAUSE,
+ CSR_STVAL,
+ CSR_SIP,
+ CSR_SATP,
+ CSR_MVENDORID,
+ CSR_MARCHID,
+ CSR_MIMPID,
+ CSR_MHARTID,
+ CSR_MSTATUS,
+ CSR_MISA,
+ CSR_MEDELEG,
+ CSR_MIDELEG,
+ CSR_MIE,
+ CSR_MTVEC,
+ CSR_MCOUNTEREN,
+ CSR_MSCRATCH,
+ CSR_MEPC,
+ CSR_MCAUSE,
+ CSR_MTVAL,
+ CSR_MIP,
+ CSR_PMPCFG0,
+ CSR_PMPCFG1,
+ CSR_PMPCFG2,
+ CSR_PMPCFG3,
+ CSR_PMPADDR0,
+ CSR_PMPADDR1,
+ CSR_PMPADDR2,
+ CSR_PMPADDR3,
+ CSR_PMPADDR4,
+ CSR_PMPADDR5,
+ CSR_PMPADDR6,
+ CSR_PMPADDR7,
+ CSR_PMPADDR8,
+ CSR_PMPADDR9,
+ CSR_PMPADDR10,
+ CSR_PMPADDR11,
+ CSR_PMPADDR12,
+ CSR_PMPADDR13,
+ CSR_PMPADDR14,
+ CSR_PMPADDR15,
+ CSR_MCYCLE,
+ CSR_MINSTRET,
+ CSR_MHPMCOUNTER3,
+ CSR_MHPMCOUNTER4,
+ CSR_MHPMCOUNTER5,
+ CSR_MHPMCOUNTER6,
+ CSR_MHPMCOUNTER7,
+ CSR_MHPMCOUNTER8,
+ CSR_MHPMCOUNTER9,
+ CSR_MHPMCOUNTER10,
+ CSR_MHPMCOUNTER11,
+ CSR_MHPMCOUNTER12,
+ CSR_MHPMCOUNTER13,
+ CSR_MHPMCOUNTER14,
+ CSR_MHPMCOUNTER15,
+ CSR_MHPMCOUNTER16,
+ CSR_MHPMCOUNTER17,
+ CSR_MHPMCOUNTER18,
+ CSR_MHPMCOUNTER19,
+ CSR_MHPMCOUNTER20,
+ CSR_MHPMCOUNTER21,
+ CSR_MHPMCOUNTER22,
+ CSR_MHPMCOUNTER23,
+ CSR_MHPMCOUNTER24,
+ CSR_MHPMCOUNTER25,
+ CSR_MHPMCOUNTER26,
+ CSR_MHPMCOUNTER27,
+ CSR_MHPMCOUNTER28,
+ CSR_MHPMCOUNTER29,
+ CSR_MHPMCOUNTER30,
+ CSR_MHPMCOUNTER31,
+ CSR_MCYCLEH,
+ CSR_MINSTRETH,
+ CSR_MHPMCOUNTER3H,
+ CSR_MHPMCOUNTER4H,
+ CSR_MHPMCOUNTER5H,
+ CSR_MHPMCOUNTER6H,
+ CSR_MHPMCOUNTER7H,
+ CSR_MHPMCOUNTER8H,
+ CSR_MHPMCOUNTER9H,
+ CSR_MHPMCOUNTER10H,
+ CSR_MHPMCOUNTER11H,
+ CSR_MHPMCOUNTER12H,
+ CSR_MHPMCOUNTER13H,
+ CSR_MHPMCOUNTER14H,
+ CSR_MHPMCOUNTER15H,
+ CSR_MHPMCOUNTER16H,
+ CSR_MHPMCOUNTER17H,
+ CSR_MHPMCOUNTER18H,
+ CSR_MHPMCOUNTER19H,
+ CSR_MHPMCOUNTER20H,
+ CSR_MHPMCOUNTER21H,
+ CSR_MHPMCOUNTER22H,
+ CSR_MHPMCOUNTER23H,
+ CSR_MHPMCOUNTER24H,
+ CSR_MHPMCOUNTER25H,
+ CSR_MHPMCOUNTER26H,
+ CSR_MHPMCOUNTER27H,
+ CSR_MHPMCOUNTER28H,
+ CSR_MHPMCOUNTER29H,
+ CSR_MHPMCOUNTER30H,
+ CSR_MHPMCOUNTER31H,
+ CSR_MHPMEVENT3,
+ CSR_MHPMEVENT4,
+ CSR_MHPMEVENT5,
+ CSR_MHPMEVENT6,
+ CSR_MHPMEVENT7,
+ CSR_MHPMEVENT8,
+ CSR_MHPMEVENT9,
+ CSR_MHPMEVENT10,
+ CSR_MHPMEVENT11,
+ CSR_MHPMEVENT12,
+ CSR_MHPMEVENT13,
+ CSR_MHPMEVENT14,
+ CSR_MHPMEVENT15,
+ CSR_MHPMEVENT16,
+ CSR_MHPMEVENT17,
+ CSR_MHPMEVENT18,
+ CSR_MHPMEVENT19,
+ CSR_MHPMEVENT20,
+ CSR_MHPMEVENT21,
+ CSR_MHPMEVENT22,
+ CSR_MHPMEVENT23,
+ CSR_MHPMEVENT24,
+ CSR_MHPMEVENT25,
+ CSR_MHPMEVENT26,
+ CSR_MHPMEVENT27,
+ CSR_MHPMEVENT28,
+ CSR_MHPMEVENT29,
+ CSR_MHPMEVENT30,
+ CSR_MHPMEVENT31,
+ CSR_TSELECT,
+ CSR_TDATA1,
+ CSR_TDATA2,
+ CSR_TDATA3,
+ CSR_DCSR,
+ CSR_DPC,
+ CSR_DSCRATCH,
+ CSR_HSTATUS,
+ CSR_HEDELEG,
+ CSR_HIDELEG,
+ CSR_HIE,
+ CSR_HTVEC,
+ CSR_HSCRATCH,
+ CSR_HEPC,
+ CSR_HCAUSE,
+ CSR_HBADADDR,
+ CSR_HIP,
+ CSR_MBASE,
+ CSR_MBOUND,
+ CSR_MIBASE,
+ CSR_MIBOUND,
+ CSR_MDBASE,
+ CSR_MDBOUND,
+ CSR_MUCOUNTEREN,
+ CSR_MSCOUNTEREN,
+ CSR_MHCOUNTEREN,
+};
+
int riscv_cpu_gdb_read_register(CPUState *cs, uint8_t *mem_buf, int n)
{
RISCVCPU *cpu = RISCV_CPU(cs);
@@ -30,13 +279,6 @@ int riscv_cpu_gdb_read_register(CPUState *cs, uint8_t *mem_buf, int n)
return gdb_get_regl(mem_buf, env->gpr[n]);
} else if (n == 32) {
return gdb_get_regl(mem_buf, env->pc);
- } else if (n < 65) {
- return gdb_get_reg64(mem_buf, env->fpr[n - 33]);
- } else if (n < 4096 + 65) {
- target_ulong val = 0;
- if (riscv_csrrw(env, n - 65, &val, 0, 0) == 0) {
- return gdb_get_regl(mem_buf, val);
- }
}
return 0;
}
@@ -55,14 +297,100 @@ int riscv_cpu_gdb_write_register(CPUState *cs, uint8_t *mem_buf, int n)
} else if (n == 32) {
env->pc = ldtul_p(mem_buf);
return sizeof(target_ulong);
- } else if (n < 65) {
- env->fpr[n - 33] = ldq_p(mem_buf); /* always 64-bit */
+ }
+ return 0;
+}
+
+static int riscv_gdb_get_fpu(CPURISCVState *env, uint8_t *mem_buf, int n)
+{
+ if (n < 32) {
+ return gdb_get_reg64(mem_buf, env->fpr[n]);
+ /* there is hole between ft11 and fflags in fpu.xml */
+ } else if (n < 36 && n > 32) {
+ target_ulong val = 0;
+ int result;
+ /*
+ * CSR_FFLAGS is at index 8 in csr_register, and gdb says it is FP
+ * register 33, so we recalculate the map index.
+ * This also works for CSR_FRM and CSR_FCSR.
+ */
+ result = riscv_csrrw_debug(env, n - 33 + 8, &val, 0, 0);
+ if (result == 0) {
+ return gdb_get_regl(mem_buf, val);
+ }
+ }
+ return 0;
+}
+
+static int riscv_gdb_set_fpu(CPURISCVState *env, uint8_t *mem_buf, int n)
+{
+ if (n < 32) {
+ env->fpr[n] = ldq_p(mem_buf); /* always 64-bit */
return sizeof(uint64_t);
- } else if (n < 4096 + 65) {
+ /* there is hole between ft11 and fflags in fpu.xml */
+ } else if (n < 36 && n > 32) {
target_ulong val = ldtul_p(mem_buf);
- if (riscv_csrrw(env, n - 65, NULL, val, -1) == 0) {
+ int result;
+ /*
+ * CSR_FFLAGS is at index 8 in csr_register, and gdb says it is FP
+ * register 33, so we recalculate the map index.
+ * This also works for CSR_FRM and CSR_FCSR.
+ */
+ result = riscv_csrrw_debug(env, n - 33 + 8, NULL, val, -1);
+ if (result == 0) {
return sizeof(target_ulong);
}
}
return 0;
}
+
+static int riscv_gdb_get_csr(CPURISCVState *env, uint8_t *mem_buf, int n)
+{
+ if (n < ARRAY_SIZE(csr_register_map)) {
+ target_ulong val = 0;
+ int result;
+
+ result = riscv_csrrw_debug(env, csr_register_map[n], &val, 0, 0);
+ if (result == 0) {
+ return gdb_get_regl(mem_buf, val);
+ }
+ }
+ return 0;
+}
+
+static int riscv_gdb_set_csr(CPURISCVState *env, uint8_t *mem_buf, int n)
+{
+ if (n < ARRAY_SIZE(csr_register_map)) {
+ target_ulong val = ldtul_p(mem_buf);
+ int result;
+
+ result = riscv_csrrw_debug(env, csr_register_map[n], NULL, val, -1);
+ if (result == 0) {
+ return sizeof(target_ulong);
+ }
+ }
+ return 0;
+}
+
+void riscv_cpu_register_gdb_regs_for_features(CPUState *cs)
+{
+ RISCVCPU *cpu = RISCV_CPU(cs);
+ CPURISCVState *env = &cpu->env;
+#if defined(TARGET_RISCV32)
+ if (env->misa & RVF) {
+ gdb_register_coprocessor(cs, riscv_gdb_get_fpu, riscv_gdb_set_fpu,
+ 36, "riscv-32bit-fpu.xml", 0);
+ }
+
+ gdb_register_coprocessor(cs, riscv_gdb_get_csr, riscv_gdb_set_csr,
+ 4096, "riscv-32bit-csr.xml", 0);
+#elif defined(TARGET_RISCV64)
+ if (env->misa & RVF) {
+ gdb_register_coprocessor(cs, riscv_gdb_get_fpu, riscv_gdb_set_fpu,
+ 36, "riscv-64bit-fpu.xml", 0);
+ }
+
+ gdb_register_coprocessor(cs, riscv_gdb_get_csr, riscv_gdb_set_csr,
+ 4096, "riscv-64bit-csr.xml", 0);
+#endif
+}
diff --git a/target/riscv/pmp.c b/target/riscv/pmp.c
index 15a5366616..b11c4ae22f 100644
--- a/target/riscv/pmp.c
+++ b/target/riscv/pmp.c
@@ -113,10 +113,11 @@ static void pmp_write_cfg(CPURISCVState *env, uint32_t pmp_index, uint8_t val)
env->pmp_state.pmp[pmp_index].cfg_reg = val;
pmp_update_rule(env, pmp_index);
} else {
- PMP_DEBUG("ignoring write - locked");
+ qemu_log_mask(LOG_GUEST_ERROR, "ignoring pmpcfg write - locked\n");
}
} else {
- PMP_DEBUG("ignoring write - out of bounds");
+ qemu_log_mask(LOG_GUEST_ERROR,
+ "ignoring pmpcfg write - out of bounds\n");
}
}
@@ -249,7 +250,8 @@ bool pmp_hart_has_privs(CPURISCVState *env, target_ulong addr,
/* partially inside */
if ((s + e) == 1) {
- PMP_DEBUG("pmp violation - access is partially inside");
+ qemu_log_mask(LOG_GUEST_ERROR,
+ "pmp violation - access is partially inside\n");
ret = 0;
break;
}
@@ -306,7 +308,8 @@ void pmpcfg_csr_write(CPURISCVState *env, uint32_t reg_index,
env->mhartid, reg_index, val);
if ((reg_index & 1) && (sizeof(target_ulong) == 8)) {
- PMP_DEBUG("ignoring write - incorrect address");
+ qemu_log_mask(LOG_GUEST_ERROR,
+ "ignoring pmpcfg write - incorrect address\n");
return;
}
@@ -353,10 +356,12 @@ void pmpaddr_csr_write(CPURISCVState *env, uint32_t addr_index,
env->pmp_state.pmp[addr_index].addr_reg = val;
pmp_update_rule(env, addr_index);
} else {
- PMP_DEBUG("ignoring write - locked");
+ qemu_log_mask(LOG_GUEST_ERROR,
+ "ignoring pmpaddr write - locked\n");
}
} else {
- PMP_DEBUG("ignoring write - out of bounds");
+ qemu_log_mask(LOG_GUEST_ERROR,
+ "ignoring pmpaddr write - out of bounds\n");
}
}
@@ -372,7 +377,8 @@ target_ulong pmpaddr_csr_read(CPURISCVState *env, uint32_t addr_index)
if (addr_index < MAX_RISCV_PMPS) {
return env->pmp_state.pmp[addr_index].addr_reg;
} else {
- PMP_DEBUG("ignoring read - out of bounds");
+ qemu_log_mask(LOG_GUEST_ERROR,
+ "ignoring pmpaddr read - out of bounds\n");
return 0;
}
}
diff --git a/target/riscv/trace-events b/target/riscv/trace-events
new file mode 100644
index 0000000000..48af0373df
--- /dev/null
+++ b/target/riscv/trace-events
@@ -0,0 +1,2 @@
+# target/riscv/cpu_helper.c
+riscv_trap(uint64_t hartid, bool async, uint64_t cause, uint64_t epc, uint64_t tval, const char *desc) "hart:%"PRId64", async:%d, cause:%"PRId64", epc:0x%"PRIx64", tval:0x%"PRIx64", desc=%s"