:p
atchew
Login
From: Alistair Francis <alistair.francis@wdc.com> The following changes since commit c77283dd5d79149f4e7e9edd00f65416c648ee59: Merge tag 'pull-request-2025-07-02' of https://gitlab.com/thuth/qemu into staging (2025-07-03 06:01:41 -0400) are available in the Git repository at: https://github.com/alistair23/qemu.git tags/pull-riscv-to-apply-20250704 for you to fetch changes up to dc8bffc4eb0a93d3266cea1b17f8848dea5b915c: target: riscv: Add Svrsw60t59b extension support (2025-07-04 21:09:49 +1000) ---------------------------------------------------------------- Second RISC-V PR for 10.1 * sstc extension fixes * Fix zama16b order in isa_edata_arr * Profile handling fixes * Extend PMP region up to 64 * Remove capital 'Z' CPU properties * Add missing named features * Support atomic instruction fetch (Ziccif) * Add max_satp_mode from host cpu * Extend and configure PMP region count * Fix PPN field of Translation-reponse register * Use qemu_chr_fe_write_all() in DBCN_CONSOLE_WRITE_BYTE * Fix fcvt.s.bf16 NaN box checking * Avoid infinite delay of async xmit function * Device tree reg cleanups * Add Kunminghu CPU and platform * Fix missing exit TB flow for ldff_trans * Fix migration failure when aia is configured as aplic-imsic * Fix MEPC/SEPC bit masking for IALIGN * Add a property to set vill bit on reserved usage of vsetvli instruction * Add Svrsw60t59b extension support ---------------------------------------------------------------- Alexandre Ghiti (1): target: riscv: Add Svrsw60t59b extension support Anton Blanchard (1): target/riscv: Fix fcvt.s.bf16 NaN box checking Charalampos Mitrodimas (2): target/riscv: Fix MEPC/SEPC bit masking for IALIGN tests/tcg/riscv64: Add test for MEPC bit masking Daniel Henrique Barboza (9): target/riscv/cpu.c: fix zama16b order in isa_edata_arr[] target/riscv/tcg: restrict satp_mode changes in cpu_set_profile target/riscv/tcg: decouple profile enablement from user prop target/riscv: add profile->present flag target/riscv: remove capital 'Z' CPU properties target/riscv/cpu.c: add 'sdtrig' in riscv,isa target/riscv/cpu.c: add 'ssstrict' to riscv, isa target/riscv/cpu.c: do better with 'named features' doc target/riscv: use qemu_chr_fe_write_all() in DBCN_CONSOLE_WRITE_BYTE Florian Lugou (1): hw/char: sifive_uart: Avoid infinite delay of async xmit function Huang Borong (2): target/riscv: Add BOSC's Xiangshan Kunminghu CPU hw/riscv: Initial support for BOSC's Xiangshan Kunminghu FPGA prototype Jay Chang (2): target/riscv: Extend PMP region up to 64 target/riscv: Make PMP region count configurable Jim Shu (5): target/riscv: Add the checking into stimecmp write function. hw/intc: riscv_aclint: Fix mtime write for sstc extension target/riscv: Fix VSTIP bit in sstc extension. target/riscv: Enable/Disable S/VS-mode Timer when STCE bit is changed target/riscv: support atomic instruction fetch (Ziccif) Joel Stanley (12): hw/riscv/virt: Fix clint base address type hw/riscv/virt: Use setprop_sized_cells for clint hw/riscv/virt: Use setprop_sized_cells for memory hw/riscv/virt: Use setprop_sized_cells for aplic hw/riscv/virt: Use setprop_sized_cells for aclint hw/riscv/virt: Use setprop_sized_cells for plic hw/riscv/virt: Use setprop_sized_cells for virtio hw/riscv/virt: Use setprop_sized_cells for reset hw/riscv/virt: Use setprop_sized_cells for uart hw/riscv/virt: Use setprop_sized_cells for rtc hw/riscv/virt: Use setprop_sized_cells for iommu hw/riscv/virt: Use setprop_sized_cells for pcie Max Chou (1): target/riscv: rvv: Fix missing exit TB flow for ldff_trans Meng Zhuo (1): target/riscv/kvm: add max_satp_mode from host cpu Nutty Liu (1): hw/riscv/riscv-iommu: Fix PPN field of Translation-reponse register Vasilis Liaskovitis (1): target/riscv: Add a property to set vill bit on reserved usage of vsetvli instruction liu.xuemei1@zte.com.cn (1): migration: Fix migration failure when aia is configured as aplic-imsic MAINTAINERS | 7 + docs/system/riscv/xiangshan-kunminghu.rst | 39 +++++ docs/system/target-riscv.rst | 1 + configs/devices/riscv64-softmmu/default.mak | 1 + hw/riscv/riscv-iommu-bits.h | 1 + include/hw/riscv/xiangshan_kmh.h | 68 +++++++++ target/riscv/cpu-qom.h | 1 + target/riscv/cpu.h | 19 ++- target/riscv/cpu_bits.h | 63 +++++++- target/riscv/helper.h | 2 +- target/riscv/internals.h | 27 ++++ target/riscv/time_helper.h | 1 + target/riscv/cpu_cfg_fields.h.inc | 3 + hw/char/sifive_uart.c | 6 +- hw/intc/riscv_aclint.c | 5 + hw/intc/riscv_aplic.c | 12 +- hw/intc/riscv_imsic.c | 10 +- hw/riscv/riscv-iommu.c | 9 +- hw/riscv/virt.c | 66 ++++----- hw/riscv/xiangshan_kmh.c | 220 ++++++++++++++++++++++++++++ target/riscv/cpu.c | 144 +++++++++++++++--- target/riscv/cpu_helper.c | 3 +- target/riscv/csr.c | 192 +++++++++++++++++++++++- target/riscv/fpu_helper.c | 2 +- target/riscv/kvm/kvm-cpu.c | 18 ++- target/riscv/machine.c | 3 +- target/riscv/op_helper.c | 4 +- target/riscv/pmp.c | 28 ++-- target/riscv/riscv-qmp-cmds.c | 2 +- target/riscv/tcg/tcg-cpu.c | 186 +++++++++++------------ target/riscv/time_helper.c | 65 +++++++- target/riscv/translate.c | 46 ++++-- target/riscv/vector_helper.c | 12 +- target/riscv/insn_trans/trans_rvv.c.inc | 10 +- hw/riscv/Kconfig | 9 ++ hw/riscv/meson.build | 1 + tests/data/acpi/riscv64/virt/RHCT | Bin 400 -> 416 bytes tests/tcg/riscv64/Makefile.softmmu-target | 4 + tests/tcg/riscv64/test-mepc-masking.S | 73 +++++++++ 39 files changed, 1151 insertions(+), 212 deletions(-) create mode 100644 docs/system/riscv/xiangshan-kunminghu.rst create mode 100644 include/hw/riscv/xiangshan_kmh.h create mode 100644 hw/riscv/xiangshan_kmh.c create mode 100644 tests/tcg/riscv64/test-mepc-masking.S
From: Jim Shu <jim.shu@sifive.com> Preparation commit to let aclint timer to use stimecmp write function. Aclint timer doesn't call sstc() predicate so we need to check inside the stimecmp write function. Signed-off-by: Jim Shu <jim.shu@sifive.com> Acked-by: Alistair Francis <alistair.francis@wdc.com> Message-ID: <20250519143518.11086-2-jim.shu@sifive.com> Signed-off-by: Alistair Francis <alistair.francis@wdc.com> --- target/riscv/time_helper.c | 19 +++++++++++++++++-- 1 file changed, 17 insertions(+), 2 deletions(-) diff --git a/target/riscv/time_helper.c b/target/riscv/time_helper.c index XXXXXXX..XXXXXXX 100644 --- a/target/riscv/time_helper.c +++ b/target/riscv/time_helper.c @@ -XXX,XX +XXX,XX @@ void riscv_timer_write_timecmp(CPURISCVState *env, QEMUTimer *timer, { uint64_t diff, ns_diff, next; RISCVAclintMTimerState *mtimer = env->rdtime_fn_arg; - uint32_t timebase_freq = mtimer->timebase_freq; - uint64_t rtc_r = env->rdtime_fn(env->rdtime_fn_arg) + delta; + uint32_t timebase_freq; + uint64_t rtc_r; + + if (!riscv_cpu_cfg(env)->ext_sstc || !env->rdtime_fn || + !env->rdtime_fn_arg || !get_field(env->menvcfg, MENVCFG_STCE)) { + /* S/VS Timer IRQ depends on sstc extension, rdtime_fn(), and STCE. */ + return; + } + + if (timer_irq == MIP_VSTIP && + (!riscv_has_ext(env, RVH) || !get_field(env->henvcfg, HENVCFG_STCE))) { + /* VS Timer IRQ also depends on RVH and henvcfg.STCE. */ + return; + } + + timebase_freq = mtimer->timebase_freq; + rtc_r = env->rdtime_fn(env->rdtime_fn_arg) + delta; if (timecmp <= rtc_r) { /* -- 2.50.0
From: Jim Shu <jim.shu@sifive.com> When changing the mtime value, the period of [s|vs]timecmp timers should also be updated, similar to the period of mtimecmp timer. The period of the stimecmp timer is the time until the next S-mode timer IRQ. The value is calculated as "stimecmp - time". [1] It is equal to "stimecmp - mtime" since the time CSR is a read-only shadow of the memory-mapped mtime register. Thus, changing mtime value will update the period of stimecmp timer. Similarly, the period of vstimecmp timer is calculated as "vstimecmp - (mtime + htimedelta)" [2], so changing mtime value will update the period of vstimecmp timer. [1] RISC-V Priv spec ch 9.1.1. Supervisor Timer (stimecmp) Register A supervisor timer interrupt becomes pending, as reflected in the STIP bit in the mip and sip registers whenever time contains a value greater than or equal to stimecmp. [2] RISC-V Priv spec ch19.2.1. Virtual Supervisor Timer (vstimecmp) Register A virtual supervisor timer interrupt becomes pending, as reflected in the VSTIP bit in the hip register, whenever (time + htimedelta), truncated to 64 bits, contains a value greater than or equal to vstimecmp Signed-off-by: Jim Shu <jim.shu@sifive.com> Acked-by: Alistair Francis <alistair.francis@wdc.com> Message-ID: <20250519143518.11086-3-jim.shu@sifive.com> Signed-off-by: Alistair Francis <alistair.francis@wdc.com> --- hw/intc/riscv_aclint.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/hw/intc/riscv_aclint.c b/hw/intc/riscv_aclint.c index XXXXXXX..XXXXXXX 100644 --- a/hw/intc/riscv_aclint.c +++ b/hw/intc/riscv_aclint.c @@ -XXX,XX +XXX,XX @@ #include "qemu/module.h" #include "hw/sysbus.h" #include "target/riscv/cpu.h" +#include "target/riscv/time_helper.h" #include "hw/qdev-properties.h" #include "hw/intc/riscv_aclint.h" #include "qemu/timer.h" @@ -XXX,XX +XXX,XX @@ static void riscv_aclint_mtimer_write(void *opaque, hwaddr addr, riscv_aclint_mtimer_write_timecmp(mtimer, RISCV_CPU(cpu), mtimer->hartid_base + i, mtimer->timecmp[i]); + riscv_timer_write_timecmp(env, env->stimer, env->stimecmp, 0, MIP_STIP); + riscv_timer_write_timecmp(env, env->vstimer, env->vstimecmp, + env->htimedelta, MIP_VSTIP); + } return; } -- 2.50.0
From: Jim Shu <jim.shu@sifive.com> VSTIP is only writable when both [mh]envcfg.STCE is enabled, or it will revert it's defined behavior as if sstc extension is not implemented. Signed-off-by: Jim Shu <jim.shu@sifive.com> Acked-by: Alistair Francis <alistair.francis@wdc.com> Message-ID: <20250519143518.11086-4-jim.shu@sifive.com> Signed-off-by: Alistair Francis <alistair.francis@wdc.com> --- target/riscv/csr.c | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/target/riscv/csr.c b/target/riscv/csr.c index XXXXXXX..XXXXXXX 100644 --- a/target/riscv/csr.c +++ b/target/riscv/csr.c @@ -XXX,XX +XXX,XX @@ static RISCVException rmw_mip64(CPURISCVState *env, int csrno, if (riscv_cpu_cfg(env)->ext_sstc && (env->priv == PRV_M) && get_field(env->menvcfg, MENVCFG_STCE)) { /* sstc extension forbids STIP & VSTIP to be writeable in mip */ - mask = mask & ~(MIP_STIP | MIP_VSTIP); + + /* STIP is not writable when menvcfg.STCE is enabled. */ + mask = mask & ~MIP_STIP; + + /* VSTIP is not writable when both [mh]envcfg.STCE are enabled. */ + if (get_field(env->henvcfg, HENVCFG_STCE)) { + mask = mask & ~MIP_VSTIP; + } } if (mask) { -- 2.50.0
From: Jim Shu <jim.shu@sifive.com> Updating STCE will enable/disable SSTC in S-mode or/and VS-mode, so we also need to update S/VS-mode Timer and S/VSTIP bits in $mip CSR. Signed-off-by: Jim Shu <jim.shu@sifive.com> Acked-by: Alistair Francis <alistair.francis@wdc.com> Message-ID: <20250519143518.11086-5-jim.shu@sifive.com> Signed-off-by: Alistair Francis <alistair.francis@wdc.com> --- target/riscv/time_helper.h | 1 + target/riscv/csr.c | 46 ++++++++++++++++++++++++++++++++++++++ target/riscv/time_helper.c | 46 ++++++++++++++++++++++++++++++++++++++ 3 files changed, 93 insertions(+) diff --git a/target/riscv/time_helper.h b/target/riscv/time_helper.h index XXXXXXX..XXXXXXX 100644 --- a/target/riscv/time_helper.h +++ b/target/riscv/time_helper.h @@ -XXX,XX +XXX,XX @@ void riscv_timer_write_timecmp(CPURISCVState *env, QEMUTimer *timer, uint64_t timecmp, uint64_t delta, uint32_t timer_irq); +void riscv_timer_stce_changed(CPURISCVState *env, bool is_m_mode, bool enable); void riscv_timer_init(RISCVCPU *cpu); #endif diff --git a/target/riscv/csr.c b/target/riscv/csr.c index XXXXXXX..XXXXXXX 100644 --- a/target/riscv/csr.c +++ b/target/riscv/csr.c @@ -XXX,XX +XXX,XX @@ static RISCVException write_menvcfg(CPURISCVState *env, int csrno, const RISCVCPUConfig *cfg = riscv_cpu_cfg(env); uint64_t mask = MENVCFG_FIOM | MENVCFG_CBIE | MENVCFG_CBCFE | MENVCFG_CBZE | MENVCFG_CDE; + bool stce_changed = false; if (riscv_cpu_mxl(env) == MXL_RV64) { mask |= (cfg->ext_svpbmt ? MENVCFG_PBMTE : 0) | @@ -XXX,XX +XXX,XX @@ static RISCVException write_menvcfg(CPURISCVState *env, int csrno, if ((val & MENVCFG_DTE) == 0) { env->mstatus &= ~MSTATUS_SDT; } + + if (cfg->ext_sstc && + ((env->menvcfg & MENVCFG_STCE) != (val & MENVCFG_STCE))) { + stce_changed = true; + } } env->menvcfg = (env->menvcfg & ~mask) | (val & mask); + + if (stce_changed) { + riscv_timer_stce_changed(env, true, !!(val & MENVCFG_STCE)); + } + return write_henvcfg(env, CSR_HENVCFG, env->henvcfg, ra); } @@ -XXX,XX +XXX,XX @@ static RISCVException write_menvcfgh(CPURISCVState *env, int csrno, (cfg->ext_smcdeleg ? MENVCFG_CDE : 0) | (cfg->ext_ssdbltrp ? MENVCFG_DTE : 0); uint64_t valh = (uint64_t)val << 32; + bool stce_changed = false; + + if (cfg->ext_sstc && + ((env->menvcfg & MENVCFG_STCE) != (valh & MENVCFG_STCE))) { + stce_changed = true; + } if ((valh & MENVCFG_DTE) == 0) { env->mstatus &= ~MSTATUS_SDT; } env->menvcfg = (env->menvcfg & ~mask) | (valh & mask); + + if (stce_changed) { + riscv_timer_stce_changed(env, true, !!(valh & MENVCFG_STCE)); + } + return write_henvcfgh(env, CSR_HENVCFGH, env->henvcfg >> 32, ra); } @@ -XXX,XX +XXX,XX @@ static RISCVException read_henvcfg(CPURISCVState *env, int csrno, static RISCVException write_henvcfg(CPURISCVState *env, int csrno, target_ulong val, uintptr_t ra) { + const RISCVCPUConfig *cfg = riscv_cpu_cfg(env); uint64_t mask = HENVCFG_FIOM | HENVCFG_CBIE | HENVCFG_CBCFE | HENVCFG_CBZE; RISCVException ret; + bool stce_changed = false; ret = smstateen_acc_ok(env, 0, SMSTATEEN0_HSENVCFG); if (ret != RISCV_EXCP_NONE) { @@ -XXX,XX +XXX,XX @@ static RISCVException write_henvcfg(CPURISCVState *env, int csrno, get_field(val, HENVCFG_PMM) != PMM_FIELD_RESERVED) { mask |= HENVCFG_PMM; } + + if (cfg->ext_sstc && + ((env->henvcfg & HENVCFG_STCE) != (val & HENVCFG_STCE))) { + stce_changed = true; + } } env->henvcfg = val & mask; @@ -XXX,XX +XXX,XX @@ static RISCVException write_henvcfg(CPURISCVState *env, int csrno, env->vsstatus &= ~MSTATUS_SDT; } + if (stce_changed) { + riscv_timer_stce_changed(env, false, !!(val & HENVCFG_STCE)); + } + return RISCV_EXCP_NONE; } @@ -XXX,XX +XXX,XX @@ static RISCVException read_henvcfgh(CPURISCVState *env, int csrno, static RISCVException write_henvcfgh(CPURISCVState *env, int csrno, target_ulong val, uintptr_t ra) { + const RISCVCPUConfig *cfg = riscv_cpu_cfg(env); uint64_t mask = env->menvcfg & (HENVCFG_PBMTE | HENVCFG_STCE | HENVCFG_ADUE | HENVCFG_DTE); uint64_t valh = (uint64_t)val << 32; RISCVException ret; + bool stce_changed = false; ret = smstateen_acc_ok(env, 0, SMSTATEEN0_HSENVCFG); if (ret != RISCV_EXCP_NONE) { return ret; } + + if (cfg->ext_sstc && + ((env->henvcfg & HENVCFG_STCE) != (valh & HENVCFG_STCE))) { + stce_changed = true; + } + env->henvcfg = (env->henvcfg & 0xFFFFFFFF) | (valh & mask); if ((env->henvcfg & HENVCFG_DTE) == 0) { env->vsstatus &= ~MSTATUS_SDT; } + + if (stce_changed) { + riscv_timer_stce_changed(env, false, !!(val & HENVCFG_STCE)); + } + return RISCV_EXCP_NONE; } diff --git a/target/riscv/time_helper.c b/target/riscv/time_helper.c index XXXXXXX..XXXXXXX 100644 --- a/target/riscv/time_helper.c +++ b/target/riscv/time_helper.c @@ -XXX,XX +XXX,XX @@ void riscv_timer_write_timecmp(CPURISCVState *env, QEMUTimer *timer, timer_mod(timer, next); } +/* + * When disabling xenvcfg.STCE, the S/VS Timer may be disabled at the same time. + * It is safe to call this function regardless of whether the timer has been + * deleted or not. timer_del() will do nothing if the timer has already + * been deleted. + */ +static void riscv_timer_disable_timecmp(CPURISCVState *env, QEMUTimer *timer, + uint32_t timer_irq) +{ + /* Disable S-mode Timer IRQ and HW-based STIP */ + if ((timer_irq == MIP_STIP) && !get_field(env->menvcfg, MENVCFG_STCE)) { + riscv_cpu_update_mip(env, timer_irq, BOOL_TO_MASK(0)); + timer_del(timer); + return; + } + + /* Disable VS-mode Timer IRQ and HW-based VSTIP */ + if ((timer_irq == MIP_VSTIP) && + (!get_field(env->menvcfg, MENVCFG_STCE) || + !get_field(env->henvcfg, HENVCFG_STCE))) { + env->vstime_irq = 0; + riscv_cpu_update_mip(env, 0, BOOL_TO_MASK(0)); + timer_del(timer); + return; + } +} + +/* Enable or disable S/VS-mode Timer when xenvcfg.STCE is changed */ +void riscv_timer_stce_changed(CPURISCVState *env, bool is_m_mode, bool enable) +{ + if (enable) { + riscv_timer_write_timecmp(env, env->vstimer, env->vstimecmp, + env->htimedelta, MIP_VSTIP); + } else { + riscv_timer_disable_timecmp(env, env->vstimer, MIP_VSTIP); + } + + if (is_m_mode) { + if (enable) { + riscv_timer_write_timecmp(env, env->stimer, env->stimecmp, 0, MIP_STIP); + } else { + riscv_timer_disable_timecmp(env, env->stimer, MIP_STIP); + } + } +} + void riscv_timer_init(RISCVCPU *cpu) { CPURISCVState *env; -- 2.50.0
From: Daniel Henrique Barboza <dbarboza@ventanamicro.com> Put it after zalrsc and before zawrs. Cc: qemu-trivial@nongnu.org Fixes: a60ce58fd9 ("target/riscv: Support Zama16b extension") Signed-off-by: Daniel Henrique Barboza <dbarboza@ventanamicro.com> Reviewed-by: Alistair Francis <alistair.francis@wdc.com> Message-ID: <20250522113344.823294-1-dbarboza@ventanamicro.com> Signed-off-by: Alistair Francis <alistair.francis@wdc.com> --- target/riscv/cpu.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/target/riscv/cpu.c b/target/riscv/cpu.c index XXXXXXX..XXXXXXX 100644 --- a/target/riscv/cpu.c +++ b/target/riscv/cpu.c @@ -XXX,XX +XXX,XX @@ const RISCVIsaExtData isa_edata_arr[] = { ISA_EXT_DATA_ENTRY(zaamo, PRIV_VERSION_1_12_0, ext_zaamo), ISA_EXT_DATA_ENTRY(zabha, PRIV_VERSION_1_13_0, ext_zabha), ISA_EXT_DATA_ENTRY(zacas, PRIV_VERSION_1_12_0, ext_zacas), - ISA_EXT_DATA_ENTRY(zama16b, PRIV_VERSION_1_13_0, ext_zama16b), ISA_EXT_DATA_ENTRY(zalrsc, PRIV_VERSION_1_12_0, ext_zalrsc), + ISA_EXT_DATA_ENTRY(zama16b, PRIV_VERSION_1_13_0, ext_zama16b), ISA_EXT_DATA_ENTRY(zawrs, PRIV_VERSION_1_12_0, ext_zawrs), ISA_EXT_DATA_ENTRY(zfa, PRIV_VERSION_1_12_0, ext_zfa), ISA_EXT_DATA_ENTRY(zfbfmin, PRIV_VERSION_1_12_0, ext_zfbfmin), -- 2.50.0
From: Daniel Henrique Barboza <dbarboza@ventanamicro.com> We're changing 'mmu' to true regardless of whether the profile is being enabled or not, and at the same time we're changing satp_mode to profile->enabled. This will promote a situation where we'll set mmu=on without a virtual memory mode, which is a mistake. Only touch 'mmu' and satp_mode if the profile is being enabled. Suggested-by: Andrew Jones <ajones@ventanamicro.com> Fixes: 55398025e7 ("target/riscv: add satp_mode profile support") Signed-off-by: Daniel Henrique Barboza <dbarboza@ventanamicro.com> Reviewed-by: Andrew Jones <ajones@ventanamicro.com> Reviewed-by: Björn Töpel <bjorn@rivosinc.com> Tested-by: Björn Töpel <bjorn@rivosinc.com> Message-ID: <20250528184407.1451983-2-dbarboza@ventanamicro.com> Signed-off-by: Alistair Francis <alistair.francis@wdc.com> --- target/riscv/tcg/tcg-cpu.c | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/target/riscv/tcg/tcg-cpu.c b/target/riscv/tcg/tcg-cpu.c index XXXXXXX..XXXXXXX 100644 --- a/target/riscv/tcg/tcg-cpu.c +++ b/target/riscv/tcg/tcg-cpu.c @@ -XXX,XX +XXX,XX @@ static void cpu_set_profile(Object *obj, Visitor *v, const char *name, if (profile->enabled) { cpu->env.priv_ver = profile->priv_spec; - } #ifndef CONFIG_USER_ONLY - if (profile->satp_mode != RISCV_PROFILE_ATTR_UNUSED) { - object_property_set_bool(obj, "mmu", true, NULL); - const char *satp_prop = satp_mode_str(profile->satp_mode, - riscv_cpu_is_32bit(cpu)); - object_property_set_bool(obj, satp_prop, profile->enabled, NULL); - } + if (profile->satp_mode != RISCV_PROFILE_ATTR_UNUSED) { + object_property_set_bool(obj, "mmu", true, NULL); + const char *satp_prop = satp_mode_str(profile->satp_mode, + riscv_cpu_is_32bit(cpu)); + object_property_set_bool(obj, satp_prop, true, NULL); + } #endif + } for (i = 0; misa_bits[i] != 0; i++) { uint32_t bit = misa_bits[i]; -- 2.50.0
From: Daniel Henrique Barboza <dbarboza@ventanamicro.com> We have code in riscv_cpu_add_profiles() to enable a profile right away in case a CPU chose the profile during its cpu_init(). But we're using the user callback option to do so, setting profile->user_set. Create a new helper that does all the grunt work to enable/disable a given profile. Use this new helper in the cases where we want a CPU to be compatible to a certain profile, leaving the user callback to be used exclusively by users. Fixes: fba92a92e3 ("target/riscv: add 'rva22u64' CPU") Signed-off-by: Daniel Henrique Barboza <dbarboza@ventanamicro.com> Reviewed-by: Andrew Jones <ajones@ventanamicro.com> Reviewed-by: Björn Töpel <bjorn@rivosinc.com> Tested-by: Björn Töpel <bjorn@rivosinc.com> Message-ID: <20250528184407.1451983-3-dbarboza@ventanamicro.com> Signed-off-by: Alistair Francis <alistair.francis@wdc.com> --- target/riscv/tcg/tcg-cpu.c | 127 +++++++++++++++++++------------------ 1 file changed, 67 insertions(+), 60 deletions(-) diff --git a/target/riscv/tcg/tcg-cpu.c b/target/riscv/tcg/tcg-cpu.c index XXXXXXX..XXXXXXX 100644 --- a/target/riscv/tcg/tcg-cpu.c +++ b/target/riscv/tcg/tcg-cpu.c @@ -XXX,XX +XXX,XX @@ static bool riscv_cpu_is_generic(Object *cpu_obj) return object_dynamic_cast(cpu_obj, TYPE_RISCV_DYNAMIC_CPU) != NULL; } +static void riscv_cpu_set_profile(RISCVCPU *cpu, + RISCVCPUProfile *profile, + bool enabled) +{ + int i, ext_offset; + + if (profile->u_parent != NULL) { + riscv_cpu_set_profile(cpu, profile->u_parent, enabled); + } + + if (profile->s_parent != NULL) { + riscv_cpu_set_profile(cpu, profile->s_parent, enabled); + } + + profile->enabled = enabled; + + if (profile->enabled) { + cpu->env.priv_ver = profile->priv_spec; + +#ifndef CONFIG_USER_ONLY + if (profile->satp_mode != RISCV_PROFILE_ATTR_UNUSED) { + object_property_set_bool(OBJECT(cpu), "mmu", true, NULL); + const char *satp_prop = satp_mode_str(profile->satp_mode, + riscv_cpu_is_32bit(cpu)); + object_property_set_bool(OBJECT(cpu), satp_prop, true, NULL); + } +#endif + } + + for (i = 0; misa_bits[i] != 0; i++) { + uint32_t bit = misa_bits[i]; + + if (!(profile->misa_ext & bit)) { + continue; + } + + if (bit == RVI && !profile->enabled) { + /* + * Disabling profiles will not disable the base + * ISA RV64I. + */ + continue; + } + + cpu_misa_ext_add_user_opt(bit, profile->enabled); + riscv_cpu_write_misa_bit(cpu, bit, profile->enabled); + } + + for (i = 0; profile->ext_offsets[i] != RISCV_PROFILE_EXT_LIST_END; i++) { + ext_offset = profile->ext_offsets[i]; + + if (profile->enabled) { + if (cpu_cfg_offset_is_named_feat(ext_offset)) { + riscv_cpu_enable_named_feat(cpu, ext_offset); + } + + cpu_bump_multi_ext_priv_ver(&cpu->env, ext_offset); + } + + cpu_cfg_ext_add_user_opt(ext_offset, profile->enabled); + isa_ext_update_enabled(cpu, ext_offset, profile->enabled); + } +} + /* * We'll get here via the following path: * @@ -XXX,XX +XXX,XX @@ static void cpu_set_profile(Object *obj, Visitor *v, const char *name, RISCVCPUProfile *profile = opaque; RISCVCPU *cpu = RISCV_CPU(obj); bool value; - int i, ext_offset; if (riscv_cpu_is_vendor(obj)) { error_setg(errp, "Profile %s is not available for vendor CPUs", @@ -XXX,XX +XXX,XX @@ static void cpu_set_profile(Object *obj, Visitor *v, const char *name, } profile->user_set = true; - profile->enabled = value; - - if (profile->u_parent != NULL) { - object_property_set_bool(obj, profile->u_parent->name, - profile->enabled, NULL); - } - - if (profile->s_parent != NULL) { - object_property_set_bool(obj, profile->s_parent->name, - profile->enabled, NULL); - } - - if (profile->enabled) { - cpu->env.priv_ver = profile->priv_spec; - -#ifndef CONFIG_USER_ONLY - if (profile->satp_mode != RISCV_PROFILE_ATTR_UNUSED) { - object_property_set_bool(obj, "mmu", true, NULL); - const char *satp_prop = satp_mode_str(profile->satp_mode, - riscv_cpu_is_32bit(cpu)); - object_property_set_bool(obj, satp_prop, true, NULL); - } -#endif - } - - for (i = 0; misa_bits[i] != 0; i++) { - uint32_t bit = misa_bits[i]; - - if (!(profile->misa_ext & bit)) { - continue; - } - if (bit == RVI && !profile->enabled) { - /* - * Disabling profiles will not disable the base - * ISA RV64I. - */ - continue; - } - - cpu_misa_ext_add_user_opt(bit, profile->enabled); - riscv_cpu_write_misa_bit(cpu, bit, profile->enabled); - } - - for (i = 0; profile->ext_offsets[i] != RISCV_PROFILE_EXT_LIST_END; i++) { - ext_offset = profile->ext_offsets[i]; - - if (profile->enabled) { - if (cpu_cfg_offset_is_named_feat(ext_offset)) { - riscv_cpu_enable_named_feat(cpu, ext_offset); - } - - cpu_bump_multi_ext_priv_ver(&cpu->env, ext_offset); - } - - cpu_cfg_ext_add_user_opt(ext_offset, profile->enabled); - isa_ext_update_enabled(cpu, ext_offset, profile->enabled); - } + riscv_cpu_set_profile(cpu, profile, value); } static void cpu_get_profile(Object *obj, Visitor *v, const char *name, @@ -XXX,XX +XXX,XX @@ static void cpu_get_profile(Object *obj, Visitor *v, const char *name, static void riscv_cpu_add_profiles(Object *cpu_obj) { for (int i = 0; riscv_profiles[i] != NULL; i++) { - const RISCVCPUProfile *profile = riscv_profiles[i]; + RISCVCPUProfile *profile = riscv_profiles[i]; object_property_add(cpu_obj, profile->name, "bool", cpu_get_profile, cpu_set_profile, @@ -XXX,XX +XXX,XX @@ static void riscv_cpu_add_profiles(Object *cpu_obj) * case. */ if (profile->enabled) { - object_property_set_bool(cpu_obj, profile->name, true, NULL); + riscv_cpu_set_profile(RISCV_CPU(cpu_obj), profile, true); } } } -- 2.50.0
From: Daniel Henrique Barboza <dbarboza@ventanamicro.com> Björn reported in [1] a case where a rv64 CPU is going through the profile code path to enable satp mode. In this case,the amount of extensions on top of the rv64 CPU made it compliant with the RVA22S64 profile during the validation of CPU 0. When the subsequent CPUs were initialized the static profile object has the 'enable' flag set, enabling the profile code path for those CPUs. This happens because we are initializing and realizing each CPU before going to the next, i.e. init and realize CPU0, then init and realize CPU1 and so on. If we change any persistent state during the validation of CPU N it will interfere with the init/realization of CPU N+1. We're using the 'enabled' profile flag to do two distinct things: inform cpu_init() that we want profile extensions to be enabled, and telling QMP that a profile is currently enabled in the CPU. We want to be flexible enough to recognize profile support for all CPUs that has the extension prerequisites, but we do not want to force the profile code path if a profile wasn't set too. Add a new 'present' flag for profiles that will coexist with the 'enabled' flag. Enabling a profile means "we want to switch on all its mandatory extensions". A profile is 'present' if we asserted during validation that the CPU has the needed prerequisites. This means that the case reported by Björn now results in RVA22S64.enabled=false and RVA22S64.present=true. QMP will recognize it as a RVA22 compliant CPU and we won't force the CPU into the profile path. [1] https://lore.kernel.org/qemu-riscv/87y0usiz22.fsf@all.your.base.are.belong.to.us/ Reported-by: Björn Töpel <bjorn@kernel.org> Fixes: 2af005d610 ("target/riscv/tcg: validate profiles during finalize") Signed-off-by: Daniel Henrique Barboza <dbarboza@ventanamicro.com> Reviewed-by: Andrew Jones <ajones@ventanamicro.com> Reviewed-by: Björn Töpel <bjorn@rivosinc.com> Tested-by: Björn Töpel <bjorn@rivosinc.com> Message-ID: <20250528184407.1451983-4-dbarboza@ventanamicro.com> Signed-off-by: Alistair Francis <alistair.francis@wdc.com> --- target/riscv/cpu.h | 15 +++++++++++++++ target/riscv/riscv-qmp-cmds.c | 2 +- target/riscv/tcg/tcg-cpu.c | 11 +++-------- 3 files changed, 19 insertions(+), 9 deletions(-) diff --git a/target/riscv/cpu.h b/target/riscv/cpu.h index XXXXXXX..XXXXXXX 100644 --- a/target/riscv/cpu.h +++ b/target/riscv/cpu.h @@ -XXX,XX +XXX,XX @@ typedef struct riscv_cpu_profile { struct riscv_cpu_profile *s_parent; const char *name; uint32_t misa_ext; + /* + * The profile is enabled/disabled via command line or + * via cpu_init(). Enabling a profile will add all its + * mandatory extensions in the CPU during init(). + */ bool enabled; + /* + * The profile is present in the CPU, i.e. the current set of + * CPU extensions complies with it. A profile can be enabled + * and not present (e.g. the user disabled a mandatory extension) + * and the other way around (e.g. all mandatory extensions are + * present in a non-profile CPU). + * + * QMP uses this flag. + */ + bool present; bool user_set; int priv_spec; int satp_mode; diff --git a/target/riscv/riscv-qmp-cmds.c b/target/riscv/riscv-qmp-cmds.c index XXXXXXX..XXXXXXX 100644 --- a/target/riscv/riscv-qmp-cmds.c +++ b/target/riscv/riscv-qmp-cmds.c @@ -XXX,XX +XXX,XX @@ static void riscv_obj_add_profiles_qdict(Object *obj, QDict *qdict_out) for (int i = 0; riscv_profiles[i] != NULL; i++) { profile = riscv_profiles[i]; - value = QOBJECT(qbool_from_bool(profile->enabled)); + value = QOBJECT(qbool_from_bool(profile->present)); qdict_put_obj(qdict_out, profile->name, value); } diff --git a/target/riscv/tcg/tcg-cpu.c b/target/riscv/tcg/tcg-cpu.c index XXXXXXX..XXXXXXX 100644 --- a/target/riscv/tcg/tcg-cpu.c +++ b/target/riscv/tcg/tcg-cpu.c @@ -XXX,XX +XXX,XX @@ static void riscv_cpu_check_parent_profile(RISCVCPU *cpu, RISCVCPUProfile *profile, RISCVCPUProfile *parent) { - const char *parent_name; - bool parent_enabled; - - if (!profile->enabled || !parent) { + if (!profile->present || !parent) { return; } - parent_name = parent->name; - parent_enabled = object_property_get_bool(OBJECT(cpu), parent_name, NULL); - profile->enabled = parent_enabled; + profile->present = parent->present; } static void riscv_cpu_validate_profile(RISCVCPU *cpu, @@ -XXX,XX +XXX,XX @@ static void riscv_cpu_validate_profile(RISCVCPU *cpu, } } - profile->enabled = profile_impl; + profile->present = profile_impl; riscv_cpu_check_parent_profile(cpu, profile, profile->u_parent); riscv_cpu_check_parent_profile(cpu, profile, profile->s_parent); -- 2.50.0
From: Jay Chang <jay.chang@sifive.com> According to the RISC-V Privileged Specification (version >1.12), RV32 supports 16 CSRs (pmpcfg0–pmpcfg15) to configure 64 PMP regions (pmpaddr0–pmpaddr63). Signed-off-by: Jay Chang <jay.chang@sifive.com> Reviewed-by: Frank Chang <frank.chang@sifive.com> Reviewed-by: Alistair Francis <alistair.francis@wdc.com> Reviewed-by: Daniel Henrique Barboza <dbarboza@ventanamicro.com> Message-ID: <20250522081236.4050-2-jay.chang@sifive.com> Signed-off-by: Alistair Francis <alistair.francis@wdc.com> --- target/riscv/cpu_bits.h | 60 +++++++++++++++++++ target/riscv/csr.c | 124 +++++++++++++++++++++++++++++++++++++++- 2 files changed, 182 insertions(+), 2 deletions(-) diff --git a/target/riscv/cpu_bits.h b/target/riscv/cpu_bits.h index XXXXXXX..XXXXXXX 100644 --- a/target/riscv/cpu_bits.h +++ b/target/riscv/cpu_bits.h @@ -XXX,XX +XXX,XX @@ #define CSR_PMPCFG1 0x3a1 #define CSR_PMPCFG2 0x3a2 #define CSR_PMPCFG3 0x3a3 +#define CSR_PMPCFG4 0x3a4 +#define CSR_PMPCFG5 0x3a5 +#define CSR_PMPCFG6 0x3a6 +#define CSR_PMPCFG7 0x3a7 +#define CSR_PMPCFG8 0x3a8 +#define CSR_PMPCFG9 0x3a9 +#define CSR_PMPCFG10 0x3aa +#define CSR_PMPCFG11 0x3ab +#define CSR_PMPCFG12 0x3ac +#define CSR_PMPCFG13 0x3ad +#define CSR_PMPCFG14 0x3ae +#define CSR_PMPCFG15 0x3af #define CSR_PMPADDR0 0x3b0 #define CSR_PMPADDR1 0x3b1 #define CSR_PMPADDR2 0x3b2 @@ -XXX,XX +XXX,XX @@ #define CSR_PMPADDR13 0x3bd #define CSR_PMPADDR14 0x3be #define CSR_PMPADDR15 0x3bf +#define CSR_PMPADDR16 0x3c0 +#define CSR_PMPADDR17 0x3c1 +#define CSR_PMPADDR18 0x3c2 +#define CSR_PMPADDR19 0x3c3 +#define CSR_PMPADDR20 0x3c4 +#define CSR_PMPADDR21 0x3c5 +#define CSR_PMPADDR22 0x3c6 +#define CSR_PMPADDR23 0x3c7 +#define CSR_PMPADDR24 0x3c8 +#define CSR_PMPADDR25 0x3c9 +#define CSR_PMPADDR26 0x3ca +#define CSR_PMPADDR27 0x3cb +#define CSR_PMPADDR28 0x3cc +#define CSR_PMPADDR29 0x3cd +#define CSR_PMPADDR30 0x3ce +#define CSR_PMPADDR31 0x3cf +#define CSR_PMPADDR32 0x3d0 +#define CSR_PMPADDR33 0x3d1 +#define CSR_PMPADDR34 0x3d2 +#define CSR_PMPADDR35 0x3d3 +#define CSR_PMPADDR36 0x3d4 +#define CSR_PMPADDR37 0x3d5 +#define CSR_PMPADDR38 0x3d6 +#define CSR_PMPADDR39 0x3d7 +#define CSR_PMPADDR40 0x3d8 +#define CSR_PMPADDR41 0x3d9 +#define CSR_PMPADDR42 0x3da +#define CSR_PMPADDR43 0x3db +#define CSR_PMPADDR44 0x3dc +#define CSR_PMPADDR45 0x3dd +#define CSR_PMPADDR46 0x3de +#define CSR_PMPADDR47 0x3df +#define CSR_PMPADDR48 0x3e0 +#define CSR_PMPADDR49 0x3e1 +#define CSR_PMPADDR50 0x3e2 +#define CSR_PMPADDR51 0x3e3 +#define CSR_PMPADDR52 0x3e4 +#define CSR_PMPADDR53 0x3e5 +#define CSR_PMPADDR54 0x3e6 +#define CSR_PMPADDR55 0x3e7 +#define CSR_PMPADDR56 0x3e8 +#define CSR_PMPADDR57 0x3e9 +#define CSR_PMPADDR58 0x3ea +#define CSR_PMPADDR59 0x3eb +#define CSR_PMPADDR60 0x3ec +#define CSR_PMPADDR61 0x3ed +#define CSR_PMPADDR62 0x3ee +#define CSR_PMPADDR63 0x3ef /* RNMI */ #define CSR_MNSCRATCH 0x740 diff --git a/target/riscv/csr.c b/target/riscv/csr.c index XXXXXXX..XXXXXXX 100644 --- a/target/riscv/csr.c +++ b/target/riscv/csr.c @@ -XXX,XX +XXX,XX @@ riscv_csr_operations csr_ops[CSR_TABLE_SIZE] = { [CSR_PMPCFG1] = { "pmpcfg1", pmp, read_pmpcfg, write_pmpcfg }, [CSR_PMPCFG2] = { "pmpcfg2", pmp, read_pmpcfg, write_pmpcfg }, [CSR_PMPCFG3] = { "pmpcfg3", pmp, read_pmpcfg, write_pmpcfg }, + [CSR_PMPCFG4] = { "pmpcfg4", pmp, read_pmpcfg, write_pmpcfg, + .min_priv_ver = PRIV_VERSION_1_12_0 }, + [CSR_PMPCFG5] = { "pmpcfg5", pmp, read_pmpcfg, write_pmpcfg, + .min_priv_ver = PRIV_VERSION_1_12_0 }, + [CSR_PMPCFG6] = { "pmpcfg6", pmp, read_pmpcfg, write_pmpcfg, + .min_priv_ver = PRIV_VERSION_1_12_0 }, + [CSR_PMPCFG7] = { "pmpcfg7", pmp, read_pmpcfg, write_pmpcfg, + .min_priv_ver = PRIV_VERSION_1_12_0 }, + [CSR_PMPCFG8] = { "pmpcfg8", pmp, read_pmpcfg, write_pmpcfg, + .min_priv_ver = PRIV_VERSION_1_12_0 }, + [CSR_PMPCFG9] = { "pmpcfg9", pmp, read_pmpcfg, write_pmpcfg, + .min_priv_ver = PRIV_VERSION_1_12_0 }, + [CSR_PMPCFG10] = { "pmpcfg10", pmp, read_pmpcfg, write_pmpcfg, + .min_priv_ver = PRIV_VERSION_1_12_0 }, + [CSR_PMPCFG11] = { "pmpcfg11", pmp, read_pmpcfg, write_pmpcfg, + .min_priv_ver = PRIV_VERSION_1_12_0 }, + [CSR_PMPCFG12] = { "pmpcfg12", pmp, read_pmpcfg, write_pmpcfg, + .min_priv_ver = PRIV_VERSION_1_12_0 }, + [CSR_PMPCFG13] = { "pmpcfg13", pmp, read_pmpcfg, write_pmpcfg, + .min_priv_ver = PRIV_VERSION_1_12_0 }, + [CSR_PMPCFG14] = { "pmpcfg14", pmp, read_pmpcfg, write_pmpcfg, + .min_priv_ver = PRIV_VERSION_1_12_0 }, + [CSR_PMPCFG15] = { "pmpcfg15", pmp, read_pmpcfg, write_pmpcfg, + .min_priv_ver = PRIV_VERSION_1_12_0 }, [CSR_PMPADDR0] = { "pmpaddr0", pmp, read_pmpaddr, write_pmpaddr }, [CSR_PMPADDR1] = { "pmpaddr1", pmp, read_pmpaddr, write_pmpaddr }, [CSR_PMPADDR2] = { "pmpaddr2", pmp, read_pmpaddr, write_pmpaddr }, @@ -XXX,XX +XXX,XX @@ riscv_csr_operations csr_ops[CSR_TABLE_SIZE] = { [CSR_PMPADDR11] = { "pmpaddr11", pmp, read_pmpaddr, write_pmpaddr }, [CSR_PMPADDR12] = { "pmpaddr12", pmp, read_pmpaddr, write_pmpaddr }, [CSR_PMPADDR13] = { "pmpaddr13", pmp, read_pmpaddr, write_pmpaddr }, - [CSR_PMPADDR14] = { "pmpaddr14", pmp, read_pmpaddr, write_pmpaddr }, - [CSR_PMPADDR15] = { "pmpaddr15", pmp, read_pmpaddr, write_pmpaddr }, + [CSR_PMPADDR14] = { "pmpaddr14", pmp, read_pmpaddr, write_pmpaddr }, + [CSR_PMPADDR15] = { "pmpaddr15", pmp, read_pmpaddr, write_pmpaddr }, + [CSR_PMPADDR16] = { "pmpaddr16", pmp, read_pmpaddr, write_pmpaddr, + .min_priv_ver = PRIV_VERSION_1_12_0 }, + [CSR_PMPADDR17] = { "pmpaddr17", pmp, read_pmpaddr, write_pmpaddr, + .min_priv_ver = PRIV_VERSION_1_12_0 }, + [CSR_PMPADDR18] = { "pmpaddr18", pmp, read_pmpaddr, write_pmpaddr, + .min_priv_ver = PRIV_VERSION_1_12_0 }, + [CSR_PMPADDR19] = { "pmpaddr19", pmp, read_pmpaddr, write_pmpaddr, + .min_priv_ver = PRIV_VERSION_1_12_0 }, + [CSR_PMPADDR20] = { "pmpaddr20", pmp, read_pmpaddr, write_pmpaddr, + .min_priv_ver = PRIV_VERSION_1_12_0 }, + [CSR_PMPADDR21] = { "pmpaddr21", pmp, read_pmpaddr, write_pmpaddr, + .min_priv_ver = PRIV_VERSION_1_12_0 }, + [CSR_PMPADDR22] = { "pmpaddr22", pmp, read_pmpaddr, write_pmpaddr, + .min_priv_ver = PRIV_VERSION_1_12_0 }, + [CSR_PMPADDR23] = { "pmpaddr23", pmp, read_pmpaddr, write_pmpaddr, + .min_priv_ver = PRIV_VERSION_1_12_0 }, + [CSR_PMPADDR24] = { "pmpaddr24", pmp, read_pmpaddr, write_pmpaddr, + .min_priv_ver = PRIV_VERSION_1_12_0 }, + [CSR_PMPADDR25] = { "pmpaddr25", pmp, read_pmpaddr, write_pmpaddr, + .min_priv_ver = PRIV_VERSION_1_12_0 }, + [CSR_PMPADDR26] = { "pmpaddr26", pmp, read_pmpaddr, write_pmpaddr, + .min_priv_ver = PRIV_VERSION_1_12_0 }, + [CSR_PMPADDR27] = { "pmpaddr27", pmp, read_pmpaddr, write_pmpaddr, + .min_priv_ver = PRIV_VERSION_1_12_0 }, + [CSR_PMPADDR28] = { "pmpaddr28", pmp, read_pmpaddr, write_pmpaddr, + .min_priv_ver = PRIV_VERSION_1_12_0 }, + [CSR_PMPADDR29] = { "pmpaddr29", pmp, read_pmpaddr, write_pmpaddr, + .min_priv_ver = PRIV_VERSION_1_12_0 }, + [CSR_PMPADDR30] = { "pmpaddr30", pmp, read_pmpaddr, write_pmpaddr, + .min_priv_ver = PRIV_VERSION_1_12_0 }, + [CSR_PMPADDR31] = { "pmpaddr31", pmp, read_pmpaddr, write_pmpaddr, + .min_priv_ver = PRIV_VERSION_1_12_0 }, + [CSR_PMPADDR32] = { "pmpaddr32", pmp, read_pmpaddr, write_pmpaddr, + .min_priv_ver = PRIV_VERSION_1_12_0 }, + [CSR_PMPADDR33] = { "pmpaddr33", pmp, read_pmpaddr, write_pmpaddr, + .min_priv_ver = PRIV_VERSION_1_12_0 }, + [CSR_PMPADDR34] = { "pmpaddr34", pmp, read_pmpaddr, write_pmpaddr, + .min_priv_ver = PRIV_VERSION_1_12_0 }, + [CSR_PMPADDR35] = { "pmpaddr35", pmp, read_pmpaddr, write_pmpaddr, + .min_priv_ver = PRIV_VERSION_1_12_0 }, + [CSR_PMPADDR36] = { "pmpaddr36", pmp, read_pmpaddr, write_pmpaddr, + .min_priv_ver = PRIV_VERSION_1_12_0 }, + [CSR_PMPADDR37] = { "pmpaddr37", pmp, read_pmpaddr, write_pmpaddr, + .min_priv_ver = PRIV_VERSION_1_12_0 }, + [CSR_PMPADDR38] = { "pmpaddr38", pmp, read_pmpaddr, write_pmpaddr, + .min_priv_ver = PRIV_VERSION_1_12_0 }, + [CSR_PMPADDR39] = { "pmpaddr39", pmp, read_pmpaddr, write_pmpaddr, + .min_priv_ver = PRIV_VERSION_1_12_0 }, + [CSR_PMPADDR40] = { "pmpaddr40", pmp, read_pmpaddr, write_pmpaddr, + .min_priv_ver = PRIV_VERSION_1_12_0 }, + [CSR_PMPADDR41] = { "pmpaddr41", pmp, read_pmpaddr, write_pmpaddr, + .min_priv_ver = PRIV_VERSION_1_12_0 }, + [CSR_PMPADDR42] = { "pmpaddr42", pmp, read_pmpaddr, write_pmpaddr, + .min_priv_ver = PRIV_VERSION_1_12_0 }, + [CSR_PMPADDR43] = { "pmpaddr43", pmp, read_pmpaddr, write_pmpaddr, + .min_priv_ver = PRIV_VERSION_1_12_0 }, + [CSR_PMPADDR44] = { "pmpaddr44", pmp, read_pmpaddr, write_pmpaddr, + .min_priv_ver = PRIV_VERSION_1_12_0 }, + [CSR_PMPADDR45] = { "pmpaddr45", pmp, read_pmpaddr, write_pmpaddr, + .min_priv_ver = PRIV_VERSION_1_12_0 }, + [CSR_PMPADDR46] = { "pmpaddr46", pmp, read_pmpaddr, write_pmpaddr, + .min_priv_ver = PRIV_VERSION_1_12_0 }, + [CSR_PMPADDR47] = { "pmpaddr47", pmp, read_pmpaddr, write_pmpaddr, + .min_priv_ver = PRIV_VERSION_1_12_0 }, + [CSR_PMPADDR48] = { "pmpaddr48", pmp, read_pmpaddr, write_pmpaddr, + .min_priv_ver = PRIV_VERSION_1_12_0 }, + [CSR_PMPADDR49] = { "pmpaddr49", pmp, read_pmpaddr, write_pmpaddr, + .min_priv_ver = PRIV_VERSION_1_12_0 }, + [CSR_PMPADDR50] = { "pmpaddr50", pmp, read_pmpaddr, write_pmpaddr, + .min_priv_ver = PRIV_VERSION_1_12_0 }, + [CSR_PMPADDR51] = { "pmpaddr51", pmp, read_pmpaddr, write_pmpaddr, + .min_priv_ver = PRIV_VERSION_1_12_0 }, + [CSR_PMPADDR52] = { "pmpaddr52", pmp, read_pmpaddr, write_pmpaddr, + .min_priv_ver = PRIV_VERSION_1_12_0 }, + [CSR_PMPADDR53] = { "pmpaddr53", pmp, read_pmpaddr, write_pmpaddr, + .min_priv_ver = PRIV_VERSION_1_12_0 }, + [CSR_PMPADDR54] = { "pmpaddr54", pmp, read_pmpaddr, write_pmpaddr, + .min_priv_ver = PRIV_VERSION_1_12_0 }, + [CSR_PMPADDR55] = { "pmpaddr55", pmp, read_pmpaddr, write_pmpaddr, + .min_priv_ver = PRIV_VERSION_1_12_0 }, + [CSR_PMPADDR56] = { "pmpaddr56", pmp, read_pmpaddr, write_pmpaddr, + .min_priv_ver = PRIV_VERSION_1_12_0 }, + [CSR_PMPADDR57] = { "pmpaddr57", pmp, read_pmpaddr, write_pmpaddr, + .min_priv_ver = PRIV_VERSION_1_12_0 }, + [CSR_PMPADDR58] = { "pmpaddr58", pmp, read_pmpaddr, write_pmpaddr, + .min_priv_ver = PRIV_VERSION_1_12_0 }, + [CSR_PMPADDR59] = { "pmpaddr59", pmp, read_pmpaddr, write_pmpaddr, + .min_priv_ver = PRIV_VERSION_1_12_0 }, + [CSR_PMPADDR60] = { "pmpaddr60", pmp, read_pmpaddr, write_pmpaddr, + .min_priv_ver = PRIV_VERSION_1_12_0 }, + [CSR_PMPADDR61] = { "pmpaddr61", pmp, read_pmpaddr, write_pmpaddr, + .min_priv_ver = PRIV_VERSION_1_12_0 }, + [CSR_PMPADDR62] = { "pmpaddr62", pmp, read_pmpaddr, write_pmpaddr, + .min_priv_ver = PRIV_VERSION_1_12_0 }, + [CSR_PMPADDR63] = { "pmpaddr63", pmp, read_pmpaddr, write_pmpaddr, + .min_priv_ver = PRIV_VERSION_1_12_0 }, /* Debug CSRs */ [CSR_TSELECT] = { "tselect", debug, read_tselect, write_tselect }, -- 2.50.0
From: Daniel Henrique Barboza <dbarboza@ventanamicro.com> These properties were deprecated in QEMU 8.2, commit 8043effd9b. Signed-off-by: Daniel Henrique Barboza <dbarboza@ventanamicro.com> Reviewed-by: Alistair Francis <alistair.francis@wdc.com> Message-ID: <20250530134608.1806922-1-dbarboza@ventanamicro.com> Signed-off-by: Alistair Francis <alistair.francis@wdc.com> --- target/riscv/cpu.h | 1 - target/riscv/cpu.c | 17 ----------------- target/riscv/tcg/tcg-cpu.c | 31 +------------------------------ 3 files changed, 1 insertion(+), 48 deletions(-) diff --git a/target/riscv/cpu.h b/target/riscv/cpu.h index XXXXXXX..XXXXXXX 100644 --- a/target/riscv/cpu.h +++ b/target/riscv/cpu.h @@ -XXX,XX +XXX,XX @@ extern const RISCVCPUMultiExtConfig riscv_cpu_extensions[]; extern const RISCVCPUMultiExtConfig riscv_cpu_vendor_exts[]; extern const RISCVCPUMultiExtConfig riscv_cpu_experimental_exts[]; extern const RISCVCPUMultiExtConfig riscv_cpu_named_features[]; -extern const RISCVCPUMultiExtConfig riscv_cpu_deprecated_exts[]; typedef struct isa_ext_data { const char *name; diff --git a/target/riscv/cpu.c b/target/riscv/cpu.c index XXXXXXX..XXXXXXX 100644 --- a/target/riscv/cpu.c +++ b/target/riscv/cpu.c @@ -XXX,XX +XXX,XX @@ const RISCVCPUMultiExtConfig riscv_cpu_named_features[] = { { }, }; -/* Deprecated entries marked for future removal */ -const RISCVCPUMultiExtConfig riscv_cpu_deprecated_exts[] = { - MULTI_EXT_CFG_BOOL("Zifencei", ext_zifencei, true), - MULTI_EXT_CFG_BOOL("Zicsr", ext_zicsr, true), - MULTI_EXT_CFG_BOOL("Zihintntl", ext_zihintntl, true), - MULTI_EXT_CFG_BOOL("Zihintpause", ext_zihintpause, true), - MULTI_EXT_CFG_BOOL("Zawrs", ext_zawrs, true), - MULTI_EXT_CFG_BOOL("Zfa", ext_zfa, true), - MULTI_EXT_CFG_BOOL("Zfh", ext_zfh, false), - MULTI_EXT_CFG_BOOL("Zfhmin", ext_zfhmin, false), - MULTI_EXT_CFG_BOOL("Zve32f", ext_zve32f, false), - MULTI_EXT_CFG_BOOL("Zve64f", ext_zve64f, false), - MULTI_EXT_CFG_BOOL("Zve64d", ext_zve64d, false), - - { }, -}; - static void cpu_set_prop_err(RISCVCPU *cpu, const char *propname, Error **errp) { diff --git a/target/riscv/tcg/tcg-cpu.c b/target/riscv/tcg/tcg-cpu.c index XXXXXXX..XXXXXXX 100644 --- a/target/riscv/tcg/tcg-cpu.c +++ b/target/riscv/tcg/tcg-cpu.c @@ -XXX,XX +XXX,XX @@ static void riscv_cpu_add_profiles(Object *cpu_obj) } } -static bool cpu_ext_is_deprecated(const char *ext_name) -{ - return isupper(ext_name[0]); -} - -/* - * String will be allocated in the heap. Caller is responsible - * for freeing it. - */ -static char *cpu_ext_to_lower(const char *ext_name) -{ - char *ret = g_malloc0(strlen(ext_name) + 1); - - strcpy(ret, ext_name); - ret[0] = tolower(ret[0]); - - return ret; -} - static void cpu_set_multi_ext_cfg(Object *obj, Visitor *v, const char *name, void *opaque, Error **errp) { @@ -XXX,XX +XXX,XX @@ static void cpu_set_multi_ext_cfg(Object *obj, Visitor *v, const char *name, return; } - if (cpu_ext_is_deprecated(multi_ext_cfg->name)) { - g_autofree char *lower = cpu_ext_to_lower(multi_ext_cfg->name); - - warn_report("CPU property '%s' is deprecated. Please use '%s' instead", - multi_ext_cfg->name, lower); - } - cpu_cfg_ext_add_user_opt(multi_ext_cfg->offset, value); prev_val = isa_ext_is_enabled(cpu, multi_ext_cfg->offset); @@ -XXX,XX +XXX,XX @@ static void cpu_add_multi_ext_prop(Object *cpu_obj, const RISCVCPUMultiExtConfig *multi_cfg) { bool generic_cpu = riscv_cpu_is_generic(cpu_obj); - bool deprecated_ext = cpu_ext_is_deprecated(multi_cfg->name); object_property_add(cpu_obj, multi_cfg->name, "bool", cpu_get_multi_ext_cfg, cpu_set_multi_ext_cfg, NULL, (void *)multi_cfg); - if (!generic_cpu || deprecated_ext) { + if (!generic_cpu) { return; } @@ -XXX,XX +XXX,XX @@ static void riscv_cpu_add_user_properties(Object *obj) riscv_cpu_add_multiext_prop_array(obj, riscv_cpu_vendor_exts); riscv_cpu_add_multiext_prop_array(obj, riscv_cpu_experimental_exts); - riscv_cpu_add_multiext_prop_array(obj, riscv_cpu_deprecated_exts); - riscv_cpu_add_profiles(obj); } -- 2.50.0
From: Daniel Henrique Barboza <dbarboza@ventanamicro.com> We have support for sdtrig for awhile but we are not advertising it. It is enabled by default via the 'debug' flag. Use the same flag to also advertise sdtrig. Add an exception in disable_priv_spec_isa_exts() to avoid spamming warnings for 'sdtrig' for vendor CPUs like sifive_u. Signed-off-by: Daniel Henrique Barboza <dbarboza@ventanamicro.com> Reviewed-by: Alistair Francis <alistair.francis@wdc.com> Message-ID: <20250604174329.1147549-2-dbarboza@ventanamicro.com> Signed-off-by: Alistair Francis <alistair.francis@wdc.com> --- target/riscv/cpu.c | 1 + target/riscv/tcg/tcg-cpu.c | 9 +++++++++ tests/data/acpi/riscv64/virt/RHCT | Bin 400 -> 406 bytes 3 files changed, 10 insertions(+) diff --git a/target/riscv/cpu.c b/target/riscv/cpu.c index XXXXXXX..XXXXXXX 100644 --- a/target/riscv/cpu.c +++ b/target/riscv/cpu.c @@ -XXX,XX +XXX,XX @@ const RISCVIsaExtData isa_edata_arr[] = { ISA_EXT_DATA_ENTRY(zvkt, PRIV_VERSION_1_12_0, ext_zvkt), ISA_EXT_DATA_ENTRY(zhinx, PRIV_VERSION_1_12_0, ext_zhinx), ISA_EXT_DATA_ENTRY(zhinxmin, PRIV_VERSION_1_12_0, ext_zhinxmin), + ISA_EXT_DATA_ENTRY(sdtrig, PRIV_VERSION_1_12_0, debug), ISA_EXT_DATA_ENTRY(shcounterenw, PRIV_VERSION_1_12_0, has_priv_1_12), ISA_EXT_DATA_ENTRY(sha, PRIV_VERSION_1_12_0, ext_sha), ISA_EXT_DATA_ENTRY(shgatpa, PRIV_VERSION_1_12_0, has_priv_1_12), diff --git a/target/riscv/tcg/tcg-cpu.c b/target/riscv/tcg/tcg-cpu.c index XXXXXXX..XXXXXXX 100644 --- a/target/riscv/tcg/tcg-cpu.c +++ b/target/riscv/tcg/tcg-cpu.c @@ -XXX,XX +XXX,XX @@ static void riscv_cpu_disable_priv_spec_isa_exts(RISCVCPU *cpu) continue; } + /* + * cpu.debug = true is marked as 'sdtrig', priv spec 1.12. + * Skip this warning since existing CPUs with older priv + * spec and debug = true will be impacted. + */ + if (!strcmp(edata->name, "sdtrig")) { + continue; + } + isa_ext_update_enabled(cpu, edata->ext_enable_offset, false); /* diff --git a/tests/data/acpi/riscv64/virt/RHCT b/tests/data/acpi/riscv64/virt/RHCT index XXXXXXX..XXXXXXX 100644 Binary files a/tests/data/acpi/riscv64/virt/RHCT and b/tests/data/acpi/riscv64/virt/RHCT differ -- 2.50.0
From: Daniel Henrique Barboza <dbarboza@ventanamicro.com> 'ssstrict' is a RVA23 profile-defined extension defined as follows: "No non-conforming extensions are present. Attempts to execute unimplemented opcodes or access unimplemented CSRs in the standard or reserved encoding spaces raises an illegal instruction exception that results in a contained trap to the supervisor-mode trap handler." In short, we need to throw an exception when accessing unimplemented CSRs or opcodes. We do that, so let's advertise it. Signed-off-by: Daniel Henrique Barboza <dbarboza@ventanamicro.com> Reviewed-by: Andrew Jones <ajones@ventanamicro.com> Message-ID: <20250529202315.1684198-3-dbarboza@ventanamicro.com> Message-ID: <20250604174329.1147549-3-dbarboza@ventanamicro.com> Signed-off-by: Alistair Francis <alistair.francis@wdc.com> --- target/riscv/cpu.c | 1 + tests/data/acpi/riscv64/virt/RHCT | Bin 406 -> 416 bytes 2 files changed, 1 insertion(+) diff --git a/target/riscv/cpu.c b/target/riscv/cpu.c index XXXXXXX..XXXXXXX 100644 --- a/target/riscv/cpu.c +++ b/target/riscv/cpu.c @@ -XXX,XX +XXX,XX @@ const RISCVIsaExtData isa_edata_arr[] = { ISA_EXT_DATA_ENTRY(ssnpm, PRIV_VERSION_1_13_0, ext_ssnpm), ISA_EXT_DATA_ENTRY(sspm, PRIV_VERSION_1_13_0, ext_sspm), ISA_EXT_DATA_ENTRY(ssstateen, PRIV_VERSION_1_12_0, ext_ssstateen), + ISA_EXT_DATA_ENTRY(ssstrict, PRIV_VERSION_1_12_0, has_priv_1_12), ISA_EXT_DATA_ENTRY(sstc, PRIV_VERSION_1_12_0, ext_sstc), ISA_EXT_DATA_ENTRY(sstvala, PRIV_VERSION_1_12_0, has_priv_1_12), ISA_EXT_DATA_ENTRY(sstvecd, PRIV_VERSION_1_12_0, has_priv_1_12), diff --git a/tests/data/acpi/riscv64/virt/RHCT b/tests/data/acpi/riscv64/virt/RHCT index XXXXXXX..XXXXXXX 100644 Binary files a/tests/data/acpi/riscv64/virt/RHCT and b/tests/data/acpi/riscv64/virt/RHCT differ -- 2.50.0
From: Daniel Henrique Barboza <dbarboza@ventanamicro.com> Most of the named features are added directly in isa_edata_arr[], some of them are also added in riscv_cpu_named_features(). There is a reason for that, and the existing docs can do better explaining it. Signed-off-by: Daniel Henrique Barboza <dbarboza@ventanamicro.com> Message-ID: <20250529202315.1684198-4-dbarboza@ventanamicro.com> Acked-by: Alistair Francis <alistair.francis@wdc.com> Message-ID: <20250604174329.1147549-4-dbarboza@ventanamicro.com> Signed-off-by: Alistair Francis <alistair.francis@wdc.com> --- target/riscv/cpu.c | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/target/riscv/cpu.c b/target/riscv/cpu.c index XXXXXXX..XXXXXXX 100644 --- a/target/riscv/cpu.c +++ b/target/riscv/cpu.c @@ -XXX,XX +XXX,XX @@ const RISCVCPUMultiExtConfig riscv_cpu_experimental_exts[] = { * 'Named features' is the name we give to extensions that we * don't want to expose to users. They are either immutable * (always enabled/disable) or they'll vary depending on - * the resulting CPU state. They have riscv,isa strings - * and priv_ver like regular extensions. + * the resulting CPU state. + * + * Some of them are always enabled depending on priv version + * of the CPU and are declared directly in isa_edata_arr[]. + * The ones listed here have special checks during finalize() + * time and require their own flags like regular extensions. + * See riscv_cpu_update_named_features() for more info. */ const RISCVCPUMultiExtConfig riscv_cpu_named_features[] = { MULTI_EXT_CFG_BOOL("zic64b", ext_zic64b, true), MULTI_EXT_CFG_BOOL("ssstateen", ext_ssstateen, true), MULTI_EXT_CFG_BOOL("sha", ext_sha, true), + + /* + * 'ziccrse' has its own flag because the KVM driver + * wants to enable/disable it on its own accord. + */ MULTI_EXT_CFG_BOOL("ziccrse", ext_ziccrse, true), { }, -- 2.50.0
From: Jim Shu <jim.shu@sifive.com> Support 4-byte atomic instruction fetch when instruction is natural aligned. Current implementation is not atomic because it loads instruction twice for first and last 2 bytes. We load 4 bytes at once to keep the atomicity. This instruction preload method only applys when instruction is 4-byte aligned. If instruction is unaligned, it could be across pages so that preload will trigger additional page fault. We encounter this issue when doing pressure test of enabling & disabling Linux kernel ftrace. Ftrace with kernel preemption requires concurrent modification and execution of instruction, so non-atomic instruction fetch will cause the race condition. We may fetch the wrong instruction which is the mixing of 2 instructions. Also, RISC-V Profile wants to provide this feature by HW. RVA20U64 Ziccif protects the atomicity of instruction fetch when it is natural aligned. This commit depends on the atomic read support of translator_ld in the commit 6a9dfe1984b0c593fb0ddb52d4e70832e6201dd6. Signed-off-by: Jim Shu <jim.shu@sifive.com> Reviewed-by: Frank Chang <frank.chang@sifive.com> Reviewed-by: Alistair Francis <alistair.francis@wdc.com> Message-ID: <20250508094838.19394-1-jim.shu@sifive.com> Signed-off-by: Alistair Francis <alistair.francis@wdc.com> --- target/riscv/translate.c | 46 +++++++++++++++++++++++++++++----------- 1 file changed, 34 insertions(+), 12 deletions(-) diff --git a/target/riscv/translate.c b/target/riscv/translate.c index XXXXXXX..XXXXXXX 100644 --- a/target/riscv/translate.c +++ b/target/riscv/translate.c @@ -XXX,XX +XXX,XX @@ const RISCVDecoder decoder_table[] = { const size_t decoder_table_size = ARRAY_SIZE(decoder_table); -static void decode_opc(CPURISCVState *env, DisasContext *ctx, uint16_t opcode) +static void decode_opc(CPURISCVState *env, DisasContext *ctx) { + uint32_t opcode; + bool pc_is_4byte_align = ((ctx->base.pc_next % 4) == 0); + ctx->virt_inst_excp = false; - ctx->cur_insn_len = insn_len(opcode); + if (pc_is_4byte_align) { + /* + * Load 4 bytes at once to make instruction fetch atomically. + * + * Note: When pc is 4-byte aligned, 4-byte instruction wouldn't be + * across pages. We could preload 4 bytes instruction no matter + * real one is 2 or 4 bytes. Instruction preload wouldn't trigger + * additional page fault. + */ + opcode = translator_ldl(env, &ctx->base, ctx->base.pc_next); + } else { + /* + * For unaligned pc, instruction preload may trigger additional + * page fault so we only load 2 bytes here. + */ + opcode = (uint32_t) translator_lduw(env, &ctx->base, ctx->base.pc_next); + } + ctx->ol = ctx->xl; + + ctx->cur_insn_len = insn_len((uint16_t)opcode); /* Check for compressed insn */ if (ctx->cur_insn_len == 2) { - ctx->opcode = opcode; + ctx->opcode = (uint16_t)opcode; /* * The Zca extension is added as way to refer to instructions in the C * extension that do not include the floating-point loads and stores @@ -XXX,XX +XXX,XX @@ static void decode_opc(CPURISCVState *env, DisasContext *ctx, uint16_t opcode) return; } } else { - uint32_t opcode32 = opcode; - opcode32 = deposit32(opcode32, 16, 16, - translator_lduw(env, &ctx->base, - ctx->base.pc_next + 2)); - ctx->opcode = opcode32; + if (!pc_is_4byte_align) { + /* Load last 2 bytes of instruction here */ + opcode = deposit32(opcode, 16, 16, + translator_lduw(env, &ctx->base, + ctx->base.pc_next + 2)); + } + ctx->opcode = opcode; for (guint i = 0; i < ctx->decoders->len; ++i) { riscv_cpu_decode_fn func = g_ptr_array_index(ctx->decoders, i); - if (func(ctx, opcode32)) { + if (func(ctx, opcode)) { return; } } @@ -XXX,XX +XXX,XX @@ static void riscv_tr_translate_insn(DisasContextBase *dcbase, CPUState *cpu) { DisasContext *ctx = container_of(dcbase, DisasContext, base); CPURISCVState *env = cpu_env(cpu); - uint16_t opcode16 = translator_lduw(env, &ctx->base, ctx->base.pc_next); - ctx->ol = ctx->xl; - decode_opc(env, ctx, opcode16); + decode_opc(env, ctx); ctx->base.pc_next += ctx->cur_insn_len; /* -- 2.50.0
From: Meng Zhuo <mengzhuo@iscas.ac.cn> This patch adds max_satp_mode from host kvm cpu setting. Tested on: Milkv Megrez (Eswin 7700x) Reviewed-by: Andrew Jones <ajones@ventanamicro.com> Resolves: https://gitlab.com/qemu-project/qemu/-/issues/2931 Signed-off-by: Meng Zhuo <mengzhuo@iscas.ac.cn> Message-ID: <20250606034250.181707-1-mengzhuo@iscas.ac.cn> Signed-off-by: Alistair Francis <alistair.francis@wdc.com> --- target/riscv/kvm/kvm-cpu.c | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) diff --git a/target/riscv/kvm/kvm-cpu.c b/target/riscv/kvm/kvm-cpu.c index XXXXXXX..XXXXXXX 100644 --- a/target/riscv/kvm/kvm-cpu.c +++ b/target/riscv/kvm/kvm-cpu.c @@ -XXX,XX +XXX,XX @@ static void kvm_riscv_destroy_scratch_vcpu(KVMScratchCPU *scratch) close(scratch->kvmfd); } +static void kvm_riscv_init_max_satp_mode(RISCVCPU *cpu, KVMScratchCPU *kvmcpu) +{ + struct kvm_one_reg reg; + int ret; + + reg.id = RISCV_CONFIG_REG(satp_mode); + reg.addr = (uint64_t)&cpu->cfg.max_satp_mode; + ret = ioctl(kvmcpu->cpufd, KVM_GET_ONE_REG, ®); + if (ret != 0) { + error_report("Unable to retrieve satp mode from host, error %d", ret); + } +} + static void kvm_riscv_init_machine_ids(RISCVCPU *cpu, KVMScratchCPU *kvmcpu) { struct kvm_one_reg reg; @@ -XXX,XX +XXX,XX @@ static void riscv_init_kvm_registers(Object *cpu_obj) kvm_riscv_init_machine_ids(cpu, &kvmcpu); kvm_riscv_init_misa_ext_mask(cpu, &kvmcpu); kvm_riscv_init_cfg(cpu, &kvmcpu); + kvm_riscv_init_max_satp_mode(cpu, &kvmcpu); kvm_riscv_destroy_scratch_vcpu(&kvmcpu); } @@ -XXX,XX +XXX,XX @@ static bool kvm_cpu_realize(CPUState *cs, Error **errp) } } - return true; + return true; } void riscv_kvm_cpu_finalize_features(RISCVCPU *cpu, Error **errp) -- 2.50.0
From: Jay Chang <jay.chang@sifive.com> Previously, the number of PMP regions was hardcoded to 16 in QEMU. This patch replaces the fixed value with a new `pmp_regions` field, allowing platforms to configure the number of PMP regions. If no specific value is provided, the default number of PMP regions remains 16 to preserve the existing behavior. A new CPU parameter num-pmp-regions has been introduced to the QEMU command line. For example: -cpu rv64, g=true, c=true, pmp=true, num-pmp-regions=8 Signed-off-by: Jay Chang <jay.chang@sifive.com> Reviewed-by: Frank Chang <frank.chang@sifive.com> Reviewed-by: Alistair Francis <alistair.francis@wdc.com> Message-ID: <20250606072525.17313-3-jay.chang@sifive.com> Signed-off-by: Alistair Francis <alistair.francis@wdc.com> --- target/riscv/cpu.h | 3 +- target/riscv/cpu_cfg_fields.h.inc | 1 + target/riscv/cpu.c | 48 +++++++++++++++++++++++++++++-- target/riscv/csr.c | 5 +++- target/riscv/machine.c | 3 +- target/riscv/pmp.c | 28 ++++++++++++------ 6 files changed, 74 insertions(+), 14 deletions(-) diff --git a/target/riscv/cpu.h b/target/riscv/cpu.h index XXXXXXX..XXXXXXX 100644 --- a/target/riscv/cpu.h +++ b/target/riscv/cpu.h @@ -XXX,XX +XXX,XX @@ extern RISCVCPUImpliedExtsRule *riscv_multi_ext_implied_rules[]; #define MMU_USER_IDX 3 -#define MAX_RISCV_PMPS (16) +#define MAX_RISCV_PMPS (64) +#define OLD_MAX_RISCV_PMPS (16) #if !defined(CONFIG_USER_ONLY) #include "pmp.h" diff --git a/target/riscv/cpu_cfg_fields.h.inc b/target/riscv/cpu_cfg_fields.h.inc index XXXXXXX..XXXXXXX 100644 --- a/target/riscv/cpu_cfg_fields.h.inc +++ b/target/riscv/cpu_cfg_fields.h.inc @@ -XXX,XX +XXX,XX @@ TYPED_FIELD(uint16_t, elen, 0) TYPED_FIELD(uint16_t, cbom_blocksize, 0) TYPED_FIELD(uint16_t, cbop_blocksize, 0) TYPED_FIELD(uint16_t, cboz_blocksize, 0) +TYPED_FIELD(uint8_t, pmp_regions, 0) TYPED_FIELD(int8_t, max_satp_mode, -1) diff --git a/target/riscv/cpu.c b/target/riscv/cpu.c index XXXXXXX..XXXXXXX 100644 --- a/target/riscv/cpu.c +++ b/target/riscv/cpu.c @@ -XXX,XX +XXX,XX @@ static void riscv_cpu_init(Object *obj) cpu->cfg.cbom_blocksize = 64; cpu->cfg.cbop_blocksize = 64; cpu->cfg.cboz_blocksize = 64; + cpu->cfg.pmp_regions = 16; cpu->env.vext_ver = VEXT_VERSION_1_00_0; cpu->cfg.max_satp_mode = -1; @@ -XXX,XX +XXX,XX @@ static const PropertyInfo prop_pmp = { .set = prop_pmp_set, }; +static void prop_num_pmp_regions_set(Object *obj, Visitor *v, const char *name, + void *opaque, Error **errp) +{ + RISCVCPU *cpu = RISCV_CPU(obj); + uint8_t value; + + visit_type_uint8(v, name, &value, errp); + + if (cpu->cfg.pmp_regions != value && riscv_cpu_is_vendor(obj)) { + cpu_set_prop_err(cpu, name, errp); + return; + } + + if (cpu->env.priv_ver < PRIV_VERSION_1_12_0 && value > OLD_MAX_RISCV_PMPS) { + error_setg(errp, "Number of PMP regions exceeds maximum available"); + return; + } else if (value > MAX_RISCV_PMPS) { + error_setg(errp, "Number of PMP regions exceeds maximum available"); + return; + } + + cpu_option_add_user_setting(name, value); + cpu->cfg.pmp_regions = value; +} + +static void prop_num_pmp_regions_get(Object *obj, Visitor *v, const char *name, + void *opaque, Error **errp) +{ + uint8_t value = RISCV_CPU(obj)->cfg.pmp_regions; + + visit_type_uint8(v, name, &value, errp); +} + +static const PropertyInfo prop_num_pmp_regions = { + .type = "uint8", + .description = "num-pmp-regions", + .get = prop_num_pmp_regions_get, + .set = prop_num_pmp_regions_set, +}; + static int priv_spec_from_str(const char *priv_spec_str) { int priv_version = -1; @@ -XXX,XX +XXX,XX @@ static const Property riscv_cpu_properties[] = { {.name = "mmu", .info = &prop_mmu}, {.name = "pmp", .info = &prop_pmp}, + {.name = "num-pmp-regions", .info = &prop_num_pmp_regions}, {.name = "priv_spec", .info = &prop_priv_spec}, {.name = "vext_spec", .info = &prop_vext_spec}, @@ -XXX,XX +XXX,XX @@ static const TypeInfo riscv_cpu_type_infos[] = { .cfg.max_satp_mode = VM_1_10_MBARE, .cfg.ext_zifencei = true, .cfg.ext_zicsr = true, - .cfg.pmp = true + .cfg.pmp = true, + .cfg.pmp_regions = 8 ), DEFINE_ABSTRACT_RISCV_CPU(TYPE_RISCV_CPU_SIFIVE_U, TYPE_RISCV_VENDOR_CPU, @@ -XXX,XX +XXX,XX @@ static const TypeInfo riscv_cpu_type_infos[] = { .cfg.ext_zifencei = true, .cfg.ext_zicsr = true, .cfg.mmu = true, - .cfg.pmp = true + .cfg.pmp = true, + .cfg.pmp_regions = 8 ), #if defined(TARGET_RISCV32) || \ diff --git a/target/riscv/csr.c b/target/riscv/csr.c index XXXXXXX..XXXXXXX 100644 --- a/target/riscv/csr.c +++ b/target/riscv/csr.c @@ -XXX,XX +XXX,XX @@ static RISCVException dbltrp_hmode(CPURISCVState *env, int csrno) static RISCVException pmp(CPURISCVState *env, int csrno) { if (riscv_cpu_cfg(env)->pmp) { - if (csrno <= CSR_PMPCFG3) { + int max_pmpcfg = (env->priv_ver >= PRIV_VERSION_1_12_0) ? ++ CSR_PMPCFG15 : CSR_PMPCFG3; + + if (csrno <= max_pmpcfg) { uint32_t reg_index = csrno - CSR_PMPCFG0; /* TODO: RV128 restriction check */ diff --git a/target/riscv/machine.c b/target/riscv/machine.c index XXXXXXX..XXXXXXX 100644 --- a/target/riscv/machine.c +++ b/target/riscv/machine.c @@ -XXX,XX +XXX,XX @@ static int pmp_post_load(void *opaque, int version_id) RISCVCPU *cpu = opaque; CPURISCVState *env = &cpu->env; int i; + uint8_t pmp_regions = riscv_cpu_cfg(env)->pmp_regions; - for (i = 0; i < MAX_RISCV_PMPS; i++) { + for (i = 0; i < pmp_regions; i++) { pmp_update_rule_addr(env, i); } pmp_update_rule_nums(env); diff --git a/target/riscv/pmp.c b/target/riscv/pmp.c index XXXXXXX..XXXXXXX 100644 --- a/target/riscv/pmp.c +++ b/target/riscv/pmp.c @@ -XXX,XX +XXX,XX @@ uint32_t pmp_get_num_rules(CPURISCVState *env) */ static inline uint8_t pmp_read_cfg(CPURISCVState *env, uint32_t pmp_index) { - if (pmp_index < MAX_RISCV_PMPS) { + uint8_t pmp_regions = riscv_cpu_cfg(env)->pmp_regions; + + if (pmp_index < pmp_regions) { return env->pmp_state.pmp[pmp_index].cfg_reg; } @@ -XXX,XX +XXX,XX @@ static inline uint8_t pmp_read_cfg(CPURISCVState *env, uint32_t pmp_index) */ static bool pmp_write_cfg(CPURISCVState *env, uint32_t pmp_index, uint8_t val) { - if (pmp_index < MAX_RISCV_PMPS) { + uint8_t pmp_regions = riscv_cpu_cfg(env)->pmp_regions; + + if (pmp_index < pmp_regions) { if (env->pmp_state.pmp[pmp_index].cfg_reg == val) { /* no change */ return false; @@ -XXX,XX +XXX,XX @@ void pmp_update_rule_addr(CPURISCVState *env, uint32_t pmp_index) void pmp_update_rule_nums(CPURISCVState *env) { int i; + uint8_t pmp_regions = riscv_cpu_cfg(env)->pmp_regions; env->pmp_state.num_rules = 0; - for (i = 0; i < MAX_RISCV_PMPS; i++) { + for (i = 0; i < pmp_regions; i++) { const uint8_t a_field = pmp_get_a_field(env->pmp_state.pmp[i].cfg_reg); if (PMP_AMATCH_OFF != a_field) { @@ -XXX,XX +XXX,XX @@ bool pmp_hart_has_privs(CPURISCVState *env, hwaddr addr, int pmp_size = 0; hwaddr s = 0; hwaddr e = 0; + uint8_t pmp_regions = riscv_cpu_cfg(env)->pmp_regions; /* Short cut if no rules */ if (0 == pmp_get_num_rules(env)) { @@ -XXX,XX +XXX,XX @@ bool pmp_hart_has_privs(CPURISCVState *env, hwaddr addr, * 1.10 draft priv spec states there is an implicit order * from low to high */ - for (i = 0; i < MAX_RISCV_PMPS; i++) { + for (i = 0; i < pmp_regions; i++) { s = pmp_is_in_range(env, i, addr); e = pmp_is_in_range(env, i, addr + pmp_size - 1); @@ -XXX,XX +XXX,XX @@ void pmpaddr_csr_write(CPURISCVState *env, uint32_t addr_index, { trace_pmpaddr_csr_write(env->mhartid, addr_index, val); bool is_next_cfg_tor = false; + uint8_t pmp_regions = riscv_cpu_cfg(env)->pmp_regions; - if (addr_index < MAX_RISCV_PMPS) { + if (addr_index < pmp_regions) { if (env->pmp_state.pmp[addr_index].addr_reg == val) { /* no change */ return; @@ -XXX,XX +XXX,XX @@ void pmpaddr_csr_write(CPURISCVState *env, uint32_t addr_index, * In TOR mode, need to check the lock bit of the next pmp * (if there is a next). */ - if (addr_index + 1 < MAX_RISCV_PMPS) { + if (addr_index + 1 < pmp_regions) { uint8_t pmp_cfg = env->pmp_state.pmp[addr_index + 1].cfg_reg; is_next_cfg_tor = PMP_AMATCH_TOR == pmp_get_a_field(pmp_cfg); @@ -XXX,XX +XXX,XX @@ void pmpaddr_csr_write(CPURISCVState *env, uint32_t addr_index, target_ulong pmpaddr_csr_read(CPURISCVState *env, uint32_t addr_index) { target_ulong val = 0; + uint8_t pmp_regions = riscv_cpu_cfg(env)->pmp_regions; - if (addr_index < MAX_RISCV_PMPS) { + if (addr_index < pmp_regions) { val = env->pmp_state.pmp[addr_index].addr_reg; trace_pmpaddr_csr_read(env->mhartid, addr_index, val); } else { @@ -XXX,XX +XXX,XX @@ void mseccfg_csr_write(CPURISCVState *env, target_ulong val) { int i; uint64_t mask = MSECCFG_MMWP | MSECCFG_MML; + uint8_t pmp_regions = riscv_cpu_cfg(env)->pmp_regions; /* Update PMM field only if the value is valid according to Zjpm v1.0 */ if (riscv_cpu_cfg(env)->ext_smmpm && riscv_cpu_mxl(env) == MXL_RV64 && @@ -XXX,XX +XXX,XX @@ void mseccfg_csr_write(CPURISCVState *env, target_ulong val) /* RLB cannot be enabled if it's already 0 and if any regions are locked */ if (!MSECCFG_RLB_ISSET(env)) { - for (i = 0; i < MAX_RISCV_PMPS; i++) { + for (i = 0; i < pmp_regions; i++) { if (pmp_is_locked(env, i)) { val &= ~MSECCFG_RLB; break; @@ -XXX,XX +XXX,XX @@ target_ulong pmp_get_tlb_size(CPURISCVState *env, hwaddr addr) hwaddr tlb_sa = addr & ~(TARGET_PAGE_SIZE - 1); hwaddr tlb_ea = tlb_sa + TARGET_PAGE_SIZE - 1; int i; + uint8_t pmp_regions = riscv_cpu_cfg(env)->pmp_regions; /* * If PMP is not supported or there are no PMP rules, the TLB page will not @@ -XXX,XX +XXX,XX @@ target_ulong pmp_get_tlb_size(CPURISCVState *env, hwaddr addr) return TARGET_PAGE_SIZE; } - for (i = 0; i < MAX_RISCV_PMPS; i++) { + for (i = 0; i < pmp_regions; i++) { if (pmp_get_a_field(env->pmp_state.pmp[i].cfg_reg) == PMP_AMATCH_OFF) { continue; } -- 2.50.0
From: Nutty Liu <liujingqi@lanxincomputing.com> The original implementation incorrectly performed a bitwise AND operation between the PPN of iova and PPN Mask, leading to an incorrect PPN field in Translation-reponse register. The PPN of iova should be set entirely in the PPN field of Translation-reponse register. Also remove the code that was used to clear S field since this field is already zero. Signed-off-by: Nutty Liu <liujingqi@lanxincomputing.com> Reviewed-by: Tomasz Jeznach <tjeznach@rivosinc.com> Message-ID: <20250605124848.1248-1-liujingqi@lanxincomputing.com> Signed-off-by: Alistair Francis <alistair.francis@wdc.com> --- hw/riscv/riscv-iommu.c | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/hw/riscv/riscv-iommu.c b/hw/riscv/riscv-iommu.c index XXXXXXX..XXXXXXX 100644 --- a/hw/riscv/riscv-iommu.c +++ b/hw/riscv/riscv-iommu.c @@ -XXX,XX +XXX,XX @@ static void riscv_iommu_process_dbg(RISCVIOMMUState *s) iova = RISCV_IOMMU_TR_RESPONSE_FAULT | (((uint64_t) fault) << 10); } else { iova = iotlb.translated_addr & ~iotlb.addr_mask; - iova >>= TARGET_PAGE_BITS; - iova &= RISCV_IOMMU_TR_RESPONSE_PPN; - - /* We do not support superpages (> 4kbs) for now */ - iova &= ~RISCV_IOMMU_TR_RESPONSE_S; + iova = set_field(0, RISCV_IOMMU_TR_RESPONSE_PPN, PPN_DOWN(iova)); } riscv_iommu_reg_set64(s, RISCV_IOMMU_REG_TR_RESPONSE, iova); } -- 2.50.0
From: Daniel Henrique Barboza <dbarboza@ventanamicro.com> The SBI spec states, for console write byte: "This is a blocking SBI call and it will only return after writing the specified byte to the debug console. It will also return, with SBI_ERR_FAILED, if there are I/O errors." Being a blocker call will either succeed writing the byte or error out, it's feasible to use the blocking qemu_chr_fe_write_all() instead of qemu_chr_fe_write(). Last but not the least, we will duck possible changes in qemu_chr_fe_write() where ret = 0 will have a 'zero byte written' semantic [1] - something that we're not ready to deal in this current state. [1] https://lore.kernel.org/qemu-devel/CAFEAcA_kEndvNtw4EHySXWwQPoGs029yAzZGGBcV=zGHaj7KUQ@mail.gmail.com/ Signed-off-by: Daniel Henrique Barboza <dbarboza@ventanamicro.com> Reviewed-by: Philippe Mathieu-Daudé <philmd@linaro.org> Message-ID: <20250605094456.1385105-2-dbarboza@ventanamicro.com> Signed-off-by: Alistair Francis <alistair.francis@wdc.com> --- target/riscv/kvm/kvm-cpu.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/target/riscv/kvm/kvm-cpu.c b/target/riscv/kvm/kvm-cpu.c index XXXXXXX..XXXXXXX 100644 --- a/target/riscv/kvm/kvm-cpu.c +++ b/target/riscv/kvm/kvm-cpu.c @@ -XXX,XX +XXX,XX @@ static void kvm_riscv_handle_sbi_dbcn(CPUState *cs, struct kvm_run *run) break; case SBI_EXT_DBCN_CONSOLE_WRITE_BYTE: ch = run->riscv_sbi.args[0]; - ret = qemu_chr_fe_write(serial_hd(0)->be, &ch, sizeof(ch)); + ret = qemu_chr_fe_write_all(serial_hd(0)->be, &ch, sizeof(ch)); if (ret < 0) { error_report("SBI_EXT_DBCN_CONSOLE_WRITE_BYTE: error when " -- 2.50.0
From: Anton Blanchard <antonb@tenstorrent.com> fcvt.s.bf16 uses the FP16 check_nanbox_h() which returns an FP16 quiet NaN. Add check_nanbox_bf16() which returns a BF16 quiet NaN. Signed-off-by: Anton Blanchard <antonb@tenstorrent.com> Acked-by: Alistair Francis <alistair.francis@wdc.com> Message-ID: <20250501114253.594887-1-antonb@tenstorrent.com> Signed-off-by: Alistair Francis <alistair.francis@wdc.com> --- target/riscv/internals.h | 16 ++++++++++++++++ target/riscv/fpu_helper.c | 2 +- 2 files changed, 17 insertions(+), 1 deletion(-) diff --git a/target/riscv/internals.h b/target/riscv/internals.h index XXXXXXX..XXXXXXX 100644 --- a/target/riscv/internals.h +++ b/target/riscv/internals.h @@ -XXX,XX +XXX,XX @@ static inline float16 check_nanbox_h(CPURISCVState *env, uint64_t f) } } +static inline float16 check_nanbox_bf16(CPURISCVState *env, uint64_t f) +{ + /* Disable nanbox check when enable zfinx */ + if (env_archcpu(env)->cfg.ext_zfinx) { + return (uint16_t)f; + } + + uint64_t mask = MAKE_64BIT_MASK(16, 48); + + if (likely((f & mask) == mask)) { + return (uint16_t)f; + } else { + return 0x7FC0u; /* default qnan */ + } +} + #ifndef CONFIG_USER_ONLY /* Our implementation of SysemuCPUOps::has_work */ bool riscv_cpu_has_work(CPUState *cs); diff --git a/target/riscv/fpu_helper.c b/target/riscv/fpu_helper.c index XXXXXXX..XXXXXXX 100644 --- a/target/riscv/fpu_helper.c +++ b/target/riscv/fpu_helper.c @@ -XXX,XX +XXX,XX @@ uint64_t helper_fcvt_bf16_s(CPURISCVState *env, uint64_t rs1) uint64_t helper_fcvt_s_bf16(CPURISCVState *env, uint64_t rs1) { - float16 frs1 = check_nanbox_h(env, rs1); + float16 frs1 = check_nanbox_bf16(env, rs1); return nanbox_s(env, bfloat16_to_float32(frs1, &env->fp_status)); } -- 2.50.0
From: Florian Lugou <florian.lugou@provenrun.com> The current handler for TXFIFO writes schedules an async callback to pop characters from the queue. When software writes to TXFIFO faster than the async callback delay (100ns), the timer may be pushed back while the previous character has not be dequeued yet. This happens in particular when using -icount with small shift values. This is especially worrysome when software repetitively issues amoor.w instructions (as suggested by SiFive specification) and the FIFO is full, leading to the callback being infinitly pushed back. This commit fixes the issue by never pushing back the timer, only updating it if it is not already active. Signed-off-by: Florian Lugou <florian.lugou@provenrun.com> Reviewed-by: Alistair Francis <alistair.francis@wdc.com> Message-ID: <20250605101255.797162-1-florian.lugou@provenrun.com> Signed-off-by: Alistair Francis <alistair.francis@wdc.com> --- hw/char/sifive_uart.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/hw/char/sifive_uart.c b/hw/char/sifive_uart.c index XXXXXXX..XXXXXXX 100644 --- a/hw/char/sifive_uart.c +++ b/hw/char/sifive_uart.c @@ -XXX,XX +XXX,XX @@ static void sifive_uart_write_tx_fifo(SiFiveUARTState *s, const uint8_t *buf, s->txfifo |= SIFIVE_UART_TXFIFO_FULL; } - timer_mod(s->fifo_trigger_handle, current_time + - TX_INTERRUPT_TRIGGER_DELAY_NS); + if (!timer_pending(s->fifo_trigger_handle)) { + timer_mod(s->fifo_trigger_handle, current_time + + TX_INTERRUPT_TRIGGER_DELAY_NS); + } } static uint64_t -- 2.50.0
From: Joel Stanley <joel@jms.id.au> The address is a hardware address, so use hwaddr for consistency with the rest of the machine. Reviewed-by: Daniel Henrique Barboza <dbarboza@ventanamicro.com> Reviewed-by: Alistair Francis <alistair.francis@wdc.com> Signed-off-by: Joel Stanley <joel@jms.id.au> Message-ID: <20250604025450.85327-2-joel@jms.id.au> Signed-off-by: Alistair Francis <alistair.francis@wdc.com> --- hw/riscv/virt.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/hw/riscv/virt.c b/hw/riscv/virt.c index XXXXXXX..XXXXXXX 100644 --- a/hw/riscv/virt.c +++ b/hw/riscv/virt.c @@ -XXX,XX +XXX,XX @@ static void create_fdt_socket_clint(RISCVVirtState *s, int cpu; g_autofree char *clint_name = NULL; g_autofree uint32_t *clint_cells = NULL; - unsigned long clint_addr; + hwaddr clint_addr; MachineState *ms = MACHINE(s); static const char * const clint_compat[2] = { "sifive,clint0", "riscv,clint0" @@ -XXX,XX +XXX,XX @@ static void create_fdt_socket_clint(RISCVVirtState *s, } clint_addr = s->memmap[VIRT_CLINT].base + - (s->memmap[VIRT_CLINT].size * socket); - clint_name = g_strdup_printf("/soc/clint@%lx", clint_addr); + s->memmap[VIRT_CLINT].size * socket; + clint_name = g_strdup_printf("/soc/clint@%"HWADDR_PRIx, clint_addr); qemu_fdt_add_subnode(ms->fdt, clint_name); qemu_fdt_setprop_string_array(ms->fdt, clint_name, "compatible", (char **)&clint_compat, -- 2.50.0
From: Joel Stanley <joel@jms.id.au> The current device tree property uses two cells for the address (and for the size), but assumes the they are less than 32 bits by hard coding the high cell to zero. Use qemu_fdt_setprop_sized_cells to do the job of splitting the upper and lower 32 bits across cells. Reviewed-by: Daniel Henrique Barboza <dbarboza@ventanamicro.com> Reviewed-by: Alistair Francis <alistair.francis@wdc.com> Signed-off-by: Joel Stanley <joel@jms.id.au> Message-ID: <20250604025450.85327-3-joel@jms.id.au> Signed-off-by: Alistair Francis <alistair.francis@wdc.com> --- hw/riscv/virt.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/hw/riscv/virt.c b/hw/riscv/virt.c index XXXXXXX..XXXXXXX 100644 --- a/hw/riscv/virt.c +++ b/hw/riscv/virt.c @@ -XXX,XX +XXX,XX @@ static void create_fdt_socket_clint(RISCVVirtState *s, qemu_fdt_setprop_string_array(ms->fdt, clint_name, "compatible", (char **)&clint_compat, ARRAY_SIZE(clint_compat)); - qemu_fdt_setprop_cells(ms->fdt, clint_name, "reg", - 0x0, clint_addr, 0x0, s->memmap[VIRT_CLINT].size); + qemu_fdt_setprop_sized_cells(ms->fdt, clint_name, "reg", + 2, clint_addr, 2, s->memmap[VIRT_CLINT].size); qemu_fdt_setprop(ms->fdt, clint_name, "interrupts-extended", clint_cells, s->soc[socket].num_harts * sizeof(uint32_t) * 4); riscv_socket_fdt_write_id(ms, clint_name, socket); -- 2.50.0
From: Joel Stanley <joel@jms.id.au> Use qemu_fdt_setprop_sized_cells to do the job of splitting the upper and lower 32 bits across cells. Reviewed-by: Daniel Henrique Barboza <dbarboza@ventanamicro.com> Reviewed-by: Alistair Francis <alistair.francis@wdc.com> Signed-off-by: Joel Stanley <joel@jms.id.au> Message-ID: <20250604025450.85327-4-joel@jms.id.au> Signed-off-by: Alistair Francis <alistair.francis@wdc.com> --- hw/riscv/virt.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/hw/riscv/virt.c b/hw/riscv/virt.c index XXXXXXX..XXXXXXX 100644 --- a/hw/riscv/virt.c +++ b/hw/riscv/virt.c @@ -XXX,XX +XXX,XX @@ static void create_fdt_socket_memory(RISCVVirtState *s, int socket) size = riscv_socket_mem_size(ms, socket); mem_name = g_strdup_printf("/memory@%"HWADDR_PRIx, addr); qemu_fdt_add_subnode(ms->fdt, mem_name); - qemu_fdt_setprop_cells(ms->fdt, mem_name, "reg", - addr >> 32, addr, size >> 32, size); + qemu_fdt_setprop_sized_cells(ms->fdt, mem_name, "reg", 2, addr, 2, size); qemu_fdt_setprop_string(ms->fdt, mem_name, "device_type", "memory"); riscv_socket_fdt_write_id(ms, mem_name, socket); } -- 2.50.0
From: Joel Stanley <joel@jms.id.au> The current device tree property uses two cells for the address (and for the size), but assumes the they are less than 32 bits by hard coding the high cell to zero. Use qemu_fdt_setprop_sized_cells to do the job of splitting the upper and lower 32 bits across cells. Reviewed-by: Daniel Henrique Barboza <dbarboza@ventanamicro.com> Reviewed-by: Alistair Francis <alistair.francis@wdc.com> Signed-off-by: Joel Stanley <joel@jms.id.au> Message-ID: <20250604025450.85327-5-joel@jms.id.au> Signed-off-by: Alistair Francis <alistair.francis@wdc.com> --- hw/riscv/virt.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/hw/riscv/virt.c b/hw/riscv/virt.c index XXXXXXX..XXXXXXX 100644 --- a/hw/riscv/virt.c +++ b/hw/riscv/virt.c @@ -XXX,XX +XXX,XX @@ static void create_fdt_one_aplic(RISCVVirtState *s, int socket, qemu_fdt_setprop_cell(ms->fdt, aplic_name, "msi-parent", msi_phandle); } - qemu_fdt_setprop_cells(ms->fdt, aplic_name, "reg", - 0x0, aplic_addr, 0x0, aplic_size); + qemu_fdt_setprop_sized_cells(ms->fdt, aplic_name, "reg", + 2, aplic_addr, 2, aplic_size); qemu_fdt_setprop_cell(ms->fdt, aplic_name, "riscv,num-sources", VIRT_IRQCHIP_NUM_SOURCES); -- 2.50.0
From: Joel Stanley <joel@jms.id.au> The current device tree property uses two cells for the address (and for the size), but assumes the they are less than 32 bits by hard coding the high cell to zero. Use qemu_fdt_setprop_sized_cells to do the job of splitting the upper and lower 32 bits across cells. Reviewed-by: Daniel Henrique Barboza <dbarboza@ventanamicro.com> Reviewed-by: Alistair Francis <alistair.francis@wdc.com> Signed-off-by: Joel Stanley <joel@jms.id.au> Message-ID: <20250604025450.85327-6-joel@jms.id.au> Signed-off-by: Alistair Francis <alistair.francis@wdc.com> --- hw/riscv/virt.c | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/hw/riscv/virt.c b/hw/riscv/virt.c index XXXXXXX..XXXXXXX 100644 --- a/hw/riscv/virt.c +++ b/hw/riscv/virt.c @@ -XXX,XX +XXX,XX @@ static void create_fdt_socket_aclint(RISCVVirtState *s, qemu_fdt_add_subnode(ms->fdt, name); qemu_fdt_setprop_string(ms->fdt, name, "compatible", "riscv,aclint-mswi"); - qemu_fdt_setprop_cells(ms->fdt, name, "reg", - 0x0, addr, 0x0, RISCV_ACLINT_SWI_SIZE); + qemu_fdt_setprop_sized_cells(ms->fdt, name, "reg", + 2, addr, 2, RISCV_ACLINT_SWI_SIZE); qemu_fdt_setprop(ms->fdt, name, "interrupts-extended", aclint_mswi_cells, aclint_cells_size); qemu_fdt_setprop(ms->fdt, name, "interrupt-controller", NULL, 0); @@ -XXX,XX +XXX,XX @@ static void create_fdt_socket_aclint(RISCVVirtState *s, qemu_fdt_add_subnode(ms->fdt, name); qemu_fdt_setprop_string(ms->fdt, name, "compatible", "riscv,aclint-mtimer"); - qemu_fdt_setprop_cells(ms->fdt, name, "reg", - 0x0, addr + RISCV_ACLINT_DEFAULT_MTIME, - 0x0, size - RISCV_ACLINT_DEFAULT_MTIME, - 0x0, addr + RISCV_ACLINT_DEFAULT_MTIMECMP, - 0x0, RISCV_ACLINT_DEFAULT_MTIME); + qemu_fdt_setprop_sized_cells(ms->fdt, name, "reg", + 2, addr + RISCV_ACLINT_DEFAULT_MTIME, + 2, size - RISCV_ACLINT_DEFAULT_MTIME, + 2, addr + RISCV_ACLINT_DEFAULT_MTIMECMP, + 2, RISCV_ACLINT_DEFAULT_MTIME); qemu_fdt_setprop(ms->fdt, name, "interrupts-extended", aclint_mtimer_cells, aclint_cells_size); riscv_socket_fdt_write_id(ms, name, socket); @@ -XXX,XX +XXX,XX @@ static void create_fdt_socket_aclint(RISCVVirtState *s, qemu_fdt_add_subnode(ms->fdt, name); qemu_fdt_setprop_string(ms->fdt, name, "compatible", "riscv,aclint-sswi"); - qemu_fdt_setprop_cells(ms->fdt, name, "reg", - 0x0, addr, 0x0, s->memmap[VIRT_ACLINT_SSWI].size); + qemu_fdt_setprop_sized_cells(ms->fdt, name, "reg", + 2, addr, 2, s->memmap[VIRT_ACLINT_SSWI].size); qemu_fdt_setprop(ms->fdt, name, "interrupts-extended", aclint_sswi_cells, aclint_cells_size); qemu_fdt_setprop(ms->fdt, name, "interrupt-controller", NULL, 0); -- 2.50.0
From: Joel Stanley <joel@jms.id.au> The current device tree property uses two cells for the address (and for the size), but assumes the they are less than 32 bits by hard coding the high cell to zero. Use qemu_fdt_setprop_sized_cells to do the job of splitting the upper and lower 32 bits across cells. Reviewed-by: Daniel Henrique Barboza <dbarboza@ventanamicro.com> Reviewed-by: Alistair Francis <alistair.francis@wdc.com> Signed-off-by: Joel Stanley <joel@jms.id.au> Message-ID: <20250604025450.85327-7-joel@jms.id.au> Signed-off-by: Alistair Francis <alistair.francis@wdc.com> --- hw/riscv/virt.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/hw/riscv/virt.c b/hw/riscv/virt.c index XXXXXXX..XXXXXXX 100644 --- a/hw/riscv/virt.c +++ b/hw/riscv/virt.c @@ -XXX,XX +XXX,XX @@ static void create_fdt_socket_plic(RISCVVirtState *s, s->soc[socket].num_harts * sizeof(uint32_t) * 4); } - qemu_fdt_setprop_cells(ms->fdt, plic_name, "reg", - 0x0, plic_addr, 0x0, s->memmap[VIRT_PLIC].size); + qemu_fdt_setprop_sized_cells(ms->fdt, plic_name, "reg", + 2, plic_addr, 2, s->memmap[VIRT_PLIC].size); qemu_fdt_setprop_cell(ms->fdt, plic_name, "riscv,ndev", VIRT_IRQCHIP_NUM_SOURCES - 1); riscv_socket_fdt_write_id(ms, plic_name, socket); -- 2.50.0
From: Joel Stanley <joel@jms.id.au> The current device tree property uses two cells for the address (and for the size), but assumes the they are less than 32 bits by hard coding the high cell to zero. Use qemu_fdt_setprop_sized_cells to do the job of splitting the upper and lower 32 bits across cells. Reviewed-by: Daniel Henrique Barboza <dbarboza@ventanamicro.com> Reviewed-by: Alistair Francis <alistair.francis@wdc.com> Signed-off-by: Joel Stanley <joel@jms.id.au> Message-ID: <20250604025450.85327-8-joel@jms.id.au> Signed-off-by: Alistair Francis <alistair.francis@wdc.com> --- hw/riscv/virt.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/hw/riscv/virt.c b/hw/riscv/virt.c index XXXXXXX..XXXXXXX 100644 --- a/hw/riscv/virt.c +++ b/hw/riscv/virt.c @@ -XXX,XX +XXX,XX @@ static void create_fdt_virtio(RISCVVirtState *s, uint32_t irq_virtio_phandle) qemu_fdt_add_subnode(ms->fdt, name); qemu_fdt_setprop_string(ms->fdt, name, "compatible", "virtio,mmio"); - qemu_fdt_setprop_cells(ms->fdt, name, "reg", - 0x0, addr, - 0x0, size); + qemu_fdt_setprop_sized_cells(ms->fdt, name, "reg", 2, addr, 2, size); qemu_fdt_setprop_cell(ms->fdt, name, "interrupt-parent", irq_virtio_phandle); if (s->aia_type == VIRT_AIA_TYPE_NONE) { -- 2.50.0
From: Joel Stanley <joel@jms.id.au> The current device tree property uses two cells for the address (and for the size), but assumes the they are less than 32 bits by hard coding the high cell to zero. Use qemu_fdt_setprop_sized_cells to do the job of splitting the upper and lower 32 bits across cells. Reviewed-by: Daniel Henrique Barboza <dbarboza@ventanamicro.com> Reviewed-by: Alistair Francis <alistair.francis@wdc.com> Signed-off-by: Joel Stanley <joel@jms.id.au> Message-ID: <20250604025450.85327-9-joel@jms.id.au> Signed-off-by: Alistair Francis <alistair.francis@wdc.com> --- hw/riscv/virt.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/hw/riscv/virt.c b/hw/riscv/virt.c index XXXXXXX..XXXXXXX 100644 --- a/hw/riscv/virt.c +++ b/hw/riscv/virt.c @@ -XXX,XX +XXX,XX @@ static void create_fdt_reset(RISCVVirtState *s, uint32_t *phandle) qemu_fdt_setprop_string_array(ms->fdt, name, "compatible", (char **)&compat, ARRAY_SIZE(compat)); } - qemu_fdt_setprop_cells(ms->fdt, name, "reg", - 0x0, s->memmap[VIRT_TEST].base, 0x0, s->memmap[VIRT_TEST].size); + qemu_fdt_setprop_sized_cells(ms->fdt, name, "reg", + 2, s->memmap[VIRT_TEST].base, + 2, s->memmap[VIRT_TEST].size); qemu_fdt_setprop_cell(ms->fdt, name, "phandle", test_phandle); test_phandle = qemu_fdt_get_phandle(ms->fdt, name); g_free(name); -- 2.50.0
From: Joel Stanley <joel@jms.id.au> The current device tree property uses two cells for the address (and for the size), but assumes the they are less than 32 bits by hard coding the high cell to zero. Use qemu_fdt_setprop_sized_cells to do the job of splitting the upper and lower 32 bits across cells. Reviewed-by: Daniel Henrique Barboza <dbarboza@ventanamicro.com> Reviewed-by: Alistair Francis <alistair.francis@wdc.com> Signed-off-by: Joel Stanley <joel@jms.id.au> Message-ID: <20250604025450.85327-10-joel@jms.id.au> Signed-off-by: Alistair Francis <alistair.francis@wdc.com> --- hw/riscv/virt.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/hw/riscv/virt.c b/hw/riscv/virt.c index XXXXXXX..XXXXXXX 100644 --- a/hw/riscv/virt.c +++ b/hw/riscv/virt.c @@ -XXX,XX +XXX,XX @@ static void create_fdt_uart(RISCVVirtState *s, s->memmap[VIRT_UART0].base); qemu_fdt_add_subnode(ms->fdt, name); qemu_fdt_setprop_string(ms->fdt, name, "compatible", "ns16550a"); - qemu_fdt_setprop_cells(ms->fdt, name, "reg", - 0x0, s->memmap[VIRT_UART0].base, - 0x0, s->memmap[VIRT_UART0].size); + qemu_fdt_setprop_sized_cells(ms->fdt, name, "reg", + 2, s->memmap[VIRT_UART0].base, + 2, s->memmap[VIRT_UART0].size); qemu_fdt_setprop_cell(ms->fdt, name, "clock-frequency", 3686400); qemu_fdt_setprop_cell(ms->fdt, name, "interrupt-parent", irq_mmio_phandle); if (s->aia_type == VIRT_AIA_TYPE_NONE) { -- 2.50.0
From: Joel Stanley <joel@jms.id.au> The current device tree property uses two cells for the address (and for the size), but assumes the they are less than 32 bits by hard coding the high cell to zero. Use qemu_fdt_setprop_sized_cells to do the job of splitting the upper and lower 32 bits across cells. Reviewed-by: Daniel Henrique Barboza <dbarboza@ventanamicro.com> Reviewed-by: Alistair Francis <alistair.francis@wdc.com> Signed-off-by: Joel Stanley <joel@jms.id.au> Message-ID: <20250604025450.85327-11-joel@jms.id.au> Signed-off-by: Alistair Francis <alistair.francis@wdc.com> --- hw/riscv/virt.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/hw/riscv/virt.c b/hw/riscv/virt.c index XXXXXXX..XXXXXXX 100644 --- a/hw/riscv/virt.c +++ b/hw/riscv/virt.c @@ -XXX,XX +XXX,XX @@ static void create_fdt_rtc(RISCVVirtState *s, qemu_fdt_add_subnode(ms->fdt, name); qemu_fdt_setprop_string(ms->fdt, name, "compatible", "google,goldfish-rtc"); - qemu_fdt_setprop_cells(ms->fdt, name, "reg", - 0x0, s->memmap[VIRT_RTC].base, 0x0, s->memmap[VIRT_RTC].size); + qemu_fdt_setprop_sized_cells(ms->fdt, name, "reg", + 2, s->memmap[VIRT_RTC].base, + 2, s->memmap[VIRT_RTC].size); qemu_fdt_setprop_cell(ms->fdt, name, "interrupt-parent", irq_mmio_phandle); if (s->aia_type == VIRT_AIA_TYPE_NONE) { -- 2.50.0
From: Joel Stanley <joel@jms.id.au> The current device tree property uses two cells for the address (and for the size), but assumes the they are less than 32 bits by hard coding the high cell to zero. Use qemu_fdt_setprop_sized_cells to do the job of splitting the upper and lower 32 bits across cells. Reviewed-by: Daniel Henrique Barboza <dbarboza@ventanamicro.com> Reviewed-by: Alistair Francis <alistair.francis@wdc.com> Signed-off-by: Joel Stanley <joel@jms.id.au> Message-ID: <20250604025450.85327-12-joel@jms.id.au> Signed-off-by: Alistair Francis <alistair.francis@wdc.com> --- hw/riscv/virt.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/hw/riscv/virt.c b/hw/riscv/virt.c index XXXXXXX..XXXXXXX 100644 --- a/hw/riscv/virt.c +++ b/hw/riscv/virt.c @@ -XXX,XX +XXX,XX @@ static void create_fdt_iommu_sys(RISCVVirtState *s, uint32_t irq_chip, qemu_fdt_setprop_cell(fdt, iommu_node, "#iommu-cells", 1); qemu_fdt_setprop_cell(fdt, iommu_node, "phandle", iommu_phandle); - qemu_fdt_setprop_cells(fdt, iommu_node, "reg", - addr >> 32, addr, size >> 32, size); + qemu_fdt_setprop_sized_cells(fdt, iommu_node, "reg", 2, addr, 2, size); qemu_fdt_setprop_cell(fdt, iommu_node, "interrupt-parent", irq_chip); qemu_fdt_setprop_cells(fdt, iommu_node, "interrupts", -- 2.50.0
From: Joel Stanley <joel@jms.id.au> The current device tree property uses two cells for the address (and for the size), but assumes the they are less than 32 bits by hard coding the high cell to zero. Use qemu_fdt_setprop_sized_cells to do the job of splitting the upper and lower 32 bits across cells. Reviewed-by: Daniel Henrique Barboza <dbarboza@ventanamicro.com> Reviewed-by: Alistair Francis <alistair.francis@wdc.com> Signed-off-by: Joel Stanley <joel@jms.id.au> Message-ID: <20250604025450.85327-13-joel@jms.id.au> Signed-off-by: Alistair Francis <alistair.francis@wdc.com> --- hw/riscv/virt.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/hw/riscv/virt.c b/hw/riscv/virt.c index XXXXXXX..XXXXXXX 100644 --- a/hw/riscv/virt.c +++ b/hw/riscv/virt.c @@ -XXX,XX +XXX,XX @@ static void create_fdt_pcie(RISCVVirtState *s, if (s->aia_type == VIRT_AIA_TYPE_APLIC_IMSIC) { qemu_fdt_setprop_cell(ms->fdt, name, "msi-parent", msi_pcie_phandle); } - qemu_fdt_setprop_cells(ms->fdt, name, "reg", 0, - s->memmap[VIRT_PCIE_ECAM].base, 0, s->memmap[VIRT_PCIE_ECAM].size); + qemu_fdt_setprop_sized_cells(ms->fdt, name, "reg", 2, + s->memmap[VIRT_PCIE_ECAM].base, 2, s->memmap[VIRT_PCIE_ECAM].size); qemu_fdt_setprop_sized_cells(ms->fdt, name, "ranges", 1, FDT_PCI_RANGE_IOPORT, 2, 0, 2, s->memmap[VIRT_PCIE_PIO].base, 2, s->memmap[VIRT_PCIE_PIO].size, -- 2.50.0
From: Huang Borong <3543977024@qq.com> Add a CPU entry for the Xiangshan Kunminghu CPU, an open-source, high-performance RISC-V processor. More details can be found at: https://github.com/OpenXiangShan/XiangShan Note: The ISA extensions supported by the Xiangshan Kunminghu CPU are categorized based on four RISC-V specifications: Volume I: Unprivileged Architecture, Volume II: Privileged Architecture, AIA, and RVA23. The extensions within each category are organized according to the chapter order in the specifications. Signed-off-by: Yu Hu <huyu@bosc.ac.cn> Signed-off-by: Ran Wang <wangran@bosc.ac.cn> Signed-off-by: Borong Huang <3543977024@qq.com> Reviewed-by: Daniel Henrique Barboza <dbarboza@ventanamicro.com> Acked-by: Alistair Francis <alistair.francis@wdc.com> Message-ID: <20250425122212.364-1-wangran@bosc.ac.cn> Signed-off-by: Alistair Francis <alistair.francis@wdc.com> --- target/riscv/cpu-qom.h | 1 + target/riscv/cpu.c | 58 ++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 59 insertions(+) diff --git a/target/riscv/cpu-qom.h b/target/riscv/cpu-qom.h index XXXXXXX..XXXXXXX 100644 --- a/target/riscv/cpu-qom.h +++ b/target/riscv/cpu-qom.h @@ -XXX,XX +XXX,XX @@ #define TYPE_RISCV_CPU_VEYRON_V1 RISCV_CPU_TYPE_NAME("veyron-v1") #define TYPE_RISCV_CPU_TT_ASCALON RISCV_CPU_TYPE_NAME("tt-ascalon") #define TYPE_RISCV_CPU_XIANGSHAN_NANHU RISCV_CPU_TYPE_NAME("xiangshan-nanhu") +#define TYPE_RISCV_CPU_XIANGSHAN_KMH RISCV_CPU_TYPE_NAME("xiangshan-kunminghu") #define TYPE_RISCV_CPU_HOST RISCV_CPU_TYPE_NAME("host") OBJECT_DECLARE_CPU_TYPE(RISCVCPU, RISCVCPUClass, RISCV_CPU) diff --git a/target/riscv/cpu.c b/target/riscv/cpu.c index XXXXXXX..XXXXXXX 100644 --- a/target/riscv/cpu.c +++ b/target/riscv/cpu.c @@ -XXX,XX +XXX,XX @@ static const TypeInfo riscv_cpu_type_infos[] = { .cfg.max_satp_mode = VM_1_10_SV39, ), + DEFINE_RISCV_CPU(TYPE_RISCV_CPU_XIANGSHAN_KMH, TYPE_RISCV_VENDOR_CPU, + .misa_mxl_max = MXL_RV64, + .misa_ext = RVG | RVC | RVB | RVS | RVU | RVH | RVV, + .priv_spec = PRIV_VERSION_1_13_0, + /* + * The RISC-V Instruction Set Manual: Volume I + * Unprivileged Architecture + */ + .cfg.ext_zicntr = true, + .cfg.ext_zihpm = true, + .cfg.ext_zihintntl = true, + .cfg.ext_zihintpause = true, + .cfg.ext_zimop = true, + .cfg.ext_zcmop = true, + .cfg.ext_zicond = true, + .cfg.ext_zawrs = true, + .cfg.ext_zacas = true, + .cfg.ext_zfh = true, + .cfg.ext_zfa = true, + .cfg.ext_zcb = true, + .cfg.ext_zbc = true, + .cfg.ext_zvfh = true, + .cfg.ext_zkn = true, + .cfg.ext_zks = true, + .cfg.ext_zkt = true, + .cfg.ext_zvbb = true, + .cfg.ext_zvkt = true, + /* + * The RISC-V Instruction Set Manual: Volume II + * Privileged Architecture + */ + .cfg.ext_smstateen = true, + .cfg.ext_smcsrind = true, + .cfg.ext_sscsrind = true, + .cfg.ext_svnapot = true, + .cfg.ext_svpbmt = true, + .cfg.ext_svinval = true, + .cfg.ext_sstc = true, + .cfg.ext_sscofpmf = true, + .cfg.ext_ssdbltrp = true, + .cfg.ext_ssnpm = true, + .cfg.ext_smnpm = true, + .cfg.ext_smmpm = true, + .cfg.ext_sspm = true, + .cfg.ext_supm = true, + /* The RISC-V Advanced Interrupt Architecture */ + .cfg.ext_smaia = true, + .cfg.ext_ssaia = true, + /* RVA23 Profiles */ + .cfg.ext_zicbom = true, + .cfg.ext_zicbop = true, + .cfg.ext_zicboz = true, + .cfg.ext_svade = true, + .cfg.mmu = true, + .cfg.pmp = true, + .cfg.max_satp_mode = VM_1_10_SV48, + ), + #if defined(CONFIG_TCG) && !defined(CONFIG_USER_ONLY) DEFINE_RISCV_CPU(TYPE_RISCV_CPU_BASE128, TYPE_RISCV_DYNAMIC_CPU, .cfg.max_satp_mode = VM_1_10_SV57, -- 2.50.0
From: Huang Borong <3543977024@qq.com> This implementation provides emulation for the Xiangshan Kunminghu FPGA prototype platform, including support for UART, CLINT, IMSIC, and APLIC devices. More details can be found at https://github.com/OpenXiangShan/XiangShan Signed-off-by: qinshaoqing <qinshaoqing@bosc.ac.cn> Signed-off-by: Yang Wang <wangyang@bosc.ac.cn> Signed-off-by: Yu Hu <819258943@qq.com> Signed-off-by: Ran Wang <wangran@bosc.ac.cn> Signed-off-by: Borong Huang <3543977024@qq.com> Reviewed-by: Daniel Henrique Barboza <dbarboza@ventanamicro.com> Message-ID: <20250617074222.17618-1-wangran@bosc.ac.cn> Signed-off-by: Alistair Francis <alistair.francis@wdc.com> --- MAINTAINERS | 7 + docs/system/riscv/xiangshan-kunminghu.rst | 39 ++++ docs/system/target-riscv.rst | 1 + configs/devices/riscv64-softmmu/default.mak | 1 + include/hw/riscv/xiangshan_kmh.h | 68 ++++++ hw/riscv/xiangshan_kmh.c | 220 ++++++++++++++++++++ hw/riscv/Kconfig | 9 + hw/riscv/meson.build | 1 + 8 files changed, 346 insertions(+) create mode 100644 docs/system/riscv/xiangshan-kunminghu.rst create mode 100644 include/hw/riscv/xiangshan_kmh.h create mode 100644 hw/riscv/xiangshan_kmh.c diff --git a/MAINTAINERS b/MAINTAINERS index XXXXXXX..XXXXXXX 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -XXX,XX +XXX,XX @@ S: Maintained F: hw/riscv/microblaze-v-generic.c F: docs/system/riscv/microblaze-v-generic.rst +Xiangshan Kunminghu +M: Ran Wang <wangran@bosc.ac.cn> +S: Maintained +F: docs/system/riscv/xiangshan-kunminghu.rst +F: hw/riscv/xiangshan_kmh.c +F: include/hw/riscv/xiangshan_kmh.h + RX Machines ----------- rx-gdbsim diff --git a/docs/system/riscv/xiangshan-kunminghu.rst b/docs/system/riscv/xiangshan-kunminghu.rst new file mode 100644 index XXXXXXX..XXXXXXX --- /dev/null +++ b/docs/system/riscv/xiangshan-kunminghu.rst @@ -XXX,XX +XXX,XX @@ +BOSC Xiangshan Kunminghu FPGA prototype platform (``xiangshan-kunminghu``) +========================================================================== +The ``xiangshan-kunminghu`` machine is compatible with our FPGA prototype +platform. + +XiangShan is an open-source high-performance RISC-V processor project. +The third generation processor is called Kunminghu. Kunminghu is a 64-bit +RV64GCBSUHV processor core. More information can be found in our Github +repository: +https://github.com/OpenXiangShan/XiangShan + +Supported devices +----------------- +The ``xiangshan-kunminghu`` machine supports the following devices: + +* Up to 16 xiangshan-kunminghu cores +* Core Local Interruptor (CLINT) +* Incoming MSI Controller (IMSIC) +* Advanced Platform-Level Interrupt Controller (APLIC) +* 1 UART + +Boot options +------------ +The ``xiangshan-kunminghu`` machine can start using the standard ``-bios`` +functionality for loading the boot image. You need to compile and link +the firmware, kernel, and Device Tree (FDT) into a single binary file, +such as ``fw_payload.bin``. + +Running +------- +Below is an example command line for running the ``xiangshan-kunminghu`` +machine: + +.. code-block:: bash + + $ qemu-system-riscv64 -machine xiangshan-kunminghu \ + -smp 16 -m 16G \ + -bios path/to/opensbi/platform/generic/firmware/fw_payload.bin \ + -nographic diff --git a/docs/system/target-riscv.rst b/docs/system/target-riscv.rst index XXXXXXX..XXXXXXX 100644 --- a/docs/system/target-riscv.rst +++ b/docs/system/target-riscv.rst @@ -XXX,XX +XXX,XX @@ undocumented; you can get a complete list by running riscv/shakti-c riscv/sifive_u riscv/virt + riscv/xiangshan-kunminghu RISC-V CPU firmware ------------------- diff --git a/configs/devices/riscv64-softmmu/default.mak b/configs/devices/riscv64-softmmu/default.mak index XXXXXXX..XXXXXXX 100644 --- a/configs/devices/riscv64-softmmu/default.mak +++ b/configs/devices/riscv64-softmmu/default.mak @@ -XXX,XX +XXX,XX @@ # CONFIG_RISCV_VIRT=n # CONFIG_MICROCHIP_PFSOC=n # CONFIG_SHAKTI_C=n +# CONFIG_XIANGSHAN_KUNMINGHU=n diff --git a/include/hw/riscv/xiangshan_kmh.h b/include/hw/riscv/xiangshan_kmh.h new file mode 100644 index XXXXXXX..XXXXXXX --- /dev/null +++ b/include/hw/riscv/xiangshan_kmh.h @@ -XXX,XX +XXX,XX @@ +/* SPDX-License-Identifier: BSD-2-Clause */ +/* + * QEMU RISC-V Board Compatible with the Xiangshan Kunminghu + * FPGA prototype platform + * + * Copyright (c) 2025 Beijing Institute of Open Source Chip (BOSC) + * + */ + +#ifndef HW_XIANGSHAN_KMH_H +#define HW_XIANGSHAN_KMH_H + +#include "hw/boards.h" +#include "hw/riscv/riscv_hart.h" + +#define XIANGSHAN_KMH_MAX_CPUS 16 + +typedef struct XiangshanKmhSoCState { + /*< private >*/ + DeviceState parent_obj; + + /*< public >*/ + RISCVHartArrayState cpus; + DeviceState *irqchip; + MemoryRegion rom; +} XiangshanKmhSoCState; + +#define TYPE_XIANGSHAN_KMH_SOC "xiangshan.kunminghu.soc" +DECLARE_INSTANCE_CHECKER(XiangshanKmhSoCState, XIANGSHAN_KMH_SOC, + TYPE_XIANGSHAN_KMH_SOC) + +typedef struct XiangshanKmhState { + /*< private >*/ + MachineState parent_obj; + + /*< public >*/ + XiangshanKmhSoCState soc; +} XiangshanKmhState; + +#define TYPE_XIANGSHAN_KMH_MACHINE MACHINE_TYPE_NAME("xiangshan-kunminghu") +DECLARE_INSTANCE_CHECKER(XiangshanKmhState, XIANGSHAN_KMH_MACHINE, + TYPE_XIANGSHAN_KMH_MACHINE) + +enum { + XIANGSHAN_KMH_ROM, + XIANGSHAN_KMH_UART0, + XIANGSHAN_KMH_CLINT, + XIANGSHAN_KMH_APLIC_M, + XIANGSHAN_KMH_APLIC_S, + XIANGSHAN_KMH_IMSIC_M, + XIANGSHAN_KMH_IMSIC_S, + XIANGSHAN_KMH_DRAM, +}; + +enum { + XIANGSHAN_KMH_UART0_IRQ = 10, +}; + +/* Indicating Timebase-freq (1MHZ) */ +#define XIANGSHAN_KMH_CLINT_TIMEBASE_FREQ 1000000 + +#define XIANGSHAN_KMH_IMSIC_NUM_IDS 255 +#define XIANGSHAN_KMH_IMSIC_NUM_GUESTS 7 +#define XIANGSHAN_KMH_IMSIC_GUEST_BITS 3 + +#define XIANGSHAN_KMH_APLIC_NUM_SOURCES 96 + +#endif diff --git a/hw/riscv/xiangshan_kmh.c b/hw/riscv/xiangshan_kmh.c new file mode 100644 index XXXXXXX..XXXXXXX --- /dev/null +++ b/hw/riscv/xiangshan_kmh.c @@ -XXX,XX +XXX,XX @@ +/* + * QEMU RISC-V Board Compatible with the Xiangshan Kunminghu + * FPGA prototype platform + * + * Copyright (c) 2025 Beijing Institute of Open Source Chip (BOSC) + * SPDX-License-Identifier: GPL-2.0-or-later + * + * Provides a board compatible with the Xiangshan Kunminghu + * FPGA prototype platform: + * + * 0) UART (16550A) + * 1) CLINT (Core-Local Interruptor) + * 2) IMSIC (Incoming MSI Controller) + * 3) APLIC (Advanced Platform-Level Interrupt Controller) + * + * More information can be found in our Github repository: + * https://github.com/OpenXiangShan/XiangShan + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2 or later, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along with + * this program. If not, see <http://www.gnu.org/licenses/>. + */ + +#include "qemu/osdep.h" +#include "qapi/error.h" +#include "system/address-spaces.h" +#include "hw/boards.h" +#include "hw/char/serial-mm.h" +#include "hw/intc/riscv_aclint.h" +#include "hw/intc/riscv_aplic.h" +#include "hw/intc/riscv_imsic.h" +#include "hw/qdev-properties.h" +#include "hw/riscv/boot.h" +#include "hw/riscv/xiangshan_kmh.h" +#include "hw/riscv/riscv_hart.h" +#include "system/system.h" + +static const MemMapEntry xiangshan_kmh_memmap[] = { + [XIANGSHAN_KMH_ROM] = { 0x1000, 0xF000 }, + [XIANGSHAN_KMH_UART0] = { 0x310B0000, 0x10000 }, + [XIANGSHAN_KMH_CLINT] = { 0x38000000, 0x10000 }, + [XIANGSHAN_KMH_APLIC_M] = { 0x31100000, 0x4000 }, + [XIANGSHAN_KMH_APLIC_S] = { 0x31120000, 0x4000 }, + [XIANGSHAN_KMH_IMSIC_M] = { 0x3A800000, 0x10000 }, + [XIANGSHAN_KMH_IMSIC_S] = { 0x3B000000, 0x80000 }, + [XIANGSHAN_KMH_DRAM] = { 0x80000000, 0x0 }, +}; + +static DeviceState *xiangshan_kmh_create_aia(uint32_t num_harts) +{ + int i; + const MemMapEntry *memmap = xiangshan_kmh_memmap; + hwaddr addr = 0; + DeviceState *aplic_m = NULL; + + /* M-level IMSICs */ + addr = memmap[XIANGSHAN_KMH_IMSIC_M].base; + for (i = 0; i < num_harts; i++) { + riscv_imsic_create(addr + i * IMSIC_HART_SIZE(0), i, true, + 1, XIANGSHAN_KMH_IMSIC_NUM_IDS); + } + + /* S-level IMSICs */ + addr = memmap[XIANGSHAN_KMH_IMSIC_S].base; + for (i = 0; i < num_harts; i++) { + riscv_imsic_create(addr + + i * IMSIC_HART_SIZE(XIANGSHAN_KMH_IMSIC_GUEST_BITS), + i, false, 1 + XIANGSHAN_KMH_IMSIC_GUEST_BITS, + XIANGSHAN_KMH_IMSIC_NUM_IDS); + } + + /* M-level APLIC */ + aplic_m = riscv_aplic_create(memmap[XIANGSHAN_KMH_APLIC_M].base, + memmap[XIANGSHAN_KMH_APLIC_M].size, + 0, 0, XIANGSHAN_KMH_APLIC_NUM_SOURCES, + 1, true, true, NULL); + + /* S-level APLIC */ + riscv_aplic_create(memmap[XIANGSHAN_KMH_APLIC_S].base, + memmap[XIANGSHAN_KMH_APLIC_S].size, + 0, 0, XIANGSHAN_KMH_APLIC_NUM_SOURCES, + 1, true, false, aplic_m); + + return aplic_m; +} + +static void xiangshan_kmh_soc_realize(DeviceState *dev, Error **errp) +{ + MachineState *ms = MACHINE(qdev_get_machine()); + XiangshanKmhSoCState *s = XIANGSHAN_KMH_SOC(dev); + const MemMapEntry *memmap = xiangshan_kmh_memmap; + MemoryRegion *system_memory = get_system_memory(); + uint32_t num_harts = ms->smp.cpus; + + qdev_prop_set_uint32(DEVICE(&s->cpus), "num-harts", num_harts); + qdev_prop_set_uint32(DEVICE(&s->cpus), "hartid-base", 0); + qdev_prop_set_string(DEVICE(&s->cpus), "cpu-type", + TYPE_RISCV_CPU_XIANGSHAN_KMH); + sysbus_realize(SYS_BUS_DEVICE(&s->cpus), &error_fatal); + + /* AIA */ + s->irqchip = xiangshan_kmh_create_aia(num_harts); + + /* UART */ + serial_mm_init(system_memory, memmap[XIANGSHAN_KMH_UART0].base, 2, + qdev_get_gpio_in(s->irqchip, XIANGSHAN_KMH_UART0_IRQ), + 115200, serial_hd(0), DEVICE_LITTLE_ENDIAN); + + /* CLINT */ + riscv_aclint_swi_create(memmap[XIANGSHAN_KMH_CLINT].base, + 0, num_harts, false); + riscv_aclint_mtimer_create(memmap[XIANGSHAN_KMH_CLINT].base + + RISCV_ACLINT_SWI_SIZE, + RISCV_ACLINT_DEFAULT_MTIMER_SIZE, + 0, num_harts, RISCV_ACLINT_DEFAULT_MTIMECMP, + RISCV_ACLINT_DEFAULT_MTIME, + XIANGSHAN_KMH_CLINT_TIMEBASE_FREQ, true); + + /* ROM */ + memory_region_init_rom(&s->rom, OBJECT(dev), "xiangshan.kunminghu.rom", + memmap[XIANGSHAN_KMH_ROM].size, &error_fatal); + memory_region_add_subregion(system_memory, + memmap[XIANGSHAN_KMH_ROM].base, &s->rom); +} + +static void xiangshan_kmh_soc_class_init(ObjectClass *klass, const void *data) +{ + DeviceClass *dc = DEVICE_CLASS(klass); + + dc->realize = xiangshan_kmh_soc_realize; + dc->user_creatable = false; +} + +static void xiangshan_kmh_soc_instance_init(Object *obj) +{ + XiangshanKmhSoCState *s = XIANGSHAN_KMH_SOC(obj); + + object_initialize_child(obj, "cpus", &s->cpus, TYPE_RISCV_HART_ARRAY); +} + +static const TypeInfo xiangshan_kmh_soc_info = { + .name = TYPE_XIANGSHAN_KMH_SOC, + .parent = TYPE_DEVICE, + .instance_size = sizeof(XiangshanKmhSoCState), + .instance_init = xiangshan_kmh_soc_instance_init, + .class_init = xiangshan_kmh_soc_class_init, +}; + +static void xiangshan_kmh_soc_register_types(void) +{ + type_register_static(&xiangshan_kmh_soc_info); +} +type_init(xiangshan_kmh_soc_register_types) + +static void xiangshan_kmh_machine_init(MachineState *machine) +{ + XiangshanKmhState *s = XIANGSHAN_KMH_MACHINE(machine); + const MemMapEntry *memmap = xiangshan_kmh_memmap; + MemoryRegion *system_memory = get_system_memory(); + hwaddr start_addr = memmap[XIANGSHAN_KMH_DRAM].base; + + /* Initialize SoC */ + object_initialize_child(OBJECT(machine), "soc", &s->soc, + TYPE_XIANGSHAN_KMH_SOC); + qdev_realize(DEVICE(&s->soc), NULL, &error_fatal); + + /* Register RAM */ + memory_region_add_subregion(system_memory, + memmap[XIANGSHAN_KMH_DRAM].base, + machine->ram); + + /* ROM reset vector */ + riscv_setup_rom_reset_vec(machine, &s->soc.cpus, + start_addr, + memmap[XIANGSHAN_KMH_ROM].base, + memmap[XIANGSHAN_KMH_ROM].size, 0, 0); + if (machine->firmware) { + riscv_load_firmware(machine->firmware, &start_addr, NULL); + } + + /* Note: dtb has been integrated into firmware(OpenSBI) when compiling */ +} + +static void xiangshan_kmh_machine_class_init(ObjectClass *klass, const void *data) +{ + MachineClass *mc = MACHINE_CLASS(klass); + static const char *const valid_cpu_types[] = { + TYPE_RISCV_CPU_XIANGSHAN_KMH, + NULL + }; + + mc->desc = "RISC-V Board compatible with the Xiangshan " \ + "Kunminghu FPGA prototype platform"; + mc->init = xiangshan_kmh_machine_init; + mc->max_cpus = XIANGSHAN_KMH_MAX_CPUS; + mc->default_cpu_type = TYPE_RISCV_CPU_XIANGSHAN_KMH; + mc->valid_cpu_types = valid_cpu_types; + mc->default_ram_id = "xiangshan.kunminghu.ram"; +} + +static const TypeInfo xiangshan_kmh_machine_info = { + .name = TYPE_XIANGSHAN_KMH_MACHINE, + .parent = TYPE_MACHINE, + .instance_size = sizeof(XiangshanKmhState), + .class_init = xiangshan_kmh_machine_class_init, +}; + +static void xiangshan_kmh_machine_register_types(void) +{ + type_register_static(&xiangshan_kmh_machine_info); +} +type_init(xiangshan_kmh_machine_register_types) diff --git a/hw/riscv/Kconfig b/hw/riscv/Kconfig index XXXXXXX..XXXXXXX 100644 --- a/hw/riscv/Kconfig +++ b/hw/riscv/Kconfig @@ -XXX,XX +XXX,XX @@ config SPIKE select HTIF select RISCV_ACLINT select SIFIVE_PLIC + +config XIANGSHAN_KUNMINGHU + bool + default y + depends on RISCV64 + select RISCV_ACLINT + select RISCV_APLIC + select RISCV_IMSIC + select SERIAL_MM diff --git a/hw/riscv/meson.build b/hw/riscv/meson.build index XXXXXXX..XXXXXXX 100644 --- a/hw/riscv/meson.build +++ b/hw/riscv/meson.build @@ -XXX,XX +XXX,XX @@ riscv_ss.add(when: 'CONFIG_ACPI', if_true: files('virt-acpi-build.c')) riscv_ss.add(when: 'CONFIG_RISCV_IOMMU', if_true: files( 'riscv-iommu.c', 'riscv-iommu-pci.c', 'riscv-iommu-sys.c', 'riscv-iommu-hpm.c')) riscv_ss.add(when: 'CONFIG_MICROBLAZE_V', if_true: files('microblaze-v-generic.c')) +riscv_ss.add(when: 'CONFIG_XIANGSHAN_KUNMINGHU', if_true: files('xiangshan_kmh.c')) hw_arch += {'riscv': riscv_ss} -- 2.50.0
From: Max Chou <max.chou@sifive.com> According to the V spec, the vector fault-only-first load instructions may change the VL CSR. So the ldff_trans TCG translation function should generate the lookup_and_goto_ptr flow as the vsetvl/vsetvli translation function to make sure the vl_eq_vlmax TB flag is correct. Signed-off-by: Max Chou <max.chou@sifive.com> Reviewed-by: Richard Henderson <richard.henderson@linaro.org> Message-ID: <20250627133013.443997-1-max.chou@sifive.com> Signed-off-by: Alistair Francis <alistair.francis@wdc.com> --- target/riscv/insn_trans/trans_rvv.c.inc | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/target/riscv/insn_trans/trans_rvv.c.inc b/target/riscv/insn_trans/trans_rvv.c.inc index XXXXXXX..XXXXXXX 100644 --- a/target/riscv/insn_trans/trans_rvv.c.inc +++ b/target/riscv/insn_trans/trans_rvv.c.inc @@ -XXX,XX +XXX,XX @@ static bool ldff_trans(uint32_t vd, uint32_t rs1, uint32_t data, fn(dest, mask, base, tcg_env, desc); finalize_rvv_inst(s); + + /* vector unit-stride fault-only-first load may modify vl CSR */ + gen_update_pc(s, s->cur_insn_len); + lookup_and_goto_ptr(s); + s->base.is_jmp = DISAS_NORETURN; + return true; } -- 2.50.0
From: "liu.xuemei1@zte.com.cn" <liu.xuemei1@zte.com.cn> Address an error in migration when aia is configured as 'aplic-imsic' in riscv kvm vm by adding riscv_aplic_state_needed() and riscv_imsic_state_needed() to determine whether the corresponding sates are needed. Previously, the fields in the vmsds of 'riscv_aplic' and 'riscv_imsic' can only be initialized under certain special conditions in commit 95a97b3fd2. However, the corresponding ses of these vmsds are inserted into the savevm_state.handlers unconditionally. This led to migration failure characterized by uninitialized fields when save vm state: qemu-system-riscv64: ../migration/vmstate.c:433: vmstate_save_state_v: Assertion 'first_elem || !n_elems || !size' failed. Fixes: 95a97b3fd2 ("target/riscv: update APLIC and IMSIC to support KVM AIA") Signed-off-by: Xuemei Liu <liu.xuemei1@zte.com.cn> Reviewed-by: Alistair Francis <alistair.francis@wdc.com> Message-ID: <20250616150034827wuHs_ffe3Qm8cqFXT7HeW@zte.com.cn> Signed-off-by: Alistair Francis <alistair.francis@wdc.com> --- hw/intc/riscv_aplic.c | 12 ++++++++++-- hw/intc/riscv_imsic.c | 10 ++++++++-- 2 files changed, 18 insertions(+), 4 deletions(-) diff --git a/hw/intc/riscv_aplic.c b/hw/intc/riscv_aplic.c index XXXXXXX..XXXXXXX 100644 --- a/hw/intc/riscv_aplic.c +++ b/hw/intc/riscv_aplic.c @@ -XXX,XX +XXX,XX @@ static const Property riscv_aplic_properties[] = { DEFINE_PROP_BOOL("mmode", RISCVAPLICState, mmode, 0), }; +static bool riscv_aplic_state_needed(void *opaque) +{ + RISCVAPLICState *aplic = opaque; + + return riscv_use_emulated_aplic(aplic->msimode); +} + static const VMStateDescription vmstate_riscv_aplic = { .name = "riscv_aplic", - .version_id = 2, - .minimum_version_id = 2, + .version_id = 3, + .minimum_version_id = 3, + .needed = riscv_aplic_state_needed, .fields = (const VMStateField[]) { VMSTATE_UINT32(domaincfg, RISCVAPLICState), VMSTATE_UINT32(mmsicfgaddr, RISCVAPLICState), diff --git a/hw/intc/riscv_imsic.c b/hw/intc/riscv_imsic.c index XXXXXXX..XXXXXXX 100644 --- a/hw/intc/riscv_imsic.c +++ b/hw/intc/riscv_imsic.c @@ -XXX,XX +XXX,XX @@ static const Property riscv_imsic_properties[] = { DEFINE_PROP_UINT32("num-irqs", RISCVIMSICState, num_irqs, 0), }; +static bool riscv_imsic_state_needed(void *opaque) +{ + return !kvm_irqchip_in_kernel(); +} + static const VMStateDescription vmstate_riscv_imsic = { .name = "riscv_imsic", - .version_id = 1, - .minimum_version_id = 1, + .version_id = 2, + .minimum_version_id = 2, + .needed = riscv_imsic_state_needed, .fields = (const VMStateField[]) { VMSTATE_VARRAY_UINT32(eidelivery, RISCVIMSICState, num_pages, 0, -- 2.50.0
From: Charalampos Mitrodimas <charmitro@posteo.net> According to the RISC-V Privileged Architecture specification, the low bit of MEPC/SEPC must always be zero. When IALIGN=32, the two low bits must be zero. This commit fixes the behavior of MEPC/SEPC CSR reads and writes, and the implicit reads by MRET/SRET instructions to properly mask the lowest bit(s) based on whether the C extension is enabled: - When C extension is enabled (IALIGN=16): mask bit 0 - When C extension is disabled (IALIGN=32): mask bits [1:0] Previously, when vectored mode bits from STVEC (which sets bit 0 for vectored mode) were written to MEPC, the bits would not be cleared correctly, causing incorrect behavior on MRET. Resolves: https://gitlab.com/qemu-project/qemu/-/issues/2855 Signed-off-by: Charalampos Mitrodimas <charmitro@posteo.net> Reviewed-by: Alistair Francis <alistair.francis@wdc.com> Reviewed-by: Daniel Henrique Barboza <dbarboza@ventanamicro.com> Message-ID: <20250703182157.281320-2-charmitro@posteo.net> Signed-off-by: Alistair Francis <alistair.francis@wdc.com> --- target/riscv/internals.h | 11 +++++++++++ target/riscv/csr.c | 8 ++++---- target/riscv/op_helper.c | 4 ++-- 3 files changed, 17 insertions(+), 6 deletions(-) diff --git a/target/riscv/internals.h b/target/riscv/internals.h index XXXXXXX..XXXXXXX 100644 --- a/target/riscv/internals.h +++ b/target/riscv/internals.h @@ -XXX,XX +XXX,XX @@ static inline float16 check_nanbox_bf16(CPURISCVState *env, uint64_t f) } } +static inline target_ulong get_xepc_mask(CPURISCVState *env) +{ + /* When IALIGN=32, both low bits must be zero. + * When IALIGN=16 (has C extension), only bit 0 must be zero. */ + if (riscv_has_ext(env, RVC)) { + return ~(target_ulong)1; + } else { + return ~(target_ulong)3; + } +} + #ifndef CONFIG_USER_ONLY /* Our implementation of SysemuCPUOps::has_work */ bool riscv_cpu_has_work(CPUState *cs); diff --git a/target/riscv/csr.c b/target/riscv/csr.c index XXXXXXX..XXXXXXX 100644 --- a/target/riscv/csr.c +++ b/target/riscv/csr.c @@ -XXX,XX +XXX,XX @@ static RISCVException write_mscratch(CPURISCVState *env, int csrno, static RISCVException read_mepc(CPURISCVState *env, int csrno, target_ulong *val) { - *val = env->mepc; + *val = env->mepc & get_xepc_mask(env); return RISCV_EXCP_NONE; } static RISCVException write_mepc(CPURISCVState *env, int csrno, target_ulong val, uintptr_t ra) { - env->mepc = val; + env->mepc = val & get_xepc_mask(env); return RISCV_EXCP_NONE; } @@ -XXX,XX +XXX,XX @@ static RISCVException write_sscratch(CPURISCVState *env, int csrno, static RISCVException read_sepc(CPURISCVState *env, int csrno, target_ulong *val) { - *val = env->sepc; + *val = env->sepc & get_xepc_mask(env); return RISCV_EXCP_NONE; } static RISCVException write_sepc(CPURISCVState *env, int csrno, target_ulong val, uintptr_t ra) { - env->sepc = val; + env->sepc = val & get_xepc_mask(env); return RISCV_EXCP_NONE; } diff --git a/target/riscv/op_helper.c b/target/riscv/op_helper.c index XXXXXXX..XXXXXXX 100644 --- a/target/riscv/op_helper.c +++ b/target/riscv/op_helper.c @@ -XXX,XX +XXX,XX @@ target_ulong helper_sret(CPURISCVState *env) riscv_raise_exception(env, RISCV_EXCP_ILLEGAL_INST, GETPC()); } - target_ulong retpc = env->sepc; + target_ulong retpc = env->sepc & get_xepc_mask(env); if (!riscv_cpu_allow_16bit_insn(&env_archcpu(env)->cfg, env->priv_ver, env->misa_ext) && (retpc & 0x3)) { @@ -XXX,XX +XXX,XX @@ static target_ulong ssdbltrp_mxret(CPURISCVState *env, target_ulong mstatus, target_ulong helper_mret(CPURISCVState *env) { - target_ulong retpc = env->mepc; + target_ulong retpc = env->mepc & get_xepc_mask(env); uint64_t mstatus = env->mstatus; target_ulong prev_priv = get_field(mstatus, MSTATUS_MPP); -- 2.50.0
From: Charalampos Mitrodimas <charmitro@posteo.net> Add a regression test to verify that MEPC properly masks the lower bits when an address with mode bits is written to it, as required by the RISC-V Privileged Architecture specification. The test sets STVEC to an address with bit 0 set (vectored mode), triggers an illegal instruction exception, copies STVEC to MEPC in the trap handler, and verifies that MEPC masks bits [1:0] correctly for IALIGN=32. Without the fix, MEPC retains the mode bits (returns non-zero/FAIL). With the fix, MEPC clears bits [1:0] (returns 0/PASS). Signed-off-by: Charalampos Mitrodimas <charmitro@posteo.net> Reviewed-by: Daniel Henrique Barboza <dbarboza@ventanamicro.com> Message-ID: <20250703182157.281320-3-charmitro@posteo.net> Signed-off-by: Alistair Francis <alistair.francis@wdc.com> --- tests/tcg/riscv64/Makefile.softmmu-target | 4 ++ tests/tcg/riscv64/test-mepc-masking.S | 73 +++++++++++++++++++++++ 2 files changed, 77 insertions(+) create mode 100644 tests/tcg/riscv64/test-mepc-masking.S diff --git a/tests/tcg/riscv64/Makefile.softmmu-target b/tests/tcg/riscv64/Makefile.softmmu-target index XXXXXXX..XXXXXXX 100644 --- a/tests/tcg/riscv64/Makefile.softmmu-target +++ b/tests/tcg/riscv64/Makefile.softmmu-target @@ -XXX,XX +XXX,XX @@ EXTRA_RUNS += run-issue1060 run-issue1060: issue1060 $(call run-test, $<, $(QEMU) $(QEMU_OPTS)$<) +EXTRA_RUNS += run-test-mepc-masking +run-test-mepc-masking: test-mepc-masking + $(call run-test, $<, $(QEMU) $(QEMU_OPTS)$<) + # We don't currently support the multiarch system tests undefine MULTIARCH_TESTS diff --git a/tests/tcg/riscv64/test-mepc-masking.S b/tests/tcg/riscv64/test-mepc-masking.S new file mode 100644 index XXXXXXX..XXXXXXX --- /dev/null +++ b/tests/tcg/riscv64/test-mepc-masking.S @@ -XXX,XX +XXX,XX @@ +/* + * Test for MEPC masking bug fix + * + * This test verifies that MEPC properly masks the lower bits according + * to the RISC-V specification when vectored mode bits from STVEC are + * written to MEPC. + */ + + .option norvc + + .text + .global _start +_start: + /* Set up machine trap vector */ + lla t0, machine_trap_handler + csrw mtvec, t0 + + /* Set STVEC with vectored mode (mode bits = 01) */ + li t0, 0x80004001 + csrw stvec, t0 + + /* Clear medeleg to handle exceptions in M-mode */ + csrw medeleg, zero + + /* Trigger illegal instruction exception */ + .word 0xffffffff + +test_completed: + /* Exit with result in a0 */ + /* a0 = 0: success (bits [1:0] were masked) */ + /* a0 != 0: failure (some bits were not masked) */ + j _exit + +machine_trap_handler: + /* Check if illegal instruction (mcause = 2) */ + csrr t0, mcause + li t1, 2 + bne t0, t1, skip_test + + /* Test: Copy STVEC (with mode bits) to MEPC */ + csrr t0, stvec /* t0 = 0x80004001 */ + csrw mepc, t0 /* Write to MEPC */ + csrr t1, mepc /* Read back MEPC */ + + /* Check if bits [1:0] are masked (IALIGN=32 without RVC) */ + andi a0, t1, 3 /* a0 = 0 if both bits masked correctly */ + + /* Set correct return address */ + lla t0, test_completed + csrw mepc, t0 + +skip_test: + mret + +/* Exit with semihosting */ +_exit: + lla a1, semiargs + li t0, 0x20026 /* ADP_Stopped_ApplicationExit */ + sd t0, 0(a1) + sd a0, 8(a1) + li a0, 0x20 /* TARGET_SYS_EXIT_EXTENDED */ + + /* Semihosting call sequence */ + .balign 16 + slli zero, zero, 0x1f + ebreak + srai zero, zero, 0x7 + j . + + .data + .balign 8 +semiargs: + .space 16 -- 2.50.0
From: Vasilis Liaskovitis <vliaskovitis@suse.com> Usage of vsetvli instruction is reserved if VLMAX is changed when vsetvli rs1 and rd arguments are x0. In this case, if the new property is true, only the vill bit will be set. See https://github.com/riscv/riscv-isa-manual/blob/main/src/v-st-ext.adoc#avl-encoding According to the spec, the above use cases are reserved, and "Implementations may set vill in either case." Resolves: https://gitlab.com/qemu-project/qemu/-/issues/2422 Signed-off-by: Vasilis Liaskovitis <vliaskovitis@suse.com> Reviewed-by: Daniel Henrique Barboza <dbarboza@ventanamicro.com> Message-ID: <20250618213542.22873-1-vliaskovitis@suse.com> Signed-off-by: Alistair Francis <alistair.francis@wdc.com> --- target/riscv/helper.h | 2 +- target/riscv/cpu_cfg_fields.h.inc | 1 + target/riscv/cpu.c | 1 + target/riscv/vector_helper.c | 12 +++++++++++- target/riscv/insn_trans/trans_rvv.c.inc | 4 ++-- 5 files changed, 16 insertions(+), 4 deletions(-) diff --git a/target/riscv/helper.h b/target/riscv/helper.h index XXXXXXX..XXXXXXX 100644 --- a/target/riscv/helper.h +++ b/target/riscv/helper.h @@ -XXX,XX +XXX,XX @@ DEF_HELPER_FLAGS_3(hyp_hsv_d, TCG_CALL_NO_WG, void, env, tl, tl) #endif /* Vector functions */ -DEF_HELPER_3(vsetvl, tl, env, tl, tl) +DEF_HELPER_4(vsetvl, tl, env, tl, tl, tl) DEF_HELPER_5(vle8_v, void, ptr, ptr, tl, env, i32) DEF_HELPER_5(vle16_v, void, ptr, ptr, tl, env, i32) DEF_HELPER_5(vle32_v, void, ptr, ptr, tl, env, i32) diff --git a/target/riscv/cpu_cfg_fields.h.inc b/target/riscv/cpu_cfg_fields.h.inc index XXXXXXX..XXXXXXX 100644 --- a/target/riscv/cpu_cfg_fields.h.inc +++ b/target/riscv/cpu_cfg_fields.h.inc @@ -XXX,XX +XXX,XX @@ BOOL_FIELD(ext_supm) BOOL_FIELD(rvv_ta_all_1s) BOOL_FIELD(rvv_ma_all_1s) BOOL_FIELD(rvv_vl_half_avl) +BOOL_FIELD(rvv_vsetvl_x0_vill) /* Named features */ BOOL_FIELD(ext_svade) BOOL_FIELD(ext_zic64b) diff --git a/target/riscv/cpu.c b/target/riscv/cpu.c index XXXXXXX..XXXXXXX 100644 --- a/target/riscv/cpu.c +++ b/target/riscv/cpu.c @@ -XXX,XX +XXX,XX @@ static const Property riscv_cpu_properties[] = { DEFINE_PROP_BOOL("rvv_ta_all_1s", RISCVCPU, cfg.rvv_ta_all_1s, false), DEFINE_PROP_BOOL("rvv_ma_all_1s", RISCVCPU, cfg.rvv_ma_all_1s, false), DEFINE_PROP_BOOL("rvv_vl_half_avl", RISCVCPU, cfg.rvv_vl_half_avl, false), + DEFINE_PROP_BOOL("rvv_vsetvl_x0_vill", RISCVCPU, cfg.rvv_vsetvl_x0_vill, false), /* * write_misa() is marked as experimental for now so mark diff --git a/target/riscv/vector_helper.c b/target/riscv/vector_helper.c index XXXXXXX..XXXXXXX 100644 --- a/target/riscv/vector_helper.c +++ b/target/riscv/vector_helper.c @@ -XXX,XX +XXX,XX @@ #include <math.h> target_ulong HELPER(vsetvl)(CPURISCVState *env, target_ulong s1, - target_ulong s2) + target_ulong s2, target_ulong x0) { int vlmax, vl; RISCVCPU *cpu = env_archcpu(env); @@ -XXX,XX +XXX,XX @@ target_ulong HELPER(vsetvl)(CPURISCVState *env, target_ulong s1, } else { vl = vlmax; } + + if (cpu->cfg.rvv_vsetvl_x0_vill && x0 && (env->vl != vl)) { + /* only set vill bit. */ + env->vill = 1; + env->vtype = 0; + env->vl = 0; + env->vstart = 0; + return 0; + } + env->vl = vl; env->vtype = s2; env->vstart = 0; diff --git a/target/riscv/insn_trans/trans_rvv.c.inc b/target/riscv/insn_trans/trans_rvv.c.inc index XXXXXXX..XXXXXXX 100644 --- a/target/riscv/insn_trans/trans_rvv.c.inc +++ b/target/riscv/insn_trans/trans_rvv.c.inc @@ -XXX,XX +XXX,XX @@ static bool do_vsetvl(DisasContext *s, int rd, int rs1, TCGv s2) s1 = get_gpr(s, rs1, EXT_ZERO); } - gen_helper_vsetvl(dst, tcg_env, s1, s2); + gen_helper_vsetvl(dst, tcg_env, s1, s2, tcg_constant_tl((int) (rd == 0 && rs1 == 0))); gen_set_gpr(s, rd, dst); finalize_rvv_inst(s); @@ -XXX,XX +XXX,XX @@ static bool do_vsetivli(DisasContext *s, int rd, TCGv s1, TCGv s2) dst = dest_gpr(s, rd); - gen_helper_vsetvl(dst, tcg_env, s1, s2); + gen_helper_vsetvl(dst, tcg_env, s1, s2, tcg_constant_tl(0)); gen_set_gpr(s, rd, dst); finalize_rvv_inst(s); gen_update_pc(s, s->cur_insn_len); -- 2.50.0
From: Alexandre Ghiti <alexghiti@rivosinc.com> The Svrsw60t59b extension allows to free the PTE reserved bits 60 and 59 for software to use. Reviewed-by: Deepak Gupta <debug@rivosinc.com> Signed-off-by: Alexandre Ghiti <alexghiti@rivosinc.com> Reviewed-by: Daniel Henrique Barboza <dbarboza@ventanamicro.com> Reviewed-by: Nutty Liu<liujingqi@lanxincomputing.com> Message-ID: <20250702-dev-alex-svrsw60b59b_v2-v2-1-504ddf0f8530@rivosinc.com> Signed-off-by: Alistair Francis <alistair.francis@wdc.com> --- hw/riscv/riscv-iommu-bits.h | 1 + target/riscv/cpu_bits.h | 3 ++- target/riscv/cpu_cfg_fields.h.inc | 1 + hw/riscv/riscv-iommu.c | 3 ++- target/riscv/cpu.c | 2 ++ target/riscv/cpu_helper.c | 3 ++- target/riscv/tcg/tcg-cpu.c | 8 ++++++++ 7 files changed, 18 insertions(+), 3 deletions(-) diff --git a/hw/riscv/riscv-iommu-bits.h b/hw/riscv/riscv-iommu-bits.h index XXXXXXX..XXXXXXX 100644 --- a/hw/riscv/riscv-iommu-bits.h +++ b/hw/riscv/riscv-iommu-bits.h @@ -XXX,XX +XXX,XX @@ struct riscv_iommu_pq_record { #define RISCV_IOMMU_CAP_SV39 BIT_ULL(9) #define RISCV_IOMMU_CAP_SV48 BIT_ULL(10) #define RISCV_IOMMU_CAP_SV57 BIT_ULL(11) +#define RISCV_IOMMU_CAP_SVRSW60T59B BIT_ULL(14) #define RISCV_IOMMU_CAP_SV32X4 BIT_ULL(16) #define RISCV_IOMMU_CAP_SV39X4 BIT_ULL(17) #define RISCV_IOMMU_CAP_SV48X4 BIT_ULL(18) diff --git a/target/riscv/cpu_bits.h b/target/riscv/cpu_bits.h index XXXXXXX..XXXXXXX 100644 --- a/target/riscv/cpu_bits.h +++ b/target/riscv/cpu_bits.h @@ -XXX,XX +XXX,XX @@ typedef enum { #define PTE_SOFT 0x300 /* Reserved for Software */ #define PTE_PBMT 0x6000000000000000ULL /* Page-based memory types */ #define PTE_N 0x8000000000000000ULL /* NAPOT translation */ -#define PTE_RESERVED 0x1FC0000000000000ULL /* Reserved bits */ +#define PTE_RESERVED(svrsw60t59b) \ + (svrsw60t59b ? 0x07C0000000000000ULL : 0x1FC0000000000000ULL) /* Reserved bits */ #define PTE_ATTR (PTE_N | PTE_PBMT) /* All attributes bits */ /* Page table PPN shift amount */ diff --git a/target/riscv/cpu_cfg_fields.h.inc b/target/riscv/cpu_cfg_fields.h.inc index XXXXXXX..XXXXXXX 100644 --- a/target/riscv/cpu_cfg_fields.h.inc +++ b/target/riscv/cpu_cfg_fields.h.inc @@ -XXX,XX +XXX,XX @@ BOOL_FIELD(ext_svadu) BOOL_FIELD(ext_svinval) BOOL_FIELD(ext_svnapot) BOOL_FIELD(ext_svpbmt) +BOOL_FIELD(ext_svrsw60t59b) BOOL_FIELD(ext_svvptc) BOOL_FIELD(ext_svukte) BOOL_FIELD(ext_zdinx) diff --git a/hw/riscv/riscv-iommu.c b/hw/riscv/riscv-iommu.c index XXXXXXX..XXXXXXX 100644 --- a/hw/riscv/riscv-iommu.c +++ b/hw/riscv/riscv-iommu.c @@ -XXX,XX +XXX,XX @@ static void riscv_iommu_realize(DeviceState *dev, Error **errp) } if (s->enable_g_stage) { s->cap |= RISCV_IOMMU_CAP_SV32X4 | RISCV_IOMMU_CAP_SV39X4 | - RISCV_IOMMU_CAP_SV48X4 | RISCV_IOMMU_CAP_SV57X4; + RISCV_IOMMU_CAP_SV48X4 | RISCV_IOMMU_CAP_SV57X4 | + RISCV_IOMMU_CAP_SVRSW60T59B; } if (s->hpm_cntrs > 0) { diff --git a/target/riscv/cpu.c b/target/riscv/cpu.c index XXXXXXX..XXXXXXX 100644 --- a/target/riscv/cpu.c +++ b/target/riscv/cpu.c @@ -XXX,XX +XXX,XX @@ const RISCVIsaExtData isa_edata_arr[] = { ISA_EXT_DATA_ENTRY(svinval, PRIV_VERSION_1_12_0, ext_svinval), ISA_EXT_DATA_ENTRY(svnapot, PRIV_VERSION_1_12_0, ext_svnapot), ISA_EXT_DATA_ENTRY(svpbmt, PRIV_VERSION_1_12_0, ext_svpbmt), + ISA_EXT_DATA_ENTRY(svrsw60t59b, PRIV_VERSION_1_13_0, ext_svrsw60t59b), ISA_EXT_DATA_ENTRY(svukte, PRIV_VERSION_1_13_0, ext_svukte), ISA_EXT_DATA_ENTRY(svvptc, PRIV_VERSION_1_13_0, ext_svvptc), ISA_EXT_DATA_ENTRY(xtheadba, PRIV_VERSION_1_11_0, ext_xtheadba), @@ -XXX,XX +XXX,XX @@ const RISCVCPUMultiExtConfig riscv_cpu_extensions[] = { MULTI_EXT_CFG_BOOL("svinval", ext_svinval, false), MULTI_EXT_CFG_BOOL("svnapot", ext_svnapot, false), MULTI_EXT_CFG_BOOL("svpbmt", ext_svpbmt, false), + MULTI_EXT_CFG_BOOL("svrsw60t59b", ext_svrsw60t59b, false), MULTI_EXT_CFG_BOOL("svvptc", ext_svvptc, true), MULTI_EXT_CFG_BOOL("zicntr", ext_zicntr, true), diff --git a/target/riscv/cpu_helper.c b/target/riscv/cpu_helper.c index XXXXXXX..XXXXXXX 100644 --- a/target/riscv/cpu_helper.c +++ b/target/riscv/cpu_helper.c @@ -XXX,XX +XXX,XX @@ static int get_physical_address(CPURISCVState *env, hwaddr *physical, bool svade = riscv_cpu_cfg(env)->ext_svade; bool svadu = riscv_cpu_cfg(env)->ext_svadu; bool adue = svadu ? env->menvcfg & MENVCFG_ADUE : !svade; + bool svrsw60t59b = riscv_cpu_cfg(env)->ext_svrsw60t59b; if (first_stage && two_stage && env->virt_enabled) { pbmte = pbmte && (env->henvcfg & HENVCFG_PBMTE); @@ -XXX,XX +XXX,XX @@ static int get_physical_address(CPURISCVState *env, hwaddr *physical, if (riscv_cpu_sxl(env) == MXL_RV32) { ppn = pte >> PTE_PPN_SHIFT; } else { - if (pte & PTE_RESERVED) { + if (pte & PTE_RESERVED(svrsw60t59b)) { qemu_log_mask(LOG_GUEST_ERROR, "%s: reserved bits set in PTE: " "addr: 0x%" HWADDR_PRIx " pte: 0x" TARGET_FMT_lx "\n", __func__, pte_addr, pte); diff --git a/target/riscv/tcg/tcg-cpu.c b/target/riscv/tcg/tcg-cpu.c index XXXXXXX..XXXXXXX 100644 --- a/target/riscv/tcg/tcg-cpu.c +++ b/target/riscv/tcg/tcg-cpu.c @@ -XXX,XX +XXX,XX @@ void riscv_cpu_validate_set_extensions(RISCVCPU *cpu, Error **errp) cpu->cfg.ext_ssctr = false; } + if (cpu->cfg.ext_svrsw60t59b && + (!cpu->cfg.mmu || mcc->def->misa_mxl_max == MXL_RV32)) { + error_setg(errp, "svrsw60t59b is not supported on RV32 and MMU-less platforms"); + return; + } + /* * Disable isa extensions based on priv spec after we * validated and set everything we need. @@ -XXX,XX +XXX,XX @@ static void riscv_init_max_cpu_extensions(Object *obj) if (env->misa_mxl != MXL_RV32) { isa_ext_update_enabled(cpu, CPU_CFG_OFFSET(ext_zcf), false); + } else { + isa_ext_update_enabled(cpu, CPU_CFG_OFFSET(ext_svrsw60t59b), false); } /* -- 2.50.0
From: Alistair Francis <alistair.francis@wdc.com> The following changes since commit 3b5fe75e2c30e249acabe29924385782014c7632: Merge tag 'pull-monitor-2026-01-07' of https://repo.or.cz/qemu/armbru into staging (2026-01-08 17:45:15 +1100) are available in the Git repository at: https://github.com/alistair23/qemu.git tags/pull-riscv-to-apply-20260109 for you to fetch changes up to e71111e26bdf5e98243d6a896c9e595e205dd9bb: test/functional: Add test for boston-aia board (2026-01-09 15:14:58 +1000) ---------------------------------------------------------------- First RISC-V PR for 11. * Remove unused import statement from sifive_u test * Free allocated memory in core/loader * Add all available CSRs to 'info registers' * Add 'riscv-aia' accel prop info to documentation * Fix IOMMU MemoryRegion owner * Make riscv cpu.h target partially independent * Expand AIA target[i] source handling and refactor related code * Don't look up DDT cache in Off and Bare modes * Add Zilsd and Zclsd extension support * Add RISCV ZALASR extension * Add support for MIPS P8700 CPU ---------------------------------------------------------------- Akihiko Odaki (1): hw/riscv/riscv-iommu: Fix MemoryRegion owner Alistair Francis (4): hw/core/loader: Fixup whitespace for get_image_size() hw/core/loader: Free the image file descriptor on error hw/core/loader: Free the allocated string from size_to_str() target/riscv: Remove upper_half from riscv_pmu_ctr_get_fixed_counters_val Anton Johansson (7): target/riscv: Fix size of trivial CPUArchState fields target/riscv: Fix size of mhartid target/riscv: Bugfix make bit 62 read-only 0 for sireg* cfg CSR read target/riscv: Combine mhpmevent and mhpmeventh target/riscv: Combine mcyclecfg and mcyclecfgh target/riscv: Combine minstretcfg and minstretcfgh target/riscv: Combine mhpmcounter and mhpmcounterh Daniel Henrique Barboza (4): target/riscv/cpu: add riscv_dump_csr() helper target/riscv/cpu: print all FPU CSRs in riscv_cpu_dump_state() target/riscv: print all available CSRs in riscv_cpu_dump_state() docs/specs/riscv-aia.rst: add 'riscv-aia' accel prop info Djordje Todorovic (12): target/riscv: Add cpu_set_exception_base target/riscv: Add MIPS P8700 CPU target/riscv: Add MIPS P8700 CSRs target/riscv: Add mips.ccmov instruction target/riscv: Add mips.pref instruction target/riscv: Add Xmipslsp instructions hw/misc: Add RISC-V CMGCR device implementation hw/misc: Add RISC-V CPC device implementation hw/riscv: Add support for RISCV CPS hw/riscv: Add support for MIPS Boston-aia board mode riscv/boston-aia: Add an e1000e NIC in slot 0 func 1 test/functional: Add test for boston-aia board Frank Chang (1): hw/riscv: riscv-iommu: Don't look up DDT cache in Off and Bare modes Nikita Novikov (2): hw/intc/riscv_aplic: Expand inactive source handling for AIA target[i] hw/intc/riscv_aplic: Factor out source_active() and remove duplicate checks Roan Richmond (1): Add RISCV ZALASR extension Thomas Huth (1): tests/functional/riscv64/test_sifive_u: Remove unused import statement lxx (1): target/riscv: Add Zilsd and Zclsd extension support docs/specs/riscv-aia.rst | 43 ++- docs/system/riscv/mips.rst | 20 ++ docs/system/target-riscv.rst | 1 + configs/devices/riscv64-softmmu/default.mak | 1 + include/hw/misc/riscv_cmgcr.h | 48 +++ include/hw/misc/riscv_cpc.h | 64 ++++ include/hw/riscv/cps.h | 66 ++++ target/riscv/cpu-qom.h | 1 + target/riscv/cpu.h | 115 +++---- target/riscv/cpu_cfg.h | 5 + target/riscv/cpu_vendorid.h | 1 + target/riscv/cpu_cfg_fields.h.inc | 6 + target/riscv/insn16.decode | 8 + target/riscv/insn32.decode | 22 +- target/riscv/xmips.decode | 35 ++ hw/core/loader.c | 15 +- hw/intc/riscv_aplic.c | 66 ++-- hw/misc/riscv_cmgcr.c | 243 ++++++++++++++ hw/misc/riscv_cpc.c | 265 +++++++++++++++ hw/riscv/boston-aia.c | 476 +++++++++++++++++++++++++++ hw/riscv/cps.c | 196 +++++++++++ hw/riscv/riscv-iommu.c | 15 +- target/riscv/cpu.c | 157 +++++---- target/riscv/cpu_helper.c | 2 +- target/riscv/csr.c | 239 +++++++------- target/riscv/machine.c | 99 +++--- target/riscv/mips_csr.c | 217 ++++++++++++ target/riscv/pmu.c | 150 ++------- target/riscv/tcg/tcg-cpu.c | 35 +- target/riscv/translate.c | 5 + target/riscv/insn_trans/trans_rvzalasr.c.inc | 113 +++++++ target/riscv/insn_trans/trans_xmips.c.inc | 136 ++++++++ target/riscv/insn_trans/trans_zilsd.c.inc | 105 ++++++ hw/misc/Kconfig | 17 + hw/misc/meson.build | 3 + hw/riscv/Kconfig | 6 + hw/riscv/meson.build | 3 + target/riscv/meson.build | 2 + tests/functional/riscv64/meson.build | 2 + tests/functional/riscv64/test_boston.py | 123 +++++++ tests/functional/riscv64/test_sifive_u.py | 1 - 41 files changed, 2657 insertions(+), 470 deletions(-) create mode 100644 docs/system/riscv/mips.rst create mode 100644 include/hw/misc/riscv_cmgcr.h create mode 100644 include/hw/misc/riscv_cpc.h create mode 100644 include/hw/riscv/cps.h create mode 100644 target/riscv/xmips.decode create mode 100644 hw/misc/riscv_cmgcr.c create mode 100644 hw/misc/riscv_cpc.c create mode 100644 hw/riscv/boston-aia.c create mode 100644 hw/riscv/cps.c create mode 100644 target/riscv/mips_csr.c create mode 100644 target/riscv/insn_trans/trans_rvzalasr.c.inc create mode 100644 target/riscv/insn_trans/trans_xmips.c.inc create mode 100644 target/riscv/insn_trans/trans_zilsd.c.inc create mode 100755 tests/functional/riscv64/test_boston.py
From: Thomas Huth <thuth@redhat.com> skipIfMissingCommands is not used here, remove the import to silence a pylint warning for this file. Signed-off-by: Thomas Huth <thuth@redhat.com> Reviewed-by: Alistair Francis <alistair.francis@wdc.com> Reviewed-by: Daniel Henrique Barboza <dbarboza@ventanamicro.com> Reviewed-by: Nutty Liu <nutty.liu@hotmail.com> Reviewed-by: Philippe Mathieu-Daudé <philmd@linaro.org> Message-ID: <20251027112803.54564-1-thuth@redhat.com> Signed-off-by: Alistair Francis <alistair.francis@wdc.com> --- tests/functional/riscv64/test_sifive_u.py | 1 - 1 file changed, 1 deletion(-) diff --git a/tests/functional/riscv64/test_sifive_u.py b/tests/functional/riscv64/test_sifive_u.py index XXXXXXX..XXXXXXX 100755 --- a/tests/functional/riscv64/test_sifive_u.py +++ b/tests/functional/riscv64/test_sifive_u.py @@ -XXX,XX +XXX,XX @@ import os from qemu_test import Asset, LinuxKernelTest -from qemu_test import skipIfMissingCommands class SifiveU(LinuxKernelTest): -- 2.52.0
From: Alistair Francis <alistair.francis@wdc.com> Signed-off-by: Alistair Francis <alistair.francis@wdc.com> Reviewed-by:Vishal Chourasia <vishalc@linux.ibm.com> Reviewed-by: Philippe Mathieu-Daudé <philmd@linaro.org> Message-ID: <20251030015306.2279148-1-alistair.francis@wdc.com> Signed-off-by: Alistair Francis <alistair.francis@wdc.com> --- hw/core/loader.c | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/hw/core/loader.c b/hw/core/loader.c index XXXXXXX..XXXXXXX 100644 --- a/hw/core/loader.c +++ b/hw/core/loader.c @@ -XXX,XX +XXX,XX @@ int64_t get_image_size(const char *filename, Error **errp) { int fd; int64_t size; + fd = qemu_open(filename, O_RDONLY | O_BINARY, errp); - if (fd < 0) + + if (fd < 0) { return -1; + } + size = lseek(fd, 0, SEEK_END); + if (size < 0) { error_setg_errno(errp, errno, "lseek failure: %s", filename); return -1; } + close(fd); return size; } -- 2.52.0
From: Alistair Francis <alistair.francis@wdc.com> Coverity: CID 1642764 Fixes: f62226f7dc4 ("hw/core/loader: improve error handling in image loading functions") Signed-off-by: Alistair Francis <alistair.francis@wdc.com> Reviewed-by: Philippe Mathieu-Daudé <philmd@linaro.org> Reviewed-by: Vishal Chourasia <vishalc@linux.ibm.com> Message-ID: <20251030015306.2279148-2-alistair.francis@wdc.com> Signed-off-by: Alistair Francis <alistair.francis@wdc.com> --- hw/core/loader.c | 1 + 1 file changed, 1 insertion(+) diff --git a/hw/core/loader.c b/hw/core/loader.c index XXXXXXX..XXXXXXX 100644 --- a/hw/core/loader.c +++ b/hw/core/loader.c @@ -XXX,XX +XXX,XX @@ int64_t get_image_size(const char *filename, Error **errp) if (size < 0) { error_setg_errno(errp, errno, "lseek failure: %s", filename); + close(fd); return -1; } -- 2.52.0
From: Alistair Francis <alistair.francis@wdc.com> The string needs be be freed with g_free() according to the functions documentation. Coverity: CID 1642762 Fixes: f62226f7dc44 ("hw/core/loader: improve error handling in image loading functions") Signed-off-by: Alistair Francis <alistair.francis@wdc.com> Reviewed-by: Philippe Mathieu-Daudé <philmd@linaro.org> Message-ID: <20251030015306.2279148-3-alistair.francis@wdc.com> Signed-off-by: Alistair Francis <alistair.francis@wdc.com> --- hw/core/loader.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/hw/core/loader.c b/hw/core/loader.c index XXXXXXX..XXXXXXX 100644 --- a/hw/core/loader.c +++ b/hw/core/loader.c @@ -XXX,XX +XXX,XX @@ ssize_t load_image_targphys_as(const char *filename, } if (size > max_sz) { + char *size_str = size_to_str(max_sz); + error_setg(errp, "%s exceeds maximum image size (%s)", - filename, size_to_str(max_sz)); + filename, size_str); + + g_free(size_str); return -1; } -- 2.52.0
From: Daniel Henrique Barboza <dbarboza@ventanamicro.com> riscv_cpu_dump_state() is using the same pattern to print a CSR given its number. Add a helper to avoid code repetition. While we're at it fix the identation of the 'flags & CPU_DUMP_VPU' block. Signed-off-by: Daniel Henrique Barboza <dbarboza@ventanamicro.com> Reviewed-by: Alistair Francis <alistair.francis@wdc.com> Message-ID: <20250623172119.997166-2-dbarboza@ventanamicro.com> Signed-off-by: Alistair Francis <alistair.francis@wdc.com> --- target/riscv/cpu.c | 54 +++++++++++++++++++--------------------------- 1 file changed, 22 insertions(+), 32 deletions(-) diff --git a/target/riscv/cpu.c b/target/riscv/cpu.c index XXXXXXX..XXXXXXX 100644 --- a/target/riscv/cpu.c +++ b/target/riscv/cpu.c @@ -XXX,XX +XXX,XX @@ char *riscv_cpu_get_name(RISCVCPU *cpu) return cpu_model_from_type(typename); } +static void riscv_dump_csr(CPURISCVState *env, int csrno, FILE *f) +{ + target_ulong val = 0; + RISCVException res = riscv_csrrw_debug(env, csrno, &val, 0, 0); + + /* + * Rely on the smode, hmode, etc, predicates within csr.c + * to do the filtering of the registers that are present. + */ + if (res == RISCV_EXCP_NONE) { + qemu_fprintf(f, " %-8s " TARGET_FMT_lx "\n", + csr_ops[csrno].name, val); + } +} + static void riscv_cpu_dump_state(CPUState *cs, FILE *f, int flags) { RISCVCPU *cpu = RISCV_CPU(cs); @@ -XXX,XX +XXX,XX @@ static void riscv_cpu_dump_state(CPUState *cs, FILE *f, int flags) }; for (i = 0; i < ARRAY_SIZE(dump_csrs); ++i) { - int csrno = dump_csrs[i]; - target_ulong val = 0; - RISCVException res = riscv_csrrw_debug(env, csrno, &val, 0, 0); - - /* - * Rely on the smode, hmode, etc, predicates within csr.c - * to do the filtering of the registers that are present. - */ - if (res == RISCV_EXCP_NONE) { - qemu_fprintf(f, " %-8s " TARGET_FMT_lx "\n", - csr_ops[csrno].name, val); - } + riscv_dump_csr(env, dump_csrs[i], f); } } #endif @@ -XXX,XX +XXX,XX @@ static void riscv_cpu_dump_state(CPUState *cs, FILE *f, int flags) } } if (flags & CPU_DUMP_FPU) { - target_ulong val = 0; - RISCVException res = riscv_csrrw_debug(env, CSR_FCSR, &val, 0, 0); - if (res == RISCV_EXCP_NONE) { - qemu_fprintf(f, " %-8s " TARGET_FMT_lx "\n", - csr_ops[CSR_FCSR].name, val); - } + riscv_dump_csr(env, CSR_FCSR, f); + for (i = 0; i < 32; i++) { qemu_fprintf(f, " %-8s %016" PRIx64, riscv_fpr_regnames[i], env->fpr[i]); @@ -XXX,XX +XXX,XX @@ static void riscv_cpu_dump_state(CPUState *cs, FILE *f, int flags) CSR_VL, CSR_VTYPE, CSR_VLENB, - }; - for (i = 0; i < ARRAY_SIZE(dump_rvv_csrs); ++i) { - int csrno = dump_rvv_csrs[i]; - target_ulong val = 0; - RISCVException res = riscv_csrrw_debug(env, csrno, &val, 0, 0); + }; + uint16_t vlenb = cpu->cfg.vlenb; - /* - * Rely on the smode, hmode, etc, predicates within csr.c - * to do the filtering of the registers that are present. - */ - if (res == RISCV_EXCP_NONE) { - qemu_fprintf(f, " %-8s " TARGET_FMT_lx "\n", - csr_ops[csrno].name, val); - } + for (i = 0; i < ARRAY_SIZE(dump_rvv_csrs); ++i) { + riscv_dump_csr(env, dump_rvv_csrs[i], f); } - uint16_t vlenb = cpu->cfg.vlenb; for (i = 0; i < 32; i++) { qemu_fprintf(f, " %-8s ", riscv_rvv_regnames[i]); -- 2.52.0
From: Daniel Henrique Barboza <dbarboza@ventanamicro.com> We're missing fflags and frm. Signed-off-by: Daniel Henrique Barboza <dbarboza@ventanamicro.com> Reviewed-by: Alistair Francis <alistair.francis@wdc.com> Message-ID: <20250623172119.997166-3-dbarboza@ventanamicro.com> Signed-off-by: Alistair Francis <alistair.francis@wdc.com> --- target/riscv/cpu.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/target/riscv/cpu.c b/target/riscv/cpu.c index XXXXXXX..XXXXXXX 100644 --- a/target/riscv/cpu.c +++ b/target/riscv/cpu.c @@ -XXX,XX +XXX,XX @@ static void riscv_cpu_dump_state(CPUState *cs, FILE *f, int flags) } } if (flags & CPU_DUMP_FPU) { + riscv_dump_csr(env, CSR_FFLAGS, f); + riscv_dump_csr(env, CSR_FRM, f); riscv_dump_csr(env, CSR_FCSR, f); for (i = 0; i < 32; i++) { -- 2.52.0
From: Daniel Henrique Barboza <dbarboza@ventanamicro.com> At this moment we're printing a small selection of CSRs. There's no particular reason to not print all of them. We're ignoring the note about CSR_SSTATUS being ommited because it can be read via CSR_MSTATUS. There's a huge list of CSRs that would fall in this category and it would be an extra burden to manage them, not mentioning having to document "we're not listing X because it's the same value as Y" to users. Remove 'dump_csrs' and use the existing 'csr_ops' array to print all available CSRs. Create two helpers in csr.c to identify FPU and VPU CSRs and skip them - they'll be printed in the FPU/VPU blocks later. Signed-off-by: Daniel Henrique Barboza <dbarboza@ventanamicro.com> Reviewed-by: Alistair Francis <alistair.francis@wdc.com> Message-ID: <20250623172119.997166-4-dbarboza@ventanamicro.com> Signed-off-by: Alistair Francis <alistair.francis@wdc.com> --- target/riscv/cpu.h | 2 ++ target/riscv/cpu.c | 55 ++++++++++++++++------------------------------ target/riscv/csr.c | 18 +++++++++++++++ 3 files changed, 39 insertions(+), 36 deletions(-) diff --git a/target/riscv/cpu.h b/target/riscv/cpu.h index XXXXXXX..XXXXXXX 100644 --- a/target/riscv/cpu.h +++ b/target/riscv/cpu.h @@ -XXX,XX +XXX,XX @@ bool riscv_cpu_accelerator_compatible(RISCVCPU *cpu); /* CSR function table */ extern riscv_csr_operations csr_ops[CSR_TABLE_SIZE]; +bool riscv_csr_is_fpu(int csrno); +bool riscv_csr_is_vpu(int csrno); extern const bool valid_vm_1_10_32[], valid_vm_1_10_64[]; diff --git a/target/riscv/cpu.c b/target/riscv/cpu.c index XXXXXXX..XXXXXXX 100644 --- a/target/riscv/cpu.c +++ b/target/riscv/cpu.c @@ -XXX,XX +XXX,XX @@ static void riscv_cpu_dump_state(CPUState *cs, FILE *f, int flags) #endif qemu_fprintf(f, " %s " TARGET_FMT_lx "\n", "pc ", env->pc); #ifndef CONFIG_USER_ONLY - { - static const int dump_csrs[] = { - CSR_MHARTID, - CSR_MSTATUS, - CSR_MSTATUSH, - /* - * CSR_SSTATUS is intentionally omitted here as its value - * can be figured out by looking at CSR_MSTATUS - */ - CSR_HSTATUS, - CSR_VSSTATUS, - CSR_MIP, - CSR_MIE, - CSR_MIDELEG, - CSR_HIDELEG, - CSR_MEDELEG, - CSR_HEDELEG, - CSR_MTVEC, - CSR_STVEC, - CSR_VSTVEC, - CSR_MEPC, - CSR_SEPC, - CSR_VSEPC, - CSR_MCAUSE, - CSR_SCAUSE, - CSR_VSCAUSE, - CSR_MTVAL, - CSR_STVAL, - CSR_HTVAL, - CSR_MTVAL2, - CSR_MSCRATCH, - CSR_SSCRATCH, - CSR_SATP, - }; + for (i = 0; i < ARRAY_SIZE(csr_ops); i++) { + int csrno = i; - for (i = 0; i < ARRAY_SIZE(dump_csrs); ++i) { - riscv_dump_csr(env, dump_csrs[i], f); + /* + * Early skip when possible since we're going + * through a lot of NULL entries. + */ + if (csr_ops[csrno].predicate == NULL) { + continue; } + + /* + * FPU and VPU CSRs will be printed in the + * CPU_DUMP_FPU/CPU_DUMP_VPU blocks later. + */ + if (riscv_csr_is_fpu(csrno) || + riscv_csr_is_vpu(csrno)) { + continue; + } + + riscv_dump_csr(env, csrno, f); } #endif diff --git a/target/riscv/csr.c b/target/riscv/csr.c index XXXXXXX..XXXXXXX 100644 --- a/target/riscv/csr.c +++ b/target/riscv/csr.c @@ -XXX,XX +XXX,XX @@ static RISCVException write_jvt(CPURISCVState *env, int csrno, return RISCV_EXCP_NONE; } +bool riscv_csr_is_fpu(int csrno) +{ + if (!csr_ops[csrno].predicate) { + return false; + } + + return csr_ops[csrno].predicate == fs; +} + +bool riscv_csr_is_vpu(int csrno) +{ + if (!csr_ops[csrno].predicate) { + return false; + } + + return csr_ops[csrno].predicate == vs; +} + /* * Control and Status Register function table * riscv_csr_operations::predicate() must be provided for an implemented CSR -- 2.52.0
From: Daniel Henrique Barboza <dbarboza@ventanamicro.com> Add a small section talking about the 'riscv-aia' KVM setting we implement and how it affects the provisioning of the IMSIC s-mode in-kernel controller. While we're at it, fix the formatting of the AIA bullet list. Signed-off-by: Daniel Henrique Barboza <dbarboza@ventanamicro.com> Acked-by: Alistair Francis <alistair.francis@wdc.com> Message-ID: <20251028084622.1177574-1-dbarboza@ventanamicro.com> Signed-off-by: Alistair Francis <alistair.francis@wdc.com> --- docs/specs/riscv-aia.rst | 43 ++++++++++++++++++++++++++++++++++++---- 1 file changed, 39 insertions(+), 4 deletions(-) diff --git a/docs/specs/riscv-aia.rst b/docs/specs/riscv-aia.rst index XXXXXXX..XXXXXXX 100644 --- a/docs/specs/riscv-aia.rst +++ b/docs/specs/riscv-aia.rst @@ -XXX,XX +XXX,XX @@ RISC-V machine for TCG and KVM accelerators. The support consists of two main modes: -- "aia=aplic": adds one or more APLIC (Advanced Platform Level Interrupt Controller) - devices -- "aia=aplic-imsic": adds one or more APLIC device and an IMSIC (Incoming MSI - Controller) device for each CPU +- *aia=aplic*: adds one or more APLIC (Advanced Platform Level Interrupt Controller) devices +- *aia=aplic-imsic*: adds one or more APLIC device and an IMSIC (Incoming MSI Controller) device for each CPU From an user standpoint, these modes will behave the same regardless of the accelerator used. From a developer standpoint the accelerator settings will change what it being @@ -XXX,XX +XXX,XX @@ we will emulate in userspace: - n/a - emul - in-kernel + + +KVM accel option 'riscv-aia' +---------------------------- + +The KVM accelerator property 'riscv-aia' interacts with the "aia=aplic-imsic" +to determine how the host KVM module will provide the in-kernel IMSIC s-mode +controller. The 'kernel-irqchip' setting has no impact in 'riscv-aia' given +that any available 'kernel-irqchip' setting will always have an in-kernel +IMSIC s-mode. 'riscv-aia' has no impact in APLIC m-mode/s-mode and +IMSIC m-mode settings. + + +.. list-table:: How 'riscv-aia' changes in-kernel IMSIC s-mode provisioning + :widths: 25 25 25 25 + :header-rows: 1 + + * - Accel + - KVM riscv-aia + - AIA type + - IMSIC s-mode + * - kvm + - none + - aplic-imsic + - in-kernel, default to 'auto' + * - kvm + - auto + - aplic-imsic + - in-kernel, hwaccel if available, emul otherwise + * - kvm + - hwaccel + - aplic-imsic + - in-kernel, use IMSIC controller from guest hardware + * - kvm + - emul + - aplic-imsic + - in-kernel, IMSIC is emulated by KVM -- 2.52.0
From: Akihiko Odaki <odaki@rsg.ci.i.u-tokyo.ac.jp> as points to the MemoryRegion itself. s is the device that owns the MemoryRegion. Signed-off-by: Akihiko Odaki <odaki@rsg.ci.i.u-tokyo.ac.jp> Reviewed-by: Daniel Henrique Barboza <dbarboza@ventanamicro.com> Reviewed-by: Nutty Liu <nutty.liu@hotmail.com> Reviewed-by: Philippe Mathieu-Daudé <philmd@linaro.org> Message-ID: <20251027-iommu-v1-1-0fc52a02a273@rsg.ci.i.u-tokyo.ac.jp> Signed-off-by: Alistair Francis <alistair.francis@wdc.com> --- hw/riscv/riscv-iommu.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/hw/riscv/riscv-iommu.c b/hw/riscv/riscv-iommu.c index XXXXXXX..XXXXXXX 100644 --- a/hw/riscv/riscv-iommu.c +++ b/hw/riscv/riscv-iommu.c @@ -XXX,XX +XXX,XX @@ static AddressSpace *riscv_iommu_space(RISCVIOMMUState *s, uint32_t devid) /* IOVA address space, untranslated addresses */ memory_region_init_iommu(&as->iova_mr, sizeof(as->iova_mr), TYPE_RISCV_IOMMU_MEMORY_REGION, - OBJECT(as), "riscv_iommu", UINT64_MAX); + OBJECT(s), "riscv_iommu", UINT64_MAX); address_space_init(&as->iova_as, MEMORY_REGION(&as->iova_mr), name); QLIST_INSERT_HEAD(&s->spaces, as, list); -- 2.52.0
From: Anton Johansson <anjo@rev.ng> This commits groups together all CPUArchState fields whose behaviour can be retained by simply changing the size of the field. Note, senvcfg is defined to be SXLEN bits wide, but is widened to 64 bits to match henvcfg and menvcfg. Next, [m|h]edeleg are changed to 64 bits as defined privileged specification, and hvictl is fixed to 32 bits which holds all relevant values, see HVICTL_VALID_MASK. The remaining fields touched in the commit are widened from [H|S|M]XLEN to 64-bit. Note, the cpu/hyper, cpu/envcfg, cpu/jvt, and cpu VMSTATE versions are bumped, breaking migration from older versions. References to the privileged/unprivileged RISCV specification refer to version 20250508. Signed-off-by: Anton Johansson <anjo@rev.ng> Reviewed-by: Pierrick Bouvier <pierrick.bouvier@linaro.org> Reviewed-by: Alistair Francis <alistair.francis@wdc.com> Message-ID: <20251027181831.27016-2-anjo@rev.ng> Signed-off-by: Alistair Francis <alistair.francis@wdc.com> Message-ID: <20251103033713.904455-2-alistair.francis@wdc.com> Signed-off-by: Alistair Francis <alistair.francis@wdc.com> --- target/riscv/cpu.h | 78 +++++++++++++++++++-------------------- target/riscv/machine.c | 84 +++++++++++++++++++++--------------------- 2 files changed, 81 insertions(+), 81 deletions(-) diff --git a/target/riscv/cpu.h b/target/riscv/cpu.h index XXXXXXX..XXXXXXX 100644 --- a/target/riscv/cpu.h +++ b/target/riscv/cpu.h @@ -XXX,XX +XXX,XX @@ struct CPUArchState { /* 128-bit helpers upper part return value */ target_ulong retxh; - target_ulong jvt; + uint64_t jvt; /* elp state for zicfilp extension */ bool elp; @@ -XXX,XX +XXX,XX @@ struct CPUArchState { target_ulong priv; /* CSRs for execution environment configuration */ uint64_t menvcfg; - target_ulong senvcfg; + uint64_t senvcfg; #ifndef CONFIG_USER_ONLY /* This contains QEMU specific information about the virt state. */ @@ -XXX,XX +XXX,XX @@ struct CPUArchState { */ uint64_t vsie; - target_ulong satp; /* since: priv-1.10.0 */ - target_ulong stval; - target_ulong medeleg; + uint64_t satp; /* since: priv-1.10.0 */ + uint64_t stval; + uint64_t medeleg; - target_ulong stvec; - target_ulong sepc; - target_ulong scause; + uint64_t stvec; + uint64_t sepc; + uint64_t scause; - target_ulong mtvec; - target_ulong mepc; - target_ulong mcause; - target_ulong mtval; /* since: priv-1.10.0 */ + uint64_t mtvec; + uint64_t mepc; + uint64_t mcause; + uint64_t mtval; /* since: priv-1.10.0 */ uint64_t mctrctl; uint32_t sctrdepth; @@ -XXX,XX +XXX,XX @@ struct CPUArchState { uint64_t mvip; /* Hypervisor CSRs */ - target_ulong hstatus; - target_ulong hedeleg; + uint64_t hstatus; + uint64_t hedeleg; uint64_t hideleg; uint32_t hcounteren; - target_ulong htval; - target_ulong htinst; - target_ulong hgatp; + uint64_t htval; + uint64_t htinst; + uint64_t hgatp; target_ulong hgeie; target_ulong hgeip; uint64_t htimedelta; @@ -XXX,XX +XXX,XX @@ struct CPUArchState { uint64_t hvip; /* Hypervisor controlled virtual interrupt priorities */ - target_ulong hvictl; + uint32_t hvictl; uint8_t hviprio[64]; /* Upper 64-bits of 128-bit CSRs */ @@ -XXX,XX +XXX,XX @@ struct CPUArchState { * For RV64 this is a 64-bit vsstatus. */ uint64_t vsstatus; - target_ulong vstvec; - target_ulong vsscratch; - target_ulong vsepc; - target_ulong vscause; - target_ulong vstval; - target_ulong vsatp; + uint64_t vstvec; + uint64_t vsscratch; + uint64_t vsepc; + uint64_t vscause; + uint64_t vstval; + uint64_t vsatp; /* AIA VS-mode CSRs */ target_ulong vsiselect; - target_ulong mtval2; - target_ulong mtinst; + uint64_t mtval2; + uint64_t mtinst; /* HS Backup CSRs */ - target_ulong stvec_hs; - target_ulong sscratch_hs; - target_ulong sepc_hs; - target_ulong scause_hs; - target_ulong stval_hs; - target_ulong satp_hs; + uint64_t stvec_hs; + uint64_t sscratch_hs; + uint64_t sepc_hs; + uint64_t scause_hs; + uint64_t stval_hs; + uint64_t satp_hs; uint64_t mstatus_hs; /* @@ -XXX,XX +XXX,XX @@ struct CPUArchState { PMUFixedCtrState pmu_fixed_ctrs[2]; - target_ulong sscratch; - target_ulong mscratch; + uint64_t sscratch; + uint64_t mscratch; /* Sstc CSRs */ uint64_t stimecmp; @@ -XXX,XX +XXX,XX @@ struct CPUArchState { #endif /* CONFIG_KVM */ /* RNMI */ - target_ulong mnscratch; - target_ulong mnepc; - target_ulong mncause; /* mncause without bit XLEN-1 set to 1 */ - target_ulong mnstatus; - target_ulong rnmip; + uint64_t mnscratch; + uint64_t mnepc; + uint64_t mncause; /* mncause without bit XLEN-1 set to 1 */ + uint64_t mnstatus; + uint64_t rnmip; uint64_t rnmi_irqvec; uint64_t rnmi_excpvec; }; diff --git a/target/riscv/machine.c b/target/riscv/machine.c index XXXXXXX..XXXXXXX 100644 --- a/target/riscv/machine.c +++ b/target/riscv/machine.c @@ -XXX,XX +XXX,XX @@ static bool hyper_needed(void *opaque) static const VMStateDescription vmstate_hyper = { .name = "cpu/hyper", - .version_id = 4, - .minimum_version_id = 4, + .version_id = 5, + .minimum_version_id = 5, .needed = hyper_needed, .fields = (const VMStateField[]) { - VMSTATE_UINTTL(env.hstatus, RISCVCPU), - VMSTATE_UINTTL(env.hedeleg, RISCVCPU), + VMSTATE_UINT64(env.hstatus, RISCVCPU), + VMSTATE_UINT64(env.hedeleg, RISCVCPU), VMSTATE_UINT64(env.hideleg, RISCVCPU), VMSTATE_UINT32(env.hcounteren, RISCVCPU), - VMSTATE_UINTTL(env.htval, RISCVCPU), - VMSTATE_UINTTL(env.htinst, RISCVCPU), - VMSTATE_UINTTL(env.hgatp, RISCVCPU), + VMSTATE_UINT64(env.htval, RISCVCPU), + VMSTATE_UINT64(env.htinst, RISCVCPU), + VMSTATE_UINT64(env.hgatp, RISCVCPU), VMSTATE_UINTTL(env.hgeie, RISCVCPU), VMSTATE_UINTTL(env.hgeip, RISCVCPU), VMSTATE_UINT64(env.hvien, RISCVCPU), @@ -XXX,XX +XXX,XX @@ static const VMStateDescription vmstate_hyper = { VMSTATE_UINT64(env.htimedelta, RISCVCPU), VMSTATE_UINT64(env.vstimecmp, RISCVCPU), - VMSTATE_UINTTL(env.hvictl, RISCVCPU), + VMSTATE_UINT32(env.hvictl, RISCVCPU), VMSTATE_UINT8_ARRAY(env.hviprio, RISCVCPU, 64), VMSTATE_UINT64(env.vsstatus, RISCVCPU), - VMSTATE_UINTTL(env.vstvec, RISCVCPU), - VMSTATE_UINTTL(env.vsscratch, RISCVCPU), - VMSTATE_UINTTL(env.vsepc, RISCVCPU), - VMSTATE_UINTTL(env.vscause, RISCVCPU), - VMSTATE_UINTTL(env.vstval, RISCVCPU), - VMSTATE_UINTTL(env.vsatp, RISCVCPU), + VMSTATE_UINT64(env.vstvec, RISCVCPU), + VMSTATE_UINT64(env.vsscratch, RISCVCPU), + VMSTATE_UINT64(env.vsepc, RISCVCPU), + VMSTATE_UINT64(env.vscause, RISCVCPU), + VMSTATE_UINT64(env.vstval, RISCVCPU), + VMSTATE_UINT64(env.vsatp, RISCVCPU), VMSTATE_UINTTL(env.vsiselect, RISCVCPU), VMSTATE_UINT64(env.vsie, RISCVCPU), - VMSTATE_UINTTL(env.mtval2, RISCVCPU), - VMSTATE_UINTTL(env.mtinst, RISCVCPU), + VMSTATE_UINT64(env.mtval2, RISCVCPU), + VMSTATE_UINT64(env.mtinst, RISCVCPU), - VMSTATE_UINTTL(env.stvec_hs, RISCVCPU), - VMSTATE_UINTTL(env.sscratch_hs, RISCVCPU), - VMSTATE_UINTTL(env.sepc_hs, RISCVCPU), - VMSTATE_UINTTL(env.scause_hs, RISCVCPU), - VMSTATE_UINTTL(env.stval_hs, RISCVCPU), - VMSTATE_UINTTL(env.satp_hs, RISCVCPU), + VMSTATE_UINT64(env.stvec_hs, RISCVCPU), + VMSTATE_UINT64(env.sscratch_hs, RISCVCPU), + VMSTATE_UINT64(env.sepc_hs, RISCVCPU), + VMSTATE_UINT64(env.scause_hs, RISCVCPU), + VMSTATE_UINT64(env.stval_hs, RISCVCPU), + VMSTATE_UINT64(env.satp_hs, RISCVCPU), VMSTATE_UINT64(env.mstatus_hs, RISCVCPU), VMSTATE_END_OF_LIST() @@ -XXX,XX +XXX,XX @@ static bool envcfg_needed(void *opaque) static const VMStateDescription vmstate_envcfg = { .name = "cpu/envcfg", - .version_id = 1, - .minimum_version_id = 1, + .version_id = 2, + .minimum_version_id = 2, .needed = envcfg_needed, .fields = (const VMStateField[]) { VMSTATE_UINT64(env.menvcfg, RISCVCPU), - VMSTATE_UINTTL(env.senvcfg, RISCVCPU), + VMSTATE_UINT64(env.senvcfg, RISCVCPU), VMSTATE_UINT64(env.henvcfg, RISCVCPU), VMSTATE_END_OF_LIST() } @@ -XXX,XX +XXX,XX @@ static bool jvt_needed(void *opaque) static const VMStateDescription vmstate_jvt = { .name = "cpu/jvt", - .version_id = 1, - .minimum_version_id = 1, + .version_id = 2, + .minimum_version_id = 2, .needed = jvt_needed, .fields = (const VMStateField[]) { - VMSTATE_UINTTL(env.jvt, RISCVCPU), + VMSTATE_UINT64(env.jvt, RISCVCPU), VMSTATE_END_OF_LIST() } }; @@ -XXX,XX +XXX,XX @@ static const VMStateDescription vmstate_sstc = { const VMStateDescription vmstate_riscv_cpu = { .name = "cpu", - .version_id = 10, - .minimum_version_id = 10, + .version_id = 11, + .minimum_version_id = 11, .post_load = riscv_cpu_post_load, .fields = (const VMStateField[]) { VMSTATE_UINTTL_ARRAY(env.gpr, RISCVCPU, 32), @@ -XXX,XX +XXX,XX @@ const VMStateDescription vmstate_riscv_cpu = { VMSTATE_UINT64(env.mvip, RISCVCPU), VMSTATE_UINT64(env.sie, RISCVCPU), VMSTATE_UINT64(env.mideleg, RISCVCPU), - VMSTATE_UINTTL(env.satp, RISCVCPU), - VMSTATE_UINTTL(env.stval, RISCVCPU), - VMSTATE_UINTTL(env.medeleg, RISCVCPU), - VMSTATE_UINTTL(env.stvec, RISCVCPU), - VMSTATE_UINTTL(env.sepc, RISCVCPU), - VMSTATE_UINTTL(env.scause, RISCVCPU), - VMSTATE_UINTTL(env.mtvec, RISCVCPU), - VMSTATE_UINTTL(env.mepc, RISCVCPU), - VMSTATE_UINTTL(env.mcause, RISCVCPU), - VMSTATE_UINTTL(env.mtval, RISCVCPU), + VMSTATE_UINT64(env.satp, RISCVCPU), + VMSTATE_UINT64(env.stval, RISCVCPU), + VMSTATE_UINT64(env.medeleg, RISCVCPU), + VMSTATE_UINT64(env.stvec, RISCVCPU), + VMSTATE_UINT64(env.sepc, RISCVCPU), + VMSTATE_UINT64(env.scause, RISCVCPU), + VMSTATE_UINT64(env.mtvec, RISCVCPU), + VMSTATE_UINT64(env.mepc, RISCVCPU), + VMSTATE_UINT64(env.mcause, RISCVCPU), + VMSTATE_UINT64(env.mtval, RISCVCPU), VMSTATE_UINTTL(env.miselect, RISCVCPU), VMSTATE_UINTTL(env.siselect, RISCVCPU), VMSTATE_UINT32(env.scounteren, RISCVCPU), @@ -XXX,XX +XXX,XX @@ const VMStateDescription vmstate_riscv_cpu = { vmstate_pmu_ctr_state, PMUCTRState), VMSTATE_UINTTL_ARRAY(env.mhpmevent_val, RISCVCPU, RV_MAX_MHPMEVENTS), VMSTATE_UINTTL_ARRAY(env.mhpmeventh_val, RISCVCPU, RV_MAX_MHPMEVENTS), - VMSTATE_UINTTL(env.sscratch, RISCVCPU), - VMSTATE_UINTTL(env.mscratch, RISCVCPU), + VMSTATE_UINT64(env.sscratch, RISCVCPU), + VMSTATE_UINT64(env.mscratch, RISCVCPU), VMSTATE_UINT64(env.stimecmp, RISCVCPU), VMSTATE_END_OF_LIST() -- 2.52.0
From: Anton Johansson <anjo@rev.ng> and update formatting in log. Signed-off-by: Anton Johansson <anjo@rev.ng> Reviewed-by: Pierrick Bouvier <pierrick.bouvier@linaro.org> Reviewed-by: Alistair Francis <alistair.francis@wdc.com> Message-ID: <20251027181831.27016-3-anjo@rev.ng> Signed-off-by: Alistair Francis <alistair.francis@wdc.com> Message-ID: <20251103033713.904455-3-alistair.francis@wdc.com> Signed-off-by: Alistair Francis <alistair.francis@wdc.com> --- target/riscv/cpu.h | 2 +- target/riscv/cpu_helper.c | 2 +- target/riscv/machine.c | 2 +- target/riscv/tcg/tcg-cpu.c | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/target/riscv/cpu.h b/target/riscv/cpu.h index XXXXXXX..XXXXXXX 100644 --- a/target/riscv/cpu.h +++ b/target/riscv/cpu.h @@ -XXX,XX +XXX,XX @@ struct CPUArchState { target_ulong geilen; uint64_t resetvec; - target_ulong mhartid; + uint64_t mhartid; /* * For RV32 this is 32-bit mstatus and 32-bit mstatush. * For RV64 this is a 64-bit mstatus. diff --git a/target/riscv/cpu_helper.c b/target/riscv/cpu_helper.c index XXXXXXX..XXXXXXX 100644 --- a/target/riscv/cpu_helper.c +++ b/target/riscv/cpu_helper.c @@ -XXX,XX +XXX,XX @@ void riscv_cpu_do_interrupt(CPUState *cs) riscv_cpu_get_trap_name(cause, async)); qemu_log_mask(CPU_LOG_INT, - "%s: hart:"TARGET_FMT_ld", async:%d, cause:"TARGET_FMT_lx", " + "%s: hart:%"PRIu64", async:%d, cause:"TARGET_FMT_lx", " "epc:0x"TARGET_FMT_lx", tval:0x"TARGET_FMT_lx", desc=%s\n", __func__, env->mhartid, async, cause, env->pc, tval, riscv_cpu_get_trap_name(cause, async)); diff --git a/target/riscv/machine.c b/target/riscv/machine.c index XXXXXXX..XXXXXXX 100644 --- a/target/riscv/machine.c +++ b/target/riscv/machine.c @@ -XXX,XX +XXX,XX @@ const VMStateDescription vmstate_riscv_cpu = { VMSTATE_UINTTL(env.priv, RISCVCPU), VMSTATE_BOOL(env.virt_enabled, RISCVCPU), VMSTATE_UINT64(env.resetvec, RISCVCPU), - VMSTATE_UINTTL(env.mhartid, RISCVCPU), + VMSTATE_UINT64(env.mhartid, RISCVCPU), VMSTATE_UINT64(env.mstatus, RISCVCPU), VMSTATE_UINT64(env.mip, RISCVCPU), VMSTATE_UINT64(env.miclaim, RISCVCPU), diff --git a/target/riscv/tcg/tcg-cpu.c b/target/riscv/tcg/tcg-cpu.c index XXXXXXX..XXXXXXX 100644 --- a/target/riscv/tcg/tcg-cpu.c +++ b/target/riscv/tcg/tcg-cpu.c @@ -XXX,XX +XXX,XX @@ static void riscv_cpu_disable_priv_spec_isa_exts(RISCVCPU *cpu) continue; } #ifndef CONFIG_USER_ONLY - warn_report("disabling %s extension for hart 0x" TARGET_FMT_lx + warn_report("disabling %s extension for hart 0x%" PRIx64 " because privilege spec version does not match", edata->name, env->mhartid); #else -- 2.52.0
From: Anton Johansson <anjo@rev.ng> According to version 20250508 of the privileged specification, a read of cyclecfg or instretcfg through sireg* should make the MINH bit read-only 0, currently bit 30 is zeroed. Signed-off-by: Anton Johansson <anjo@rev.ng> Reviewed-by: Alistair Francis <alistair.francis@wdc.com> Reviewed-by: Pierrick Bouvier <pierrick.bouvier@linaro.org> Message-ID: <20251027181831.27016-5-anjo@rev.ng> Signed-off-by: Alistair Francis <alistair.francis@wdc.com> Message-ID: <20251103033713.904455-4-alistair.francis@wdc.com> Signed-off-by: Alistair Francis <alistair.francis@wdc.com> --- target/riscv/csr.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/target/riscv/csr.c b/target/riscv/csr.c index XXXXXXX..XXXXXXX 100644 --- a/target/riscv/csr.c +++ b/target/riscv/csr.c @@ -XXX,XX +XXX,XX @@ static int rmw_cd_ctr_cfg(CPURISCVState *env, int cfg_index, target_ulong *val, wr_mask &= ~MCYCLECFG_BIT_MINH; env->mcyclecfg = (new_val & wr_mask) | (env->mcyclecfg & ~wr_mask); } else { - *val = env->mcyclecfg &= ~MHPMEVENTH_BIT_MINH; + *val = env->mcyclecfg &= ~MHPMEVENT_BIT_MINH; } break; case 2: /* INSTRETCFG */ @@ -XXX,XX +XXX,XX @@ static int rmw_cd_ctr_cfg(CPURISCVState *env, int cfg_index, target_ulong *val, env->minstretcfg = (new_val & wr_mask) | (env->minstretcfg & ~wr_mask); } else { - *val = env->minstretcfg &= ~MHPMEVENTH_BIT_MINH; + *val = env->minstretcfg &= ~MHPMEVENT_BIT_MINH; } break; default: -- 2.52.0
From: Anton Johansson <anjo@rev.ng> According to version 20250508 of the privileged specification, mhpmeventn is 64 bits in size and mhpmeventnh is only ever used when XLEN == 32 and accesses the top 32 bits of the 64-bit mhpmeventn registers. Combine the two arrays of target_ulong mhpmeventh[] and mhpmevent[] to a single array of uint64_t. This also allows for some minor code simplification where branches handling either mhpmeventh[] or mhpmevent[] could be combined. Signed-off-by: Anton Johansson <anjo@rev.ng> Reviewed-by: Alistair Francis <alistair.francis@wdc.com> Reviewed-by: Pierrick Bouvier <pierrick.bouvier@linaro.org> Message-ID: <20251027181831.27016-6-anjo@rev.ng> Signed-off-by: Alistair Francis <alistair.francis@wdc.com> Message-ID: <20251103033713.904455-5-alistair.francis@wdc.com> Signed-off-by: Alistair Francis <alistair.francis@wdc.com> --- target/riscv/cpu.h | 10 +++---- target/riscv/csr.c | 67 +++++++++++++++--------------------------- target/riscv/machine.c | 3 +- target/riscv/pmu.c | 53 ++++++++------------------------- 4 files changed, 42 insertions(+), 91 deletions(-) diff --git a/target/riscv/cpu.h b/target/riscv/cpu.h index XXXXXXX..XXXXXXX 100644 --- a/target/riscv/cpu.h +++ b/target/riscv/cpu.h @@ -XXX,XX +XXX,XX @@ struct CPUArchState { /* PMU counter state */ PMUCTRState pmu_ctrs[RV_MAX_MHPMCOUNTERS]; - /* PMU event selector configured values. First three are unused */ - target_ulong mhpmevent_val[RV_MAX_MHPMEVENTS]; - - /* PMU event selector configured values for RV32 */ - target_ulong mhpmeventh_val[RV_MAX_MHPMEVENTS]; + /* + * PMU event selector configured values. First three are unused. + * For RV32 top 32 bits are accessed via the mhpmeventh CSR. + */ + uint64_t mhpmevent_val[RV_MAX_MHPMEVENTS]; PMUFixedCtrState pmu_fixed_ctrs[2]; diff --git a/target/riscv/csr.c b/target/riscv/csr.c index XXXXXXX..XXXXXXX 100644 --- a/target/riscv/csr.c +++ b/target/riscv/csr.c @@ -XXX,XX +XXX,XX @@ static RISCVException read_mhpmevent(CPURISCVState *env, int csrno, target_ulong *val) { int evt_index = csrno - CSR_MCOUNTINHIBIT; + bool rv32 = riscv_cpu_mxl(env) == MXL_RV32; - *val = env->mhpmevent_val[evt_index]; + *val = extract64(env->mhpmevent_val[evt_index], 0, rv32 ? 32 : 64); return RISCV_EXCP_NONE; } @@ -XXX,XX +XXX,XX @@ static RISCVException write_mhpmevent(CPURISCVState *env, int csrno, target_ulong val, uintptr_t ra) { int evt_index = csrno - CSR_MCOUNTINHIBIT; - uint64_t mhpmevt_val = val; + uint64_t mhpmevt_val; uint64_t inh_avail_mask; if (riscv_cpu_mxl(env) == MXL_RV32) { - env->mhpmevent_val[evt_index] = val; - mhpmevt_val = mhpmevt_val | - ((uint64_t)env->mhpmeventh_val[evt_index] << 32); + mhpmevt_val = deposit64(env->mhpmevent_val[evt_index], 0, 32, val); } else { inh_avail_mask = ~MHPMEVENT_FILTER_MASK | MHPMEVENT_BIT_MINH; inh_avail_mask |= riscv_has_ext(env, RVU) ? MHPMEVENT_BIT_UINH : 0; @@ -XXX,XX +XXX,XX @@ static RISCVException write_mhpmevent(CPURISCVState *env, int csrno, inh_avail_mask |= (riscv_has_ext(env, RVH) && riscv_has_ext(env, RVS)) ? MHPMEVENT_BIT_VSINH : 0; mhpmevt_val = val & inh_avail_mask; - env->mhpmevent_val[evt_index] = mhpmevt_val; } + env->mhpmevent_val[evt_index] = mhpmevt_val; riscv_pmu_update_event_map(env, mhpmevt_val, evt_index); return RISCV_EXCP_NONE; @@ -XXX,XX +XXX,XX @@ static RISCVException read_mhpmeventh(CPURISCVState *env, int csrno, { int evt_index = csrno - CSR_MHPMEVENT3H + 3; - *val = env->mhpmeventh_val[evt_index]; + *val = extract64(env->mhpmevent_val[evt_index], 32, 32); return RISCV_EXCP_NONE; } @@ -XXX,XX +XXX,XX @@ static RISCVException write_mhpmeventh(CPURISCVState *env, int csrno, target_ulong val, uintptr_t ra) { int evt_index = csrno - CSR_MHPMEVENT3H + 3; - uint64_t mhpmevth_val; - uint64_t mhpmevt_val = env->mhpmevent_val[evt_index]; target_ulong inh_avail_mask = (target_ulong)(~MHPMEVENTH_FILTER_MASK | MHPMEVENTH_BIT_MINH); @@ -XXX,XX +XXX,XX @@ static RISCVException write_mhpmeventh(CPURISCVState *env, int csrno, inh_avail_mask |= (riscv_has_ext(env, RVH) && riscv_has_ext(env, RVS)) ? MHPMEVENTH_BIT_VSINH : 0; - mhpmevth_val = val & inh_avail_mask; - mhpmevt_val = mhpmevt_val | (mhpmevth_val << 32); - env->mhpmeventh_val[evt_index] = mhpmevth_val; + env->mhpmevent_val[evt_index] = deposit64(env->mhpmevent_val[evt_index], + 32, 32, val & inh_avail_mask); - riscv_pmu_update_event_map(env, mhpmevt_val, evt_index); + riscv_pmu_update_event_map(env, env->mhpmevent_val[evt_index], evt_index); return RISCV_EXCP_NONE; } @@ -XXX,XX +XXX,XX @@ static target_ulong riscv_pmu_ctr_get_fixed_counters_val(CPURISCVState *env, cfg_val = upper_half ? ((uint64_t)env->minstretcfgh << 32) : env->minstretcfg; } else { - cfg_val = upper_half ? - ((uint64_t)env->mhpmeventh_val[counter_idx] << 32) : - env->mhpmevent_val[counter_idx]; + cfg_val = env->mhpmevent_val[counter_idx]; cfg_val &= MHPMEVENT_FILTER_MASK; } @@ -XXX,XX +XXX,XX @@ static int rmw_cd_mhpmcounterh(CPURISCVState *env, int ctr_idx, static int rmw_cd_mhpmevent(CPURISCVState *env, int evt_index, target_ulong *val, target_ulong new_val, - target_ulong wr_mask) + uint64_t wr_mask) { - uint64_t mhpmevt_val = new_val; + uint64_t mhpmevt_val = env->mhpmevent_val[evt_index]; if (wr_mask != 0 && wr_mask != -1) { return -EINVAL; } if (!wr_mask && val) { - *val = env->mhpmevent_val[evt_index]; + *val = mhpmevt_val; if (riscv_cpu_cfg(env)->ext_sscofpmf) { *val &= ~MHPMEVENT_BIT_MINH; } } else if (wr_mask) { wr_mask &= ~MHPMEVENT_BIT_MINH; - mhpmevt_val = (new_val & wr_mask) | - (env->mhpmevent_val[evt_index] & ~wr_mask); - if (riscv_cpu_mxl(env) == MXL_RV32) { - mhpmevt_val = mhpmevt_val | - ((uint64_t)env->mhpmeventh_val[evt_index] << 32); - } + /* wr_mask is 64-bit so upper 32 bits of mhpmevt_val are retained */ + mhpmevt_val = (new_val & wr_mask) | (mhpmevt_val & ~wr_mask); env->mhpmevent_val[evt_index] = mhpmevt_val; riscv_pmu_update_event_map(env, mhpmevt_val, evt_index); } else { @@ -XXX,XX +XXX,XX @@ static int rmw_cd_mhpmeventh(CPURISCVState *env, int evt_index, target_ulong *val, target_ulong new_val, target_ulong wr_mask) { - uint64_t mhpmevth_val; uint64_t mhpmevt_val = env->mhpmevent_val[evt_index]; + uint32_t mhpmevth_val = extract64(mhpmevt_val, 32, 32); if (wr_mask != 0 && wr_mask != -1) { return -EINVAL; } if (!wr_mask && val) { - *val = env->mhpmeventh_val[evt_index]; + *val = mhpmevth_val; if (riscv_cpu_cfg(env)->ext_sscofpmf) { *val &= ~MHPMEVENTH_BIT_MINH; } } else if (wr_mask) { wr_mask &= ~MHPMEVENTH_BIT_MINH; - env->mhpmeventh_val[evt_index] = - (new_val & wr_mask) | (env->mhpmeventh_val[evt_index] & ~wr_mask); - mhpmevth_val = env->mhpmeventh_val[evt_index]; - mhpmevt_val = mhpmevt_val | (mhpmevth_val << 32); + mhpmevth_val = (new_val & wr_mask) | (mhpmevth_val & ~wr_mask); + mhpmevt_val = deposit64(mhpmevt_val, 32, 32, mhpmevth_val); + env->mhpmevent_val[evt_index] = mhpmevt_val; riscv_pmu_update_event_map(env, mhpmevt_val, evt_index); } else { return -EINVAL; @@ -XXX,XX +XXX,XX @@ static RISCVException read_scountovf(CPURISCVState *env, int csrno, int mhpmevt_start = CSR_MHPMEVENT3 - CSR_MCOUNTINHIBIT; int i; *val = 0; - target_ulong *mhpm_evt_val; - uint64_t of_bit_mask; /* Virtualize scountovf for counter delegation */ if (riscv_cpu_cfg(env)->ext_sscofpmf && @@ -XXX,XX +XXX,XX @@ static RISCVException read_scountovf(CPURISCVState *env, int csrno, return RISCV_EXCP_VIRT_INSTRUCTION_FAULT; } - if (riscv_cpu_mxl(env) == MXL_RV32) { - mhpm_evt_val = env->mhpmeventh_val; - of_bit_mask = MHPMEVENTH_BIT_OF; - } else { - mhpm_evt_val = env->mhpmevent_val; - of_bit_mask = MHPMEVENT_BIT_OF; - } - for (i = mhpmevt_start; i < RV_MAX_MHPMEVENTS; i++) { if ((get_field(env->mcounteren, BIT(i))) && - (mhpm_evt_val[i] & of_bit_mask)) { - *val |= BIT(i); - } + (env->mhpmevent_val[i] & MHPMEVENT_BIT_OF)) { + *val |= BIT(i); + } } return RISCV_EXCP_NONE; diff --git a/target/riscv/machine.c b/target/riscv/machine.c index XXXXXXX..XXXXXXX 100644 --- a/target/riscv/machine.c +++ b/target/riscv/machine.c @@ -XXX,XX +XXX,XX @@ const VMStateDescription vmstate_riscv_cpu = { VMSTATE_UINT32(env.mcountinhibit, RISCVCPU), VMSTATE_STRUCT_ARRAY(env.pmu_ctrs, RISCVCPU, RV_MAX_MHPMCOUNTERS, 0, vmstate_pmu_ctr_state, PMUCTRState), - VMSTATE_UINTTL_ARRAY(env.mhpmevent_val, RISCVCPU, RV_MAX_MHPMEVENTS), - VMSTATE_UINTTL_ARRAY(env.mhpmeventh_val, RISCVCPU, RV_MAX_MHPMEVENTS), + VMSTATE_UINT64_ARRAY(env.mhpmevent_val, RISCVCPU, RV_MAX_MHPMEVENTS), VMSTATE_UINT64(env.sscratch, RISCVCPU), VMSTATE_UINT64(env.mscratch, RISCVCPU), VMSTATE_UINT64(env.stimecmp, RISCVCPU), diff --git a/target/riscv/pmu.c b/target/riscv/pmu.c index XXXXXXX..XXXXXXX 100644 --- a/target/riscv/pmu.c +++ b/target/riscv/pmu.c @@ -XXX,XX +XXX,XX @@ static int riscv_pmu_incr_ctr_rv32(RISCVCPU *cpu, uint32_t ctr_idx) /* Privilege mode filtering */ if ((env->priv == PRV_M && - (env->mhpmeventh_val[ctr_idx] & MHPMEVENTH_BIT_MINH)) || + (env->mhpmevent_val[ctr_idx] & MHPMEVENT_BIT_MINH)) || (env->priv == PRV_S && virt_on && - (env->mhpmeventh_val[ctr_idx] & MHPMEVENTH_BIT_VSINH)) || + (env->mhpmevent_val[ctr_idx] & MHPMEVENT_BIT_VSINH)) || (env->priv == PRV_U && virt_on && - (env->mhpmeventh_val[ctr_idx] & MHPMEVENTH_BIT_VUINH)) || + (env->mhpmevent_val[ctr_idx] & MHPMEVENT_BIT_VUINH)) || (env->priv == PRV_S && !virt_on && - (env->mhpmeventh_val[ctr_idx] & MHPMEVENTH_BIT_SINH)) || + (env->mhpmevent_val[ctr_idx] & MHPMEVENT_BIT_SINH)) || (env->priv == PRV_U && !virt_on && - (env->mhpmeventh_val[ctr_idx] & MHPMEVENTH_BIT_UINH))) { + (env->mhpmevent_val[ctr_idx] & MHPMEVENT_BIT_UINH))) { return 0; } @@ -XXX,XX +XXX,XX @@ static int riscv_pmu_incr_ctr_rv32(RISCVCPU *cpu, uint32_t ctr_idx) counter->mhpmcounter_val = 0; counter->mhpmcounterh_val = 0; /* Generate interrupt only if OF bit is clear */ - if (!(env->mhpmeventh_val[ctr_idx] & MHPMEVENTH_BIT_OF)) { - env->mhpmeventh_val[ctr_idx] |= MHPMEVENTH_BIT_OF; + if (!(env->mhpmevent_val[ctr_idx] & MHPMEVENT_BIT_OF)) { + env->mhpmevent_val[ctr_idx] |= MHPMEVENT_BIT_OF; riscv_cpu_update_mip(env, MIP_LCOFIP, BOOL_TO_MASK(1)); } } else { @@ -XXX,XX +XXX,XX @@ int riscv_pmu_update_event_map(CPURISCVState *env, uint64_t value, return 0; } -static bool pmu_hpmevent_is_of_set(CPURISCVState *env, uint32_t ctr_idx) -{ - target_ulong mhpmevent_val; - uint64_t of_bit_mask; - - if (riscv_cpu_mxl(env) == MXL_RV32) { - mhpmevent_val = env->mhpmeventh_val[ctr_idx]; - of_bit_mask = MHPMEVENTH_BIT_OF; - } else { - mhpmevent_val = env->mhpmevent_val[ctr_idx]; - of_bit_mask = MHPMEVENT_BIT_OF; - } - - return get_field(mhpmevent_val, of_bit_mask); -} - static bool pmu_hpmevent_set_of_if_clear(CPURISCVState *env, uint32_t ctr_idx) { - target_ulong *mhpmevent_val; - uint64_t of_bit_mask; - - if (riscv_cpu_mxl(env) == MXL_RV32) { - mhpmevent_val = &env->mhpmeventh_val[ctr_idx]; - of_bit_mask = MHPMEVENTH_BIT_OF; - } else { - mhpmevent_val = &env->mhpmevent_val[ctr_idx]; - of_bit_mask = MHPMEVENT_BIT_OF; - } - - if (!get_field(*mhpmevent_val, of_bit_mask)) { - *mhpmevent_val |= of_bit_mask; + if (!get_field(env->mhpmevent_val[ctr_idx], MHPMEVENT_BIT_OF)) { + env->mhpmevent_val[ctr_idx] |= MHPMEVENT_BIT_OF; return true; + } else { + return false; } - - return false; } static void pmu_timer_trigger_irq(RISCVCPU *cpu, @@ -XXX,XX +XXX,XX @@ static void pmu_timer_trigger_irq(RISCVCPU *cpu, } /* Generate interrupt only if OF bit is clear */ - if (pmu_hpmevent_is_of_set(env, ctr_idx)) { + if (get_field(env->mhpmevent_val[ctr_idx], MHPMEVENT_BIT_OF)) { return; } @@ -XXX,XX +XXX,XX @@ int riscv_pmu_setup_timer(CPURISCVState *env, uint64_t value, uint32_t ctr_idx) /* No need to setup a timer if LCOFI is disabled when OF is set */ if (!riscv_pmu_counter_valid(cpu, ctr_idx) || !cpu->cfg.ext_sscofpmf || - pmu_hpmevent_is_of_set(env, ctr_idx)) { + get_field(env->mhpmevent_val[ctr_idx], MHPMEVENT_BIT_OF)) { return -1; } -- 2.52.0
From: Anton Johansson <anjo@rev.ng> According to version 20250508 of the privileged specification, mcyclecfg is a 64-bit register and mcyclecfgh refers to the top 32 bits of this register when XLEN == 32. No real advantage is gained by keeping them separate, and combining them allows for slight simplification. Signed-off-by: Anton Johansson <anjo@rev.ng> Reviewed-by: Alistair Francis <alistair.francis@wdc.com> Reviewed-by: Pierrick Bouvier <pierrick.bouvier@linaro.org> Message-ID: <20251027181831.27016-7-anjo@rev.ng> Signed-off-by: Alistair Francis <alistair.francis@wdc.com> Message-ID: <20251103033713.904455-6-alistair.francis@wdc.com> Signed-off-by: Alistair Francis <alistair.francis@wdc.com> --- target/riscv/cpu.h | 3 +-- target/riscv/csr.c | 28 +++++++++++++++++----------- 2 files changed, 18 insertions(+), 13 deletions(-) diff --git a/target/riscv/cpu.h b/target/riscv/cpu.h index XXXXXXX..XXXXXXX 100644 --- a/target/riscv/cpu.h +++ b/target/riscv/cpu.h @@ -XXX,XX +XXX,XX @@ struct CPUArchState { uint32_t mcountinhibit; /* PMU cycle & instret privilege mode filtering */ - target_ulong mcyclecfg; - target_ulong mcyclecfgh; + uint64_t mcyclecfg; target_ulong minstretcfg; target_ulong minstretcfgh; diff --git a/target/riscv/csr.c b/target/riscv/csr.c index XXXXXXX..XXXXXXX 100644 --- a/target/riscv/csr.c +++ b/target/riscv/csr.c @@ -XXX,XX +XXX,XX @@ static RISCVException read_hpmcounterh(CPURISCVState *env, int csrno, static RISCVException read_mcyclecfg(CPURISCVState *env, int csrno, target_ulong *val) { - *val = env->mcyclecfg; + bool rv32 = riscv_cpu_mxl(env) == MXL_RV32; + *val = extract64(env->mcyclecfg, 0, rv32 ? 32 : 64); return RISCV_EXCP_NONE; } @@ -XXX,XX +XXX,XX @@ static RISCVException write_mcyclecfg(CPURISCVState *env, int csrno, uint64_t inh_avail_mask; if (riscv_cpu_mxl(env) == MXL_RV32) { - env->mcyclecfg = val; + env->mcyclecfg = deposit64(env->mcyclecfg, 0, 32, val); } else { /* Set xINH fields if priv mode supported */ inh_avail_mask = ~MHPMEVENT_FILTER_MASK | MCYCLECFG_BIT_MINH; @@ -XXX,XX +XXX,XX @@ static RISCVException write_mcyclecfg(CPURISCVState *env, int csrno, static RISCVException read_mcyclecfgh(CPURISCVState *env, int csrno, target_ulong *val) { - *val = env->mcyclecfgh; + *val = extract64(env->mcyclecfg, 32, 32); return RISCV_EXCP_NONE; } @@ -XXX,XX +XXX,XX @@ static RISCVException write_mcyclecfgh(CPURISCVState *env, int csrno, inh_avail_mask |= (riscv_has_ext(env, RVH) && riscv_has_ext(env, RVS)) ? MCYCLECFGH_BIT_VSINH : 0; - env->mcyclecfgh = val & inh_avail_mask; + env->mcyclecfg = deposit64(env->mcyclecfg, 32, 32, val & inh_avail_mask); return RISCV_EXCP_NONE; } @@ -XXX,XX +XXX,XX @@ static target_ulong riscv_pmu_ctr_get_fixed_counters_val(CPURISCVState *env, uint64_t cfg_val = 0; if (counter_idx == 0) { - cfg_val = upper_half ? ((uint64_t)env->mcyclecfgh << 32) : - env->mcyclecfg; + cfg_val = env->mcyclecfg; } else if (counter_idx == 2) { cfg_val = upper_half ? ((uint64_t)env->minstretcfgh << 32) : env->minstretcfg; @@ -XXX,XX +XXX,XX @@ static int rmw_cd_mhpmeventh(CPURISCVState *env, int evt_index, } static int rmw_cd_ctr_cfg(CPURISCVState *env, int cfg_index, target_ulong *val, - target_ulong new_val, target_ulong wr_mask) + target_ulong new_val, uint64_t wr_mask) { + /* + * wr_mask is 64-bit so upper 32 bits of mcyclecfg and minstretcfg + * are retained. + */ switch (cfg_index) { case 0: /* CYCLECFG */ if (wr_mask) { @@ -XXX,XX +XXX,XX @@ static int rmw_cd_ctr_cfg(CPURISCVState *env, int cfg_index, target_ulong *val, } static int rmw_cd_ctr_cfgh(CPURISCVState *env, int cfg_index, target_ulong *val, - target_ulong new_val, target_ulong wr_mask) + target_ulong new_val, target_ulong wr_mask) { + uint64_t cfgh; if (riscv_cpu_mxl(env) != MXL_RV32) { return RISCV_EXCP_ILLEGAL_INST; @@ -XXX,XX +XXX,XX @@ static int rmw_cd_ctr_cfgh(CPURISCVState *env, int cfg_index, target_ulong *val, switch (cfg_index) { case 0: /* CYCLECFGH */ + cfgh = extract64(env->mcyclecfg, 32, 32); if (wr_mask) { wr_mask &= ~MCYCLECFGH_BIT_MINH; - env->mcyclecfgh = (new_val & wr_mask) | - (env->mcyclecfgh & ~wr_mask); + cfgh = (new_val & wr_mask) | (cfgh & ~wr_mask); + env->mcyclecfg = deposit64(env->mcyclecfg, 32, 32, cfgh); } else { - *val = env->mcyclecfgh; + *val = cfgh; } break; case 2: /* INSTRETCFGH */ -- 2.52.0
From: Anton Johansson <anjo@rev.ng> According to version 20250508 of the privileged specification, minstretcfg is a 64-bit register and minstretcfgh refers to the top 32 bits of this register when XLEN == 32. No real advantage is gained by keeping them separate, and combining them allows for slight simplification. Signed-off-by: Anton Johansson <anjo@rev.ng> Reviewed-by: Alistair Francis <alistair.francis@wdc.com> Reviewed-by: Pierrick Bouvier <pierrick.bouvier@linaro.org> Message-ID: <20251027181831.27016-8-anjo@rev.ng> Signed-off-by: Alistair Francis <alistair.francis@wdc.com> Message-ID: <20251103033713.904455-7-alistair.francis@wdc.com> Signed-off-by: Alistair Francis <alistair.francis@wdc.com> --- target/riscv/cpu.h | 3 +-- target/riscv/csr.c | 18 ++++++++++-------- 2 files changed, 11 insertions(+), 10 deletions(-) diff --git a/target/riscv/cpu.h b/target/riscv/cpu.h index XXXXXXX..XXXXXXX 100644 --- a/target/riscv/cpu.h +++ b/target/riscv/cpu.h @@ -XXX,XX +XXX,XX @@ struct CPUArchState { /* PMU cycle & instret privilege mode filtering */ uint64_t mcyclecfg; - target_ulong minstretcfg; - target_ulong minstretcfgh; + uint64_t minstretcfg; /* PMU counter state */ PMUCTRState pmu_ctrs[RV_MAX_MHPMCOUNTERS]; diff --git a/target/riscv/csr.c b/target/riscv/csr.c index XXXXXXX..XXXXXXX 100644 --- a/target/riscv/csr.c +++ b/target/riscv/csr.c @@ -XXX,XX +XXX,XX @@ static RISCVException write_mcyclecfgh(CPURISCVState *env, int csrno, static RISCVException read_minstretcfg(CPURISCVState *env, int csrno, target_ulong *val) { - *val = env->minstretcfg; + bool rv32 = riscv_cpu_mxl(env) == MXL_RV32; + *val = extract64(env->minstretcfg, 0, rv32 ? 32 : 64); return RISCV_EXCP_NONE; } @@ -XXX,XX +XXX,XX @@ static RISCVException write_minstretcfg(CPURISCVState *env, int csrno, static RISCVException read_minstretcfgh(CPURISCVState *env, int csrno, target_ulong *val) { - *val = env->minstretcfgh; + *val = extract64(env->minstretcfg, 32, 32); return RISCV_EXCP_NONE; } @@ -XXX,XX +XXX,XX @@ static RISCVException write_minstretcfgh(CPURISCVState *env, int csrno, inh_avail_mask |= (riscv_has_ext(env, RVH) && riscv_has_ext(env, RVS)) ? MINSTRETCFGH_BIT_VSINH : 0; - env->minstretcfgh = val & inh_avail_mask; + env->minstretcfg = deposit64(env->minstretcfg, 32, 32, + val & inh_avail_mask); return RISCV_EXCP_NONE; } @@ -XXX,XX +XXX,XX @@ static target_ulong riscv_pmu_ctr_get_fixed_counters_val(CPURISCVState *env, if (counter_idx == 0) { cfg_val = env->mcyclecfg; } else if (counter_idx == 2) { - cfg_val = upper_half ? ((uint64_t)env->minstretcfgh << 32) : - env->minstretcfg; + cfg_val = env->minstretcfg; } else { cfg_val = env->mhpmevent_val[counter_idx]; cfg_val &= MHPMEVENT_FILTER_MASK; @@ -XXX,XX +XXX,XX @@ static int rmw_cd_ctr_cfgh(CPURISCVState *env, int cfg_index, target_ulong *val, } break; case 2: /* INSTRETCFGH */ + cfgh = extract64(env->minstretcfg, 32, 32); if (wr_mask) { wr_mask &= ~MINSTRETCFGH_BIT_MINH; - env->minstretcfgh = (new_val & wr_mask) | - (env->minstretcfgh & ~wr_mask); + cfgh = (new_val & wr_mask) | (cfgh & ~wr_mask); + env->minstretcfg = deposit64(env->minstretcfg, 32, 32, cfgh); } else { - *val = env->minstretcfgh; + *val = cfgh; } break; default: -- 2.52.0
From: Anton Johansson <anjo@rev.ng> According to version 20250508 of the privileged specification, mhpmconter is a 64-bit register and mhpmcounterh refers to the top 32 bits of this register when XLEN == 32. No real advantage is gained by keeping them separate, and combining allows for slight simplification. Note, the cpu/pmu VMSTATE version is bumped breaking migration from older versions. Signed-off-by: Anton Johansson <anjo@rev.ng> Reviewed-by: Pierrick Bouvier <pierrick.bouvier@linaro.org> Reviewed-by: Alistair Francis <alistair.francis@wdc.com> Message-ID: <20251027181831.27016-9-anjo@rev.ng> Signed-off-by: Alistair Francis <alistair.francis@wdc.com> Message-ID: <20251103033713.904455-8-alistair.francis@wdc.com> Signed-off-by: Alistair Francis <alistair.francis@wdc.com> --- target/riscv/cpu.h | 10 ++-- target/riscv/csr.c | 76 ++++++++++++++-------------- target/riscv/machine.c | 10 ++-- target/riscv/pmu.c | 111 +++++++++++------------------------------ 4 files changed, 73 insertions(+), 134 deletions(-) diff --git a/target/riscv/cpu.h b/target/riscv/cpu.h index XXXXXXX..XXXXXXX 100644 --- a/target/riscv/cpu.h +++ b/target/riscv/cpu.h @@ -XXX,XX +XXX,XX @@ FIELD(VTYPE, RESERVED, 10, sizeof(target_ulong) * 8 - 11) typedef struct PMUCTRState { /* Current value of a counter */ - target_ulong mhpmcounter_val; - /* Current value of a counter in RV32 */ - target_ulong mhpmcounterh_val; - /* Snapshot values of counter */ - target_ulong mhpmcounter_prev; - /* Snapshort value of a counter in RV32 */ - target_ulong mhpmcounterh_prev; + uint64_t mhpmcounter_val; + /* Snapshot value of a counter */ + uint64_t mhpmcounter_prev; /* Value beyond UINT32_MAX/UINT64_MAX before overflow interrupt trigger */ target_ulong irq_overflow_left; } PMUCTRState; diff --git a/target/riscv/csr.c b/target/riscv/csr.c index XXXXXXX..XXXXXXX 100644 --- a/target/riscv/csr.c +++ b/target/riscv/csr.c @@ -XXX,XX +XXX,XX @@ static RISCVException riscv_pmu_write_ctr(CPURISCVState *env, target_ulong val, uint32_t ctr_idx) { PMUCTRState *counter = &env->pmu_ctrs[ctr_idx]; - uint64_t mhpmctr_val = val; + bool rv32 = riscv_cpu_mxl(env) == MXL_RV32; + int deposit_size = rv32 ? 32 : 64; + uint64_t ctr; + + counter->mhpmcounter_val = deposit64(counter->mhpmcounter_val, + 0, deposit_size, val); - counter->mhpmcounter_val = val; if (!get_field(env->mcountinhibit, BIT(ctr_idx)) && (riscv_pmu_ctr_monitor_cycles(env, ctr_idx) || riscv_pmu_ctr_monitor_instructions(env, ctr_idx))) { - counter->mhpmcounter_prev = riscv_pmu_ctr_get_fixed_counters_val(env, - ctr_idx, false); + ctr = riscv_pmu_ctr_get_fixed_counters_val(env, ctr_idx, false); + counter->mhpmcounter_prev = deposit64(counter->mhpmcounter_prev, + 0, deposit_size, ctr); if (ctr_idx > 2) { - if (riscv_cpu_mxl(env) == MXL_RV32) { - mhpmctr_val = mhpmctr_val | - ((uint64_t)counter->mhpmcounterh_val << 32); - } - riscv_pmu_setup_timer(env, mhpmctr_val, ctr_idx); + riscv_pmu_setup_timer(env, counter->mhpmcounter_val, ctr_idx); } } else { /* Other counters can keep incrementing from the given value */ - counter->mhpmcounter_prev = val; + counter->mhpmcounter_prev = deposit64(counter->mhpmcounter_prev, + 0, deposit_size, val); + } return RISCV_EXCP_NONE; @@ -XXX,XX +XXX,XX @@ static RISCVException riscv_pmu_write_ctrh(CPURISCVState *env, target_ulong val, uint32_t ctr_idx) { PMUCTRState *counter = &env->pmu_ctrs[ctr_idx]; - uint64_t mhpmctr_val = counter->mhpmcounter_val; - uint64_t mhpmctrh_val = val; + uint64_t ctrh; - counter->mhpmcounterh_val = val; - mhpmctr_val = mhpmctr_val | (mhpmctrh_val << 32); + counter->mhpmcounter_val = deposit64(counter->mhpmcounter_val, + 32, 32, val); if (!get_field(env->mcountinhibit, BIT(ctr_idx)) && (riscv_pmu_ctr_monitor_cycles(env, ctr_idx) || riscv_pmu_ctr_monitor_instructions(env, ctr_idx))) { - counter->mhpmcounterh_prev = riscv_pmu_ctr_get_fixed_counters_val(env, - ctr_idx, true); + ctrh = riscv_pmu_ctr_get_fixed_counters_val(env, ctr_idx, true); + counter->mhpmcounter_prev = deposit64(counter->mhpmcounter_prev, + 32, 32, ctrh); if (ctr_idx > 2) { - riscv_pmu_setup_timer(env, mhpmctr_val, ctr_idx); + riscv_pmu_setup_timer(env, counter->mhpmcounter_val, ctr_idx); } } else { - counter->mhpmcounterh_prev = val; + counter->mhpmcounter_prev = deposit64(counter->mhpmcounter_prev, + 32, 32, val); } return RISCV_EXCP_NONE; @@ -XXX,XX +XXX,XX @@ static RISCVException write_mhpmcounterh(CPURISCVState *env, int csrno, } RISCVException riscv_pmu_read_ctr(CPURISCVState *env, target_ulong *val, - bool upper_half, uint32_t ctr_idx) + bool upper_half, uint32_t ctr_idx) { PMUCTRState *counter = &env->pmu_ctrs[ctr_idx]; - target_ulong ctr_prev = upper_half ? counter->mhpmcounterh_prev : - counter->mhpmcounter_prev; - target_ulong ctr_val = upper_half ? counter->mhpmcounterh_val : - counter->mhpmcounter_val; + bool rv32 = riscv_cpu_mxl(env) == MXL_RV32; + int start = upper_half ? 32 : 0; + int length = rv32 ? 32 : 64; + uint64_t ctr_prev, ctr_val; + + /* Ensure upper_half is only set for XLEN == 32 */ + g_assert(rv32 || !upper_half); + + ctr_prev = extract64(counter->mhpmcounter_prev, start, length); + ctr_val = extract64(counter->mhpmcounter_val, start, length); if (get_field(env->mcountinhibit, BIT(ctr_idx))) { /* @@ -XXX,XX +XXX,XX @@ static RISCVException write_mcountinhibit(CPURISCVState *env, int csrno, uint32_t present_ctrs = cpu->pmu_avail_ctrs | COUNTEREN_CY | COUNTEREN_IR; target_ulong updated_ctrs = (env->mcountinhibit ^ val) & present_ctrs; uint64_t mhpmctr_val, prev_count, curr_count; + uint64_t ctrh; /* WARL register - disable unavailable counters; TM bit is always 0 */ env->mcountinhibit = val & present_ctrs; @@ -XXX,XX +XXX,XX @@ static RISCVException write_mcountinhibit(CPURISCVState *env, int csrno, counter->mhpmcounter_prev = riscv_pmu_ctr_get_fixed_counters_val(env, cidx, false); if (riscv_cpu_mxl(env) == MXL_RV32) { - counter->mhpmcounterh_prev = - riscv_pmu_ctr_get_fixed_counters_val(env, cidx, true); + ctrh = riscv_pmu_ctr_get_fixed_counters_val(env, cidx, true); + counter->mhpmcounter_prev = deposit64(counter->mhpmcounter_prev, + 32, 32, ctrh); } if (cidx > 2) { - mhpmctr_val = counter->mhpmcounter_val; - if (riscv_cpu_mxl(env) == MXL_RV32) { - mhpmctr_val = mhpmctr_val | - ((uint64_t)counter->mhpmcounterh_val << 32); - } - riscv_pmu_setup_timer(env, mhpmctr_val, cidx); + riscv_pmu_setup_timer(env, counter->mhpmcounter_val, cidx); } } else { curr_count = riscv_pmu_ctr_get_fixed_counters_val(env, cidx, false); @@ -XXX,XX +XXX,XX @@ static RISCVException write_mcountinhibit(CPURISCVState *env, int csrno, riscv_pmu_ctr_get_fixed_counters_val(env, cidx, true); curr_count = curr_count | (tmp << 32); - mhpmctr_val = mhpmctr_val | - ((uint64_t)counter->mhpmcounterh_val << 32); - prev_count = prev_count | - ((uint64_t)counter->mhpmcounterh_prev << 32); } /* Adjust the counter for later reads. */ mhpmctr_val = curr_count - prev_count + mhpmctr_val; counter->mhpmcounter_val = mhpmctr_val; - if (riscv_cpu_mxl(env) == MXL_RV32) { - counter->mhpmcounterh_val = mhpmctr_val >> 32; - } } } diff --git a/target/riscv/machine.c b/target/riscv/machine.c index XXXXXXX..XXXXXXX 100644 --- a/target/riscv/machine.c +++ b/target/riscv/machine.c @@ -XXX,XX +XXX,XX @@ static bool pmu_needed(void *opaque) static const VMStateDescription vmstate_pmu_ctr_state = { .name = "cpu/pmu", - .version_id = 2, - .minimum_version_id = 2, + .version_id = 3, + .minimum_version_id = 3, .needed = pmu_needed, .fields = (const VMStateField[]) { - VMSTATE_UINTTL(mhpmcounter_val, PMUCTRState), - VMSTATE_UINTTL(mhpmcounterh_val, PMUCTRState), - VMSTATE_UINTTL(mhpmcounter_prev, PMUCTRState), - VMSTATE_UINTTL(mhpmcounterh_prev, PMUCTRState), + VMSTATE_UINT64(mhpmcounter_val, PMUCTRState), + VMSTATE_UINT64(mhpmcounter_prev, PMUCTRState), VMSTATE_END_OF_LIST() } }; diff --git a/target/riscv/pmu.c b/target/riscv/pmu.c index XXXXXXX..XXXXXXX 100644 --- a/target/riscv/pmu.c +++ b/target/riscv/pmu.c @@ -XXX,XX +XXX,XX @@ static bool riscv_pmu_counter_enabled(RISCVCPU *cpu, uint32_t ctr_idx) } } -static int riscv_pmu_incr_ctr_rv32(RISCVCPU *cpu, uint32_t ctr_idx) -{ - CPURISCVState *env = &cpu->env; - target_ulong max_val = UINT32_MAX; - PMUCTRState *counter = &env->pmu_ctrs[ctr_idx]; - bool virt_on = env->virt_enabled; - - /* Privilege mode filtering */ - if ((env->priv == PRV_M && - (env->mhpmevent_val[ctr_idx] & MHPMEVENT_BIT_MINH)) || - (env->priv == PRV_S && virt_on && - (env->mhpmevent_val[ctr_idx] & MHPMEVENT_BIT_VSINH)) || - (env->priv == PRV_U && virt_on && - (env->mhpmevent_val[ctr_idx] & MHPMEVENT_BIT_VUINH)) || - (env->priv == PRV_S && !virt_on && - (env->mhpmevent_val[ctr_idx] & MHPMEVENT_BIT_SINH)) || - (env->priv == PRV_U && !virt_on && - (env->mhpmevent_val[ctr_idx] & MHPMEVENT_BIT_UINH))) { - return 0; - } - - /* Handle the overflow scenario */ - if (counter->mhpmcounter_val == max_val) { - if (counter->mhpmcounterh_val == max_val) { - counter->mhpmcounter_val = 0; - counter->mhpmcounterh_val = 0; - /* Generate interrupt only if OF bit is clear */ - if (!(env->mhpmevent_val[ctr_idx] & MHPMEVENT_BIT_OF)) { - env->mhpmevent_val[ctr_idx] |= MHPMEVENT_BIT_OF; - riscv_cpu_update_mip(env, MIP_LCOFIP, BOOL_TO_MASK(1)); - } - } else { - counter->mhpmcounterh_val++; - } - } else { - counter->mhpmcounter_val++; - } - - return 0; -} - -static int riscv_pmu_incr_ctr_rv64(RISCVCPU *cpu, uint32_t ctr_idx) -{ - CPURISCVState *env = &cpu->env; - PMUCTRState *counter = &env->pmu_ctrs[ctr_idx]; - uint64_t max_val = UINT64_MAX; - bool virt_on = env->virt_enabled; - - /* Privilege mode filtering */ - if ((env->priv == PRV_M && - (env->mhpmevent_val[ctr_idx] & MHPMEVENT_BIT_MINH)) || - (env->priv == PRV_S && virt_on && - (env->mhpmevent_val[ctr_idx] & MHPMEVENT_BIT_VSINH)) || - (env->priv == PRV_U && virt_on && - (env->mhpmevent_val[ctr_idx] & MHPMEVENT_BIT_VUINH)) || - (env->priv == PRV_S && !virt_on && - (env->mhpmevent_val[ctr_idx] & MHPMEVENT_BIT_SINH)) || - (env->priv == PRV_U && !virt_on && - (env->mhpmevent_val[ctr_idx] & MHPMEVENT_BIT_UINH))) { - return 0; - } - - /* Handle the overflow scenario */ - if (counter->mhpmcounter_val == max_val) { - counter->mhpmcounter_val = 0; - /* Generate interrupt only if OF bit is clear */ - if (!(env->mhpmevent_val[ctr_idx] & MHPMEVENT_BIT_OF)) { - env->mhpmevent_val[ctr_idx] |= MHPMEVENT_BIT_OF; - riscv_cpu_update_mip(env, MIP_LCOFIP, BOOL_TO_MASK(1)); - } - } else { - counter->mhpmcounter_val++; - } - return 0; -} - /* * Information needed to update counters: * new_priv, new_virt: To correctly save starting snapshot for the newly @@ -XXX,XX +XXX,XX @@ void riscv_pmu_update_fixed_ctrs(CPURISCVState *env, target_ulong newpriv, int riscv_pmu_incr_ctr(RISCVCPU *cpu, enum riscv_pmu_event_idx event_idx) { uint32_t ctr_idx; - int ret; CPURISCVState *env = &cpu->env; + uint64_t max_val = UINT64_MAX; + bool virt_on = env->virt_enabled; + PMUCTRState *counter; gpointer value; if (!cpu->cfg.pmu_mask) { @@ -XXX,XX +XXX,XX @@ int riscv_pmu_incr_ctr(RISCVCPU *cpu, enum riscv_pmu_event_idx event_idx) return -1; } - if (riscv_cpu_mxl(env) == MXL_RV32) { - ret = riscv_pmu_incr_ctr_rv32(cpu, ctr_idx); + /* Privilege mode filtering */ + if ((env->priv == PRV_M && + (env->mhpmevent_val[ctr_idx] & MHPMEVENT_BIT_MINH)) || + (env->priv == PRV_S && virt_on && + (env->mhpmevent_val[ctr_idx] & MHPMEVENT_BIT_VSINH)) || + (env->priv == PRV_U && virt_on && + (env->mhpmevent_val[ctr_idx] & MHPMEVENT_BIT_VUINH)) || + (env->priv == PRV_S && !virt_on && + (env->mhpmevent_val[ctr_idx] & MHPMEVENT_BIT_SINH)) || + (env->priv == PRV_U && !virt_on && + (env->mhpmevent_val[ctr_idx] & MHPMEVENT_BIT_UINH))) { + return 0; + } + + /* Handle the overflow scenario */ + counter = &env->pmu_ctrs[ctr_idx]; + if (counter->mhpmcounter_val == max_val) { + counter->mhpmcounter_val = 0; + /* Generate interrupt only if OF bit is clear */ + if (!(env->mhpmevent_val[ctr_idx] & MHPMEVENT_BIT_OF)) { + env->mhpmevent_val[ctr_idx] |= MHPMEVENT_BIT_OF; + riscv_cpu_update_mip(env, MIP_LCOFIP, BOOL_TO_MASK(1)); + } } else { - ret = riscv_pmu_incr_ctr_rv64(cpu, ctr_idx); + counter->mhpmcounter_val++; } - return ret; + return 0; } bool riscv_pmu_ctr_monitor_instructions(CPURISCVState *env, @@ -XXX,XX +XXX,XX @@ static void pmu_timer_trigger_irq(RISCVCPU *cpu, if (riscv_cpu_mxl(env) == MXL_RV32) { riscv_pmu_read_ctr(env, (target_ulong *)&curr_ctrh_val, true, ctr_idx); curr_ctr_val = curr_ctr_val | (curr_ctrh_val << 32); - ctr_val = ctr_val | - ((uint64_t)counter->mhpmcounterh_val << 32); } /* -- 2.52.0
From: Alistair Francis <alistair.francis@wdc.com> Now that mhpmcounter is always a 64-bit value we can remove the upper_half argument from riscv_pmu_ctr_get_fixed_counters_val() and always return a 64-bit value. Signed-off-by: Alistair Francis <alistair.francis@wdc.com> Reviewed-by: Anton Johansson <anjo@rev.ng> Reviewed-by: Philippe Mathieu-Daudé <philmd@linaro.org> Message-ID: <20251103033713.904455-9-alistair.francis@wdc.com> Signed-off-by: Alistair Francis <alistair.francis@wdc.com> --- target/riscv/csr.c | 40 +++++++++------------------------------- 1 file changed, 9 insertions(+), 31 deletions(-) diff --git a/target/riscv/csr.c b/target/riscv/csr.c index XXXXXXX..XXXXXXX 100644 --- a/target/riscv/csr.c +++ b/target/riscv/csr.c @@ -XXX,XX +XXX,XX @@ static RISCVException write_mhpmeventh(CPURISCVState *env, int csrno, return RISCV_EXCP_NONE; } -static target_ulong riscv_pmu_ctr_get_fixed_counters_val(CPURISCVState *env, - int counter_idx, - bool upper_half) +static uint64_t riscv_pmu_ctr_get_fixed_counters_val(CPURISCVState *env, + int counter_idx) { int inst = riscv_pmu_ctr_monitor_instructions(env, counter_idx); uint64_t *counter_arr_virt = env->pmu_fixed_ctrs[inst].counter_virt; uint64_t *counter_arr = env->pmu_fixed_ctrs[inst].counter; - target_ulong result = 0; uint64_t curr_val = 0; uint64_t cfg_val = 0; @@ -XXX,XX +XXX,XX @@ static target_ulong riscv_pmu_ctr_get_fixed_counters_val(CPURISCVState *env, curr_val = cpu_get_host_ticks(); } - goto done; + return curr_val; } /* Update counter before reading. */ @@ -XXX,XX +XXX,XX @@ static target_ulong riscv_pmu_ctr_get_fixed_counters_val(CPURISCVState *env, curr_val += counter_arr_virt[PRV_U]; } -done: - if (riscv_cpu_mxl(env) == MXL_RV32) { - result = upper_half ? curr_val >> 32 : curr_val; - } else { - result = curr_val; - } - - return result; + return curr_val; } static RISCVException riscv_pmu_write_ctr(CPURISCVState *env, target_ulong val, @@ -XXX,XX +XXX,XX @@ static RISCVException riscv_pmu_write_ctr(CPURISCVState *env, target_ulong val, if (!get_field(env->mcountinhibit, BIT(ctr_idx)) && (riscv_pmu_ctr_monitor_cycles(env, ctr_idx) || riscv_pmu_ctr_monitor_instructions(env, ctr_idx))) { - ctr = riscv_pmu_ctr_get_fixed_counters_val(env, ctr_idx, false); + ctr = riscv_pmu_ctr_get_fixed_counters_val(env, ctr_idx); counter->mhpmcounter_prev = deposit64(counter->mhpmcounter_prev, 0, deposit_size, ctr); if (ctr_idx > 2) { @@ -XXX,XX +XXX,XX @@ static RISCVException riscv_pmu_write_ctrh(CPURISCVState *env, target_ulong val, if (!get_field(env->mcountinhibit, BIT(ctr_idx)) && (riscv_pmu_ctr_monitor_cycles(env, ctr_idx) || riscv_pmu_ctr_monitor_instructions(env, ctr_idx))) { - ctrh = riscv_pmu_ctr_get_fixed_counters_val(env, ctr_idx, true); + ctrh = riscv_pmu_ctr_get_fixed_counters_val(env, ctr_idx); counter->mhpmcounter_prev = deposit64(counter->mhpmcounter_prev, 32, 32, ctrh); if (ctr_idx > 2) { @@ -XXX,XX +XXX,XX @@ RISCVException riscv_pmu_read_ctr(CPURISCVState *env, target_ulong *val, */ if (riscv_pmu_ctr_monitor_cycles(env, ctr_idx) || riscv_pmu_ctr_monitor_instructions(env, ctr_idx)) { - *val = riscv_pmu_ctr_get_fixed_counters_val(env, ctr_idx, upper_half) - + *val = riscv_pmu_ctr_get_fixed_counters_val(env, ctr_idx) - ctr_prev + ctr_val; } else { *val = ctr_val; @@ -XXX,XX +XXX,XX @@ static RISCVException write_mcountinhibit(CPURISCVState *env, int csrno, uint32_t present_ctrs = cpu->pmu_avail_ctrs | COUNTEREN_CY | COUNTEREN_IR; target_ulong updated_ctrs = (env->mcountinhibit ^ val) & present_ctrs; uint64_t mhpmctr_val, prev_count, curr_count; - uint64_t ctrh; /* WARL register - disable unavailable counters; TM bit is always 0 */ env->mcountinhibit = val & present_ctrs; @@ -XXX,XX +XXX,XX @@ static RISCVException write_mcountinhibit(CPURISCVState *env, int csrno, counter = &env->pmu_ctrs[cidx]; if (!get_field(env->mcountinhibit, BIT(cidx))) { - counter->mhpmcounter_prev = - riscv_pmu_ctr_get_fixed_counters_val(env, cidx, false); - if (riscv_cpu_mxl(env) == MXL_RV32) { - ctrh = riscv_pmu_ctr_get_fixed_counters_val(env, cidx, true); - counter->mhpmcounter_prev = deposit64(counter->mhpmcounter_prev, - 32, 32, ctrh); - } + counter->mhpmcounter_prev = riscv_pmu_ctr_get_fixed_counters_val(env, cidx); if (cidx > 2) { riscv_pmu_setup_timer(env, counter->mhpmcounter_val, cidx); } } else { - curr_count = riscv_pmu_ctr_get_fixed_counters_val(env, cidx, false); + curr_count = riscv_pmu_ctr_get_fixed_counters_val(env, cidx); mhpmctr_val = counter->mhpmcounter_val; prev_count = counter->mhpmcounter_prev; - if (riscv_cpu_mxl(env) == MXL_RV32) { - uint64_t tmp = - riscv_pmu_ctr_get_fixed_counters_val(env, cidx, true); - - curr_count = curr_count | (tmp << 32); - } /* Adjust the counter for later reads. */ mhpmctr_val = curr_count - prev_count + mhpmctr_val; -- 2.52.0
From: Nikita Novikov <n.novikov@syntacore.com> According to the RISC-V AIA v1.0, section 4.5.2 ("Source configurations"), register target[i] shall be read-only zero when interrupt source i is inactive in this domain. A source is inactive if it is delegated to a child domain or its source mode is INACTIVE. The previous implementation only checked SM == INACTIVE. This patch adds full compliance: - Return zero on read if D == 1 or SM == INACTIVE - Ignore writes in both cases Fixes: b6f1244678 ("intc/riscv_aplic: Fix target register read when source is inactive") Signed-off-by: Nikita Novikov <n.novikov@syntacore.com> Acked-by: Alistair Francis <alistair.francis@wdc.com> Reviewed-by: Daniel Henrique Barboza <dbarboza@ventanamicro.com> Message-ID: <20251029-n-novikov-aplic_aia_ro-v1-1-39fec74c918a@syntacore.com> Signed-off-by: Alistair Francis <alistair.francis@wdc.com> --- hw/intc/riscv_aplic.c | 28 +++++++++++++++++++++++++--- 1 file changed, 25 insertions(+), 3 deletions(-) diff --git a/hw/intc/riscv_aplic.c b/hw/intc/riscv_aplic.c index XXXXXXX..XXXXXXX 100644 --- a/hw/intc/riscv_aplic.c +++ b/hw/intc/riscv_aplic.c @@ -XXX,XX +XXX,XX @@ void riscv_aplic_set_kvm_msicfgaddr(RISCVAPLICState *aplic, hwaddr addr) #endif } +/* + * APLIC target[i] must be read-only zero if the source i is inactive + * in this domain (delegated or SM == INACTIVE) + */ +static inline bool riscv_aplic_source_active(RISCVAPLICState *aplic, + uint32_t irq) +{ + uint32_t sc, sm; + + if ((irq == 0) || (aplic->num_irqs <= irq)) { + return false; + } + sc = aplic->sourcecfg[irq]; + if (sc & APLIC_SOURCECFG_D) { + return false; + } + sm = sc & APLIC_SOURCECFG_SM_MASK; + return sm != APLIC_SOURCECFG_SM_INACTIVE; +} + static bool riscv_aplic_irq_rectified_val(RISCVAPLICState *aplic, uint32_t irq) { @@ -XXX,XX +XXX,XX @@ static void riscv_aplic_request(void *opaque, int irq, int level) static uint64_t riscv_aplic_read(void *opaque, hwaddr addr, unsigned size) { - uint32_t irq, word, idc, sm; + uint32_t irq, word, idc; RISCVAPLICState *aplic = opaque; /* Reads must be 4 byte words */ @@ -XXX,XX +XXX,XX @@ static uint64_t riscv_aplic_read(void *opaque, hwaddr addr, unsigned size) } else if ((APLIC_TARGET_BASE <= addr) && (addr < (APLIC_TARGET_BASE + (aplic->num_irqs - 1) * 4))) { irq = ((addr - APLIC_TARGET_BASE) >> 2) + 1; - sm = aplic->sourcecfg[irq] & APLIC_SOURCECFG_SM_MASK; - if (sm == APLIC_SOURCECFG_SM_INACTIVE) { + if (!riscv_aplic_source_active(aplic, irq)) { return 0; } return aplic->target[irq]; @@ -XXX,XX +XXX,XX @@ static void riscv_aplic_write(void *opaque, hwaddr addr, uint64_t value, } else if ((APLIC_TARGET_BASE <= addr) && (addr < (APLIC_TARGET_BASE + (aplic->num_irqs - 1) * 4))) { irq = ((addr - APLIC_TARGET_BASE) >> 2) + 1; + if (!riscv_aplic_source_active(aplic, irq)) { + return; + } if (aplic->msimode) { aplic->target[irq] = value; } else { -- 2.52.0
From: Nikita Novikov <n.novikov@syntacore.com> Refactor the APLIC code to consolidate repeated conditions checking whether an interrupt source is valid, delegated, or inactive. Signed-off-by: Nikita Novikov <n.novikov@syntacore.com> Reviewed-by: Alistair Francis <alistair.francis@wdc.com> Reviewed-by: Daniel Henrique Barboza <dbarboza@ventanamicro.com> Message-ID: <20251029-n-novikov-aplic_aia_ro-v1-2-39fec74c918a@syntacore.com> Signed-off-by: Alistair Francis <alistair.francis@wdc.com> --- hw/intc/riscv_aplic.c | 44 +++++++------------------------------------ 1 file changed, 7 insertions(+), 37 deletions(-) diff --git a/hw/intc/riscv_aplic.c b/hw/intc/riscv_aplic.c index XXXXXXX..XXXXXXX 100644 --- a/hw/intc/riscv_aplic.c +++ b/hw/intc/riscv_aplic.c @@ -XXX,XX +XXX,XX @@ static inline bool riscv_aplic_source_active(RISCVAPLICState *aplic, static bool riscv_aplic_irq_rectified_val(RISCVAPLICState *aplic, uint32_t irq) { - uint32_t sourcecfg, sm, raw_input, irq_inverted; + uint32_t sm, raw_input, irq_inverted; - if (!irq || aplic->num_irqs <= irq) { - return false; - } - - sourcecfg = aplic->sourcecfg[irq]; - if (sourcecfg & APLIC_SOURCECFG_D) { - return false; - } - - sm = sourcecfg & APLIC_SOURCECFG_SM_MASK; - if (sm == APLIC_SOURCECFG_SM_INACTIVE) { + if (!riscv_aplic_source_active(aplic, irq)) { return false; } + sm = aplic->sourcecfg[irq] & APLIC_SOURCECFG_SM_MASK; raw_input = (aplic->state[irq] & APLIC_ISTATE_INPUT) ? 1 : 0; irq_inverted = (sm == APLIC_SOURCECFG_SM_LEVEL_LOW || sm == APLIC_SOURCECFG_SM_EDGE_FALL) ? 1 : 0; @@ -XXX,XX +XXX,XX @@ static void riscv_aplic_set_pending_raw(RISCVAPLICState *aplic, static void riscv_aplic_set_pending(RISCVAPLICState *aplic, uint32_t irq, bool pending) { - uint32_t sourcecfg, sm; + uint32_t sm; - if ((irq <= 0) || (aplic->num_irqs <= irq)) { - return; - } - - sourcecfg = aplic->sourcecfg[irq]; - if (sourcecfg & APLIC_SOURCECFG_D) { - return; - } - - sm = sourcecfg & APLIC_SOURCECFG_SM_MASK; - if (sm == APLIC_SOURCECFG_SM_INACTIVE) { + if (!riscv_aplic_source_active(aplic, irq)) { return; } + sm = aplic->sourcecfg[irq] & APLIC_SOURCECFG_SM_MASK; if ((sm == APLIC_SOURCECFG_SM_LEVEL_HIGH) || (sm == APLIC_SOURCECFG_SM_LEVEL_LOW)) { if (!aplic->msimode) { @@ -XXX,XX +XXX,XX @@ static void riscv_aplic_set_enabled_raw(RISCVAPLICState *aplic, static void riscv_aplic_set_enabled(RISCVAPLICState *aplic, uint32_t irq, bool enabled) { - uint32_t sourcecfg, sm; - - if ((irq <= 0) || (aplic->num_irqs <= irq)) { - return; - } - - sourcecfg = aplic->sourcecfg[irq]; - if (sourcecfg & APLIC_SOURCECFG_D) { - return; - } - - sm = sourcecfg & APLIC_SOURCECFG_SM_MASK; - if (sm == APLIC_SOURCECFG_SM_INACTIVE) { + if (!riscv_aplic_source_active(aplic, irq)) { return; } -- 2.52.0
From: Frank Chang <frank.chang@sifive.com> According to the RISC-V IOMMU specification: * When ddtp.iommu_mode is set to Off, there is no DDT look-up, and an "All inbound transactions disallowed" fault (cause = 256) is reported for any inbound transaction. * When ddtp.iommu_mode is set to Bare, there is no DDT look-up, and the translated address is the same as the IOVA, unless the transaction type is disallowed (cause = 260). In the current implementation, the DDT cache is incorrectly looked up even when ddtp.iommu_mode is set to Off or Bare. This may result in unintended cache hits. Therefore, the DDT cache must not be looked up when ddtp.iommu_mode is set to Off or Bare. For other modes, software is required to issue cache invalidation commands before any inbound transactions. Signed-off-by: Frank Chang <frank.chang@sifive.com> Acked-by: Alistair Francis <alistair.francis@wdc.com> Reviewed-by: Daniel Henrique Barboza <dbarboza@ventanamicro.com> Reviewed-by: Jim Shu <jim.shu@sifive.com> Message-ID: <20251028085032.2053569-1-frank.chang@sifive.com> Signed-off-by: Alistair Francis <alistair.francis@wdc.com> --- hw/riscv/riscv-iommu.c | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/hw/riscv/riscv-iommu.c b/hw/riscv/riscv-iommu.c index XXXXXXX..XXXXXXX 100644 --- a/hw/riscv/riscv-iommu.c +++ b/hw/riscv/riscv-iommu.c @@ -XXX,XX +XXX,XX @@ static RISCVIOMMUContext *riscv_iommu_ctx(RISCVIOMMUState *s, .devid = devid, .process_id = process_id, }; + unsigned mode = get_field(s->ddtp, RISCV_IOMMU_DDTP_MODE); ctx_cache = g_hash_table_ref(s->ctx_cache); - ctx = g_hash_table_lookup(ctx_cache, &key); - if (ctx && (ctx->tc & RISCV_IOMMU_DC_TC_V)) { - *ref = ctx_cache; - return ctx; + if (mode != RISCV_IOMMU_DDTP_MODE_OFF && + mode != RISCV_IOMMU_DDTP_MODE_BARE) { + ctx = g_hash_table_lookup(ctx_cache, &key); + + if (ctx && (ctx->tc & RISCV_IOMMU_DC_TC_V)) { + *ref = ctx_cache; + return ctx; + } } ctx = g_new0(RISCVIOMMUContext, 1); -- 2.52.0
From: lxx <1733205434@qq.com> This patch adds support for the Zilsd and Zclsd extension, which is documented at https://github.com/riscv/riscv-zilsd/releases/tag/v1.0 Signed-off-by: LIU Xu <liuxu@nucleisys.com> Co-developed-by: SUN Dongya <sundongya@nucleisys.com> Co-developed-by: ZHAO Fujin <zhaofujin@nucleisys.com> Reviewed-by: Alistair Francis <alistair.francis@wdc.com> Message-ID: <176154834968.21563.217396575391240410-1@git.sr.ht> Signed-off-by: Alistair Francis <alistair.francis@wdc.com> --- target/riscv/cpu_cfg_fields.h.inc | 2 + target/riscv/insn16.decode | 8 ++ target/riscv/insn32.decode | 12 ++- target/riscv/cpu.c | 4 + target/riscv/tcg/tcg-cpu.c | 33 +++++++ target/riscv/translate.c | 1 + target/riscv/insn_trans/trans_zilsd.c.inc | 105 ++++++++++++++++++++++ 7 files changed, 163 insertions(+), 2 deletions(-) create mode 100644 target/riscv/insn_trans/trans_zilsd.c.inc diff --git a/target/riscv/cpu_cfg_fields.h.inc b/target/riscv/cpu_cfg_fields.h.inc index XXXXXXX..XXXXXXX 100644 --- a/target/riscv/cpu_cfg_fields.h.inc +++ b/target/riscv/cpu_cfg_fields.h.inc @@ -XXX,XX +XXX,XX @@ BOOL_FIELD(ext_zce) BOOL_FIELD(ext_zcf) BOOL_FIELD(ext_zcmp) BOOL_FIELD(ext_zcmt) +BOOL_FIELD(ext_zclsd) BOOL_FIELD(ext_zk) BOOL_FIELD(ext_zkn) BOOL_FIELD(ext_zknd) @@ -XXX,XX +XXX,XX @@ BOOL_FIELD(ext_zicond) BOOL_FIELD(ext_zihintntl) BOOL_FIELD(ext_zihintpause) BOOL_FIELD(ext_zihpm) +BOOL_FIELD(ext_zilsd) BOOL_FIELD(ext_zimop) BOOL_FIELD(ext_zcmop) BOOL_FIELD(ext_ztso) diff --git a/target/riscv/insn16.decode b/target/riscv/insn16.decode index XXXXXXX..XXXXXXX 100644 --- a/target/riscv/insn16.decode +++ b/target/riscv/insn16.decode @@ -XXX,XX +XXX,XX @@ sw 110 ... ... .. ... 00 @cs_w { ld 011 ... ... .. ... 00 @cl_d c_flw 011 ... ... .. ... 00 @cl_w + # *** Zclsd Extension *** + zclsd_ld 011 ... ... .. ... 00 @cl_d } { sd 111 ... ... .. ... 00 @cs_d c_fsw 111 ... ... .. ... 00 @cs_w + # *** Zclsd Extension *** + zclsd_sd 111 ... ... .. ... 00 @cs_d } # *** RV32/64C Standard Extension (Quadrant 1) *** @@ -XXX,XX +XXX,XX @@ sw 110 . ..... ..... 10 @c_swsp c64_illegal 011 - 00000 ----- 10 # c.ldsp, RES rd=0 ld 011 . ..... ..... 10 @c_ldsp c_flw 011 . ..... ..... 10 @c_lwsp + # *** Zclsd Extension *** + zclsd_ldsp 011 . ..... ..... 10 @c_ldsp } { sd 111 . ..... ..... 10 @c_sdsp c_fsw 111 . ..... ..... 10 @c_swsp + # *** Zclsd Extension *** + zclsd_sd 111 . ..... ..... 10 @c_sdsp } # *** RV64 and RV32 Zcb Extension *** diff --git a/target/riscv/insn32.decode b/target/riscv/insn32.decode index XXXXXXX..XXXXXXX 100644 --- a/target/riscv/insn32.decode +++ b/target/riscv/insn32.decode @@ -XXX,XX +XXX,XX @@ csrrci ............ ..... 111 ..... 1110011 @csr # *** RV64I Base Instruction Set (in addition to RV32I) *** lwu ............ ..... 110 ..... 0000011 @i -ld ............ ..... 011 ..... 0000011 @i -sd ....... ..... ..... 011 ..... 0100011 @s +{ + ld ............ ..... 011 ..... 0000011 @i + # *** Zilsd instructions *** + zilsd_ld ............ ..... 011 ..... 0000011 @i +} +{ + sd ....... ..... ..... 011 ..... 0100011 @s + # *** Zilsd instructions *** + zilsd_sd ....... ..... ..... 011 ..... 0100011 @s +} addiw ............ ..... 000 ..... 0011011 @i slliw 0000000 ..... ..... 001 ..... 0011011 @sh5 srliw 0000000 ..... ..... 101 ..... 0011011 @sh5 diff --git a/target/riscv/cpu.c b/target/riscv/cpu.c index XXXXXXX..XXXXXXX 100644 --- a/target/riscv/cpu.c +++ b/target/riscv/cpu.c @@ -XXX,XX +XXX,XX @@ const RISCVIsaExtData isa_edata_arr[] = { ISA_EXT_DATA_ENTRY(zihintntl, PRIV_VERSION_1_10_0, ext_zihintntl), ISA_EXT_DATA_ENTRY(zihintpause, PRIV_VERSION_1_10_0, ext_zihintpause), ISA_EXT_DATA_ENTRY(zihpm, PRIV_VERSION_1_12_0, ext_zihpm), + ISA_EXT_DATA_ENTRY(zilsd, PRIV_VERSION_1_12_0, ext_zilsd), ISA_EXT_DATA_ENTRY(zimop, PRIV_VERSION_1_13_0, ext_zimop), ISA_EXT_DATA_ENTRY(zmmul, PRIV_VERSION_1_12_0, ext_zmmul), ISA_EXT_DATA_ENTRY(za64rs, PRIV_VERSION_1_12_0, has_priv_1_12), @@ -XXX,XX +XXX,XX @@ const RISCVIsaExtData isa_edata_arr[] = { ISA_EXT_DATA_ENTRY(zcmop, PRIV_VERSION_1_13_0, ext_zcmop), ISA_EXT_DATA_ENTRY(zcmp, PRIV_VERSION_1_12_0, ext_zcmp), ISA_EXT_DATA_ENTRY(zcmt, PRIV_VERSION_1_12_0, ext_zcmt), + ISA_EXT_DATA_ENTRY(zclsd, PRIV_VERSION_1_12_0, ext_zclsd), ISA_EXT_DATA_ENTRY(zba, PRIV_VERSION_1_12_0, ext_zba), ISA_EXT_DATA_ENTRY(zbb, PRIV_VERSION_1_12_0, ext_zbb), ISA_EXT_DATA_ENTRY(zbc, PRIV_VERSION_1_12_0, ext_zbc), @@ -XXX,XX +XXX,XX @@ const RISCVCPUMultiExtConfig riscv_cpu_extensions[] = { MULTI_EXT_CFG_BOOL("zicntr", ext_zicntr, true), MULTI_EXT_CFG_BOOL("zihpm", ext_zihpm, true), + MULTI_EXT_CFG_BOOL("zilsd", ext_zilsd, false), MULTI_EXT_CFG_BOOL("zba", ext_zba, true), MULTI_EXT_CFG_BOOL("zbb", ext_zbb, true), @@ -XXX,XX +XXX,XX @@ const RISCVCPUMultiExtConfig riscv_cpu_extensions[] = { MULTI_EXT_CFG_BOOL("zcmp", ext_zcmp, false), MULTI_EXT_CFG_BOOL("zcmt", ext_zcmt, false), MULTI_EXT_CFG_BOOL("zicond", ext_zicond, false), + MULTI_EXT_CFG_BOOL("zclsd", ext_zclsd, false), /* Vector cryptography extensions */ MULTI_EXT_CFG_BOOL("zvbb", ext_zvbb, false), diff --git a/target/riscv/tcg/tcg-cpu.c b/target/riscv/tcg/tcg-cpu.c index XXXXXXX..XXXXXXX 100644 --- a/target/riscv/tcg/tcg-cpu.c +++ b/target/riscv/tcg/tcg-cpu.c @@ -XXX,XX +XXX,XX @@ void riscv_cpu_validate_set_extensions(RISCVCPU *cpu, Error **errp) cpu->pmu_avail_ctrs = 0; } + if (cpu->cfg.ext_zclsd) { + if (riscv_has_ext(env, RVC) && riscv_has_ext(env, RVF)) { + error_setg(errp, + "Zclsd cannot be supported together with C and F extension"); + return; + } + if (cpu->cfg.ext_zcf) { + error_setg(errp, + "Zclsd cannot be supported together with Zcf extension"); + return; + } + } + if (cpu->cfg.ext_zicfilp && !cpu->cfg.ext_zicsr) { error_setg(errp, "zicfilp extension requires zicsr extension"); return; @@ -XXX,XX +XXX,XX @@ static void cpu_enable_zc_implied_rules(RISCVCPU *cpu) } } +static void cpu_enable_zilsd_implied_rules(RISCVCPU *cpu) +{ + CPURISCVState *env = &cpu->env; + + if (cpu->cfg.ext_zilsd && riscv_has_ext(env, RVC)) { + cpu_cfg_ext_auto_update(cpu, CPU_CFG_OFFSET(ext_zclsd), true); + } + + if (cpu->cfg.ext_zclsd) { + cpu_cfg_ext_auto_update(cpu, CPU_CFG_OFFSET(ext_zca), true); + cpu_cfg_ext_auto_update(cpu, CPU_CFG_OFFSET(ext_zilsd), true); + } +} + static void riscv_cpu_enable_implied_rules(RISCVCPU *cpu) { RISCVCPUImpliedExtsRule *rule; @@ -XXX,XX +XXX,XX @@ static void riscv_cpu_enable_implied_rules(RISCVCPU *cpu) /* Enable the implied extensions for Zc. */ cpu_enable_zc_implied_rules(cpu); + /* Enable the implied extensions for Zilsd. */ + cpu_enable_zilsd_implied_rules(cpu); + /* Enable the implied MISAs. */ for (i = 0; (rule = riscv_misa_ext_implied_rules[i]); i++) { if (riscv_has_ext(&cpu->env, rule->ext)) { @@ -XXX,XX +XXX,XX @@ static void riscv_init_max_cpu_extensions(Object *obj) isa_ext_update_enabled(cpu, CPU_CFG_OFFSET(ext_zcmp), false); isa_ext_update_enabled(cpu, CPU_CFG_OFFSET(ext_zcmt), false); + isa_ext_update_enabled(cpu, CPU_CFG_OFFSET(ext_zilsd), false); + isa_ext_update_enabled(cpu, CPU_CFG_OFFSET(ext_zclsd), false); + if (env->misa_mxl != MXL_RV32) { isa_ext_update_enabled(cpu, CPU_CFG_OFFSET(ext_zcf), false); } else { diff --git a/target/riscv/translate.c b/target/riscv/translate.c index XXXXXXX..XXXXXXX 100644 --- a/target/riscv/translate.c +++ b/target/riscv/translate.c @@ -XXX,XX +XXX,XX @@ static uint32_t opcode_at(DisasContextBase *dcbase, target_ulong pc) /* Include the auto-generated decoder for 16 bit insn */ #include "decode-insn16.c.inc" #include "insn_trans/trans_rvzce.c.inc" +#include "insn_trans/trans_zilsd.c.inc" #include "insn_trans/trans_rvzcmop.c.inc" #include "insn_trans/trans_rvzicfiss.c.inc" diff --git a/target/riscv/insn_trans/trans_zilsd.c.inc b/target/riscv/insn_trans/trans_zilsd.c.inc new file mode 100644 index XXXXXXX..XXXXXXX --- /dev/null +++ b/target/riscv/insn_trans/trans_zilsd.c.inc @@ -XXX,XX +XXX,XX @@ +/* + * RISC-V translation routines for the Zilsd & Zclsd Extension. + * + * Copyright (c) 2025 Nucleisys, Inc. + * + * SPDX-License-Identifier: GPL-2.0-or-later + * + * The documentation of the ISA extensions can be found here: + * https://github.com/riscv/riscv-zilsd/releases/tag/v1.0 + */ + +#define REQUIRE_ZILSD(ctx) do { \ + if (!ctx->cfg_ptr->ext_zilsd) \ + return false; \ +} while (0) + +#define REQUIRE_ZCLSD(ctx) do { \ + if (!ctx->cfg_ptr->ext_zclsd) \ + return false; \ +} while (0) + +static bool gen_load_i64(DisasContext *ctx, arg_ld *a) +{ + if ((a->rd) % 2) { + return false; + } + + TCGv dest_low = dest_gpr(ctx, a->rd); + TCGv dest_high = dest_gpr(ctx, a->rd + 1); + TCGv addr = get_address(ctx, a->rs1, a->imm); + TCGv_i64 tmp = tcg_temp_new_i64(); + + tcg_gen_qemu_ld_i64(tmp, addr, ctx->mem_idx, MO_TESQ); + + if (a->rd == 0) { + return true; + } + + tcg_gen_extr_i64_tl(dest_low, dest_high, tmp); + + gen_set_gpr(ctx, a->rd, dest_low); + gen_set_gpr(ctx, a->rd + 1, dest_high); + + return true; +} + +static bool trans_zilsd_ld(DisasContext *ctx, arg_zilsd_ld *a) +{ + REQUIRE_32BIT(ctx); + REQUIRE_ZILSD(ctx); + return gen_load_i64(ctx, a); +} + +static bool trans_zclsd_ld(DisasContext *ctx, arg_zclsd_ld *a) +{ + REQUIRE_32BIT(ctx); + REQUIRE_ZCLSD(ctx); + return gen_load_i64(ctx, a); +} + +static bool trans_zclsd_ldsp(DisasContext *ctx, arg_zclsd_ldsp *a) +{ + REQUIRE_32BIT(ctx); + REQUIRE_ZCLSD(ctx); + + if (a->rd == 0) { + return false; + } + return gen_load_i64(ctx, a); +} + +static bool gen_store_i64(DisasContext *ctx, arg_sd *a) +{ + if ((a->rs2) % 2) { + return false; + } + + TCGv data_low = get_gpr(ctx, a->rs2, EXT_NONE); + TCGv data_high = get_gpr(ctx, a->rs2 + 1, EXT_NONE); + TCGv addr = get_address(ctx, a->rs1, a->imm); + TCGv_i64 tmp = tcg_temp_new_i64(); + + if (a->rs2 == 0) { + tmp = tcg_constant_i64(0); + } else { + tcg_gen_concat_tl_i64(tmp, data_low, data_high); + } + tcg_gen_qemu_st_i64(tmp, addr, ctx->mem_idx, MO_TESQ); + + return true; +} + +static bool trans_zilsd_sd(DisasContext *ctx, arg_zilsd_sd *a) +{ + REQUIRE_32BIT(ctx); + REQUIRE_ZILSD(ctx); + return gen_store_i64(ctx, a); +} + +static bool trans_zclsd_sd(DisasContext *ctx, arg_zclsd_sd *a) +{ + REQUIRE_32BIT(ctx); + REQUIRE_ZCLSD(ctx); + return gen_store_i64(ctx, a); +} -- 2.52.0
From: Roan Richmond <roan.richmond@codethink.co.uk> This is based on version v0.9 of the ZALASR specification [1]. The specification is listed as in Ratified state [2]. [1]: https://github.com/riscv/riscv-zalasr/tree/v0.9 [2]: https://lf-riscv.atlassian.net/wiki/spaces/HOME/pages/16154882/All+RISC-V+Specifications+Under+Active+Development Reviewed-by: Alistair Francis <alistair.francis@wdc.com> Signed-off-by: Roan Richmond <roan.richmond@codethink.co.uk> Message-ID: <20251112162923.311714-1-roan.richmond@codethink.co.uk> Signed-off-by: Alistair Francis <alistair.francis@wdc.com> --- target/riscv/cpu_cfg_fields.h.inc | 1 + target/riscv/insn32.decode | 10 ++ target/riscv/cpu.c | 2 + target/riscv/translate.c | 1 + target/riscv/insn_trans/trans_rvzalasr.c.inc | 113 +++++++++++++++++++ 5 files changed, 127 insertions(+) create mode 100644 target/riscv/insn_trans/trans_rvzalasr.c.inc diff --git a/target/riscv/cpu_cfg_fields.h.inc b/target/riscv/cpu_cfg_fields.h.inc index XXXXXXX..XXXXXXX 100644 --- a/target/riscv/cpu_cfg_fields.h.inc +++ b/target/riscv/cpu_cfg_fields.h.inc @@ -XXX,XX +XXX,XX @@ BOOL_FIELD(ext_zaamo) BOOL_FIELD(ext_zacas) BOOL_FIELD(ext_zama16b) BOOL_FIELD(ext_zabha) +BOOL_FIELD(ext_zalasr) BOOL_FIELD(ext_zalrsc) BOOL_FIELD(ext_zawrs) BOOL_FIELD(ext_zfa) diff --git a/target/riscv/insn32.decode b/target/riscv/insn32.decode index XXXXXXX..XXXXXXX 100644 --- a/target/riscv/insn32.decode +++ b/target/riscv/insn32.decode @@ -XXX,XX +XXX,XX @@ amominu_h 11000 . . ..... ..... 001 ..... 0101111 @atom_st amomaxu_h 11100 . . ..... ..... 001 ..... 0101111 @atom_st amocas_b 00101 . . ..... ..... 000 ..... 0101111 @atom_st amocas_h 00101 . . ..... ..... 001 ..... 0101111 @atom_st + +# *** Zalasr Standard Extension *** +lb_aqrl 00110 . . ..... ..... 000 ..... 0101111 @atom_st +lh_aqrl 00110 . . ..... ..... 001 ..... 0101111 @atom_st +lw_aqrl 00110 . . ..... ..... 010 ..... 0101111 @atom_st +ld_aqrl 00110 . . ..... ..... 011 ..... 0101111 @atom_st +sb_aqrl 00111 . . ..... ..... 000 ..... 0101111 @atom_st +sh_aqrl 00111 . . ..... ..... 001 ..... 0101111 @atom_st +sw_aqrl 00111 . . ..... ..... 010 ..... 0101111 @atom_st +sd_aqrl 00111 . . ..... ..... 011 ..... 0101111 @atom_st diff --git a/target/riscv/cpu.c b/target/riscv/cpu.c index XXXXXXX..XXXXXXX 100644 --- a/target/riscv/cpu.c +++ b/target/riscv/cpu.c @@ -XXX,XX +XXX,XX @@ const RISCVIsaExtData isa_edata_arr[] = { ISA_EXT_DATA_ENTRY(zaamo, PRIV_VERSION_1_12_0, ext_zaamo), ISA_EXT_DATA_ENTRY(zabha, PRIV_VERSION_1_13_0, ext_zabha), ISA_EXT_DATA_ENTRY(zacas, PRIV_VERSION_1_12_0, ext_zacas), + ISA_EXT_DATA_ENTRY(zalasr, PRIV_VERSION_1_12_0, ext_zalasr), ISA_EXT_DATA_ENTRY(zalrsc, PRIV_VERSION_1_12_0, ext_zalrsc), ISA_EXT_DATA_ENTRY(zama16b, PRIV_VERSION_1_13_0, ext_zama16b), ISA_EXT_DATA_ENTRY(zawrs, PRIV_VERSION_1_12_0, ext_zawrs), @@ -XXX,XX +XXX,XX @@ const RISCVCPUMultiExtConfig riscv_cpu_extensions[] = { MULTI_EXT_CFG_BOOL("zama16b", ext_zama16b, false), MULTI_EXT_CFG_BOOL("zabha", ext_zabha, false), MULTI_EXT_CFG_BOOL("zaamo", ext_zaamo, false), + MULTI_EXT_CFG_BOOL("zalasr", ext_zalasr, false), MULTI_EXT_CFG_BOOL("zalrsc", ext_zalrsc, false), MULTI_EXT_CFG_BOOL("zawrs", ext_zawrs, true), MULTI_EXT_CFG_BOOL("zfa", ext_zfa, true), diff --git a/target/riscv/translate.c b/target/riscv/translate.c index XXXXXXX..XXXXXXX 100644 --- a/target/riscv/translate.c +++ b/target/riscv/translate.c @@ -XXX,XX +XXX,XX @@ static uint32_t opcode_at(DisasContextBase *dcbase, target_ulong pc) #include "insn_trans/trans_rvzicond.c.inc" #include "insn_trans/trans_rvzacas.c.inc" #include "insn_trans/trans_rvzabha.c.inc" +#include "insn_trans/trans_rvzalasr.c.inc" #include "insn_trans/trans_rvzawrs.c.inc" #include "insn_trans/trans_rvzicbo.c.inc" #include "insn_trans/trans_rvzimop.c.inc" diff --git a/target/riscv/insn_trans/trans_rvzalasr.c.inc b/target/riscv/insn_trans/trans_rvzalasr.c.inc new file mode 100644 index XXXXXXX..XXXXXXX --- /dev/null +++ b/target/riscv/insn_trans/trans_rvzalasr.c.inc @@ -XXX,XX +XXX,XX @@ +/* + * RISC-V translation routines for the ZALASR (Load-Aquire and Store-Release) + * Extension. + * + * Copyright (c) 2025 Roan Richmond, roan.richmond@codethink.co.uk + * + * SPDX-License-Identifier: GPL-2.0-or-later + * + * The documentation of the ISA extension can be found here: + * https://github.com/riscv/riscv-zalasr/tree/v0.9 + */ + +#define REQUIRE_ZALASR(ctx) do { \ + if (!ctx->cfg_ptr->ext_zalasr) { \ + return false; \ + } \ +} while (0) + +static bool gen_load_acquire(DisasContext *ctx, arg_lb_aqrl *a, MemOp memop) +{ + decode_save_opc(ctx, 0); + + TCGv addr = get_address(ctx, a->rs1, 0); + TCGv dest = get_gpr(ctx, a->rd, EXT_NONE); + TCGBar bar = (a->rl) ? TCG_BAR_STRL : 0; + + /* Check that AQ is set, as this is mandatory */ + if (!a->aq) { + return false; + } + + memop |= (ctx->cfg_ptr->ext_zama16b) ? MO_ATOM_WITHIN16 : 0; + + tcg_gen_qemu_ld_tl(dest, addr, ctx->mem_idx, memop); + gen_set_gpr(ctx, a->rd, dest); + + /* Add a memory barrier implied by AQ (mandatory) and RL (optional) */ + tcg_gen_mb(TCG_MO_ALL | TCG_BAR_LDAQ | bar); + + return true; +} + +static bool trans_lb_aqrl(DisasContext *ctx, arg_lb_aqrl *a) +{ + REQUIRE_ZALASR(ctx); + return gen_load_acquire(ctx, a, (MO_ALIGN | MO_SB)); +} + +static bool trans_lh_aqrl(DisasContext *ctx, arg_lh_aqrl *a) +{ + REQUIRE_ZALASR(ctx); + return gen_load_acquire(ctx, a, (MO_ALIGN | MO_TESW)); +} + +static bool trans_lw_aqrl(DisasContext *ctx, arg_lw_aqrl *a) +{ + REQUIRE_ZALASR(ctx); + return gen_load_acquire(ctx, a, (MO_ALIGN | MO_TESL)); +} + +static bool trans_ld_aqrl(DisasContext *ctx, arg_ld_aqrl *a) +{ + REQUIRE_64BIT(ctx); + REQUIRE_ZALASR(ctx); + return gen_load_acquire(ctx, a, (MO_ALIGN | MO_TEUQ)); +} + +static bool gen_store_release(DisasContext *ctx, arg_sb_aqrl *a, MemOp memop) +{ + decode_save_opc(ctx, 0); + + TCGv addr = get_address(ctx, a->rs1, 0); + TCGv data = get_gpr(ctx, a->rs2, EXT_NONE); + TCGBar bar = (a->aq) ? TCG_BAR_LDAQ : 0; + + /* Check that RL is set, as this is mandatory */ + if (!a->rl) { + return false; + } + + memop |= (ctx->cfg_ptr->ext_zama16b) ? MO_ATOM_WITHIN16 : 0; + + /* Add a memory barrier implied by RL (mandatory) and AQ (optional) */ + tcg_gen_mb(TCG_MO_ALL | TCG_BAR_STRL | bar); + + tcg_gen_qemu_st_tl(data, addr, ctx->mem_idx, memop); + return true; +} + +static bool trans_sb_aqrl(DisasContext *ctx, arg_sb_aqrl *a) +{ + REQUIRE_ZALASR(ctx); + return gen_store_release(ctx, a, (MO_ALIGN | MO_SB)); +} + +static bool trans_sh_aqrl(DisasContext *ctx, arg_sh_aqrl *a) +{ + REQUIRE_ZALASR(ctx); + return gen_store_release(ctx, a, (MO_ALIGN | MO_TESW)); +} + +static bool trans_sw_aqrl(DisasContext *ctx, arg_sw_aqrl *a) +{ + REQUIRE_ZALASR(ctx); + return gen_store_release(ctx, a, (MO_ALIGN | MO_TESL)); +} + +static bool trans_sd_aqrl(DisasContext *ctx, arg_sd_aqrl *a) +{ + REQUIRE_64BIT(ctx); + REQUIRE_ZALASR(ctx); + return gen_store_release(ctx, a, (MO_ALIGN | MO_TEUQ)); +} -- 2.52.0
From: Djordje Todorovic <Djordje.Todorovic@htecgroup.com> Add a new function, so we can change reset vector from platforms during runtime. Signed-off-by: Chao-ying Fu <cfu@mips.com> Signed-off-by: Djordje Todorovic <djordje.todorovic@htecgroup.com> Reviewed-by: Daniel Henrique Barboza <dbarboza@ventanamicro.com> Reviewed-by: Alistair Francis <alistair.francis@wdc.com> Message-ID: <20260108134128.2218102-2-djordje.todorovic@htecgroup.com> Signed-off-by: Alistair Francis <alistair.francis@wdc.com> --- target/riscv/cpu.h | 4 ++++ target/riscv/cpu.c | 16 ++++++++++++++++ 2 files changed, 20 insertions(+) diff --git a/target/riscv/cpu.h b/target/riscv/cpu.h index XXXXXXX..XXXXXXX 100644 --- a/target/riscv/cpu.h +++ b/target/riscv/cpu.h @@ -XXX,XX +XXX,XX @@ G_NORETURN void riscv_raise_exception(CPURISCVState *env, target_ulong riscv_cpu_get_fflags(CPURISCVState *env); void riscv_cpu_set_fflags(CPURISCVState *env, target_ulong); +#ifndef CONFIG_USER_ONLY +void cpu_set_exception_base(int vp_index, target_ulong address); +#endif + FIELD(TB_FLAGS, MEM_IDX, 0, 3) FIELD(TB_FLAGS, FS, 3, 2) /* Vector flags */ diff --git a/target/riscv/cpu.c b/target/riscv/cpu.c index XXXXXXX..XXXXXXX 100644 --- a/target/riscv/cpu.c +++ b/target/riscv/cpu.c @@ -XXX,XX +XXX,XX @@ bool riscv_cpu_option_set(const char *optname) return g_hash_table_contains(general_user_opts, optname); } +#ifndef CONFIG_USER_ONLY +/* This is used in runtime only. */ +void cpu_set_exception_base(int vp_index, target_ulong address) +{ + RISCVCPU *cpu; + CPUState *cs = qemu_get_cpu(vp_index); + if (cs == NULL) { + qemu_log_mask(LOG_GUEST_ERROR, + "cpu_set_exception_base: invalid vp_index: %u", + vp_index); + } + cpu = RISCV_CPU(cs); + cpu->env.resetvec = address; +} +#endif + static void riscv_cpu_cfg_merge(RISCVCPUConfig *dest, const RISCVCPUConfig *src) { #define BOOL_FIELD(x) dest->x |= src->x; -- 2.52.0
From: Djordje Todorovic <Djordje.Todorovic@htecgroup.com> Introduce P8700 CPU by MIPS. Signed-off-by: Chao-ying Fu <cfu@mips.com> Signed-off-by: Djordje Todorovic <djordje.todorovic@htecgroup.com> Reviewed-by: Daniel Henrique Barboza <dbarboza@ventanamicro.com> Reviewed-by: Alistair Francis <alistair.francis@wdc.com> Message-ID: <20260108134128.2218102-3-djordje.todorovic@htecgroup.com> Signed-off-by: Alistair Francis <alistair.francis@wdc.com> --- target/riscv/cpu-qom.h | 1 + target/riscv/cpu_vendorid.h | 1 + target/riscv/cpu.c | 16 ++++++++++++++++ 3 files changed, 18 insertions(+) diff --git a/target/riscv/cpu-qom.h b/target/riscv/cpu-qom.h index XXXXXXX..XXXXXXX 100644 --- a/target/riscv/cpu-qom.h +++ b/target/riscv/cpu-qom.h @@ -XXX,XX +XXX,XX @@ #define TYPE_RISCV_CPU_TT_ASCALON RISCV_CPU_TYPE_NAME("tt-ascalon") #define TYPE_RISCV_CPU_XIANGSHAN_NANHU RISCV_CPU_TYPE_NAME("xiangshan-nanhu") #define TYPE_RISCV_CPU_XIANGSHAN_KMH RISCV_CPU_TYPE_NAME("xiangshan-kunminghu") +#define TYPE_RISCV_CPU_MIPS_P8700 RISCV_CPU_TYPE_NAME("mips-p8700") #define TYPE_RISCV_CPU_HOST RISCV_CPU_TYPE_NAME("host") OBJECT_DECLARE_CPU_TYPE(RISCVCPU, RISCVCPUClass, RISCV_CPU) diff --git a/target/riscv/cpu_vendorid.h b/target/riscv/cpu_vendorid.h index XXXXXXX..XXXXXXX 100644 --- a/target/riscv/cpu_vendorid.h +++ b/target/riscv/cpu_vendorid.h @@ -XXX,XX +XXX,XX @@ #define TARGET_RISCV_CPU_VENDORID_H #define THEAD_VENDOR_ID 0x5b7 +#define MIPS_VENDOR_ID 0x127 #define VEYRON_V1_MARCHID 0x8000000000010000 #define VEYRON_V1_MIMPID 0x111 diff --git a/target/riscv/cpu.c b/target/riscv/cpu.c index XXXXXXX..XXXXXXX 100644 --- a/target/riscv/cpu.c +++ b/target/riscv/cpu.c @@ -XXX,XX +XXX,XX @@ static const TypeInfo riscv_cpu_type_infos[] = { .cfg.max_satp_mode = VM_1_10_SV48, ), + /* https://mips.com/products/hardware/p8700/ */ + DEFINE_RISCV_CPU(TYPE_RISCV_CPU_MIPS_P8700, TYPE_RISCV_VENDOR_CPU, + .misa_mxl_max = MXL_RV64, + .misa_ext = RVI | RVM | RVA | RVF | RVD | RVC | RVS | RVU, + .priv_spec = PRIV_VERSION_1_12_0, + .cfg.max_satp_mode = VM_1_10_SV48, + .cfg.ext_zifencei = true, + .cfg.ext_zicsr = true, + .cfg.mmu = true, + .cfg.pmp = true, + .cfg.ext_zba = true, + .cfg.ext_zbb = true, + .cfg.marchid = 0x8000000000000201, + .cfg.mvendorid = MIPS_VENDOR_ID, + ), + #if defined(CONFIG_TCG) && !defined(CONFIG_USER_ONLY) DEFINE_RISCV_CPU(TYPE_RISCV_CPU_BASE128, TYPE_RISCV_DYNAMIC_CPU, .cfg.max_satp_mode = VM_1_10_SV57, -- 2.52.0
From: Djordje Todorovic <Djordje.Todorovic@htecgroup.com> Define MIPS CSRs used for P8700 CPU. Signed-off-by: Chao-ying Fu <cfu@mips.com> Signed-off-by: Djordje Todorovic <djordje.todorovic@htecgroup.com> Reviewed-by: Daniel Henrique Barboza <dbarboza@ventanamicro.com> Reviewed-by: Alistair Francis <alistair.francis@wdc.com> Message-ID: <20260108134128.2218102-4-djordje.todorovic@htecgroup.com> Signed-off-by: Alistair Francis <alistair.francis@wdc.com> --- target/riscv/cpu.h | 3 + target/riscv/cpu.c | 3 + target/riscv/mips_csr.c | 217 +++++++++++++++++++++++++++++++++++++++ target/riscv/meson.build | 1 + 4 files changed, 224 insertions(+) create mode 100644 target/riscv/mips_csr.c diff --git a/target/riscv/cpu.h b/target/riscv/cpu.h index XXXXXXX..XXXXXXX 100644 --- a/target/riscv/cpu.h +++ b/target/riscv/cpu.h @@ -XXX,XX +XXX,XX @@ const char *satp_mode_str(uint8_t satp_mode, bool is_32_bit); /* In th_csr.c */ extern const RISCVCSR th_csr_list[]; +/* Implemented in mips_csr.c */ +extern const RISCVCSR mips_csr_list[]; + const char *priv_spec_to_str(int priv_version); #endif /* RISCV_CPU_H */ diff --git a/target/riscv/cpu.c b/target/riscv/cpu.c index XXXXXXX..XXXXXXX 100644 --- a/target/riscv/cpu.c +++ b/target/riscv/cpu.c @@ -XXX,XX +XXX,XX @@ static const TypeInfo riscv_cpu_type_infos[] = { .cfg.ext_zbb = true, .cfg.marchid = 0x8000000000000201, .cfg.mvendorid = MIPS_VENDOR_ID, +#ifndef CONFIG_USER_ONLY + .custom_csrs = mips_csr_list, +#endif ), #if defined(CONFIG_TCG) && !defined(CONFIG_USER_ONLY) diff --git a/target/riscv/mips_csr.c b/target/riscv/mips_csr.c new file mode 100644 index XXXXXXX..XXXXXXX --- /dev/null +++ b/target/riscv/mips_csr.c @@ -XXX,XX +XXX,XX @@ +/* + * MIPS-specific CSRs. + * + * Copyright (c) 2025 MIPS + * + * SPDX-License-Identifier: GPL-2.0-or-later + * + */ + +#include "qemu/osdep.h" +#include "cpu.h" +#include "cpu_vendorid.h" + +/* Static MIPS CSR state storage */ +static struct { + uint64_t tvec; + uint64_t config[12]; + uint64_t pmacfg[16]; +} mips_csr_state; + +/* MIPS CSR */ +#define CSR_MIPSTVEC 0x7c0 +#define CSR_MIPSCONFIG0 0x7d0 +#define CSR_MIPSCONFIG1 0x7d1 +#define CSR_MIPSCONFIG2 0x7d2 +#define CSR_MIPSCONFIG3 0x7d3 +#define CSR_MIPSCONFIG4 0x7d4 +#define CSR_MIPSCONFIG5 0x7d5 +#define CSR_MIPSCONFIG6 0x7d6 +#define CSR_MIPSCONFIG7 0x7d7 +#define CSR_MIPSCONFIG8 0x7d8 +#define CSR_MIPSCONFIG9 0x7d9 +#define CSR_MIPSCONFIG10 0x7da +#define CSR_MIPSCONFIG11 0x7db +#define CSR_MIPSPMACFG0 0x7e0 +#define CSR_MIPSPMACFG1 0x7e1 +#define CSR_MIPSPMACFG2 0x7e2 +#define CSR_MIPSPMACFG3 0x7e3 +#define CSR_MIPSPMACFG4 0x7e4 +#define CSR_MIPSPMACFG5 0x7e5 +#define CSR_MIPSPMACFG6 0x7e6 +#define CSR_MIPSPMACFG7 0x7e7 +#define CSR_MIPSPMACFG8 0x7e8 +#define CSR_MIPSPMACFG9 0x7e9 +#define CSR_MIPSPMACFG10 0x7ea +#define CSR_MIPSPMACFG11 0x7eb +#define CSR_MIPSPMACFG12 0x7ec +#define CSR_MIPSPMACFG13 0x7ed +#define CSR_MIPSPMACFG14 0x7ee +#define CSR_MIPSPMACFG15 0x7ef + +static RISCVException any(CPURISCVState *env, int csrno) +{ + return RISCV_EXCP_NONE; +} + +static RISCVException read_mipstvec(CPURISCVState *env, int csrno, + target_ulong *val) +{ + *val = mips_csr_state.tvec; + return RISCV_EXCP_NONE; +} + +static RISCVException write_mipstvec(CPURISCVState *env, int csrno, + target_ulong val, uintptr_t ra) +{ + mips_csr_state.tvec = val; + return RISCV_EXCP_NONE; +} + +static RISCVException read_mipsconfig(CPURISCVState *env, int csrno, + target_ulong *val) +{ + *val = mips_csr_state.config[csrno - CSR_MIPSCONFIG0]; + return RISCV_EXCP_NONE; +} + +static RISCVException write_mipsconfig(CPURISCVState *env, int csrno, + target_ulong val, uintptr_t ra) +{ + mips_csr_state.config[csrno - CSR_MIPSCONFIG0] = val; + return RISCV_EXCP_NONE; +} + +static RISCVException read_mipspmacfg(CPURISCVState *env, int csrno, + target_ulong *val) +{ + *val = mips_csr_state.pmacfg[csrno - CSR_MIPSPMACFG0]; + return RISCV_EXCP_NONE; +} + +static RISCVException write_mipspmacfg(CPURISCVState *env, int csrno, + target_ulong val, uintptr_t ra) +{ + mips_csr_state.pmacfg[csrno - CSR_MIPSPMACFG0] = val; + return RISCV_EXCP_NONE; +} + +const RISCVCSR mips_csr_list[] = { + { + .csrno = CSR_MIPSTVEC, + .csr_ops = { "mipstvec", any, read_mipstvec, write_mipstvec } + }, + { + .csrno = CSR_MIPSCONFIG0, + .csr_ops = { "mipsconfig0", any, read_mipsconfig, write_mipsconfig } + }, + { + .csrno = CSR_MIPSCONFIG1, + .csr_ops = { "mipsconfig1", any, read_mipsconfig, write_mipsconfig } + }, + { + .csrno = CSR_MIPSCONFIG2, + .csr_ops = { "mipsconfig2", any, read_mipsconfig, write_mipsconfig } + }, + { + .csrno = CSR_MIPSCONFIG3, + .csr_ops = { "mipsconfig3", any, read_mipsconfig, write_mipsconfig } + }, + { + .csrno = CSR_MIPSCONFIG4, + .csr_ops = { "mipsconfig4", any, read_mipsconfig, write_mipsconfig } + }, + { + .csrno = CSR_MIPSCONFIG5, + .csr_ops = { "mipsconfig5", any, read_mipsconfig, write_mipsconfig } + }, + { + .csrno = CSR_MIPSCONFIG6, + .csr_ops = { "mipsconfig6", any, read_mipsconfig, write_mipsconfig } + }, + { + .csrno = CSR_MIPSCONFIG7, + .csr_ops = { "mipsconfig7", any, read_mipsconfig, write_mipsconfig } + }, + { + .csrno = CSR_MIPSCONFIG8, + .csr_ops = { "mipsconfig8", any, read_mipsconfig, write_mipsconfig } + }, + { + .csrno = CSR_MIPSCONFIG9, + .csr_ops = { "mipsconfig9", any, read_mipsconfig, write_mipsconfig } + }, + { + .csrno = CSR_MIPSCONFIG10, + .csr_ops = { "mipsconfig10", any, read_mipsconfig, write_mipsconfig } + }, + { + .csrno = CSR_MIPSCONFIG11, + .csr_ops = { "mipsconfig11", any, read_mipsconfig, write_mipsconfig } + }, + { + .csrno = CSR_MIPSPMACFG0, + .csr_ops = { "mipspmacfg0", any, read_mipspmacfg, write_mipspmacfg } + }, + { + .csrno = CSR_MIPSPMACFG1, + .csr_ops = { "mipspmacfg1", any, read_mipspmacfg, write_mipspmacfg } + }, + { + .csrno = CSR_MIPSPMACFG2, + .csr_ops = { "mipspmacfg2", any, read_mipspmacfg, write_mipspmacfg } + }, + { + .csrno = CSR_MIPSPMACFG3, + .csr_ops = { "mipspmacfg3", any, read_mipspmacfg, write_mipspmacfg } + }, + { + .csrno = CSR_MIPSPMACFG4, + .csr_ops = { "mipspmacfg4", any, read_mipspmacfg, write_mipspmacfg } + }, + { + .csrno = CSR_MIPSPMACFG5, + .csr_ops = { "mipspmacfg5", any, read_mipspmacfg, write_mipspmacfg } + }, + { + .csrno = CSR_MIPSPMACFG6, + .csr_ops = { "mipspmacfg6", any, read_mipspmacfg, write_mipspmacfg } + }, + { + .csrno = CSR_MIPSPMACFG7, + .csr_ops = { "mipspmacfg7", any, read_mipspmacfg, write_mipspmacfg } + }, + { + .csrno = CSR_MIPSPMACFG8, + .csr_ops = { "mipspmacfg8", any, read_mipspmacfg, write_mipspmacfg } + }, + { + .csrno = CSR_MIPSPMACFG9, + .csr_ops = { "mipspmacfg9", any, read_mipspmacfg, write_mipspmacfg } + }, + { + .csrno = CSR_MIPSPMACFG10, + .csr_ops = { "mipspmacfg10", any, read_mipspmacfg, write_mipspmacfg } + }, + { + .csrno = CSR_MIPSPMACFG11, + .csr_ops = { "mipspmacfg11", any, read_mipspmacfg, write_mipspmacfg } + }, + { + .csrno = CSR_MIPSPMACFG12, + .csr_ops = { "mipspmacfg12", any, read_mipspmacfg, write_mipspmacfg } + }, + { + .csrno = CSR_MIPSPMACFG13, + .csr_ops = { "mipspmacfg13", any, read_mipspmacfg, write_mipspmacfg } + }, + { + .csrno = CSR_MIPSPMACFG14, + .csr_ops = { "mipspmacfg14", any, read_mipspmacfg, write_mipspmacfg } + }, + { + .csrno = CSR_MIPSPMACFG15, + .csr_ops = { "mipspmacfg15", any, read_mipspmacfg, write_mipspmacfg } + }, + { }, +}; diff --git a/target/riscv/meson.build b/target/riscv/meson.build index XXXXXXX..XXXXXXX 100644 --- a/target/riscv/meson.build +++ b/target/riscv/meson.build @@ -XXX,XX +XXX,XX @@ riscv_system_ss.add(files( 'debug.c', 'monitor.c', 'machine.c', + 'mips_csr.c', 'pmu.c', 'th_csr.c', 'time_helper.c', -- 2.52.0
From: Djordje Todorovic <Djordje.Todorovic@htecgroup.com> Add mips.ccmov defined by Xmipscmov. Signed-off-by: Chao-ying Fu <cfu@mips.com> Signed-off-by: Djordje Todorovic <djordje.todorovic@htecgroup.com> Acked-by: Daniel Henrique Barboza <dbarboza@ventanamicro.com> Acked-by: Alistair Francis <alistair.francis@wdc.com> Message-ID: <20260108134128.2218102-5-djordje.todorovic@htecgroup.com> Signed-off-by: Alistair Francis <alistair.francis@wdc.com> --- target/riscv/cpu_cfg.h | 5 ++++ target/riscv/cpu_cfg_fields.h.inc | 1 + target/riscv/xmips.decode | 11 ++++++++ target/riscv/cpu.c | 3 +++ target/riscv/translate.c | 3 +++ target/riscv/insn_trans/trans_xmips.c.inc | 33 +++++++++++++++++++++++ target/riscv/meson.build | 1 + 7 files changed, 57 insertions(+) create mode 100644 target/riscv/xmips.decode create mode 100644 target/riscv/insn_trans/trans_xmips.c.inc diff --git a/target/riscv/cpu_cfg.h b/target/riscv/cpu_cfg.h index XXXXXXX..XXXXXXX 100644 --- a/target/riscv/cpu_cfg.h +++ b/target/riscv/cpu_cfg.h @@ -XXX,XX +XXX,XX @@ static inline bool always_true_p(const RISCVCPUConfig *cfg __attribute__((__unus return true; } +static inline bool has_xmips_p(const RISCVCPUConfig *cfg) +{ + return cfg->ext_xmipscmov; +} + static inline bool has_xthead_p(const RISCVCPUConfig *cfg) { return cfg->ext_xtheadba || cfg->ext_xtheadbb || diff --git a/target/riscv/cpu_cfg_fields.h.inc b/target/riscv/cpu_cfg_fields.h.inc index XXXXXXX..XXXXXXX 100644 --- a/target/riscv/cpu_cfg_fields.h.inc +++ b/target/riscv/cpu_cfg_fields.h.inc @@ -XXX,XX +XXX,XX @@ BOOL_FIELD(ext_xtheadmemidx) BOOL_FIELD(ext_xtheadmempair) BOOL_FIELD(ext_xtheadsync) BOOL_FIELD(ext_XVentanaCondOps) +BOOL_FIELD(ext_xmipscmov) BOOL_FIELD(mmu) BOOL_FIELD(pmp) diff --git a/target/riscv/xmips.decode b/target/riscv/xmips.decode new file mode 100644 index XXXXXXX..XXXXXXX --- /dev/null +++ b/target/riscv/xmips.decode @@ -XXX,XX +XXX,XX @@ +# +# RISC-V translation routines for the MIPS extension +# +# Copyright (c) 2025 MIPS +# +# SPDX-License-Identifier: GPL-2.0-or-later +# +# Reference: MIPS P8700 instructions +# (https://mips.com/products/hardware/p8700/) + +ccmov rs3:5 11 rs2:5 rs1:5 011 rd:5 0001011 diff --git a/target/riscv/cpu.c b/target/riscv/cpu.c index XXXXXXX..XXXXXXX 100644 --- a/target/riscv/cpu.c +++ b/target/riscv/cpu.c @@ -XXX,XX +XXX,XX @@ const RISCVIsaExtData isa_edata_arr[] = { ISA_EXT_DATA_ENTRY(svrsw60t59b, PRIV_VERSION_1_13_0, ext_svrsw60t59b), ISA_EXT_DATA_ENTRY(svukte, PRIV_VERSION_1_13_0, ext_svukte), ISA_EXT_DATA_ENTRY(svvptc, PRIV_VERSION_1_13_0, ext_svvptc), + ISA_EXT_DATA_ENTRY(xmipscmov, PRIV_VERSION_1_12_0, ext_xmipscmov), ISA_EXT_DATA_ENTRY(xtheadba, PRIV_VERSION_1_11_0, ext_xtheadba), ISA_EXT_DATA_ENTRY(xtheadbb, PRIV_VERSION_1_11_0, ext_xtheadbb), ISA_EXT_DATA_ENTRY(xtheadbs, PRIV_VERSION_1_11_0, ext_xtheadbs), @@ -XXX,XX +XXX,XX @@ const RISCVCPUMultiExtConfig riscv_cpu_vendor_exts[] = { MULTI_EXT_CFG_BOOL("xtheadmempair", ext_xtheadmempair, false), MULTI_EXT_CFG_BOOL("xtheadsync", ext_xtheadsync, false), MULTI_EXT_CFG_BOOL("xventanacondops", ext_XVentanaCondOps, false), + MULTI_EXT_CFG_BOOL("xmipscmov", ext_xmipscmov, false), { }, }; @@ -XXX,XX +XXX,XX @@ static const TypeInfo riscv_cpu_type_infos[] = { .cfg.pmp = true, .cfg.ext_zba = true, .cfg.ext_zbb = true, + .cfg.ext_xmipscmov = true, .cfg.marchid = 0x8000000000000201, .cfg.mvendorid = MIPS_VENDOR_ID, #ifndef CONFIG_USER_ONLY diff --git a/target/riscv/translate.c b/target/riscv/translate.c index XXXXXXX..XXXXXXX 100644 --- a/target/riscv/translate.c +++ b/target/riscv/translate.c @@ -XXX,XX +XXX,XX @@ static uint32_t opcode_at(DisasContextBase *dcbase, target_ulong pc) #include "insn_trans/trans_svinval.c.inc" #include "insn_trans/trans_rvbf16.c.inc" #include "decode-xthead.c.inc" +#include "decode-xmips.c.inc" #include "insn_trans/trans_xthead.c.inc" #include "insn_trans/trans_xventanacondops.c.inc" +#include "insn_trans/trans_xmips.c.inc" /* Include the auto-generated decoder for 16 bit insn */ #include "decode-insn16.c.inc" @@ -XXX,XX +XXX,XX @@ static uint32_t opcode_at(DisasContextBase *dcbase, target_ulong pc) const RISCVDecoder decoder_table[] = { { always_true_p, decode_insn32 }, + { has_xmips_p, decode_xmips}, { has_xthead_p, decode_xthead}, { has_XVentanaCondOps_p, decode_XVentanaCodeOps}, }; diff --git a/target/riscv/insn_trans/trans_xmips.c.inc b/target/riscv/insn_trans/trans_xmips.c.inc new file mode 100644 index XXXXXXX..XXXXXXX --- /dev/null +++ b/target/riscv/insn_trans/trans_xmips.c.inc @@ -XXX,XX +XXX,XX @@ +/* + * RISC-V translation routines for the MIPS extensions (xmips*). + * + * Copyright (c) 2025 MIPS + * + * SPDX-License-Identifier: GPL-2.0-or-later + * + * Reference: MIPS P8700 instructions + * (https://mips.com/products/hardware/p8700/) + */ + +#define REQUIRE_XMIPSCMOV(ctx) do { \ + if (!ctx->cfg_ptr->ext_xmipscmov) { \ + return false; \ + } \ +} while (0) + +/* Conditional move by MIPS. */ +static bool trans_ccmov(DisasContext *ctx, arg_ccmov *a) +{ + REQUIRE_XMIPSCMOV(ctx); + + TCGv zero, source1, source2, source3; + zero = tcg_constant_tl(0); + source1 = get_gpr(ctx, a->rs1, EXT_NONE); + source2 = get_gpr(ctx, a->rs2, EXT_NONE); + source3 = get_gpr(ctx, a->rs3, EXT_NONE); + + tcg_gen_movcond_tl(TCG_COND_NE, cpu_gpr[a->rd], + source2, zero, source1, source3); + + return true; +} diff --git a/target/riscv/meson.build b/target/riscv/meson.build index XXXXXXX..XXXXXXX 100644 --- a/target/riscv/meson.build +++ b/target/riscv/meson.build @@ -XXX,XX +XXX,XX @@ gen = [ decodetree.process('insn32.decode', extra_args: '--static-decode=decode_insn32'), decodetree.process('xthead.decode', extra_args: '--static-decode=decode_xthead'), decodetree.process('XVentanaCondOps.decode', extra_args: '--static-decode=decode_XVentanaCodeOps'), + decodetree.process('xmips.decode', extra_args: '--static-decode=decode_xmips'), ] riscv_ss = ss.source_set() -- 2.52.0
From: Djordje Todorovic <Djordje.Todorovic@htecgroup.com> Add MIPS P8700 prefetch instruction defined by Xmipscbop. Signed-off-by: Chao-ying Fu <cfu@mips.com> Signed-off-by: Djordje Todorovic <djordje.todorovic@htecgroup.com> Reviewed-by: Daniel Henrique Barboza <dbarboza@ventanamicro.com> Acked-by: Alistair Francis <alistair.francis@wdc.com> Message-ID: <20260108134128.2218102-6-djordje.todorovic@htecgroup.com> Signed-off-by: Alistair Francis <alistair.francis@wdc.com> --- target/riscv/cpu_cfg.h | 2 +- target/riscv/cpu_cfg_fields.h.inc | 1 + target/riscv/xmips.decode | 1 + target/riscv/cpu.c | 3 +++ target/riscv/insn_trans/trans_xmips.c.inc | 15 +++++++++++++++ 5 files changed, 21 insertions(+), 1 deletion(-) diff --git a/target/riscv/cpu_cfg.h b/target/riscv/cpu_cfg.h index XXXXXXX..XXXXXXX 100644 --- a/target/riscv/cpu_cfg.h +++ b/target/riscv/cpu_cfg.h @@ -XXX,XX +XXX,XX @@ static inline bool always_true_p(const RISCVCPUConfig *cfg __attribute__((__unus static inline bool has_xmips_p(const RISCVCPUConfig *cfg) { - return cfg->ext_xmipscmov; + return cfg->ext_xmipscbop || cfg->ext_xmipscmov; } static inline bool has_xthead_p(const RISCVCPUConfig *cfg) diff --git a/target/riscv/cpu_cfg_fields.h.inc b/target/riscv/cpu_cfg_fields.h.inc index XXXXXXX..XXXXXXX 100644 --- a/target/riscv/cpu_cfg_fields.h.inc +++ b/target/riscv/cpu_cfg_fields.h.inc @@ -XXX,XX +XXX,XX @@ BOOL_FIELD(ext_xtheadmemidx) BOOL_FIELD(ext_xtheadmempair) BOOL_FIELD(ext_xtheadsync) BOOL_FIELD(ext_XVentanaCondOps) +BOOL_FIELD(ext_xmipscbop) BOOL_FIELD(ext_xmipscmov) BOOL_FIELD(mmu) diff --git a/target/riscv/xmips.decode b/target/riscv/xmips.decode index XXXXXXX..XXXXXXX 100644 --- a/target/riscv/xmips.decode +++ b/target/riscv/xmips.decode @@ -XXX,XX +XXX,XX @@ # (https://mips.com/products/hardware/p8700/) ccmov rs3:5 11 rs2:5 rs1:5 011 rd:5 0001011 +pref 000 imm_9:9 rs1:5 000 imm_hint:5 0001011 diff --git a/target/riscv/cpu.c b/target/riscv/cpu.c index XXXXXXX..XXXXXXX 100644 --- a/target/riscv/cpu.c +++ b/target/riscv/cpu.c @@ -XXX,XX +XXX,XX @@ const RISCVIsaExtData isa_edata_arr[] = { ISA_EXT_DATA_ENTRY(svrsw60t59b, PRIV_VERSION_1_13_0, ext_svrsw60t59b), ISA_EXT_DATA_ENTRY(svukte, PRIV_VERSION_1_13_0, ext_svukte), ISA_EXT_DATA_ENTRY(svvptc, PRIV_VERSION_1_13_0, ext_svvptc), + ISA_EXT_DATA_ENTRY(xmipscbop, PRIV_VERSION_1_12_0, ext_xmipscbop), ISA_EXT_DATA_ENTRY(xmipscmov, PRIV_VERSION_1_12_0, ext_xmipscmov), ISA_EXT_DATA_ENTRY(xtheadba, PRIV_VERSION_1_11_0, ext_xtheadba), ISA_EXT_DATA_ENTRY(xtheadbb, PRIV_VERSION_1_11_0, ext_xtheadbb), @@ -XXX,XX +XXX,XX @@ const RISCVCPUMultiExtConfig riscv_cpu_vendor_exts[] = { MULTI_EXT_CFG_BOOL("xtheadmempair", ext_xtheadmempair, false), MULTI_EXT_CFG_BOOL("xtheadsync", ext_xtheadsync, false), MULTI_EXT_CFG_BOOL("xventanacondops", ext_XVentanaCondOps, false), + MULTI_EXT_CFG_BOOL("xmipscbop", ext_xmipscbop, false), MULTI_EXT_CFG_BOOL("xmipscmov", ext_xmipscmov, false), { }, @@ -XXX,XX +XXX,XX @@ static const TypeInfo riscv_cpu_type_infos[] = { .cfg.pmp = true, .cfg.ext_zba = true, .cfg.ext_zbb = true, + .cfg.ext_xmipscbop = true, .cfg.ext_xmipscmov = true, .cfg.marchid = 0x8000000000000201, .cfg.mvendorid = MIPS_VENDOR_ID, diff --git a/target/riscv/insn_trans/trans_xmips.c.inc b/target/riscv/insn_trans/trans_xmips.c.inc index XXXXXXX..XXXXXXX 100644 --- a/target/riscv/insn_trans/trans_xmips.c.inc +++ b/target/riscv/insn_trans/trans_xmips.c.inc @@ -XXX,XX +XXX,XX @@ * (https://mips.com/products/hardware/p8700/) */ +#define REQUIRE_XMIPSCBOP(ctx) do { \ + if (!ctx->cfg_ptr->ext_xmipscbop) { \ + return false; \ + } \ +} while (0) + #define REQUIRE_XMIPSCMOV(ctx) do { \ if (!ctx->cfg_ptr->ext_xmipscmov) { \ return false; \ @@ -XXX,XX +XXX,XX @@ static bool trans_ccmov(DisasContext *ctx, arg_ccmov *a) return true; } + +/* Move data from memory into cache. */ +static bool trans_pref(DisasContext *ctx, arg_pref *a) +{ + REQUIRE_XMIPSCBOP(ctx); + + /* Nop */ + return true; +} -- 2.52.0
From: Djordje Todorovic <Djordje.Todorovic@htecgroup.com> Add MIPS P8700 ldp, lwp, sdp, swp instructions. Signed-off-by: Chao-ying Fu <cfu@mips.com> Signed-off-by: Djordje Todorovic <djordje.todorovic@htecgroup.com> Acked-by: Daniel Henrique Barboza <dbarboza@ventanamicro.com> Acked-by: Alistair Francis <alistair.francis@wdc.com> Message-ID: <20260108134128.2218102-7-djordje.todorovic@htecgroup.com> Signed-off-by: Alistair Francis <alistair.francis@wdc.com> --- target/riscv/cpu_cfg.h | 2 +- target/riscv/cpu_cfg_fields.h.inc | 1 + target/riscv/xmips.decode | 23 ++++++ target/riscv/cpu.c | 3 + target/riscv/insn_trans/trans_xmips.c.inc | 88 +++++++++++++++++++++++ 5 files changed, 116 insertions(+), 1 deletion(-) diff --git a/target/riscv/cpu_cfg.h b/target/riscv/cpu_cfg.h index XXXXXXX..XXXXXXX 100644 --- a/target/riscv/cpu_cfg.h +++ b/target/riscv/cpu_cfg.h @@ -XXX,XX +XXX,XX @@ static inline bool always_true_p(const RISCVCPUConfig *cfg __attribute__((__unus static inline bool has_xmips_p(const RISCVCPUConfig *cfg) { - return cfg->ext_xmipscbop || cfg->ext_xmipscmov; + return cfg->ext_xmipscbop || cfg->ext_xmipscmov || cfg->ext_xmipslsp; } static inline bool has_xthead_p(const RISCVCPUConfig *cfg) diff --git a/target/riscv/cpu_cfg_fields.h.inc b/target/riscv/cpu_cfg_fields.h.inc index XXXXXXX..XXXXXXX 100644 --- a/target/riscv/cpu_cfg_fields.h.inc +++ b/target/riscv/cpu_cfg_fields.h.inc @@ -XXX,XX +XXX,XX @@ BOOL_FIELD(ext_xtheadsync) BOOL_FIELD(ext_XVentanaCondOps) BOOL_FIELD(ext_xmipscbop) BOOL_FIELD(ext_xmipscmov) +BOOL_FIELD(ext_xmipslsp) BOOL_FIELD(mmu) BOOL_FIELD(pmp) diff --git a/target/riscv/xmips.decode b/target/riscv/xmips.decode index XXXXXXX..XXXXXXX 100644 --- a/target/riscv/xmips.decode +++ b/target/riscv/xmips.decode @@ -XXX,XX +XXX,XX @@ # Reference: MIPS P8700 instructions # (https://mips.com/products/hardware/p8700/) +# Fields +%rs3 27:5 +%rs2 20:5 +%rs1 15:5 +%rd 7:5 +%imm_9 20:9 +%imm_hint 7:5 +%imm_v 25:2 9:3 !function=ex_shift_2 +%imm_w 25:2 10:2 !function=ex_shift_3 +%imm_x 22:5 !function=ex_shift_2 +%imm_y 23:4 !function=ex_shift_3 + +# Formats +@r4_immv ..... .. ..... ..... ... ... .. ....... %rs2 %rs3 %imm_v %rs1 +@r4_immw ..... .. ..... ..... ... .. ... ....... %rs2 %rs3 %imm_w %rs1 +@r4_immx ..... ..... .. ..... ... ..... ....... %rs3 %imm_x %rs1 %rd +@r4_immy ..... .... ... ..... ... ..... ....... %rs3 %imm_y %rs1 %rd + +# *** RV64 MIPS Extension *** ccmov rs3:5 11 rs2:5 rs1:5 011 rd:5 0001011 pref 000 imm_9:9 rs1:5 000 imm_hint:5 0001011 +ldp ..... .... 000 ..... 100 ..... 0001011 @r4_immy +lwp ..... ..... 01 ..... 100 ..... 0001011 @r4_immx +sdp ..... .. ..... ..... 101 .. 0000001011 @r4_immw +swp ..... .. ..... ..... 101 ... 010001011 @r4_immv diff --git a/target/riscv/cpu.c b/target/riscv/cpu.c index XXXXXXX..XXXXXXX 100644 --- a/target/riscv/cpu.c +++ b/target/riscv/cpu.c @@ -XXX,XX +XXX,XX @@ const RISCVIsaExtData isa_edata_arr[] = { ISA_EXT_DATA_ENTRY(svvptc, PRIV_VERSION_1_13_0, ext_svvptc), ISA_EXT_DATA_ENTRY(xmipscbop, PRIV_VERSION_1_12_0, ext_xmipscbop), ISA_EXT_DATA_ENTRY(xmipscmov, PRIV_VERSION_1_12_0, ext_xmipscmov), + ISA_EXT_DATA_ENTRY(xmipslsp, PRIV_VERSION_1_12_0, ext_xmipslsp), ISA_EXT_DATA_ENTRY(xtheadba, PRIV_VERSION_1_11_0, ext_xtheadba), ISA_EXT_DATA_ENTRY(xtheadbb, PRIV_VERSION_1_11_0, ext_xtheadbb), ISA_EXT_DATA_ENTRY(xtheadbs, PRIV_VERSION_1_11_0, ext_xtheadbs), @@ -XXX,XX +XXX,XX @@ const RISCVCPUMultiExtConfig riscv_cpu_vendor_exts[] = { MULTI_EXT_CFG_BOOL("xventanacondops", ext_XVentanaCondOps, false), MULTI_EXT_CFG_BOOL("xmipscbop", ext_xmipscbop, false), MULTI_EXT_CFG_BOOL("xmipscmov", ext_xmipscmov, false), + MULTI_EXT_CFG_BOOL("xmipslsp", ext_xmipslsp, false), { }, }; @@ -XXX,XX +XXX,XX @@ static const TypeInfo riscv_cpu_type_infos[] = { .cfg.pmp = true, .cfg.ext_zba = true, .cfg.ext_zbb = true, + .cfg.ext_xmipslsp = true, .cfg.ext_xmipscbop = true, .cfg.ext_xmipscmov = true, .cfg.marchid = 0x8000000000000201, diff --git a/target/riscv/insn_trans/trans_xmips.c.inc b/target/riscv/insn_trans/trans_xmips.c.inc index XXXXXXX..XXXXXXX 100644 --- a/target/riscv/insn_trans/trans_xmips.c.inc +++ b/target/riscv/insn_trans/trans_xmips.c.inc @@ -XXX,XX +XXX,XX @@ } \ } while (0) +#define REQUIRE_XMIPSLSP(ctx) do { \ + if (!ctx->cfg_ptr->ext_xmipslsp) { \ + return false; \ + } \ +} while (0) + /* Conditional move by MIPS. */ static bool trans_ccmov(DisasContext *ctx, arg_ccmov *a) { @@ -XXX,XX +XXX,XX @@ static bool trans_ccmov(DisasContext *ctx, arg_ccmov *a) return true; } +/* Load Doubleword Pair. */ +static bool trans_ldp(DisasContext *ctx, arg_ldp *a) +{ + REQUIRE_XMIPSLSP(ctx); + REQUIRE_64_OR_128BIT(ctx); + + TCGv src = get_gpr(ctx, a->rs1, EXT_NONE); + TCGv dest0 = dest_gpr(ctx, a->rd); + TCGv dest1 = dest_gpr(ctx, a->rs3); + TCGv addr = tcg_temp_new(); + + tcg_gen_addi_tl(addr, src, a->imm_y); + tcg_gen_qemu_ld_tl(dest0, addr, ctx->mem_idx, MO_TESQ); + gen_set_gpr(ctx, a->rd, dest0); + + tcg_gen_addi_tl(addr, addr, 8); + tcg_gen_qemu_ld_tl(dest1, addr, ctx->mem_idx, MO_TESQ); + gen_set_gpr(ctx, a->rs3, dest1); + + return true; +} + +/* Load Word Pair. */ +static bool trans_lwp(DisasContext *ctx, arg_lwp *a) +{ + REQUIRE_XMIPSLSP(ctx); + + TCGv src = get_gpr(ctx, a->rs1, EXT_NONE); + TCGv dest0 = dest_gpr(ctx, a->rd); + TCGv dest1 = dest_gpr(ctx, a->rs3); + TCGv addr = tcg_temp_new(); + + tcg_gen_addi_tl(addr, src, a->imm_x); + tcg_gen_qemu_ld_tl(dest0, addr, ctx->mem_idx, MO_TESL); + gen_set_gpr(ctx, a->rd, dest0); + + tcg_gen_addi_tl(addr, addr, 4); + tcg_gen_qemu_ld_tl(dest1, addr, ctx->mem_idx, MO_TESL); + gen_set_gpr(ctx, a->rs3, dest1); + + return true; +} + +/* Store Doubleword Pair. */ +static bool trans_sdp(DisasContext *ctx, arg_sdp *a) +{ + REQUIRE_XMIPSLSP(ctx); + REQUIRE_64_OR_128BIT(ctx); + + TCGv src = get_gpr(ctx, a->rs1, EXT_NONE); + TCGv data0 = get_gpr(ctx, a->rs2, EXT_NONE); + TCGv data1 = get_gpr(ctx, a->rs3, EXT_NONE); + TCGv addr = tcg_temp_new(); + + tcg_gen_addi_tl(addr, src, a->imm_w); + tcg_gen_qemu_st_tl(data0, addr, ctx->mem_idx, MO_TEUQ); + + tcg_gen_addi_tl(addr, addr, 8); + tcg_gen_qemu_st_tl(data1, addr, ctx->mem_idx, MO_TEUQ); + + return true; +} + +/* Store Word Pair. */ +static bool trans_swp(DisasContext *ctx, arg_swp *a) +{ + REQUIRE_XMIPSLSP(ctx); + + TCGv src = get_gpr(ctx, a->rs1, EXT_NONE); + TCGv data0 = get_gpr(ctx, a->rs2, EXT_NONE); + TCGv data1 = get_gpr(ctx, a->rs3, EXT_NONE); + TCGv addr = tcg_temp_new(); + + tcg_gen_addi_tl(addr, src, a->imm_v); + tcg_gen_qemu_st_tl(data0, addr, ctx->mem_idx, MO_TESL); + + tcg_gen_addi_tl(addr, addr, 4); + tcg_gen_qemu_st_tl(data1, addr, ctx->mem_idx, MO_TESL); + + return true; +} + /* Move data from memory into cache. */ static bool trans_pref(DisasContext *ctx, arg_pref *a) { -- 2.52.0
From: Djordje Todorovic <Djordje.Todorovic@htecgroup.com> Add RISC-V implementation of the Coherent Manager Global Control Register (CMGCR) device. It is based on the existing MIPS CMGCR implementation but adapted for RISC-V systems. The CMGCR device provides global system control for multi-core configurations in RISC-V systems. This is needed for the MIPS BOSTON AIA board. Signed-off-by: Chao-ying Fu <cfu@mips.com> Signed-off-by: Djordje Todorovic <djordje.todorovic@htecgroup.com> Reviewed-by: Daniel Henrique Barboza <dbarboza@ventanamicro.com> Message-ID: <20260108134128.2218102-8-djordje.todorovic@htecgroup.com> Signed-off-by: Alistair Francis <alistair.francis@wdc.com> --- include/hw/misc/riscv_cmgcr.h | 48 +++++++ hw/misc/riscv_cmgcr.c | 243 ++++++++++++++++++++++++++++++++++ hw/misc/Kconfig | 9 ++ hw/misc/meson.build | 2 + 4 files changed, 302 insertions(+) create mode 100644 include/hw/misc/riscv_cmgcr.h create mode 100644 hw/misc/riscv_cmgcr.c diff --git a/include/hw/misc/riscv_cmgcr.h b/include/hw/misc/riscv_cmgcr.h new file mode 100644 index XXXXXXX..XXXXXXX --- /dev/null +++ b/include/hw/misc/riscv_cmgcr.h @@ -XXX,XX +XXX,XX @@ +/* + * Coherent Manager Global Control Register + * + * Copyright (C) 2015 Imagination Technologies + * + * Copyright (C) 2025 MIPS + * + * SPDX-License-Identifier: GPL-2.0-or-later + * + */ + +#ifndef RISCV_CMGCR_H +#define RISCV_CMGCR_H + +#include "hw/core/sysbus.h" +#include "qom/object.h" + +#define TYPE_RISCV_GCR "riscv-gcr" +OBJECT_DECLARE_SIMPLE_TYPE(RISCVGCRState, RISCV_GCR) + +#define GCR_BASE_ADDR 0x1fb80000ULL +#define GCR_MAX_VPS 256 + +typedef struct RISCVGCRVPState RISCVGCRVPState; +struct RISCVGCRVPState { + uint64_t reset_base; +}; + +typedef struct RISCVGCRState RISCVGCRState; +struct RISCVGCRState { + SysBusDevice parent_obj; + + int32_t gcr_rev; + uint32_t cluster_id; + uint32_t num_vps; + uint32_t num_hart; + uint32_t num_core; + hwaddr gcr_base; + MemoryRegion iomem; + MemoryRegion *cpc_mr; + + uint64_t cpc_base; + + /* VP Local/Other Registers */ + RISCVGCRVPState *vps; +}; + +#endif /* RISCV_CMGCR_H */ diff --git a/hw/misc/riscv_cmgcr.c b/hw/misc/riscv_cmgcr.c new file mode 100644 index XXXXXXX..XXXXXXX --- /dev/null +++ b/hw/misc/riscv_cmgcr.c @@ -XXX,XX +XXX,XX @@ +/* + * Coherent Manager Global Control Register + * + * Copyright (C) 2015 Imagination Technologies + * + * Copyright (C) 2025 MIPS + * + * SPDX-License-Identifier: GPL-2.0-or-later + * + * Reference: MIPS P8700 documentation + * (https://mips.com/products/hardware/p8700/) + */ + +#include "qemu/osdep.h" +#include "qemu/log.h" +#include "qemu/module.h" +#include "qapi/error.h" +#include "hw/core/sysbus.h" +#include "migration/vmstate.h" +#include "hw/misc/riscv_cmgcr.h" +#include "hw/core/qdev-properties.h" + +#include "cpu.h" + +#define CM_RESET_VEC 0x1FC00000 +#define GCR_ADDRSPACE_SZ 0x8000 + +/* Offsets to register blocks */ +#define RISCV_GCB_OFS 0x0000 /* Global Control Block */ +#define RISCV_CLCB_OFS 0x2000 /* Core Control Block */ +#define RISCV_CORE_REG_STRIDE 0x100 /* Stride between core-specific registers */ + +/* Global Control Block Register Map */ +#define GCR_CONFIG_OFS 0x0000 +#define GCR_BASE_OFS 0x0008 +#define GCR_REV_OFS 0x0030 +#define GCR_CPC_STATUS_OFS 0x00F0 +#define GCR_L2_CONFIG_OFS 0x0130 + +/* GCR_L2_CONFIG register fields */ +#define GCR_L2_CONFIG_BYPASS_SHF 20 +#define GCR_L2_CONFIG_BYPASS_MSK ((0x1ULL) << GCR_L2_CONFIG_BYPASS_SHF) + +/* GCR_BASE register fields */ +#define GCR_BASE_GCRBASE_MSK 0xffffffff8000ULL + +/* GCR_CPC_BASE register fields */ +#define GCR_CPC_BASE_CPCEN_MSK 1 +#define GCR_CPC_BASE_CPCBASE_MSK 0xFFFFFFFF8000ULL +#define GCR_CPC_BASE_MSK (GCR_CPC_BASE_CPCEN_MSK | GCR_CPC_BASE_CPCBASE_MSK) + +/* GCR_CL_RESETBASE_OFS register fields */ +#define GCR_CL_RESET_BASE_RESETBASE_MSK 0xFFFFFFFFFFFFF000U +#define GCR_CL_RESET_BASE_MSK GCR_CL_RESET_BASE_RESETBASE_MSK + +static inline bool is_cpc_connected(RISCVGCRState *s) +{ + return s->cpc_mr != NULL; +} + +static inline void update_cpc_base(RISCVGCRState *gcr, uint64_t val) +{ + if (is_cpc_connected(gcr)) { + gcr->cpc_base = val & GCR_CPC_BASE_MSK; + memory_region_transaction_begin(); + memory_region_set_address(gcr->cpc_mr, + gcr->cpc_base & GCR_CPC_BASE_CPCBASE_MSK); + memory_region_set_enabled(gcr->cpc_mr, + gcr->cpc_base & GCR_CPC_BASE_CPCEN_MSK); + memory_region_transaction_commit(); + } +} + +static inline void update_gcr_base(RISCVGCRState *gcr, uint64_t val) +{ + gcr->gcr_base = val & GCR_BASE_GCRBASE_MSK; + memory_region_set_address(&gcr->iomem, gcr->gcr_base); + + /* + * For boston-aia, cpc_base is set to gcr_base + 0x8001 to enable + * cpc automatically. + */ + update_cpc_base(gcr, val + 0x8001); +} + +/* Read GCR registers */ +static uint64_t gcr_read(void *opaque, hwaddr addr, unsigned size) +{ + RISCVGCRState *gcr = (RISCVGCRState *) opaque; + + switch (addr) { + /* Global Control Block Register */ + case GCR_CONFIG_OFS: + /* Set PCORES to 0 */ + return 0; + case GCR_BASE_OFS: + return gcr->gcr_base; + case GCR_REV_OFS: + return gcr->gcr_rev; + case GCR_CPC_STATUS_OFS: + return is_cpc_connected(gcr); + case GCR_L2_CONFIG_OFS: + /* L2 BYPASS */ + return GCR_L2_CONFIG_BYPASS_MSK; + default: + qemu_log_mask(LOG_UNIMP, "Read %d bytes at GCR offset 0x%" HWADDR_PRIx + "\n", size, addr); + } + return 0; +} + +static inline target_ulong get_exception_base(RISCVGCRVPState *vps) +{ + return vps->reset_base & GCR_CL_RESET_BASE_RESETBASE_MSK; +} + +/* Write GCR registers */ +static void gcr_write(void *opaque, hwaddr addr, uint64_t data, unsigned size) +{ + RISCVGCRState *gcr = (RISCVGCRState *)opaque; + RISCVGCRVPState *current_vps; + int cpu_index, c, h; + + for (c = 0; c < gcr->num_core; c++) { + for (h = 0; h < gcr->num_hart; h++) { + if (addr == RISCV_CLCB_OFS + c * RISCV_CORE_REG_STRIDE + h * 8) { + cpu_index = c * gcr->num_hart + h; + current_vps = &gcr->vps[cpu_index]; + current_vps->reset_base = data & GCR_CL_RESET_BASE_MSK; + cpu_set_exception_base(cpu_index + gcr->cluster_id * + gcr->num_core * gcr->num_hart, + get_exception_base(current_vps)); + return; + } + } + } + + switch (addr) { + case GCR_BASE_OFS: + update_gcr_base(gcr, data); + break; + default: + qemu_log_mask(LOG_UNIMP, "Write %d bytes at GCR offset 0x%" HWADDR_PRIx + " 0x%" PRIx64 "\n", size, addr, data); + break; + } +} + +static const MemoryRegionOps gcr_ops = { + .read = gcr_read, + .write = gcr_write, + .endianness = DEVICE_LITTLE_ENDIAN, + .impl = { + .max_access_size = 8, + }, +}; + +static void riscv_gcr_init(Object *obj) +{ + SysBusDevice *sbd = SYS_BUS_DEVICE(obj); + RISCVGCRState *s = RISCV_GCR(obj); + + memory_region_init_io(&s->iomem, OBJECT(s), &gcr_ops, s, + "riscv-gcr", GCR_ADDRSPACE_SZ); + sysbus_init_mmio(sbd, &s->iomem); +} + +static void riscv_gcr_reset(DeviceState *dev) +{ + RISCVGCRState *s = RISCV_GCR(dev); + int i; + + /* Update cpc_base to gcr_base + 0x8001 to enable cpc automatically. */ + update_cpc_base(s, s->gcr_base + 0x8001); + + for (i = 0; i < s->num_vps; i++) { + s->vps[i].reset_base = CM_RESET_VEC & GCR_CL_RESET_BASE_MSK; + cpu_set_exception_base(i, get_exception_base(&s->vps[i])); + } +} + +static const VMStateDescription vmstate_riscv_gcr = { + .name = "riscv-gcr", + .version_id = 0, + .minimum_version_id = 0, + .fields = (VMStateField[]) { + VMSTATE_UINT64(cpc_base, RISCVGCRState), + VMSTATE_END_OF_LIST() + }, +}; + +static const Property riscv_gcr_properties[] = { + DEFINE_PROP_UINT32("cluster-id", RISCVGCRState, cluster_id, 0), + DEFINE_PROP_UINT32("num-vp", RISCVGCRState, num_vps, 1), + DEFINE_PROP_UINT32("num-hart", RISCVGCRState, num_hart, 1), + DEFINE_PROP_UINT32("num-core", RISCVGCRState, num_core, 1), + DEFINE_PROP_INT32("gcr-rev", RISCVGCRState, gcr_rev, 0xa00), + DEFINE_PROP_UINT64("gcr-base", RISCVGCRState, gcr_base, GCR_BASE_ADDR), + DEFINE_PROP_LINK("cpc", RISCVGCRState, cpc_mr, TYPE_MEMORY_REGION, + MemoryRegion *), +}; + +static void riscv_gcr_realize(DeviceState *dev, Error **errp) +{ + RISCVGCRState *s = RISCV_GCR(dev); + + /* Validate num_vps */ + if (s->num_vps == 0) { + error_setg(errp, "num-vp must be at least 1"); + return; + } + if (s->num_vps > GCR_MAX_VPS) { + error_setg(errp, "num-vp cannot exceed %d", GCR_MAX_VPS); + return; + } + + /* Create local set of registers for each VP */ + s->vps = g_new(RISCVGCRVPState, s->num_vps); +} + +static void riscv_gcr_class_init(ObjectClass *klass, const void *data) +{ + DeviceClass *dc = DEVICE_CLASS(klass); + device_class_set_props(dc, riscv_gcr_properties); + dc->vmsd = &vmstate_riscv_gcr; + device_class_set_legacy_reset(dc, riscv_gcr_reset); + dc->realize = riscv_gcr_realize; +} + +static const TypeInfo riscv_gcr_info = { + .name = TYPE_RISCV_GCR, + .parent = TYPE_SYS_BUS_DEVICE, + .instance_size = sizeof(RISCVGCRState), + .instance_init = riscv_gcr_init, + .class_init = riscv_gcr_class_init, +}; + +static void riscv_gcr_register_types(void) +{ + type_register_static(&riscv_gcr_info); +} + +type_init(riscv_gcr_register_types) diff --git a/hw/misc/Kconfig b/hw/misc/Kconfig index XXXXXXX..XXXXXXX 100644 --- a/hw/misc/Kconfig +++ b/hw/misc/Kconfig @@ -XXX,XX +XXX,XX @@ config MIPS_ITU bool depends on TCG +config RISCV_MIPS_CMGCR + bool + +config MIPS_BOSTON_AIA + bool + default y + depends on RISCV64 + select RISCV_MIPS_CMGCR + config MPS2_FPGAIO bool select LED diff --git a/hw/misc/meson.build b/hw/misc/meson.build index XXXXXXX..XXXXXXX 100644 --- a/hw/misc/meson.build +++ b/hw/misc/meson.build @@ -XXX,XX +XXX,XX @@ specific_ss.add(when: 'CONFIG_MAC_VIA', if_true: files('mac_via.c')) specific_ss.add(when: 'CONFIG_MIPS_CPS', if_true: files('mips_cmgcr.c', 'mips_cpc.c')) specific_ss.add(when: 'CONFIG_MIPS_ITU', if_true: files('mips_itu.c')) +specific_ss.add(when: 'CONFIG_RISCV_MIPS_CMGCR', if_true: files('riscv_cmgcr.c')) + system_ss.add(when: 'CONFIG_SBSA_REF', if_true: files('sbsa_ec.c')) # HPPA devices -- 2.52.0
From: Djordje Todorovic <Djordje.Todorovic@htecgroup.com> Add RISC-V implementation of the Cluster Power Controller (CPC) device. It is based on the existing MIPS CPC implementations but adapted for RISC-V systems. The CPC device manages power control for CPU clusters in RISC-V systems. This is needed for the MIPS BOSTON AIA board. Signed-off-by: Chao-ying Fu <cfu@mips.com> Signed-off-by: Djordje Todorovic <djordje.todorovic@htecgroup.com> Reviewed-by: Daniel Henrique Barboza <dbarboza@ventanamicro.com> Message-ID: <20260108134128.2218102-9-djordje.todorovic@htecgroup.com> Signed-off-by: Alistair Francis <alistair.francis@wdc.com> --- include/hw/misc/riscv_cpc.h | 64 +++++++++ hw/misc/riscv_cpc.c | 265 ++++++++++++++++++++++++++++++++++++ hw/misc/Kconfig | 4 + hw/misc/meson.build | 1 + 4 files changed, 334 insertions(+) create mode 100644 include/hw/misc/riscv_cpc.h create mode 100644 hw/misc/riscv_cpc.c diff --git a/include/hw/misc/riscv_cpc.h b/include/hw/misc/riscv_cpc.h new file mode 100644 index XXXXXXX..XXXXXXX --- /dev/null +++ b/include/hw/misc/riscv_cpc.h @@ -XXX,XX +XXX,XX @@ +/* + * Cluster Power Controller emulation + * + * Copyright (c) 2016 Imagination Technologies + * + * Copyright (c) 2025 MIPS + * + * SPDX-License-Identifier: GPL-2.0-or-later + * + */ + +#ifndef RISCV_CPC_H +#define RISCV_CPC_H + +#include "hw/core/sysbus.h" +#include "qom/object.h" + +#define CPC_ADDRSPACE_SZ 0x6000 + +/* CPC global register offsets relative to base address */ +#define CPC_MTIME_REG_OFS 0x50 + +#define CPC_CM_STAT_CONF_OFS 0x1008 + +/* CPC blocks offsets relative to base address */ +#define CPC_CL_BASE_OFS 0x2000 +#define CPC_CORE_REG_STRIDE 0x100 /* Stride between core-specific registers */ + +/* CPC register offsets relative to block offsets */ +#define CPC_STAT_CONF_OFS 0x08 +#define CPC_VP_STOP_OFS 0x20 +#define CPC_VP_RUN_OFS 0x28 +#define CPC_VP_RUNNING_OFS 0x30 + +#define SEQ_STATE_BIT 19 +#define SEQ_STATE_U5 0x6 +#define SEQ_STATE_U6 0x7 +#define CPC_Cx_STAT_CONF_SEQ_STATE_U5 (SEQ_STATE_U5 << SEQ_STATE_BIT) +#define CPC_Cx_STAT_CONF_SEQ_STATE_U6 (SEQ_STATE_U6 << SEQ_STATE_BIT) + +#define TYPE_RISCV_CPC "xmips-cpc" +OBJECT_DECLARE_SIMPLE_TYPE(RISCVCPCState, RISCV_CPC) + +typedef struct RISCVCPCState { + SysBusDevice parent_obj; + + uint32_t cluster_id; + uint32_t num_vp; + uint32_t num_hart; + uint32_t num_core; + /* VPs running from restart mask */ + uint64_t vps_start_running_mask; + + MemoryRegion mr; + /* Indicates which VPs are in the run state mask */ + uint64_t vps_running_mask; + + /* Array of CPUs managed by this CPC */ + CPUState **cpus; +} RISCVCPCState; + +#define CPC_MAX_VPS 64 /* Maximum number of VPs supported */ + +#endif /* RISCV_CPC_H */ diff --git a/hw/misc/riscv_cpc.c b/hw/misc/riscv_cpc.c new file mode 100644 index XXXXXXX..XXXXXXX --- /dev/null +++ b/hw/misc/riscv_cpc.c @@ -XXX,XX +XXX,XX @@ +/* + * Cluster Power Controller emulation + * + * Copyright (c) 2016 Imagination Technologies + * + * Copyright (c) 2025 MIPS + * + * SPDX-License-Identifier: GPL-2.0-or-later + * + * Reference: MIPS P8700 documentation + * (https://mips.com/products/hardware/p8700/) + */ + +#include "qemu/osdep.h" +#include "qapi/error.h" +#include "cpu.h" +#include "qemu/log.h" +#include "qemu/module.h" +#include "qemu/timer.h" +#include "qemu/bitops.h" +#include "hw/core/sysbus.h" +#include "migration/vmstate.h" + +#include "hw/misc/riscv_cpc.h" +#include "hw/core/qdev-properties.h" +#include "hw/intc/riscv_aclint.h" +#include "hw/core/resettable.h" + +static inline uint64_t cpc_vp_run_mask(RISCVCPCState *cpc) +{ + return MAKE_64BIT_MASK(0, cpc->num_vp); +} + +static void riscv_cpu_reset_async_work(CPUState *cs, run_on_cpu_data data) +{ + RISCVCPCState *cpc = (RISCVCPCState *) data.host_ptr; + int i; + + cpu_reset(cs); + cs->halted = 0; + + /* Find this CPU's index in the CPC's CPU array */ + for (i = 0; i < cpc->num_vp; i++) { + if (cpc->cpus[i] == cs) { + cpc->vps_running_mask |= BIT_ULL(i); + break; + } + } +} + +static void cpc_run_vp(RISCVCPCState *cpc, uint64_t vps_run_mask) +{ + int vp; + + for (vp = 0; vp < cpc->num_vp; vp++) { + CPUState *cs = cpc->cpus[vp]; + + if (!extract64(vps_run_mask, vp, 1)) { + continue; + } + + if (extract64(cpc->vps_running_mask, vp, 1)) { + continue; + } + + /* + * To avoid racing with a CPU we are just kicking off. + * We do the final bit of preparation for the work in + * the target CPUs context. + */ + async_safe_run_on_cpu(cs, riscv_cpu_reset_async_work, + RUN_ON_CPU_HOST_PTR(cpc)); + } +} + +static void cpc_stop_vp(RISCVCPCState *cpc, uint64_t vps_stop_mask) +{ + int vp; + + for (vp = 0; vp < cpc->num_vp; vp++) { + CPUState *cs = cpc->cpus[vp]; + + if (!extract64(vps_stop_mask, vp, 1)) { + continue; + } + + if (!extract64(cpc->vps_running_mask, vp, 1)) { + continue; + } + + cpu_interrupt(cs, CPU_INTERRUPT_HALT); + cpc->vps_running_mask &= ~BIT_ULL(vp); + } +} + +static void cpc_write(void *opaque, hwaddr offset, uint64_t data, + unsigned size) +{ + RISCVCPCState *s = opaque; + int cpu_index, c; + + for (c = 0; c < s->num_core; c++) { + cpu_index = c * s->num_hart + + s->cluster_id * s->num_core * s->num_hart; + if (offset == + CPC_CL_BASE_OFS + CPC_VP_RUN_OFS + c * CPC_CORE_REG_STRIDE) { + cpc_run_vp(s, (data << cpu_index) & cpc_vp_run_mask(s)); + return; + } + if (offset == + CPC_CL_BASE_OFS + CPC_VP_STOP_OFS + c * CPC_CORE_REG_STRIDE) { + cpc_stop_vp(s, (data << cpu_index) & cpc_vp_run_mask(s)); + return; + } + } + + switch (offset) { + default: + qemu_log_mask(LOG_UNIMP, + "%s: Bad offset 0x%x\n", __func__, (int)offset); + break; + } + + return; +} + +static uint64_t cpc_read(void *opaque, hwaddr offset, unsigned size) +{ + RISCVCPCState *s = opaque; + int c; + + for (c = 0; c < s->num_core; c++) { + if (offset == + CPC_CL_BASE_OFS + CPC_STAT_CONF_OFS + c * CPC_CORE_REG_STRIDE) { + /* Return the state as U6. */ + return CPC_Cx_STAT_CONF_SEQ_STATE_U6; + } + } + + switch (offset) { + case CPC_CM_STAT_CONF_OFS: + return CPC_Cx_STAT_CONF_SEQ_STATE_U5; + case CPC_MTIME_REG_OFS: + return muldiv64(qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL), + RISCV_ACLINT_DEFAULT_TIMEBASE_FREQ, + NANOSECONDS_PER_SECOND); + return 0; + default: + qemu_log_mask(LOG_UNIMP, + "%s: Bad offset 0x%x\n", __func__, (int)offset); + return 0; + } +} + +static const MemoryRegionOps cpc_ops = { + .read = cpc_read, + .write = cpc_write, + .endianness = DEVICE_LITTLE_ENDIAN, + .impl = { + .min_access_size = 8, + }, +}; + +static void riscv_cpc_init(Object *obj) +{ + SysBusDevice *sbd = SYS_BUS_DEVICE(obj); + RISCVCPCState *s = RISCV_CPC(obj); + int i; + + memory_region_init_io(&s->mr, OBJECT(s), &cpc_ops, s, "xmips-cpc", + CPC_ADDRSPACE_SZ); + sysbus_init_mmio(sbd, &s->mr); + + /* Allocate CPU array */ + s->cpus = g_new0(CPUState *, CPC_MAX_VPS); + + /* Create link properties for each possible CPU slot */ + for (i = 0; i < CPC_MAX_VPS; i++) { + char *propname = g_strdup_printf("cpu[%d]", i); + object_property_add_link(obj, propname, TYPE_CPU, + (Object **)&s->cpus[i], + qdev_prop_allow_set_link_before_realize, + OBJ_PROP_LINK_STRONG); + g_free(propname); + } +} + +static void riscv_cpc_realize(DeviceState *dev, Error **errp) +{ + RISCVCPCState *s = RISCV_CPC(dev); + int i; + + if (s->vps_start_running_mask & ~cpc_vp_run_mask(s)) { + error_setg(errp, + "incorrect vps-start-running-mask 0x%" PRIx64 + " for num_vp = %d", + s->vps_start_running_mask, s->num_vp); + return; + } + + /* Verify that required CPUs have been linked */ + for (i = 0; i < s->num_vp; i++) { + if (!s->cpus[i]) { + error_setg(errp, "CPU %d has not been linked", i); + return; + } + } +} + +static void riscv_cpc_reset_hold(Object *obj, ResetType type) +{ + RISCVCPCState *s = RISCV_CPC(obj); + + /* Reflect the fact that all VPs are halted on reset */ + s->vps_running_mask = 0; + + /* Put selected VPs into run state */ + cpc_run_vp(s, s->vps_start_running_mask); +} + +static const VMStateDescription vmstate_riscv_cpc = { + .name = "xmips-cpc", + .version_id = 0, + .minimum_version_id = 0, + .fields = (VMStateField[]) { + VMSTATE_UINT64(vps_running_mask, RISCVCPCState), + VMSTATE_END_OF_LIST() + }, +}; + +static const Property riscv_cpc_properties[] = { + DEFINE_PROP_UINT32("cluster-id", RISCVCPCState, cluster_id, 0x0), + DEFINE_PROP_UINT32("num-vp", RISCVCPCState, num_vp, 0x1), + DEFINE_PROP_UINT32("num-hart", RISCVCPCState, num_hart, 0x1), + DEFINE_PROP_UINT32("num-core", RISCVCPCState, num_core, 0x1), + DEFINE_PROP_UINT64("vps-start-running-mask", RISCVCPCState, + vps_start_running_mask, 0x1), +}; + +static void riscv_cpc_class_init(ObjectClass *klass, const void *data) +{ + DeviceClass *dc = DEVICE_CLASS(klass); + ResettableClass *rc = RESETTABLE_CLASS(klass); + + dc->realize = riscv_cpc_realize; + rc->phases.hold = riscv_cpc_reset_hold; + dc->vmsd = &vmstate_riscv_cpc; + device_class_set_props(dc, riscv_cpc_properties); + dc->user_creatable = false; +} + +static const TypeInfo riscv_cpc_info = { + .name = TYPE_RISCV_CPC, + .parent = TYPE_SYS_BUS_DEVICE, + .instance_size = sizeof(RISCVCPCState), + .instance_init = riscv_cpc_init, + .class_init = riscv_cpc_class_init, +}; + +static void riscv_cpc_register_types(void) +{ + type_register_static(&riscv_cpc_info); +} + +type_init(riscv_cpc_register_types) diff --git a/hw/misc/Kconfig b/hw/misc/Kconfig index XXXXXXX..XXXXXXX 100644 --- a/hw/misc/Kconfig +++ b/hw/misc/Kconfig @@ -XXX,XX +XXX,XX @@ config MIPS_ITU config RISCV_MIPS_CMGCR bool +config RISCV_MIPS_CPC + bool + config MIPS_BOSTON_AIA bool default y depends on RISCV64 select RISCV_MIPS_CMGCR + select RISCV_MIPS_CPC config MPS2_FPGAIO bool diff --git a/hw/misc/meson.build b/hw/misc/meson.build index XXXXXXX..XXXXXXX 100644 --- a/hw/misc/meson.build +++ b/hw/misc/meson.build @@ -XXX,XX +XXX,XX @@ specific_ss.add(when: 'CONFIG_MIPS_CPS', if_true: files('mips_cmgcr.c', 'mips_cp specific_ss.add(when: 'CONFIG_MIPS_ITU', if_true: files('mips_itu.c')) specific_ss.add(when: 'CONFIG_RISCV_MIPS_CMGCR', if_true: files('riscv_cmgcr.c')) +specific_ss.add(when: 'CONFIG_RISCV_MIPS_CPC', if_true: files('riscv_cpc.c')) system_ss.add(when: 'CONFIG_SBSA_REF', if_true: files('sbsa_ec.c')) -- 2.52.0
From: Djordje Todorovic <Djordje.Todorovic@htecgroup.com> Add support for the Coherent Processing System for RISC-V. This enables SMP support for RISC-V boards that require cache-coherent multiprocessor systems. Signed-off-by: Chao-ying Fu <cfu@mips.com> Signed-off-by: Djordje Todorovic <djordje.todorovic@htecgroup.com> Acked-by: Daniel Henrique Barboza <dbarboza@ventanamicro.com> Message-ID: <20260108134128.2218102-10-djordje.todorovic@htecgroup.com> Signed-off-by: Alistair Francis <alistair.francis@wdc.com> --- include/hw/riscv/cps.h | 66 ++++++++++++++ hw/riscv/cps.c | 196 +++++++++++++++++++++++++++++++++++++++++ hw/misc/Kconfig | 4 + hw/riscv/meson.build | 2 + 4 files changed, 268 insertions(+) create mode 100644 include/hw/riscv/cps.h create mode 100644 hw/riscv/cps.c diff --git a/include/hw/riscv/cps.h b/include/hw/riscv/cps.h new file mode 100644 index XXXXXXX..XXXXXXX --- /dev/null +++ b/include/hw/riscv/cps.h @@ -XXX,XX +XXX,XX @@ +/* + * Coherent Processing System emulation. + * + * Copyright (c) 2016 Imagination Technologies + * + * Copyright (c) 2025 MIPS + * + * SPDX-License-Identifier: GPL-2.0-or-later + * + */ + +#ifndef RISCV_CPS_H +#define RISCV_CPS_H + +#include "hw/core/sysbus.h" +#include "hw/misc/riscv_cmgcr.h" +#include "hw/misc/riscv_cpc.h" +#include "target/riscv/cpu.h" +#include "qom/object.h" + +#define TYPE_RISCV_CPS "riscv-cps" +OBJECT_DECLARE_SIMPLE_TYPE(RISCVCPSState, RISCV_CPS) + +/* The model supports up to 64 harts. */ +#define MAX_HARTS 64 + +/* The global CM base for the boston-aia model. */ +#define GLOBAL_CM_BASE 0x16100000 +/* The CM block is 512 KiB. */ +#define CM_SIZE (1 << 19) + +/* + * The mhartid bits has cluster at bit 16, core at bit 4, and hart at + * bit 0. + */ + +#define MHARTID_CLUSTER_SHIFT 16 +#define MHARTID_CORE_SHIFT 4 +#define MHARTID_HART_SHIFT 0 + +#define APLIC_NUM_SOURCES 0x35 /* Arbitray maximum number of interrupts. */ +#define APLIC_NUM_PRIO_BITS 3 +#define AIA_PLIC_M_OFFSET 0x40000 +#define AIA_PLIC_M_SIZE 0x8000 +#define AIA_PLIC_S_OFFSET 0x60000 +#define AIA_PLIC_S_SIZE 0x8000 +#define AIA_CLINT_OFFSET 0x50000 + +typedef struct RISCVCPSState { + SysBusDevice parent_obj; + + uint32_t num_vp; + uint32_t num_hart; + uint32_t num_core; + uint64_t gcr_base; + char *cpu_type; + + MemoryRegion container; + RISCVGCRState gcr; + RISCVCPCState cpc; + + DeviceState *aplic; + CPUState **cpus; +} RISCVCPSState; + +#endif diff --git a/hw/riscv/cps.c b/hw/riscv/cps.c new file mode 100644 index XXXXXXX..XXXXXXX --- /dev/null +++ b/hw/riscv/cps.c @@ -XXX,XX +XXX,XX @@ +/* + * Coherent Processing System emulation. + * + * Copyright (c) 2016 Imagination Technologies + * + * Copyright (c) 2025 MIPS + * + * SPDX-License-Identifier: GPL-2.0-or-later + * + */ + +#include "qemu/osdep.h" +#include "qapi/error.h" +#include "qemu/module.h" +#include "hw/riscv/cps.h" +#include "hw/core/qdev-properties.h" +#include "system/reset.h" +#include "hw/intc/riscv_aclint.h" +#include "hw/intc/riscv_aplic.h" +#include "hw/intc/riscv_imsic.h" +#include "hw/pci/msi.h" + +static void riscv_cps_init(Object *obj) +{ + SysBusDevice *sbd = SYS_BUS_DEVICE(obj); + RISCVCPSState *s = RISCV_CPS(obj); + + /* + * Cover entire address space as there do not seem to be any + * constraints for the base address of CPC . + */ + memory_region_init(&s->container, obj, "mips-cps-container", UINT64_MAX); + sysbus_init_mmio(sbd, &s->container); +} + +static void main_cpu_reset(void *opaque) +{ + CPUState *cs = opaque; + + cpu_reset(cs); +} + +static void riscv_cps_realize(DeviceState *dev, Error **errp) +{ + RISCVCPSState *s = RISCV_CPS(dev); + RISCVCPU *cpu; + int i; + + /* Validate num_vp */ + if (s->num_vp == 0) { + error_setg(errp, "num-vp must be at least 1"); + return; + } + if (s->num_vp > MAX_HARTS) { + error_setg(errp, "num-vp cannot exceed %d", MAX_HARTS); + return; + } + + /* Allocate CPU array */ + s->cpus = g_new0(CPUState *, s->num_vp); + + /* Set up cpu_index and mhartid for avaiable CPUs. */ + int harts_in_cluster = s->num_hart * s->num_core; + int num_of_clusters = s->num_vp / harts_in_cluster; + for (i = 0; i < s->num_vp; i++) { + cpu = RISCV_CPU(object_new(s->cpu_type)); + + /* All VPs are halted on reset. Leave powering up to CPC. */ + object_property_set_bool(OBJECT(cpu), "start-powered-off", true, + &error_abort); + + if (!qdev_realize_and_unref(DEVICE(cpu), NULL, errp)) { + return; + } + + /* Store CPU in array */ + s->cpus[i] = CPU(cpu); + + /* Set up mhartid */ + int cluster_id = i / harts_in_cluster; + int hart_id = (i % harts_in_cluster) % s->num_hart; + int core_id = (i % harts_in_cluster) / s->num_hart; + int mhartid = (cluster_id << MHARTID_CLUSTER_SHIFT) + + (core_id << MHARTID_CORE_SHIFT) + + (hart_id << MHARTID_HART_SHIFT); + cpu->env.mhartid = mhartid; + qemu_register_reset(main_cpu_reset, s->cpus[i]); + } + + /* Cluster Power Controller */ + object_initialize_child(OBJECT(dev), "cpc", &s->cpc, TYPE_RISCV_CPC); + object_property_set_uint(OBJECT(&s->cpc), "cluster-id", 0, + &error_abort); + object_property_set_uint(OBJECT(&s->cpc), "num-vp", s->num_vp, + &error_abort); + object_property_set_uint(OBJECT(&s->cpc), "num-hart", s->num_hart, + &error_abort); + object_property_set_uint(OBJECT(&s->cpc), "num-core", s->num_core, + &error_abort); + + /* Pass CPUs to CPC using link properties */ + for (i = 0; i < s->num_vp; i++) { + char *propname = g_strdup_printf("cpu[%d]", i); + object_property_set_link(OBJECT(&s->cpc), propname, + OBJECT(s->cpus[i]), &error_abort); + g_free(propname); + } + + if (!sysbus_realize(SYS_BUS_DEVICE(&s->cpc), errp)) { + return; + } + + memory_region_add_subregion(&s->container, 0, + sysbus_mmio_get_region(SYS_BUS_DEVICE(&s->cpc), 0)); + + /* Global Configuration Registers */ + object_initialize_child(OBJECT(dev), "gcr", &s->gcr, TYPE_RISCV_GCR); + object_property_set_uint(OBJECT(&s->gcr), "cluster-id", 0, + &error_abort); + object_property_set_uint(OBJECT(&s->gcr), "num-vp", s->num_vp, + &error_abort); + object_property_set_int(OBJECT(&s->gcr), "gcr-rev", 0xa00, + &error_abort); + object_property_set_int(OBJECT(&s->gcr), "gcr-base", s->gcr_base, + &error_abort); + object_property_set_link(OBJECT(&s->gcr), "cpc", OBJECT(&s->cpc.mr), + &error_abort); + if (!sysbus_realize(SYS_BUS_DEVICE(&s->gcr), errp)) { + return; + } + + memory_region_add_subregion(&s->container, s->gcr_base, + sysbus_mmio_get_region(SYS_BUS_DEVICE(&s->gcr), 0)); + + for (i = 0; i < num_of_clusters; i++) { + uint64_t cm_base = GLOBAL_CM_BASE + (CM_SIZE * i); + uint32_t hartid_base = i << MHARTID_CLUSTER_SHIFT; + s->aplic = riscv_aplic_create(cm_base + AIA_PLIC_M_OFFSET, + AIA_PLIC_M_SIZE, + hartid_base, /* hartid_base */ + MAX_HARTS, /* num_harts */ + APLIC_NUM_SOURCES, + APLIC_NUM_PRIO_BITS, + false, true, NULL); + riscv_aplic_create(cm_base + AIA_PLIC_S_OFFSET, + AIA_PLIC_S_SIZE, + hartid_base, /* hartid_base */ + MAX_HARTS, /* num_harts */ + APLIC_NUM_SOURCES, + APLIC_NUM_PRIO_BITS, + false, false, s->aplic); + /* PLIC changes msi_nonbroken to ture. We revert the change. */ + msi_nonbroken = false; + riscv_aclint_swi_create(cm_base + AIA_CLINT_OFFSET, + hartid_base, MAX_HARTS, false); + riscv_aclint_mtimer_create(cm_base + AIA_CLINT_OFFSET + + RISCV_ACLINT_SWI_SIZE, + RISCV_ACLINT_DEFAULT_MTIMER_SIZE, + hartid_base, + MAX_HARTS, + RISCV_ACLINT_DEFAULT_MTIMECMP, + RISCV_ACLINT_DEFAULT_MTIME, + RISCV_ACLINT_DEFAULT_TIMEBASE_FREQ, false); + } +} + +static const Property riscv_cps_properties[] = { + DEFINE_PROP_UINT32("num-vp", RISCVCPSState, num_vp, 1), + DEFINE_PROP_UINT32("num-hart", RISCVCPSState, num_hart, 1), + DEFINE_PROP_UINT32("num-core", RISCVCPSState, num_core, 1), + DEFINE_PROP_UINT64("gcr-base", RISCVCPSState, gcr_base, GCR_BASE_ADDR), + DEFINE_PROP_STRING("cpu-type", RISCVCPSState, cpu_type), +}; + +static void riscv_cps_class_init(ObjectClass *klass, const void *data) +{ + DeviceClass *dc = DEVICE_CLASS(klass); + + dc->realize = riscv_cps_realize; + device_class_set_props(dc, riscv_cps_properties); +} + +static const TypeInfo riscv_cps_info = { + .name = TYPE_RISCV_CPS, + .parent = TYPE_SYS_BUS_DEVICE, + .instance_size = sizeof(RISCVCPSState), + .instance_init = riscv_cps_init, + .class_init = riscv_cps_class_init, +}; + +static void riscv_cps_register_types(void) +{ + type_register_static(&riscv_cps_info); +} + +type_init(riscv_cps_register_types) diff --git a/hw/misc/Kconfig b/hw/misc/Kconfig index XXXXXXX..XXXXXXX 100644 --- a/hw/misc/Kconfig +++ b/hw/misc/Kconfig @@ -XXX,XX +XXX,XX @@ config RISCV_MIPS_CMGCR config RISCV_MIPS_CPC bool +config RISCV_MIPS_CPS + bool + config MIPS_BOSTON_AIA bool default y depends on RISCV64 select RISCV_MIPS_CMGCR select RISCV_MIPS_CPC + select RISCV_MIPS_CPS config MPS2_FPGAIO bool diff --git a/hw/riscv/meson.build b/hw/riscv/meson.build index XXXXXXX..XXXXXXX 100644 --- a/hw/riscv/meson.build +++ b/hw/riscv/meson.build @@ -XXX,XX +XXX,XX @@ riscv_ss.add(when: 'CONFIG_RISCV_IOMMU', if_true: files( riscv_ss.add(when: 'CONFIG_MICROBLAZE_V', if_true: files('microblaze-v-generic.c')) riscv_ss.add(when: 'CONFIG_XIANGSHAN_KUNMINGHU', if_true: files('xiangshan_kmh.c')) +riscv_ss.add(when: 'CONFIG_RISCV_MIPS_CPS', if_true: files('cps.c')) + hw_arch += {'riscv': riscv_ss} -- 2.52.0
From: Djordje Todorovic <Djordje.Todorovic@htecgroup.com> The board model supports up to 64 harts with MIPS CPS, MIPS GCR, MIPS CPC, AIA plic, and AIA clint devices. The model can create boot code, if there is no -bios parameter. We can specify -smp x, cores=y,thread=z. Ex: Use 4 cores and 2 threads with each core to have 8 smp cpus as follows. qemu-system-riscv64 -cpu mips-p8700 \ -m 2G -M boston-aia \ -smp 8,cores=4,threads=2 -kernel fw_payload.bin \ -drive file=rootfs.ext2,format=raw -serial stdio Signed-off-by: Chao-ying Fu <cfu@mips.com> Signed-off-by: Djordje Todorovic <djordje.todorovic@htecgroup.com> Acked-by: Daniel Henrique Barboza <dbarboza@ventanamicro.com> Acked-by: Alistair Francis <alistair.francis@wdc.com> Message-ID: <20260108134128.2218102-11-djordje.todorovic@htecgroup.com> Signed-off-by: Alistair Francis <alistair.francis@wdc.com> --- docs/system/riscv/mips.rst | 20 + docs/system/target-riscv.rst | 1 + configs/devices/riscv64-softmmu/default.mak | 1 + hw/riscv/boston-aia.c | 471 ++++++++++++++++++++ hw/riscv/Kconfig | 6 + hw/riscv/meson.build | 1 + 6 files changed, 500 insertions(+) create mode 100644 docs/system/riscv/mips.rst create mode 100644 hw/riscv/boston-aia.c diff --git a/docs/system/riscv/mips.rst b/docs/system/riscv/mips.rst new file mode 100644 index XXXXXXX..XXXXXXX --- /dev/null +++ b/docs/system/riscv/mips.rst @@ -XXX,XX +XXX,XX @@ +Boards for RISC-V Processors by MIPS +==================================== + +RISC-V processors developed by MIPS support Boston-aia board model. The board +model supports up to 64 harts with MIPS CPS, MIPS GCR, MIPS CPC, AIA plic, +and AIA clint devices. The model can create boot code, if there is no +```-bios``` parameter. Also, we can specify ```-smp x,cores=y,thread=z```. + +Running Linux kernel +-------------------- + +For example, to use 4 cores and 2 threads with each core to have 8 smp cpus, +that runs on the ```mips-p8700``` CPU, run qemu as follows: + +.. code-block:: bash + + qemu-system-riscv64 -cpu mips-p8700 \ + -m 2G -M boston-aia \ + -smp 8,cores=4,threads=2 -kernel fw_payload.bin \ + -drive file=rootfs.ext2,format=raw -serial stdio diff --git a/docs/system/target-riscv.rst b/docs/system/target-riscv.rst index XXXXXXX..XXXXXXX 100644 --- a/docs/system/target-riscv.rst +++ b/docs/system/target-riscv.rst @@ -XXX,XX +XXX,XX @@ undocumented; you can get a complete list by running riscv/microblaze-v-generic riscv/microchip-icicle-kit + riscv/mips riscv/shakti-c riscv/sifive_u riscv/virt diff --git a/configs/devices/riscv64-softmmu/default.mak b/configs/devices/riscv64-softmmu/default.mak index XXXXXXX..XXXXXXX 100644 --- a/configs/devices/riscv64-softmmu/default.mak +++ b/configs/devices/riscv64-softmmu/default.mak @@ -XXX,XX +XXX,XX @@ # CONFIG_MICROCHIP_PFSOC=n # CONFIG_SHAKTI_C=n # CONFIG_XIANGSHAN_KUNMINGHU=n +# CONFIG_MIPS_BOSTON_AIA=n diff --git a/hw/riscv/boston-aia.c b/hw/riscv/boston-aia.c new file mode 100644 index XXXXXXX..XXXXXXX --- /dev/null +++ b/hw/riscv/boston-aia.c @@ -XXX,XX +XXX,XX @@ +/* + * MIPS Boston-aia development board emulation. + * + * Copyright (c) 2016 Imagination Technologies + * + * Copyright (c) 2025 MIPS + * + * SPDX-License-Identifier: GPL-2.0-or-later + * + */ + +#include "qemu/osdep.h" +#include "qemu/units.h" + +#include "hw/core/boards.h" +#include "hw/char/serial-mm.h" +#include "hw/ide/pci.h" +#include "hw/ide/ahci-pci.h" +#include "hw/core/loader.h" +#include "hw/riscv/cps.h" +#include "hw/pci-host/xilinx-pcie.h" +#include "hw/core/qdev-properties.h" +#include "qapi/error.h" +#include "qemu/error-report.h" +#include "qemu/log.h" +#include "chardev/char.h" +#include "system/address-spaces.h" +#include "system/device_tree.h" +#include "system/system.h" +#include "system/qtest.h" +#include "system/runstate.h" + +#include <libfdt.h> +#include "qom/object.h" + +#define TYPE_MIPS_BOSTON_AIA "mips-boston-aia" +typedef struct BostonState BostonState; +DECLARE_INSTANCE_CHECKER(BostonState, BOSTON, + TYPE_MIPS_BOSTON_AIA) + +enum { + BOSTON_PCIE2, + BOSTON_PCIE2_MMIO, + BOSTON_PLATREG, + BOSTON_UART, + BOSTON_LCD, + BOSTON_FLASH, + BOSTON_HIGHDDR, +}; + +static const MemMapEntry boston_memmap[] = { + [BOSTON_PCIE2] = { 0x14000000, 0x2000000 }, + [BOSTON_PCIE2_MMIO] = { 0x16000000, 0x100000 }, + [BOSTON_PLATREG] = { 0x17ffd000, 0x1000 }, + [BOSTON_UART] = { 0x17ffe000, 0x20 }, + [BOSTON_LCD] = { 0x17fff000, 0x8 }, + [BOSTON_FLASH] = { 0x18000000, 0x8000000 }, + [BOSTON_HIGHDDR] = { 0x80000000, 0x0 }, +}; + +/* Interrupt numbers for APLIC. */ +#define UART_INT 4 +#define PCIE2_INT 7 + +struct BostonState { + SysBusDevice parent_obj; + + MachineState *mach; + RISCVCPSState cps; + SerialMM *uart; + + CharFrontend lcd_display; + char lcd_content[8]; + bool lcd_inited; +}; + +enum boston_plat_reg { + PLAT_FPGA_BUILD = 0x00, + PLAT_CORE_CL = 0x04, + PLAT_WRAPPER_CL = 0x08, + PLAT_SYSCLK_STATUS = 0x0c, + PLAT_SOFTRST_CTL = 0x10, +#define PLAT_SOFTRST_CTL_SYSRESET (1 << 4) + PLAT_DDR3_STATUS = 0x14, +#define PLAT_DDR3_STATUS_LOCKED (1 << 0) +#define PLAT_DDR3_STATUS_CALIBRATED (1 << 2) +#define PLAT_DDR3_INTERFACE_RESET (1 << 3) + PLAT_PCIE_STATUS = 0x18, +#define PLAT_PCIE_STATUS_PCIE0_LOCKED (1 << 0) +#define PLAT_PCIE_STATUS_PCIE1_LOCKED (1 << 8) +#define PLAT_PCIE_STATUS_PCIE2_LOCKED (1 << 16) + PLAT_FLASH_CTL = 0x1c, + PLAT_SPARE0 = 0x20, + PLAT_SPARE1 = 0x24, + PLAT_SPARE2 = 0x28, + PLAT_SPARE3 = 0x2c, + PLAT_MMCM_DIV = 0x30, +#define PLAT_MMCM_DIV_CLK0DIV_SHIFT 0 +#define PLAT_MMCM_DIV_INPUT_SHIFT 8 +#define PLAT_MMCM_DIV_MUL_SHIFT 16 +#define PLAT_MMCM_DIV_CLK1DIV_SHIFT 24 + PLAT_BUILD_CFG = 0x34, +#define PLAT_BUILD_CFG_IOCU_EN (1 << 0) +#define PLAT_BUILD_CFG_PCIE0_EN (1 << 1) +#define PLAT_BUILD_CFG_PCIE1_EN (1 << 2) +#define PLAT_BUILD_CFG_PCIE2_EN (1 << 3) + PLAT_DDR_CFG = 0x38, +#define PLAT_DDR_CFG_SIZE (0xf << 0) +#define PLAT_DDR_CFG_MHZ (0xfff << 4) + PLAT_NOC_PCIE0_ADDR = 0x3c, + PLAT_NOC_PCIE1_ADDR = 0x40, + PLAT_NOC_PCIE2_ADDR = 0x44, + PLAT_SYS_CTL = 0x48, +}; + +static void boston_lcd_event(void *opaque, QEMUChrEvent event) +{ + BostonState *s = opaque; + if (event == CHR_EVENT_OPENED && !s->lcd_inited) { + qemu_chr_fe_printf(&s->lcd_display, " "); + s->lcd_inited = true; + } +} + +static uint64_t boston_lcd_read(void *opaque, hwaddr addr, + unsigned size) +{ + BostonState *s = opaque; + uint64_t val = 0; + + switch (size) { + case 8: + val |= (uint64_t)s->lcd_content[(addr + 7) & 0x7] << 56; + val |= (uint64_t)s->lcd_content[(addr + 6) & 0x7] << 48; + val |= (uint64_t)s->lcd_content[(addr + 5) & 0x7] << 40; + val |= (uint64_t)s->lcd_content[(addr + 4) & 0x7] << 32; + /* fall through */ + case 4: + val |= (uint64_t)s->lcd_content[(addr + 3) & 0x7] << 24; + val |= (uint64_t)s->lcd_content[(addr + 2) & 0x7] << 16; + /* fall through */ + case 2: + val |= (uint64_t)s->lcd_content[(addr + 1) & 0x7] << 8; + /* fall through */ + case 1: + val |= (uint64_t)s->lcd_content[(addr + 0) & 0x7]; + break; + } + + return val; +} + +static void boston_lcd_write(void *opaque, hwaddr addr, + uint64_t val, unsigned size) +{ + BostonState *s = opaque; + + switch (size) { + case 8: + s->lcd_content[(addr + 7) & 0x7] = val >> 56; + s->lcd_content[(addr + 6) & 0x7] = val >> 48; + s->lcd_content[(addr + 5) & 0x7] = val >> 40; + s->lcd_content[(addr + 4) & 0x7] = val >> 32; + /* fall through */ + case 4: + s->lcd_content[(addr + 3) & 0x7] = val >> 24; + s->lcd_content[(addr + 2) & 0x7] = val >> 16; + /* fall through */ + case 2: + s->lcd_content[(addr + 1) & 0x7] = val >> 8; + /* fall through */ + case 1: + s->lcd_content[(addr + 0) & 0x7] = val; + break; + } + + qemu_chr_fe_printf(&s->lcd_display, + "\r%-8.8s", s->lcd_content); +} + +static const MemoryRegionOps boston_lcd_ops = { + .read = boston_lcd_read, + .write = boston_lcd_write, + .endianness = DEVICE_LITTLE_ENDIAN, +}; + +static uint64_t boston_platreg_read(void *opaque, hwaddr addr, + unsigned size) +{ + BostonState *s = opaque; + uint32_t gic_freq, val; + + switch (addr & 0xffff) { + case PLAT_FPGA_BUILD: + case PLAT_CORE_CL: + case PLAT_WRAPPER_CL: + return 0; + case PLAT_DDR3_STATUS: + return PLAT_DDR3_STATUS_LOCKED | PLAT_DDR3_STATUS_CALIBRATED + | PLAT_DDR3_INTERFACE_RESET; + case PLAT_MMCM_DIV: + gic_freq = 25000000 / 1000000; + val = gic_freq << PLAT_MMCM_DIV_INPUT_SHIFT; + val |= 1 << PLAT_MMCM_DIV_MUL_SHIFT; + val |= 1 << PLAT_MMCM_DIV_CLK0DIV_SHIFT; + val |= 1 << PLAT_MMCM_DIV_CLK1DIV_SHIFT; + return val; + case PLAT_BUILD_CFG: + val = PLAT_BUILD_CFG_PCIE0_EN; + val |= PLAT_BUILD_CFG_PCIE1_EN; + val |= PLAT_BUILD_CFG_PCIE2_EN; + return val; + case PLAT_DDR_CFG: + val = s->mach->ram_size / GiB; + assert(!(val & ~PLAT_DDR_CFG_SIZE)); + val |= PLAT_DDR_CFG_MHZ; + return val; + default: + qemu_log_mask(LOG_UNIMP, "Read platform register 0x%" HWADDR_PRIx "\n", + addr & 0xffff); + return 0; + } +} + +static void boston_platreg_write(void *opaque, hwaddr addr, + uint64_t val, unsigned size) +{ + if (size != 4) { + qemu_log_mask(LOG_UNIMP, "%uB platform register write\n", size); + return; + } + + switch (addr & 0xffff) { + case PLAT_FPGA_BUILD: + case PLAT_CORE_CL: + case PLAT_WRAPPER_CL: + case PLAT_DDR3_STATUS: + case PLAT_PCIE_STATUS: + case PLAT_MMCM_DIV: + case PLAT_BUILD_CFG: + case PLAT_DDR_CFG: + /* read only */ + break; + case PLAT_SOFTRST_CTL: + if (val & PLAT_SOFTRST_CTL_SYSRESET) { + qemu_system_reset_request(SHUTDOWN_CAUSE_GUEST_RESET); + } + break; + default: + qemu_log_mask(LOG_UNIMP, "Write platform register 0x%" HWADDR_PRIx + " = 0x%" PRIx64 "\n", addr & 0xffff, val); + break; + } +} + +static const MemoryRegionOps boston_platreg_ops = { + .read = boston_platreg_read, + .write = boston_platreg_write, + .endianness = DEVICE_LITTLE_ENDIAN, + .impl = { + .min_access_size = 4, + .max_access_size = 4, + }, +}; + +static const TypeInfo boston_device = { + .name = TYPE_MIPS_BOSTON_AIA, + .parent = TYPE_SYS_BUS_DEVICE, + .instance_size = sizeof(BostonState), +}; + +static void boston_register_types(void) +{ + type_register_static(&boston_device); +} +type_init(boston_register_types) + +#define NUM_INSNS 6 +static void gen_firmware(uint32_t *p) +{ + int i; + uint32_t reset_vec[NUM_INSNS] = { + /* CM relocate */ + 0x1fb802b7, /* li t0,0x1fb80000 */ + 0x16100337, /* li t1,0x16100000 */ + 0x0062b423, /* sd t1,8(t0) */ + /* Jump to 0x80000000 */ + 0x00100293, /* li t0,1 */ + 0x01f29293, /* slli t0,t0,1f */ + 0x00028067 /* jr t0 */ + }; + + for (i = 0; i < NUM_INSNS; i++) { + *p++ = reset_vec[i]; + } +} + +static inline XilinxPCIEHost * +xilinx_pcie_init(MemoryRegion *sys_mem, uint32_t bus_nr, + hwaddr cfg_base, uint64_t cfg_size, + hwaddr mmio_base, uint64_t mmio_size, + qemu_irq irq) +{ + DeviceState *dev; + MemoryRegion *cfg, *mmio; + + dev = qdev_new(TYPE_XILINX_PCIE_HOST); + + qdev_prop_set_uint32(dev, "bus_nr", bus_nr); + qdev_prop_set_uint64(dev, "cfg_base", cfg_base); + qdev_prop_set_uint64(dev, "cfg_size", cfg_size); + qdev_prop_set_uint64(dev, "mmio_base", mmio_base); + qdev_prop_set_uint64(dev, "mmio_size", mmio_size); + + sysbus_realize_and_unref(SYS_BUS_DEVICE(dev), &error_fatal); + + cfg = sysbus_mmio_get_region(SYS_BUS_DEVICE(dev), 0); + memory_region_add_subregion_overlap(sys_mem, cfg_base, cfg, 0); + + mmio = sysbus_mmio_get_region(SYS_BUS_DEVICE(dev), 1); + memory_region_add_subregion_overlap(sys_mem, 0, mmio, 0); + + qdev_connect_gpio_out_named(dev, "interrupt_out", 0, irq); + + return XILINX_PCIE_HOST(dev); +} + +static void boston_mach_init(MachineState *machine) +{ + DeviceState *dev; + BostonState *s; + MemoryRegion *flash, *ddr_low_alias, *lcd, *platreg; + MemoryRegion *sys_mem = get_system_memory(); + XilinxPCIEHost *pcie2; + PCIDevice *pdev; + AHCIPCIState *ich9; + DriveInfo *hd[6]; + Chardev *chr; + int fw_size; + + if ((machine->ram_size % GiB) || + (machine->ram_size > (4 * GiB))) { + error_report("Memory size must be 1GB, 2GB, 3GB, or 4GB"); + exit(1); + } + + if (machine->smp.cpus / machine->smp.cores / machine->smp.threads > 1) { + error_report( + "Invalid -smp x,cores=y,threads=z. The max number of clusters " + "supported is 1"); + exit(1); + } + + dev = qdev_new(TYPE_MIPS_BOSTON_AIA); + sysbus_realize_and_unref(SYS_BUS_DEVICE(dev), &error_fatal); + + s = BOSTON(dev); + s->mach = machine; + + object_initialize_child(OBJECT(machine), "cps", &s->cps, TYPE_RISCV_CPS); + object_property_set_str(OBJECT(&s->cps), "cpu-type", machine->cpu_type, + &error_fatal); + object_property_set_uint(OBJECT(&s->cps), "num-vp", machine->smp.cpus, + &error_fatal); + object_property_set_uint(OBJECT(&s->cps), "num-hart", machine->smp.threads, + &error_fatal); + object_property_set_uint(OBJECT(&s->cps), "num-core", machine->smp.cores, + &error_fatal); + object_property_set_uint(OBJECT(&s->cps), "gcr-base", GCR_BASE_ADDR, + &error_fatal); + sysbus_realize(SYS_BUS_DEVICE(&s->cps), &error_fatal); + + sysbus_mmio_map_overlap(SYS_BUS_DEVICE(&s->cps), 0, 0, 1); + + flash = g_new(MemoryRegion, 1); + memory_region_init_rom(flash, NULL, "boston.flash", + boston_memmap[BOSTON_FLASH].size, &error_fatal); + memory_region_add_subregion_overlap(sys_mem, + boston_memmap[BOSTON_FLASH].base, + flash, 0); + + memory_region_add_subregion_overlap(sys_mem, + boston_memmap[BOSTON_HIGHDDR].base, + machine->ram, 0); + + ddr_low_alias = g_new(MemoryRegion, 1); + memory_region_init_alias(ddr_low_alias, NULL, "boston_low.ddr", + machine->ram, 0, + MIN(machine->ram_size, (256 * MiB))); + memory_region_add_subregion_overlap(sys_mem, 0, ddr_low_alias, 0); + + pcie2 = xilinx_pcie_init(sys_mem, 2, + boston_memmap[BOSTON_PCIE2].base, + boston_memmap[BOSTON_PCIE2].size, + boston_memmap[BOSTON_PCIE2_MMIO].base, + boston_memmap[BOSTON_PCIE2_MMIO].size, + qdev_get_gpio_in(s->cps.aplic, PCIE2_INT)); + + platreg = g_new(MemoryRegion, 1); + memory_region_init_io(platreg, NULL, &boston_platreg_ops, s, + "boston-platregs", + boston_memmap[BOSTON_PLATREG].size); + memory_region_add_subregion_overlap(sys_mem, + boston_memmap[BOSTON_PLATREG].base, platreg, 0); + + s->uart = serial_mm_init(sys_mem, boston_memmap[BOSTON_UART].base, 2, + qdev_get_gpio_in(s->cps.aplic, UART_INT), 10000000, + serial_hd(0), DEVICE_LITTLE_ENDIAN); + + lcd = g_new(MemoryRegion, 1); + memory_region_init_io(lcd, NULL, &boston_lcd_ops, s, "boston-lcd", 0x8); + memory_region_add_subregion_overlap(sys_mem, + boston_memmap[BOSTON_LCD].base, lcd, 0); + + chr = qemu_chr_new("lcd", "vc:320x240", NULL); + qemu_chr_fe_init(&s->lcd_display, chr, NULL); + qemu_chr_fe_set_handlers(&s->lcd_display, NULL, NULL, + boston_lcd_event, NULL, s, NULL, true); + + pdev = pci_create_simple_multifunction(&PCI_BRIDGE(&pcie2->root)->sec_bus, + PCI_DEVFN(0, 0), TYPE_ICH9_AHCI); + ich9 = ICH9_AHCI(pdev); + g_assert(ARRAY_SIZE(hd) == ich9->ahci.ports); + ide_drive_get(hd, ich9->ahci.ports); + ahci_ide_create_devs(&ich9->ahci, hd); + + if (machine->firmware) { + fw_size = load_image_targphys(machine->firmware, + 0x1fc00000, 4 * MiB, NULL); + if (fw_size == -1) { + error_report("unable to load firmware image '%s'", + machine->firmware); + exit(1); + } + if (machine->kernel_filename) { + fw_size = load_image_targphys(machine->kernel_filename, + 0x80000000, 64 * MiB, NULL); + if (fw_size == -1) { + error_report("unable to load kernel image '%s'", + machine->kernel_filename); + exit(1); + } + } + } else if (machine->kernel_filename) { + fw_size = load_image_targphys(machine->kernel_filename, + 0x80000000, 64 * MiB, NULL); + if (fw_size == -1) { + error_report("unable to load kernel image '%s'", + machine->kernel_filename); + exit(1); + } + + gen_firmware(memory_region_get_ram_ptr(flash) + 0x7c00000); + } else if (!qtest_enabled()) { + error_report("Please provide either a -kernel or -bios argument"); + exit(1); + } +} + +static void boston_mach_class_init(MachineClass *mc) +{ + mc->desc = "MIPS Boston-aia"; + mc->init = boston_mach_init; + mc->block_default_type = IF_IDE; + mc->default_ram_size = 2 * GiB; + mc->default_ram_id = "boston.ddr"; + mc->max_cpus = MAX_HARTS; + mc->default_cpu_type = TYPE_RISCV_CPU_MIPS_P8700; +} + +DEFINE_MACHINE("boston-aia", boston_mach_class_init) diff --git a/hw/riscv/Kconfig b/hw/riscv/Kconfig index XXXXXXX..XXXXXXX 100644 --- a/hw/riscv/Kconfig +++ b/hw/riscv/Kconfig @@ -XXX,XX +XXX,XX @@ config XIANGSHAN_KUNMINGHU select RISCV_APLIC select RISCV_IMSIC select SERIAL_MM + +config MIPS_BOSTON_AIA + bool + default y + select PCI_EXPRESS + select PCI_EXPRESS_XILINX diff --git a/hw/riscv/meson.build b/hw/riscv/meson.build index XXXXXXX..XXXXXXX 100644 --- a/hw/riscv/meson.build +++ b/hw/riscv/meson.build @@ -XXX,XX +XXX,XX @@ riscv_ss.add(when: 'CONFIG_MICROBLAZE_V', if_true: files('microblaze-v-generic.c riscv_ss.add(when: 'CONFIG_XIANGSHAN_KUNMINGHU', if_true: files('xiangshan_kmh.c')) riscv_ss.add(when: 'CONFIG_RISCV_MIPS_CPS', if_true: files('cps.c')) +riscv_ss.add(when: 'CONFIG_MIPS_BOSTON_AIA', if_true: files('boston-aia.c')) hw_arch += {'riscv': riscv_ss} -- 2.52.0
From: Djordje Todorovic <Djordje.Todorovic@htecgroup.com> The Boston AIA board needs a basic GbE NIC. There is no PCH GbE device emulation, so use an `e1000e` instead. We place it in **slot 0, function 1** in order not to conflict with the existing AHCI device in slot 0 func 0. Signed-off-by: Chao-ying Fu <cfu@mips.com> Signed-off-by: Djordje Todorovic <djordje.todorovic@htecgroup.com> Reviewed-by: Daniel Henrique Barboza <dbarboza@ventanamicro.com> Message-ID: <20260108134128.2218102-12-djordje.todorovic@htecgroup.com> Signed-off-by: Alistair Francis <alistair.francis@wdc.com> --- hw/riscv/boston-aia.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/hw/riscv/boston-aia.c b/hw/riscv/boston-aia.c index XXXXXXX..XXXXXXX 100644 --- a/hw/riscv/boston-aia.c +++ b/hw/riscv/boston-aia.c @@ -XXX,XX +XXX,XX @@ static void boston_mach_init(MachineState *machine) ide_drive_get(hd, ich9->ahci.ports); ahci_ide_create_devs(&ich9->ahci, hd); + /* Create e1000e using slot 0 func 1 */ + pci_init_nic_in_slot(&PCI_BRIDGE(&pcie2->root)->sec_bus, "e1000e", NULL, + "00.1"); + pci_init_nic_devices(&PCI_BRIDGE(&pcie2->root)->sec_bus, "e1000e"); + if (machine->firmware) { fw_size = load_image_targphys(machine->firmware, 0x1fc00000, 4 * MiB, NULL); -- 2.52.0
From: Djordje Todorovic <Djordje.Todorovic@htecgroup.com> Add functional test for Boston AIA board. The P8700 RISC-V based CPU by MIPS supports it at the moment. Signed-off-by: Chao-ying Fu <cfu@mips.com> Signed-off-by: Djordje Todorovic <djordje.todorovic@htecgroup.com> Acked-by: Alistair Francis <alistair.francis@wdc.com> Reviewed-by: Thomas Huth <thuth@redhat.com> Message-ID: <20260108134128.2218102-13-djordje.todorovic@htecgroup.com> Signed-off-by: Alistair Francis <alistair.francis@wdc.com> --- tests/functional/riscv64/meson.build | 2 + tests/functional/riscv64/test_boston.py | 123 ++++++++++++++++++++++++ 2 files changed, 125 insertions(+) create mode 100755 tests/functional/riscv64/test_boston.py diff --git a/tests/functional/riscv64/meson.build b/tests/functional/riscv64/meson.build index XXXXXXX..XXXXXXX 100644 --- a/tests/functional/riscv64/meson.build +++ b/tests/functional/riscv64/meson.build @@ -XXX,XX +XXX,XX @@ # SPDX-License-Identifier: GPL-2.0-or-later test_riscv64_timeouts = { + 'boston' : 120, 'tuxrun' : 120, } @@ -XXX,XX +XXX,XX @@ tests_riscv64_system_quick = [ ] tests_riscv64_system_thorough = [ + 'boston', 'sifive_u', 'tuxrun', ] diff --git a/tests/functional/riscv64/test_boston.py b/tests/functional/riscv64/test_boston.py new file mode 100755 index XXXXXXX..XXXXXXX --- /dev/null +++ b/tests/functional/riscv64/test_boston.py @@ -XXX,XX +XXX,XX @@ +#!/usr/bin/env python3 +# +# Boston board test for RISC-V P8700 processor by MIPS +# +# Copyright (c) 2025 MIPS +# +# SPDX-License-Identifier: GPL-2.0-or-later +# + +from qemu_test import QemuSystemTest, Asset +from qemu_test import wait_for_console_pattern + + +class RiscvBostonTest(QemuSystemTest): + """ + Test the boston-aia board with P8700 processor + """ + + ASSET_FW_PAYLOAD = Asset( + 'https://github.com/MIPS/linux-test-downloads/raw/main/p8700/fw_payload.bin', + 'd6f4ae14d0c178c1d0bb38ddf64557536ca8602a588b220729a8aa17caa383aa') + + ASSET_ROOTFS = Asset( + 'https://github.com/MIPS/linux-test-downloads/raw/main/p8700/rootfs.ext2', + 'f937e21b588f0d1d17d10a063053979686897bbbbc5e9617a5582f7c1f48e565') + + def _boot_linux_test(self, smp_count): + """Common setup and boot test for Linux on Boston board + + Args: + smp_count: Number of CPUs to use for SMP + """ + self.set_machine('boston-aia') + fw_payload_path = self.ASSET_FW_PAYLOAD.fetch() + rootfs_path = self.ASSET_ROOTFS.fetch() + + self.vm.add_args('-cpu', 'mips-p8700') + self.vm.add_args('-m', '2G') + self.vm.add_args('-smp', str(smp_count)) + self.vm.add_args('-kernel', fw_payload_path) + self.vm.add_args('-drive', f'file={rootfs_path},format=raw,snapshot=on') + + self.vm.set_console() + self.vm.launch() + + # Wait for OpenSBI + wait_for_console_pattern(self, 'OpenSBI') + + # Wait for Linux kernel boot + wait_for_console_pattern(self, 'Linux version') + wait_for_console_pattern(self, 'Machine model: MIPS P8700') + + # Test e1000e network card functionality + wait_for_console_pattern(self, 'e1000e') + wait_for_console_pattern(self, 'Network Connection') + + # Wait for boot to complete - system reaches login prompt + wait_for_console_pattern(self, 'Run /sbin/init as init process') + + def test_boston_boot_linux_min_cpus(self): + """ + Test Linux kernel boot with minimum CPU count (2) + """ + self._boot_linux_test(smp_count=2) + + def test_boston_boot_linux_7_cpus(self): + """ + Test Linux kernel boot with 7 CPUs + + 7 CPUs is a special configuration that tests odd CPU count + handling and ensures proper core distribution across clusters. + """ + self._boot_linux_test(smp_count=7) + + def test_boston_boot_linux_35_cpus(self): + """ + Test Linux kernel boot with 35 CPUs + + 35 CPUs is a special configuration that tests a non-power-of-2 + CPU count above 32, validating proper handling of larger + asymmetric SMP configurations. + """ + self._boot_linux_test(smp_count=35) + + def test_boston_boot_linux_max_cpus(self): + """ + Test Linux kernel boot with maximum supported CPU count (64) + """ + self._boot_linux_test(smp_count=64) + + def test_boston_invalid_cpu_count(self): + """ + Test that 65 CPUs is rejected as invalid (negative test case) + """ + from subprocess import run, PIPE + + fw_payload_path = self.ASSET_FW_PAYLOAD.fetch() + rootfs_path = self.ASSET_ROOTFS.fetch() + + cmd = [ + self.qemu_bin, + '-M', 'boston-aia', + '-cpu', 'mips-p8700', + '-m', '2G', + '-smp', '65', + '-kernel', fw_payload_path, + '-drive', f'file={rootfs_path},format=raw,snapshot=on', + '-nographic' + ] + + # Run QEMU and expect it to fail immediately. + result = run(cmd, capture_output=True, text=True, timeout=5) + + # Check that QEMU exited with error code 1 + self.assertEqual(result.returncode, 1, + "QEMU should exit with code 1 for invalid SMP count") + + # Check error message + self.assertIn('Invalid SMP CPUs 65', result.stderr, + "Error message should indicate invalid SMP CPU count") + +if __name__ == '__main__': + QemuSystemTest.main() -- 2.52.0