From 1a987a1d5faaff6c3616a857c111aa3fd9d40ffa Mon Sep 17 00:00:00 2001 From: Jim Wilson Date: Fri, 15 Mar 2019 03:26:55 -0700 Subject: [PATCH 01/19] RISC-V: Add 32-bit gdb xml files. Signed-off-by: Jim Wilson Signed-off-by: Chih-Min Chao Reviewed-by: Alistair Francis Signed-off-by: Palmer Dabbelt --- configure | 1 + gdb-xml/riscv-32bit-cpu.xml | 47 +++++++ gdb-xml/riscv-32bit-csr.xml | 250 ++++++++++++++++++++++++++++++++++++ gdb-xml/riscv-32bit-fpu.xml | 50 ++++++++ 4 files changed, 348 insertions(+) create mode 100644 gdb-xml/riscv-32bit-cpu.xml create mode 100644 gdb-xml/riscv-32bit-csr.xml create mode 100644 gdb-xml/riscv-32bit-fpu.xml diff --git a/configure b/configure index 02ea221272..e191456828 100755 --- a/configure +++ b/configure @@ -7514,6 +7514,7 @@ 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) 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..32a1dee415 --- /dev/null +++ b/gdb-xml/riscv-32bit-fpu.xml @@ -0,0 +1,50 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + From c670970dc069ebaf941a786f0608fca701dcf7d0 Mon Sep 17 00:00:00 2001 From: Jim Wilson Date: Fri, 15 Mar 2019 03:26:56 -0700 Subject: [PATCH 02/19] RISC-V: Add 64-bit gdb xml files. Signed-off-by: Jim Wilson Signed-off-by: Chih-Min Chao Reviewed-by: Alistair Francis Signed-off-by: Palmer Dabbelt --- configure | 1 + gdb-xml/riscv-32bit-fpu.xml | 6 +- gdb-xml/riscv-64bit-cpu.xml | 47 +++++++ gdb-xml/riscv-64bit-csr.xml | 250 ++++++++++++++++++++++++++++++++++++ gdb-xml/riscv-64bit-fpu.xml | 56 ++++++++ 5 files changed, 357 insertions(+), 3 deletions(-) create mode 100644 gdb-xml/riscv-64bit-cpu.xml create mode 100644 gdb-xml/riscv-64bit-csr.xml create mode 100644 gdb-xml/riscv-64bit-fpu.xml diff --git a/configure b/configure index e191456828..c5032425e6 100755 --- a/configure +++ b/configure @@ -7521,6 +7521,7 @@ case "$target_name" in 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/gdb-xml/riscv-32bit-fpu.xml b/gdb-xml/riscv-32bit-fpu.xml index 32a1dee415..1eaae9119e 100644 --- a/gdb-xml/riscv-32bit-fpu.xml +++ b/gdb-xml/riscv-32bit-fpu.xml @@ -44,7 +44,7 @@ - - - + + + 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 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + From 8e73df6aa3f2f0e5c26c03a94a88406616291815 Mon Sep 17 00:00:00 2001 From: Jim Wilson Date: Fri, 15 Mar 2019 03:26:57 -0700 Subject: [PATCH 03/19] RISC-V: Fixes to CSR_* register macros. This adds some missing CSR_* register macros, and documents some as being priv v1.9.1 specific. Signed-off-by: Jim Wilson Reviewed-by: Alistair Francis Message-Id: <20190212230830.9160-1-jimw@sifive.com> Signed-off-by: Palmer Dabbelt --- target/riscv/cpu_bits.h | 35 +++++++++++++++++++++++++++++++++-- 1 file changed, 33 insertions(+), 2 deletions(-) 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 From 753e3fe207db08ce0ef0405e8452c3397c9b9308 Mon Sep 17 00:00:00 2001 From: Jim Wilson Date: Fri, 15 Mar 2019 03:26:58 -0700 Subject: [PATCH 04/19] RISC-V: Add debug support for accessing CSRs. Add a debugger field to CPURISCVState. Add riscv_csrrw_debug function to set it. Disable mode checks when debugger field true. Signed-off-by: Jim Wilson Reviewed-by: Alistair Francis Message-Id: <20190212230903.9215-1-jimw@sifive.com> Signed-off-by: Palmer Dabbelt --- target/riscv/cpu.h | 5 +++++ target/riscv/csr.c | 32 +++++++++++++++++++++++++------- 2 files changed, 30 insertions(+), 7 deletions(-) diff --git a/target/riscv/cpu.h b/target/riscv/cpu.h index 5c2aebf132..4c5de30b37 100644 --- a/target/riscv/cpu.h +++ b/target/riscv/cpu.h @@ -172,6 +172,9 @@ struct CPURISCVState { /* physical memory protection */ pmp_table_t pmp_state; + + /* True if in debugger mode. */ + bool debugger; #endif float_status fp_status; @@ -293,6 +296,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) diff --git a/target/riscv/csr.c b/target/riscv/csr.c index 960d2b0aa9..9a40b4c7ba 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; @@ -827,6 +827,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 */ From 5371f5cd7170f29310575977f89e6e35d4d65168 Mon Sep 17 00:00:00 2001 From: Jim Wilson Date: Fri, 15 Mar 2019 03:26:59 -0700 Subject: [PATCH 05/19] RISC-V: Add hooks to use the gdb xml files. The gdb CSR xml file has registers in documentation order, not numerical order, so we need a table to map the register numbers. This also adds fairly standard gdb hooks to access xml specified registers. notice: The fpu xml from gdb 8.3 has unused register #, 65 and make first csr register # become 69. We register extra register on gdb to correct csr offset calculation Signed-off-by: Jim Wilson Signed-off-by: Chih-Min Chao Reviewed-by: Alistair Francis Signed-off-by: Palmer Dabbelt --- target/riscv/cpu.c | 9 +- target/riscv/cpu.h | 2 + target/riscv/gdbstub.c | 350 +++++++++++++++++++++++++++++++++++++++-- 3 files changed, 349 insertions(+), 12 deletions(-) diff --git a/target/riscv/cpu.c b/target/riscv/cpu.c index cc3ddc0ae4..feea169e12 100644 --- a/target/riscv/cpu.c +++ b/target/riscv/cpu.c @@ -311,6 +311,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 +353,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 4c5de30b37..9b673de23e 100644 --- a/target/riscv/cpu.h +++ b/target/riscv/cpu.h @@ -330,6 +330,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/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 +} From aad5ac2311f3ad2c0be12d0eaaf4ef4398438fc2 Mon Sep 17 00:00:00 2001 From: Alistair Francis Date: Sat, 16 Mar 2019 01:20:02 +0000 Subject: [PATCH 06/19] riscv: pmp: Log pmp access errors as guest errors Signed-off-by: Alistair Francis Signed-off-by: Palmer Dabbelt --- target/riscv/pmp.c | 20 +++++++++++++------- 1 file changed, 13 insertions(+), 7 deletions(-) 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; } } From 244df421333970e66bc48e48e7fb45fcb1017ea0 Mon Sep 17 00:00:00 2001 From: Michael Clark Date: Sat, 16 Mar 2019 01:20:11 +0000 Subject: [PATCH 07/19] RISC-V: Replace __builtin_popcount with ctpop8 in PLIC The mode variable only uses the lower 4-bits (M,H,S,U) so replace the GCC specific __builtin_popcount with ctpop8. Cc: Palmer Dabbelt Cc: Sagar Karandikar Cc: Bastian Koppelmann Cc: Alistair Francis Signed-off-by: Michael Clark Signed-off-by: Alistair Francis Signed-off-by: Palmer Dabbelt --- hw/riscv/sifive_plic.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/hw/riscv/sifive_plic.c b/hw/riscv/sifive_plic.c index d12ec3fc9a..b859f919a7 100644 --- a/hw/riscv/sifive_plic.c +++ b/hw/riscv/sifive_plic.c @@ -383,7 +383,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 +397,7 @@ static void parse_hart_config(SiFivePLICState *plic) } } if (modes) { - addrid += __builtin_popcount(modes); + addrid += ctpop8(modes); } hartid++; From e3e7039cc24ecf47d81c091e8bb04552d6564ad8 Mon Sep 17 00:00:00 2001 From: Michael Clark Date: Sat, 16 Mar 2019 01:20:20 +0000 Subject: [PATCH 08/19] RISC-V: Allow interrupt controllers to claim interrupts 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 logic was previously hard-coded so SEIP was always masked even if no PLIC was attached. This patch adds riscv_cpu_claim_interrupts so that the PLIC can register control of SEIP. In the case of models without a PLIC (spike), the SEIP bit remains software controlled. This interface allows for hardware control of supervisor timer and software interrupts by other interrupt controller models. Cc: Palmer Dabbelt Cc: Sagar Karandikar Cc: Bastian Koppelmann Cc: Alistair Francis Signed-off-by: Michael Clark Signed-off-by: Alistair Francis Signed-off-by: Palmer Dabbelt --- hw/riscv/sifive_plic.c | 15 +++++++++++++++ target/riscv/cpu.h | 2 ++ target/riscv/cpu_helper.c | 11 +++++++++++ target/riscv/csr.c | 10 ++-------- 4 files changed, 30 insertions(+), 8 deletions(-) diff --git a/hw/riscv/sifive_plic.c b/hw/riscv/sifive_plic.c index b859f919a7..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 @@ -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/target/riscv/cpu.h b/target/riscv/cpu.h index 9b673de23e..df43a0898d 100644 --- a/target/riscv/cpu.h +++ b/target/riscv/cpu.h @@ -140,6 +140,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; @@ -266,6 +267,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 diff --git a/target/riscv/cpu_helper.c b/target/riscv/cpu_helper.c index f49e98ed59..555756d40c 100644 --- a/target/riscv/cpu_helper.c +++ b/target/riscv/cpu_helper.c @@ -72,6 +72,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) { diff --git a/target/riscv/csr.c b/target/riscv/csr.c index 9a40b4c7ba..385bb38768 100644 --- a/target/riscv/csr.c +++ b/target/riscv/csr.c @@ -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)); From c124c152428559216c5d083e11a35e51f773c007 Mon Sep 17 00:00:00 2001 From: Michael Clark Date: Sat, 16 Mar 2019 01:20:28 +0000 Subject: [PATCH 09/19] RISC-V: Remove unnecessary disassembler constraints Remove machine generated constraints that are not referenced by the pseudo-instruction constraints. Cc: Palmer Dabbelt Cc: Sagar Karandikar Cc: Bastian Koppelmann Cc: Alistair Francis Signed-off-by: Michael Clark Signed-off-by: Alistair Francis Signed-off-by: Palmer Dabbelt --- disas/riscv.c | 138 -------------------------------------------------- 1 file changed, 138 deletions(-) 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; From c02b78c7b4cecfe0a027abff8ecc3ec02e8b4a53 Mon Sep 17 00:00:00 2001 From: Michael Clark Date: Sat, 16 Mar 2019 01:20:37 +0000 Subject: [PATCH 10/19] elf: Add RISC-V PSABI ELF header defines Refer to the RISC-V PSABI specification for details: - https://github.com/riscv/riscv-elf-psabi-doc/blob/master/riscv-elf.md Cc: Michael Tokarev Cc: Richard Henderson Cc: Alistair Francis Reviewed-by: Laurent Vivier Signed-off-by: Michael Clark Signed-off-by: Alistair Francis Signed-off-by: Palmer Dabbelt --- include/elf.h | 10 ++++++++++ 1 file changed, 10 insertions(+) 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; From 5836c3eccedb6dfab16b8f606f2de24b8938b69c Mon Sep 17 00:00:00 2001 From: Kito Cheng Date: Sat, 16 Mar 2019 01:20:46 +0000 Subject: [PATCH 11/19] RISC-V: linux-user support for RVE ABI This change checks elf_flags for EF_RISCV_RVE and if present uses the RVE linux syscall ABI which uses t0 for the syscall number instead of a7. Warn and exit if a non-RVE ABI binary is run on a cpu with the RVE extension as it is incompatible. Cc: Palmer Dabbelt Cc: Sagar Karandikar Cc: Bastian Koppelmann Cc: Alistair Francis Co-authored-by: Kito Cheng Co-authored-by: Michael Clark Signed-off-by: Michael Clark Signed-off-by: Alistair Francis Signed-off-by: Palmer Dabbelt --- linux-user/riscv/cpu_loop.c | 15 ++++++++++++++- target/riscv/cpu.h | 4 ++++ target/riscv/cpu_user.h | 3 ++- 3 files changed, 20 insertions(+), 2 deletions(-) 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.h b/target/riscv/cpu.h index df43a0898d..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; 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 */ From d26f5a423438e579d3ff0ca35e44edb966a36233 Mon Sep 17 00:00:00 2001 From: Michael Clark Date: Sat, 16 Mar 2019 01:20:54 +0000 Subject: [PATCH 12/19] RISC-V: Change local interrupts from edge to level This effectively changes riscv_cpu_update_mip from edge to level. i.e. cpu_interrupt or cpu_reset_interrupt are called regardless of the current interrupt level. Fixes WFI doesn't return when a IPI is issued: - https://github.com/riscv/riscv-qemu/issues/132 To test: 1) Apply RISC-V Linux CPU hotplug patch: - http://lists.infradead.org/pipermail/linux-riscv/2018-May/000603.html 2) Enable CONFIG_CPU_HOTPLUG in linux .config 3) Try to offline and online cpus: echo 1 > /sys/devices/system/cpu/cpu2/online echo 0 > /sys/devices/system/cpu/cpu2/online echo 1 > /sys/devices/system/cpu/cpu2/online Reported-by: Atish Patra Cc: Atish Patra Cc: Alistair Francis Signed-off-by: Michael Clark Signed-off-by: Alistair Francis Signed-off-by: Palmer Dabbelt --- target/riscv/cpu_helper.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/target/riscv/cpu_helper.c b/target/riscv/cpu_helper.c index 555756d40c..073bdcfe74 100644 --- a/target/riscv/cpu_helper.c +++ b/target/riscv/cpu_helper.c @@ -95,9 +95,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); } From acbbb94e5730c9808830938e869d243014e2923a Mon Sep 17 00:00:00 2001 From: Michael Clark Date: Sat, 16 Mar 2019 01:21:03 +0000 Subject: [PATCH 13/19] RISC-V: Add support for vectored interrupts If vectored interrupts are enabled (bits[1:0] of mtvec/stvec == 1) then use the following logic for trap entry address calculation: pc = mtvec + cause * 4 In addition to adding support for vectored interrupts this patch simplifies the interrupt delivery logic by making sync/async cause decoding and encoding steps distinct. The cause code and the sign bit indicating sync/async is split at the beginning of the function and fixed cause is renamed to cause. The MSB setting for async traps is delayed until setting mcause/scause to allow redundant variables to be eliminated. Some variables are renamed for conciseness and moved so that decls are at the start of the block. Cc: Palmer Dabbelt Cc: Alistair Francis Signed-off-by: Michael Clark Signed-off-by: Alistair Francis Signed-off-by: Palmer Dabbelt --- target/riscv/cpu_helper.c | 151 ++++++++++++++------------------------ target/riscv/csr.c | 12 +-- 2 files changed, 63 insertions(+), 100 deletions(-) diff --git a/target/riscv/cpu_helper.c b/target/riscv/cpu_helper.c index 073bdcfe74..a02f4dad8c 100644 --- a/target/riscv/cpu_helper.c +++ b/target/riscv/cpu_helper.c @@ -454,118 +454,81 @@ void riscv_cpu_do_interrupt(CPUState *cs) RISCVCPU *cpu = RISCV_CPU(cs); CPURISCVState *env = &cpu->env; + /* 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]; + } + } + 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); - } + qemu_log_mask(LOG_TRACE, "core " TARGET_FMT_ld ": %s %s, " + "epc 0x" TARGET_FMT_lx ": tval 0x" TARGET_FMT_lx "\n", + env->mhartid, async ? "intr" : "trap", + (async ? riscv_intr_names : riscv_excp_names)[cause], + env->pc, tval); } - 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; - } - } - - 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 */ diff --git a/target/riscv/csr.c b/target/riscv/csr.c index 385bb38768..e1d91b6c60 100644 --- a/target/riscv/csr.c +++ b/target/riscv/csr.c @@ -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; } @@ -607,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; } From 929f0a7fc40d7123ddda4c9dbd78a1806999b4f7 Mon Sep 17 00:00:00 2001 From: Michael Clark Date: Sat, 16 Mar 2019 01:21:12 +0000 Subject: [PATCH 14/19] RISC-V: Convert trap debugging to trace events Cc: Palmer Dabbelt Cc: Alistair Francis Signed-off-by: Michael Clark Signed-off-by: Alistair Francis Signed-off-by: Palmer Dabbelt --- Makefile.objs | 1 + target/riscv/cpu_helper.c | 12 +++--------- target/riscv/trace-events | 2 ++ 3 files changed, 6 insertions(+), 9 deletions(-) create mode 100644 target/riscv/trace-events 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/target/riscv/cpu_helper.c b/target/riscv/cpu_helper.c index a02f4dad8c..6d3fbc3401 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) { @@ -493,13 +492,8 @@ void riscv_cpu_do_interrupt(CPUState *cs) } } - if (RISCV_DEBUG_INTERRUPT) { - qemu_log_mask(LOG_TRACE, "core " TARGET_FMT_ld ": %s %s, " - "epc 0x" TARGET_FMT_lx ": tval 0x" TARGET_FMT_lx "\n", - env->mhartid, async ? "intr" : "trap", - (async ? riscv_intr_names : riscv_excp_names)[cause], - env->pc, tval); - } + 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 && cause < TARGET_LONG_BITS && ((deleg >> cause) & 1)) { 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" From d9360e96885dbd69ce4aa925d1701c7a10cf54ae Mon Sep 17 00:00:00 2001 From: Michael Clark Date: Sat, 16 Mar 2019 01:21:21 +0000 Subject: [PATCH 15/19] RISC-V: Update load reservation comment in do_interrupt Cc: Palmer Dabbelt Cc: Alistair Francis Signed-off-by: Michael Clark Signed-off-by: Alistair Francis Signed-off-by: Palmer Dabbelt --- target/riscv/cpu_helper.c | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/target/riscv/cpu_helper.c b/target/riscv/cpu_helper.c index 6d3fbc3401..b17f169681 100644 --- a/target/riscv/cpu_helper.c +++ b/target/riscv/cpu_helper.c @@ -525,7 +525,13 @@ void riscv_cpu_do_interrupt(CPUState *cs) ((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 */ } From 8b1d0714bfdd1ac2704519200120e326cba31066 Mon Sep 17 00:00:00 2001 From: Alistair Francis Date: Sat, 16 Mar 2019 01:21:29 +0000 Subject: [PATCH 16/19] riscv: sifive_u: Allow up to 4 CPUs to be created Signed-off-by: Alistair Francis Signed-off-by: Palmer Dabbelt --- hw/riscv/sifive_u.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/hw/riscv/sifive_u.c b/hw/riscv/sifive_u.c index 7bc25820fe..3199238ba0 100644 --- a/hw/riscv/sifive_u.c +++ b/hw/riscv/sifive_u.c @@ -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) From 6b745d4fada5c73db44f596a62e29a5dbe3fc53f Mon Sep 17 00:00:00 2001 From: Alistair Francis Date: Sat, 16 Mar 2019 01:21:39 +0000 Subject: [PATCH 17/19] target/riscv: Remove unused struct Signed-off-by: Alistair Francis Signed-off-by: Palmer Dabbelt --- target/riscv/cpu.c | 6 ------ 1 file changed, 6 deletions(-) diff --git a/target/riscv/cpu.c b/target/riscv/cpu.c index feea169e12..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; From 4e85ea82c1b2cd7c27970b671cd4ca6ef6f78354 Mon Sep 17 00:00:00 2001 From: Bin Meng Date: Sun, 17 Mar 2019 01:03:10 -0700 Subject: [PATCH 18/19] riscv: sifive_uart: Generate TX interrupt At present the sifive uart model only generates RX interrupt. This updates it to generate TX interrupt so that it is more useful. Note the TX fifo is still unimplemented. Signed-off-by: Bin Meng Reviewed-by: Alistair Francis Signed-off-by: Palmer Dabbelt --- hw/riscv/sifive_uart.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) 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; From a9ec1c76d57491602b4d3b521f898905825ca848 Mon Sep 17 00:00:00 2001 From: Bin Meng Date: Sun, 17 Mar 2019 01:03:11 -0700 Subject: [PATCH 19/19] riscv: sifive_u: Correct UART0's IRQ in the device tree The UART0's interrupt vector is wrongly set to 1 in the device tree. Use SIFIVE_U_UART0_IRQ instead. Signed-off-by: Bin Meng Reviewed-by: Alistair Francis Signed-off-by: Palmer Dabbelt --- hw/riscv/sifive_u.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/hw/riscv/sifive_u.c b/hw/riscv/sifive_u.c index 3199238ba0..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);