: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
The following changes since commit 03e4bc0bc02779fdf6f8e8d83197f05e70881abf: Merge tag 'pull-tcg-20240205-2' of https://gitlab.com/rth7680/qemu into staging (2024-02-08 16:08:42 +0000) are available in the Git repository at: https://github.com/alistair23/qemu.git tags/pull-riscv-to-apply-20240209 for you to fetch changes up to deb0ff0c777d20602ecc5b6f74f18cb7ecc0b91f: target/riscv: add rv32i, rv32e and rv64e CPUs (2024-02-09 20:49:41 +1000) ---------------------------------------------------------------- RISC-V PR for 9.0 * Check for 'A' extension on all atomic instructions * Add support for 'B' extension * Internally deprecate riscv_cpu_options * Implement optional CSR mcontext of debug Sdtrig extension * Internally add cpu->cfg.vlenb and remove cpu->cfg.vlen * Support vlenb and vregs[] in KVM * RISC-V gdbstub and TCG plugin improvements * Remove vxrm and vxsat from FCSR * Use RISCVException as return type for all csr ops * Use g_autofree more and fix a memory leak * Add support for Zaamo and Zalrsc * Support new isa extension detection devicetree properties * SMBIOS support for RISC-V virt machine * Enable xtheadsync under user mode * Add rv32i,rv32e and rv64e CPUs ---------------------------------------------------------------- Akihiko Odaki (3): target/riscv: Remove misa_mxl validation target/riscv: Move misa_mxl_max to class target/riscv: Validate misa_mxl_max only once Alvin Chang (1): target/riscv: Implement optional CSR mcontext of debug Sdtrig extension Conor Dooley (2): target/riscv: use misa_mxl_max to populate isa string rather than TARGET_LONG_BITS target/riscv: support new isa extension detection devicetree properties Daniel Henrique Barboza (42): target/riscv/cpu_cfg.h: remove unused fields target/riscv: make riscv_cpu_is_vendor() public target/riscv: move 'pmu-mask' and 'pmu-num' to riscv_cpu_properties[] target/riscv: move 'mmu' to riscv_cpu_properties[] target/riscv: move 'pmp' to riscv_cpu_properties[] target/riscv: rework 'priv_spec' target/riscv: rework 'vext_spec' target/riscv: move 'vlen' to riscv_cpu_properties[] target/riscv: move 'elen' to riscv_cpu_properties[] target/riscv: create finalize_features() for KVM target/riscv: move 'cbom_blocksize' to riscv_cpu_properties[] target/riscv: move 'cbop_blocksize' to riscv_cpu_properties[] target/riscv: move 'cboz_blocksize' to riscv_cpu_properties[] target/riscv: remove riscv_cpu_options[] target/riscv/cpu.c: move 'mvendorid' to riscv_cpu_properties[] target/riscv/cpu.c: move 'mimpid' to riscv_cpu_properties[] target/riscv/cpu.c: move 'marchid' to riscv_cpu_properties[] target/riscv: add 'vlenb' field in cpu->cfg target/riscv/csr.c: use 'vlenb' instead of 'vlen' target/riscv/gdbstub.c: use 'vlenb' instead of shifting 'vlen' target/riscv/insn_trans/trans_rvbf16.c.inc: use cpu->cfg.vlenb target/riscv/insn_trans/trans_rvv.c.inc: use 'vlenb' target/riscv/insn_trans/trans_rvvk.c.inc: use 'vlenb' target/riscv/vector_helper.c: use 'vlenb' target/riscv/vector_helper.c: use vlenb in HELPER(vsetvl) target/riscv/insn_trans/trans_rvv.c.inc: use 'vlenb' in MAXSZ() target/riscv/cpu.h: use 'vlenb' in vext_get_vlmax() target/riscv: change vext_get_vlmax() arguments trans_rvv.c.inc: use vext_get_vlmax() in trans_vrgather_v*() target/riscv/cpu.c: remove cpu->cfg.vlen target/riscv/kvm: change kvm_reg_id to uint64_t target/riscv/kvm: initialize 'vlenb' via get-reg-list target/riscv/kvm: get/set vector vregs[] hw/riscv/virt-acpi-build.c: fix leak in build_rhct() hw/riscv/numa.c: use g_autofree in socket_fdt_write_distance_matrix() hw/riscv/virt.c: use g_autofree in create_fdt_socket_cpus() hw/riscv/virt.c: use g_autofree in create_fdt_sockets() hw/riscv/virt.c: use g_autofree in create_fdt_virtio() hw/riscv/virt.c: use g_autofree in virt_machine_init() hw/riscv/virt.c: use g_autofree in create_fdt_* target/riscv/cpu.c: add riscv_bare_cpu_init() target/riscv: add rv32i, rv32e and rv64e CPUs Heinrich Schuchardt (4): smbios: add processor-family option smbios: function to set default processor family target/riscv: SMBIOS support for RISC-V virt machine qemu-options: enable -smbios option on RISC-V LIU Zhiwei (3): target/riscv: FCSR doesn't contain vxrm and vxsat target/riscv: Use RISCVException as return type for all csr ops target/riscv: Enable xtheadsync under user mode Rob Bradford (6): target/riscv: Check for 'A' extension on all atomic instructions target/riscv: Add infrastructure for 'B' MISA extension target/riscv: Add step to validate 'B' extension target/riscv: Add Zaamo and Zalrsc extension infrastructure target/riscv: Check 'A' and split extensions for atomic instructions target/riscv: Expose Zaamo and Zalrsc extensions include/hw/firmware/smbios.h | 1 + target/riscv/cpu-qom.h | 3 + target/riscv/cpu.h | 30 +- target/riscv/cpu_bits.h | 15 +- target/riscv/cpu_cfg.h | 8 +- target/riscv/kvm/kvm_riscv.h | 1 + hw/riscv/boot.c | 3 +- hw/riscv/numa.c | 4 +- hw/riscv/sifive_u.c | 7 +- hw/riscv/spike.c | 6 +- hw/riscv/virt-acpi-build.c | 2 +- hw/riscv/virt.c | 153 ++-- hw/smbios/smbios.c | 20 +- target/riscv/cpu.c | 1106 +++++++++++++++++++++------- target/riscv/cpu_helper.c | 11 +- target/riscv/csr.c | 157 ++-- target/riscv/debug.c | 2 + target/riscv/gdbstub.c | 18 +- target/riscv/kvm/kvm-cpu.c | 250 +++++-- target/riscv/machine.c | 7 +- target/riscv/tcg/tcg-cpu.c | 143 ++-- target/riscv/translate.c | 3 +- target/riscv/vector_helper.c | 43 +- target/riscv/insn_trans/trans_rva.c.inc | 45 +- target/riscv/insn_trans/trans_rvbf16.c.inc | 12 +- target/riscv/insn_trans/trans_rvv.c.inc | 152 ++-- target/riscv/insn_trans/trans_rvvk.c.inc | 16 +- target/riscv/insn_trans/trans_xthead.c.inc | 10 - hw/riscv/Kconfig | 1 + qemu-options.hx | 6 +- 30 files changed, 1522 insertions(+), 713 deletions(-)
From: Rob Bradford <rbradford@rivosinc.com> Add requirement that 'A' is enabled for all atomic instructions that lack the check. This makes the 64-bit versions consistent with the 32-bit versions in the same file. Signed-off-by: Rob Bradford <rbradford@rivosinc.com> Reviewed-by: Alistair Francis <alistair.francis@wdc.com> Reviewed-by: Daniel Henrique Barboza <dbarboza@ventanamicro.com> Message-ID: <20240110163959.31291-1-rbradford@rivosinc.com> Signed-off-by: Alistair Francis <alistair.francis@wdc.com> --- target/riscv/insn_trans/trans_rva.c.inc | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/target/riscv/insn_trans/trans_rva.c.inc b/target/riscv/insn_trans/trans_rva.c.inc index XXXXXXX..XXXXXXX 100644 --- a/target/riscv/insn_trans/trans_rva.c.inc +++ b/target/riscv/insn_trans/trans_rva.c.inc @@ -XXX,XX +XXX,XX @@ static bool trans_amomaxu_w(DisasContext *ctx, arg_amomaxu_w *a) static bool trans_lr_d(DisasContext *ctx, arg_lr_d *a) { REQUIRE_64BIT(ctx); + REQUIRE_EXT(ctx, RVA); return gen_lr(ctx, a, MO_ALIGN | MO_TEUQ); } static bool trans_sc_d(DisasContext *ctx, arg_sc_d *a) { REQUIRE_64BIT(ctx); + REQUIRE_EXT(ctx, RVA); return gen_sc(ctx, a, (MO_ALIGN | MO_TEUQ)); } static bool trans_amoswap_d(DisasContext *ctx, arg_amoswap_d *a) { REQUIRE_64BIT(ctx); + REQUIRE_EXT(ctx, RVA); return gen_amo(ctx, a, &tcg_gen_atomic_xchg_tl, (MO_ALIGN | MO_TEUQ)); } static bool trans_amoadd_d(DisasContext *ctx, arg_amoadd_d *a) { REQUIRE_64BIT(ctx); + REQUIRE_EXT(ctx, RVA); return gen_amo(ctx, a, &tcg_gen_atomic_fetch_add_tl, (MO_ALIGN | MO_TEUQ)); } static bool trans_amoxor_d(DisasContext *ctx, arg_amoxor_d *a) { REQUIRE_64BIT(ctx); + REQUIRE_EXT(ctx, RVA); return gen_amo(ctx, a, &tcg_gen_atomic_fetch_xor_tl, (MO_ALIGN | MO_TEUQ)); } static bool trans_amoand_d(DisasContext *ctx, arg_amoand_d *a) { REQUIRE_64BIT(ctx); + REQUIRE_EXT(ctx, RVA); return gen_amo(ctx, a, &tcg_gen_atomic_fetch_and_tl, (MO_ALIGN | MO_TEUQ)); } static bool trans_amoor_d(DisasContext *ctx, arg_amoor_d *a) { REQUIRE_64BIT(ctx); + REQUIRE_EXT(ctx, RVA); return gen_amo(ctx, a, &tcg_gen_atomic_fetch_or_tl, (MO_ALIGN | MO_TEUQ)); } static bool trans_amomin_d(DisasContext *ctx, arg_amomin_d *a) { REQUIRE_64BIT(ctx); + REQUIRE_EXT(ctx, RVA); return gen_amo(ctx, a, &tcg_gen_atomic_fetch_smin_tl, (MO_ALIGN | MO_TEUQ)); } static bool trans_amomax_d(DisasContext *ctx, arg_amomax_d *a) { REQUIRE_64BIT(ctx); + REQUIRE_EXT(ctx, RVA); return gen_amo(ctx, a, &tcg_gen_atomic_fetch_smax_tl, (MO_ALIGN | MO_TEUQ)); } static bool trans_amominu_d(DisasContext *ctx, arg_amominu_d *a) { REQUIRE_64BIT(ctx); + REQUIRE_EXT(ctx, RVA); return gen_amo(ctx, a, &tcg_gen_atomic_fetch_umin_tl, (MO_ALIGN | MO_TEUQ)); } static bool trans_amomaxu_d(DisasContext *ctx, arg_amomaxu_d *a) { REQUIRE_64BIT(ctx); + REQUIRE_EXT(ctx, RVA); return gen_amo(ctx, a, &tcg_gen_atomic_fetch_umax_tl, (MO_ALIGN | MO_TEUQ)); } -- 2.43.0
From: Rob Bradford <rbradford@rivosinc.com> Add the infrastructure for the 'B' extension which is the union of the Zba, Zbb and Zbs instructions. Signed-off-by: Rob Bradford <rbradford@rivosinc.com> Reviewed-by: Daniel Henrique Barboza <dbarboza@ventanamicro.com> Reviewed-by: Andrew Jones <ajones@ventanamicro.com> Reviewed-by: Alistair Francis <alistair.francis@wdc.com> Message-ID: <20240111161644.33630-2-rbradford@rivosinc.com> Signed-off-by: Alistair Francis <alistair.francis@wdc.com> --- target/riscv/cpu.h | 1 + target/riscv/cpu.c | 5 +++-- target/riscv/tcg/tcg-cpu.c | 1 + 3 files changed, 5 insertions(+), 2 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 CPUArchState CPURISCVState; #define RVH RV('H') #define RVJ RV('J') #define RVG RV('G') +#define RVB RV('B') extern const uint32_t misa_bits[]; const char *riscv_get_misa_ext_name(uint32_t bit); 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 @@ #include "tcg/tcg.h" /* RISC-V CPU definitions */ -static const char riscv_single_letter_exts[] = "IEMAFDQCPVH"; +static const char riscv_single_letter_exts[] = "IEMAFDQCBPVH"; const uint32_t misa_bits[] = {RVI, RVE, RVM, RVA, RVF, RVD, RVV, - RVC, RVS, RVU, RVH, RVJ, RVG, 0}; + RVC, RVS, RVU, RVH, RVJ, RVG, RVB, 0}; /* * From vector_helper.c @@ -XXX,XX +XXX,XX @@ static const MISAExtInfo misa_ext_info_arr[] = { MISA_EXT_INFO(RVJ, "x-j", "Dynamic translated languages"), MISA_EXT_INFO(RVV, "v", "Vector operations"), MISA_EXT_INFO(RVG, "g", "General purpose (IMAFD_Zicsr_Zifencei)"), + MISA_EXT_INFO(RVB, "x-b", "Bit manipulation (Zba_Zbb_Zbs)") }; static int riscv_validate_misa_info_idx(uint32_t bit) 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 const RISCVCPUMisaExtConfig misa_ext_cfgs[] = { MISA_CFG(RVJ, false), MISA_CFG(RVV, false), MISA_CFG(RVG, false), + MISA_CFG(RVB, false), }; /* -- 2.43.0
From: Rob Bradford <rbradford@rivosinc.com> If the B extension is enabled warn if the user has disabled any of the required extensions that are part of the 'B' extension. Conversely enable the extensions that make up the 'B' extension if it is enabled. Signed-off-by: Rob Bradford <rbradford@rivosinc.com> Reviewed-by: Daniel Henrique Barboza <dbarboza@ventanamicro.com> Reviewed-by: Andrew Jones <ajones@ventanamicro.com> Reviewed-by: Alistair Francis <alistair.francis@wdc.com> Message-ID: <20240111161644.33630-3-rbradford@rivosinc.com> Signed-off-by: Alistair Francis <alistair.francis@wdc.com> --- target/riscv/tcg/tcg-cpu.c | 33 +++++++++++++++++++++++++++++++++ 1 file changed, 33 insertions(+) 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_validate_g(RISCVCPU *cpu) } } +static void riscv_cpu_validate_b(RISCVCPU *cpu) +{ + const char *warn_msg = "RVB mandates disabled extension %s"; + + if (!cpu->cfg.ext_zba) { + if (!cpu_cfg_ext_is_user_set(CPU_CFG_OFFSET(ext_zba))) { + cpu->cfg.ext_zba = true; + } else { + warn_report(warn_msg, "zba"); + } + } + + if (!cpu->cfg.ext_zbb) { + if (!cpu_cfg_ext_is_user_set(CPU_CFG_OFFSET(ext_zbb))) { + cpu->cfg.ext_zbb = true; + } else { + warn_report(warn_msg, "zbb"); + } + } + + if (!cpu->cfg.ext_zbs) { + if (!cpu_cfg_ext_is_user_set(CPU_CFG_OFFSET(ext_zbs))) { + cpu->cfg.ext_zbs = true; + } else { + warn_report(warn_msg, "zbs"); + } + } +} + /* * Check consistency between chosen extensions while setting * cpu->cfg accordingly. @@ -XXX,XX +XXX,XX @@ void riscv_cpu_validate_set_extensions(RISCVCPU *cpu, Error **errp) riscv_cpu_validate_g(cpu); } + if (riscv_has_ext(env, RVB)) { + riscv_cpu_validate_b(cpu); + } + if (riscv_has_ext(env, RVI) && riscv_has_ext(env, RVE)) { error_setg(errp, "I and E extensions are incompatible"); -- 2.43.0
From: Daniel Henrique Barboza <dbarboza@ventanamicro.com> user_spec, bext_spec and bext_ver aren't being used. Signed-off-by: Daniel Henrique Barboza <dbarboza@ventanamicro.com> Reviewed-by: Alistair Francis <alistair.francis@wdc.com> Tested-by: Vladimir Isaev <vladimir.isaev@syntacore.com> Message-ID: <20240105230546.265053-2-dbarboza@ventanamicro.com> Signed-off-by: Alistair Francis <alistair.francis@wdc.com> --- target/riscv/cpu.h | 1 - target/riscv/cpu_cfg.h | 2 -- 2 files changed, 3 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 guest_phys_fault_addr; target_ulong priv_ver; - target_ulong bext_ver; target_ulong vext_ver; /* RISCVMXL, but uint32_t for vmstate migration */ 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 @@ struct RISCVCPUConfig { uint32_t pmu_mask; char *priv_spec; - char *user_spec; - char *bext_spec; char *vext_spec; uint16_t vlen; uint16_t elen; -- 2.43.0
From: Daniel Henrique Barboza <dbarboza@ventanamicro.com> We'll use this function in target/riscv/cpu.c to implement setters that won't allow vendor CPU options to be changed. Signed-off-by: Daniel Henrique Barboza <dbarboza@ventanamicro.com> Reviewed-by: Alistair Francis <alistair.francis@wdc.com> Tested-by: Vladimir Isaev <vladimir.isaev@syntacore.com> Message-ID: <20240105230546.265053-3-dbarboza@ventanamicro.com> Signed-off-by: Alistair Francis <alistair.francis@wdc.com> --- target/riscv/cpu.h | 1 + target/riscv/cpu.c | 5 +++++ target/riscv/tcg/tcg-cpu.c | 5 ----- 3 files changed, 6 insertions(+), 5 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 @@ enum riscv_pmu_event_idx { void isa_ext_update_enabled(RISCVCPU *cpu, uint32_t ext_offset, bool en); bool isa_ext_is_enabled(RISCVCPU *cpu, uint32_t ext_offset); void riscv_cpu_set_misa(CPURISCVState *env, RISCVMXL mxl, uint32_t ext); +bool riscv_cpu_is_vendor(Object *cpu_obj); typedef struct RISCVCPUMultiExtConfig { 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 @@ void isa_ext_update_enabled(RISCVCPU *cpu, uint32_t ext_offset, bool en) *ext_enabled = en; } +bool riscv_cpu_is_vendor(Object *cpu_obj) +{ + return object_dynamic_cast(cpu_obj, TYPE_RISCV_VENDOR_CPU) != NULL; +} + const char * const riscv_int_regnames[] = { "x0/zero", "x1/ra", "x2/sp", "x3/gp", "x4/tp", "x5/t0", "x6/t1", "x7/t2", "x8/s0", "x9/s1", "x10/a0", "x11/a1", "x12/a2", "x13/a3", 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 bool riscv_cpu_is_vendor(Object *cpu_obj) -{ - return object_dynamic_cast(cpu_obj, TYPE_RISCV_VENDOR_CPU) != NULL; -} - /* * We'll get here via the following path: * -- 2.43.0
From: Daniel Henrique Barboza <dbarboza@ventanamicro.com> Every property in riscv_cpu_options[] will be migrated to riscv_cpu_properties[]. This will make their default values init earlier, allowing cpu_init() functions to overwrite them. We'll also implement common getters and setters that both accelerators will use, allowing them to share validations that TCG is doing. At the same time, some options (namely 'vlen', 'elen' and the cache blocksizes) need a way of tracking if the user set a value for them. This is benign for TCG since the cost of always validating these values are small, but for KVM we need syscalls to read the host values to make the validations, thus knowing whether the user didn't touch the values makes a difference. We'll track user setting for these properties using a hash, like we do in the TCG driver. All riscv cpu options will update this hash in case the user sets it. The KVM driver will use this hash to minimize the amount of syscalls done. For now, both 'pmu-mask' and 'pmu-num' shouldn't be changed for vendor CPUs. The existing setter for 'pmu-num' is changed to add this restriction. New getters and setters are required for 'pmu-mask' While we're at it, add a 'static' modifier to 'prop_pmu_num' since we're not exporting it. Signed-off-by: Daniel Henrique Barboza <dbarboza@ventanamicro.com> Reviewed-by: Alistair Francis <alistair.francis@wdc.com> Tested-by: Vladimir Isaev <vladimir.isaev@syntacore.com> Message-ID: <20240105230546.265053-4-dbarboza@ventanamicro.com> Signed-off-by: Alistair Francis <alistair.francis@wdc.com> --- target/riscv/cpu.c | 91 ++++++++++++++++++++++++++++++++++++++++++---- 1 file changed, 84 insertions(+), 7 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 @@ bool riscv_cpu_is_32bit(RISCVCPU *cpu) return riscv_cpu_mxl(&cpu->env) == MXL_RV32; } +/* Hash that stores general user set numeric options */ +static GHashTable *general_user_opts; + +static void cpu_option_add_user_setting(const char *optname, uint32_t value) +{ + g_hash_table_insert(general_user_opts, (gpointer)optname, + GUINT_TO_POINTER(value)); +} + #define ISA_EXT_DATA_ENTRY(_name, _min_ver, _prop) \ {#_name, _min_ver, CPU_CFG_OFFSET(_prop)} @@ -XXX,XX +XXX,XX @@ static void riscv_cpu_post_init(Object *obj) static void riscv_cpu_init(Object *obj) { + RISCVCPU *cpu = RISCV_CPU(obj); + #ifndef CONFIG_USER_ONLY qdev_init_gpio_in(DEVICE(obj), riscv_cpu_set_irq, IRQ_LOCAL_MAX + IRQ_LOCAL_GUEST_MAX); #endif /* CONFIG_USER_ONLY */ + general_user_opts = g_hash_table_new(g_str_hash, g_str_equal); + /* * The timer and performance counters extensions were supported * in QEMU before they were added as discrete extensions in the @@ -XXX,XX +XXX,XX @@ static void riscv_cpu_init(Object *obj) */ RISCV_CPU(obj)->cfg.ext_zicntr = true; RISCV_CPU(obj)->cfg.ext_zihpm = true; + + /* Default values for non-bool cpu properties */ + cpu->cfg.pmu_mask = MAKE_64BIT_MASK(3, 16); } typedef struct misa_ext_info { @@ -XXX,XX +XXX,XX @@ const RISCVCPUMultiExtConfig riscv_cpu_deprecated_exts[] = { DEFINE_PROP_END_OF_LIST(), }; +static void cpu_set_prop_err(RISCVCPU *cpu, const char *propname, + Error **errp) +{ + g_autofree char *cpuname = riscv_cpu_get_name(cpu); + error_setg(errp, "CPU '%s' does not allow changing the value of '%s'", + cpuname, propname); +} + static void prop_pmu_num_set(Object *obj, Visitor *v, const char *name, void *opaque, Error **errp) { RISCVCPU *cpu = RISCV_CPU(obj); - uint8_t pmu_num; + uint8_t pmu_num, curr_pmu_num; + uint32_t pmu_mask; visit_type_uint8(v, name, &pmu_num, errp); + curr_pmu_num = ctpop32(cpu->cfg.pmu_mask); + + if (pmu_num != curr_pmu_num && riscv_cpu_is_vendor(obj)) { + cpu_set_prop_err(cpu, name, errp); + error_append_hint(errp, "Current '%s' val: %u\n", + name, curr_pmu_num); + return; + } + if (pmu_num > (RV_MAX_MHPMCOUNTERS - 3)) { error_setg(errp, "Number of counters exceeds maximum available"); return; } if (pmu_num == 0) { - cpu->cfg.pmu_mask = 0; + pmu_mask = 0; } else { - cpu->cfg.pmu_mask = MAKE_64BIT_MASK(3, pmu_num); + pmu_mask = MAKE_64BIT_MASK(3, pmu_num); } warn_report("\"pmu-num\" property is deprecated; use \"pmu-mask\""); + cpu->cfg.pmu_mask = pmu_mask; + cpu_option_add_user_setting("pmu-mask", pmu_mask); } static void prop_pmu_num_get(Object *obj, Visitor *v, const char *name, @@ -XXX,XX +XXX,XX @@ static void prop_pmu_num_get(Object *obj, Visitor *v, const char *name, visit_type_uint8(v, name, &pmu_num, errp); } -const PropertyInfo prop_pmu_num = { +static const PropertyInfo prop_pmu_num = { .name = "pmu-num", .get = prop_pmu_num_get, .set = prop_pmu_num_set, }; -Property riscv_cpu_options[] = { - DEFINE_PROP_UINT32("pmu-mask", RISCVCPU, cfg.pmu_mask, MAKE_64BIT_MASK(3, 16)), - {.name = "pmu-num", .info = &prop_pmu_num}, /* Deprecated */ +static void prop_pmu_mask_set(Object *obj, Visitor *v, const char *name, + void *opaque, Error **errp) +{ + RISCVCPU *cpu = RISCV_CPU(obj); + uint32_t value; + uint8_t pmu_num; + visit_type_uint32(v, name, &value, errp); + + if (value != cpu->cfg.pmu_mask && riscv_cpu_is_vendor(obj)) { + cpu_set_prop_err(cpu, name, errp); + error_append_hint(errp, "Current '%s' val: %x\n", + name, cpu->cfg.pmu_mask); + return; + } + + pmu_num = ctpop32(value); + + if (pmu_num > (RV_MAX_MHPMCOUNTERS - 3)) { + error_setg(errp, "Number of counters exceeds maximum available"); + return; + } + + cpu_option_add_user_setting(name, value); + cpu->cfg.pmu_mask = value; +} + +static void prop_pmu_mask_get(Object *obj, Visitor *v, const char *name, + void *opaque, Error **errp) +{ + uint8_t pmu_mask = RISCV_CPU(obj)->cfg.pmu_mask; + + visit_type_uint8(v, name, &pmu_mask, errp); +} + +static const PropertyInfo prop_pmu_mask = { + .name = "pmu-mask", + .get = prop_pmu_mask_get, + .set = prop_pmu_mask_set, +}; + +Property riscv_cpu_options[] = { DEFINE_PROP_BOOL("mmu", RISCVCPU, cfg.mmu, true), DEFINE_PROP_BOOL("pmp", RISCVCPU, cfg.pmp, true), @@ -XXX,XX +XXX,XX @@ RISCVCPUProfile *riscv_profiles[] = { static Property riscv_cpu_properties[] = { DEFINE_PROP_BOOL("debug", RISCVCPU, cfg.debug, true), + {.name = "pmu-mask", .info = &prop_pmu_mask}, + {.name = "pmu-num", .info = &prop_pmu_num}, /* Deprecated */ + #ifndef CONFIG_USER_ONLY DEFINE_PROP_UINT64("resetvec", RISCVCPU, env.resetvec, DEFAULT_RSTVEC), #endif -- 2.43.0
From: Daniel Henrique Barboza <dbarboza@ventanamicro.com> Commit 7f0bdfb5bfc ("target/riscv/cpu.c: remove cfg setup from riscv_cpu_init()") already did some of the work by making some cpu_init() functions to explictly enable their own 'mmu' default. The generic CPUs didn't get update by that commit, so they are still relying on the defaults set by the 'mmu' option. But having 'mmu' and 'pmp' being default=true will force CPUs that doesn't implement these options to set them to 'false' in their cpu_init(), which isn't ideal. We'll move 'mmu' to riscv_cpu_properties[] without any defaults, i.e. the default will be 'false'. Compensate it by manually setting 'mmu = true' to the generic CPUs that requires it. Implement a setter for it to forbid the 'mmu' setting to be changed for vendor CPUs. This will allow the option to exist for all CPUs and, at the same time, protect vendor CPUs from undesired changes: $ ./build/qemu-system-riscv64 -M virt -cpu sifive-e51,mmu=true qemu-system-riscv64: can't apply global sifive-e51-riscv-cpu.mmu=true: CPU 'sifive-e51' does not allow changing the value of 'mmu' Signed-off-by: Daniel Henrique Barboza <dbarboza@ventanamicro.com> Reviewed-by: Alistair Francis <alistair.francis@wdc.com> Tested-by: Vladimir Isaev <vladimir.isaev@syntacore.com> Message-ID: <20240105230546.265053-5-dbarboza@ventanamicro.com> Signed-off-by: Alistair Francis <alistair.francis@wdc.com> --- target/riscv/cpu.c | 55 ++++++++++++++++++++++++++++++++++++++++++---- 1 file changed, 51 insertions(+), 4 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 @@ static void riscv_max_cpu_init(Object *obj) CPURISCVState *env = &cpu->env; RISCVMXL mlx = MXL_RV64; + cpu->cfg.mmu = true; + #ifdef TARGET_RISCV32 mlx = MXL_RV32; #endif @@ -XXX,XX +XXX,XX @@ static void riscv_max_cpu_init(Object *obj) #if defined(TARGET_RISCV64) static void rv64_base_cpu_init(Object *obj) { - CPURISCVState *env = &RISCV_CPU(obj)->env; + RISCVCPU *cpu = RISCV_CPU(obj); + CPURISCVState *env = &cpu->env; + + cpu->cfg.mmu = true; + /* We set this in the realise function */ riscv_cpu_set_misa(env, MXL_RV64, 0); /* Set latest version of privileged specification */ @@ -XXX,XX +XXX,XX @@ static void rv64_veyron_v1_cpu_init(Object *obj) static void rv128_base_cpu_init(Object *obj) { + RISCVCPU *cpu = RISCV_CPU(obj); + CPURISCVState *env = &cpu->env; + if (qemu_tcg_mttcg_enabled()) { /* Missing 128-bit aligned atomics */ error_report("128-bit RISC-V currently does not work with Multi " "Threaded TCG. Please use: -accel tcg,thread=single"); exit(EXIT_FAILURE); } - CPURISCVState *env = &RISCV_CPU(obj)->env; + + cpu->cfg.mmu = true; + /* We set this in the realise function */ riscv_cpu_set_misa(env, MXL_RV128, 0); /* Set latest version of privileged specification */ @@ -XXX,XX +XXX,XX @@ static void rv64i_bare_cpu_init(Object *obj) #else static void rv32_base_cpu_init(Object *obj) { - CPURISCVState *env = &RISCV_CPU(obj)->env; + RISCVCPU *cpu = RISCV_CPU(obj); + CPURISCVState *env = &cpu->env; + + cpu->cfg.mmu = true; + /* We set this in the realise function */ riscv_cpu_set_misa(env, MXL_RV32, 0); /* Set latest version of privileged specification */ @@ -XXX,XX +XXX,XX @@ static const PropertyInfo prop_pmu_mask = { .set = prop_pmu_mask_set, }; +static void prop_mmu_set(Object *obj, Visitor *v, const char *name, + void *opaque, Error **errp) +{ + RISCVCPU *cpu = RISCV_CPU(obj); + bool value; + + visit_type_bool(v, name, &value, errp); + + if (cpu->cfg.mmu != value && riscv_cpu_is_vendor(obj)) { + cpu_set_prop_err(cpu, "mmu", errp); + return; + } + + cpu_option_add_user_setting(name, value); + cpu->cfg.mmu = value; +} + +static void prop_mmu_get(Object *obj, Visitor *v, const char *name, + void *opaque, Error **errp) +{ + bool value = RISCV_CPU(obj)->cfg.mmu; + + visit_type_bool(v, name, &value, errp); +} + +static const PropertyInfo prop_mmu = { + .name = "mmu", + .get = prop_mmu_get, + .set = prop_mmu_set, +}; + Property riscv_cpu_options[] = { - DEFINE_PROP_BOOL("mmu", RISCVCPU, cfg.mmu, true), DEFINE_PROP_BOOL("pmp", RISCVCPU, cfg.pmp, true), DEFINE_PROP_STRING("priv_spec", RISCVCPU, cfg.priv_spec), @@ -XXX,XX +XXX,XX @@ static Property riscv_cpu_properties[] = { {.name = "pmu-mask", .info = &prop_pmu_mask}, {.name = "pmu-num", .info = &prop_pmu_num}, /* Deprecated */ + {.name = "mmu", .info = &prop_mmu}, + #ifndef CONFIG_USER_ONLY DEFINE_PROP_UINT64("resetvec", RISCVCPU, env.resetvec, DEFAULT_RSTVEC), #endif -- 2.43.0
From: Daniel Henrique Barboza <dbarboza@ventanamicro.com> Move 'pmp' to riscv_cpu_properties[], creating a new setter() for it that forbids 'pmp' to be changed in vendor CPUs, like we did with the 'mmu' option. We'll also have to manually set 'pmp = true' to generic CPUs that were still relying on the previous default to set it. Signed-off-by: Daniel Henrique Barboza <dbarboza@ventanamicro.com> Reviewed-by: Alistair Francis <alistair.francis@wdc.com> Tested-by: Vladimir Isaev <vladimir.isaev@syntacore.com> Message-ID: <20240105230546.265053-6-dbarboza@ventanamicro.com> Signed-off-by: Alistair Francis <alistair.francis@wdc.com> --- target/riscv/cpu.c | 38 ++++++++++++++++++++++++++++++++++++-- 1 file changed, 36 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 @@ static void riscv_max_cpu_init(Object *obj) RISCVMXL mlx = MXL_RV64; cpu->cfg.mmu = true; + cpu->cfg.pmp = true; #ifdef TARGET_RISCV32 mlx = MXL_RV32; @@ -XXX,XX +XXX,XX @@ static void rv64_base_cpu_init(Object *obj) CPURISCVState *env = &cpu->env; cpu->cfg.mmu = true; + cpu->cfg.pmp = true; /* We set this in the realise function */ riscv_cpu_set_misa(env, MXL_RV64, 0); @@ -XXX,XX +XXX,XX @@ static void rv128_base_cpu_init(Object *obj) } cpu->cfg.mmu = true; + cpu->cfg.pmp = true; /* We set this in the realise function */ riscv_cpu_set_misa(env, MXL_RV128, 0); @@ -XXX,XX +XXX,XX @@ static void rv32_base_cpu_init(Object *obj) CPURISCVState *env = &cpu->env; cpu->cfg.mmu = true; + cpu->cfg.pmp = true; /* We set this in the realise function */ riscv_cpu_set_misa(env, MXL_RV32, 0); @@ -XXX,XX +XXX,XX @@ static const PropertyInfo prop_mmu = { .set = prop_mmu_set, }; -Property riscv_cpu_options[] = { - DEFINE_PROP_BOOL("pmp", RISCVCPU, cfg.pmp, true), +static void prop_pmp_set(Object *obj, Visitor *v, const char *name, + void *opaque, Error **errp) +{ + RISCVCPU *cpu = RISCV_CPU(obj); + bool value; + + visit_type_bool(v, name, &value, errp); + if (cpu->cfg.pmp != value && riscv_cpu_is_vendor(obj)) { + cpu_set_prop_err(cpu, name, errp); + return; + } + + cpu_option_add_user_setting(name, value); + cpu->cfg.pmp = value; +} + +static void prop_pmp_get(Object *obj, Visitor *v, const char *name, + void *opaque, Error **errp) +{ + bool value = RISCV_CPU(obj)->cfg.pmp; + + visit_type_bool(v, name, &value, errp); +} + +static const PropertyInfo prop_pmp = { + .name = "pmp", + .get = prop_pmp_get, + .set = prop_pmp_set, +}; + +Property riscv_cpu_options[] = { DEFINE_PROP_STRING("priv_spec", RISCVCPU, cfg.priv_spec), DEFINE_PROP_STRING("vext_spec", RISCVCPU, cfg.vext_spec), @@ -XXX,XX +XXX,XX @@ static Property riscv_cpu_properties[] = { {.name = "pmu-num", .info = &prop_pmu_num}, /* Deprecated */ {.name = "mmu", .info = &prop_mmu}, + {.name = "pmp", .info = &prop_pmp}, #ifndef CONFIG_USER_ONLY DEFINE_PROP_UINT64("resetvec", RISCVCPU, env.resetvec, DEFAULT_RSTVEC), -- 2.43.0
From: Daniel Henrique Barboza <dbarboza@ventanamicro.com> 'priv_spec' and 'vext_spec' are two string options used as a fancy way of setting integers in the CPU state (cpu->env.priv_ver and cpu->env.vext_ver). It requires us to deal with string parsing and to store them in cpu_cfg. We must support these string options, but we don't need to store them. We have a precedence for this kind of arrangement in target/ppc/compat.c, ppc_compat_prop_get|set, getters and setters used for the 'max-cpu-compat' class property of the pseries ppc64 machine. We'll do the same with both 'priv_spec' and 'vext_spec'. For 'priv_spec', the validation from riscv_cpu_validate_priv_spec() will be done by the prop_priv_spec_set() setter, while also preventing it to be changed for vendor CPUs. Add two helpers that converts env->priv_ver back and forth to its string representation. These helpers allow us to get a string and set 'env->priv_ver' and return a string giving the current env->priv_ver value. In other words, make the cpu->cfg.priv_spec string obsolete. Last but not the least, move the reworked 'priv_spec' option to riscv_cpu_properties[]. After all said and done, we don't need to store the 'priv_spec' string in the CPU state, and we're now protecting vendor CPUs from priv_ver changes: $ ./build/qemu-system-riscv64 -M virt -cpu sifive-e51,priv_spec="v1.12.0" qemu-system-riscv64: can't apply global sifive-e51-riscv-cpu.priv_spec=v1.12.0: CPU 'sifive-e51' does not allow changing the value of 'priv_spec' Current 'priv_spec' val: v1.10.0 $ Signed-off-by: Daniel Henrique Barboza <dbarboza@ventanamicro.com> Reviewed-by: Alistair Francis <alistair.francis@wdc.com> Tested-by: Vladimir Isaev <vladimir.isaev@syntacore.com> Message-ID: <20240105230546.265053-7-dbarboza@ventanamicro.com> Signed-off-by: Alistair Francis <alistair.francis@wdc.com> --- target/riscv/cpu.h | 3 ++ target/riscv/cpu_cfg.h | 1 - target/riscv/cpu.c | 73 +++++++++++++++++++++++++++++++++++++- target/riscv/tcg/tcg-cpu.c | 29 --------------- 4 files changed, 75 insertions(+), 31 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 { extern RISCVCPUProfile *riscv_profiles[]; /* Privileged specification version */ +#define PRIV_VER_1_10_0_STR "v1.10.0" +#define PRIV_VER_1_11_0_STR "v1.11.0" +#define PRIV_VER_1_12_0_STR "v1.12.0" enum { PRIV_VERSION_1_10_0 = 0, PRIV_VERSION_1_11_0, 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 @@ struct RISCVCPUConfig { bool ext_XVentanaCondOps; uint32_t pmu_mask; - char *priv_spec; char *vext_spec; uint16_t vlen; uint16_t elen; 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 PropertyInfo prop_pmp = { .set = prop_pmp_set, }; +static int priv_spec_from_str(const char *priv_spec_str) +{ + int priv_version = -1; + + if (!g_strcmp0(priv_spec_str, PRIV_VER_1_12_0_STR)) { + priv_version = PRIV_VERSION_1_12_0; + } else if (!g_strcmp0(priv_spec_str, PRIV_VER_1_11_0_STR)) { + priv_version = PRIV_VERSION_1_11_0; + } else if (!g_strcmp0(priv_spec_str, PRIV_VER_1_10_0_STR)) { + priv_version = PRIV_VERSION_1_10_0; + } + + return priv_version; +} + +static const char *priv_spec_to_str(int priv_version) +{ + switch (priv_version) { + case PRIV_VERSION_1_10_0: + return PRIV_VER_1_10_0_STR; + case PRIV_VERSION_1_11_0: + return PRIV_VER_1_11_0_STR; + case PRIV_VERSION_1_12_0: + return PRIV_VER_1_12_0_STR; + default: + return NULL; + } +} + +static void prop_priv_spec_set(Object *obj, Visitor *v, const char *name, + void *opaque, Error **errp) +{ + RISCVCPU *cpu = RISCV_CPU(obj); + g_autofree char *value = NULL; + int priv_version = -1; + + visit_type_str(v, name, &value, errp); + + priv_version = priv_spec_from_str(value); + if (priv_version < 0) { + error_setg(errp, "Unsupported privilege spec version '%s'", value); + return; + } + + if (priv_version != cpu->env.priv_ver && riscv_cpu_is_vendor(obj)) { + cpu_set_prop_err(cpu, name, errp); + error_append_hint(errp, "Current '%s' val: %s\n", name, + object_property_get_str(obj, name, NULL)); + return; + } + + cpu_option_add_user_setting(name, priv_version); + cpu->env.priv_ver = priv_version; +} + +static void prop_priv_spec_get(Object *obj, Visitor *v, const char *name, + void *opaque, Error **errp) +{ + RISCVCPU *cpu = RISCV_CPU(obj); + const char *value = priv_spec_to_str(cpu->env.priv_ver); + + visit_type_str(v, name, (char **)&value, errp); +} + +static const PropertyInfo prop_priv_spec = { + .name = "priv_spec", + .get = prop_priv_spec_get, + .set = prop_priv_spec_set, +}; + Property riscv_cpu_options[] = { - DEFINE_PROP_STRING("priv_spec", RISCVCPU, cfg.priv_spec), DEFINE_PROP_STRING("vext_spec", RISCVCPU, cfg.vext_spec), DEFINE_PROP_UINT16("vlen", RISCVCPU, cfg.vlen, 128), @@ -XXX,XX +XXX,XX @@ static Property riscv_cpu_properties[] = { {.name = "mmu", .info = &prop_mmu}, {.name = "pmp", .info = &prop_pmp}, + {.name = "priv_spec", .info = &prop_priv_spec}, + #ifndef CONFIG_USER_ONLY DEFINE_PROP_UINT64("resetvec", RISCVCPU, env.resetvec, DEFAULT_RSTVEC), #endif 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_validate_misa_mxl(RISCVCPU *cpu, Error **errp) } } -static void riscv_cpu_validate_priv_spec(RISCVCPU *cpu, Error **errp) -{ - CPURISCVState *env = &cpu->env; - int priv_version = -1; - - if (cpu->cfg.priv_spec) { - if (!g_strcmp0(cpu->cfg.priv_spec, "v1.12.0")) { - priv_version = PRIV_VERSION_1_12_0; - } else if (!g_strcmp0(cpu->cfg.priv_spec, "v1.11.0")) { - priv_version = PRIV_VERSION_1_11_0; - } else if (!g_strcmp0(cpu->cfg.priv_spec, "v1.10.0")) { - priv_version = PRIV_VERSION_1_10_0; - } else { - error_setg(errp, - "Unsupported privilege spec version '%s'", - cpu->cfg.priv_spec); - return; - } - - env->priv_ver = priv_version; - } -} - static void riscv_cpu_validate_v(CPURISCVState *env, RISCVCPUConfig *cfg, Error **errp) { @@ -XXX,XX +XXX,XX @@ void riscv_tcg_cpu_finalize_features(RISCVCPU *cpu, Error **errp) CPURISCVState *env = &cpu->env; Error *local_err = NULL; - riscv_cpu_validate_priv_spec(cpu, &local_err); - if (local_err != NULL) { - error_propagate(errp, local_err); - return; - } - riscv_cpu_validate_misa_priv(env, &local_err); if (local_err != NULL) { error_propagate(errp, local_err); -- 2.43.0
From: Daniel Henrique Barboza <dbarboza@ventanamicro.com> The same rework did in 'priv_spec' is done for 'vext_spec'. This time is simpler, since we only accept one value ("v1.0") and we'll always have env->vext_ver set to VEXT_VERSION_1_00_0, thus we don't need helpers to convert string to 'vext_ver' back and forth like we needed for 'priv_spec'. Signed-off-by: Daniel Henrique Barboza <dbarboza@ventanamicro.com> Reviewed-by: Alistair Francis <alistair.francis@wdc.com> Tested-by: Vladimir Isaev <vladimir.isaev@syntacore.com> Message-ID: <20240105230546.265053-8-dbarboza@ventanamicro.com> Signed-off-by: Alistair Francis <alistair.francis@wdc.com> --- target/riscv/cpu.h | 1 + target/riscv/cpu_cfg.h | 1 - target/riscv/cpu.c | 35 +++++++++++++++++++++++++++++++++-- target/riscv/tcg/tcg-cpu.c | 15 --------------- 4 files changed, 34 insertions(+), 18 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 @@ enum { }; #define VEXT_VERSION_1_00_0 0x00010000 +#define VEXT_VER_1_00_0_STR "v1.0" enum { TRANSLATE_SUCCESS, 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 @@ struct RISCVCPUConfig { bool ext_XVentanaCondOps; uint32_t pmu_mask; - char *vext_spec; uint16_t vlen; uint16_t elen; uint16_t cbom_blocksize; 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) /* Default values for non-bool cpu properties */ cpu->cfg.pmu_mask = MAKE_64BIT_MASK(3, 16); + cpu->env.vext_ver = VEXT_VERSION_1_00_0; } typedef struct misa_ext_info { @@ -XXX,XX +XXX,XX @@ static const PropertyInfo prop_priv_spec = { .set = prop_priv_spec_set, }; -Property riscv_cpu_options[] = { - DEFINE_PROP_STRING("vext_spec", RISCVCPU, cfg.vext_spec), +static void prop_vext_spec_set(Object *obj, Visitor *v, const char *name, + void *opaque, Error **errp) +{ + RISCVCPU *cpu = RISCV_CPU(obj); + g_autofree char *value = NULL; + visit_type_str(v, name, &value, errp); + + if (g_strcmp0(value, VEXT_VER_1_00_0_STR) != 0) { + error_setg(errp, "Unsupported vector spec version '%s'", value); + return; + } + + cpu_option_add_user_setting(name, VEXT_VERSION_1_00_0); + cpu->env.vext_ver = VEXT_VERSION_1_00_0; +} + +static void prop_vext_spec_get(Object *obj, Visitor *v, const char *name, + void *opaque, Error **errp) +{ + const char *value = VEXT_VER_1_00_0_STR; + + visit_type_str(v, name, (char **)&value, errp); +} + +static const PropertyInfo prop_vext_spec = { + .name = "vext_spec", + .get = prop_vext_spec_get, + .set = prop_vext_spec_set, +}; + +Property riscv_cpu_options[] = { DEFINE_PROP_UINT16("vlen", RISCVCPU, cfg.vlen, 128), DEFINE_PROP_UINT16("elen", RISCVCPU, cfg.elen, 64), @@ -XXX,XX +XXX,XX @@ static Property riscv_cpu_properties[] = { {.name = "pmp", .info = &prop_pmp}, {.name = "priv_spec", .info = &prop_priv_spec}, + {.name = "vext_spec", .info = &prop_vext_spec}, #ifndef CONFIG_USER_ONLY DEFINE_PROP_UINT64("resetvec", RISCVCPU, env.resetvec, DEFAULT_RSTVEC), 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_validate_v(CPURISCVState *env, RISCVCPUConfig *cfg, "in the range [8, 64]"); return; } - - if (cfg->vext_spec) { - if (!g_strcmp0(cfg->vext_spec, "v1.0")) { - env->vext_ver = VEXT_VERSION_1_00_0; - } else { - error_setg(errp, "Unsupported vector spec version '%s'", - cfg->vext_spec); - return; - } - } else if (env->vext_ver == 0) { - qemu_log("vector version is not specified, " - "use the default value v1.0\n"); - - env->vext_ver = VEXT_VERSION_1_00_0; - } } static void riscv_cpu_disable_priv_spec_isa_exts(RISCVCPU *cpu) -- 2.43.0
From: Daniel Henrique Barboza <dbarboza@ventanamicro.com> Turning 'vlen' into a class property will allow its default value to be overwritten by cpu_init() later on, solving the issue we have now where CPU specific settings are getting overwritten by the default. Common validation bits are moved from riscv_cpu_validate_v() to prop_vlen_set() to be shared with KVM. And, as done with every option we migrated to riscv_cpu_properties[], vendor CPUs can't have their 'vlen' value changed. Signed-off-by: Daniel Henrique Barboza <dbarboza@ventanamicro.com> Reviewed-by: Alistair Francis <alistair.francis@wdc.com> Tested-by: Vladimir Isaev <vladimir.isaev@syntacore.com> Message-ID: <20240105230546.265053-9-dbarboza@ventanamicro.com> Signed-off-by: Alistair Francis <alistair.francis@wdc.com> --- target/riscv/cpu.c | 45 +++++++++++++++++++++++++++++++++++++- target/riscv/tcg/tcg-cpu.c | 5 ----- 2 files changed, 44 insertions(+), 6 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 @@ #include "qapi/visitor.h" #include "qemu/error-report.h" #include "hw/qdev-properties.h" +#include "hw/core/qdev-prop-internal.h" #include "migration/vmstate.h" #include "fpu/softfloat-helpers.h" #include "sysemu/kvm.h" @@ -XXX,XX +XXX,XX @@ static void riscv_cpu_init(Object *obj) /* Default values for non-bool cpu properties */ cpu->cfg.pmu_mask = MAKE_64BIT_MASK(3, 16); + cpu->cfg.vlen = 128; cpu->env.vext_ver = VEXT_VERSION_1_00_0; } @@ -XXX,XX +XXX,XX @@ static const PropertyInfo prop_vext_spec = { .set = prop_vext_spec_set, }; +static void prop_vlen_set(Object *obj, Visitor *v, const char *name, + void *opaque, Error **errp) +{ + RISCVCPU *cpu = RISCV_CPU(obj); + uint16_t value; + + if (!visit_type_uint16(v, name, &value, errp)) { + return; + } + + if (!is_power_of_2(value)) { + error_setg(errp, "Vector extension VLEN must be power of 2"); + return; + } + + if (value != cpu->cfg.vlen && riscv_cpu_is_vendor(obj)) { + cpu_set_prop_err(cpu, name, errp); + error_append_hint(errp, "Current '%s' val: %u\n", + name, cpu->cfg.vlen); + return; + } + + cpu_option_add_user_setting(name, value); + cpu->cfg.vlen = value; +} + +static void prop_vlen_get(Object *obj, Visitor *v, const char *name, + void *opaque, Error **errp) +{ + uint16_t value = RISCV_CPU(obj)->cfg.vlen; + + visit_type_uint16(v, name, &value, errp); +} + +static const PropertyInfo prop_vlen = { + .name = "vlen", + .get = prop_vlen_get, + .set = prop_vlen_set, +}; + Property riscv_cpu_options[] = { - DEFINE_PROP_UINT16("vlen", RISCVCPU, cfg.vlen, 128), DEFINE_PROP_UINT16("elen", RISCVCPU, cfg.elen, 64), DEFINE_PROP_UINT16("cbom_blocksize", RISCVCPU, cfg.cbom_blocksize, 64), @@ -XXX,XX +XXX,XX @@ static Property riscv_cpu_properties[] = { {.name = "priv_spec", .info = &prop_priv_spec}, {.name = "vext_spec", .info = &prop_vext_spec}, + {.name = "vlen", .info = &prop_vlen}, + #ifndef CONFIG_USER_ONLY DEFINE_PROP_UINT64("resetvec", RISCVCPU, env.resetvec, DEFAULT_RSTVEC), #endif 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_validate_misa_mxl(RISCVCPU *cpu, Error **errp) static void riscv_cpu_validate_v(CPURISCVState *env, RISCVCPUConfig *cfg, Error **errp) { - if (!is_power_of_2(cfg->vlen)) { - error_setg(errp, "Vector extension VLEN must be power of 2"); - return; - } - if (cfg->vlen > RV_VLEN_MAX || cfg->vlen < 128) { error_setg(errp, "Vector extension implementation only supports VLEN " -- 2.43.0
From: Daniel Henrique Barboza <dbarboza@ventanamicro.com> Do the same thing we did with 'vlen' in the previous patch with 'elen'. Signed-off-by: Daniel Henrique Barboza <dbarboza@ventanamicro.com> Reviewed-by: Alistair Francis <alistair.francis@wdc.com> Tested-by: Vladimir Isaev <vladimir.isaev@syntacore.com> Message-ID: <20240105230546.265053-10-dbarboza@ventanamicro.com> Signed-off-by: Alistair Francis <alistair.francis@wdc.com> --- target/riscv/cpu.c | 44 ++++++++++++++++++++++++++++++++++++-- target/riscv/tcg/tcg-cpu.c | 5 ----- 2 files changed, 42 insertions(+), 7 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 @@ static void riscv_cpu_init(Object *obj) /* Default values for non-bool cpu properties */ cpu->cfg.pmu_mask = MAKE_64BIT_MASK(3, 16); cpu->cfg.vlen = 128; + cpu->cfg.elen = 64; cpu->env.vext_ver = VEXT_VERSION_1_00_0; } @@ -XXX,XX +XXX,XX @@ static const PropertyInfo prop_vlen = { .set = prop_vlen_set, }; -Property riscv_cpu_options[] = { - DEFINE_PROP_UINT16("elen", RISCVCPU, cfg.elen, 64), +static void prop_elen_set(Object *obj, Visitor *v, const char *name, + void *opaque, Error **errp) +{ + RISCVCPU *cpu = RISCV_CPU(obj); + uint16_t value; + + if (!visit_type_uint16(v, name, &value, errp)) { + return; + } + + if (!is_power_of_2(value)) { + error_setg(errp, "Vector extension ELEN must be power of 2"); + return; + } + + if (value != cpu->cfg.elen && riscv_cpu_is_vendor(obj)) { + cpu_set_prop_err(cpu, name, errp); + error_append_hint(errp, "Current '%s' val: %u\n", + name, cpu->cfg.elen); + return; + } + + cpu_option_add_user_setting(name, value); + cpu->cfg.elen = value; +} +static void prop_elen_get(Object *obj, Visitor *v, const char *name, + void *opaque, Error **errp) +{ + uint16_t value = RISCV_CPU(obj)->cfg.elen; + + visit_type_uint16(v, name, &value, errp); +} + +static const PropertyInfo prop_elen = { + .name = "elen", + .get = prop_elen_get, + .set = prop_elen_set, +}; + +Property riscv_cpu_options[] = { DEFINE_PROP_UINT16("cbom_blocksize", RISCVCPU, cfg.cbom_blocksize, 64), DEFINE_PROP_UINT16("cbop_blocksize", RISCVCPU, cfg.cbop_blocksize, 64), DEFINE_PROP_UINT16("cboz_blocksize", RISCVCPU, cfg.cboz_blocksize, 64), @@ -XXX,XX +XXX,XX @@ static Property riscv_cpu_properties[] = { {.name = "vext_spec", .info = &prop_vext_spec}, {.name = "vlen", .info = &prop_vlen}, + {.name = "elen", .info = &prop_elen}, #ifndef CONFIG_USER_ONLY DEFINE_PROP_UINT64("resetvec", RISCVCPU, env.resetvec, DEFAULT_RSTVEC), 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_validate_v(CPURISCVState *env, RISCVCPUConfig *cfg, return; } - if (!is_power_of_2(cfg->elen)) { - error_setg(errp, "Vector extension ELEN must be power of 2"); - return; - } - if (cfg->elen > 64 || cfg->elen < 8) { error_setg(errp, "Vector extension implementation only supports ELEN " -- 2.43.0
From: Daniel Henrique Barboza <dbarboza@ventanamicro.com> To turn cbom_blocksize and cboz_blocksize into class properties we need KVM specific changes. KVM is creating its own version of these options with a customized setter() that prevents users from picking an invalid value during init() time. This comes at the cost of duplicating each option that KVM supports. This will keep happening for each new shared option KVM implements in the future. We can avoid that by using the same property TCG uses and adding specific KVM handling during finalize() time, like TCG already does with riscv_tcg_cpu_finalize_features(). To do that, the common CPU property offers a way of knowing if an option was user set or not, sparing us from doing unneeded syscalls. riscv_kvm_cpu_finalize_features() is then created using the same KVMScratch CPU we already use during init() time, since finalize() time is still too early to use the official KVM CPU for it. cbom_blocksize and cboz_blocksize are then handled during finalize() in the same way they're handled by their KVM specific setter. With this change we can proceed with the blocksize changes in the common code without breaking the KVM driver. Signed-off-by: Daniel Henrique Barboza <dbarboza@ventanamicro.com> Reviewed-by: Alistair Francis <alistair.francis@wdc.com> tested-by tags added, rebased with Alistair's riscv-to-apply.next. Message-ID: <20240112140201.127083-2-dbarboza@ventanamicro.com> Signed-off-by: Alistair Francis <alistair.francis@wdc.com> --- target/riscv/cpu.h | 1 + target/riscv/kvm/kvm_riscv.h | 1 + target/riscv/cpu.c | 16 +++++++--- target/riscv/kvm/kvm-cpu.c | 59 ++++++++++++++++++++++++++++++++++++ 4 files changed, 72 insertions(+), 5 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_tlb_fill(CPUState *cs, vaddr address, int size, MMUAccessType access_type, int mmu_idx, bool probe, uintptr_t retaddr); char *riscv_isa_string(RISCVCPU *cpu); +bool riscv_cpu_option_set(const char *optname); #ifndef CONFIG_USER_ONLY void riscv_cpu_do_transaction_failed(CPUState *cs, hwaddr physaddr, diff --git a/target/riscv/kvm/kvm_riscv.h b/target/riscv/kvm/kvm_riscv.h index XXXXXXX..XXXXXXX 100644 --- a/target/riscv/kvm/kvm_riscv.h +++ b/target/riscv/kvm/kvm_riscv.h @@ -XXX,XX +XXX,XX @@ void kvm_riscv_aia_create(MachineState *machine, uint64_t group_shift, uint64_t guest_num); void riscv_kvm_aplic_request(void *opaque, int irq, int level); int kvm_riscv_sync_mpstate_to_kvm(RISCVCPU *cpu, int state); +void riscv_kvm_cpu_finalize_features(RISCVCPU *cpu, Error **errp); #endif 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 cpu_option_add_user_setting(const char *optname, uint32_t value) GUINT_TO_POINTER(value)); } +bool riscv_cpu_option_set(const char *optname) +{ + return g_hash_table_contains(general_user_opts, optname); +} + #define ISA_EXT_DATA_ENTRY(_name, _min_ver, _prop) \ {#_name, _min_ver, CPU_CFG_OFFSET(_prop)} @@ -XXX,XX +XXX,XX @@ void riscv_cpu_finalize_features(RISCVCPU *cpu, Error **errp) } #endif - /* - * KVM accel does not have a specialized finalize() - * callback because its extensions are validated - * in the get()/set() callbacks of each property. - */ if (tcg_enabled()) { riscv_tcg_cpu_finalize_features(cpu, &local_err); if (local_err != NULL) { error_propagate(errp, local_err); return; } + } else if (kvm_enabled()) { + riscv_kvm_cpu_finalize_features(cpu, &local_err); + if (local_err != NULL) { + error_propagate(errp, local_err); + return; + } } } 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 bool kvm_cpu_realize(CPUState *cs, Error **errp) return true; } +void riscv_kvm_cpu_finalize_features(RISCVCPU *cpu, Error **errp) +{ + CPURISCVState *env = &cpu->env; + KVMScratchCPU kvmcpu; + struct kvm_one_reg reg; + uint64_t val; + int ret; + + /* short-circuit without spinning the scratch CPU */ + if (!cpu->cfg.ext_zicbom && !cpu->cfg.ext_zicboz) { + return; + } + + if (!kvm_riscv_create_scratch_vcpu(&kvmcpu)) { + error_setg(errp, "Unable to create scratch KVM cpu"); + return; + } + + if (cpu->cfg.ext_zicbom && + riscv_cpu_option_set(kvm_cbom_blocksize.name)) { + + reg.id = kvm_riscv_reg_id_ulong(env, KVM_REG_RISCV_CONFIG, + kvm_cbom_blocksize.kvm_reg_id); + reg.addr = (uint64_t)&val; + ret = ioctl(kvmcpu.cpufd, KVM_GET_ONE_REG, ®); + if (ret != 0) { + error_setg(errp, "Unable to read cbom_blocksize, error %d", errno); + return; + } + + if (cpu->cfg.cbom_blocksize != val) { + error_setg(errp, "Unable to set cbom_blocksize to a different " + "value than the host (%lu)", val); + return; + } + } + + if (cpu->cfg.ext_zicboz && + riscv_cpu_option_set(kvm_cboz_blocksize.name)) { + + reg.id = kvm_riscv_reg_id_ulong(env, KVM_REG_RISCV_CONFIG, + kvm_cboz_blocksize.kvm_reg_id); + reg.addr = (uint64_t)&val; + ret = ioctl(kvmcpu.cpufd, KVM_GET_ONE_REG, ®); + if (ret != 0) { + error_setg(errp, "Unable to read cboz_blocksize, error %d", errno); + return; + } + + if (cpu->cfg.cboz_blocksize != val) { + error_setg(errp, "Unable to set cboz_blocksize to a different " + "value than the host (%lu)", val); + return; + } + } + + kvm_riscv_destroy_scratch_vcpu(&kvmcpu); +} + static void kvm_cpu_accel_class_init(ObjectClass *oc, void *data) { AccelCPUClass *acc = ACCEL_CPU_CLASS(oc); -- 2.43.0
From: Daniel Henrique Barboza <dbarboza@ventanamicro.com> After adding a KVM finalize() implementation, turn cbom_blocksize into a class property. Follow the same design we used with 'vlen' and 'elen'. The duplicated 'cbom_blocksize' KVM property can be removed from kvm_riscv_add_cpu_user_properties(). Signed-off-by: Daniel Henrique Barboza <dbarboza@ventanamicro.com> Reviewed-by: Alistair Francis <alistair.francis@wdc.com> Tested-by: Vladimir Isaev <vladimir.isaev@syntacore.com> tested-by tags added, rebased with Alistair's riscv-to-apply.next. Message-ID: <20240112140201.127083-3-dbarboza@ventanamicro.com> Signed-off-by: Alistair Francis <alistair.francis@wdc.com> --- target/riscv/cpu.c | 39 +++++++++++++++++++++++++++++++++++++- target/riscv/kvm/kvm-cpu.c | 4 ---- 2 files changed, 38 insertions(+), 5 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 @@ static void riscv_cpu_init(Object *obj) cpu->cfg.pmu_mask = MAKE_64BIT_MASK(3, 16); cpu->cfg.vlen = 128; cpu->cfg.elen = 64; + cpu->cfg.cbom_blocksize = 64; cpu->env.vext_ver = VEXT_VERSION_1_00_0; } @@ -XXX,XX +XXX,XX @@ static const PropertyInfo prop_elen = { .set = prop_elen_set, }; +static void prop_cbom_blksize_set(Object *obj, Visitor *v, const char *name, + void *opaque, Error **errp) +{ + RISCVCPU *cpu = RISCV_CPU(obj); + uint16_t value; + + if (!visit_type_uint16(v, name, &value, errp)) { + return; + } + + if (value != cpu->cfg.cbom_blocksize && riscv_cpu_is_vendor(obj)) { + cpu_set_prop_err(cpu, name, errp); + error_append_hint(errp, "Current '%s' val: %u\n", + name, cpu->cfg.cbom_blocksize); + return; + } + + cpu_option_add_user_setting(name, value); + cpu->cfg.cbom_blocksize = value; +} + +static void prop_cbom_blksize_get(Object *obj, Visitor *v, const char *name, + void *opaque, Error **errp) +{ + uint16_t value = RISCV_CPU(obj)->cfg.cbom_blocksize; + + visit_type_uint16(v, name, &value, errp); +} + +static const PropertyInfo prop_cbom_blksize = { + .name = "cbom_blocksize", + .get = prop_cbom_blksize_get, + .set = prop_cbom_blksize_set, +}; + Property riscv_cpu_options[] = { - DEFINE_PROP_UINT16("cbom_blocksize", RISCVCPU, cfg.cbom_blocksize, 64), DEFINE_PROP_UINT16("cbop_blocksize", RISCVCPU, cfg.cbop_blocksize, 64), DEFINE_PROP_UINT16("cboz_blocksize", RISCVCPU, cfg.cboz_blocksize, 64), @@ -XXX,XX +XXX,XX @@ static Property riscv_cpu_properties[] = { {.name = "vlen", .info = &prop_vlen}, {.name = "elen", .info = &prop_elen}, + {.name = "cbom_blocksize", .info = &prop_cbom_blksize}, + #ifndef CONFIG_USER_ONLY DEFINE_PROP_UINT64("resetvec", RISCVCPU, env.resetvec, DEFAULT_RSTVEC), #endif 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_add_cpu_user_properties(Object *cpu_obj) NULL, multi_cfg); } - object_property_add(cpu_obj, "cbom_blocksize", "uint16", - NULL, kvm_cpu_set_cbomz_blksize, - NULL, &kvm_cbom_blocksize); - object_property_add(cpu_obj, "cboz_blocksize", "uint16", NULL, kvm_cpu_set_cbomz_blksize, NULL, &kvm_cboz_blocksize); -- 2.43.0
From: Daniel Henrique Barboza <dbarboza@ventanamicro.com> Do the same we did with 'cbom_blocksize' in the previous patch. Signed-off-by: Daniel Henrique Barboza <dbarboza@ventanamicro.com> Reviewed-by: Alistair Francis <alistair.francis@wdc.com> Tested-by: Vladimir Isaev <vladimir.isaev@syntacore.com> tested-by tags added, rebased with Alistair's riscv-to-apply.next. Message-ID: <20240112140201.127083-4-dbarboza@ventanamicro.com> Signed-off-by: Alistair Francis <alistair.francis@wdc.com> --- target/riscv/cpu.c | 38 +++++++++++++++++++++++++++++++++++++- 1 file changed, 37 insertions(+), 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 @@ static void riscv_cpu_init(Object *obj) cpu->cfg.vlen = 128; cpu->cfg.elen = 64; cpu->cfg.cbom_blocksize = 64; + cpu->cfg.cbop_blocksize = 64; cpu->env.vext_ver = VEXT_VERSION_1_00_0; } @@ -XXX,XX +XXX,XX @@ static const PropertyInfo prop_cbom_blksize = { .set = prop_cbom_blksize_set, }; +static void prop_cbop_blksize_set(Object *obj, Visitor *v, const char *name, + void *opaque, Error **errp) +{ + RISCVCPU *cpu = RISCV_CPU(obj); + uint16_t value; + + if (!visit_type_uint16(v, name, &value, errp)) { + return; + } + + if (value != cpu->cfg.cbop_blocksize && riscv_cpu_is_vendor(obj)) { + cpu_set_prop_err(cpu, name, errp); + error_append_hint(errp, "Current '%s' val: %u\n", + name, cpu->cfg.cbop_blocksize); + return; + } + + cpu_option_add_user_setting(name, value); + cpu->cfg.cbop_blocksize = value; +} + +static void prop_cbop_blksize_get(Object *obj, Visitor *v, const char *name, + void *opaque, Error **errp) +{ + uint16_t value = RISCV_CPU(obj)->cfg.cbop_blocksize; + + visit_type_uint16(v, name, &value, errp); +} + +static const PropertyInfo prop_cbop_blksize = { + .name = "cbop_blocksize", + .get = prop_cbop_blksize_get, + .set = prop_cbop_blksize_set, +}; + Property riscv_cpu_options[] = { - DEFINE_PROP_UINT16("cbop_blocksize", RISCVCPU, cfg.cbop_blocksize, 64), DEFINE_PROP_UINT16("cboz_blocksize", RISCVCPU, cfg.cboz_blocksize, 64), DEFINE_PROP_END_OF_LIST(), @@ -XXX,XX +XXX,XX @@ static Property riscv_cpu_properties[] = { {.name = "elen", .info = &prop_elen}, {.name = "cbom_blocksize", .info = &prop_cbom_blksize}, + {.name = "cbop_blocksize", .info = &prop_cbop_blksize}, #ifndef CONFIG_USER_ONLY DEFINE_PROP_UINT64("resetvec", RISCVCPU, env.resetvec, DEFAULT_RSTVEC), -- 2.43.0
From: Daniel Henrique Barboza <dbarboza@ventanamicro.com> And remove the now unused kvm_cpu_set_cbomz_blksize() setter. Signed-off-by: Daniel Henrique Barboza <dbarboza@ventanamicro.com> Reviewed-by: Alistair Francis <alistair.francis@wdc.com> Tested-by: Vladimir Isaev <vladimir.isaev@syntacore.com> tested-by tags added, rebased with Alistair's riscv-to-apply.next. Message-ID: <20240112140201.127083-5-dbarboza@ventanamicro.com> Signed-off-by: Alistair Francis <alistair.francis@wdc.com> --- target/riscv/cpu.c | 38 +++++++++++++++++++++++++++++++++++++- target/riscv/kvm/kvm-cpu.c | 28 ---------------------------- 2 files changed, 37 insertions(+), 29 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 @@ static void riscv_cpu_init(Object *obj) cpu->cfg.elen = 64; cpu->cfg.cbom_blocksize = 64; cpu->cfg.cbop_blocksize = 64; + cpu->cfg.cboz_blocksize = 64; cpu->env.vext_ver = VEXT_VERSION_1_00_0; } @@ -XXX,XX +XXX,XX @@ static const PropertyInfo prop_cbop_blksize = { .set = prop_cbop_blksize_set, }; +static void prop_cboz_blksize_set(Object *obj, Visitor *v, const char *name, + void *opaque, Error **errp) +{ + RISCVCPU *cpu = RISCV_CPU(obj); + uint16_t value; + + if (!visit_type_uint16(v, name, &value, errp)) { + return; + } + + if (value != cpu->cfg.cboz_blocksize && riscv_cpu_is_vendor(obj)) { + cpu_set_prop_err(cpu, name, errp); + error_append_hint(errp, "Current '%s' val: %u\n", + name, cpu->cfg.cboz_blocksize); + return; + } + + cpu_option_add_user_setting(name, value); + cpu->cfg.cboz_blocksize = value; +} + +static void prop_cboz_blksize_get(Object *obj, Visitor *v, const char *name, + void *opaque, Error **errp) +{ + uint16_t value = RISCV_CPU(obj)->cfg.cboz_blocksize; + + visit_type_uint16(v, name, &value, errp); +} + +static const PropertyInfo prop_cboz_blksize = { + .name = "cboz_blocksize", + .get = prop_cboz_blksize_get, + .set = prop_cboz_blksize_set, +}; + Property riscv_cpu_options[] = { - DEFINE_PROP_UINT16("cboz_blocksize", RISCVCPU, cfg.cboz_blocksize, 64), DEFINE_PROP_END_OF_LIST(), }; @@ -XXX,XX +XXX,XX @@ static Property riscv_cpu_properties[] = { {.name = "cbom_blocksize", .info = &prop_cbom_blksize}, {.name = "cbop_blocksize", .info = &prop_cbop_blksize}, + {.name = "cboz_blocksize", .info = &prop_cboz_blksize}, #ifndef CONFIG_USER_ONLY DEFINE_PROP_UINT64("resetvec", RISCVCPU, env.resetvec, DEFAULT_RSTVEC), 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 KVMCPUConfig kvm_cboz_blocksize = { .kvm_reg_id = KVM_REG_RISCV_CONFIG_REG(zicboz_block_size) }; -static void kvm_cpu_set_cbomz_blksize(Object *obj, Visitor *v, - const char *name, - void *opaque, Error **errp) -{ - KVMCPUConfig *cbomz_cfg = opaque; - RISCVCPU *cpu = RISCV_CPU(obj); - uint16_t value, *host_val; - - if (!visit_type_uint16(v, name, &value, errp)) { - return; - } - - host_val = kvmconfig_get_cfg_addr(cpu, cbomz_cfg); - - if (value != *host_val) { - error_report("Unable to set %s to a different value than " - "the host (%u)", - cbomz_cfg->name, *host_val); - exit(EXIT_FAILURE); - } - - cbomz_cfg->user_set = true; -} - static void kvm_riscv_update_cpu_cfg_isa_ext(RISCVCPU *cpu, CPUState *cs) { CPURISCVState *env = &cpu->env; @@ -XXX,XX +XXX,XX @@ static void kvm_riscv_add_cpu_user_properties(Object *cpu_obj) NULL, multi_cfg); } - object_property_add(cpu_obj, "cboz_blocksize", "uint16", - NULL, kvm_cpu_set_cbomz_blksize, - NULL, &kvm_cboz_blocksize); - riscv_cpu_add_kvm_unavail_prop_array(cpu_obj, riscv_cpu_extensions); riscv_cpu_add_kvm_unavail_prop_array(cpu_obj, riscv_cpu_vendor_exts); riscv_cpu_add_kvm_unavail_prop_array(cpu_obj, riscv_cpu_experimental_exts); -- 2.43.0
From: Daniel Henrique Barboza <dbarboza@ventanamicro.com> The array is empty and can be removed. Signed-off-by: Daniel Henrique Barboza <dbarboza@ventanamicro.com> Reviewed-by: Alistair Francis <alistair.francis@wdc.com> Tested-by: Vladimir Isaev <vladimir.isaev@syntacore.com> tested-by tags added, rebased with Alistair's riscv-to-apply.next. Message-ID: <20240112140201.127083-6-dbarboza@ventanamicro.com> Signed-off-by: Alistair Francis <alistair.francis@wdc.com> --- target/riscv/cpu.h | 1 - target/riscv/cpu.c | 5 ----- target/riscv/kvm/kvm-cpu.c | 9 --------- target/riscv/tcg/tcg-cpu.c | 4 ---- 4 files changed, 19 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_vendor_exts[]; extern const RISCVCPUMultiExtConfig riscv_cpu_experimental_exts[]; extern const RISCVCPUMultiExtConfig riscv_cpu_named_features[]; extern const RISCVCPUMultiExtConfig riscv_cpu_deprecated_exts[]; -extern Property riscv_cpu_options[]; 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 @@ static const PropertyInfo prop_cboz_blksize = { .set = prop_cboz_blksize_set, }; -Property riscv_cpu_options[] = { - - DEFINE_PROP_END_OF_LIST(), -}; - /* * RVA22U64 defines some 'named features' or 'synthetic extensions' * that are cache related: Za64rs, Zic64b, Ziccif, Ziccrse, Ziccamoa 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 @@ void kvm_riscv_aia_create(MachineState *machine, uint64_t group_shift, static void kvm_cpu_instance_init(CPUState *cs) { Object *obj = OBJECT(RISCV_CPU(cs)); - DeviceState *dev = DEVICE(obj); riscv_init_kvm_registers(obj); kvm_riscv_add_cpu_user_properties(obj); - - for (Property *prop = riscv_cpu_options; prop && prop->name; prop++) { - /* Check if we have a specific KVM handler for the option */ - if (object_property_find(obj, prop->name)) { - continue; - } - qdev_property_add_static(dev, prop); - } } /* 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_user_properties(Object *obj) riscv_cpu_add_multiext_prop_array(obj, riscv_cpu_deprecated_exts); riscv_cpu_add_profiles(obj); - - for (Property *prop = riscv_cpu_options; prop && prop->name; prop++) { - qdev_property_add_static(DEVICE(obj), prop); - } } /* -- 2.43.0
From: Daniel Henrique Barboza <dbarboza@ventanamicro.com> Keep all class properties in riscv_cpu_properties[]. Signed-off-by: Daniel Henrique Barboza <dbarboza@ventanamicro.com> Reviewed-by: Alistair Francis <alistair.francis@wdc.com> Tested-by: Vladimir Isaev <vladimir.isaev@syntacore.com> tested-by tags added, rebased with Alistair's riscv-to-apply.next. Message-ID: <20240112140201.127083-7-dbarboza@ventanamicro.com> Signed-off-by: Alistair Francis <alistair.francis@wdc.com> --- target/riscv/cpu.c | 69 +++++++++++++++++++++++++--------------------- 1 file changed, 37 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 @@ static const PropertyInfo prop_cboz_blksize = { .set = prop_cboz_blksize_set, }; +static void prop_mvendorid_set(Object *obj, Visitor *v, const char *name, + void *opaque, Error **errp) +{ + bool dynamic_cpu = riscv_cpu_is_dynamic(obj); + RISCVCPU *cpu = RISCV_CPU(obj); + uint32_t prev_val = cpu->cfg.mvendorid; + uint32_t value; + + if (!visit_type_uint32(v, name, &value, errp)) { + return; + } + + if (!dynamic_cpu && prev_val != value) { + error_setg(errp, "Unable to change %s mvendorid (0x%x)", + object_get_typename(obj), prev_val); + return; + } + + cpu->cfg.mvendorid = value; +} + +static void prop_mvendorid_get(Object *obj, Visitor *v, const char *name, + void *opaque, Error **errp) +{ + uint32_t value = RISCV_CPU(obj)->cfg.mvendorid; + + visit_type_uint32(v, name, &value, errp); +} + +static const PropertyInfo prop_mvendorid = { + .name = "mvendorid", + .get = prop_mvendorid_get, + .set = prop_mvendorid_set, +}; + /* * RVA22U64 defines some 'named features' or 'synthetic extensions' * that are cache related: Za64rs, Zic64b, Ziccif, Ziccrse, Ziccamoa @@ -XXX,XX +XXX,XX @@ static Property riscv_cpu_properties[] = { {.name = "cbop_blocksize", .info = &prop_cbop_blksize}, {.name = "cboz_blocksize", .info = &prop_cboz_blksize}, + {.name = "mvendorid", .info = &prop_mvendorid}, + #ifndef CONFIG_USER_ONLY DEFINE_PROP_UINT64("resetvec", RISCVCPU, env.resetvec, DEFAULT_RSTVEC), #endif @@ -XXX,XX +XXX,XX @@ static const struct SysemuCPUOps riscv_sysemu_ops = { }; #endif -static void cpu_set_mvendorid(Object *obj, Visitor *v, const char *name, - void *opaque, Error **errp) -{ - bool dynamic_cpu = riscv_cpu_is_dynamic(obj); - RISCVCPU *cpu = RISCV_CPU(obj); - uint32_t prev_val = cpu->cfg.mvendorid; - uint32_t value; - - if (!visit_type_uint32(v, name, &value, errp)) { - return; - } - - if (!dynamic_cpu && prev_val != value) { - error_setg(errp, "Unable to change %s mvendorid (0x%x)", - object_get_typename(obj), prev_val); - return; - } - - cpu->cfg.mvendorid = value; -} - -static void cpu_get_mvendorid(Object *obj, Visitor *v, const char *name, - void *opaque, Error **errp) -{ - uint32_t value = RISCV_CPU(obj)->cfg.mvendorid; - - visit_type_uint32(v, name, &value, errp); -} - static void cpu_set_mimpid(Object *obj, Visitor *v, const char *name, void *opaque, Error **errp) { @@ -XXX,XX +XXX,XX @@ static void riscv_cpu_class_init(ObjectClass *c, void *data) cc->gdb_arch_name = riscv_gdb_arch_name; cc->gdb_get_dynamic_xml = riscv_gdb_get_dynamic_xml; - object_class_property_add(c, "mvendorid", "uint32", cpu_get_mvendorid, - cpu_set_mvendorid, NULL, NULL); - object_class_property_add(c, "mimpid", "uint64", cpu_get_mimpid, cpu_set_mimpid, NULL, NULL); -- 2.43.0
From: Daniel Henrique Barboza <dbarboza@ventanamicro.com> Keep all class properties in riscv_cpu_properties[]. Signed-off-by: Daniel Henrique Barboza <dbarboza@ventanamicro.com> Reviewed-by: Alistair Francis <alistair.francis@wdc.com> Tested-by: Vladimir Isaev <vladimir.isaev@syntacore.com> tested-by tags added, rebased with Alistair's riscv-to-apply.next. Message-ID: <20240112140201.127083-8-dbarboza@ventanamicro.com> Signed-off-by: Alistair Francis <alistair.francis@wdc.com> --- target/riscv/cpu.c | 68 ++++++++++++++++++++++++---------------------- 1 file changed, 36 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 @@ static const PropertyInfo prop_mvendorid = { .set = prop_mvendorid_set, }; +static void prop_mimpid_set(Object *obj, Visitor *v, const char *name, + void *opaque, Error **errp) +{ + bool dynamic_cpu = riscv_cpu_is_dynamic(obj); + RISCVCPU *cpu = RISCV_CPU(obj); + uint64_t prev_val = cpu->cfg.mimpid; + uint64_t value; + + if (!visit_type_uint64(v, name, &value, errp)) { + return; + } + + if (!dynamic_cpu && prev_val != value) { + error_setg(errp, "Unable to change %s mimpid (0x%" PRIu64 ")", + object_get_typename(obj), prev_val); + return; + } + + cpu->cfg.mimpid = value; +} + +static void prop_mimpid_get(Object *obj, Visitor *v, const char *name, + void *opaque, Error **errp) +{ + uint64_t value = RISCV_CPU(obj)->cfg.mimpid; + + visit_type_uint64(v, name, &value, errp); +} + +static const PropertyInfo prop_mimpid = { + .name = "mimpid", + .get = prop_mimpid_get, + .set = prop_mimpid_set, +}; + /* * RVA22U64 defines some 'named features' or 'synthetic extensions' * that are cache related: Za64rs, Zic64b, Ziccif, Ziccrse, Ziccamoa @@ -XXX,XX +XXX,XX @@ static Property riscv_cpu_properties[] = { {.name = "cboz_blocksize", .info = &prop_cboz_blksize}, {.name = "mvendorid", .info = &prop_mvendorid}, + {.name = "mimpid", .info = &prop_mimpid}, #ifndef CONFIG_USER_ONLY DEFINE_PROP_UINT64("resetvec", RISCVCPU, env.resetvec, DEFAULT_RSTVEC), @@ -XXX,XX +XXX,XX @@ static const struct SysemuCPUOps riscv_sysemu_ops = { }; #endif -static void cpu_set_mimpid(Object *obj, Visitor *v, const char *name, - void *opaque, Error **errp) -{ - bool dynamic_cpu = riscv_cpu_is_dynamic(obj); - RISCVCPU *cpu = RISCV_CPU(obj); - uint64_t prev_val = cpu->cfg.mimpid; - uint64_t value; - - if (!visit_type_uint64(v, name, &value, errp)) { - return; - } - - if (!dynamic_cpu && prev_val != value) { - error_setg(errp, "Unable to change %s mimpid (0x%" PRIu64 ")", - object_get_typename(obj), prev_val); - return; - } - - cpu->cfg.mimpid = value; -} - -static void cpu_get_mimpid(Object *obj, Visitor *v, const char *name, - void *opaque, Error **errp) -{ - uint64_t value = RISCV_CPU(obj)->cfg.mimpid; - - visit_type_uint64(v, name, &value, errp); -} - static void cpu_set_marchid(Object *obj, Visitor *v, const char *name, void *opaque, Error **errp) { @@ -XXX,XX +XXX,XX @@ static void riscv_cpu_class_init(ObjectClass *c, void *data) cc->gdb_arch_name = riscv_gdb_arch_name; cc->gdb_get_dynamic_xml = riscv_gdb_get_dynamic_xml; - object_class_property_add(c, "mimpid", "uint64", cpu_get_mimpid, - cpu_set_mimpid, NULL, NULL); - object_class_property_add(c, "marchid", "uint64", cpu_get_marchid, cpu_set_marchid, NULL, NULL); -- 2.43.0
From: Daniel Henrique Barboza <dbarboza@ventanamicro.com> Keep all class properties in riscv_cpu_properties[]. Signed-off-by: Daniel Henrique Barboza <dbarboza@ventanamicro.com> Reviewed-by: Alistair Francis <alistair.francis@wdc.com> Tested-by: Vladimir Isaev <vladimir.isaev@syntacore.com> tested-by tags added, rebased with Alistair's riscv-to-apply.next. Message-ID: <20240112140201.127083-9-dbarboza@ventanamicro.com> Signed-off-by: Alistair Francis <alistair.francis@wdc.com> --- target/riscv/cpu.c | 110 +++++++++++++++++++++++---------------------- 1 file changed, 57 insertions(+), 53 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 @@ static const PropertyInfo prop_mimpid = { .set = prop_mimpid_set, }; +static void prop_marchid_set(Object *obj, Visitor *v, const char *name, + void *opaque, Error **errp) +{ + bool dynamic_cpu = riscv_cpu_is_dynamic(obj); + RISCVCPU *cpu = RISCV_CPU(obj); + uint64_t prev_val = cpu->cfg.marchid; + uint64_t value, invalid_val; + uint32_t mxlen = 0; + + if (!visit_type_uint64(v, name, &value, errp)) { + return; + } + + if (!dynamic_cpu && prev_val != value) { + error_setg(errp, "Unable to change %s marchid (0x%" PRIu64 ")", + object_get_typename(obj), prev_val); + return; + } + + switch (riscv_cpu_mxl(&cpu->env)) { + case MXL_RV32: + mxlen = 32; + break; + case MXL_RV64: + case MXL_RV128: + mxlen = 64; + break; + default: + g_assert_not_reached(); + } + + invalid_val = 1LL << (mxlen - 1); + + if (value == invalid_val) { + error_setg(errp, "Unable to set marchid with MSB (%u) bit set " + "and the remaining bits zero", mxlen); + return; + } + + cpu->cfg.marchid = value; +} + +static void prop_marchid_get(Object *obj, Visitor *v, const char *name, + void *opaque, Error **errp) +{ + uint64_t value = RISCV_CPU(obj)->cfg.marchid; + + visit_type_uint64(v, name, &value, errp); +} + +static const PropertyInfo prop_marchid = { + .name = "marchid", + .get = prop_marchid_get, + .set = prop_marchid_set, +}; + /* * RVA22U64 defines some 'named features' or 'synthetic extensions' * that are cache related: Za64rs, Zic64b, Ziccif, Ziccrse, Ziccamoa @@ -XXX,XX +XXX,XX @@ static Property riscv_cpu_properties[] = { {.name = "mvendorid", .info = &prop_mvendorid}, {.name = "mimpid", .info = &prop_mimpid}, + {.name = "marchid", .info = &prop_marchid}, #ifndef CONFIG_USER_ONLY DEFINE_PROP_UINT64("resetvec", RISCVCPU, env.resetvec, DEFAULT_RSTVEC), @@ -XXX,XX +XXX,XX @@ static const struct SysemuCPUOps riscv_sysemu_ops = { }; #endif -static void cpu_set_marchid(Object *obj, Visitor *v, const char *name, - void *opaque, Error **errp) -{ - bool dynamic_cpu = riscv_cpu_is_dynamic(obj); - RISCVCPU *cpu = RISCV_CPU(obj); - uint64_t prev_val = cpu->cfg.marchid; - uint64_t value, invalid_val; - uint32_t mxlen = 0; - - if (!visit_type_uint64(v, name, &value, errp)) { - return; - } - - if (!dynamic_cpu && prev_val != value) { - error_setg(errp, "Unable to change %s marchid (0x%" PRIu64 ")", - object_get_typename(obj), prev_val); - return; - } - - switch (riscv_cpu_mxl(&cpu->env)) { - case MXL_RV32: - mxlen = 32; - break; - case MXL_RV64: - case MXL_RV128: - mxlen = 64; - break; - default: - g_assert_not_reached(); - } - - invalid_val = 1LL << (mxlen - 1); - - if (value == invalid_val) { - error_setg(errp, "Unable to set marchid with MSB (%u) bit set " - "and the remaining bits zero", mxlen); - return; - } - - cpu->cfg.marchid = value; -} - -static void cpu_get_marchid(Object *obj, Visitor *v, const char *name, - void *opaque, Error **errp) -{ - uint64_t value = RISCV_CPU(obj)->cfg.marchid; - - visit_type_uint64(v, name, &value, errp); -} - static void riscv_cpu_class_init(ObjectClass *c, void *data) { RISCVCPUClass *mcc = RISCV_CPU_CLASS(c); @@ -XXX,XX +XXX,XX @@ static void riscv_cpu_class_init(ObjectClass *c, void *data) cc->gdb_arch_name = riscv_gdb_arch_name; cc->gdb_get_dynamic_xml = riscv_gdb_get_dynamic_xml; - object_class_property_add(c, "marchid", "uint64", cpu_get_marchid, - cpu_set_marchid, NULL, NULL); - device_class_set_props(dc, riscv_cpu_properties); } -- 2.43.0
From: Alvin Chang <alvinga@andestech.com> The debug Sdtrig extension defines an CSR "mcontext". This commit implements its predicate and read/write operations into CSR table. Its value is reset as 0 when the trigger module is reset. Signed-off-by: Alvin Chang <alvinga@andestech.com> Reviewed-by: Alistair Francis <alistair.francis@wdc.com> Reviewed-by: Daniel Henrique Barboza <dbarboza@ventanamicro.com> Message-ID: <20231219123244.290935-1-alvinga@andestech.com> Signed-off-by: Alistair Francis <alistair.francis@wdc.com> --- target/riscv/cpu.h | 1 + target/riscv/cpu_bits.h | 7 +++++++ target/riscv/csr.c | 36 +++++++++++++++++++++++++++++++----- target/riscv/debug.c | 2 ++ 4 files changed, 41 insertions(+), 5 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 tdata1[RV_MAX_TRIGGERS]; target_ulong tdata2[RV_MAX_TRIGGERS]; target_ulong tdata3[RV_MAX_TRIGGERS]; + target_ulong mcontext; struct CPUBreakpoint *cpu_breakpoint[RV_MAX_TRIGGERS]; struct CPUWatchpoint *cpu_watchpoint[RV_MAX_TRIGGERS]; QEMUTimer *itrigger_timer[RV_MAX_TRIGGERS]; 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_TDATA2 0x7a2 #define CSR_TDATA3 0x7a3 #define CSR_TINFO 0x7a4 +#define CSR_MCONTEXT 0x7a8 /* Debug Mode Registers */ #define CSR_DCSR 0x7b0 @@ -XXX,XX +XXX,XX @@ typedef enum RISCVException { /* JVT CSR bits */ #define JVT_MODE 0x3F #define JVT_BASE (~0x3F) + +/* Debug Sdtrig CSR masks */ +#define MCONTEXT32 0x0000003F +#define MCONTEXT64 0x0000000000001FFFULL +#define MCONTEXT32_HCONTEXT 0x0000007F +#define MCONTEXT64_HCONTEXT 0x0000000000003FFFULL #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 read_tinfo(CPURISCVState *env, int csrno, return RISCV_EXCP_NONE; } +static RISCVException read_mcontext(CPURISCVState *env, int csrno, + target_ulong *val) +{ + *val = env->mcontext; + return RISCV_EXCP_NONE; +} + +static RISCVException write_mcontext(CPURISCVState *env, int csrno, + target_ulong val) +{ + bool rv32 = riscv_cpu_mxl(env) == MXL_RV32 ? true : false; + int32_t mask; + + if (riscv_has_ext(env, RVH)) { + /* Spec suggest 7-bit for RV32 and 14-bit for RV64 w/ H extension */ + mask = rv32 ? MCONTEXT32_HCONTEXT : MCONTEXT64_HCONTEXT; + } else { + /* Spec suggest 6-bit for RV32 and 13-bit for RV64 w/o H extension */ + mask = rv32 ? MCONTEXT32 : MCONTEXT64; + } + + env->mcontext = val & mask; + return RISCV_EXCP_NONE; +} + /* * Functions to access Pointer Masking feature registers * We have to check if current priv lvl could modify @@ -XXX,XX +XXX,XX @@ riscv_csr_operations csr_ops[CSR_TABLE_SIZE] = { [CSR_PMPADDR15] = { "pmpaddr15", pmp, read_pmpaddr, write_pmpaddr }, /* Debug CSRs */ - [CSR_TSELECT] = { "tselect", debug, read_tselect, write_tselect }, - [CSR_TDATA1] = { "tdata1", debug, read_tdata, write_tdata }, - [CSR_TDATA2] = { "tdata2", debug, read_tdata, write_tdata }, - [CSR_TDATA3] = { "tdata3", debug, read_tdata, write_tdata }, - [CSR_TINFO] = { "tinfo", debug, read_tinfo, write_ignore }, + [CSR_TSELECT] = { "tselect", debug, read_tselect, write_tselect }, + [CSR_TDATA1] = { "tdata1", debug, read_tdata, write_tdata }, + [CSR_TDATA2] = { "tdata2", debug, read_tdata, write_tdata }, + [CSR_TDATA3] = { "tdata3", debug, read_tdata, write_tdata }, + [CSR_TINFO] = { "tinfo", debug, read_tinfo, write_ignore }, + [CSR_MCONTEXT] = { "mcontext", debug, read_mcontext, write_mcontext }, /* User Pointer Masking */ [CSR_UMTE] = { "umte", pointer_masking, read_umte, write_umte }, diff --git a/target/riscv/debug.c b/target/riscv/debug.c index XXXXXXX..XXXXXXX 100644 --- a/target/riscv/debug.c +++ b/target/riscv/debug.c @@ -XXX,XX +XXX,XX @@ void riscv_trigger_reset_hold(CPURISCVState *env) env->cpu_watchpoint[i] = NULL; timer_del(env->itrigger_timer[i]); } + + env->mcontext = 0; } -- 2.43.0
From: Daniel Henrique Barboza <dbarboza@ventanamicro.com> Our usage of 'vlenb' is overwhelming superior than the use of 'vlen'. We're using 'vlenb' most of the time, having to do 'vlen >> 3' or 'vlen / 8' in every instance. In hindsight we would be better if the 'vlenb' property was introduced instead of 'vlen'. That's not what happened, and now we can't easily get rid of it due to user scripts all around. What we can do, however, is to change our internal representation to use 'vlenb'. Add a 'vlenb' field in cpu->cfg. It'll be set via the existing 'vlen' property, i.e. setting 'vlen' will also set 'vlenb'. We'll replace all 'vlen >> 3' code to use 'vlenb' directly. Start with the single instance we have in target/riscv/cpu.c. Signed-off-by: Daniel Henrique Barboza <dbarboza@ventanamicro.com> Reviewed-by: Richard Henderson <richard.henderson@linaro.org> Reviewed-by: Alistair Francis <alistair.francis@wdc.com> Message-ID: <20240122161107.26737-2-dbarboza@ventanamicro.com> Signed-off-by: Alistair Francis <alistair.francis@wdc.com> --- target/riscv/cpu_cfg.h | 1 + target/riscv/cpu.c | 4 +++- 2 files changed, 4 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 @@ struct RISCVCPUConfig { uint32_t pmu_mask; uint16_t vlen; + uint16_t vlenb; uint16_t elen; uint16_t cbom_blocksize; uint16_t cbop_blocksize; 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) csr_ops[csrno].name, val); } } - uint16_t vlenb = cpu->cfg.vlen >> 3; + uint16_t vlenb = cpu->cfg.vlenb; for (i = 0; i < 32; i++) { qemu_fprintf(f, " %-8s ", riscv_rvv_regnames[i]); @@ -XXX,XX +XXX,XX @@ static void riscv_cpu_init(Object *obj) /* Default values for non-bool cpu properties */ cpu->cfg.pmu_mask = MAKE_64BIT_MASK(3, 16); cpu->cfg.vlen = 128; + cpu->cfg.vlenb = 128 >> 3; cpu->cfg.elen = 64; cpu->cfg.cbom_blocksize = 64; cpu->cfg.cbop_blocksize = 64; @@ -XXX,XX +XXX,XX @@ static void prop_vlen_set(Object *obj, Visitor *v, const char *name, cpu_option_add_user_setting(name, value); cpu->cfg.vlen = value; + cpu->cfg.vlenb = value >> 3; } static void prop_vlen_get(Object *obj, Visitor *v, const char *name, -- 2.43.0
From: Daniel Henrique Barboza <dbarboza@ventanamicro.com> As a bonus, we're being more idiomatic using cpu->cfg.vlenb when reading CSR_VLENB. Signed-off-by: Daniel Henrique Barboza <dbarboza@ventanamicro.com> Reviewed-by: Richard Henderson <richard.henderson@linaro.org> Reviewed-by: Alistair Francis <alistair.francis@wdc.com> Message-ID: <20240122161107.26737-3-dbarboza@ventanamicro.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 RISCVException read_vl(CPURISCVState *env, int csrno, static int read_vlenb(CPURISCVState *env, int csrno, target_ulong *val) { - *val = riscv_cpu_cfg(env)->vlen >> 3; + *val = riscv_cpu_cfg(env)->vlenb; return RISCV_EXCP_NONE; } @@ -XXX,XX +XXX,XX @@ static RISCVException write_vstart(CPURISCVState *env, int csrno, * The vstart CSR is defined to have only enough writable bits * to hold the largest element index, i.e. lg2(VLEN) bits. */ - env->vstart = val & ~(~0ULL << ctzl(riscv_cpu_cfg(env)->vlen)); + env->vstart = val & ~(~0ULL << ctzl(riscv_cpu_cfg(env)->vlenb << 3)); return RISCV_EXCP_NONE; } -- 2.43.0
From: Daniel Henrique Barboza <dbarboza@ventanamicro.com> Signed-off-by: Daniel Henrique Barboza <dbarboza@ventanamicro.com> Reviewed-by: Richard Henderson <richard.henderson@linaro.org> Reviewed-by: Alistair Francis <alistair.francis@wdc.com> Message-ID: <20240122161107.26737-4-dbarboza@ventanamicro.com> Signed-off-by: Alistair Francis <alistair.francis@wdc.com> --- target/riscv/gdbstub.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/target/riscv/gdbstub.c b/target/riscv/gdbstub.c index XXXXXXX..XXXXXXX 100644 --- a/target/riscv/gdbstub.c +++ b/target/riscv/gdbstub.c @@ -XXX,XX +XXX,XX @@ static int riscv_gdb_set_fpu(CPURISCVState *env, uint8_t *mem_buf, int n) static int riscv_gdb_get_vector(CPURISCVState *env, GByteArray *buf, int n) { - uint16_t vlenb = riscv_cpu_cfg(env)->vlen >> 3; + uint16_t vlenb = riscv_cpu_cfg(env)->vlenb; if (n < 32) { int i; int cnt = 0; @@ -XXX,XX +XXX,XX @@ static int riscv_gdb_get_vector(CPURISCVState *env, GByteArray *buf, int n) static int riscv_gdb_set_vector(CPURISCVState *env, uint8_t *mem_buf, int n) { - uint16_t vlenb = riscv_cpu_cfg(env)->vlen >> 3; + uint16_t vlenb = riscv_cpu_cfg(env)->vlenb; if (n < 32) { int i; for (i = 0; i < vlenb; i += 8) { @@ -XXX,XX +XXX,XX @@ static int ricsv_gen_dynamic_vector_xml(CPUState *cs, int base_reg) RISCVCPU *cpu = RISCV_CPU(cs); GString *s = g_string_new(NULL); g_autoptr(GString) ts = g_string_new(""); - int reg_width = cpu->cfg.vlen; + int reg_width = cpu->cfg.vlenb << 3; int num_regs = 0; int i; -- 2.43.0
From: Daniel Henrique Barboza <dbarboza@ventanamicro.com> Use ctx->cfg_ptr->vlenb instead of ctx->cfg_ptr->vlen / 8. Signed-off-by: Daniel Henrique Barboza <dbarboza@ventanamicro.com> Reviewed-by: Richard Henderson <richard.henderson@linaro.org> Reviewed-by: Alistair Francis <alistair.francis@wdc.com> Message-ID: <20240122161107.26737-5-dbarboza@ventanamicro.com> Signed-off-by: Alistair Francis <alistair.francis@wdc.com> --- target/riscv/insn_trans/trans_rvbf16.c.inc | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/target/riscv/insn_trans/trans_rvbf16.c.inc b/target/riscv/insn_trans/trans_rvbf16.c.inc index XXXXXXX..XXXXXXX 100644 --- a/target/riscv/insn_trans/trans_rvbf16.c.inc +++ b/target/riscv/insn_trans/trans_rvbf16.c.inc @@ -XXX,XX +XXX,XX @@ static bool trans_vfncvtbf16_f_f_w(DisasContext *ctx, arg_vfncvtbf16_f_f_w *a) data = FIELD_DP32(data, VDATA, VMA, ctx->vma); tcg_gen_gvec_3_ptr(vreg_ofs(ctx, a->rd), vreg_ofs(ctx, 0), vreg_ofs(ctx, a->rs2), tcg_env, - ctx->cfg_ptr->vlen / 8, - ctx->cfg_ptr->vlen / 8, data, + ctx->cfg_ptr->vlenb, + ctx->cfg_ptr->vlenb, data, gen_helper_vfncvtbf16_f_f_w); mark_vs_dirty(ctx); gen_set_label(over); @@ -XXX,XX +XXX,XX @@ static bool trans_vfwcvtbf16_f_f_v(DisasContext *ctx, arg_vfwcvtbf16_f_f_v *a) data = FIELD_DP32(data, VDATA, VMA, ctx->vma); tcg_gen_gvec_3_ptr(vreg_ofs(ctx, a->rd), vreg_ofs(ctx, 0), vreg_ofs(ctx, a->rs2), tcg_env, - ctx->cfg_ptr->vlen / 8, - ctx->cfg_ptr->vlen / 8, data, + ctx->cfg_ptr->vlenb, + ctx->cfg_ptr->vlenb, data, gen_helper_vfwcvtbf16_f_f_v); mark_vs_dirty(ctx); gen_set_label(over); @@ -XXX,XX +XXX,XX @@ static bool trans_vfwmaccbf16_vv(DisasContext *ctx, arg_vfwmaccbf16_vv *a) tcg_gen_gvec_4_ptr(vreg_ofs(ctx, a->rd), vreg_ofs(ctx, 0), vreg_ofs(ctx, a->rs1), vreg_ofs(ctx, a->rs2), tcg_env, - ctx->cfg_ptr->vlen / 8, - ctx->cfg_ptr->vlen / 8, data, + ctx->cfg_ptr->vlenb, + ctx->cfg_ptr->vlenb, data, gen_helper_vfwmaccbf16_vv); mark_vs_dirty(ctx); gen_set_label(over); -- 2.43.0
From: Daniel Henrique Barboza <dbarboza@ventanamicro.com> Use s->cfg_ptr->vlenb instead of "s->cfg_ptr->vlen / 8" and "s->cfg_ptr->vlen >> 3". Signed-off-by: Daniel Henrique Barboza <dbarboza@ventanamicro.com> Reviewed-by: Richard Henderson <richard.henderson@linaro.org> Reviewed-by: Alistair Francis <alistair.francis@wdc.com> Message-ID: <20240122161107.26737-6-dbarboza@ventanamicro.com> Signed-off-by: Alistair Francis <alistair.francis@wdc.com> --- target/riscv/insn_trans/trans_rvv.c.inc | 140 ++++++++++++------------ 1 file changed, 70 insertions(+), 70 deletions(-) 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 trans_vsetivli(DisasContext *s, arg_vsetivli *a) /* vector register offset from env */ static uint32_t vreg_ofs(DisasContext *s, int reg) { - return offsetof(CPURISCVState, vreg) + reg * s->cfg_ptr->vlen / 8; + return offsetof(CPURISCVState, vreg) + reg * s->cfg_ptr->vlenb; } /* check functions */ @@ -XXX,XX +XXX,XX @@ static bool ldst_us_trans(uint32_t vd, uint32_t rs1, uint32_t data, * As simd_desc supports at most 2048 bytes, and in this implementation, * the max vector group length is 4096 bytes. So split it into two parts. * - * The first part is vlen in bytes, encoded in maxsz of simd_desc. + * The first part is vlen in bytes (vlenb), encoded in maxsz of simd_desc. * The second part is lmul, encoded in data of simd_desc. */ - desc = tcg_constant_i32(simd_desc(s->cfg_ptr->vlen / 8, - s->cfg_ptr->vlen / 8, data)); + desc = tcg_constant_i32(simd_desc(s->cfg_ptr->vlenb, + s->cfg_ptr->vlenb, data)); tcg_gen_addi_ptr(dest, tcg_env, vreg_ofs(s, vd)); tcg_gen_addi_ptr(mask, tcg_env, vreg_ofs(s, 0)); @@ -XXX,XX +XXX,XX @@ static bool ldst_stride_trans(uint32_t vd, uint32_t rs1, uint32_t rs2, mask = tcg_temp_new_ptr(); base = get_gpr(s, rs1, EXT_NONE); stride = get_gpr(s, rs2, EXT_NONE); - desc = tcg_constant_i32(simd_desc(s->cfg_ptr->vlen / 8, - s->cfg_ptr->vlen / 8, data)); + desc = tcg_constant_i32(simd_desc(s->cfg_ptr->vlenb, + s->cfg_ptr->vlenb, data)); tcg_gen_addi_ptr(dest, tcg_env, vreg_ofs(s, vd)); tcg_gen_addi_ptr(mask, tcg_env, vreg_ofs(s, 0)); @@ -XXX,XX +XXX,XX @@ static bool ldst_index_trans(uint32_t vd, uint32_t rs1, uint32_t vs2, mask = tcg_temp_new_ptr(); index = tcg_temp_new_ptr(); base = get_gpr(s, rs1, EXT_NONE); - desc = tcg_constant_i32(simd_desc(s->cfg_ptr->vlen / 8, - s->cfg_ptr->vlen / 8, data)); + desc = tcg_constant_i32(simd_desc(s->cfg_ptr->vlenb, + s->cfg_ptr->vlenb, data)); tcg_gen_addi_ptr(dest, tcg_env, vreg_ofs(s, vd)); tcg_gen_addi_ptr(index, tcg_env, vreg_ofs(s, vs2)); @@ -XXX,XX +XXX,XX @@ static bool ldff_trans(uint32_t vd, uint32_t rs1, uint32_t data, dest = tcg_temp_new_ptr(); mask = tcg_temp_new_ptr(); base = get_gpr(s, rs1, EXT_NONE); - desc = tcg_constant_i32(simd_desc(s->cfg_ptr->vlen / 8, - s->cfg_ptr->vlen / 8, data)); + desc = tcg_constant_i32(simd_desc(s->cfg_ptr->vlenb, + s->cfg_ptr->vlenb, data)); tcg_gen_addi_ptr(dest, tcg_env, vreg_ofs(s, vd)); tcg_gen_addi_ptr(mask, tcg_env, vreg_ofs(s, 0)); @@ -XXX,XX +XXX,XX @@ static bool ldst_whole_trans(uint32_t vd, uint32_t rs1, uint32_t nf, uint32_t width, gen_helper_ldst_whole *fn, DisasContext *s, bool is_store) { - uint32_t evl = (s->cfg_ptr->vlen / 8) * nf / width; + uint32_t evl = s->cfg_ptr->vlenb * nf / width; TCGLabel *over = gen_new_label(); tcg_gen_brcondi_tl(TCG_COND_GEU, cpu_vstart, evl, over); @@ -XXX,XX +XXX,XX @@ static bool ldst_whole_trans(uint32_t vd, uint32_t rs1, uint32_t nf, uint32_t data = FIELD_DP32(0, VDATA, NF, nf); dest = tcg_temp_new_ptr(); - desc = tcg_constant_i32(simd_desc(s->cfg_ptr->vlen / 8, - s->cfg_ptr->vlen / 8, data)); + desc = tcg_constant_i32(simd_desc(s->cfg_ptr->vlenb, + s->cfg_ptr->vlenb, data)); base = get_gpr(s, rs1, EXT_NONE); tcg_gen_addi_ptr(dest, tcg_env, vreg_ofs(s, vd)); @@ -XXX,XX +XXX,XX @@ do_opivv_gvec(DisasContext *s, arg_rmrr *a, GVecGen3Fn *gvec_fn, data = FIELD_DP32(data, VDATA, VMA, s->vma); tcg_gen_gvec_4_ptr(vreg_ofs(s, a->rd), vreg_ofs(s, 0), vreg_ofs(s, a->rs1), vreg_ofs(s, a->rs2), - tcg_env, s->cfg_ptr->vlen / 8, - s->cfg_ptr->vlen / 8, data, fn); + tcg_env, s->cfg_ptr->vlenb, + s->cfg_ptr->vlenb, data, fn); } mark_vs_dirty(s); gen_set_label(over); @@ -XXX,XX +XXX,XX @@ static bool opivx_trans(uint32_t vd, uint32_t rs1, uint32_t vs2, uint32_t vm, data = FIELD_DP32(data, VDATA, VTA, s->vta); data = FIELD_DP32(data, VDATA, VTA_ALL_1S, s->cfg_vta_all_1s); data = FIELD_DP32(data, VDATA, VMA, s->vma); - desc = tcg_constant_i32(simd_desc(s->cfg_ptr->vlen / 8, - s->cfg_ptr->vlen / 8, data)); + desc = tcg_constant_i32(simd_desc(s->cfg_ptr->vlenb, + s->cfg_ptr->vlenb, data)); tcg_gen_addi_ptr(dest, tcg_env, vreg_ofs(s, vd)); tcg_gen_addi_ptr(src2, tcg_env, vreg_ofs(s, vs2)); @@ -XXX,XX +XXX,XX @@ static bool opivi_trans(uint32_t vd, uint32_t imm, uint32_t vs2, uint32_t vm, data = FIELD_DP32(data, VDATA, VTA, s->vta); data = FIELD_DP32(data, VDATA, VTA_ALL_1S, s->cfg_vta_all_1s); data = FIELD_DP32(data, VDATA, VMA, s->vma); - desc = tcg_constant_i32(simd_desc(s->cfg_ptr->vlen / 8, - s->cfg_ptr->vlen / 8, data)); + desc = tcg_constant_i32(simd_desc(s->cfg_ptr->vlenb, + s->cfg_ptr->vlenb, data)); tcg_gen_addi_ptr(dest, tcg_env, vreg_ofs(s, vd)); tcg_gen_addi_ptr(src2, tcg_env, vreg_ofs(s, vs2)); @@ -XXX,XX +XXX,XX @@ static bool do_opivv_widen(DisasContext *s, arg_rmrr *a, tcg_gen_gvec_4_ptr(vreg_ofs(s, a->rd), vreg_ofs(s, 0), vreg_ofs(s, a->rs1), vreg_ofs(s, a->rs2), - tcg_env, s->cfg_ptr->vlen / 8, - s->cfg_ptr->vlen / 8, + tcg_env, s->cfg_ptr->vlenb, + s->cfg_ptr->vlenb, data, fn); mark_vs_dirty(s); gen_set_label(over); @@ -XXX,XX +XXX,XX @@ static bool do_opiwv_widen(DisasContext *s, arg_rmrr *a, tcg_gen_gvec_4_ptr(vreg_ofs(s, a->rd), vreg_ofs(s, 0), vreg_ofs(s, a->rs1), vreg_ofs(s, a->rs2), - tcg_env, s->cfg_ptr->vlen / 8, - s->cfg_ptr->vlen / 8, data, fn); + tcg_env, s->cfg_ptr->vlenb, + s->cfg_ptr->vlenb, data, fn); mark_vs_dirty(s); gen_set_label(over); return true; @@ -XXX,XX +XXX,XX @@ static bool opivv_trans(uint32_t vd, uint32_t vs1, uint32_t vs2, uint32_t vm, data = FIELD_DP32(data, VDATA, VTA_ALL_1S, s->cfg_vta_all_1s); data = FIELD_DP32(data, VDATA, VMA, s->vma); tcg_gen_gvec_4_ptr(vreg_ofs(s, vd), vreg_ofs(s, 0), vreg_ofs(s, vs1), - vreg_ofs(s, vs2), tcg_env, s->cfg_ptr->vlen / 8, - s->cfg_ptr->vlen / 8, data, fn); + vreg_ofs(s, vs2), tcg_env, s->cfg_ptr->vlenb, + s->cfg_ptr->vlenb, data, fn); mark_vs_dirty(s); gen_set_label(over); return true; @@ -XXX,XX +XXX,XX @@ static bool trans_##NAME(DisasContext *s, arg_rmrr *a) \ tcg_gen_gvec_4_ptr(vreg_ofs(s, a->rd), vreg_ofs(s, 0), \ vreg_ofs(s, a->rs1), \ vreg_ofs(s, a->rs2), tcg_env, \ - s->cfg_ptr->vlen / 8, \ - s->cfg_ptr->vlen / 8, data, \ + s->cfg_ptr->vlenb, \ + s->cfg_ptr->vlenb, data, \ fns[s->sew]); \ mark_vs_dirty(s); \ gen_set_label(over); \ @@ -XXX,XX +XXX,XX @@ static bool trans_vmv_v_v(DisasContext *s, arg_vmv_v_v *a) tcg_gen_brcond_tl(TCG_COND_GEU, cpu_vstart, cpu_vl, over); tcg_gen_gvec_2_ptr(vreg_ofs(s, a->rd), vreg_ofs(s, a->rs1), - tcg_env, s->cfg_ptr->vlen / 8, - s->cfg_ptr->vlen / 8, data, + tcg_env, s->cfg_ptr->vlenb, + s->cfg_ptr->vlenb, data, fns[s->sew]); gen_set_label(over); } @@ -XXX,XX +XXX,XX @@ static bool trans_vmv_v_x(DisasContext *s, arg_vmv_v_x *a) }; tcg_gen_ext_tl_i64(s1_i64, s1); - desc = tcg_constant_i32(simd_desc(s->cfg_ptr->vlen / 8, - s->cfg_ptr->vlen / 8, data)); + desc = tcg_constant_i32(simd_desc(s->cfg_ptr->vlenb, + s->cfg_ptr->vlenb, data)); tcg_gen_addi_ptr(dest, tcg_env, vreg_ofs(s, a->rd)); fns[s->sew](dest, s1_i64, tcg_env, desc); } @@ -XXX,XX +XXX,XX @@ static bool trans_vmv_v_i(DisasContext *s, arg_vmv_v_i *a) s1 = tcg_constant_i64(simm); dest = tcg_temp_new_ptr(); - desc = tcg_constant_i32(simd_desc(s->cfg_ptr->vlen / 8, - s->cfg_ptr->vlen / 8, data)); + desc = tcg_constant_i32(simd_desc(s->cfg_ptr->vlenb, + s->cfg_ptr->vlenb, data)); tcg_gen_addi_ptr(dest, tcg_env, vreg_ofs(s, a->rd)); fns[s->sew](dest, s1, tcg_env, desc); @@ -XXX,XX +XXX,XX @@ static bool trans_##NAME(DisasContext *s, arg_rmrr *a) \ tcg_gen_gvec_4_ptr(vreg_ofs(s, a->rd), vreg_ofs(s, 0), \ vreg_ofs(s, a->rs1), \ vreg_ofs(s, a->rs2), tcg_env, \ - s->cfg_ptr->vlen / 8, \ - s->cfg_ptr->vlen / 8, data, \ + s->cfg_ptr->vlenb, \ + s->cfg_ptr->vlenb, data, \ fns[s->sew - 1]); \ mark_vs_dirty(s); \ gen_set_label(over); \ @@ -XXX,XX +XXX,XX @@ static bool opfvf_trans(uint32_t vd, uint32_t rs1, uint32_t vs2, dest = tcg_temp_new_ptr(); mask = tcg_temp_new_ptr(); src2 = tcg_temp_new_ptr(); - desc = tcg_constant_i32(simd_desc(s->cfg_ptr->vlen / 8, - s->cfg_ptr->vlen / 8, data)); + desc = tcg_constant_i32(simd_desc(s->cfg_ptr->vlenb, + s->cfg_ptr->vlenb, data)); tcg_gen_addi_ptr(dest, tcg_env, vreg_ofs(s, vd)); tcg_gen_addi_ptr(src2, tcg_env, vreg_ofs(s, vs2)); @@ -XXX,XX +XXX,XX @@ static bool trans_##NAME(DisasContext *s, arg_rmrr *a) \ tcg_gen_gvec_4_ptr(vreg_ofs(s, a->rd), vreg_ofs(s, 0), \ vreg_ofs(s, a->rs1), \ vreg_ofs(s, a->rs2), tcg_env, \ - s->cfg_ptr->vlen / 8, \ - s->cfg_ptr->vlen / 8, data, \ + s->cfg_ptr->vlenb, \ + s->cfg_ptr->vlenb, data, \ fns[s->sew - 1]); \ mark_vs_dirty(s); \ gen_set_label(over); \ @@ -XXX,XX +XXX,XX @@ static bool trans_##NAME(DisasContext *s, arg_rmrr *a) \ tcg_gen_gvec_4_ptr(vreg_ofs(s, a->rd), vreg_ofs(s, 0), \ vreg_ofs(s, a->rs1), \ vreg_ofs(s, a->rs2), tcg_env, \ - s->cfg_ptr->vlen / 8, \ - s->cfg_ptr->vlen / 8, data, \ + s->cfg_ptr->vlenb, \ + s->cfg_ptr->vlenb, data, \ fns[s->sew - 1]); \ mark_vs_dirty(s); \ gen_set_label(over); \ @@ -XXX,XX +XXX,XX @@ static bool do_opfv(DisasContext *s, arg_rmr *a, data = FIELD_DP32(data, VDATA, VMA, s->vma); tcg_gen_gvec_3_ptr(vreg_ofs(s, a->rd), vreg_ofs(s, 0), vreg_ofs(s, a->rs2), tcg_env, - s->cfg_ptr->vlen / 8, - s->cfg_ptr->vlen / 8, data, fn); + s->cfg_ptr->vlenb, + s->cfg_ptr->vlenb, data, fn); mark_vs_dirty(s); gen_set_label(over); return true; @@ -XXX,XX +XXX,XX @@ static bool trans_vfmv_v_f(DisasContext *s, arg_vfmv_v_f *a) do_nanbox(s, t1, cpu_fpr[a->rs1]); dest = tcg_temp_new_ptr(); - desc = tcg_constant_i32(simd_desc(s->cfg_ptr->vlen / 8, - s->cfg_ptr->vlen / 8, data)); + desc = tcg_constant_i32(simd_desc(s->cfg_ptr->vlenb, + s->cfg_ptr->vlenb, data)); tcg_gen_addi_ptr(dest, tcg_env, vreg_ofs(s, a->rd)); fns[s->sew - 1](dest, t1, tcg_env, desc); @@ -XXX,XX +XXX,XX @@ static bool trans_##NAME(DisasContext *s, arg_rmr *a) \ data = FIELD_DP32(data, VDATA, VMA, s->vma); \ tcg_gen_gvec_3_ptr(vreg_ofs(s, a->rd), vreg_ofs(s, 0), \ vreg_ofs(s, a->rs2), tcg_env, \ - s->cfg_ptr->vlen / 8, \ - s->cfg_ptr->vlen / 8, data, \ + s->cfg_ptr->vlenb, \ + s->cfg_ptr->vlenb, data, \ fns[s->sew - 1]); \ mark_vs_dirty(s); \ gen_set_label(over); \ @@ -XXX,XX +XXX,XX @@ static bool trans_##NAME(DisasContext *s, arg_rmr *a) \ data = FIELD_DP32(data, VDATA, VMA, s->vma); \ tcg_gen_gvec_3_ptr(vreg_ofs(s, a->rd), vreg_ofs(s, 0), \ vreg_ofs(s, a->rs2), tcg_env, \ - s->cfg_ptr->vlen / 8, \ - s->cfg_ptr->vlen / 8, data, \ + s->cfg_ptr->vlenb, \ + s->cfg_ptr->vlenb, data, \ fns[s->sew]); \ mark_vs_dirty(s); \ gen_set_label(over); \ @@ -XXX,XX +XXX,XX @@ static bool trans_##NAME(DisasContext *s, arg_rmr *a) \ data = FIELD_DP32(data, VDATA, VMA, s->vma); \ tcg_gen_gvec_3_ptr(vreg_ofs(s, a->rd), vreg_ofs(s, 0), \ vreg_ofs(s, a->rs2), tcg_env, \ - s->cfg_ptr->vlen / 8, \ - s->cfg_ptr->vlen / 8, data, \ + s->cfg_ptr->vlenb, \ + s->cfg_ptr->vlenb, data, \ fns[s->sew - 1]); \ mark_vs_dirty(s); \ gen_set_label(over); \ @@ -XXX,XX +XXX,XX @@ static bool trans_##NAME(DisasContext *s, arg_rmr *a) \ data = FIELD_DP32(data, VDATA, VMA, s->vma); \ tcg_gen_gvec_3_ptr(vreg_ofs(s, a->rd), vreg_ofs(s, 0), \ vreg_ofs(s, a->rs2), tcg_env, \ - s->cfg_ptr->vlen / 8, \ - s->cfg_ptr->vlen / 8, data, \ + s->cfg_ptr->vlenb, \ + s->cfg_ptr->vlenb, data, \ fns[s->sew]); \ mark_vs_dirty(s); \ gen_set_label(over); \ @@ -XXX,XX +XXX,XX @@ static bool trans_##NAME(DisasContext *s, arg_r *a) \ tcg_gen_gvec_4_ptr(vreg_ofs(s, a->rd), vreg_ofs(s, 0), \ vreg_ofs(s, a->rs1), \ vreg_ofs(s, a->rs2), tcg_env, \ - s->cfg_ptr->vlen / 8, \ - s->cfg_ptr->vlen / 8, data, fn); \ + s->cfg_ptr->vlenb, \ + s->cfg_ptr->vlenb, data, fn); \ mark_vs_dirty(s); \ gen_set_label(over); \ return true; \ @@ -XXX,XX +XXX,XX @@ static bool trans_vcpop_m(DisasContext *s, arg_rmr *a) mask = tcg_temp_new_ptr(); src2 = tcg_temp_new_ptr(); dst = dest_gpr(s, a->rd); - desc = tcg_constant_i32(simd_desc(s->cfg_ptr->vlen / 8, - s->cfg_ptr->vlen / 8, data)); + desc = tcg_constant_i32(simd_desc(s->cfg_ptr->vlenb, + s->cfg_ptr->vlenb, data)); tcg_gen_addi_ptr(src2, tcg_env, vreg_ofs(s, a->rs2)); tcg_gen_addi_ptr(mask, tcg_env, vreg_ofs(s, 0)); @@ -XXX,XX +XXX,XX @@ static bool trans_vfirst_m(DisasContext *s, arg_rmr *a) mask = tcg_temp_new_ptr(); src2 = tcg_temp_new_ptr(); dst = dest_gpr(s, a->rd); - desc = tcg_constant_i32(simd_desc(s->cfg_ptr->vlen / 8, - s->cfg_ptr->vlen / 8, data)); + desc = tcg_constant_i32(simd_desc(s->cfg_ptr->vlenb, + s->cfg_ptr->vlenb, data)); tcg_gen_addi_ptr(src2, tcg_env, vreg_ofs(s, a->rs2)); tcg_gen_addi_ptr(mask, tcg_env, vreg_ofs(s, 0)); @@ -XXX,XX +XXX,XX @@ static bool trans_##NAME(DisasContext *s, arg_rmr *a) \ data = FIELD_DP32(data, VDATA, VMA, s->vma); \ tcg_gen_gvec_3_ptr(vreg_ofs(s, a->rd), \ vreg_ofs(s, 0), vreg_ofs(s, a->rs2), \ - tcg_env, s->cfg_ptr->vlen / 8, \ - s->cfg_ptr->vlen / 8, \ + tcg_env, s->cfg_ptr->vlenb, \ + s->cfg_ptr->vlenb, \ data, fn); \ mark_vs_dirty(s); \ gen_set_label(over); \ @@ -XXX,XX +XXX,XX @@ static bool trans_viota_m(DisasContext *s, arg_viota_m *a) }; tcg_gen_gvec_3_ptr(vreg_ofs(s, a->rd), vreg_ofs(s, 0), vreg_ofs(s, a->rs2), tcg_env, - s->cfg_ptr->vlen / 8, - s->cfg_ptr->vlen / 8, data, fns[s->sew]); + s->cfg_ptr->vlenb, + s->cfg_ptr->vlenb, data, fns[s->sew]); mark_vs_dirty(s); gen_set_label(over); return true; @@ -XXX,XX +XXX,XX @@ static bool trans_vid_v(DisasContext *s, arg_vid_v *a) gen_helper_vid_v_w, gen_helper_vid_v_d, }; tcg_gen_gvec_2_ptr(vreg_ofs(s, a->rd), vreg_ofs(s, 0), - tcg_env, s->cfg_ptr->vlen / 8, - s->cfg_ptr->vlen / 8, + tcg_env, s->cfg_ptr->vlenb, + s->cfg_ptr->vlenb, data, fns[s->sew]); mark_vs_dirty(s); gen_set_label(over); @@ -XXX,XX +XXX,XX @@ static bool trans_vcompress_vm(DisasContext *s, arg_r *a) data = FIELD_DP32(data, VDATA, VTA, s->vta); tcg_gen_gvec_4_ptr(vreg_ofs(s, a->rd), vreg_ofs(s, 0), vreg_ofs(s, a->rs1), vreg_ofs(s, a->rs2), - tcg_env, s->cfg_ptr->vlen / 8, - s->cfg_ptr->vlen / 8, data, + tcg_env, s->cfg_ptr->vlenb, + s->cfg_ptr->vlenb, data, fns[s->sew]); mark_vs_dirty(s); gen_set_label(over); @@ -XXX,XX +XXX,XX @@ static bool trans_##NAME(DisasContext *s, arg_##NAME * a) \ vext_check_isa_ill(s) && \ QEMU_IS_ALIGNED(a->rd, LEN) && \ QEMU_IS_ALIGNED(a->rs2, LEN)) { \ - uint32_t maxsz = (s->cfg_ptr->vlen >> 3) * LEN; \ + uint32_t maxsz = s->cfg_ptr->vlenb * LEN; \ if (s->vstart_eq_zero) { \ tcg_gen_gvec_mov(s->sew, vreg_ofs(s, a->rd), \ vreg_ofs(s, a->rs2), maxsz, maxsz); \ @@ -XXX,XX +XXX,XX @@ static bool int_ext_op(DisasContext *s, arg_rmr *a, uint8_t seq) tcg_gen_gvec_3_ptr(vreg_ofs(s, a->rd), vreg_ofs(s, 0), vreg_ofs(s, a->rs2), tcg_env, - s->cfg_ptr->vlen / 8, - s->cfg_ptr->vlen / 8, data, fn); + s->cfg_ptr->vlenb, + s->cfg_ptr->vlenb, data, fn); mark_vs_dirty(s); gen_set_label(over); -- 2.43.0
From: Daniel Henrique Barboza <dbarboza@ventanamicro.com> Use s->cfg_ptr->vlenb instead of s->cfg_ptr->vlen / 8. Signed-off-by: Daniel Henrique Barboza <dbarboza@ventanamicro.com> Reviewed-by: Richard Henderson <richard.henderson@linaro.org> Reviewed-by: Alistair Francis <alistair.francis@wdc.com> Message-ID: <20240122161107.26737-7-dbarboza@ventanamicro.com> Signed-off-by: Alistair Francis <alistair.francis@wdc.com> --- target/riscv/insn_trans/trans_rvvk.c.inc | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/target/riscv/insn_trans/trans_rvvk.c.inc b/target/riscv/insn_trans/trans_rvvk.c.inc index XXXXXXX..XXXXXXX 100644 --- a/target/riscv/insn_trans/trans_rvvk.c.inc +++ b/target/riscv/insn_trans/trans_rvvk.c.inc @@ -XXX,XX +XXX,XX @@ GEN_OPIVX_GVEC_TRANS_CHECK(vandn_vx, andcs, zvkb_vx_check) data = FIELD_DP32(data, VDATA, VMA, s->vma); \ tcg_gen_gvec_3_ptr(vreg_ofs(s, a->rd), vreg_ofs(s, 0), \ vreg_ofs(s, a->rs2), tcg_env, \ - s->cfg_ptr->vlen / 8, s->cfg_ptr->vlen / 8, \ + s->cfg_ptr->vlenb, s->cfg_ptr->vlenb, \ data, fns[s->sew]); \ mark_vs_dirty(s); \ gen_set_label(over); \ @@ -XXX,XX +XXX,XX @@ GEN_OPIVI_WIDEN_TRANS(vwsll_vi, IMM_ZX, vwsll_vx, vwsll_vx_check) rd_v = tcg_temp_new_ptr(); \ rs2_v = tcg_temp_new_ptr(); \ desc = tcg_constant_i32( \ - simd_desc(s->cfg_ptr->vlen / 8, s->cfg_ptr->vlen / 8, data)); \ + simd_desc(s->cfg_ptr->vlenb, s->cfg_ptr->vlenb, data)); \ tcg_gen_addi_ptr(rd_v, tcg_env, vreg_ofs(s, a->rd)); \ tcg_gen_addi_ptr(rs2_v, tcg_env, vreg_ofs(s, a->rs2)); \ gen_helper_##NAME(rd_v, rs2_v, tcg_env, desc); \ @@ -XXX,XX +XXX,XX @@ GEN_V_UNMASKED_TRANS(vaesem_vs, vaes_check_vs, ZVKNED_EGS) rs2_v = tcg_temp_new_ptr(); \ uimm_v = tcg_constant_i32(a->rs1); \ desc = tcg_constant_i32( \ - simd_desc(s->cfg_ptr->vlen / 8, s->cfg_ptr->vlen / 8, data)); \ + simd_desc(s->cfg_ptr->vlenb, s->cfg_ptr->vlenb, data)); \ tcg_gen_addi_ptr(rd_v, tcg_env, vreg_ofs(s, a->rd)); \ tcg_gen_addi_ptr(rs2_v, tcg_env, vreg_ofs(s, a->rs2)); \ gen_helper_##NAME(rd_v, rs2_v, uimm_v, tcg_env, desc); \ @@ -XXX,XX +XXX,XX @@ GEN_VI_UNMASKED_TRANS(vaeskf2_vi, vaeskf2_check, ZVKNED_EGS) \ tcg_gen_gvec_3_ptr(vreg_ofs(s, a->rd), vreg_ofs(s, a->rs1), \ vreg_ofs(s, a->rs2), tcg_env, \ - s->cfg_ptr->vlen / 8, s->cfg_ptr->vlen / 8, \ + s->cfg_ptr->vlenb, s->cfg_ptr->vlenb, \ data, gen_helper_##NAME); \ \ mark_vs_dirty(s); \ @@ -XXX,XX +XXX,XX @@ static bool trans_vsha2cl_vv(DisasContext *s, arg_rmrr *a) data = FIELD_DP32(data, VDATA, VMA, s->vma); tcg_gen_gvec_3_ptr(vreg_ofs(s, a->rd), vreg_ofs(s, a->rs1), - vreg_ofs(s, a->rs2), tcg_env, s->cfg_ptr->vlen / 8, - s->cfg_ptr->vlen / 8, data, + vreg_ofs(s, a->rs2), tcg_env, s->cfg_ptr->vlenb, + s->cfg_ptr->vlenb, data, s->sew == MO_32 ? gen_helper_vsha2cl32_vv : gen_helper_vsha2cl64_vv); @@ -XXX,XX +XXX,XX @@ static bool trans_vsha2ch_vv(DisasContext *s, arg_rmrr *a) data = FIELD_DP32(data, VDATA, VMA, s->vma); tcg_gen_gvec_3_ptr(vreg_ofs(s, a->rd), vreg_ofs(s, a->rs1), - vreg_ofs(s, a->rs2), tcg_env, s->cfg_ptr->vlen / 8, - s->cfg_ptr->vlen / 8, data, + vreg_ofs(s, a->rs2), tcg_env, s->cfg_ptr->vlenb, + s->cfg_ptr->vlenb, data, s->sew == MO_32 ? gen_helper_vsha2ch32_vv : gen_helper_vsha2ch64_vv); -- 2.43.0
From: Daniel Henrique Barboza <dbarboza@ventanamicro.com> Use 'cpu->cfg.vlenb' instead of 'cpu->cfg.vlen >> 3'. Signed-off-by: Daniel Henrique Barboza <dbarboza@ventanamicro.com> Reviewed-by: Richard Henderson <richard.henderson@linaro.org> Reviewed-by: Alistair Francis <alistair.francis@wdc.com> Message-ID: <20240122161107.26737-8-dbarboza@ventanamicro.com> Signed-off-by: Alistair Francis <alistair.francis@wdc.com> --- target/riscv/vector_helper.c | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) 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 @@ vext_ldst_whole(void *vd, target_ulong base, CPURISCVState *env, uint32_t desc, { uint32_t i, k, off, pos; uint32_t nf = vext_nf(desc); - uint32_t vlenb = riscv_cpu_cfg(env)->vlen >> 3; + uint32_t vlenb = riscv_cpu_cfg(env)->vlenb; uint32_t max_elems = vlenb >> log2_esz; k = env->vstart / max_elems; @@ -XXX,XX +XXX,XX @@ void HELPER(NAME)(void *vd, void *v0, void *vs1, void *vs2, \ { \ uint32_t vl = env->vl; \ uint32_t vm = vext_vm(desc); \ - uint32_t total_elems = riscv_cpu_cfg(env)->vlen; \ + uint32_t total_elems = riscv_cpu_cfg(env)->vlenb << 3; \ uint32_t vta_all_1s = vext_vta_all_1s(desc); \ uint32_t i; \ \ @@ -XXX,XX +XXX,XX @@ void HELPER(NAME)(void *vd, void *v0, target_ulong s1, \ { \ uint32_t vl = env->vl; \ uint32_t vm = vext_vm(desc); \ - uint32_t total_elems = riscv_cpu_cfg(env)->vlen; \ + uint32_t total_elems = riscv_cpu_cfg(env)->vlenb << 3; \ uint32_t vta_all_1s = vext_vta_all_1s(desc); \ uint32_t i; \ \ @@ -XXX,XX +XXX,XX @@ void HELPER(NAME)(void *vd, void *v0, void *vs1, void *vs2, \ { \ uint32_t vm = vext_vm(desc); \ uint32_t vl = env->vl; \ - uint32_t total_elems = riscv_cpu_cfg(env)->vlen; \ + uint32_t total_elems = riscv_cpu_cfg(env)->vlenb << 3; \ uint32_t vta_all_1s = vext_vta_all_1s(desc); \ uint32_t vma = vext_vma(desc); \ uint32_t i; \ @@ -XXX,XX +XXX,XX @@ void HELPER(NAME)(void *vd, void *v0, target_ulong s1, void *vs2, \ { \ uint32_t vm = vext_vm(desc); \ uint32_t vl = env->vl; \ - uint32_t total_elems = riscv_cpu_cfg(env)->vlen; \ + uint32_t total_elems = riscv_cpu_cfg(env)->vlenb << 3; \ uint32_t vta_all_1s = vext_vta_all_1s(desc); \ uint32_t vma = vext_vma(desc); \ uint32_t i; \ @@ -XXX,XX +XXX,XX @@ void HELPER(NAME)(void *vd, void *v0, void *vs1, void *vs2, \ { \ uint32_t vm = vext_vm(desc); \ uint32_t vl = env->vl; \ - uint32_t total_elems = riscv_cpu_cfg(env)->vlen; \ + uint32_t total_elems = riscv_cpu_cfg(env)->vlenb << 3; \ uint32_t vta_all_1s = vext_vta_all_1s(desc); \ uint32_t vma = vext_vma(desc); \ uint32_t i; \ @@ -XXX,XX +XXX,XX @@ void HELPER(NAME)(void *vd, void *v0, uint64_t s1, void *vs2, \ { \ uint32_t vm = vext_vm(desc); \ uint32_t vl = env->vl; \ - uint32_t total_elems = riscv_cpu_cfg(env)->vlen; \ + uint32_t total_elems = riscv_cpu_cfg(env)->vlenb << 3; \ uint32_t vta_all_1s = vext_vta_all_1s(desc); \ uint32_t vma = vext_vma(desc); \ uint32_t i; \ @@ -XXX,XX +XXX,XX @@ void HELPER(NAME)(void *vd, void *v0, void *vs1, \ uint32_t desc) \ { \ uint32_t vl = env->vl; \ - uint32_t total_elems = riscv_cpu_cfg(env)->vlen; \ + uint32_t total_elems = riscv_cpu_cfg(env)->vlenb << 3;\ uint32_t vta_all_1s = vext_vta_all_1s(desc); \ uint32_t i; \ int a, b; \ @@ -XXX,XX +XXX,XX @@ static void vmsetm(void *vd, void *v0, void *vs2, CPURISCVState *env, { uint32_t vm = vext_vm(desc); uint32_t vl = env->vl; - uint32_t total_elems = riscv_cpu_cfg(env)->vlen; + uint32_t total_elems = riscv_cpu_cfg(env)->vlenb << 3; uint32_t vta_all_1s = vext_vta_all_1s(desc); uint32_t vma = vext_vma(desc); int i; -- 2.43.0
From: Daniel Henrique Barboza <dbarboza@ventanamicro.com> Use the new 'vlenb' CPU config to validate fractional LMUL. The original comparison is done with 'vlen' and 'sew', both in bits. Adjust the shift to use vlenb. Signed-off-by: Daniel Henrique Barboza <dbarboza@ventanamicro.com> Reviewed-by: Richard Henderson <richard.henderson@linaro.org> Reviewed-by: Alistair Francis <alistair.francis@wdc.com> Message-ID: <20240122161107.26737-9-dbarboza@ventanamicro.com> Signed-off-by: Alistair Francis <alistair.francis@wdc.com> --- target/riscv/vector_helper.c | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) 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 @@ target_ulong HELPER(vsetvl)(CPURISCVState *env, target_ulong s1, xlen - 1 - R_VTYPE_RESERVED_SHIFT); if (lmul & 4) { - /* Fractional LMUL - check LMUL * VLEN >= SEW */ + /* + * Fractional LMUL, check: + * + * VLEN * LMUL >= SEW + * VLEN >> (8 - lmul) >= sew + * (vlenb << 3) >> (8 - lmul) >= sew + * vlenb >> (8 - 3 - lmul) >= sew + */ if (lmul == 4 || - cpu->cfg.vlen >> (8 - lmul) < sew) { + cpu->cfg.vlenb >> (8 - 3 - lmul) < sew) { vill = true; } } -- 2.43.0
From: Daniel Henrique Barboza <dbarboza@ventanamicro.com> Calculate the maximum vector size possible, 'max_sz', which is the size in bytes 'vlenb' multiplied by the max value of LMUL (LMUL = 8, when s->lmul = 3). 'max_sz' is then shifted right by 'scale', expressed as '3 - s->lmul', which is clearer than doing 'scale = lmul - 3' and then using '-scale' in the shift right. Signed-off-by: Daniel Henrique Barboza <dbarboza@ventanamicro.com> Reviewed-by: Richard Henderson <richard.henderson@linaro.org> Reviewed-by: Alistair Francis <alistair.francis@wdc.com> Message-ID: <20240122161107.26737-10-dbarboza@ventanamicro.com> Signed-off-by: Alistair Francis <alistair.francis@wdc.com> --- target/riscv/insn_trans/trans_rvv.c.inc | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) 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 @@ GEN_LDST_WHOLE_TRANS(vs8r_v, 8, 1, true) /* * MAXSZ returns the maximum vector size can be operated in bytes, * which is used in GVEC IR when vl_eq_vlmax flag is set to true - * to accerlate vector operation. + * to accelerate vector operation. */ static inline uint32_t MAXSZ(DisasContext *s) { - int scale = s->lmul - 3; - return s->cfg_ptr->vlen >> -scale; + int max_sz = s->cfg_ptr->vlenb * 8; + return max_sz >> (3 - s->lmul); } static bool opivv_check(DisasContext *s, arg_rmrr *a) -- 2.43.0
From: Daniel Henrique Barboza <dbarboza@ventanamicro.com> Rename the existing 'sew' variable to 'vsew' for extra clarity. Signed-off-by: Daniel Henrique Barboza <dbarboza@ventanamicro.com> Reviewed-by: Alistair Francis <alistair.francis@wdc.com> Message-ID: <20240122161107.26737-11-dbarboza@ventanamicro.com> Signed-off-by: Alistair Francis <alistair.francis@wdc.com> --- target/riscv/cpu.h | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 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 @@ static inline RISCVMXL riscv_cpu_sxl(CPURISCVState *env) */ static inline uint32_t vext_get_vlmax(RISCVCPU *cpu, target_ulong vtype) { - uint8_t sew = FIELD_EX64(vtype, VTYPE, VSEW); + uint8_t vsew = FIELD_EX64(vtype, VTYPE, VSEW); int8_t lmul = sextract32(FIELD_EX64(vtype, VTYPE, VLMUL), 0, 3); - return cpu->cfg.vlen >> (sew + 3 - lmul); + uint32_t vlen = cpu->cfg.vlenb << 3; + + /* + * We need to use 'vlen' instead of 'vlenb' to + * preserve the '+ 3' in the formula. Otherwise + * we risk a negative shift if vsew < lmul. + */ + return vlen >> (vsew + 3 - lmul); } void cpu_get_tb_cpu_state(CPURISCVState *env, vaddr *pc, -- 2.43.0
From: Daniel Henrique Barboza <dbarboza@ventanamicro.com> We'll re-use the logic froim vext_get_vlmax() in 2 other occurrences in the next patch, but first we need to make it independent of both 'cpu' and 'vtype'. To do that, add 'vlenb', 'vsew' and 'lmul' as parameters instead. Adapt the two existing callers. In cpu_get_tb_cpu_state(), rename 'sew' to 'vsew' to be less ambiguous about what we're encoding into *pflags. In HELPER(vsetvl) the following changes were made: - add a 'vsew' var to store vsew. Use it in the shift to get 'sew'; - the existing 'lmul' var was renamed to 'vlmul'; - add a new 'lmul' var to store 'lmul' encoded like DisasContext:lmul. Signed-off-by: Daniel Henrique Barboza <dbarboza@ventanamicro.com> Reviewed-by: Alistair Francis <alistair.francis@wdc.com> Message-ID: <20240122161107.26737-12-dbarboza@ventanamicro.com> Signed-off-by: Alistair Francis <alistair.francis@wdc.com> --- target/riscv/cpu.h | 7 +++---- target/riscv/cpu_helper.c | 11 +++++++---- target/riscv/vector_helper.c | 16 ++++++++++------ 3 files changed, 20 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 @@ static inline RISCVMXL riscv_cpu_sxl(CPURISCVState *env) * = 256 >> 7 * = 2 */ -static inline uint32_t vext_get_vlmax(RISCVCPU *cpu, target_ulong vtype) +static inline uint32_t vext_get_vlmax(uint32_t vlenb, uint32_t vsew, + int8_t lmul) { - uint8_t vsew = FIELD_EX64(vtype, VTYPE, VSEW); - int8_t lmul = sextract32(FIELD_EX64(vtype, VTYPE, VLMUL), 0, 3); - uint32_t vlen = cpu->cfg.vlenb << 3; + uint32_t vlen = vlenb << 3; /* * We need to use 'vlen' instead of 'vlenb' to 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 cpu_get_tb_cpu_state(CPURISCVState *env, vaddr *pc, * which is not supported by GVEC. So we set vl_eq_vlmax flag to true * only when maxsz >= 8 bytes. */ - uint32_t vlmax = vext_get_vlmax(cpu, env->vtype); - uint32_t sew = FIELD_EX64(env->vtype, VTYPE, VSEW); - uint32_t maxsz = vlmax << sew; + + /* lmul encoded as in DisasContext::lmul */ + int8_t lmul = sextract32(FIELD_EX64(env->vtype, VTYPE, VLMUL), 0, 3); + uint32_t vsew = FIELD_EX64(env->vtype, VTYPE, VSEW); + uint32_t vlmax = vext_get_vlmax(cpu->cfg.vlenb, vsew, lmul); + uint32_t maxsz = vlmax << vsew; bool vl_eq_vlmax = (env->vstart == 0) && (vlmax == env->vl) && (maxsz >= 8); flags = FIELD_DP32(flags, TB_FLAGS, VILL, env->vill); - flags = FIELD_DP32(flags, TB_FLAGS, SEW, sew); + flags = FIELD_DP32(flags, TB_FLAGS, SEW, vsew); flags = FIELD_DP32(flags, TB_FLAGS, LMUL, FIELD_EX64(env->vtype, VTYPE, VLMUL)); flags = FIELD_DP32(flags, TB_FLAGS, VL_EQ_VLMAX, vl_eq_vlmax); 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 @@ target_ulong HELPER(vsetvl)(CPURISCVState *env, target_ulong s1, { int vlmax, vl; RISCVCPU *cpu = env_archcpu(env); - uint64_t lmul = FIELD_EX64(s2, VTYPE, VLMUL); - uint16_t sew = 8 << FIELD_EX64(s2, VTYPE, VSEW); + uint64_t vlmul = FIELD_EX64(s2, VTYPE, VLMUL); + uint8_t vsew = FIELD_EX64(s2, VTYPE, VSEW); + uint16_t sew = 8 << vsew; uint8_t ediv = FIELD_EX64(s2, VTYPE, VEDIV); int xlen = riscv_cpu_xlen(env); bool vill = (s2 >> (xlen - 1)) & 0x1; target_ulong reserved = s2 & MAKE_64BIT_MASK(R_VTYPE_RESERVED_SHIFT, xlen - 1 - R_VTYPE_RESERVED_SHIFT); + int8_t lmul; - if (lmul & 4) { + if (vlmul & 4) { /* * Fractional LMUL, check: * @@ -XXX,XX +XXX,XX @@ target_ulong HELPER(vsetvl)(CPURISCVState *env, target_ulong s1, * (vlenb << 3) >> (8 - lmul) >= sew * vlenb >> (8 - 3 - lmul) >= sew */ - if (lmul == 4 || - cpu->cfg.vlenb >> (8 - 3 - lmul) < sew) { + if (vlmul == 4 || + cpu->cfg.vlenb >> (8 - 3 - vlmul) < sew) { vill = true; } } @@ -XXX,XX +XXX,XX @@ target_ulong HELPER(vsetvl)(CPURISCVState *env, target_ulong s1, return 0; } - vlmax = vext_get_vlmax(cpu, s2); + /* lmul encoded as in DisasContext::lmul */ + lmul = sextract32(FIELD_EX64(s2, VTYPE, VLMUL), 0, 3); + vlmax = vext_get_vlmax(cpu->cfg.vlenb, vsew, lmul); if (s1 <= vlmax) { vl = s1; } else { -- 2.43.0
From: Daniel Henrique Barboza <dbarboza@ventanamicro.com> Use the helper instead of calculating vlmax by hand. Signed-off-by: Daniel Henrique Barboza <dbarboza@ventanamicro.com> Reviewed-by: Alistair Francis <alistair.francis@wdc.com> Message-ID: <20240122161107.26737-13-dbarboza@ventanamicro.com> Signed-off-by: Alistair Francis <alistair.francis@wdc.com> --- target/riscv/insn_trans/trans_rvv.c.inc | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) 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 trans_vrgather_vx(DisasContext *s, arg_rmrr *a) } if (a->vm && s->vl_eq_vlmax && !(s->vta && s->lmul < 0)) { - int scale = s->lmul - (s->sew + 3); - int vlmax = s->cfg_ptr->vlen >> -scale; + int vlmax = vext_get_vlmax(s->cfg_ptr->vlenb, s->sew, s->lmul); TCGv_i64 dest = tcg_temp_new_i64(); if (a->rs1 == 0) { @@ -XXX,XX +XXX,XX @@ static bool trans_vrgather_vi(DisasContext *s, arg_rmrr *a) } if (a->vm && s->vl_eq_vlmax && !(s->vta && s->lmul < 0)) { - int scale = s->lmul - (s->sew + 3); - int vlmax = s->cfg_ptr->vlen >> -scale; + int vlmax = vext_get_vlmax(s->cfg_ptr->vlenb, s->sew, s->lmul); if (a->rs1 >= vlmax) { tcg_gen_gvec_dup_imm(MO_64, vreg_ofs(s, a->rd), MAXSZ(s), MAXSZ(s), 0); -- 2.43.0
From: Daniel Henrique Barboza <dbarboza@ventanamicro.com> There is no need to keep both 'vlen' and 'vlenb'. All existing code that requires 'vlen' is retrieving it via 'vlenb << 3'. Signed-off-by: Daniel Henrique Barboza <dbarboza@ventanamicro.com> Reviewed-by: Richard Henderson <richard.henderson@linaro.org> Reviewed-by: Alistair Francis <alistair.francis@wdc.com> Message-ID: <20240122161107.26737-14-dbarboza@ventanamicro.com> Signed-off-by: Alistair Francis <alistair.francis@wdc.com> --- target/riscv/cpu_cfg.h | 1 - target/riscv/cpu.c | 8 +++----- target/riscv/tcg/tcg-cpu.c | 4 +++- 3 files changed, 6 insertions(+), 7 deletions(-) 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 @@ struct RISCVCPUConfig { bool ext_XVentanaCondOps; uint32_t pmu_mask; - uint16_t vlen; uint16_t vlenb; uint16_t elen; uint16_t cbom_blocksize; 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) /* Default values for non-bool cpu properties */ cpu->cfg.pmu_mask = MAKE_64BIT_MASK(3, 16); - cpu->cfg.vlen = 128; cpu->cfg.vlenb = 128 >> 3; cpu->cfg.elen = 64; cpu->cfg.cbom_blocksize = 64; @@ -XXX,XX +XXX,XX @@ static void prop_vlen_set(Object *obj, Visitor *v, const char *name, return; } - if (value != cpu->cfg.vlen && riscv_cpu_is_vendor(obj)) { + if (value != cpu->cfg.vlenb && riscv_cpu_is_vendor(obj)) { cpu_set_prop_err(cpu, name, errp); error_append_hint(errp, "Current '%s' val: %u\n", - name, cpu->cfg.vlen); + name, cpu->cfg.vlenb << 3); return; } cpu_option_add_user_setting(name, value); - cpu->cfg.vlen = value; cpu->cfg.vlenb = value >> 3; } static void prop_vlen_get(Object *obj, Visitor *v, const char *name, void *opaque, Error **errp) { - uint16_t value = RISCV_CPU(obj)->cfg.vlen; + uint16_t value = RISCV_CPU(obj)->cfg.vlenb << 3; visit_type_uint16(v, name, &value, 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_validate_misa_mxl(RISCVCPU *cpu, Error **errp) static void riscv_cpu_validate_v(CPURISCVState *env, RISCVCPUConfig *cfg, Error **errp) { - if (cfg->vlen > RV_VLEN_MAX || cfg->vlen < 128) { + uint32_t vlen = cfg->vlenb << 3; + + if (vlen > RV_VLEN_MAX || vlen < 128) { error_setg(errp, "Vector extension implementation only supports VLEN " "in the range [128, %d]", RV_VLEN_MAX); -- 2.43.0
From: Daniel Henrique Barboza <dbarboza@ventanamicro.com> The field isn't big enough to hold an uint64_t kvm register and Vector registers will end up overflowing it. Signed-off-by: Daniel Henrique Barboza <dbarboza@ventanamicro.com> Reviewed-by: Alistair Francis <alistair.francis@wdc.com> Message-ID: <20240123161714.160149-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 @@ typedef struct KVMCPUConfig { const char *name; const char *description; target_ulong offset; - int kvm_reg_id; + uint64_t kvm_reg_id; bool user_set; bool supported; } KVMCPUConfig; -- 2.43.0
From: Daniel Henrique Barboza <dbarboza@ventanamicro.com> KVM will check for the correct 'reg_size' when accessing the vector registers, erroring with EINVAL if we encode the wrong size in reg ID. Vector registers varies in size with the vector length in bytes, or 'vlenb'. This means that we need the current 'vlenb' being used by the host, otherwise we won't be able to fetch all vector regs. We'll deal with 'vlenb' first. Its support was added in Linux 6.8 as a get-reg-list register. We'll read 'vlenb' via get-reg-list and mark the register as 'supported'. All 'vlenb' ops via kvm_arch_get_registers() and kvm_arch_put_registers() will only be done if the reg is supported, i.e. we fetched it in get-reg-list during init. If the user sets a new vlenb value using the 'vlen' property, throw an error if the user value differs from the host. Signed-off-by: Daniel Henrique Barboza <dbarboza@ventanamicro.com> Acked-by: Alistair Francis <alistair.francis@wdc.com> Message-ID: <20240123161714.160149-3-dbarboza@ventanamicro.com> Signed-off-by: Alistair Francis <alistair.francis@wdc.com> --- target/riscv/kvm/kvm-cpu.c | 85 ++++++++++++++++++++++++++++++++++++-- 1 file changed, 82 insertions(+), 3 deletions(-) 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 KVMCPUConfig kvm_cboz_blocksize = { .kvm_reg_id = KVM_REG_RISCV_CONFIG_REG(zicboz_block_size) }; +static KVMCPUConfig kvm_v_vlenb = { + .name = "vlenb", + .offset = CPU_CFG_OFFSET(vlenb), + .kvm_reg_id = KVM_REG_RISCV | KVM_REG_SIZE_U64 | KVM_REG_RISCV_VECTOR | + KVM_REG_RISCV_VECTOR_CSR_REG(vlenb) +}; + static void kvm_riscv_update_cpu_cfg_isa_ext(RISCVCPU *cpu, CPUState *cs) { CPURISCVState *env = &cpu->env; @@ -XXX,XX +XXX,XX @@ static void kvm_riscv_put_regs_timer(CPUState *cs) static int kvm_riscv_get_regs_vector(CPUState *cs) { - CPURISCVState *env = &RISCV_CPU(cs)->env; + RISCVCPU *cpu = RISCV_CPU(cs); + CPURISCVState *env = &cpu->env; target_ulong reg; int ret = 0; @@ -XXX,XX +XXX,XX @@ static int kvm_riscv_get_regs_vector(CPUState *cs) } env->vtype = reg; + if (kvm_v_vlenb.supported) { + ret = kvm_get_one_reg(cs, RISCV_VECTOR_CSR_REG(env, vlenb), ®); + if (ret) { + return ret; + } + cpu->cfg.vlenb = reg; + } + return 0; } static int kvm_riscv_put_regs_vector(CPUState *cs) { - CPURISCVState *env = &RISCV_CPU(cs)->env; + RISCVCPU *cpu = RISCV_CPU(cs); + CPURISCVState *env = &cpu->env; target_ulong reg; int ret = 0; @@ -XXX,XX +XXX,XX @@ static int kvm_riscv_put_regs_vector(CPUState *cs) reg = env->vtype; ret = kvm_set_one_reg(cs, RISCV_VECTOR_CSR_REG(env, vtype), ®); + if (ret) { + return ret; + } + + if (kvm_v_vlenb.supported) { + reg = cpu->cfg.vlenb; + ret = kvm_set_one_reg(cs, RISCV_VECTOR_CSR_REG(env, vlenb), ®); + } return ret; } @@ -XXX,XX +XXX,XX @@ static int uint64_cmp(const void *a, const void *b) return 0; } +static void kvm_riscv_read_vlenb(RISCVCPU *cpu, KVMScratchCPU *kvmcpu, + struct kvm_reg_list *reglist) +{ + struct kvm_one_reg reg; + struct kvm_reg_list *reg_search; + uint64_t val; + int ret; + + reg_search = bsearch(&kvm_v_vlenb.kvm_reg_id, reglist->reg, reglist->n, + sizeof(uint64_t), uint64_cmp); + + if (reg_search) { + reg.id = kvm_v_vlenb.kvm_reg_id; + reg.addr = (uint64_t)&val; + + ret = ioctl(kvmcpu->cpufd, KVM_GET_ONE_REG, ®); + if (ret != 0) { + error_report("Unable to read vlenb register, error code: %s", + strerrorname_np(errno)); + exit(EXIT_FAILURE); + } + + kvm_v_vlenb.supported = true; + cpu->cfg.vlenb = val; + } +} + static void kvm_riscv_init_multiext_cfg(RISCVCPU *cpu, KVMScratchCPU *kvmcpu) { KVMCPUConfig *multi_ext_cfg; @@ -XXX,XX +XXX,XX @@ static void kvm_riscv_init_multiext_cfg(RISCVCPU *cpu, KVMScratchCPU *kvmcpu) if (cpu->cfg.ext_zicboz) { kvm_riscv_read_cbomz_blksize(cpu, kvmcpu, &kvm_cboz_blocksize); } + + if (riscv_has_ext(&cpu->env, RVV)) { + kvm_riscv_read_vlenb(cpu, kvmcpu, reglist); + } } static void riscv_init_kvm_registers(Object *cpu_obj) @@ -XXX,XX +XXX,XX @@ void riscv_kvm_cpu_finalize_features(RISCVCPU *cpu, Error **errp) int ret; /* short-circuit without spinning the scratch CPU */ - if (!cpu->cfg.ext_zicbom && !cpu->cfg.ext_zicboz) { + if (!cpu->cfg.ext_zicbom && !cpu->cfg.ext_zicboz && + !riscv_has_ext(env, RVV)) { return; } @@ -XXX,XX +XXX,XX @@ void riscv_kvm_cpu_finalize_features(RISCVCPU *cpu, Error **errp) } } + /* Users are setting vlen, not vlenb */ + if (riscv_has_ext(env, RVV) && riscv_cpu_option_set("vlen")) { + if (!kvm_v_vlenb.supported) { + error_setg(errp, "Unable to set 'vlenb': register not supported"); + return; + } + + reg.id = kvm_v_vlenb.kvm_reg_id; + reg.addr = (uint64_t)&val; + ret = ioctl(kvmcpu.cpufd, KVM_GET_ONE_REG, ®); + if (ret != 0) { + error_setg(errp, "Unable to read vlenb register, error %d", errno); + return; + } + + if (cpu->cfg.vlenb != val) { + error_setg(errp, "Unable to set 'vlen' to a different " + "value than the host (%lu)", val * 8); + return; + } + } + kvm_riscv_destroy_scratch_vcpu(&kvmcpu); } -- 2.43.0
From: Daniel Henrique Barboza <dbarboza@ventanamicro.com> vregs[] have variable size that depends on the current vlenb set by the host, meaning we can't use our regular kvm_riscv_reg_id() to retrieve it. Create a generic kvm_encode_reg_size_id() helper to encode any given size in bytes into a given kvm reg id. kvm_riscv_vector_reg_id() will use it to encode vlenb into a given vreg ID. kvm_riscv_(get|set)_vector() can then get/set all 32 vregs. Signed-off-by: Daniel Henrique Barboza <dbarboza@ventanamicro.com> Acked-by: Alistair Francis <alistair.francis@wdc.com> Message-ID: <20240123161714.160149-4-dbarboza@ventanamicro.com> Signed-off-by: Alistair Francis <alistair.francis@wdc.com> --- target/riscv/kvm/kvm-cpu.c | 57 ++++++++++++++++++++++++++++++++++++-- 1 file changed, 55 insertions(+), 2 deletions(-) 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 uint64_t kvm_riscv_reg_id_u64(uint64_t type, uint64_t idx) return KVM_REG_RISCV | KVM_REG_SIZE_U64 | type | idx; } +static uint64_t kvm_encode_reg_size_id(uint64_t id, size_t size_b) +{ + uint64_t size_ctz = __builtin_ctz(size_b); + + return id | (size_ctz << KVM_REG_SIZE_SHIFT); +} + +static uint64_t kvm_riscv_vector_reg_id(RISCVCPU *cpu, + uint64_t idx) +{ + uint64_t id; + size_t size_b; + + g_assert(idx < 32); + + id = KVM_REG_RISCV | KVM_REG_RISCV_VECTOR | KVM_REG_RISCV_VECTOR_REG(idx); + size_b = cpu->cfg.vlenb; + + return kvm_encode_reg_size_id(id, size_b); +} + #define RISCV_CORE_REG(env, name) \ kvm_riscv_reg_id_ulong(env, KVM_REG_RISCV_CORE, \ KVM_REG_RISCV_CORE_REG(name)) @@ -XXX,XX +XXX,XX @@ static int kvm_riscv_get_regs_vector(CPUState *cs) RISCVCPU *cpu = RISCV_CPU(cs); CPURISCVState *env = &cpu->env; target_ulong reg; - int ret = 0; + uint64_t vreg_id; + int vreg_idx, ret = 0; if (!riscv_has_ext(env, RVV)) { return 0; @@ -XXX,XX +XXX,XX @@ static int kvm_riscv_get_regs_vector(CPUState *cs) return ret; } cpu->cfg.vlenb = reg; + + for (int i = 0; i < 32; i++) { + /* + * vreg[] is statically allocated using RV_VLEN_MAX. + * Use it instead of vlenb to calculate vreg_idx for + * simplicity. + */ + vreg_idx = i * RV_VLEN_MAX / 64; + vreg_id = kvm_riscv_vector_reg_id(cpu, i); + + ret = kvm_get_one_reg(cs, vreg_id, &env->vreg[vreg_idx]); + if (ret) { + return ret; + } + } } return 0; @@ -XXX,XX +XXX,XX @@ static int kvm_riscv_put_regs_vector(CPUState *cs) RISCVCPU *cpu = RISCV_CPU(cs); CPURISCVState *env = &cpu->env; target_ulong reg; - int ret = 0; + uint64_t vreg_id; + int vreg_idx, ret = 0; if (!riscv_has_ext(env, RVV)) { return 0; @@ -XXX,XX +XXX,XX @@ static int kvm_riscv_put_regs_vector(CPUState *cs) if (kvm_v_vlenb.supported) { reg = cpu->cfg.vlenb; ret = kvm_set_one_reg(cs, RISCV_VECTOR_CSR_REG(env, vlenb), ®); + + for (int i = 0; i < 32; i++) { + /* + * vreg[] is statically allocated using RV_VLEN_MAX. + * Use it instead of vlenb to calculate vreg_idx for + * simplicity. + */ + vreg_idx = i * RV_VLEN_MAX / 64; + vreg_id = kvm_riscv_vector_reg_id(cpu, i); + + ret = kvm_set_one_reg(cs, vreg_id, &env->vreg[vreg_idx]); + if (ret) { + return ret; + } + } } return ret; -- 2.43.0
From: Akihiko Odaki <akihiko.odaki@daynix.com> It is initialized with a simple assignment and there is little room for error. In fact, the validation is even more complex. Signed-off-by: Akihiko Odaki <akihiko.odaki@daynix.com> Acked-by: LIU Zhiwei <zhiwei_liu@linux.alibaba.com> Reviewed-by: Daniel Henrique Barboza <dbarboza@ventanamicro.com> Acked-by: Alistair Francis <alistair.francis@wdc.com> Message-ID: <20240203-riscv-v11-1-a23f4848a628@daynix.com> Signed-off-by: Alistair Francis <alistair.francis@wdc.com> --- target/riscv/tcg/tcg-cpu.c | 15 +++------------ 1 file changed, 3 insertions(+), 12 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 riscv_cpu_validate_misa_priv(CPURISCVState *env, Error **errp) } } -static void riscv_cpu_validate_misa_mxl(RISCVCPU *cpu, Error **errp) +static void riscv_cpu_validate_misa_mxl(RISCVCPU *cpu) { RISCVCPUClass *mcc = RISCV_CPU_GET_CLASS(cpu); CPUClass *cc = CPU_CLASS(mcc); @@ -XXX,XX +XXX,XX @@ static void riscv_cpu_validate_misa_mxl(RISCVCPU *cpu, Error **errp) default: g_assert_not_reached(); } - - if (env->misa_mxl_max != env->misa_mxl) { - error_setg(errp, "misa_mxl_max must be equal to misa_mxl"); - return; - } } static void riscv_cpu_validate_v(CPURISCVState *env, RISCVCPUConfig *cfg, @@ -XXX,XX +XXX,XX @@ static bool riscv_cpu_is_generic(Object *cpu_obj) static bool riscv_tcg_cpu_realize(CPUState *cs, Error **errp) { RISCVCPU *cpu = RISCV_CPU(cs); - Error *local_err = NULL; if (!riscv_cpu_tcg_compatible(cpu)) { g_autofree char *name = riscv_cpu_get_name(cpu); @@ -XXX,XX +XXX,XX @@ static bool riscv_tcg_cpu_realize(CPUState *cs, Error **errp) return false; } - riscv_cpu_validate_misa_mxl(cpu, &local_err); - if (local_err != NULL) { - error_propagate(errp, local_err); - return false; - } + riscv_cpu_validate_misa_mxl(cpu); #ifndef CONFIG_USER_ONLY CPURISCVState *env = &cpu->env; + Error *local_err = NULL; CPU(cs)->tcg_cflags |= CF_PCREL; -- 2.43.0
From: Akihiko Odaki <akihiko.odaki@daynix.com> misa_mxl_max is common for all instances of a RISC-V CPU class so they are better put into class. Signed-off-by: Akihiko Odaki <akihiko.odaki@daynix.com> Reviewed-by: Alistair Francis <alistair.francis@wdc.com> Message-ID: <20240203-riscv-v11-2-a23f4848a628@daynix.com> Signed-off-by: Alistair Francis <alistair.francis@wdc.com> --- target/riscv/cpu.h | 4 +- hw/riscv/boot.c | 3 +- target/riscv/cpu.c | 160 +++++++++++++++++++------------------ target/riscv/gdbstub.c | 12 ++- target/riscv/kvm/kvm-cpu.c | 10 +-- target/riscv/machine.c | 7 +- target/riscv/tcg/tcg-cpu.c | 12 +-- target/riscv/translate.c | 3 +- 8 files changed, 112 insertions(+), 99 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 { /* RISCVMXL, but uint32_t for vmstate migration */ uint32_t misa_mxl; /* current mxl */ - uint32_t misa_mxl_max; /* max mxl for this cpu */ uint32_t misa_ext; /* current extensions */ uint32_t misa_ext_mask; /* max ext for this cpu */ uint32_t xl; /* current xlen */ @@ -XXX,XX +XXX,XX @@ struct RISCVCPUClass { DeviceRealize parent_realize; ResettablePhases parent_phases; + uint32_t misa_mxl_max; /* max mxl for this cpu */ }; static inline int riscv_has_ext(CPURISCVState *env, target_ulong ext) @@ -XXX,XX +XXX,XX @@ enum riscv_pmu_event_idx { /* used by tcg/tcg-cpu.c*/ void isa_ext_update_enabled(RISCVCPU *cpu, uint32_t ext_offset, bool en); bool isa_ext_is_enabled(RISCVCPU *cpu, uint32_t ext_offset); -void riscv_cpu_set_misa(CPURISCVState *env, RISCVMXL mxl, uint32_t ext); +void riscv_cpu_set_misa_ext(CPURISCVState *env, uint32_t ext); bool riscv_cpu_is_vendor(Object *cpu_obj); typedef struct RISCVCPUMultiExtConfig { diff --git a/hw/riscv/boot.c b/hw/riscv/boot.c index XXXXXXX..XXXXXXX 100644 --- a/hw/riscv/boot.c +++ b/hw/riscv/boot.c @@ -XXX,XX +XXX,XX @@ bool riscv_is_32bit(RISCVHartArrayState *harts) { - return harts->harts[0].env.misa_mxl_max == MXL_RV32; + RISCVCPUClass *mcc = RISCV_CPU_GET_CLASS(&harts->harts[0]); + return mcc->misa_mxl_max == MXL_RV32; } /* 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 char *riscv_cpu_get_trap_name(target_ulong cause, bool async) } } -void riscv_cpu_set_misa(CPURISCVState *env, RISCVMXL mxl, uint32_t ext) +void riscv_cpu_set_misa_ext(CPURISCVState *env, uint32_t ext) { - env->misa_mxl_max = env->misa_mxl = mxl; env->misa_ext_mask = env->misa_ext = ext; } @@ -XXX,XX +XXX,XX @@ static void riscv_any_cpu_init(Object *obj) { RISCVCPU *cpu = RISCV_CPU(obj); CPURISCVState *env = &cpu->env; -#if defined(TARGET_RISCV32) - riscv_cpu_set_misa(env, MXL_RV32, RVI | RVM | RVA | RVF | RVD | RVC | RVU); -#elif defined(TARGET_RISCV64) - riscv_cpu_set_misa(env, MXL_RV64, RVI | RVM | RVA | RVF | RVD | RVC | RVU); -#endif + riscv_cpu_set_misa_ext(env, RVI | RVM | RVA | RVF | RVD | RVC | RVU); #ifndef CONFIG_USER_ONLY set_satp_mode_max_supported(RISCV_CPU(obj), @@ -XXX,XX +XXX,XX @@ static void riscv_max_cpu_init(Object *obj) { RISCVCPU *cpu = RISCV_CPU(obj); CPURISCVState *env = &cpu->env; - RISCVMXL mlx = MXL_RV64; cpu->cfg.mmu = true; cpu->cfg.pmp = true; -#ifdef TARGET_RISCV32 - mlx = MXL_RV32; -#endif - riscv_cpu_set_misa(env, mlx, 0); env->priv_ver = PRIV_VERSION_LATEST; #ifndef CONFIG_USER_ONLY - set_satp_mode_max_supported(RISCV_CPU(obj), mlx == MXL_RV32 ? - VM_1_10_SV32 : VM_1_10_SV57); +#ifdef TARGET_RISCV32 + set_satp_mode_max_supported(cpu, VM_1_10_SV32); +#else + set_satp_mode_max_supported(cpu, VM_1_10_SV57); +#endif #endif } @@ -XXX,XX +XXX,XX @@ static void rv64_base_cpu_init(Object *obj) cpu->cfg.mmu = true; cpu->cfg.pmp = true; - /* We set this in the realise function */ - riscv_cpu_set_misa(env, MXL_RV64, 0); /* Set latest version of privileged specification */ env->priv_ver = PRIV_VERSION_LATEST; #ifndef CONFIG_USER_ONLY @@ -XXX,XX +XXX,XX @@ static void rv64_sifive_u_cpu_init(Object *obj) { RISCVCPU *cpu = RISCV_CPU(obj); CPURISCVState *env = &cpu->env; - riscv_cpu_set_misa(env, MXL_RV64, - RVI | RVM | RVA | RVF | RVD | RVC | RVS | RVU); + riscv_cpu_set_misa_ext(env, RVI | RVM | RVA | RVF | RVD | RVC | RVS | RVU); env->priv_ver = PRIV_VERSION_1_10_0; #ifndef CONFIG_USER_ONLY set_satp_mode_max_supported(RISCV_CPU(obj), VM_1_10_SV39); @@ -XXX,XX +XXX,XX @@ static void rv64_sifive_e_cpu_init(Object *obj) CPURISCVState *env = &RISCV_CPU(obj)->env; RISCVCPU *cpu = RISCV_CPU(obj); - riscv_cpu_set_misa(env, MXL_RV64, RVI | RVM | RVA | RVC | RVU); + riscv_cpu_set_misa_ext(env, RVI | RVM | RVA | RVC | RVU); env->priv_ver = PRIV_VERSION_1_10_0; #ifndef CONFIG_USER_ONLY set_satp_mode_max_supported(cpu, VM_1_10_MBARE); @@ -XXX,XX +XXX,XX @@ static void rv64_thead_c906_cpu_init(Object *obj) CPURISCVState *env = &RISCV_CPU(obj)->env; RISCVCPU *cpu = RISCV_CPU(obj); - riscv_cpu_set_misa(env, MXL_RV64, RVG | RVC | RVS | RVU); + riscv_cpu_set_misa_ext(env, RVG | RVC | RVS | RVU); env->priv_ver = PRIV_VERSION_1_11_0; cpu->cfg.ext_zfa = true; @@ -XXX,XX +XXX,XX @@ static void rv64_veyron_v1_cpu_init(Object *obj) CPURISCVState *env = &RISCV_CPU(obj)->env; RISCVCPU *cpu = RISCV_CPU(obj); - riscv_cpu_set_misa(env, MXL_RV64, RVG | RVC | RVS | RVU | RVH); + riscv_cpu_set_misa_ext(env, RVG | RVC | RVS | RVU | RVH); env->priv_ver = PRIV_VERSION_1_12_0; /* Enable ISA extensions */ @@ -XXX,XX +XXX,XX @@ static void rv128_base_cpu_init(Object *obj) cpu->cfg.mmu = true; cpu->cfg.pmp = true; - /* We set this in the realise function */ - riscv_cpu_set_misa(env, MXL_RV128, 0); /* Set latest version of privileged specification */ env->priv_ver = PRIV_VERSION_LATEST; #ifndef CONFIG_USER_ONLY @@ -XXX,XX +XXX,XX @@ static void rv128_base_cpu_init(Object *obj) static void rv64i_bare_cpu_init(Object *obj) { CPURISCVState *env = &RISCV_CPU(obj)->env; - riscv_cpu_set_misa(env, MXL_RV64, RVI); + riscv_cpu_set_misa_ext(env, RVI); /* Remove the defaults from the parent class */ RISCV_CPU(obj)->cfg.ext_zicntr = false; @@ -XXX,XX +XXX,XX @@ static void rv32_base_cpu_init(Object *obj) cpu->cfg.mmu = true; cpu->cfg.pmp = true; - /* We set this in the realise function */ - riscv_cpu_set_misa(env, MXL_RV32, 0); /* Set latest version of privileged specification */ env->priv_ver = PRIV_VERSION_LATEST; #ifndef CONFIG_USER_ONLY @@ -XXX,XX +XXX,XX @@ static void rv32_sifive_u_cpu_init(Object *obj) { RISCVCPU *cpu = RISCV_CPU(obj); CPURISCVState *env = &cpu->env; - riscv_cpu_set_misa(env, MXL_RV32, - RVI | RVM | RVA | RVF | RVD | RVC | RVS | RVU); + riscv_cpu_set_misa_ext(env, RVI | RVM | RVA | RVF | RVD | RVC | RVS | RVU); env->priv_ver = PRIV_VERSION_1_10_0; #ifndef CONFIG_USER_ONLY set_satp_mode_max_supported(RISCV_CPU(obj), VM_1_10_SV32); @@ -XXX,XX +XXX,XX @@ static void rv32_sifive_e_cpu_init(Object *obj) CPURISCVState *env = &RISCV_CPU(obj)->env; RISCVCPU *cpu = RISCV_CPU(obj); - riscv_cpu_set_misa(env, MXL_RV32, RVI | RVM | RVA | RVC | RVU); + riscv_cpu_set_misa_ext(env, RVI | RVM | RVA | RVC | RVU); env->priv_ver = PRIV_VERSION_1_10_0; #ifndef CONFIG_USER_ONLY set_satp_mode_max_supported(cpu, VM_1_10_MBARE); @@ -XXX,XX +XXX,XX @@ static void rv32_ibex_cpu_init(Object *obj) CPURISCVState *env = &RISCV_CPU(obj)->env; RISCVCPU *cpu = RISCV_CPU(obj); - riscv_cpu_set_misa(env, MXL_RV32, RVI | RVM | RVC | RVU); + riscv_cpu_set_misa_ext(env, RVI | RVM | RVC | RVU); env->priv_ver = PRIV_VERSION_1_12_0; #ifndef CONFIG_USER_ONLY set_satp_mode_max_supported(cpu, VM_1_10_MBARE); @@ -XXX,XX +XXX,XX @@ static void rv32_imafcu_nommu_cpu_init(Object *obj) CPURISCVState *env = &RISCV_CPU(obj)->env; RISCVCPU *cpu = RISCV_CPU(obj); - riscv_cpu_set_misa(env, MXL_RV32, RVI | RVM | RVA | RVF | RVC | RVU); + riscv_cpu_set_misa_ext(env, RVI | RVM | RVA | RVF | RVC | RVU); env->priv_ver = PRIV_VERSION_1_10_0; #ifndef CONFIG_USER_ONLY set_satp_mode_max_supported(cpu, VM_1_10_MBARE); @@ -XXX,XX +XXX,XX @@ static void riscv_cpu_reset_hold(Object *obj) mcc->parent_phases.hold(obj); } #ifndef CONFIG_USER_ONLY - env->misa_mxl = env->misa_mxl_max; + env->misa_mxl = mcc->misa_mxl_max; env->priv = PRV_M; env->mstatus &= ~(MSTATUS_MIE | MSTATUS_MPRV); if (env->misa_mxl > MXL_RV32) { @@ -XXX,XX +XXX,XX @@ static void riscv_cpu_post_init(Object *obj) static void riscv_cpu_init(Object *obj) { + RISCVCPUClass *mcc = RISCV_CPU_GET_CLASS(obj); RISCVCPU *cpu = RISCV_CPU(obj); + CPURISCVState *env = &cpu->env; + + env->misa_mxl = mcc->misa_mxl_max; #ifndef CONFIG_USER_ONLY qdev_init_gpio_in(DEVICE(obj), riscv_cpu_set_irq, @@ -XXX,XX +XXX,XX @@ static const struct SysemuCPUOps riscv_sysemu_ops = { }; #endif -static void riscv_cpu_class_init(ObjectClass *c, void *data) +static void riscv_cpu_common_class_init(ObjectClass *c, void *data) { RISCVCPUClass *mcc = RISCV_CPU_CLASS(c); CPUClass *cc = CPU_CLASS(c); @@ -XXX,XX +XXX,XX @@ static void riscv_cpu_class_init(ObjectClass *c, void *data) device_class_set_props(dc, riscv_cpu_properties); } +static void riscv_cpu_class_init(ObjectClass *c, void *data) +{ + RISCVCPUClass *mcc = RISCV_CPU_CLASS(c); + + mcc->misa_mxl_max = (uint32_t)(uintptr_t)data; +} + static void riscv_isa_string_ext(RISCVCPU *cpu, char **isa_str, int max_str_len) { @@ -XXX,XX +XXX,XX @@ char *riscv_isa_string(RISCVCPU *cpu) return isa_str; } -#define DEFINE_CPU(type_name, initfn) \ - { \ - .name = type_name, \ - .parent = TYPE_RISCV_CPU, \ - .instance_init = initfn \ +#define DEFINE_CPU(type_name, misa_mxl_max, initfn) \ + { \ + .name = (type_name), \ + .parent = TYPE_RISCV_CPU, \ + .instance_init = (initfn), \ + .class_init = riscv_cpu_class_init, \ + .class_data = (void *)(misa_mxl_max) \ } -#define DEFINE_DYNAMIC_CPU(type_name, initfn) \ - { \ - .name = type_name, \ - .parent = TYPE_RISCV_DYNAMIC_CPU, \ - .instance_init = initfn \ +#define DEFINE_DYNAMIC_CPU(type_name, misa_mxl_max, initfn) \ + { \ + .name = (type_name), \ + .parent = TYPE_RISCV_DYNAMIC_CPU, \ + .instance_init = (initfn), \ + .class_init = riscv_cpu_class_init, \ + .class_data = (void *)(misa_mxl_max) \ } -#define DEFINE_VENDOR_CPU(type_name, initfn) \ - { \ - .name = type_name, \ - .parent = TYPE_RISCV_VENDOR_CPU, \ - .instance_init = initfn \ +#define DEFINE_VENDOR_CPU(type_name, misa_mxl_max, initfn) \ + { \ + .name = (type_name), \ + .parent = TYPE_RISCV_VENDOR_CPU, \ + .instance_init = (initfn), \ + .class_init = riscv_cpu_class_init, \ + .class_data = (void *)(misa_mxl_max) \ } -#define DEFINE_BARE_CPU(type_name, initfn) \ - { \ - .name = type_name, \ - .parent = TYPE_RISCV_BARE_CPU, \ - .instance_init = initfn \ +#define DEFINE_BARE_CPU(type_name, misa_mxl_max, initfn) \ + { \ + .name = (type_name), \ + .parent = TYPE_RISCV_BARE_CPU, \ + .instance_init = (initfn), \ + .class_init = riscv_cpu_class_init, \ + .class_data = (void *)(misa_mxl_max) \ } -#define DEFINE_PROFILE_CPU(type_name, initfn) \ - { \ - .name = type_name, \ - .parent = TYPE_RISCV_BARE_CPU, \ - .instance_init = initfn \ +#define DEFINE_PROFILE_CPU(type_name, misa_mxl_max, initfn) \ + { \ + .name = (type_name), \ + .parent = TYPE_RISCV_BARE_CPU, \ + .instance_init = (initfn), \ + .class_init = riscv_cpu_class_init, \ + .class_data = (void *)(misa_mxl_max) \ } static const TypeInfo riscv_cpu_type_infos[] = { @@ -XXX,XX +XXX,XX @@ static const TypeInfo riscv_cpu_type_infos[] = { .instance_post_init = riscv_cpu_post_init, .abstract = true, .class_size = sizeof(RISCVCPUClass), - .class_init = riscv_cpu_class_init, + .class_init = riscv_cpu_common_class_init, }, { .name = TYPE_RISCV_DYNAMIC_CPU, @@ -XXX,XX +XXX,XX @@ static const TypeInfo riscv_cpu_type_infos[] = { .parent = TYPE_RISCV_CPU, .abstract = true, }, - DEFINE_DYNAMIC_CPU(TYPE_RISCV_CPU_ANY, riscv_any_cpu_init), - DEFINE_DYNAMIC_CPU(TYPE_RISCV_CPU_MAX, riscv_max_cpu_init), #if defined(TARGET_RISCV32) - DEFINE_DYNAMIC_CPU(TYPE_RISCV_CPU_BASE32, rv32_base_cpu_init), - DEFINE_VENDOR_CPU(TYPE_RISCV_CPU_IBEX, rv32_ibex_cpu_init), - DEFINE_VENDOR_CPU(TYPE_RISCV_CPU_SIFIVE_E31, rv32_sifive_e_cpu_init), - DEFINE_VENDOR_CPU(TYPE_RISCV_CPU_SIFIVE_E34, rv32_imafcu_nommu_cpu_init), - DEFINE_VENDOR_CPU(TYPE_RISCV_CPU_SIFIVE_U34, rv32_sifive_u_cpu_init), + DEFINE_DYNAMIC_CPU(TYPE_RISCV_CPU_ANY, MXL_RV32, riscv_any_cpu_init), + DEFINE_DYNAMIC_CPU(TYPE_RISCV_CPU_MAX, MXL_RV32, riscv_max_cpu_init), + DEFINE_DYNAMIC_CPU(TYPE_RISCV_CPU_BASE32, MXL_RV32, rv32_base_cpu_init), + DEFINE_VENDOR_CPU(TYPE_RISCV_CPU_IBEX, MXL_RV32, rv32_ibex_cpu_init), + DEFINE_VENDOR_CPU(TYPE_RISCV_CPU_SIFIVE_E31, MXL_RV32, rv32_sifive_e_cpu_init), + DEFINE_VENDOR_CPU(TYPE_RISCV_CPU_SIFIVE_E34, MXL_RV32, rv32_imafcu_nommu_cpu_init), + DEFINE_VENDOR_CPU(TYPE_RISCV_CPU_SIFIVE_U34, MXL_RV32, rv32_sifive_u_cpu_init), #elif defined(TARGET_RISCV64) - DEFINE_DYNAMIC_CPU(TYPE_RISCV_CPU_BASE64, rv64_base_cpu_init), - DEFINE_VENDOR_CPU(TYPE_RISCV_CPU_SIFIVE_E51, rv64_sifive_e_cpu_init), - DEFINE_VENDOR_CPU(TYPE_RISCV_CPU_SIFIVE_U54, rv64_sifive_u_cpu_init), - DEFINE_VENDOR_CPU(TYPE_RISCV_CPU_SHAKTI_C, rv64_sifive_u_cpu_init), - DEFINE_VENDOR_CPU(TYPE_RISCV_CPU_THEAD_C906, rv64_thead_c906_cpu_init), - DEFINE_VENDOR_CPU(TYPE_RISCV_CPU_VEYRON_V1, rv64_veyron_v1_cpu_init), - DEFINE_DYNAMIC_CPU(TYPE_RISCV_CPU_BASE128, rv128_base_cpu_init), - DEFINE_BARE_CPU(TYPE_RISCV_CPU_RV64I, rv64i_bare_cpu_init), - DEFINE_PROFILE_CPU(TYPE_RISCV_CPU_RVA22U64, rva22u64_profile_cpu_init), - DEFINE_PROFILE_CPU(TYPE_RISCV_CPU_RVA22S64, rva22s64_profile_cpu_init), + DEFINE_DYNAMIC_CPU(TYPE_RISCV_CPU_ANY, MXL_RV64, riscv_any_cpu_init), + DEFINE_DYNAMIC_CPU(TYPE_RISCV_CPU_MAX, MXL_RV64, riscv_max_cpu_init), + DEFINE_DYNAMIC_CPU(TYPE_RISCV_CPU_BASE64, MXL_RV64, rv64_base_cpu_init), + DEFINE_VENDOR_CPU(TYPE_RISCV_CPU_SIFIVE_E51, MXL_RV64, rv64_sifive_e_cpu_init), + DEFINE_VENDOR_CPU(TYPE_RISCV_CPU_SIFIVE_U54, MXL_RV64, rv64_sifive_u_cpu_init), + DEFINE_VENDOR_CPU(TYPE_RISCV_CPU_SHAKTI_C, MXL_RV64, rv64_sifive_u_cpu_init), + DEFINE_VENDOR_CPU(TYPE_RISCV_CPU_THEAD_C906, MXL_RV64, rv64_thead_c906_cpu_init), + DEFINE_VENDOR_CPU(TYPE_RISCV_CPU_VEYRON_V1, MXL_RV64, rv64_veyron_v1_cpu_init), + DEFINE_DYNAMIC_CPU(TYPE_RISCV_CPU_BASE128, MXL_RV128, rv128_base_cpu_init), + DEFINE_BARE_CPU(TYPE_RISCV_CPU_RV64I, MXL_RV64, rv64i_bare_cpu_init), + DEFINE_PROFILE_CPU(TYPE_RISCV_CPU_RVA22U64, MXL_RV64, rva22u64_profile_cpu_init), + DEFINE_PROFILE_CPU(TYPE_RISCV_CPU_RVA22S64, MXL_RV64, rva22s64_profile_cpu_init), #endif }; diff --git a/target/riscv/gdbstub.c b/target/riscv/gdbstub.c index XXXXXXX..XXXXXXX 100644 --- a/target/riscv/gdbstub.c +++ b/target/riscv/gdbstub.c @@ -XXX,XX +XXX,XX @@ static const struct TypeSize vec_lanes[] = { int riscv_cpu_gdb_read_register(CPUState *cs, GByteArray *mem_buf, int n) { + RISCVCPUClass *mcc = RISCV_CPU_GET_CLASS(cs); RISCVCPU *cpu = RISCV_CPU(cs); CPURISCVState *env = &cpu->env; target_ulong tmp; @@ -XXX,XX +XXX,XX @@ int riscv_cpu_gdb_read_register(CPUState *cs, GByteArray *mem_buf, int n) return 0; } - switch (env->misa_mxl_max) { + switch (mcc->misa_mxl_max) { case MXL_RV32: return gdb_get_reg32(mem_buf, tmp); case MXL_RV64: @@ -XXX,XX +XXX,XX @@ int riscv_cpu_gdb_read_register(CPUState *cs, GByteArray *mem_buf, int n) int riscv_cpu_gdb_write_register(CPUState *cs, uint8_t *mem_buf, int n) { + RISCVCPUClass *mcc = RISCV_CPU_GET_CLASS(cs); RISCVCPU *cpu = RISCV_CPU(cs); CPURISCVState *env = &cpu->env; int length = 0; target_ulong tmp; - switch (env->misa_mxl_max) { + switch (mcc->misa_mxl_max) { case MXL_RV32: tmp = (int32_t)ldl_p(mem_buf); length = 4; @@ -XXX,XX +XXX,XX @@ static int riscv_gdb_set_virtual(CPURISCVState *cs, uint8_t *mem_buf, int n) static int riscv_gen_dynamic_csr_xml(CPUState *cs, int base_reg) { + RISCVCPUClass *mcc = RISCV_CPU_GET_CLASS(cs); RISCVCPU *cpu = RISCV_CPU(cs); CPURISCVState *env = &cpu->env; GString *s = g_string_new(NULL); riscv_csr_predicate_fn predicate; - int bitsize = 16 << env->misa_mxl_max; + int bitsize = 16 << mcc->misa_mxl_max; int i; #if !defined(CONFIG_USER_ONLY) @@ -XXX,XX +XXX,XX @@ static int ricsv_gen_dynamic_vector_xml(CPUState *cs, int base_reg) void riscv_cpu_register_gdb_regs_for_features(CPUState *cs) { + RISCVCPUClass *mcc = RISCV_CPU_GET_CLASS(cs); RISCVCPU *cpu = RISCV_CPU(cs); CPURISCVState *env = &cpu->env; if (env->misa_ext & RVD) { @@ -XXX,XX +XXX,XX @@ void riscv_cpu_register_gdb_regs_for_features(CPUState *cs) ricsv_gen_dynamic_vector_xml(cs, base_reg), "riscv-vector.xml", 0); } - switch (env->misa_mxl_max) { + switch (mcc->misa_mxl_max) { case MXL_RV32: gdb_register_coprocessor(cs, riscv_gdb_get_virtual, riscv_gdb_set_virtual, 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_cpu_accel_register_types(void) } type_init(kvm_cpu_accel_register_types); -static void riscv_host_cpu_init(Object *obj) +static void riscv_host_cpu_class_init(ObjectClass *c, void *data) { - CPURISCVState *env = &RISCV_CPU(obj)->env; + RISCVCPUClass *mcc = RISCV_CPU_CLASS(c); #if defined(TARGET_RISCV32) - env->misa_mxl_max = env->misa_mxl = MXL_RV32; + mcc->misa_mxl_max = MXL_RV32; #elif defined(TARGET_RISCV64) - env->misa_mxl_max = env->misa_mxl = MXL_RV64; + mcc->misa_mxl_max = MXL_RV64; #endif } @@ -XXX,XX +XXX,XX @@ static const TypeInfo riscv_kvm_cpu_type_infos[] = { { .name = TYPE_RISCV_CPU_HOST, .parent = TYPE_RISCV_CPU, - .instance_init = riscv_host_cpu_init, + .class_init = riscv_host_cpu_class_init, } }; 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 const VMStateDescription vmstate_pointermasking = { static bool rv128_needed(void *opaque) { - RISCVCPU *cpu = opaque; - CPURISCVState *env = &cpu->env; + RISCVCPUClass *mcc = RISCV_CPU_GET_CLASS(opaque); - return env->misa_mxl_max == MXL_RV128; + return mcc->misa_mxl_max == MXL_RV128; } static const VMStateDescription vmstate_rv128 = { @@ -XXX,XX +XXX,XX @@ const VMStateDescription vmstate_riscv_cpu = { VMSTATE_UINTTL(env.vext_ver, RISCVCPU), VMSTATE_UINT32(env.misa_mxl, RISCVCPU), VMSTATE_UINT32(env.misa_ext, RISCVCPU), - VMSTATE_UINT32(env.misa_mxl_max, RISCVCPU), + VMSTATE_UNUSED(4), VMSTATE_UINT32(env.misa_ext_mask, RISCVCPU), VMSTATE_UINTTL(env.priv, RISCVCPU), VMSTATE_BOOL(env.virt_enabled, 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_validate_misa_mxl(RISCVCPU *cpu) { RISCVCPUClass *mcc = RISCV_CPU_GET_CLASS(cpu); CPUClass *cc = CPU_CLASS(mcc); - CPURISCVState *env = &cpu->env; /* Validate that MISA_MXL is set properly. */ - switch (env->misa_mxl_max) { + switch (mcc->misa_mxl_max) { #ifdef TARGET_RISCV64 case MXL_RV64: case MXL_RV128: @@ -XXX,XX +XXX,XX @@ static void riscv_cpu_validate_b(RISCVCPU *cpu) */ void riscv_cpu_validate_set_extensions(RISCVCPU *cpu, Error **errp) { + RISCVCPUClass *mcc = RISCV_CPU_GET_CLASS(cpu); CPURISCVState *env = &cpu->env; Error *local_err = NULL; @@ -XXX,XX +XXX,XX @@ void riscv_cpu_validate_set_extensions(RISCVCPU *cpu, Error **errp) cpu_cfg_ext_auto_update(cpu, CPU_CFG_OFFSET(ext_zcb), true); cpu_cfg_ext_auto_update(cpu, CPU_CFG_OFFSET(ext_zcmp), true); cpu_cfg_ext_auto_update(cpu, CPU_CFG_OFFSET(ext_zcmt), true); - if (riscv_has_ext(env, RVF) && env->misa_mxl_max == MXL_RV32) { + if (riscv_has_ext(env, RVF) && mcc->misa_mxl_max == MXL_RV32) { cpu_cfg_ext_auto_update(cpu, CPU_CFG_OFFSET(ext_zcf), true); } } @@ -XXX,XX +XXX,XX @@ void riscv_cpu_validate_set_extensions(RISCVCPU *cpu, Error **errp) /* zca, zcd and zcf has a PRIV 1.12.0 restriction */ if (riscv_has_ext(env, RVC) && env->priv_ver >= PRIV_VERSION_1_12_0) { cpu_cfg_ext_auto_update(cpu, CPU_CFG_OFFSET(ext_zca), true); - if (riscv_has_ext(env, RVF) && env->misa_mxl_max == MXL_RV32) { + if (riscv_has_ext(env, RVF) && mcc->misa_mxl_max == MXL_RV32) { cpu_cfg_ext_auto_update(cpu, CPU_CFG_OFFSET(ext_zcf), true); } if (riscv_has_ext(env, RVD)) { @@ -XXX,XX +XXX,XX @@ void riscv_cpu_validate_set_extensions(RISCVCPU *cpu, Error **errp) } } - if (env->misa_mxl_max != MXL_RV32 && cpu->cfg.ext_zcf) { + if (mcc->misa_mxl_max != MXL_RV32 && cpu->cfg.ext_zcf) { error_setg(errp, "Zcf extension is only relevant to RV32"); return; } @@ -XXX,XX +XXX,XX @@ static void riscv_init_max_cpu_extensions(Object *obj) const RISCVCPUMultiExtConfig *prop; /* Enable RVG, RVJ and RVV that are disabled by default */ - riscv_cpu_set_misa(env, env->misa_mxl, env->misa_ext | RVG | RVJ | RVV); + riscv_cpu_set_misa_ext(env, env->misa_ext | RVG | RVJ | RVV); for (prop = riscv_cpu_extensions; prop && prop->name; prop++) { isa_ext_update_enabled(cpu, prop->offset, 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 void riscv_tr_init_disas_context(DisasContextBase *dcbase, CPUState *cs) { DisasContext *ctx = container_of(dcbase, DisasContext, base); CPURISCVState *env = cpu_env(cs); + RISCVCPUClass *mcc = RISCV_CPU_GET_CLASS(cs); RISCVCPU *cpu = RISCV_CPU(cs); uint32_t tb_flags = ctx->base.tb->flags; @@ -XXX,XX +XXX,XX @@ static void riscv_tr_init_disas_context(DisasContextBase *dcbase, CPUState *cs) ctx->cfg_vta_all_1s = cpu->cfg.rvv_ta_all_1s; ctx->vstart_eq_zero = FIELD_EX32(tb_flags, TB_FLAGS, VSTART_EQ_ZERO); ctx->vl_eq_vlmax = FIELD_EX32(tb_flags, TB_FLAGS, VL_EQ_VLMAX); - ctx->misa_mxl_max = env->misa_mxl_max; + ctx->misa_mxl_max = mcc->misa_mxl_max; ctx->xl = FIELD_EX32(tb_flags, TB_FLAGS, XL); ctx->address_xl = FIELD_EX32(tb_flags, TB_FLAGS, AXL); ctx->cs = cs; -- 2.43.0
From: Akihiko Odaki <akihiko.odaki@daynix.com> misa_mxl_max is now a class member and initialized only once for each class. This also moves the initialization of gdb_core_xml_file which will be referenced before realization in the future. Signed-off-by: Akihiko Odaki <akihiko.odaki@daynix.com> Reviewed-by: Alistair Francis <alistair.francis@wdc.com> Message-ID: <20240203-riscv-v11-3-a23f4848a628@daynix.com> Signed-off-by: Alistair Francis <alistair.francis@wdc.com> --- target/riscv/cpu.c | 21 +++++++++++++++++++++ target/riscv/tcg/tcg-cpu.c | 23 ----------------------- 2 files changed, 21 insertions(+), 23 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 @@ static const MISAExtInfo misa_ext_info_arr[] = { MISA_EXT_INFO(RVB, "x-b", "Bit manipulation (Zba_Zbb_Zbs)") }; +static void riscv_cpu_validate_misa_mxl(RISCVCPUClass *mcc) +{ + CPUClass *cc = CPU_CLASS(mcc); + + /* Validate that MISA_MXL is set properly. */ + switch (mcc->misa_mxl_max) { +#ifdef TARGET_RISCV64 + case MXL_RV64: + case MXL_RV128: + cc->gdb_core_xml_file = "riscv-64bit-cpu.xml"; + break; +#endif + case MXL_RV32: + cc->gdb_core_xml_file = "riscv-32bit-cpu.xml"; + break; + default: + g_assert_not_reached(); + } +} + static int riscv_validate_misa_info_idx(uint32_t bit) { int idx; @@ -XXX,XX +XXX,XX @@ static void riscv_cpu_class_init(ObjectClass *c, void *data) RISCVCPUClass *mcc = RISCV_CPU_CLASS(c); mcc->misa_mxl_max = (uint32_t)(uintptr_t)data; + riscv_cpu_validate_misa_mxl(mcc); } static void riscv_isa_string_ext(RISCVCPU *cpu, char **isa_str, 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_validate_misa_priv(CPURISCVState *env, Error **errp) } } -static void riscv_cpu_validate_misa_mxl(RISCVCPU *cpu) -{ - RISCVCPUClass *mcc = RISCV_CPU_GET_CLASS(cpu); - CPUClass *cc = CPU_CLASS(mcc); - - /* Validate that MISA_MXL is set properly. */ - switch (mcc->misa_mxl_max) { -#ifdef TARGET_RISCV64 - case MXL_RV64: - case MXL_RV128: - cc->gdb_core_xml_file = "riscv-64bit-cpu.xml"; - break; -#endif - case MXL_RV32: - cc->gdb_core_xml_file = "riscv-32bit-cpu.xml"; - break; - default: - g_assert_not_reached(); - } -} - static void riscv_cpu_validate_v(CPURISCVState *env, RISCVCPUConfig *cfg, Error **errp) { @@ -XXX,XX +XXX,XX @@ static bool riscv_tcg_cpu_realize(CPUState *cs, Error **errp) return false; } - riscv_cpu_validate_misa_mxl(cpu); - #ifndef CONFIG_USER_ONLY CPURISCVState *env = &cpu->env; Error *local_err = NULL; -- 2.43.0
From: LIU Zhiwei <zhiwei_liu@linux.alibaba.com> vxrm and vxsat have been moved into a special register vcsr since RVV v1.0. So remove them from FCSR for vector 1.0. Signed-off-by: LIU Zhiwei <zhiwei_liu@linux.alibaba.com> Reviewed-by: Daniel Henrique Barboza <dbarboza@ventanamicro.com> Message-ID: <20240130110945.486-1-zhiwei_liu@linux.alibaba.com> Signed-off-by: Alistair Francis <alistair.francis@wdc.com> --- target/riscv/cpu_bits.h | 8 -------- 1 file changed, 8 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 FSR_NXA (FPEXC_NX << FSR_AEXC_SHIFT) #define FSR_AEXC (FSR_NVA | FSR_OFA | FSR_UFA | FSR_DZA | FSR_NXA) -/* Vector Fixed-Point round model */ -#define FSR_VXRM_SHIFT 9 -#define FSR_VXRM (0x3 << FSR_VXRM_SHIFT) - -/* Vector Fixed-Point saturation flag */ -#define FSR_VXSAT_SHIFT 8 -#define FSR_VXSAT (0x1 << FSR_VXSAT_SHIFT) - /* Control and Status Registers */ /* User Trap Setup */ -- 2.43.0
From: LIU Zhiwei <zhiwei_liu@linux.alibaba.com> The real return value type has been converted to RISCVException, but some function declarations still not. This patch makes all csr operation declarations use RISCVExcetion. Signed-off-by: LIU Zhiwei <zhiwei_liu@linux.alibaba.com> Reviewed-by: Alistair Francis <alistair.francis@wdc.com> Reviewed-by: Daniel Henrique Barboza <dbarboza@ventanamicro.com> Message-ID: <20240130110844.437-1-zhiwei_liu@linux.alibaba.com> Signed-off-by: Alistair Francis <alistair.francis@wdc.com> --- target/riscv/csr.c | 117 ++++++++++++++++++++++++++++----------------- 1 file changed, 74 insertions(+), 43 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 any32(CPURISCVState *env, int csrno) } -static int aia_any(CPURISCVState *env, int csrno) +static RISCVException aia_any(CPURISCVState *env, int csrno) { if (!riscv_cpu_cfg(env)->ext_smaia) { return RISCV_EXCP_ILLEGAL_INST; @@ -XXX,XX +XXX,XX @@ static int aia_any(CPURISCVState *env, int csrno) return any(env, csrno); } -static int aia_any32(CPURISCVState *env, int csrno) +static RISCVException aia_any32(CPURISCVState *env, int csrno) { if (!riscv_cpu_cfg(env)->ext_smaia) { return RISCV_EXCP_ILLEGAL_INST; @@ -XXX,XX +XXX,XX @@ static RISCVException smode(CPURISCVState *env, int csrno) return RISCV_EXCP_ILLEGAL_INST; } -static int smode32(CPURISCVState *env, int csrno) +static RISCVException smode32(CPURISCVState *env, int csrno) { if (riscv_cpu_mxl(env) != MXL_RV32) { return RISCV_EXCP_ILLEGAL_INST; @@ -XXX,XX +XXX,XX @@ static int smode32(CPURISCVState *env, int csrno) return smode(env, csrno); } -static int aia_smode(CPURISCVState *env, int csrno) +static RISCVException aia_smode(CPURISCVState *env, int csrno) { if (!riscv_cpu_cfg(env)->ext_ssaia) { return RISCV_EXCP_ILLEGAL_INST; @@ -XXX,XX +XXX,XX @@ static int aia_smode(CPURISCVState *env, int csrno) return smode(env, csrno); } -static int aia_smode32(CPURISCVState *env, int csrno) +static RISCVException aia_smode32(CPURISCVState *env, int csrno) { if (!riscv_cpu_cfg(env)->ext_ssaia) { return RISCV_EXCP_ILLEGAL_INST; @@ -XXX,XX +XXX,XX @@ static RISCVException pointer_masking(CPURISCVState *env, int csrno) return RISCV_EXCP_ILLEGAL_INST; } -static int aia_hmode(CPURISCVState *env, int csrno) +static RISCVException aia_hmode(CPURISCVState *env, int csrno) { if (!riscv_cpu_cfg(env)->ext_ssaia) { return RISCV_EXCP_ILLEGAL_INST; @@ -XXX,XX +XXX,XX @@ static int aia_hmode(CPURISCVState *env, int csrno) return hmode(env, csrno); } -static int aia_hmode32(CPURISCVState *env, int csrno) +static RISCVException aia_hmode32(CPURISCVState *env, int csrno) { if (!riscv_cpu_cfg(env)->ext_ssaia) { return RISCV_EXCP_ILLEGAL_INST; @@ -XXX,XX +XXX,XX @@ static RISCVException read_vl(CPURISCVState *env, int csrno, return RISCV_EXCP_NONE; } -static int read_vlenb(CPURISCVState *env, int csrno, target_ulong *val) +static RISCVException read_vlenb(CPURISCVState *env, int csrno, + target_ulong *val) { *val = riscv_cpu_cfg(env)->vlenb; return RISCV_EXCP_NONE; @@ -XXX,XX +XXX,XX @@ static RISCVException write_vstart(CPURISCVState *env, int csrno, return RISCV_EXCP_NONE; } -static int read_vcsr(CPURISCVState *env, int csrno, target_ulong *val) +static RISCVException read_vcsr(CPURISCVState *env, int csrno, + target_ulong *val) { *val = (env->vxrm << VCSR_VXRM_SHIFT) | (env->vxsat << VCSR_VXSAT_SHIFT); return RISCV_EXCP_NONE; } -static int write_vcsr(CPURISCVState *env, int csrno, target_ulong val) +static RISCVException write_vcsr(CPURISCVState *env, int csrno, + target_ulong val) { #if !defined(CONFIG_USER_ONLY) env->mstatus |= MSTATUS_VS; @@ -XXX,XX +XXX,XX @@ static RISCVException read_timeh(CPURISCVState *env, int csrno, return RISCV_EXCP_NONE; } -static int read_hpmcounter(CPURISCVState *env, int csrno, target_ulong *val) +static RISCVException read_hpmcounter(CPURISCVState *env, int csrno, + target_ulong *val) { *val = get_ticks(false); return RISCV_EXCP_NONE; } -static int read_hpmcounterh(CPURISCVState *env, int csrno, target_ulong *val) +static RISCVException read_hpmcounterh(CPURISCVState *env, int csrno, + target_ulong *val) { *val = get_ticks(true); return RISCV_EXCP_NONE; @@ -XXX,XX +XXX,XX @@ static int read_hpmcounterh(CPURISCVState *env, int csrno, target_ulong *val) #else /* CONFIG_USER_ONLY */ -static int read_mhpmevent(CPURISCVState *env, int csrno, target_ulong *val) +static RISCVException read_mhpmevent(CPURISCVState *env, int csrno, + target_ulong *val) { int evt_index = csrno - CSR_MCOUNTINHIBIT; @@ -XXX,XX +XXX,XX @@ static int read_mhpmevent(CPURISCVState *env, int csrno, target_ulong *val) return RISCV_EXCP_NONE; } -static int write_mhpmevent(CPURISCVState *env, int csrno, target_ulong val) +static RISCVException write_mhpmevent(CPURISCVState *env, int csrno, + target_ulong val) { int evt_index = csrno - CSR_MCOUNTINHIBIT; uint64_t mhpmevt_val = val; @@ -XXX,XX +XXX,XX @@ static int write_mhpmevent(CPURISCVState *env, int csrno, target_ulong val) return RISCV_EXCP_NONE; } -static int read_mhpmeventh(CPURISCVState *env, int csrno, target_ulong *val) +static RISCVException read_mhpmeventh(CPURISCVState *env, int csrno, + target_ulong *val) { int evt_index = csrno - CSR_MHPMEVENT3H + 3; @@ -XXX,XX +XXX,XX @@ static int read_mhpmeventh(CPURISCVState *env, int csrno, target_ulong *val) return RISCV_EXCP_NONE; } -static int write_mhpmeventh(CPURISCVState *env, int csrno, target_ulong val) +static RISCVException write_mhpmeventh(CPURISCVState *env, int csrno, + target_ulong val) { int evt_index = csrno - CSR_MHPMEVENT3H + 3; uint64_t mhpmevth_val = val; @@ -XXX,XX +XXX,XX @@ static int write_mhpmeventh(CPURISCVState *env, int csrno, target_ulong val) return RISCV_EXCP_NONE; } -static int write_mhpmcounter(CPURISCVState *env, int csrno, target_ulong val) +static RISCVException write_mhpmcounter(CPURISCVState *env, int csrno, + target_ulong val) { int ctr_idx = csrno - CSR_MCYCLE; PMUCTRState *counter = &env->pmu_ctrs[ctr_idx]; @@ -XXX,XX +XXX,XX @@ static int write_mhpmcounter(CPURISCVState *env, int csrno, target_ulong val) return RISCV_EXCP_NONE; } -static int write_mhpmcounterh(CPURISCVState *env, int csrno, target_ulong val) +static RISCVException write_mhpmcounterh(CPURISCVState *env, int csrno, + target_ulong val) { int ctr_idx = csrno - CSR_MCYCLEH; PMUCTRState *counter = &env->pmu_ctrs[ctr_idx]; @@ -XXX,XX +XXX,XX @@ static RISCVException riscv_pmu_read_ctr(CPURISCVState *env, target_ulong *val, return RISCV_EXCP_NONE; } -static int read_hpmcounter(CPURISCVState *env, int csrno, target_ulong *val) +static RISCVException read_hpmcounter(CPURISCVState *env, int csrno, + target_ulong *val) { uint16_t ctr_index; @@ -XXX,XX +XXX,XX @@ static int read_hpmcounter(CPURISCVState *env, int csrno, target_ulong *val) return riscv_pmu_read_ctr(env, val, false, ctr_index); } -static int read_hpmcounterh(CPURISCVState *env, int csrno, target_ulong *val) +static RISCVException read_hpmcounterh(CPURISCVState *env, int csrno, + target_ulong *val) { uint16_t ctr_index; @@ -XXX,XX +XXX,XX @@ static int read_hpmcounterh(CPURISCVState *env, int csrno, target_ulong *val) return riscv_pmu_read_ctr(env, val, true, ctr_index); } -static int read_scountovf(CPURISCVState *env, int csrno, target_ulong *val) +static RISCVException read_scountovf(CPURISCVState *env, int csrno, + target_ulong *val) { int mhpmevt_start = CSR_MHPMEVENT3 - CSR_MCOUNTINHIBIT; int i; @@ -XXX,XX +XXX,XX @@ static RISCVException rmw_mvienh(CPURISCVState *env, int csrno, return ret; } -static int read_mtopi(CPURISCVState *env, int csrno, target_ulong *val) +static RISCVException read_mtopi(CPURISCVState *env, int csrno, + target_ulong *val) { int irq; uint8_t iprio; @@ -XXX,XX +XXX,XX @@ static int aia_xlate_vs_csrno(CPURISCVState *env, int csrno) }; } -static int rmw_xiselect(CPURISCVState *env, int csrno, target_ulong *val, - target_ulong new_val, target_ulong wr_mask) +static RISCVException rmw_xiselect(CPURISCVState *env, int csrno, + target_ulong *val, target_ulong new_val, + target_ulong wr_mask) { target_ulong *iselect; @@ -XXX,XX +XXX,XX @@ static int rmw_iprio(target_ulong xlen, return 0; } -static int rmw_xireg(CPURISCVState *env, int csrno, target_ulong *val, - target_ulong new_val, target_ulong wr_mask) +static RISCVException rmw_xireg(CPURISCVState *env, int csrno, + target_ulong *val, target_ulong new_val, + target_ulong wr_mask) { bool virt, isel_reserved; uint8_t *iprio; @@ -XXX,XX +XXX,XX @@ done: return RISCV_EXCP_NONE; } -static int rmw_xtopei(CPURISCVState *env, int csrno, target_ulong *val, - target_ulong new_val, target_ulong wr_mask) +static RISCVException rmw_xtopei(CPURISCVState *env, int csrno, + target_ulong *val, target_ulong new_val, + target_ulong wr_mask) { bool virt; int ret = -EINVAL; @@ -XXX,XX +XXX,XX @@ static RISCVException write_satp(CPURISCVState *env, int csrno, return RISCV_EXCP_NONE; } -static int read_vstopi(CPURISCVState *env, int csrno, target_ulong *val) +static RISCVException read_vstopi(CPURISCVState *env, int csrno, + target_ulong *val) { int irq, ret; target_ulong topei; @@ -XXX,XX +XXX,XX @@ static int read_vstopi(CPURISCVState *env, int csrno, target_ulong *val) return RISCV_EXCP_NONE; } -static int read_stopi(CPURISCVState *env, int csrno, target_ulong *val) +static RISCVException read_stopi(CPURISCVState *env, int csrno, + target_ulong *val) { int irq; uint8_t iprio; @@ -XXX,XX +XXX,XX @@ static RISCVException write_htimedeltah(CPURISCVState *env, int csrno, return RISCV_EXCP_NONE; } -static int read_hvictl(CPURISCVState *env, int csrno, target_ulong *val) +static RISCVException read_hvictl(CPURISCVState *env, int csrno, + target_ulong *val) { *val = env->hvictl; return RISCV_EXCP_NONE; } -static int write_hvictl(CPURISCVState *env, int csrno, target_ulong val) +static RISCVException write_hvictl(CPURISCVState *env, int csrno, + target_ulong val) { env->hvictl = val & HVICTL_VALID_MASK; return RISCV_EXCP_NONE; } -static int read_hvipriox(CPURISCVState *env, int first_index, +static RISCVException read_hvipriox(CPURISCVState *env, int first_index, uint8_t *iprio, target_ulong *val) { int i, irq, rdzero, num_irqs = 4 * (riscv_cpu_mxl_bits(env) / 32); @@ -XXX,XX +XXX,XX @@ static int read_hvipriox(CPURISCVState *env, int first_index, return RISCV_EXCP_NONE; } -static int write_hvipriox(CPURISCVState *env, int first_index, +static RISCVException write_hvipriox(CPURISCVState *env, int first_index, uint8_t *iprio, target_ulong val) { int i, irq, rdzero, num_irqs = 4 * (riscv_cpu_mxl_bits(env) / 32); @@ -XXX,XX +XXX,XX @@ static int write_hvipriox(CPURISCVState *env, int first_index, return RISCV_EXCP_NONE; } -static int read_hviprio1(CPURISCVState *env, int csrno, target_ulong *val) +static RISCVException read_hviprio1(CPURISCVState *env, int csrno, + target_ulong *val) { return read_hvipriox(env, 0, env->hviprio, val); } -static int write_hviprio1(CPURISCVState *env, int csrno, target_ulong val) +static RISCVException write_hviprio1(CPURISCVState *env, int csrno, + target_ulong val) { return write_hvipriox(env, 0, env->hviprio, val); } -static int read_hviprio1h(CPURISCVState *env, int csrno, target_ulong *val) +static RISCVException read_hviprio1h(CPURISCVState *env, int csrno, + target_ulong *val) { return read_hvipriox(env, 4, env->hviprio, val); } -static int write_hviprio1h(CPURISCVState *env, int csrno, target_ulong val) +static RISCVException write_hviprio1h(CPURISCVState *env, int csrno, + target_ulong val) { return write_hvipriox(env, 4, env->hviprio, val); } -static int read_hviprio2(CPURISCVState *env, int csrno, target_ulong *val) +static RISCVException read_hviprio2(CPURISCVState *env, int csrno, + target_ulong *val) { return read_hvipriox(env, 8, env->hviprio, val); } -static int write_hviprio2(CPURISCVState *env, int csrno, target_ulong val) +static RISCVException write_hviprio2(CPURISCVState *env, int csrno, + target_ulong val) { return write_hvipriox(env, 8, env->hviprio, val); } -static int read_hviprio2h(CPURISCVState *env, int csrno, target_ulong *val) +static RISCVException read_hviprio2h(CPURISCVState *env, int csrno, + target_ulong *val) { return read_hvipriox(env, 12, env->hviprio, val); } -static int write_hviprio2h(CPURISCVState *env, int csrno, target_ulong val) +static RISCVException write_hviprio2h(CPURISCVState *env, int csrno, + target_ulong val) { return write_hvipriox(env, 12, env->hviprio, val); } @@ -XXX,XX +XXX,XX @@ static RISCVException write_vsstatus(CPURISCVState *env, int csrno, return RISCV_EXCP_NONE; } -static int read_vstvec(CPURISCVState *env, int csrno, target_ulong *val) +static RISCVException read_vstvec(CPURISCVState *env, int csrno, + target_ulong *val) { *val = env->vstvec; return RISCV_EXCP_NONE; -- 2.43.0
From: Daniel Henrique Barboza <dbarboza@ventanamicro.com> The 'isa' char pointer isn't being freed after use. Issue detected by Valgrind: ==38752== 128 bytes in 1 blocks are definitely lost in loss record 3,190 of 3,884 ==38752== at 0x484280F: malloc (vg_replace_malloc.c:442) ==38752== by 0x5189619: g_malloc (gmem.c:130) ==38752== by 0x51A5BF2: g_strconcat (gstrfuncs.c:628) ==38752== by 0x6C1E3E: riscv_isa_string_ext (cpu.c:2321) ==38752== by 0x6C1E3E: riscv_isa_string (cpu.c:2343) ==38752== by 0x6BD2EA: build_rhct (virt-acpi-build.c:232) ==38752== by 0x6BD2EA: virt_acpi_build (virt-acpi-build.c:556) ==38752== by 0x6BDC86: virt_acpi_setup (virt-acpi-build.c:662) ==38752== by 0x9C8DC6: notifier_list_notify (notify.c:39) ==38752== by 0x4A595A: qdev_machine_creation_done (machine.c:1589) ==38752== by 0x61E052: qemu_machine_creation_done (vl.c:2680) ==38752== by 0x61E052: qmp_x_exit_preconfig.part.0 (vl.c:2709) ==38752== by 0x6220C6: qmp_x_exit_preconfig (vl.c:2702) ==38752== by 0x6220C6: qemu_init (vl.c:3758) ==38752== by 0x425858: main (main.c:47) Fixes: ebfd392893 ("hw/riscv/virt: virt-acpi-build.c: Add RHCT Table") Signed-off-by: Daniel Henrique Barboza <dbarboza@ventanamicro.com> Reviewed-by: Alistair Francis <alistair.francis@wdc.com> Message-ID: <20240122221529.86562-2-dbarboza@ventanamicro.com> Signed-off-by: Alistair Francis <alistair.francis@wdc.com> --- hw/riscv/virt-acpi-build.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/hw/riscv/virt-acpi-build.c b/hw/riscv/virt-acpi-build.c index XXXXXXX..XXXXXXX 100644 --- a/hw/riscv/virt-acpi-build.c +++ b/hw/riscv/virt-acpi-build.c @@ -XXX,XX +XXX,XX @@ static void build_rhct(GArray *table_data, RISCVCPU *cpu = &s->soc[0].harts[0]; uint32_t mmu_offset = 0; uint8_t satp_mode_max; - char *isa; + g_autofree char *isa = NULL; AcpiTable table = { .sig = "RHCT", .rev = 1, .oem_id = s->oem_id, .oem_table_id = s->oem_table_id }; -- 2.43.0
From: Daniel Henrique Barboza <dbarboza@ventanamicro.com> Use g_autofree in 'dist_matrix' to avoid the manual g_free(). Signed-off-by: Daniel Henrique Barboza <dbarboza@ventanamicro.com> Reviewed-by: Alistair Francis <alistair.francis@wdc.com> Message-ID: <20240122221529.86562-3-dbarboza@ventanamicro.com> Signed-off-by: Alistair Francis <alistair.francis@wdc.com> --- hw/riscv/numa.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/hw/riscv/numa.c b/hw/riscv/numa.c index XXXXXXX..XXXXXXX 100644 --- a/hw/riscv/numa.c +++ b/hw/riscv/numa.c @@ -XXX,XX +XXX,XX @@ void riscv_socket_fdt_write_id(const MachineState *ms, const char *node_name, void riscv_socket_fdt_write_distance_matrix(const MachineState *ms) { int i, j, idx; - uint32_t *dist_matrix, dist_matrix_size; + g_autofree uint32_t *dist_matrix = NULL; + uint32_t dist_matrix_size; if (numa_enabled(ms) && ms->numa_state->have_numa_distance) { dist_matrix_size = riscv_socket_count(ms) * riscv_socket_count(ms); @@ -XXX,XX +XXX,XX @@ void riscv_socket_fdt_write_distance_matrix(const MachineState *ms) "numa-distance-map-v1"); qemu_fdt_setprop(ms->fdt, "/distance-map", "distance-matrix", dist_matrix, dist_matrix_size); - g_free(dist_matrix); } } -- 2.43.0
From: Daniel Henrique Barboza <dbarboza@ventanamicro.com> Move all char pointers to the loop. Use g_autofree in all of them to avoid the g_free() calls. Signed-off-by: Daniel Henrique Barboza <dbarboza@ventanamicro.com> Reviewed-by: Alistair Francis <alistair.francis@wdc.com> Reviewed-by: Philippe Mathieu-Daudé <philmd@linaro.org> Message-ID: <20240122221529.86562-4-dbarboza@ventanamicro.com> Signed-off-by: Alistair Francis <alistair.francis@wdc.com> --- hw/riscv/virt.c | 12 +++++------- 1 file changed, 5 insertions(+), 7 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_cpus(RISCVVirtState *s, int socket, int cpu; uint32_t cpu_phandle; MachineState *ms = MACHINE(s); - char *name, *cpu_name, *core_name, *intc_name, *sv_name; bool is_32_bit = riscv_is_32bit(&s->soc[0]); uint8_t satp_mode_max; for (cpu = s->soc[socket].num_harts - 1; cpu >= 0; cpu--) { RISCVCPU *cpu_ptr = &s->soc[socket].harts[cpu]; + g_autofree char *name = NULL; + g_autofree char *cpu_name = NULL; + g_autofree char *core_name = NULL; + g_autofree char *intc_name = NULL; + g_autofree char *sv_name = NULL; cpu_phandle = (*phandle)++; @@ -XXX,XX +XXX,XX @@ static void create_fdt_socket_cpus(RISCVVirtState *s, int socket, sv_name = g_strdup_printf("riscv,%s", satp_mode_str(satp_mode_max, is_32_bit)); qemu_fdt_setprop_string(ms->fdt, cpu_name, "mmu-type", sv_name); - g_free(sv_name); } name = riscv_isa_string(cpu_ptr); qemu_fdt_setprop_string(ms->fdt, cpu_name, "riscv,isa", name); - g_free(name); if (cpu_ptr->cfg.ext_zicbom) { qemu_fdt_setprop_cell(ms->fdt, cpu_name, "riscv,cbom-block-size", @@ -XXX,XX +XXX,XX @@ static void create_fdt_socket_cpus(RISCVVirtState *s, int socket, core_name = g_strdup_printf("%s/core%d", clust_name, cpu); qemu_fdt_add_subnode(ms->fdt, core_name); qemu_fdt_setprop_cell(ms->fdt, core_name, "cpu", cpu_phandle); - - g_free(core_name); - g_free(intc_name); - g_free(cpu_name); } } -- 2.43.0
From: Daniel Henrique Barboza <dbarboza@ventanamicro.com> Move 'clust_name' inside the loop, and g_autofree, to avoid having to g_free() manually in each loop iteration. 'intc_phandles' is also g_autofreed to avoid another manual g_free(). Signed-off-by: Daniel Henrique Barboza <dbarboza@ventanamicro.com> Reviewed-by: Alistair Francis <alistair.francis@wdc.com> Message-ID: <20240122221529.86562-5-dbarboza@ventanamicro.com> Signed-off-by: Alistair Francis <alistair.francis@wdc.com> --- hw/riscv/virt.c | 9 +++------ 1 file changed, 3 insertions(+), 6 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_sockets(RISCVVirtState *s, const MemMapEntry *memmap, uint32_t *irq_virtio_phandle, uint32_t *msi_pcie_phandle) { - char *clust_name; int socket, phandle_pos; MachineState *ms = MACHINE(s); uint32_t msi_m_phandle = 0, msi_s_phandle = 0; - uint32_t *intc_phandles, xplic_phandles[MAX_NODES]; + uint32_t xplic_phandles[MAX_NODES]; + g_autofree uint32_t *intc_phandles = NULL; int socket_count = riscv_socket_count(ms); qemu_fdt_add_subnode(ms->fdt, "/cpus"); @@ -XXX,XX +XXX,XX @@ static void create_fdt_sockets(RISCVVirtState *s, const MemMapEntry *memmap, phandle_pos = ms->smp.cpus; for (socket = (socket_count - 1); socket >= 0; socket--) { + g_autofree char *clust_name = NULL; phandle_pos -= s->soc[socket].num_harts; clust_name = g_strdup_printf("/cpus/cpu-map/cluster%d", socket); @@ -XXX,XX +XXX,XX @@ static void create_fdt_sockets(RISCVVirtState *s, const MemMapEntry *memmap, create_fdt_socket_memory(s, memmap, socket); - g_free(clust_name); - if (tcg_enabled()) { if (s->have_aclint) { create_fdt_socket_aclint(s, memmap, socket, @@ -XXX,XX +XXX,XX @@ static void create_fdt_sockets(RISCVVirtState *s, const MemMapEntry *memmap, } } - g_free(intc_phandles); - if (kvm_enabled() && virt_use_kvm_aia(s)) { *irq_mmio_phandle = xplic_phandles[0]; *irq_virtio_phandle = xplic_phandles[0]; -- 2.43.0
From: Daniel Henrique Barboza <dbarboza@ventanamicro.com> Put 'name' declaration inside the loop, with g_autofree, to avoid manually doing g_free() in each iteration. Signed-off-by: Daniel Henrique Barboza <dbarboza@ventanamicro.com> Reviewed-by: Alistair Francis <alistair.francis@wdc.com> Reviewed-by: Philippe Mathieu-Daudé <philmd@linaro.org> Message-ID: <20240122221529.86562-6-dbarboza@ventanamicro.com> Signed-off-by: Alistair Francis <alistair.francis@wdc.com> --- hw/riscv/virt.c | 5 ++--- 1 file changed, 2 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_virtio(RISCVVirtState *s, const MemMapEntry *memmap, uint32_t irq_virtio_phandle) { int i; - char *name; MachineState *ms = MACHINE(s); for (i = 0; i < VIRTIO_COUNT; i++) { - name = g_strdup_printf("/soc/virtio_mmio@%lx", + g_autofree char *name = g_strdup_printf("/soc/virtio_mmio@%lx", (long)(memmap[VIRT_VIRTIO].base + i * memmap[VIRT_VIRTIO].size)); + 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", @@ -XXX,XX +XXX,XX @@ static void create_fdt_virtio(RISCVVirtState *s, const MemMapEntry *memmap, qemu_fdt_setprop_cells(ms->fdt, name, "interrupts", VIRTIO_IRQ + i, 0x4); } - g_free(name); } } -- 2.43.0
From: Daniel Henrique Barboza <dbarboza@ventanamicro.com> Move 'soc_name' to the loop, and give it g_autofree, to avoid the manual g_free(). Signed-off-by: Daniel Henrique Barboza <dbarboza@ventanamicro.com> Reviewed-by: Alistair Francis <alistair.francis@wdc.com> Reviewed-by: Philippe Mathieu-Daudé <philmd@linaro.org> Message-ID: <20240122221529.86562-7-dbarboza@ventanamicro.com> Signed-off-by: Alistair Francis <alistair.francis@wdc.com> --- hw/riscv/virt.c | 5 ++--- 1 file changed, 2 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 virt_machine_init(MachineState *machine) RISCVVirtState *s = RISCV_VIRT_MACHINE(machine); MemoryRegion *system_memory = get_system_memory(); MemoryRegion *mask_rom = g_new(MemoryRegion, 1); - char *soc_name; DeviceState *mmio_irqchip, *virtio_irqchip, *pcie_irqchip; int i, base_hartid, hart_count; int socket_count = riscv_socket_count(machine); @@ -XXX,XX +XXX,XX @@ static void virt_machine_init(MachineState *machine) /* Initialize sockets */ mmio_irqchip = virtio_irqchip = pcie_irqchip = NULL; for (i = 0; i < socket_count; i++) { + g_autofree char *soc_name = g_strdup_printf("soc%d", i); + if (!riscv_socket_check_hartids(machine, i)) { error_report("discontinuous hartids in socket%d", i); exit(1); @@ -XXX,XX +XXX,XX @@ static void virt_machine_init(MachineState *machine) exit(1); } - soc_name = g_strdup_printf("soc%d", i); object_initialize_child(OBJECT(machine), soc_name, &s->soc[i], TYPE_RISCV_HART_ARRAY); - g_free(soc_name); object_property_set_str(OBJECT(&s->soc[i]), "cpu-type", machine->cpu_type, &error_abort); object_property_set_int(OBJECT(&s->soc[i]), "hartid-base", -- 2.43.0
From: Daniel Henrique Barboza <dbarboza@ventanamicro.com> We have a lot of cases where a char or an uint32_t pointer is used once to alloc a string/array, read/written during the function, and then g_free() at the end. There's no pointer re-use - a single alloc, a single g_free(). Use 'g_autofree' to avoid the g_free() calls. Signed-off-by: Daniel Henrique Barboza <dbarboza@ventanamicro.com> Reviewed-by: Alistair Francis <alistair.francis@wdc.com> Message-ID: <20240122221529.86562-8-dbarboza@ventanamicro.com> Signed-off-by: Alistair Francis <alistair.francis@wdc.com> --- hw/riscv/virt.c | 78 ++++++++++++++----------------------------------- 1 file changed, 22 insertions(+), 56 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_cpus(RISCVVirtState *s, int socket, static void create_fdt_socket_memory(RISCVVirtState *s, const MemMapEntry *memmap, int socket) { - char *mem_name; + g_autofree char *mem_name = NULL; uint64_t addr, size; MachineState *ms = MACHINE(s); @@ -XXX,XX +XXX,XX @@ static void create_fdt_socket_memory(RISCVVirtState *s, addr >> 32, addr, size >> 32, size); qemu_fdt_setprop_string(ms->fdt, mem_name, "device_type", "memory"); riscv_socket_fdt_write_id(ms, mem_name, socket); - g_free(mem_name); } static void create_fdt_socket_clint(RISCVVirtState *s, @@ -XXX,XX +XXX,XX @@ static void create_fdt_socket_clint(RISCVVirtState *s, uint32_t *intc_phandles) { int cpu; - char *clint_name; - uint32_t *clint_cells; + g_autofree char *clint_name = NULL; + g_autofree uint32_t *clint_cells = NULL; unsigned long clint_addr; MachineState *ms = MACHINE(s); static const char * const clint_compat[2] = { @@ -XXX,XX +XXX,XX @@ static void create_fdt_socket_clint(RISCVVirtState *s, 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); - g_free(clint_name); - - g_free(clint_cells); } static void create_fdt_socket_aclint(RISCVVirtState *s, @@ -XXX,XX +XXX,XX @@ static void create_fdt_socket_aclint(RISCVVirtState *s, char *name; unsigned long addr, size; uint32_t aclint_cells_size; - uint32_t *aclint_mswi_cells; - uint32_t *aclint_sswi_cells; - uint32_t *aclint_mtimer_cells; + g_autofree uint32_t *aclint_mswi_cells = NULL; + g_autofree uint32_t *aclint_sswi_cells = NULL; + g_autofree uint32_t *aclint_mtimer_cells = NULL; MachineState *ms = MACHINE(s); aclint_mswi_cells = g_new0(uint32_t, s->soc[socket].num_harts * 2); @@ -XXX,XX +XXX,XX @@ static void create_fdt_socket_aclint(RISCVVirtState *s, riscv_socket_fdt_write_id(ms, name, socket); g_free(name); } - - g_free(aclint_mswi_cells); - g_free(aclint_mtimer_cells); - g_free(aclint_sswi_cells); } static void create_fdt_socket_plic(RISCVVirtState *s, @@ -XXX,XX +XXX,XX @@ static void create_fdt_socket_plic(RISCVVirtState *s, uint32_t *plic_phandles) { int cpu; - char *plic_name; - uint32_t *plic_cells; + g_autofree char *plic_name = NULL; + g_autofree uint32_t *plic_cells; unsigned long plic_addr; MachineState *ms = MACHINE(s); static const char * const plic_compat[2] = { @@ -XXX,XX +XXX,XX @@ static void create_fdt_socket_plic(RISCVVirtState *s, memmap[VIRT_PLATFORM_BUS].size, VIRT_PLATFORM_BUS_IRQ); } - - g_free(plic_name); - - g_free(plic_cells); } uint32_t imsic_num_bits(uint32_t count) @@ -XXX,XX +XXX,XX @@ static void create_fdt_one_imsic(RISCVVirtState *s, hwaddr base_addr, bool m_mode, uint32_t imsic_guest_bits) { int cpu, socket; - char *imsic_name; + g_autofree char *imsic_name = NULL; MachineState *ms = MACHINE(s); int socket_count = riscv_socket_count(ms); - uint32_t imsic_max_hart_per_socket; - uint32_t *imsic_cells, *imsic_regs, imsic_addr, imsic_size; + uint32_t imsic_max_hart_per_socket, imsic_addr, imsic_size; + g_autofree uint32_t *imsic_cells = NULL; + g_autofree uint32_t *imsic_regs = NULL; imsic_cells = g_new0(uint32_t, ms->smp.cpus * 2); imsic_regs = g_new0(uint32_t, socket_count * 4); @@ -XXX,XX +XXX,XX @@ static void create_fdt_one_imsic(RISCVVirtState *s, hwaddr base_addr, IMSIC_MMIO_GROUP_MIN_SHIFT); } qemu_fdt_setprop_cell(ms->fdt, imsic_name, "phandle", msi_phandle); - - g_free(imsic_name); - g_free(imsic_regs); - g_free(imsic_cells); } static void create_fdt_imsic(RISCVVirtState *s, const MemMapEntry *memmap, @@ -XXX,XX +XXX,XX @@ static void create_fdt_one_aplic(RISCVVirtState *s, int socket, bool m_mode, int num_harts) { int cpu; - char *aplic_name; - uint32_t *aplic_cells; + g_autofree char *aplic_name = NULL; + g_autofree uint32_t *aplic_cells = g_new0(uint32_t, num_harts * 2); MachineState *ms = MACHINE(s); - aplic_cells = g_new0(uint32_t, num_harts * 2); - for (cpu = 0; cpu < num_harts; cpu++) { aplic_cells[cpu * 2 + 0] = cpu_to_be32(intc_phandles[cpu]); aplic_cells[cpu * 2 + 1] = cpu_to_be32(m_mode ? IRQ_M_EXT : IRQ_S_EXT); @@ -XXX,XX +XXX,XX @@ static void create_fdt_one_aplic(RISCVVirtState *s, int socket, riscv_socket_fdt_write_id(ms, aplic_name, socket); qemu_fdt_setprop_cell(ms->fdt, aplic_name, "phandle", aplic_phandle); - - g_free(aplic_name); - g_free(aplic_cells); } static void create_fdt_socket_aplic(RISCVVirtState *s, @@ -XXX,XX +XXX,XX @@ static void create_fdt_socket_aplic(RISCVVirtState *s, uint32_t *aplic_phandles, int num_harts) { - char *aplic_name; + g_autofree char *aplic_name = NULL; unsigned long aplic_addr; MachineState *ms = MACHINE(s); uint32_t aplic_m_phandle, aplic_s_phandle; @@ -XXX,XX +XXX,XX @@ static void create_fdt_socket_aplic(RISCVVirtState *s, VIRT_PLATFORM_BUS_IRQ); } - g_free(aplic_name); - aplic_phandles[socket] = aplic_s_phandle; } static void create_fdt_pmu(RISCVVirtState *s) { - char *pmu_name; + g_autofree char *pmu_name = g_strdup_printf("/pmu"); MachineState *ms = MACHINE(s); RISCVCPU hart = s->soc[0].harts[0]; - pmu_name = g_strdup_printf("/pmu"); qemu_fdt_add_subnode(ms->fdt, pmu_name); qemu_fdt_setprop_string(ms->fdt, pmu_name, "compatible", "riscv,pmu"); riscv_pmu_generate_fdt_node(ms->fdt, hart.pmu_avail_ctrs, pmu_name); - - g_free(pmu_name); } static void create_fdt_sockets(RISCVVirtState *s, const MemMapEntry *memmap, @@ -XXX,XX +XXX,XX @@ static void create_fdt_pcie(RISCVVirtState *s, const MemMapEntry *memmap, uint32_t irq_pcie_phandle, uint32_t msi_pcie_phandle) { - char *name; + g_autofree char *name = NULL; MachineState *ms = MACHINE(s); name = g_strdup_printf("/soc/pci@%lx", @@ -XXX,XX +XXX,XX @@ static void create_fdt_pcie(RISCVVirtState *s, const MemMapEntry *memmap, 2, virt_high_pcie_memmap.base, 2, virt_high_pcie_memmap.size); create_pcie_irq_map(s, ms->fdt, name, irq_pcie_phandle); - g_free(name); } static void create_fdt_reset(RISCVVirtState *s, const MemMapEntry *memmap, @@ -XXX,XX +XXX,XX @@ static void create_fdt_reset(RISCVVirtState *s, const MemMapEntry *memmap, static void create_fdt_uart(RISCVVirtState *s, const MemMapEntry *memmap, uint32_t irq_mmio_phandle) { - char *name; + g_autofree char *name = NULL; MachineState *ms = MACHINE(s); name = g_strdup_printf("/soc/serial@%lx", (long)memmap[VIRT_UART0].base); @@ -XXX,XX +XXX,XX @@ static void create_fdt_uart(RISCVVirtState *s, const MemMapEntry *memmap, } qemu_fdt_setprop_string(ms->fdt, "/chosen", "stdout-path", name); - g_free(name); } static void create_fdt_rtc(RISCVVirtState *s, const MemMapEntry *memmap, uint32_t irq_mmio_phandle) { - char *name; + g_autofree char *name = NULL; MachineState *ms = MACHINE(s); name = g_strdup_printf("/soc/rtc@%lx", (long)memmap[VIRT_RTC].base); @@ -XXX,XX +XXX,XX @@ static void create_fdt_rtc(RISCVVirtState *s, const MemMapEntry *memmap, } else { qemu_fdt_setprop_cells(ms->fdt, name, "interrupts", RTC_IRQ, 0x4); } - g_free(name); } static void create_fdt_flash(RISCVVirtState *s, const MemMapEntry *memmap) { - char *name; MachineState *ms = MACHINE(s); hwaddr flashsize = virt_memmap[VIRT_FLASH].size / 2; hwaddr flashbase = virt_memmap[VIRT_FLASH].base; + g_autofree char *name = g_strdup_printf("/flash@%" PRIx64, flashbase); - name = g_strdup_printf("/flash@%" PRIx64, flashbase); qemu_fdt_add_subnode(ms->fdt, name); qemu_fdt_setprop_string(ms->fdt, name, "compatible", "cfi-flash"); qemu_fdt_setprop_sized_cells(ms->fdt, name, "reg", 2, flashbase, 2, flashsize, 2, flashbase + flashsize, 2, flashsize); qemu_fdt_setprop_cell(ms->fdt, name, "bank-width", 4); - g_free(name); } static void create_fdt_fw_cfg(RISCVVirtState *s, const MemMapEntry *memmap) { - char *nodename; MachineState *ms = MACHINE(s); hwaddr base = memmap[VIRT_FW_CFG].base; hwaddr size = memmap[VIRT_FW_CFG].size; + g_autofree char *nodename = g_strdup_printf("/fw-cfg@%" PRIx64, base); - nodename = g_strdup_printf("/fw-cfg@%" PRIx64, base); qemu_fdt_add_subnode(ms->fdt, nodename); qemu_fdt_setprop_string(ms->fdt, nodename, "compatible", "qemu,fw-cfg-mmio"); qemu_fdt_setprop_sized_cells(ms->fdt, nodename, "reg", 2, base, 2, size); qemu_fdt_setprop(ms->fdt, nodename, "dma-coherent", NULL, 0); - g_free(nodename); } static void finalize_fdt(RISCVVirtState *s) @@ -XXX,XX +XXX,XX @@ static DeviceState *virt_create_plic(const MemMapEntry *memmap, int socket, int base_hartid, int hart_count) { DeviceState *ret; - char *plic_hart_config; + g_autofree char *plic_hart_config = NULL; /* Per-socket PLIC hart topology configuration string */ plic_hart_config = riscv_plic_hart_config_string(hart_count); @@ -XXX,XX +XXX,XX @@ static DeviceState *virt_create_plic(const MemMapEntry *memmap, int socket, VIRT_PLIC_CONTEXT_STRIDE, memmap[VIRT_PLIC].size); - g_free(plic_hart_config); - return ret; } -- 2.43.0
From: Rob Bradford <rbradford@rivosinc.com> These extensions represent the atomic operations from A (Zaamo) and the Load-Reserved/Store-Conditional operations from A (Zalrsc) Signed-off-by: Rob Bradford <rbradford@rivosinc.com> Reviewed-by: Daniel Henrique Barboza <dbarboza@ventanamicro.com> Message-ID: <20240123111030.15074-2-rbradford@rivosinc.com> Signed-off-by: Alistair Francis <alistair.francis@wdc.com> --- target/riscv/cpu_cfg.h | 2 ++ 1 file changed, 2 insertions(+) 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 @@ struct RISCVCPUConfig { bool ext_svnapot; bool ext_svpbmt; bool ext_zdinx; + bool ext_zaamo; bool ext_zacas; + bool ext_zalrsc; bool ext_zawrs; bool ext_zfa; bool ext_zfbfmin; -- 2.43.0
From: Rob Bradford <rbradford@rivosinc.com> Following the pattern for 'M' and Zmmul check if either the 'A' extension is enabled or the appropriate split extension for the instruction. Signed-off-by: Rob Bradford <rbradford@rivosinc.com> Reviewed-by: Daniel Henrique Barboza <dbarboza@ventanamicro.com> Message-ID: <20240123111030.15074-3-rbradford@rivosinc.com> Signed-off-by: Alistair Francis <alistair.francis@wdc.com> --- target/riscv/insn_trans/trans_rva.c.inc | 56 +++++++++++++++---------- 1 file changed, 34 insertions(+), 22 deletions(-) diff --git a/target/riscv/insn_trans/trans_rva.c.inc b/target/riscv/insn_trans/trans_rva.c.inc index XXXXXXX..XXXXXXX 100644 --- a/target/riscv/insn_trans/trans_rva.c.inc +++ b/target/riscv/insn_trans/trans_rva.c.inc @@ -XXX,XX +XXX,XX @@ * this program. If not, see <http://www.gnu.org/licenses/>. */ +#define REQUIRE_A_OR_ZAAMO(ctx) do { \ + if (!ctx->cfg_ptr->ext_zaamo && !has_ext(ctx, RVA)) { \ + return false; \ + } \ +} while (0) + +#define REQUIRE_A_OR_ZALRSC(ctx) do { \ + if (!ctx->cfg_ptr->ext_zalrsc && !has_ext(ctx, RVA)) { \ + return false; \ + } \ +} while (0) + static bool gen_lr(DisasContext *ctx, arg_atomic *a, MemOp mop) { TCGv src1; @@ -XXX,XX +XXX,XX @@ static bool gen_amo(DisasContext *ctx, arg_atomic *a, static bool trans_lr_w(DisasContext *ctx, arg_lr_w *a) { - REQUIRE_EXT(ctx, RVA); + REQUIRE_A_OR_ZALRSC(ctx); return gen_lr(ctx, a, (MO_ALIGN | MO_TESL)); } static bool trans_sc_w(DisasContext *ctx, arg_sc_w *a) { - REQUIRE_EXT(ctx, RVA); + REQUIRE_A_OR_ZALRSC(ctx); return gen_sc(ctx, a, (MO_ALIGN | MO_TESL)); } static bool trans_amoswap_w(DisasContext *ctx, arg_amoswap_w *a) { - REQUIRE_EXT(ctx, RVA); + REQUIRE_A_OR_ZAAMO(ctx); return gen_amo(ctx, a, &tcg_gen_atomic_xchg_tl, (MO_ALIGN | MO_TESL)); } static bool trans_amoadd_w(DisasContext *ctx, arg_amoadd_w *a) { - REQUIRE_EXT(ctx, RVA); + REQUIRE_A_OR_ZAAMO(ctx); return gen_amo(ctx, a, &tcg_gen_atomic_fetch_add_tl, (MO_ALIGN | MO_TESL)); } static bool trans_amoxor_w(DisasContext *ctx, arg_amoxor_w *a) { - REQUIRE_EXT(ctx, RVA); + REQUIRE_A_OR_ZAAMO(ctx); return gen_amo(ctx, a, &tcg_gen_atomic_fetch_xor_tl, (MO_ALIGN | MO_TESL)); } static bool trans_amoand_w(DisasContext *ctx, arg_amoand_w *a) { - REQUIRE_EXT(ctx, RVA); + REQUIRE_A_OR_ZAAMO(ctx); return gen_amo(ctx, a, &tcg_gen_atomic_fetch_and_tl, (MO_ALIGN | MO_TESL)); } static bool trans_amoor_w(DisasContext *ctx, arg_amoor_w *a) { - REQUIRE_EXT(ctx, RVA); + REQUIRE_A_OR_ZAAMO(ctx); return gen_amo(ctx, a, &tcg_gen_atomic_fetch_or_tl, (MO_ALIGN | MO_TESL)); } static bool trans_amomin_w(DisasContext *ctx, arg_amomin_w *a) { - REQUIRE_EXT(ctx, RVA); + REQUIRE_A_OR_ZAAMO(ctx); return gen_amo(ctx, a, &tcg_gen_atomic_fetch_smin_tl, (MO_ALIGN | MO_TESL)); } static bool trans_amomax_w(DisasContext *ctx, arg_amomax_w *a) { - REQUIRE_EXT(ctx, RVA); + REQUIRE_A_OR_ZAAMO(ctx); return gen_amo(ctx, a, &tcg_gen_atomic_fetch_smax_tl, (MO_ALIGN | MO_TESL)); } static bool trans_amominu_w(DisasContext *ctx, arg_amominu_w *a) { - REQUIRE_EXT(ctx, RVA); + REQUIRE_A_OR_ZAAMO(ctx); return gen_amo(ctx, a, &tcg_gen_atomic_fetch_umin_tl, (MO_ALIGN | MO_TESL)); } static bool trans_amomaxu_w(DisasContext *ctx, arg_amomaxu_w *a) { - REQUIRE_EXT(ctx, RVA); + REQUIRE_A_OR_ZAAMO(ctx); return gen_amo(ctx, a, &tcg_gen_atomic_fetch_umax_tl, (MO_ALIGN | MO_TESL)); } static bool trans_lr_d(DisasContext *ctx, arg_lr_d *a) { REQUIRE_64BIT(ctx); - REQUIRE_EXT(ctx, RVA); + REQUIRE_A_OR_ZALRSC(ctx); return gen_lr(ctx, a, MO_ALIGN | MO_TEUQ); } static bool trans_sc_d(DisasContext *ctx, arg_sc_d *a) { REQUIRE_64BIT(ctx); - REQUIRE_EXT(ctx, RVA); + REQUIRE_A_OR_ZALRSC(ctx); return gen_sc(ctx, a, (MO_ALIGN | MO_TEUQ)); } static bool trans_amoswap_d(DisasContext *ctx, arg_amoswap_d *a) { REQUIRE_64BIT(ctx); - REQUIRE_EXT(ctx, RVA); + REQUIRE_A_OR_ZAAMO(ctx); return gen_amo(ctx, a, &tcg_gen_atomic_xchg_tl, (MO_ALIGN | MO_TEUQ)); } static bool trans_amoadd_d(DisasContext *ctx, arg_amoadd_d *a) { REQUIRE_64BIT(ctx); - REQUIRE_EXT(ctx, RVA); + REQUIRE_A_OR_ZAAMO(ctx); return gen_amo(ctx, a, &tcg_gen_atomic_fetch_add_tl, (MO_ALIGN | MO_TEUQ)); } static bool trans_amoxor_d(DisasContext *ctx, arg_amoxor_d *a) { REQUIRE_64BIT(ctx); - REQUIRE_EXT(ctx, RVA); + REQUIRE_A_OR_ZAAMO(ctx); return gen_amo(ctx, a, &tcg_gen_atomic_fetch_xor_tl, (MO_ALIGN | MO_TEUQ)); } static bool trans_amoand_d(DisasContext *ctx, arg_amoand_d *a) { REQUIRE_64BIT(ctx); - REQUIRE_EXT(ctx, RVA); + REQUIRE_A_OR_ZAAMO(ctx); return gen_amo(ctx, a, &tcg_gen_atomic_fetch_and_tl, (MO_ALIGN | MO_TEUQ)); } static bool trans_amoor_d(DisasContext *ctx, arg_amoor_d *a) { REQUIRE_64BIT(ctx); - REQUIRE_EXT(ctx, RVA); + REQUIRE_A_OR_ZAAMO(ctx); return gen_amo(ctx, a, &tcg_gen_atomic_fetch_or_tl, (MO_ALIGN | MO_TEUQ)); } static bool trans_amomin_d(DisasContext *ctx, arg_amomin_d *a) { REQUIRE_64BIT(ctx); - REQUIRE_EXT(ctx, RVA); + REQUIRE_A_OR_ZAAMO(ctx); return gen_amo(ctx, a, &tcg_gen_atomic_fetch_smin_tl, (MO_ALIGN | MO_TEUQ)); } static bool trans_amomax_d(DisasContext *ctx, arg_amomax_d *a) { REQUIRE_64BIT(ctx); - REQUIRE_EXT(ctx, RVA); + REQUIRE_A_OR_ZAAMO(ctx); return gen_amo(ctx, a, &tcg_gen_atomic_fetch_smax_tl, (MO_ALIGN | MO_TEUQ)); } static bool trans_amominu_d(DisasContext *ctx, arg_amominu_d *a) { REQUIRE_64BIT(ctx); - REQUIRE_EXT(ctx, RVA); + REQUIRE_A_OR_ZAAMO(ctx); return gen_amo(ctx, a, &tcg_gen_atomic_fetch_umin_tl, (MO_ALIGN | MO_TEUQ)); } static bool trans_amomaxu_d(DisasContext *ctx, arg_amomaxu_d *a) { REQUIRE_64BIT(ctx); - REQUIRE_EXT(ctx, RVA); + REQUIRE_A_OR_ZAAMO(ctx); return gen_amo(ctx, a, &tcg_gen_atomic_fetch_umax_tl, (MO_ALIGN | MO_TEUQ)); } -- 2.43.0
From: Rob Bradford <rbradford@rivosinc.com> Expose the newly added extensions to the guest and allow their control through the CPU properties. Signed-off-by: Rob Bradford <rbradford@rivosinc.com> Reviewed-by: Daniel Henrique Barboza <dbarboza@ventanamicro.com> Message-ID: <20240123111030.15074-4-rbradford@rivosinc.com> Signed-off-by: Alistair Francis <alistair.francis@wdc.com> --- target/riscv/cpu.c | 5 +++++ 1 file changed, 5 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(zihintpause, PRIV_VERSION_1_10_0, ext_zihintpause), ISA_EXT_DATA_ENTRY(zihpm, PRIV_VERSION_1_12_0, ext_zihpm), ISA_EXT_DATA_ENTRY(zmmul, PRIV_VERSION_1_12_0, ext_zmmul), + ISA_EXT_DATA_ENTRY(zaamo, PRIV_VERSION_1_12_0, ext_zaamo), ISA_EXT_DATA_ENTRY(zacas, PRIV_VERSION_1_12_0, ext_zacas), + ISA_EXT_DATA_ENTRY(zalrsc, PRIV_VERSION_1_12_0, ext_zalrsc), 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), @@ -XXX,XX +XXX,XX @@ const RISCVCPUMultiExtConfig riscv_cpu_experimental_exts[] = { MULTI_EXT_CFG_BOOL("x-smaia", ext_smaia, false), MULTI_EXT_CFG_BOOL("x-ssaia", ext_ssaia, false), + MULTI_EXT_CFG_BOOL("x-zaamo", ext_zaamo, false), + MULTI_EXT_CFG_BOOL("x-zalrsc", ext_zalrsc, false), + MULTI_EXT_CFG_BOOL("x-zvfh", ext_zvfh, false), MULTI_EXT_CFG_BOOL("x-zvfhmin", ext_zvfhmin, false), -- 2.43.0
From: Conor Dooley <conor.dooley@microchip.com> A cpu may not have the same xlen as the compile time target, and misa_mxl_max is the source of truth for what the hart supports. The conversion from misa_mxl_max to xlen already has one user, so introduce a helper and use that to populate the isa string. Link: https://lore.kernel.org/qemu-riscv/20240108-efa3f83dcd3997dc0af458d7@orel/ Signed-off-by: Conor Dooley <conor.dooley@microchip.com> Reviewed-by: Andrew Jones <ajones@ventanamicro.com> Reviewed-by: Daniel Henrique Barboza <dbarboza@ventanamicro.com> Message-ID: <20240124-swear-monthly-56c281f809a6@spud> [ Changes by AF: - Convert to use RISCVCPUClass *mcc ] Signed-off-by: Alistair Francis <alistair.francis@wdc.com> --- target/riscv/cpu.h | 1 + target/riscv/cpu.c | 10 +++++++++- target/riscv/gdbstub.c | 2 +- 3 files changed, 11 insertions(+), 2 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_tlb_fill(CPUState *cs, vaddr address, int size, MMUAccessType access_type, int mmu_idx, bool probe, uintptr_t retaddr); char *riscv_isa_string(RISCVCPU *cpu); +int riscv_cpu_max_xlen(RISCVCPUClass *mcc); bool riscv_cpu_option_set(const char *optname); #ifndef CONFIG_USER_ONLY 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 @@ void riscv_cpu_set_misa_ext(CPURISCVState *env, uint32_t ext) env->misa_ext_mask = env->misa_ext = ext; } +int riscv_cpu_max_xlen(RISCVCPUClass *mcc) +{ + return 16 << mcc->misa_mxl_max; +} + #ifndef CONFIG_USER_ONLY static uint8_t satp_mode_from_str(const char *satp_mode_str) { @@ -XXX,XX +XXX,XX @@ static void riscv_isa_string_ext(RISCVCPU *cpu, char **isa_str, char *riscv_isa_string(RISCVCPU *cpu) { + RISCVCPUClass *mcc = RISCV_CPU_GET_CLASS(cpu); int i; const size_t maxlen = sizeof("rv128") + sizeof(riscv_single_letter_exts); char *isa_str = g_new(char, maxlen); - char *p = isa_str + snprintf(isa_str, maxlen, "rv%d", TARGET_LONG_BITS); + int xlen = riscv_cpu_max_xlen(mcc); + char *p = isa_str + snprintf(isa_str, maxlen, "rv%d", xlen); + for (i = 0; i < sizeof(riscv_single_letter_exts) - 1; i++) { if (cpu->env.misa_ext & RV(riscv_single_letter_exts[i])) { *p++ = qemu_tolower(riscv_single_letter_exts[i]); diff --git a/target/riscv/gdbstub.c b/target/riscv/gdbstub.c index XXXXXXX..XXXXXXX 100644 --- a/target/riscv/gdbstub.c +++ b/target/riscv/gdbstub.c @@ -XXX,XX +XXX,XX @@ static int riscv_gen_dynamic_csr_xml(CPUState *cs, int base_reg) CPURISCVState *env = &cpu->env; GString *s = g_string_new(NULL); riscv_csr_predicate_fn predicate; - int bitsize = 16 << mcc->misa_mxl_max; + int bitsize = riscv_cpu_max_xlen(mcc); int i; #if !defined(CONFIG_USER_ONLY) -- 2.43.0
From: Conor Dooley <conor.dooley@microchip.com> A few months ago I submitted a patch to various lists, deprecating "riscv,isa" with a lengthy commit message [0] that is now commit aeb71e42caae ("dt-bindings: riscv: deprecate riscv,isa") in the Linux kernel tree. Primarily, the goal was to replace "riscv,isa" with a new set of properties that allowed for strictly defining the meaning of various extensions, where "riscv,isa" was tied to whatever definitions inflicted upon us by the ISA manual, which have seen some variance over time. Two new properties were introduced: "riscv,isa-base" and "riscv,isa-extensions". The former is a simple string to communicate the base ISA implemented by a hart and the latter an array of strings used to communicate the set of ISA extensions supported, per the definitions of each substring in extensions.yaml [1]. A beneficial side effect was also the ability to define vendor extensions in a more "official" way, as the ISA manual and other RVI specifications only covered the format for vendor extensions in the ISA string, but not the meaning of vendor extensions, for obvious reasons. Add support for setting these two new properties in the devicetrees for the various devicetree platforms supported by QEMU for RISC-V. The Linux kernel already supports parsing ISA extensions from these new properties, and documenting them in the dt-binding is a requirement for new extension detection being added to the kernel. A side effect of the implementation is that the meaning for elements in "riscv,isa" and in "riscv,isa-extensions" are now tied together as they are constructed from the same source. The same applies to the ISA string provided in ACPI tables, but there does not appear to be any strict definitions of meanings in ACPI land either. Link: https://lore.kernel.org/qemu-riscv/20230702-eats-scorebook-c951f170d29f@spud/ [0] Link: https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/tree/Documentation/devicetree/bindings/riscv/extensions.yaml [1] Reviewed-by: Alistair Francis <alistair.francis@wdc.com> Reviewed-by: Andrew Jones <ajones@ventanamicro.com> Signed-off-by: Conor Dooley <conor.dooley@microchip.com> Reviewed-by: Daniel Henrique Barboza <dbarboza@ventanamicro.com> Message-ID: <20240124-unvarying-foothold-9dde2aaf95d4@spud> [ Changes by AF: - Rebase on recent changes ] Signed-off-by: Alistair Francis <alistair.francis@wdc.com> --- target/riscv/cpu.h | 1 + hw/riscv/sifive_u.c | 7 ++---- hw/riscv/spike.c | 6 ++--- hw/riscv/virt.c | 4 +--- target/riscv/cpu.c | 54 +++++++++++++++++++++++++++++++++++++++++++++ 5 files changed, 60 insertions(+), 12 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 @@ int riscv_cpu_max_xlen(RISCVCPUClass *mcc); bool riscv_cpu_option_set(const char *optname); #ifndef CONFIG_USER_ONLY +void riscv_isa_write_fdt(RISCVCPU *cpu, void *fdt, char *nodename); void riscv_cpu_do_transaction_failed(CPUState *cs, hwaddr physaddr, vaddr addr, unsigned size, MMUAccessType access_type, diff --git a/hw/riscv/sifive_u.c b/hw/riscv/sifive_u.c index XXXXXXX..XXXXXXX 100644 --- a/hw/riscv/sifive_u.c +++ b/hw/riscv/sifive_u.c @@ -XXX,XX +XXX,XX @@ static void create_fdt(SiFiveUState *s, const MemMapEntry *memmap, int cpu_phandle = phandle++; nodename = g_strdup_printf("/cpus/cpu@%d", cpu); char *intc = g_strdup_printf("/cpus/cpu@%d/interrupt-controller", cpu); - char *isa; qemu_fdt_add_subnode(fdt, nodename); /* cpu 0 is the management hart that does not have mmu */ if (cpu != 0) { @@ -XXX,XX +XXX,XX @@ static void create_fdt(SiFiveUState *s, const MemMapEntry *memmap, } else { qemu_fdt_setprop_string(fdt, nodename, "mmu-type", "riscv,sv48"); } - isa = riscv_isa_string(&s->soc.u_cpus.harts[cpu - 1]); + riscv_isa_write_fdt(&s->soc.u_cpus.harts[cpu - 1], fdt, nodename); } else { - isa = riscv_isa_string(&s->soc.e_cpus.harts[0]); + riscv_isa_write_fdt(&s->soc.e_cpus.harts[0], fdt, nodename); } - qemu_fdt_setprop_string(fdt, nodename, "riscv,isa", isa); qemu_fdt_setprop_string(fdt, nodename, "compatible", "riscv"); qemu_fdt_setprop_string(fdt, nodename, "status", "okay"); qemu_fdt_setprop_cell(fdt, nodename, "reg", cpu); @@ -XXX,XX +XXX,XX @@ static void create_fdt(SiFiveUState *s, const MemMapEntry *memmap, qemu_fdt_setprop_string(fdt, intc, "compatible", "riscv,cpu-intc"); qemu_fdt_setprop(fdt, intc, "interrupt-controller", NULL, 0); qemu_fdt_setprop_cell(fdt, intc, "#interrupt-cells", 1); - g_free(isa); g_free(intc); g_free(nodename); } diff --git a/hw/riscv/spike.c b/hw/riscv/spike.c index XXXXXXX..XXXXXXX 100644 --- a/hw/riscv/spike.c +++ b/hw/riscv/spike.c @@ -XXX,XX +XXX,XX @@ static void create_fdt(SpikeState *s, const MemMapEntry *memmap, MachineState *ms = MACHINE(s); uint32_t *clint_cells; uint32_t cpu_phandle, intc_phandle, phandle = 1; - char *name, *mem_name, *clint_name, *clust_name; + char *mem_name, *clint_name, *clust_name; char *core_name, *cpu_name, *intc_name; static const char * const clint_compat[2] = { "sifive,clint0", "riscv,clint0" @@ -XXX,XX +XXX,XX @@ static void create_fdt(SpikeState *s, const MemMapEntry *memmap, } else { qemu_fdt_setprop_string(fdt, cpu_name, "mmu-type", "riscv,sv48"); } - name = riscv_isa_string(&s->soc[socket].harts[cpu]); - qemu_fdt_setprop_string(fdt, cpu_name, "riscv,isa", name); - g_free(name); + riscv_isa_write_fdt(&s->soc[socket].harts[cpu], fdt, cpu_name); qemu_fdt_setprop_string(fdt, cpu_name, "compatible", "riscv"); qemu_fdt_setprop_string(fdt, cpu_name, "status", "okay"); qemu_fdt_setprop_cell(fdt, cpu_name, "reg", 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_cpus(RISCVVirtState *s, int socket, for (cpu = s->soc[socket].num_harts - 1; cpu >= 0; cpu--) { RISCVCPU *cpu_ptr = &s->soc[socket].harts[cpu]; - g_autofree char *name = NULL; g_autofree char *cpu_name = NULL; g_autofree char *core_name = NULL; g_autofree char *intc_name = NULL; @@ -XXX,XX +XXX,XX @@ static void create_fdt_socket_cpus(RISCVVirtState *s, int socket, qemu_fdt_setprop_string(ms->fdt, cpu_name, "mmu-type", sv_name); } - name = riscv_isa_string(cpu_ptr); - qemu_fdt_setprop_string(ms->fdt, cpu_name, "riscv,isa", name); + riscv_isa_write_fdt(cpu_ptr, ms->fdt, cpu_name); if (cpu_ptr->cfg.ext_zicbom) { qemu_fdt_setprop_cell(ms->fdt, cpu_name, "riscv,cbom-block-size", 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 @@ #include "hw/core/qdev-prop-internal.h" #include "migration/vmstate.h" #include "fpu/softfloat-helpers.h" +#include "sysemu/device_tree.h" #include "sysemu/kvm.h" #include "sysemu/tcg.h" #include "kvm/kvm_riscv.h" @@ -XXX,XX +XXX,XX @@ char *riscv_isa_string(RISCVCPU *cpu) return isa_str; } +#ifndef CONFIG_USER_ONLY +static char **riscv_isa_extensions_list(RISCVCPU *cpu, int *count) +{ + int maxlen = ARRAY_SIZE(riscv_single_letter_exts) + ARRAY_SIZE(isa_edata_arr); + char **extensions = g_new(char *, maxlen); + + for (int i = 0; i < sizeof(riscv_single_letter_exts) - 1; i++) { + if (cpu->env.misa_ext & RV(riscv_single_letter_exts[i])) { + extensions[*count] = g_new(char, 2); + snprintf(extensions[*count], 2, "%c", + qemu_tolower(riscv_single_letter_exts[i])); + (*count)++; + } + } + + for (const RISCVIsaExtData *edata = isa_edata_arr; edata->name; edata++) { + if (isa_ext_is_enabled(cpu, edata->ext_enable_offset)) { + extensions[*count] = g_strdup(edata->name); + (*count)++; + } + } + + return extensions; +} + +void riscv_isa_write_fdt(RISCVCPU *cpu, void *fdt, char *nodename) +{ + RISCVCPUClass *mcc = RISCV_CPU_GET_CLASS(cpu); + const size_t maxlen = sizeof("rv128i"); + g_autofree char *isa_base = g_new(char, maxlen); + g_autofree char *riscv_isa; + char **isa_extensions; + int count = 0; + int xlen = riscv_cpu_max_xlen(mcc); + + riscv_isa = riscv_isa_string(cpu); + qemu_fdt_setprop_string(fdt, nodename, "riscv,isa", riscv_isa); + + snprintf(isa_base, maxlen, "rv%di", xlen); + qemu_fdt_setprop_string(fdt, nodename, "riscv,isa-base", isa_base); + + isa_extensions = riscv_isa_extensions_list(cpu, &count); + qemu_fdt_setprop_string_array(fdt, nodename, "riscv,isa-extensions", + isa_extensions, count); + + for (int i = 0; i < count; i++) { + g_free(isa_extensions[i]); + } + + g_free(isa_extensions); +} +#endif + #define DEFINE_CPU(type_name, misa_mxl_max, initfn) \ { \ .name = (type_name), \ -- 2.43.0
From: Heinrich Schuchardt <heinrich.schuchardt@canonical.com> For RISC-V the SMBIOS standard requires specific values of the processor family value depending on the bitness of the CPU. Add a processor-family option for SMBIOS table 4. The value of processor-family may exceed 255 and therefore must be provided in the Processor Family 2 field. Set the Processor Family field to 0xFE which signals that the Processor Family 2 is used. Signed-off-by: Heinrich Schuchardt <heinrich.schuchardt@canonical.com> Reviewed-by: Alistair Francis <alistair.francis@wdc.com> Reviewed-by: Andrew Jones <ajones@ventanamicro.com> Message-ID: <20240123184229.10415-2-heinrich.schuchardt@canonical.com> Signed-off-by: Alistair Francis <alistair.francis@wdc.com> --- hw/smbios/smbios.c | 13 +++++++++++-- qemu-options.hx | 4 ++-- 2 files changed, 13 insertions(+), 4 deletions(-) diff --git a/hw/smbios/smbios.c b/hw/smbios/smbios.c index XXXXXXX..XXXXXXX 100644 --- a/hw/smbios/smbios.c +++ b/hw/smbios/smbios.c @@ -XXX,XX +XXX,XX @@ static struct { #define DEFAULT_CPU_SPEED 2000 static struct { + uint16_t processor_family; const char *sock_pfx, *manufacturer, *version, *serial, *asset, *part; uint64_t max_speed; uint64_t current_speed; @@ -XXX,XX +XXX,XX @@ static struct { .max_speed = DEFAULT_CPU_SPEED, .current_speed = DEFAULT_CPU_SPEED, .processor_id = 0, + .processor_family = 0x01, /* Other */ }; struct type8_instance { @@ -XXX,XX +XXX,XX @@ static const QemuOptDesc qemu_smbios_type4_opts[] = { .name = "part", .type = QEMU_OPT_STRING, .help = "part number", + }, { + .name = "processor-family", + .type = QEMU_OPT_NUMBER, + .help = "processor family", }, { .name = "processor-id", .type = QEMU_OPT_NUMBER, @@ -XXX,XX +XXX,XX @@ static void smbios_build_type_4_table(MachineState *ms, unsigned instance) snprintf(sock_str, sizeof(sock_str), "%s%2x", type4.sock_pfx, instance); SMBIOS_TABLE_SET_STR(4, socket_designation_str, sock_str); t->processor_type = 0x03; /* CPU */ - t->processor_family = 0x01; /* Other */ + t->processor_family = 0xfe; /* use Processor Family 2 field */ SMBIOS_TABLE_SET_STR(4, processor_manufacturer_str, type4.manufacturer); if (type4.processor_id == 0) { t->processor_id[0] = cpu_to_le32(smbios_cpuid_version); @@ -XXX,XX +XXX,XX @@ static void smbios_build_type_4_table(MachineState *ms, unsigned instance) t->thread_count = (threads_per_socket > 255) ? 0xFF : threads_per_socket; t->processor_characteristics = cpu_to_le16(0x02); /* Unknown */ - t->processor_family2 = cpu_to_le16(0x01); /* Other */ + t->processor_family2 = cpu_to_le16(type4.processor_family); if (tbl_len == SMBIOS_TYPE_4_LEN_V30) { t->core_count2 = t->core_enabled2 = cpu_to_le16(cores_per_socket); @@ -XXX,XX +XXX,XX @@ void smbios_entry_add(QemuOpts *opts, Error **errp) return; } save_opt(&type4.sock_pfx, opts, "sock_pfx"); + type4.processor_family = qemu_opt_get_number(opts, + "processor-family", + 0x01 /* Other */); save_opt(&type4.manufacturer, opts, "manufacturer"); save_opt(&type4.version, opts, "version"); save_opt(&type4.serial, opts, "serial"); diff --git a/qemu-options.hx b/qemu-options.hx index XXXXXXX..XXXXXXX 100644 --- a/qemu-options.hx +++ b/qemu-options.hx @@ -XXX,XX +XXX,XX @@ DEF("smbios", HAS_ARG, QEMU_OPTION_smbios, " specify SMBIOS type 3 fields\n" "-smbios type=4[,sock_pfx=str][,manufacturer=str][,version=str][,serial=str]\n" " [,asset=str][,part=str][,max-speed=%d][,current-speed=%d]\n" - " [,processor-id=%d]\n" + " [,processor-family=%d,processor-id=%d]\n" " specify SMBIOS type 4 fields\n" "-smbios type=8[,external_reference=str][,internal_reference=str][,connector_type=%d][,port_type=%d]\n" " specify SMBIOS type 8 fields\n" @@ -XXX,XX +XXX,XX @@ SRST ``-smbios type=3[,manufacturer=str][,version=str][,serial=str][,asset=str][,sku=str]`` Specify SMBIOS type 3 fields -``-smbios type=4[,sock_pfx=str][,manufacturer=str][,version=str][,serial=str][,asset=str][,part=str][,processor-id=%d]`` +``-smbios type=4[,sock_pfx=str][,manufacturer=str][,version=str][,serial=str][,asset=str][,part=str][,processor-family=%d][,processor-id=%d]`` Specify SMBIOS type 4 fields ``-smbios type=11[,value=str][,path=filename]`` -- 2.43.0
From: Heinrich Schuchardt <heinrich.schuchardt@canonical.com> Provide a function to set the default processor family. Signed-off-by: Heinrich Schuchardt <heinrich.schuchardt@canonical.com> Reviewed-by: Andrew Jones <ajones@ventanamicro.com> Message-ID: <20240123184229.10415-3-heinrich.schuchardt@canonical.com> Signed-off-by: Alistair Francis <alistair.francis@wdc.com> --- include/hw/firmware/smbios.h | 1 + hw/smbios/smbios.c | 7 +++++++ 2 files changed, 8 insertions(+) diff --git a/include/hw/firmware/smbios.h b/include/hw/firmware/smbios.h index XXXXXXX..XXXXXXX 100644 --- a/include/hw/firmware/smbios.h +++ b/include/hw/firmware/smbios.h @@ -XXX,XX +XXX,XX @@ void smbios_set_cpuid(uint32_t version, uint32_t features); void smbios_set_defaults(const char *manufacturer, const char *product, const char *version, bool legacy_mode, bool uuid_encoded, SmbiosEntryPointType ep_type); +void smbios_set_default_processor_family(uint16_t processor_family); uint8_t *smbios_get_table_legacy(MachineState *ms, size_t *length); void smbios_get_tables(MachineState *ms, const struct smbios_phys_mem_area *mem_array, diff --git a/hw/smbios/smbios.c b/hw/smbios/smbios.c index XXXXXXX..XXXXXXX 100644 --- a/hw/smbios/smbios.c +++ b/hw/smbios/smbios.c @@ -XXX,XX +XXX,XX @@ void smbios_set_cpuid(uint32_t version, uint32_t features) field = value; \ } +void smbios_set_default_processor_family(uint16_t processor_family) +{ + if (type4.processor_family <= 0x01) { + type4.processor_family = processor_family; + } +} + void smbios_set_defaults(const char *manufacturer, const char *product, const char *version, bool legacy_mode, bool uuid_encoded, SmbiosEntryPointType ep_type) -- 2.43.0
From: Heinrich Schuchardt <heinrich.schuchardt@canonical.com> Generate SMBIOS tables for the RISC-V mach-virt. Add CONFIG_SMBIOS=y to the RISC-V default config. Set the default processor family in the type 4 table. The implementation is based on the corresponding ARM and Loongson code. With the patch the following firmware tables are provided: etc/smbios/smbios-anchor etc/smbios/smbios-tables Signed-off-by: Heinrich Schuchardt <heinrich.schuchardt@canonical.com> Reviewed-by: Andrew Jones <ajones@ventanamicro.com> Message-ID: <20240123184229.10415-4-heinrich.schuchardt@canonical.com> Signed-off-by: Alistair Francis <alistair.francis@wdc.com> --- hw/riscv/virt.c | 42 ++++++++++++++++++++++++++++++++++++++++++ hw/riscv/Kconfig | 1 + 2 files changed, 43 insertions(+) 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 @@ #include "hw/riscv/boot.h" #include "hw/riscv/numa.h" #include "kvm/kvm_riscv.h" +#include "hw/firmware/smbios.h" #include "hw/intc/riscv_aclint.h" #include "hw/intc/riscv_aplic.h" #include "hw/intc/sifive_plic.h" @@ -XXX,XX +XXX,XX @@ static void create_platform_bus(RISCVVirtState *s, DeviceState *irqchip) sysbus_mmio_get_region(sysbus, 0)); } +static void virt_build_smbios(RISCVVirtState *s) +{ + MachineClass *mc = MACHINE_GET_CLASS(s); + MachineState *ms = MACHINE(s); + uint8_t *smbios_tables, *smbios_anchor; + size_t smbios_tables_len, smbios_anchor_len; + struct smbios_phys_mem_area mem_array; + const char *product = "QEMU Virtual Machine"; + + if (kvm_enabled()) { + product = "KVM Virtual Machine"; + } + + smbios_set_defaults("QEMU", product, mc->name, false, + true, SMBIOS_ENTRY_POINT_TYPE_64); + + if (riscv_is_32bit(&s->soc[0])) { + smbios_set_default_processor_family(0x200); + } else { + smbios_set_default_processor_family(0x201); + } + + /* build the array of physical mem area from base_memmap */ + mem_array.address = s->memmap[VIRT_DRAM].base; + mem_array.length = ms->ram_size; + + smbios_get_tables(ms, &mem_array, 1, + &smbios_tables, &smbios_tables_len, + &smbios_anchor, &smbios_anchor_len, + &error_fatal); + + if (smbios_anchor) { + fw_cfg_add_file(s->fw_cfg, "etc/smbios/smbios-tables", + smbios_tables, smbios_tables_len); + fw_cfg_add_file(s->fw_cfg, "etc/smbios/smbios-anchor", + smbios_anchor, smbios_anchor_len); + } +} + static void virt_machine_done(Notifier *notifier, void *data) { RISCVVirtState *s = container_of(notifier, RISCVVirtState, @@ -XXX,XX +XXX,XX @@ static void virt_machine_done(Notifier *notifier, void *data) riscv_setup_direct_kernel(kernel_entry, fdt_load_addr); } + virt_build_smbios(s); + if (virt_is_acpi_enabled(s)) { virt_acpi_setup(s); } 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 RISCV_VIRT select RISCV_IMSIC select SIFIVE_PLIC select SIFIVE_TEST + select SMBIOS select VIRTIO_MMIO select FW_CFG_DMA select PLATFORM_BUS -- 2.43.0
From: Heinrich Schuchardt <heinrich.schuchardt@canonical.com> With SMBIOS support added for RISC-V we also should enable the command line option. Signed-off-by: Heinrich Schuchardt <heinrich.schuchardt@canonical.com> Reviewed-by: Daniel Henrique Barboza <dbarboza@ventanamicro.com> Acked-by: Alistair Francis <alistair.francis@wdc.com> Reviewed-by: Andrew Jones <ajones@ventanamicro.com> Message-ID: <20240123184229.10415-5-heinrich.schuchardt@canonical.com> Signed-off-by: Alistair Francis <alistair.francis@wdc.com> --- qemu-options.hx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/qemu-options.hx b/qemu-options.hx index XXXXXXX..XXXXXXX 100644 --- a/qemu-options.hx +++ b/qemu-options.hx @@ -XXX,XX +XXX,XX @@ DEF("smbios", HAS_ARG, QEMU_OPTION_smbios, " specify SMBIOS type 17 fields\n" "-smbios type=41[,designation=str][,kind=str][,instance=%d][,pcidev=str]\n" " specify SMBIOS type 41 fields\n", - QEMU_ARCH_I386 | QEMU_ARCH_ARM | QEMU_ARCH_LOONGARCH) + QEMU_ARCH_I386 | QEMU_ARCH_ARM | QEMU_ARCH_LOONGARCH | QEMU_ARCH_RISCV) SRST ``-smbios file=binary`` Load SMBIOS entry from binary file. -- 2.43.0
From: LIU Zhiwei <zhiwei_liu@linux.alibaba.com> According to xtheadsync[1][2] documentation, it can be used in user mode and the behavior is same with other priviledges. [1]:https://github.com/T-head-Semi/thead-extension-spec/blob/master/xtheadsync/sync.adoc [2]:https://github.com/T-head-Semi/thead-extension-spec/blob/master/xtheadsync/sync_i.adoc Signed-off-by: LIU Zhiwei <zhiwei_liu@linux.alibaba.com> Acked-by: Alistair Francis <alistair.francis@wdc.com> Message-ID: <20240204055228.900-1-zhiwei_liu@linux.alibaba.com> Signed-off-by: Alistair Francis <alistair.francis@wdc.com> --- target/riscv/insn_trans/trans_xthead.c.inc | 10 ---------- 1 file changed, 10 deletions(-) diff --git a/target/riscv/insn_trans/trans_xthead.c.inc b/target/riscv/insn_trans/trans_xthead.c.inc index XXXXXXX..XXXXXXX 100644 --- a/target/riscv/insn_trans/trans_xthead.c.inc +++ b/target/riscv/insn_trans/trans_xthead.c.inc @@ -XXX,XX +XXX,XX @@ static bool trans_th_sfence_vmas(DisasContext *ctx, arg_th_sfence_vmas *a) #endif } -#ifndef CONFIG_USER_ONLY static void gen_th_sync_local(DisasContext *ctx) { /* @@ -XXX,XX +XXX,XX @@ static void gen_th_sync_local(DisasContext *ctx) tcg_gen_exit_tb(NULL, 0); ctx->base.is_jmp = DISAS_NORETURN; } -#endif static bool trans_th_sync(DisasContext *ctx, arg_th_sync *a) { (void) a; REQUIRE_XTHEADSYNC(ctx); -#ifndef CONFIG_USER_ONLY REQUIRE_PRIV_MSU(ctx); /* @@ -XXX,XX +XXX,XX @@ static bool trans_th_sync(DisasContext *ctx, arg_th_sync *a) gen_th_sync_local(ctx); return true; -#else - return false; -#endif } static bool trans_th_sync_i(DisasContext *ctx, arg_th_sync_i *a) @@ -XXX,XX +XXX,XX @@ static bool trans_th_sync_i(DisasContext *ctx, arg_th_sync_i *a) (void) a; REQUIRE_XTHEADSYNC(ctx); -#ifndef CONFIG_USER_ONLY REQUIRE_PRIV_MSU(ctx); /* @@ -XXX,XX +XXX,XX @@ static bool trans_th_sync_i(DisasContext *ctx, arg_th_sync_i *a) gen_th_sync_local(ctx); return true; -#else - return false; -#endif } static bool trans_th_sync_is(DisasContext *ctx, arg_th_sync_is *a) -- 2.43.0
From: Daniel Henrique Barboza <dbarboza@ventanamicro.com> Next patch will add more bare CPUs. Their cpu_init() functions would be glorified copy/pastes of rv64i_bare_cpu_init(), differing only by a riscv_cpu_set_misa() call. Add a new .instance_init for the TYPE_RISCV_BARE_CPU typ to avoid this code repetition. While we're at it, add a better explanation on why we're disabling the timing extensions for bare CPUs. Signed-off-by: Daniel Henrique Barboza <dbarboza@ventanamicro.com> Reviewed-by: Alistair Francis <alistair.francis@wdc.com> Message-ID: <20240122123348.973288-2-dbarboza@ventanamicro.com> [ Changes by AF: - Rebase on latest changes ] Signed-off-by: Alistair Francis <alistair.francis@wdc.com> --- target/riscv/cpu.c | 45 +++++++++++++++++++++++++++++---------------- 1 file changed, 29 insertions(+), 16 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 @@ static void rv64i_bare_cpu_init(Object *obj) { CPURISCVState *env = &RISCV_CPU(obj)->env; riscv_cpu_set_misa_ext(env, RVI); - - /* Remove the defaults from the parent class */ - RISCV_CPU(obj)->cfg.ext_zicntr = false; - RISCV_CPU(obj)->cfg.ext_zihpm = false; - - /* Set to QEMU's first supported priv version */ - env->priv_ver = PRIV_VERSION_1_10_0; - - /* - * Support all available satp_mode settings. The default - * value will be set to MBARE if the user doesn't set - * satp_mode manually (see set_satp_mode_default()). - */ -#ifndef CONFIG_USER_ONLY - set_satp_mode_max_supported(RISCV_CPU(obj), VM_1_10_SV64); -#endif } #else static void rv32_base_cpu_init(Object *obj) @@ -XXX,XX +XXX,XX @@ static void riscv_cpu_init(Object *obj) cpu->env.vext_ver = VEXT_VERSION_1_00_0; } +static void riscv_bare_cpu_init(Object *obj) +{ + RISCVCPU *cpu = RISCV_CPU(obj); + + /* + * Bare CPUs do not inherit the timer and performance + * counters from the parent class (see riscv_cpu_init() + * for info on why the parent enables them). + * + * Users have to explicitly enable these counters for + * bare CPUs. + */ + cpu->cfg.ext_zicntr = false; + cpu->cfg.ext_zihpm = false; + + /* Set to QEMU's first supported priv version */ + cpu->env.priv_ver = PRIV_VERSION_1_10_0; + + /* + * Support all available satp_mode settings. The default + * value will be set to MBARE if the user doesn't set + * satp_mode manually (see set_satp_mode_default()). + */ +#ifndef CONFIG_USER_ONLY + set_satp_mode_max_supported(cpu, VM_1_10_SV64); +#endif +} + typedef struct misa_ext_info { const char *name; const char *description; @@ -XXX,XX +XXX,XX @@ static const TypeInfo riscv_cpu_type_infos[] = { { .name = TYPE_RISCV_BARE_CPU, .parent = TYPE_RISCV_CPU, + .instance_init = riscv_bare_cpu_init, .abstract = true, }, #if defined(TARGET_RISCV32) -- 2.43.0
From: Daniel Henrique Barboza <dbarboza@ventanamicro.com> A bare bones 32 bit RVI CPU, rv32i, will make users lives easier when a full customized 32 bit CPU is desired, and users won't need to disable defaults by hand as they would with the rv32 CPU. [1] has an example of a situation that would be avoided with rv32i. In fact, add bare bones CPUs for RVE as well. Trying to use RVE in QEMU requires one to disable every single default extension, including RVI, and then add the desirable extension set. Adding rv32e/rv64e makes it more pleasant to use embedded CPUs in QEMU. [1] https://lore.kernel.org/qemu-riscv/258be47f-97be-4308-bed5-dc34ef7ff954@Spark/ Signed-off-by: Daniel Henrique Barboza <dbarboza@ventanamicro.com> Reviewed-by: Alistair Francis <alistair.francis@wdc.com> Message-ID: <20240122123348.973288-3-dbarboza@ventanamicro.com> [ Changes by AF: - Rebase on latest changes ] Signed-off-by: Alistair Francis <alistair.francis@wdc.com> --- target/riscv/cpu-qom.h | 3 +++ target/riscv/cpu.c | 21 +++++++++++++++++++++ 2 files changed, 24 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_BASE32 RISCV_CPU_TYPE_NAME("rv32") #define TYPE_RISCV_CPU_BASE64 RISCV_CPU_TYPE_NAME("rv64") #define TYPE_RISCV_CPU_BASE128 RISCV_CPU_TYPE_NAME("x-rv128") +#define TYPE_RISCV_CPU_RV32I RISCV_CPU_TYPE_NAME("rv32i") +#define TYPE_RISCV_CPU_RV32E RISCV_CPU_TYPE_NAME("rv32e") #define TYPE_RISCV_CPU_RV64I RISCV_CPU_TYPE_NAME("rv64i") +#define TYPE_RISCV_CPU_RV64E RISCV_CPU_TYPE_NAME("rv64e") #define TYPE_RISCV_CPU_RVA22U64 RISCV_CPU_TYPE_NAME("rva22u64") #define TYPE_RISCV_CPU_RVA22S64 RISCV_CPU_TYPE_NAME("rva22s64") #define TYPE_RISCV_CPU_IBEX RISCV_CPU_TYPE_NAME("lowrisc-ibex") 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 rv64i_bare_cpu_init(Object *obj) CPURISCVState *env = &RISCV_CPU(obj)->env; riscv_cpu_set_misa_ext(env, RVI); } + +static void rv64e_bare_cpu_init(Object *obj) +{ + CPURISCVState *env = &RISCV_CPU(obj)->env; + riscv_cpu_set_misa_ext(env, RVE); +} #else static void rv32_base_cpu_init(Object *obj) { @@ -XXX,XX +XXX,XX @@ static void rv32_imafcu_nommu_cpu_init(Object *obj) cpu->cfg.ext_zicsr = true; cpu->cfg.pmp = true; } + +static void rv32i_bare_cpu_init(Object *obj) +{ + CPURISCVState *env = &RISCV_CPU(obj)->env; + riscv_cpu_set_misa_ext(env, RVI); +} + +static void rv32e_bare_cpu_init(Object *obj) +{ + CPURISCVState *env = &RISCV_CPU(obj)->env; + riscv_cpu_set_misa_ext(env, RVE); +} #endif static ObjectClass *riscv_cpu_class_by_name(const char *cpu_model) @@ -XXX,XX +XXX,XX @@ static const TypeInfo riscv_cpu_type_infos[] = { DEFINE_VENDOR_CPU(TYPE_RISCV_CPU_SIFIVE_E31, MXL_RV32, rv32_sifive_e_cpu_init), DEFINE_VENDOR_CPU(TYPE_RISCV_CPU_SIFIVE_E34, MXL_RV32, rv32_imafcu_nommu_cpu_init), DEFINE_VENDOR_CPU(TYPE_RISCV_CPU_SIFIVE_U34, MXL_RV32, rv32_sifive_u_cpu_init), + DEFINE_BARE_CPU(TYPE_RISCV_CPU_RV32I, MXL_RV32, rv32i_bare_cpu_init), + DEFINE_BARE_CPU(TYPE_RISCV_CPU_RV32E, MXL_RV32, rv32e_bare_cpu_init), #elif defined(TARGET_RISCV64) DEFINE_DYNAMIC_CPU(TYPE_RISCV_CPU_ANY, MXL_RV64, riscv_any_cpu_init), DEFINE_DYNAMIC_CPU(TYPE_RISCV_CPU_MAX, MXL_RV64, riscv_max_cpu_init), @@ -XXX,XX +XXX,XX @@ static const TypeInfo riscv_cpu_type_infos[] = { DEFINE_VENDOR_CPU(TYPE_RISCV_CPU_VEYRON_V1, MXL_RV64, rv64_veyron_v1_cpu_init), DEFINE_DYNAMIC_CPU(TYPE_RISCV_CPU_BASE128, MXL_RV128, rv128_base_cpu_init), DEFINE_BARE_CPU(TYPE_RISCV_CPU_RV64I, MXL_RV64, rv64i_bare_cpu_init), + DEFINE_BARE_CPU(TYPE_RISCV_CPU_RV64E, MXL_RV64, rv64e_bare_cpu_init), DEFINE_PROFILE_CPU(TYPE_RISCV_CPU_RVA22U64, MXL_RV64, rva22u64_profile_cpu_init), DEFINE_PROFILE_CPU(TYPE_RISCV_CPU_RVA22S64, MXL_RV64, rva22s64_profile_cpu_init), #endif -- 2.43.0