diff --git a/Makefile.objs b/Makefile.objs
index 72debbf5c5..cf065de5ed 100644
--- a/Makefile.objs
+++ b/Makefile.objs
@@ -186,6 +186,7 @@ trace-events-subdirs += target/hppa
trace-events-subdirs += target/i386
trace-events-subdirs += target/mips
trace-events-subdirs += target/ppc
+trace-events-subdirs += target/riscv
trace-events-subdirs += target/s390x
trace-events-subdirs += target/sparc
trace-events-subdirs += ui
diff --git a/configure b/configure
index 02ea221272..c5032425e6 100755
--- a/configure
+++ b/configure
@@ -7514,12 +7514,14 @@ case "$target_name" in
TARGET_BASE_ARCH=riscv
TARGET_ABI_DIR=riscv
mttcg=yes
+ gdb_xml_files="riscv-32bit-cpu.xml riscv-32bit-fpu.xml riscv-32bit-csr.xml"
target_compiler=$cross_cc_riscv32
;;
riscv64)
TARGET_BASE_ARCH=riscv
TARGET_ABI_DIR=riscv
mttcg=yes
+ gdb_xml_files="riscv-64bit-cpu.xml riscv-64bit-fpu.xml riscv-64bit-csr.xml"
target_compiler=$cross_cc_riscv64
;;
sh4|sh4eb)
diff --git a/disas/riscv.c b/disas/riscv.c
index 7fd1019623..27546dd790 100644
--- a/disas/riscv.c
+++ b/disas/riscv.c
@@ -87,33 +87,10 @@ typedef enum {
typedef enum {
rvc_end,
- rvc_simm_6,
- rvc_imm_6,
- rvc_imm_7,
- rvc_imm_8,
- rvc_imm_9,
- rvc_imm_10,
- rvc_imm_12,
- rvc_imm_18,
- rvc_imm_nz,
- rvc_imm_x2,
- rvc_imm_x4,
- rvc_imm_x8,
- rvc_imm_x16,
- rvc_rd_b3,
- rvc_rs1_b3,
- rvc_rs2_b3,
- rvc_rd_eq_rs1,
rvc_rd_eq_ra,
- rvc_rd_eq_sp,
rvc_rd_eq_x0,
- rvc_rs1_eq_sp,
rvc_rs1_eq_x0,
rvc_rs2_eq_x0,
- rvc_rd_ne_x0_x2,
- rvc_rd_ne_x0,
- rvc_rs1_ne_x0,
- rvc_rs2_ne_x0,
rvc_rs2_eq_rs1,
rvc_rs1_eq_ra,
rvc_imm_eq_zero,
@@ -2522,111 +2499,16 @@ static bool check_constraints(rv_decode *dec, const rvc_constraint *c)
uint8_t rd = dec->rd, rs1 = dec->rs1, rs2 = dec->rs2;
while (*c != rvc_end) {
switch (*c) {
- case rvc_simm_6:
- if (!(imm >= -32 && imm < 32)) {
- return false;
- }
- break;
- case rvc_imm_6:
- if (!(imm <= 63)) {
- return false;
- }
- break;
- case rvc_imm_7:
- if (!(imm <= 127)) {
- return false;
- }
- break;
- case rvc_imm_8:
- if (!(imm <= 255)) {
- return false;
- }
- break;
- case rvc_imm_9:
- if (!(imm <= 511)) {
- return false;
- }
- break;
- case rvc_imm_10:
- if (!(imm <= 1023)) {
- return false;
- }
- break;
- case rvc_imm_12:
- if (!(imm <= 4095)) {
- return false;
- }
- break;
- case rvc_imm_18:
- if (!(imm <= 262143)) {
- return false;
- }
- break;
- case rvc_imm_nz:
- if (!(imm != 0)) {
- return false;
- }
- break;
- case rvc_imm_x2:
- if (!((imm & 0b1) == 0)) {
- return false;
- }
- break;
- case rvc_imm_x4:
- if (!((imm & 0b11) == 0)) {
- return false;
- }
- break;
- case rvc_imm_x8:
- if (!((imm & 0b111) == 0)) {
- return false;
- }
- break;
- case rvc_imm_x16:
- if (!((imm & 0b1111) == 0)) {
- return false;
- }
- break;
- case rvc_rd_b3:
- if (!(rd >= 8 && rd <= 15)) {
- return false;
- }
- break;
- case rvc_rs1_b3:
- if (!(rs1 >= 8 && rs1 <= 15)) {
- return false;
- }
- break;
- case rvc_rs2_b3:
- if (!(rs2 >= 8 && rs2 <= 15)) {
- return false;
- }
- break;
- case rvc_rd_eq_rs1:
- if (!(rd == rs1)) {
- return false;
- }
- break;
case rvc_rd_eq_ra:
if (!(rd == 1)) {
return false;
}
break;
- case rvc_rd_eq_sp:
- if (!(rd == 2)) {
- return false;
- }
- break;
case rvc_rd_eq_x0:
if (!(rd == 0)) {
return false;
}
break;
- case rvc_rs1_eq_sp:
- if (!(rs1 == 2)) {
- return false;
- }
- break;
case rvc_rs1_eq_x0:
if (!(rs1 == 0)) {
return false;
@@ -2637,26 +2519,6 @@ static bool check_constraints(rv_decode *dec, const rvc_constraint *c)
return false;
}
break;
- case rvc_rd_ne_x0_x2:
- if (!(rd != 0 && rd != 2)) {
- return false;
- }
- break;
- case rvc_rd_ne_x0:
- if (!(rd != 0)) {
- return false;
- }
- break;
- case rvc_rs1_ne_x0:
- if (!(rs1 != 0)) {
- return false;
- }
- break;
- case rvc_rs2_ne_x0:
- if (!(rs2 != 0)) {
- return false;
- }
- break;
case rvc_rs2_eq_rs1:
if (!(rs2 == rs1)) {
return false;
diff --git a/gdb-xml/riscv-32bit-cpu.xml b/gdb-xml/riscv-32bit-cpu.xml
new file mode 100644
index 0000000000..0d07aaec85
--- /dev/null
+++ b/gdb-xml/riscv-32bit-cpu.xml
@@ -0,0 +1,47 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/gdb-xml/riscv-32bit-csr.xml b/gdb-xml/riscv-32bit-csr.xml
new file mode 100644
index 0000000000..da1bf19e2f
--- /dev/null
+++ b/gdb-xml/riscv-32bit-csr.xml
@@ -0,0 +1,250 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/gdb-xml/riscv-32bit-fpu.xml b/gdb-xml/riscv-32bit-fpu.xml
new file mode 100644
index 0000000000..1eaae9119e
--- /dev/null
+++ b/gdb-xml/riscv-32bit-fpu.xml
@@ -0,0 +1,50 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/gdb-xml/riscv-64bit-cpu.xml b/gdb-xml/riscv-64bit-cpu.xml
new file mode 100644
index 0000000000..b8aa424ae4
--- /dev/null
+++ b/gdb-xml/riscv-64bit-cpu.xml
@@ -0,0 +1,47 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/gdb-xml/riscv-64bit-csr.xml b/gdb-xml/riscv-64bit-csr.xml
new file mode 100644
index 0000000000..6aa4bed9f5
--- /dev/null
+++ b/gdb-xml/riscv-64bit-csr.xml
@@ -0,0 +1,250 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/gdb-xml/riscv-64bit-fpu.xml b/gdb-xml/riscv-64bit-fpu.xml
new file mode 100644
index 0000000000..794854cc01
--- /dev/null
+++ b/gdb-xml/riscv-64bit-fpu.xml
@@ -0,0 +1,56 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/hw/riscv/sifive_plic.c b/hw/riscv/sifive_plic.c
index d12ec3fc9a..1c703e1a37 100644
--- a/hw/riscv/sifive_plic.c
+++ b/hw/riscv/sifive_plic.c
@@ -23,6 +23,7 @@
#include "qemu/error-report.h"
#include "hw/sysbus.h"
#include "target/riscv/cpu.h"
+#include "sysemu/sysemu.h"
#include "hw/riscv/sifive_plic.h"
#define RISCV_DEBUG_PLIC 0
@@ -383,7 +384,7 @@ static void parse_hart_config(SiFivePLICState *plic)
p = plic->hart_config;
while ((c = *p++)) {
if (c == ',') {
- addrid += __builtin_popcount(modes);
+ addrid += ctpop8(modes);
modes = 0;
hartid++;
} else {
@@ -397,7 +398,7 @@ static void parse_hart_config(SiFivePLICState *plic)
}
}
if (modes) {
- addrid += __builtin_popcount(modes);
+ addrid += ctpop8(modes);
}
hartid++;
@@ -431,6 +432,7 @@ static void sifive_plic_irq_request(void *opaque, int irq, int level)
static void sifive_plic_realize(DeviceState *dev, Error **errp)
{
SiFivePLICState *plic = SIFIVE_PLIC(dev);
+ int i;
memory_region_init_io(&plic->mmio, OBJECT(dev), &sifive_plic_ops, plic,
TYPE_SIFIVE_PLIC, plic->aperture_size);
@@ -443,6 +445,19 @@ static void sifive_plic_realize(DeviceState *dev, Error **errp)
plic->enable = g_new0(uint32_t, plic->bitfield_words * plic->num_addrs);
sysbus_init_mmio(SYS_BUS_DEVICE(dev), &plic->mmio);
qdev_init_gpio_in(dev, sifive_plic_irq_request, plic->num_sources);
+
+ /* 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.
+ */
+ for (i = 0; i < smp_cpus; i++) {
+ RISCVCPU *cpu = RISCV_CPU(qemu_get_cpu(i));
+ if (riscv_cpu_claim_interrupts(cpu, MIP_SEIP) < 0) {
+ error_report("SEIP already claimed");
+ exit(1);
+ }
+ }
}
static void sifive_plic_class_init(ObjectClass *klass, void *data)
diff --git a/hw/riscv/sifive_u.c b/hw/riscv/sifive_u.c
index 7bc25820fe..5ecc47cea3 100644
--- a/hw/riscv/sifive_u.c
+++ b/hw/riscv/sifive_u.c
@@ -244,7 +244,7 @@ static void create_fdt(SiFiveUState *s, const struct MemmapEntry *memmap,
qemu_fdt_setprop_cell(fdt, nodename, "clock-frequency",
SIFIVE_U_CLOCK_FREQ / 2);
qemu_fdt_setprop_cells(fdt, nodename, "interrupt-parent", plic_phandle);
- qemu_fdt_setprop_cells(fdt, nodename, "interrupts", 1);
+ qemu_fdt_setprop_cells(fdt, nodename, "interrupts", SIFIVE_U_UART0_IRQ);
qemu_fdt_add_subnode(fdt, "/chosen");
qemu_fdt_setprop_string(fdt, "/chosen", "stdout-path", nodename);
@@ -398,7 +398,10 @@ static void riscv_sifive_u_machine_init(MachineClass *mc)
{
mc->desc = "RISC-V Board compatible with SiFive U SDK";
mc->init = riscv_sifive_u_init;
- mc->max_cpus = 1;
+ /* The real hardware has 5 CPUs, but one of them is a small embedded power
+ * management CPU.
+ */
+ mc->max_cpus = 4;
}
DEFINE_MACHINE("sifive_u", riscv_sifive_u_machine_init)
diff --git a/hw/riscv/sifive_uart.c b/hw/riscv/sifive_uart.c
index 456a3d3697..3b3f94f51d 100644
--- a/hw/riscv/sifive_uart.c
+++ b/hw/riscv/sifive_uart.c
@@ -51,7 +51,8 @@ static uint64_t uart_ip(SiFiveUARTState *s)
static void update_irq(SiFiveUARTState *s)
{
int cond = 0;
- if ((s->ie & SIFIVE_UART_IE_RXWM) && s->rx_fifo_len) {
+ if ((s->ie & SIFIVE_UART_IE_TXWM) ||
+ ((s->ie & SIFIVE_UART_IE_RXWM) && s->rx_fifo_len)) {
cond = 1;
}
if (cond) {
@@ -108,6 +109,7 @@ uart_write(void *opaque, hwaddr addr,
switch (addr) {
case SIFIVE_UART_TXFIFO:
qemu_chr_fe_write(&s->chr, &ch, 1);
+ update_irq(s);
return;
case SIFIVE_UART_IE:
s->ie = val64;
diff --git a/include/elf.h b/include/elf.h
index b35347eee7..ea7708a4ea 100644
--- a/include/elf.h
+++ b/include/elf.h
@@ -1393,6 +1393,16 @@ typedef struct {
#define R_RISCV_SET16 55
#define R_RISCV_SET32 56
+/* RISC-V ELF Flags. */
+#define EF_RISCV_RVC 0x0001
+#define EF_RISCV_FLOAT_ABI 0x0006
+#define EF_RISCV_FLOAT_ABI_SOFT 0x0000
+#define EF_RISCV_FLOAT_ABI_SINGLE 0x0002
+#define EF_RISCV_FLOAT_ABI_DOUBLE 0x0004
+#define EF_RISCV_FLOAT_ABI_QUAD 0x0006
+#define EF_RISCV_RVE 0x0008
+#define EF_RISCV_TSO 0x0010
+
typedef struct elf32_rel {
Elf32_Addr r_offset;
Elf32_Word r_info;
diff --git a/linux-user/riscv/cpu_loop.c b/linux-user/riscv/cpu_loop.c
index 4cf3e94632..a9bac4ca79 100644
--- a/linux-user/riscv/cpu_loop.c
+++ b/linux-user/riscv/cpu_loop.c
@@ -18,8 +18,10 @@
*/
#include "qemu/osdep.h"
+#include "qemu/error-report.h"
#include "qemu.h"
#include "cpu_loop-common.h"
+#include "elf.h"
void cpu_loop(CPURISCVState *env)
{
@@ -53,7 +55,8 @@ void cpu_loop(CPURISCVState *env)
ret = 0;
} else {
ret = do_syscall(env,
- env->gpr[xA7],
+ env->gpr[(env->elf_flags & EF_RISCV_RVE)
+ ? xT0 : xA7],
env->gpr[xA0],
env->gpr[xA1],
env->gpr[xA2],
@@ -113,6 +116,16 @@ void cpu_loop(CPURISCVState *env)
void target_cpu_copy_regs(CPUArchState *env, struct target_pt_regs *regs)
{
+ CPUState *cpu = ENV_GET_CPU(env);
+ TaskState *ts = cpu->opaque;
+ struct image_info *info = ts->info;
+
env->pc = regs->sepc;
env->gpr[xSP] = regs->sp;
+ env->elf_flags = info->elf_flags;
+
+ if ((env->misa & RVE) && !(env->elf_flags & EF_RISCV_RVE)) {
+ error_report("Incompatible ELF: RVE cpu requires RVE ABI binary");
+ exit(EXIT_FAILURE);
+ }
}
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;
+ }
+ /* 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 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;
- }
- }
+ trace_riscv_trap(env->mhartid, async, cause, env->pc, tval, cause < 16 ?
+ (async ? riscv_intr_names : riscv_excp_names)[cause] : "(unknown)");
- 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));
- }
-
- 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"