:p
atchew
Login
From: Alistair Francis <alistair.francis@wdc.com> The following changes since commit 3b5fe75e2c30e249acabe29924385782014c7632: Merge tag 'pull-monitor-2026-01-07' of https://repo.or.cz/qemu/armbru into staging (2026-01-08 17:45:15 +1100) are available in the Git repository at: https://github.com/alistair23/qemu.git tags/pull-riscv-to-apply-20260109 for you to fetch changes up to e71111e26bdf5e98243d6a896c9e595e205dd9bb: test/functional: Add test for boston-aia board (2026-01-09 15:14:58 +1000) ---------------------------------------------------------------- First RISC-V PR for 11. * Remove unused import statement from sifive_u test * Free allocated memory in core/loader * Add all available CSRs to 'info registers' * Add 'riscv-aia' accel prop info to documentation * Fix IOMMU MemoryRegion owner * Make riscv cpu.h target partially independent * Expand AIA target[i] source handling and refactor related code * Don't look up DDT cache in Off and Bare modes * Add Zilsd and Zclsd extension support * Add RISCV ZALASR extension * Add support for MIPS P8700 CPU ---------------------------------------------------------------- Akihiko Odaki (1): hw/riscv/riscv-iommu: Fix MemoryRegion owner Alistair Francis (4): hw/core/loader: Fixup whitespace for get_image_size() hw/core/loader: Free the image file descriptor on error hw/core/loader: Free the allocated string from size_to_str() target/riscv: Remove upper_half from riscv_pmu_ctr_get_fixed_counters_val Anton Johansson (7): target/riscv: Fix size of trivial CPUArchState fields target/riscv: Fix size of mhartid target/riscv: Bugfix make bit 62 read-only 0 for sireg* cfg CSR read target/riscv: Combine mhpmevent and mhpmeventh target/riscv: Combine mcyclecfg and mcyclecfgh target/riscv: Combine minstretcfg and minstretcfgh target/riscv: Combine mhpmcounter and mhpmcounterh Daniel Henrique Barboza (4): target/riscv/cpu: add riscv_dump_csr() helper target/riscv/cpu: print all FPU CSRs in riscv_cpu_dump_state() target/riscv: print all available CSRs in riscv_cpu_dump_state() docs/specs/riscv-aia.rst: add 'riscv-aia' accel prop info Djordje Todorovic (12): target/riscv: Add cpu_set_exception_base target/riscv: Add MIPS P8700 CPU target/riscv: Add MIPS P8700 CSRs target/riscv: Add mips.ccmov instruction target/riscv: Add mips.pref instruction target/riscv: Add Xmipslsp instructions hw/misc: Add RISC-V CMGCR device implementation hw/misc: Add RISC-V CPC device implementation hw/riscv: Add support for RISCV CPS hw/riscv: Add support for MIPS Boston-aia board mode riscv/boston-aia: Add an e1000e NIC in slot 0 func 1 test/functional: Add test for boston-aia board Frank Chang (1): hw/riscv: riscv-iommu: Don't look up DDT cache in Off and Bare modes Nikita Novikov (2): hw/intc/riscv_aplic: Expand inactive source handling for AIA target[i] hw/intc/riscv_aplic: Factor out source_active() and remove duplicate checks Roan Richmond (1): Add RISCV ZALASR extension Thomas Huth (1): tests/functional/riscv64/test_sifive_u: Remove unused import statement lxx (1): target/riscv: Add Zilsd and Zclsd extension support docs/specs/riscv-aia.rst | 43 ++- docs/system/riscv/mips.rst | 20 ++ docs/system/target-riscv.rst | 1 + configs/devices/riscv64-softmmu/default.mak | 1 + include/hw/misc/riscv_cmgcr.h | 48 +++ include/hw/misc/riscv_cpc.h | 64 ++++ include/hw/riscv/cps.h | 66 ++++ target/riscv/cpu-qom.h | 1 + target/riscv/cpu.h | 115 +++---- target/riscv/cpu_cfg.h | 5 + target/riscv/cpu_vendorid.h | 1 + target/riscv/cpu_cfg_fields.h.inc | 6 + target/riscv/insn16.decode | 8 + target/riscv/insn32.decode | 22 +- target/riscv/xmips.decode | 35 ++ hw/core/loader.c | 15 +- hw/intc/riscv_aplic.c | 66 ++-- hw/misc/riscv_cmgcr.c | 243 ++++++++++++++ hw/misc/riscv_cpc.c | 265 +++++++++++++++ hw/riscv/boston-aia.c | 476 +++++++++++++++++++++++++++ hw/riscv/cps.c | 196 +++++++++++ hw/riscv/riscv-iommu.c | 15 +- target/riscv/cpu.c | 157 +++++---- target/riscv/cpu_helper.c | 2 +- target/riscv/csr.c | 239 +++++++------- target/riscv/machine.c | 99 +++--- target/riscv/mips_csr.c | 217 ++++++++++++ target/riscv/pmu.c | 150 ++------- target/riscv/tcg/tcg-cpu.c | 35 +- target/riscv/translate.c | 5 + target/riscv/insn_trans/trans_rvzalasr.c.inc | 113 +++++++ target/riscv/insn_trans/trans_xmips.c.inc | 136 ++++++++ target/riscv/insn_trans/trans_zilsd.c.inc | 105 ++++++ hw/misc/Kconfig | 17 + hw/misc/meson.build | 3 + hw/riscv/Kconfig | 6 + hw/riscv/meson.build | 3 + target/riscv/meson.build | 2 + tests/functional/riscv64/meson.build | 2 + tests/functional/riscv64/test_boston.py | 123 +++++++ tests/functional/riscv64/test_sifive_u.py | 1 - 41 files changed, 2657 insertions(+), 470 deletions(-) create mode 100644 docs/system/riscv/mips.rst create mode 100644 include/hw/misc/riscv_cmgcr.h create mode 100644 include/hw/misc/riscv_cpc.h create mode 100644 include/hw/riscv/cps.h create mode 100644 target/riscv/xmips.decode create mode 100644 hw/misc/riscv_cmgcr.c create mode 100644 hw/misc/riscv_cpc.c create mode 100644 hw/riscv/boston-aia.c create mode 100644 hw/riscv/cps.c create mode 100644 target/riscv/mips_csr.c create mode 100644 target/riscv/insn_trans/trans_rvzalasr.c.inc create mode 100644 target/riscv/insn_trans/trans_xmips.c.inc create mode 100644 target/riscv/insn_trans/trans_zilsd.c.inc create mode 100755 tests/functional/riscv64/test_boston.py
From: Thomas Huth <thuth@redhat.com> skipIfMissingCommands is not used here, remove the import to silence a pylint warning for this file. Signed-off-by: Thomas Huth <thuth@redhat.com> Reviewed-by: Alistair Francis <alistair.francis@wdc.com> Reviewed-by: Daniel Henrique Barboza <dbarboza@ventanamicro.com> Reviewed-by: Nutty Liu <nutty.liu@hotmail.com> Reviewed-by: Philippe Mathieu-Daudé <philmd@linaro.org> Message-ID: <20251027112803.54564-1-thuth@redhat.com> Signed-off-by: Alistair Francis <alistair.francis@wdc.com> --- tests/functional/riscv64/test_sifive_u.py | 1 - 1 file changed, 1 deletion(-) diff --git a/tests/functional/riscv64/test_sifive_u.py b/tests/functional/riscv64/test_sifive_u.py index XXXXXXX..XXXXXXX 100755 --- a/tests/functional/riscv64/test_sifive_u.py +++ b/tests/functional/riscv64/test_sifive_u.py @@ -XXX,XX +XXX,XX @@ import os from qemu_test import Asset, LinuxKernelTest -from qemu_test import skipIfMissingCommands class SifiveU(LinuxKernelTest): -- 2.52.0
From: Alistair Francis <alistair.francis@wdc.com> Signed-off-by: Alistair Francis <alistair.francis@wdc.com> Reviewed-by:Vishal Chourasia <vishalc@linux.ibm.com> Reviewed-by: Philippe Mathieu-Daudé <philmd@linaro.org> Message-ID: <20251030015306.2279148-1-alistair.francis@wdc.com> Signed-off-by: Alistair Francis <alistair.francis@wdc.com> --- hw/core/loader.c | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/hw/core/loader.c b/hw/core/loader.c index XXXXXXX..XXXXXXX 100644 --- a/hw/core/loader.c +++ b/hw/core/loader.c @@ -XXX,XX +XXX,XX @@ int64_t get_image_size(const char *filename, Error **errp) { int fd; int64_t size; + fd = qemu_open(filename, O_RDONLY | O_BINARY, errp); - if (fd < 0) + + if (fd < 0) { return -1; + } + size = lseek(fd, 0, SEEK_END); + if (size < 0) { error_setg_errno(errp, errno, "lseek failure: %s", filename); return -1; } + close(fd); return size; } -- 2.52.0
From: Alistair Francis <alistair.francis@wdc.com> Coverity: CID 1642764 Fixes: f62226f7dc4 ("hw/core/loader: improve error handling in image loading functions") Signed-off-by: Alistair Francis <alistair.francis@wdc.com> Reviewed-by: Philippe Mathieu-Daudé <philmd@linaro.org> Reviewed-by: Vishal Chourasia <vishalc@linux.ibm.com> Message-ID: <20251030015306.2279148-2-alistair.francis@wdc.com> Signed-off-by: Alistair Francis <alistair.francis@wdc.com> --- hw/core/loader.c | 1 + 1 file changed, 1 insertion(+) diff --git a/hw/core/loader.c b/hw/core/loader.c index XXXXXXX..XXXXXXX 100644 --- a/hw/core/loader.c +++ b/hw/core/loader.c @@ -XXX,XX +XXX,XX @@ int64_t get_image_size(const char *filename, Error **errp) if (size < 0) { error_setg_errno(errp, errno, "lseek failure: %s", filename); + close(fd); return -1; } -- 2.52.0
From: Alistair Francis <alistair.francis@wdc.com> The string needs be be freed with g_free() according to the functions documentation. Coverity: CID 1642762 Fixes: f62226f7dc44 ("hw/core/loader: improve error handling in image loading functions") Signed-off-by: Alistair Francis <alistair.francis@wdc.com> Reviewed-by: Philippe Mathieu-Daudé <philmd@linaro.org> Message-ID: <20251030015306.2279148-3-alistair.francis@wdc.com> Signed-off-by: Alistair Francis <alistair.francis@wdc.com> --- hw/core/loader.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/hw/core/loader.c b/hw/core/loader.c index XXXXXXX..XXXXXXX 100644 --- a/hw/core/loader.c +++ b/hw/core/loader.c @@ -XXX,XX +XXX,XX @@ ssize_t load_image_targphys_as(const char *filename, } if (size > max_sz) { + char *size_str = size_to_str(max_sz); + error_setg(errp, "%s exceeds maximum image size (%s)", - filename, size_to_str(max_sz)); + filename, size_str); + + g_free(size_str); return -1; } -- 2.52.0
From: Daniel Henrique Barboza <dbarboza@ventanamicro.com> riscv_cpu_dump_state() is using the same pattern to print a CSR given its number. Add a helper to avoid code repetition. While we're at it fix the identation of the 'flags & CPU_DUMP_VPU' block. Signed-off-by: Daniel Henrique Barboza <dbarboza@ventanamicro.com> Reviewed-by: Alistair Francis <alistair.francis@wdc.com> Message-ID: <20250623172119.997166-2-dbarboza@ventanamicro.com> Signed-off-by: Alistair Francis <alistair.francis@wdc.com> --- target/riscv/cpu.c | 54 +++++++++++++++++++--------------------------- 1 file changed, 22 insertions(+), 32 deletions(-) diff --git a/target/riscv/cpu.c b/target/riscv/cpu.c index XXXXXXX..XXXXXXX 100644 --- a/target/riscv/cpu.c +++ b/target/riscv/cpu.c @@ -XXX,XX +XXX,XX @@ char *riscv_cpu_get_name(RISCVCPU *cpu) return cpu_model_from_type(typename); } +static void riscv_dump_csr(CPURISCVState *env, int csrno, FILE *f) +{ + target_ulong val = 0; + RISCVException res = riscv_csrrw_debug(env, csrno, &val, 0, 0); + + /* + * Rely on the smode, hmode, etc, predicates within csr.c + * to do the filtering of the registers that are present. + */ + if (res == RISCV_EXCP_NONE) { + qemu_fprintf(f, " %-8s " TARGET_FMT_lx "\n", + csr_ops[csrno].name, val); + } +} + static void riscv_cpu_dump_state(CPUState *cs, FILE *f, int flags) { RISCVCPU *cpu = RISCV_CPU(cs); @@ -XXX,XX +XXX,XX @@ static void riscv_cpu_dump_state(CPUState *cs, FILE *f, int flags) }; for (i = 0; i < ARRAY_SIZE(dump_csrs); ++i) { - int csrno = dump_csrs[i]; - target_ulong val = 0; - RISCVException res = riscv_csrrw_debug(env, csrno, &val, 0, 0); - - /* - * Rely on the smode, hmode, etc, predicates within csr.c - * to do the filtering of the registers that are present. - */ - if (res == RISCV_EXCP_NONE) { - qemu_fprintf(f, " %-8s " TARGET_FMT_lx "\n", - csr_ops[csrno].name, val); - } + riscv_dump_csr(env, dump_csrs[i], f); } } #endif @@ -XXX,XX +XXX,XX @@ static void riscv_cpu_dump_state(CPUState *cs, FILE *f, int flags) } } if (flags & CPU_DUMP_FPU) { - target_ulong val = 0; - RISCVException res = riscv_csrrw_debug(env, CSR_FCSR, &val, 0, 0); - if (res == RISCV_EXCP_NONE) { - qemu_fprintf(f, " %-8s " TARGET_FMT_lx "\n", - csr_ops[CSR_FCSR].name, val); - } + riscv_dump_csr(env, CSR_FCSR, f); + for (i = 0; i < 32; i++) { qemu_fprintf(f, " %-8s %016" PRIx64, riscv_fpr_regnames[i], env->fpr[i]); @@ -XXX,XX +XXX,XX @@ static void riscv_cpu_dump_state(CPUState *cs, FILE *f, int flags) CSR_VL, CSR_VTYPE, CSR_VLENB, - }; - for (i = 0; i < ARRAY_SIZE(dump_rvv_csrs); ++i) { - int csrno = dump_rvv_csrs[i]; - target_ulong val = 0; - RISCVException res = riscv_csrrw_debug(env, csrno, &val, 0, 0); + }; + uint16_t vlenb = cpu->cfg.vlenb; - /* - * Rely on the smode, hmode, etc, predicates within csr.c - * to do the filtering of the registers that are present. - */ - if (res == RISCV_EXCP_NONE) { - qemu_fprintf(f, " %-8s " TARGET_FMT_lx "\n", - csr_ops[csrno].name, val); - } + for (i = 0; i < ARRAY_SIZE(dump_rvv_csrs); ++i) { + riscv_dump_csr(env, dump_rvv_csrs[i], f); } - uint16_t vlenb = cpu->cfg.vlenb; for (i = 0; i < 32; i++) { qemu_fprintf(f, " %-8s ", riscv_rvv_regnames[i]); -- 2.52.0
From: Daniel Henrique Barboza <dbarboza@ventanamicro.com> We're missing fflags and frm. Signed-off-by: Daniel Henrique Barboza <dbarboza@ventanamicro.com> Reviewed-by: Alistair Francis <alistair.francis@wdc.com> Message-ID: <20250623172119.997166-3-dbarboza@ventanamicro.com> Signed-off-by: Alistair Francis <alistair.francis@wdc.com> --- target/riscv/cpu.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/target/riscv/cpu.c b/target/riscv/cpu.c index XXXXXXX..XXXXXXX 100644 --- a/target/riscv/cpu.c +++ b/target/riscv/cpu.c @@ -XXX,XX +XXX,XX @@ static void riscv_cpu_dump_state(CPUState *cs, FILE *f, int flags) } } if (flags & CPU_DUMP_FPU) { + riscv_dump_csr(env, CSR_FFLAGS, f); + riscv_dump_csr(env, CSR_FRM, f); riscv_dump_csr(env, CSR_FCSR, f); for (i = 0; i < 32; i++) { -- 2.52.0
From: Daniel Henrique Barboza <dbarboza@ventanamicro.com> At this moment we're printing a small selection of CSRs. There's no particular reason to not print all of them. We're ignoring the note about CSR_SSTATUS being ommited because it can be read via CSR_MSTATUS. There's a huge list of CSRs that would fall in this category and it would be an extra burden to manage them, not mentioning having to document "we're not listing X because it's the same value as Y" to users. Remove 'dump_csrs' and use the existing 'csr_ops' array to print all available CSRs. Create two helpers in csr.c to identify FPU and VPU CSRs and skip them - they'll be printed in the FPU/VPU blocks later. Signed-off-by: Daniel Henrique Barboza <dbarboza@ventanamicro.com> Reviewed-by: Alistair Francis <alistair.francis@wdc.com> Message-ID: <20250623172119.997166-4-dbarboza@ventanamicro.com> Signed-off-by: Alistair Francis <alistair.francis@wdc.com> --- target/riscv/cpu.h | 2 ++ target/riscv/cpu.c | 55 ++++++++++++++++------------------------------ target/riscv/csr.c | 18 +++++++++++++++ 3 files changed, 39 insertions(+), 36 deletions(-) diff --git a/target/riscv/cpu.h b/target/riscv/cpu.h index XXXXXXX..XXXXXXX 100644 --- a/target/riscv/cpu.h +++ b/target/riscv/cpu.h @@ -XXX,XX +XXX,XX @@ bool riscv_cpu_accelerator_compatible(RISCVCPU *cpu); /* CSR function table */ extern riscv_csr_operations csr_ops[CSR_TABLE_SIZE]; +bool riscv_csr_is_fpu(int csrno); +bool riscv_csr_is_vpu(int csrno); extern const bool valid_vm_1_10_32[], valid_vm_1_10_64[]; diff --git a/target/riscv/cpu.c b/target/riscv/cpu.c index XXXXXXX..XXXXXXX 100644 --- a/target/riscv/cpu.c +++ b/target/riscv/cpu.c @@ -XXX,XX +XXX,XX @@ static void riscv_cpu_dump_state(CPUState *cs, FILE *f, int flags) #endif qemu_fprintf(f, " %s " TARGET_FMT_lx "\n", "pc ", env->pc); #ifndef CONFIG_USER_ONLY - { - static const int dump_csrs[] = { - CSR_MHARTID, - CSR_MSTATUS, - CSR_MSTATUSH, - /* - * CSR_SSTATUS is intentionally omitted here as its value - * can be figured out by looking at CSR_MSTATUS - */ - CSR_HSTATUS, - CSR_VSSTATUS, - CSR_MIP, - CSR_MIE, - CSR_MIDELEG, - CSR_HIDELEG, - CSR_MEDELEG, - CSR_HEDELEG, - CSR_MTVEC, - CSR_STVEC, - CSR_VSTVEC, - CSR_MEPC, - CSR_SEPC, - CSR_VSEPC, - CSR_MCAUSE, - CSR_SCAUSE, - CSR_VSCAUSE, - CSR_MTVAL, - CSR_STVAL, - CSR_HTVAL, - CSR_MTVAL2, - CSR_MSCRATCH, - CSR_SSCRATCH, - CSR_SATP, - }; + for (i = 0; i < ARRAY_SIZE(csr_ops); i++) { + int csrno = i; - for (i = 0; i < ARRAY_SIZE(dump_csrs); ++i) { - riscv_dump_csr(env, dump_csrs[i], f); + /* + * Early skip when possible since we're going + * through a lot of NULL entries. + */ + if (csr_ops[csrno].predicate == NULL) { + continue; } + + /* + * FPU and VPU CSRs will be printed in the + * CPU_DUMP_FPU/CPU_DUMP_VPU blocks later. + */ + if (riscv_csr_is_fpu(csrno) || + riscv_csr_is_vpu(csrno)) { + continue; + } + + riscv_dump_csr(env, csrno, f); } #endif diff --git a/target/riscv/csr.c b/target/riscv/csr.c index XXXXXXX..XXXXXXX 100644 --- a/target/riscv/csr.c +++ b/target/riscv/csr.c @@ -XXX,XX +XXX,XX @@ static RISCVException write_jvt(CPURISCVState *env, int csrno, return RISCV_EXCP_NONE; } +bool riscv_csr_is_fpu(int csrno) +{ + if (!csr_ops[csrno].predicate) { + return false; + } + + return csr_ops[csrno].predicate == fs; +} + +bool riscv_csr_is_vpu(int csrno) +{ + if (!csr_ops[csrno].predicate) { + return false; + } + + return csr_ops[csrno].predicate == vs; +} + /* * Control and Status Register function table * riscv_csr_operations::predicate() must be provided for an implemented CSR -- 2.52.0
From: Daniel Henrique Barboza <dbarboza@ventanamicro.com> Add a small section talking about the 'riscv-aia' KVM setting we implement and how it affects the provisioning of the IMSIC s-mode in-kernel controller. While we're at it, fix the formatting of the AIA bullet list. Signed-off-by: Daniel Henrique Barboza <dbarboza@ventanamicro.com> Acked-by: Alistair Francis <alistair.francis@wdc.com> Message-ID: <20251028084622.1177574-1-dbarboza@ventanamicro.com> Signed-off-by: Alistair Francis <alistair.francis@wdc.com> --- docs/specs/riscv-aia.rst | 43 ++++++++++++++++++++++++++++++++++++---- 1 file changed, 39 insertions(+), 4 deletions(-) diff --git a/docs/specs/riscv-aia.rst b/docs/specs/riscv-aia.rst index XXXXXXX..XXXXXXX 100644 --- a/docs/specs/riscv-aia.rst +++ b/docs/specs/riscv-aia.rst @@ -XXX,XX +XXX,XX @@ RISC-V machine for TCG and KVM accelerators. The support consists of two main modes: -- "aia=aplic": adds one or more APLIC (Advanced Platform Level Interrupt Controller) - devices -- "aia=aplic-imsic": adds one or more APLIC device and an IMSIC (Incoming MSI - Controller) device for each CPU +- *aia=aplic*: adds one or more APLIC (Advanced Platform Level Interrupt Controller) devices +- *aia=aplic-imsic*: adds one or more APLIC device and an IMSIC (Incoming MSI Controller) device for each CPU From an user standpoint, these modes will behave the same regardless of the accelerator used. From a developer standpoint the accelerator settings will change what it being @@ -XXX,XX +XXX,XX @@ we will emulate in userspace: - n/a - emul - in-kernel + + +KVM accel option 'riscv-aia' +---------------------------- + +The KVM accelerator property 'riscv-aia' interacts with the "aia=aplic-imsic" +to determine how the host KVM module will provide the in-kernel IMSIC s-mode +controller. The 'kernel-irqchip' setting has no impact in 'riscv-aia' given +that any available 'kernel-irqchip' setting will always have an in-kernel +IMSIC s-mode. 'riscv-aia' has no impact in APLIC m-mode/s-mode and +IMSIC m-mode settings. + + +.. list-table:: How 'riscv-aia' changes in-kernel IMSIC s-mode provisioning + :widths: 25 25 25 25 + :header-rows: 1 + + * - Accel + - KVM riscv-aia + - AIA type + - IMSIC s-mode + * - kvm + - none + - aplic-imsic + - in-kernel, default to 'auto' + * - kvm + - auto + - aplic-imsic + - in-kernel, hwaccel if available, emul otherwise + * - kvm + - hwaccel + - aplic-imsic + - in-kernel, use IMSIC controller from guest hardware + * - kvm + - emul + - aplic-imsic + - in-kernel, IMSIC is emulated by KVM -- 2.52.0
From: Akihiko Odaki <odaki@rsg.ci.i.u-tokyo.ac.jp> as points to the MemoryRegion itself. s is the device that owns the MemoryRegion. Signed-off-by: Akihiko Odaki <odaki@rsg.ci.i.u-tokyo.ac.jp> Reviewed-by: Daniel Henrique Barboza <dbarboza@ventanamicro.com> Reviewed-by: Nutty Liu <nutty.liu@hotmail.com> Reviewed-by: Philippe Mathieu-Daudé <philmd@linaro.org> Message-ID: <20251027-iommu-v1-1-0fc52a02a273@rsg.ci.i.u-tokyo.ac.jp> Signed-off-by: Alistair Francis <alistair.francis@wdc.com> --- hw/riscv/riscv-iommu.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/hw/riscv/riscv-iommu.c b/hw/riscv/riscv-iommu.c index XXXXXXX..XXXXXXX 100644 --- a/hw/riscv/riscv-iommu.c +++ b/hw/riscv/riscv-iommu.c @@ -XXX,XX +XXX,XX @@ static AddressSpace *riscv_iommu_space(RISCVIOMMUState *s, uint32_t devid) /* IOVA address space, untranslated addresses */ memory_region_init_iommu(&as->iova_mr, sizeof(as->iova_mr), TYPE_RISCV_IOMMU_MEMORY_REGION, - OBJECT(as), "riscv_iommu", UINT64_MAX); + OBJECT(s), "riscv_iommu", UINT64_MAX); address_space_init(&as->iova_as, MEMORY_REGION(&as->iova_mr), name); QLIST_INSERT_HEAD(&s->spaces, as, list); -- 2.52.0
From: Anton Johansson <anjo@rev.ng> This commits groups together all CPUArchState fields whose behaviour can be retained by simply changing the size of the field. Note, senvcfg is defined to be SXLEN bits wide, but is widened to 64 bits to match henvcfg and menvcfg. Next, [m|h]edeleg are changed to 64 bits as defined privileged specification, and hvictl is fixed to 32 bits which holds all relevant values, see HVICTL_VALID_MASK. The remaining fields touched in the commit are widened from [H|S|M]XLEN to 64-bit. Note, the cpu/hyper, cpu/envcfg, cpu/jvt, and cpu VMSTATE versions are bumped, breaking migration from older versions. References to the privileged/unprivileged RISCV specification refer to version 20250508. Signed-off-by: Anton Johansson <anjo@rev.ng> Reviewed-by: Pierrick Bouvier <pierrick.bouvier@linaro.org> Reviewed-by: Alistair Francis <alistair.francis@wdc.com> Message-ID: <20251027181831.27016-2-anjo@rev.ng> Signed-off-by: Alistair Francis <alistair.francis@wdc.com> Message-ID: <20251103033713.904455-2-alistair.francis@wdc.com> Signed-off-by: Alistair Francis <alistair.francis@wdc.com> --- target/riscv/cpu.h | 78 +++++++++++++++++++-------------------- target/riscv/machine.c | 84 +++++++++++++++++++++--------------------- 2 files changed, 81 insertions(+), 81 deletions(-) diff --git a/target/riscv/cpu.h b/target/riscv/cpu.h index XXXXXXX..XXXXXXX 100644 --- a/target/riscv/cpu.h +++ b/target/riscv/cpu.h @@ -XXX,XX +XXX,XX @@ struct CPUArchState { /* 128-bit helpers upper part return value */ target_ulong retxh; - target_ulong jvt; + uint64_t jvt; /* elp state for zicfilp extension */ bool elp; @@ -XXX,XX +XXX,XX @@ struct CPUArchState { target_ulong priv; /* CSRs for execution environment configuration */ uint64_t menvcfg; - target_ulong senvcfg; + uint64_t senvcfg; #ifndef CONFIG_USER_ONLY /* This contains QEMU specific information about the virt state. */ @@ -XXX,XX +XXX,XX @@ struct CPUArchState { */ uint64_t vsie; - target_ulong satp; /* since: priv-1.10.0 */ - target_ulong stval; - target_ulong medeleg; + uint64_t satp; /* since: priv-1.10.0 */ + uint64_t stval; + uint64_t medeleg; - target_ulong stvec; - target_ulong sepc; - target_ulong scause; + uint64_t stvec; + uint64_t sepc; + uint64_t scause; - target_ulong mtvec; - target_ulong mepc; - target_ulong mcause; - target_ulong mtval; /* since: priv-1.10.0 */ + uint64_t mtvec; + uint64_t mepc; + uint64_t mcause; + uint64_t mtval; /* since: priv-1.10.0 */ uint64_t mctrctl; uint32_t sctrdepth; @@ -XXX,XX +XXX,XX @@ struct CPUArchState { uint64_t mvip; /* Hypervisor CSRs */ - target_ulong hstatus; - target_ulong hedeleg; + uint64_t hstatus; + uint64_t hedeleg; uint64_t hideleg; uint32_t hcounteren; - target_ulong htval; - target_ulong htinst; - target_ulong hgatp; + uint64_t htval; + uint64_t htinst; + uint64_t hgatp; target_ulong hgeie; target_ulong hgeip; uint64_t htimedelta; @@ -XXX,XX +XXX,XX @@ struct CPUArchState { uint64_t hvip; /* Hypervisor controlled virtual interrupt priorities */ - target_ulong hvictl; + uint32_t hvictl; uint8_t hviprio[64]; /* Upper 64-bits of 128-bit CSRs */ @@ -XXX,XX +XXX,XX @@ struct CPUArchState { * For RV64 this is a 64-bit vsstatus. */ uint64_t vsstatus; - target_ulong vstvec; - target_ulong vsscratch; - target_ulong vsepc; - target_ulong vscause; - target_ulong vstval; - target_ulong vsatp; + uint64_t vstvec; + uint64_t vsscratch; + uint64_t vsepc; + uint64_t vscause; + uint64_t vstval; + uint64_t vsatp; /* AIA VS-mode CSRs */ target_ulong vsiselect; - target_ulong mtval2; - target_ulong mtinst; + uint64_t mtval2; + uint64_t mtinst; /* HS Backup CSRs */ - target_ulong stvec_hs; - target_ulong sscratch_hs; - target_ulong sepc_hs; - target_ulong scause_hs; - target_ulong stval_hs; - target_ulong satp_hs; + uint64_t stvec_hs; + uint64_t sscratch_hs; + uint64_t sepc_hs; + uint64_t scause_hs; + uint64_t stval_hs; + uint64_t satp_hs; uint64_t mstatus_hs; /* @@ -XXX,XX +XXX,XX @@ struct CPUArchState { PMUFixedCtrState pmu_fixed_ctrs[2]; - target_ulong sscratch; - target_ulong mscratch; + uint64_t sscratch; + uint64_t mscratch; /* Sstc CSRs */ uint64_t stimecmp; @@ -XXX,XX +XXX,XX @@ struct CPUArchState { #endif /* CONFIG_KVM */ /* RNMI */ - target_ulong mnscratch; - target_ulong mnepc; - target_ulong mncause; /* mncause without bit XLEN-1 set to 1 */ - target_ulong mnstatus; - target_ulong rnmip; + uint64_t mnscratch; + uint64_t mnepc; + uint64_t mncause; /* mncause without bit XLEN-1 set to 1 */ + uint64_t mnstatus; + uint64_t rnmip; uint64_t rnmi_irqvec; uint64_t rnmi_excpvec; }; diff --git a/target/riscv/machine.c b/target/riscv/machine.c index XXXXXXX..XXXXXXX 100644 --- a/target/riscv/machine.c +++ b/target/riscv/machine.c @@ -XXX,XX +XXX,XX @@ static bool hyper_needed(void *opaque) static const VMStateDescription vmstate_hyper = { .name = "cpu/hyper", - .version_id = 4, - .minimum_version_id = 4, + .version_id = 5, + .minimum_version_id = 5, .needed = hyper_needed, .fields = (const VMStateField[]) { - VMSTATE_UINTTL(env.hstatus, RISCVCPU), - VMSTATE_UINTTL(env.hedeleg, RISCVCPU), + VMSTATE_UINT64(env.hstatus, RISCVCPU), + VMSTATE_UINT64(env.hedeleg, RISCVCPU), VMSTATE_UINT64(env.hideleg, RISCVCPU), VMSTATE_UINT32(env.hcounteren, RISCVCPU), - VMSTATE_UINTTL(env.htval, RISCVCPU), - VMSTATE_UINTTL(env.htinst, RISCVCPU), - VMSTATE_UINTTL(env.hgatp, RISCVCPU), + VMSTATE_UINT64(env.htval, RISCVCPU), + VMSTATE_UINT64(env.htinst, RISCVCPU), + VMSTATE_UINT64(env.hgatp, RISCVCPU), VMSTATE_UINTTL(env.hgeie, RISCVCPU), VMSTATE_UINTTL(env.hgeip, RISCVCPU), VMSTATE_UINT64(env.hvien, RISCVCPU), @@ -XXX,XX +XXX,XX @@ static const VMStateDescription vmstate_hyper = { VMSTATE_UINT64(env.htimedelta, RISCVCPU), VMSTATE_UINT64(env.vstimecmp, RISCVCPU), - VMSTATE_UINTTL(env.hvictl, RISCVCPU), + VMSTATE_UINT32(env.hvictl, RISCVCPU), VMSTATE_UINT8_ARRAY(env.hviprio, RISCVCPU, 64), VMSTATE_UINT64(env.vsstatus, RISCVCPU), - VMSTATE_UINTTL(env.vstvec, RISCVCPU), - VMSTATE_UINTTL(env.vsscratch, RISCVCPU), - VMSTATE_UINTTL(env.vsepc, RISCVCPU), - VMSTATE_UINTTL(env.vscause, RISCVCPU), - VMSTATE_UINTTL(env.vstval, RISCVCPU), - VMSTATE_UINTTL(env.vsatp, RISCVCPU), + VMSTATE_UINT64(env.vstvec, RISCVCPU), + VMSTATE_UINT64(env.vsscratch, RISCVCPU), + VMSTATE_UINT64(env.vsepc, RISCVCPU), + VMSTATE_UINT64(env.vscause, RISCVCPU), + VMSTATE_UINT64(env.vstval, RISCVCPU), + VMSTATE_UINT64(env.vsatp, RISCVCPU), VMSTATE_UINTTL(env.vsiselect, RISCVCPU), VMSTATE_UINT64(env.vsie, RISCVCPU), - VMSTATE_UINTTL(env.mtval2, RISCVCPU), - VMSTATE_UINTTL(env.mtinst, RISCVCPU), + VMSTATE_UINT64(env.mtval2, RISCVCPU), + VMSTATE_UINT64(env.mtinst, RISCVCPU), - VMSTATE_UINTTL(env.stvec_hs, RISCVCPU), - VMSTATE_UINTTL(env.sscratch_hs, RISCVCPU), - VMSTATE_UINTTL(env.sepc_hs, RISCVCPU), - VMSTATE_UINTTL(env.scause_hs, RISCVCPU), - VMSTATE_UINTTL(env.stval_hs, RISCVCPU), - VMSTATE_UINTTL(env.satp_hs, RISCVCPU), + VMSTATE_UINT64(env.stvec_hs, RISCVCPU), + VMSTATE_UINT64(env.sscratch_hs, RISCVCPU), + VMSTATE_UINT64(env.sepc_hs, RISCVCPU), + VMSTATE_UINT64(env.scause_hs, RISCVCPU), + VMSTATE_UINT64(env.stval_hs, RISCVCPU), + VMSTATE_UINT64(env.satp_hs, RISCVCPU), VMSTATE_UINT64(env.mstatus_hs, RISCVCPU), VMSTATE_END_OF_LIST() @@ -XXX,XX +XXX,XX @@ static bool envcfg_needed(void *opaque) static const VMStateDescription vmstate_envcfg = { .name = "cpu/envcfg", - .version_id = 1, - .minimum_version_id = 1, + .version_id = 2, + .minimum_version_id = 2, .needed = envcfg_needed, .fields = (const VMStateField[]) { VMSTATE_UINT64(env.menvcfg, RISCVCPU), - VMSTATE_UINTTL(env.senvcfg, RISCVCPU), + VMSTATE_UINT64(env.senvcfg, RISCVCPU), VMSTATE_UINT64(env.henvcfg, RISCVCPU), VMSTATE_END_OF_LIST() } @@ -XXX,XX +XXX,XX @@ static bool jvt_needed(void *opaque) static const VMStateDescription vmstate_jvt = { .name = "cpu/jvt", - .version_id = 1, - .minimum_version_id = 1, + .version_id = 2, + .minimum_version_id = 2, .needed = jvt_needed, .fields = (const VMStateField[]) { - VMSTATE_UINTTL(env.jvt, RISCVCPU), + VMSTATE_UINT64(env.jvt, RISCVCPU), VMSTATE_END_OF_LIST() } }; @@ -XXX,XX +XXX,XX @@ static const VMStateDescription vmstate_sstc = { const VMStateDescription vmstate_riscv_cpu = { .name = "cpu", - .version_id = 10, - .minimum_version_id = 10, + .version_id = 11, + .minimum_version_id = 11, .post_load = riscv_cpu_post_load, .fields = (const VMStateField[]) { VMSTATE_UINTTL_ARRAY(env.gpr, RISCVCPU, 32), @@ -XXX,XX +XXX,XX @@ const VMStateDescription vmstate_riscv_cpu = { VMSTATE_UINT64(env.mvip, RISCVCPU), VMSTATE_UINT64(env.sie, RISCVCPU), VMSTATE_UINT64(env.mideleg, RISCVCPU), - VMSTATE_UINTTL(env.satp, RISCVCPU), - VMSTATE_UINTTL(env.stval, RISCVCPU), - VMSTATE_UINTTL(env.medeleg, RISCVCPU), - VMSTATE_UINTTL(env.stvec, RISCVCPU), - VMSTATE_UINTTL(env.sepc, RISCVCPU), - VMSTATE_UINTTL(env.scause, RISCVCPU), - VMSTATE_UINTTL(env.mtvec, RISCVCPU), - VMSTATE_UINTTL(env.mepc, RISCVCPU), - VMSTATE_UINTTL(env.mcause, RISCVCPU), - VMSTATE_UINTTL(env.mtval, RISCVCPU), + VMSTATE_UINT64(env.satp, RISCVCPU), + VMSTATE_UINT64(env.stval, RISCVCPU), + VMSTATE_UINT64(env.medeleg, RISCVCPU), + VMSTATE_UINT64(env.stvec, RISCVCPU), + VMSTATE_UINT64(env.sepc, RISCVCPU), + VMSTATE_UINT64(env.scause, RISCVCPU), + VMSTATE_UINT64(env.mtvec, RISCVCPU), + VMSTATE_UINT64(env.mepc, RISCVCPU), + VMSTATE_UINT64(env.mcause, RISCVCPU), + VMSTATE_UINT64(env.mtval, RISCVCPU), VMSTATE_UINTTL(env.miselect, RISCVCPU), VMSTATE_UINTTL(env.siselect, RISCVCPU), VMSTATE_UINT32(env.scounteren, RISCVCPU), @@ -XXX,XX +XXX,XX @@ const VMStateDescription vmstate_riscv_cpu = { vmstate_pmu_ctr_state, PMUCTRState), VMSTATE_UINTTL_ARRAY(env.mhpmevent_val, RISCVCPU, RV_MAX_MHPMEVENTS), VMSTATE_UINTTL_ARRAY(env.mhpmeventh_val, RISCVCPU, RV_MAX_MHPMEVENTS), - VMSTATE_UINTTL(env.sscratch, RISCVCPU), - VMSTATE_UINTTL(env.mscratch, RISCVCPU), + VMSTATE_UINT64(env.sscratch, RISCVCPU), + VMSTATE_UINT64(env.mscratch, RISCVCPU), VMSTATE_UINT64(env.stimecmp, RISCVCPU), VMSTATE_END_OF_LIST() -- 2.52.0
From: Anton Johansson <anjo@rev.ng> and update formatting in log. Signed-off-by: Anton Johansson <anjo@rev.ng> Reviewed-by: Pierrick Bouvier <pierrick.bouvier@linaro.org> Reviewed-by: Alistair Francis <alistair.francis@wdc.com> Message-ID: <20251027181831.27016-3-anjo@rev.ng> Signed-off-by: Alistair Francis <alistair.francis@wdc.com> Message-ID: <20251103033713.904455-3-alistair.francis@wdc.com> Signed-off-by: Alistair Francis <alistair.francis@wdc.com> --- target/riscv/cpu.h | 2 +- target/riscv/cpu_helper.c | 2 +- target/riscv/machine.c | 2 +- target/riscv/tcg/tcg-cpu.c | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/target/riscv/cpu.h b/target/riscv/cpu.h index XXXXXXX..XXXXXXX 100644 --- a/target/riscv/cpu.h +++ b/target/riscv/cpu.h @@ -XXX,XX +XXX,XX @@ struct CPUArchState { target_ulong geilen; uint64_t resetvec; - target_ulong mhartid; + uint64_t mhartid; /* * For RV32 this is 32-bit mstatus and 32-bit mstatush. * For RV64 this is a 64-bit mstatus. diff --git a/target/riscv/cpu_helper.c b/target/riscv/cpu_helper.c index XXXXXXX..XXXXXXX 100644 --- a/target/riscv/cpu_helper.c +++ b/target/riscv/cpu_helper.c @@ -XXX,XX +XXX,XX @@ void riscv_cpu_do_interrupt(CPUState *cs) riscv_cpu_get_trap_name(cause, async)); qemu_log_mask(CPU_LOG_INT, - "%s: hart:"TARGET_FMT_ld", async:%d, cause:"TARGET_FMT_lx", " + "%s: hart:%"PRIu64", async:%d, cause:"TARGET_FMT_lx", " "epc:0x"TARGET_FMT_lx", tval:0x"TARGET_FMT_lx", desc=%s\n", __func__, env->mhartid, async, cause, env->pc, tval, riscv_cpu_get_trap_name(cause, async)); diff --git a/target/riscv/machine.c b/target/riscv/machine.c index XXXXXXX..XXXXXXX 100644 --- a/target/riscv/machine.c +++ b/target/riscv/machine.c @@ -XXX,XX +XXX,XX @@ const VMStateDescription vmstate_riscv_cpu = { VMSTATE_UINTTL(env.priv, RISCVCPU), VMSTATE_BOOL(env.virt_enabled, RISCVCPU), VMSTATE_UINT64(env.resetvec, RISCVCPU), - VMSTATE_UINTTL(env.mhartid, RISCVCPU), + VMSTATE_UINT64(env.mhartid, RISCVCPU), VMSTATE_UINT64(env.mstatus, RISCVCPU), VMSTATE_UINT64(env.mip, RISCVCPU), VMSTATE_UINT64(env.miclaim, RISCVCPU), diff --git a/target/riscv/tcg/tcg-cpu.c b/target/riscv/tcg/tcg-cpu.c index XXXXXXX..XXXXXXX 100644 --- a/target/riscv/tcg/tcg-cpu.c +++ b/target/riscv/tcg/tcg-cpu.c @@ -XXX,XX +XXX,XX @@ static void riscv_cpu_disable_priv_spec_isa_exts(RISCVCPU *cpu) continue; } #ifndef CONFIG_USER_ONLY - warn_report("disabling %s extension for hart 0x" TARGET_FMT_lx + warn_report("disabling %s extension for hart 0x%" PRIx64 " because privilege spec version does not match", edata->name, env->mhartid); #else -- 2.52.0
From: Anton Johansson <anjo@rev.ng> According to version 20250508 of the privileged specification, a read of cyclecfg or instretcfg through sireg* should make the MINH bit read-only 0, currently bit 30 is zeroed. Signed-off-by: Anton Johansson <anjo@rev.ng> Reviewed-by: Alistair Francis <alistair.francis@wdc.com> Reviewed-by: Pierrick Bouvier <pierrick.bouvier@linaro.org> Message-ID: <20251027181831.27016-5-anjo@rev.ng> Signed-off-by: Alistair Francis <alistair.francis@wdc.com> Message-ID: <20251103033713.904455-4-alistair.francis@wdc.com> Signed-off-by: Alistair Francis <alistair.francis@wdc.com> --- target/riscv/csr.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/target/riscv/csr.c b/target/riscv/csr.c index XXXXXXX..XXXXXXX 100644 --- a/target/riscv/csr.c +++ b/target/riscv/csr.c @@ -XXX,XX +XXX,XX @@ static int rmw_cd_ctr_cfg(CPURISCVState *env, int cfg_index, target_ulong *val, wr_mask &= ~MCYCLECFG_BIT_MINH; env->mcyclecfg = (new_val & wr_mask) | (env->mcyclecfg & ~wr_mask); } else { - *val = env->mcyclecfg &= ~MHPMEVENTH_BIT_MINH; + *val = env->mcyclecfg &= ~MHPMEVENT_BIT_MINH; } break; case 2: /* INSTRETCFG */ @@ -XXX,XX +XXX,XX @@ static int rmw_cd_ctr_cfg(CPURISCVState *env, int cfg_index, target_ulong *val, env->minstretcfg = (new_val & wr_mask) | (env->minstretcfg & ~wr_mask); } else { - *val = env->minstretcfg &= ~MHPMEVENTH_BIT_MINH; + *val = env->minstretcfg &= ~MHPMEVENT_BIT_MINH; } break; default: -- 2.52.0
From: Anton Johansson <anjo@rev.ng> According to version 20250508 of the privileged specification, mhpmeventn is 64 bits in size and mhpmeventnh is only ever used when XLEN == 32 and accesses the top 32 bits of the 64-bit mhpmeventn registers. Combine the two arrays of target_ulong mhpmeventh[] and mhpmevent[] to a single array of uint64_t. This also allows for some minor code simplification where branches handling either mhpmeventh[] or mhpmevent[] could be combined. Signed-off-by: Anton Johansson <anjo@rev.ng> Reviewed-by: Alistair Francis <alistair.francis@wdc.com> Reviewed-by: Pierrick Bouvier <pierrick.bouvier@linaro.org> Message-ID: <20251027181831.27016-6-anjo@rev.ng> Signed-off-by: Alistair Francis <alistair.francis@wdc.com> Message-ID: <20251103033713.904455-5-alistair.francis@wdc.com> Signed-off-by: Alistair Francis <alistair.francis@wdc.com> --- target/riscv/cpu.h | 10 +++---- target/riscv/csr.c | 67 +++++++++++++++--------------------------- target/riscv/machine.c | 3 +- target/riscv/pmu.c | 53 ++++++++------------------------- 4 files changed, 42 insertions(+), 91 deletions(-) diff --git a/target/riscv/cpu.h b/target/riscv/cpu.h index XXXXXXX..XXXXXXX 100644 --- a/target/riscv/cpu.h +++ b/target/riscv/cpu.h @@ -XXX,XX +XXX,XX @@ struct CPUArchState { /* PMU counter state */ PMUCTRState pmu_ctrs[RV_MAX_MHPMCOUNTERS]; - /* PMU event selector configured values. First three are unused */ - target_ulong mhpmevent_val[RV_MAX_MHPMEVENTS]; - - /* PMU event selector configured values for RV32 */ - target_ulong mhpmeventh_val[RV_MAX_MHPMEVENTS]; + /* + * PMU event selector configured values. First three are unused. + * For RV32 top 32 bits are accessed via the mhpmeventh CSR. + */ + uint64_t mhpmevent_val[RV_MAX_MHPMEVENTS]; PMUFixedCtrState pmu_fixed_ctrs[2]; diff --git a/target/riscv/csr.c b/target/riscv/csr.c index XXXXXXX..XXXXXXX 100644 --- a/target/riscv/csr.c +++ b/target/riscv/csr.c @@ -XXX,XX +XXX,XX @@ static RISCVException read_mhpmevent(CPURISCVState *env, int csrno, target_ulong *val) { int evt_index = csrno - CSR_MCOUNTINHIBIT; + bool rv32 = riscv_cpu_mxl(env) == MXL_RV32; - *val = env->mhpmevent_val[evt_index]; + *val = extract64(env->mhpmevent_val[evt_index], 0, rv32 ? 32 : 64); return RISCV_EXCP_NONE; } @@ -XXX,XX +XXX,XX @@ static RISCVException write_mhpmevent(CPURISCVState *env, int csrno, target_ulong val, uintptr_t ra) { int evt_index = csrno - CSR_MCOUNTINHIBIT; - uint64_t mhpmevt_val = val; + uint64_t mhpmevt_val; uint64_t inh_avail_mask; if (riscv_cpu_mxl(env) == MXL_RV32) { - env->mhpmevent_val[evt_index] = val; - mhpmevt_val = mhpmevt_val | - ((uint64_t)env->mhpmeventh_val[evt_index] << 32); + mhpmevt_val = deposit64(env->mhpmevent_val[evt_index], 0, 32, val); } else { inh_avail_mask = ~MHPMEVENT_FILTER_MASK | MHPMEVENT_BIT_MINH; inh_avail_mask |= riscv_has_ext(env, RVU) ? MHPMEVENT_BIT_UINH : 0; @@ -XXX,XX +XXX,XX @@ static RISCVException write_mhpmevent(CPURISCVState *env, int csrno, inh_avail_mask |= (riscv_has_ext(env, RVH) && riscv_has_ext(env, RVS)) ? MHPMEVENT_BIT_VSINH : 0; mhpmevt_val = val & inh_avail_mask; - env->mhpmevent_val[evt_index] = mhpmevt_val; } + env->mhpmevent_val[evt_index] = mhpmevt_val; riscv_pmu_update_event_map(env, mhpmevt_val, evt_index); return RISCV_EXCP_NONE; @@ -XXX,XX +XXX,XX @@ static RISCVException read_mhpmeventh(CPURISCVState *env, int csrno, { int evt_index = csrno - CSR_MHPMEVENT3H + 3; - *val = env->mhpmeventh_val[evt_index]; + *val = extract64(env->mhpmevent_val[evt_index], 32, 32); return RISCV_EXCP_NONE; } @@ -XXX,XX +XXX,XX @@ static RISCVException write_mhpmeventh(CPURISCVState *env, int csrno, target_ulong val, uintptr_t ra) { int evt_index = csrno - CSR_MHPMEVENT3H + 3; - uint64_t mhpmevth_val; - uint64_t mhpmevt_val = env->mhpmevent_val[evt_index]; target_ulong inh_avail_mask = (target_ulong)(~MHPMEVENTH_FILTER_MASK | MHPMEVENTH_BIT_MINH); @@ -XXX,XX +XXX,XX @@ static RISCVException write_mhpmeventh(CPURISCVState *env, int csrno, inh_avail_mask |= (riscv_has_ext(env, RVH) && riscv_has_ext(env, RVS)) ? MHPMEVENTH_BIT_VSINH : 0; - mhpmevth_val = val & inh_avail_mask; - mhpmevt_val = mhpmevt_val | (mhpmevth_val << 32); - env->mhpmeventh_val[evt_index] = mhpmevth_val; + env->mhpmevent_val[evt_index] = deposit64(env->mhpmevent_val[evt_index], + 32, 32, val & inh_avail_mask); - riscv_pmu_update_event_map(env, mhpmevt_val, evt_index); + riscv_pmu_update_event_map(env, env->mhpmevent_val[evt_index], evt_index); return RISCV_EXCP_NONE; } @@ -XXX,XX +XXX,XX @@ static target_ulong riscv_pmu_ctr_get_fixed_counters_val(CPURISCVState *env, cfg_val = upper_half ? ((uint64_t)env->minstretcfgh << 32) : env->minstretcfg; } else { - cfg_val = upper_half ? - ((uint64_t)env->mhpmeventh_val[counter_idx] << 32) : - env->mhpmevent_val[counter_idx]; + cfg_val = env->mhpmevent_val[counter_idx]; cfg_val &= MHPMEVENT_FILTER_MASK; } @@ -XXX,XX +XXX,XX @@ static int rmw_cd_mhpmcounterh(CPURISCVState *env, int ctr_idx, static int rmw_cd_mhpmevent(CPURISCVState *env, int evt_index, target_ulong *val, target_ulong new_val, - target_ulong wr_mask) + uint64_t wr_mask) { - uint64_t mhpmevt_val = new_val; + uint64_t mhpmevt_val = env->mhpmevent_val[evt_index]; if (wr_mask != 0 && wr_mask != -1) { return -EINVAL; } if (!wr_mask && val) { - *val = env->mhpmevent_val[evt_index]; + *val = mhpmevt_val; if (riscv_cpu_cfg(env)->ext_sscofpmf) { *val &= ~MHPMEVENT_BIT_MINH; } } else if (wr_mask) { wr_mask &= ~MHPMEVENT_BIT_MINH; - mhpmevt_val = (new_val & wr_mask) | - (env->mhpmevent_val[evt_index] & ~wr_mask); - if (riscv_cpu_mxl(env) == MXL_RV32) { - mhpmevt_val = mhpmevt_val | - ((uint64_t)env->mhpmeventh_val[evt_index] << 32); - } + /* wr_mask is 64-bit so upper 32 bits of mhpmevt_val are retained */ + mhpmevt_val = (new_val & wr_mask) | (mhpmevt_val & ~wr_mask); env->mhpmevent_val[evt_index] = mhpmevt_val; riscv_pmu_update_event_map(env, mhpmevt_val, evt_index); } else { @@ -XXX,XX +XXX,XX @@ static int rmw_cd_mhpmeventh(CPURISCVState *env, int evt_index, target_ulong *val, target_ulong new_val, target_ulong wr_mask) { - uint64_t mhpmevth_val; uint64_t mhpmevt_val = env->mhpmevent_val[evt_index]; + uint32_t mhpmevth_val = extract64(mhpmevt_val, 32, 32); if (wr_mask != 0 && wr_mask != -1) { return -EINVAL; } if (!wr_mask && val) { - *val = env->mhpmeventh_val[evt_index]; + *val = mhpmevth_val; if (riscv_cpu_cfg(env)->ext_sscofpmf) { *val &= ~MHPMEVENTH_BIT_MINH; } } else if (wr_mask) { wr_mask &= ~MHPMEVENTH_BIT_MINH; - env->mhpmeventh_val[evt_index] = - (new_val & wr_mask) | (env->mhpmeventh_val[evt_index] & ~wr_mask); - mhpmevth_val = env->mhpmeventh_val[evt_index]; - mhpmevt_val = mhpmevt_val | (mhpmevth_val << 32); + mhpmevth_val = (new_val & wr_mask) | (mhpmevth_val & ~wr_mask); + mhpmevt_val = deposit64(mhpmevt_val, 32, 32, mhpmevth_val); + env->mhpmevent_val[evt_index] = mhpmevt_val; riscv_pmu_update_event_map(env, mhpmevt_val, evt_index); } else { return -EINVAL; @@ -XXX,XX +XXX,XX @@ static RISCVException read_scountovf(CPURISCVState *env, int csrno, int mhpmevt_start = CSR_MHPMEVENT3 - CSR_MCOUNTINHIBIT; int i; *val = 0; - target_ulong *mhpm_evt_val; - uint64_t of_bit_mask; /* Virtualize scountovf for counter delegation */ if (riscv_cpu_cfg(env)->ext_sscofpmf && @@ -XXX,XX +XXX,XX @@ static RISCVException read_scountovf(CPURISCVState *env, int csrno, return RISCV_EXCP_VIRT_INSTRUCTION_FAULT; } - if (riscv_cpu_mxl(env) == MXL_RV32) { - mhpm_evt_val = env->mhpmeventh_val; - of_bit_mask = MHPMEVENTH_BIT_OF; - } else { - mhpm_evt_val = env->mhpmevent_val; - of_bit_mask = MHPMEVENT_BIT_OF; - } - for (i = mhpmevt_start; i < RV_MAX_MHPMEVENTS; i++) { if ((get_field(env->mcounteren, BIT(i))) && - (mhpm_evt_val[i] & of_bit_mask)) { - *val |= BIT(i); - } + (env->mhpmevent_val[i] & MHPMEVENT_BIT_OF)) { + *val |= BIT(i); + } } return RISCV_EXCP_NONE; diff --git a/target/riscv/machine.c b/target/riscv/machine.c index XXXXXXX..XXXXXXX 100644 --- a/target/riscv/machine.c +++ b/target/riscv/machine.c @@ -XXX,XX +XXX,XX @@ const VMStateDescription vmstate_riscv_cpu = { VMSTATE_UINT32(env.mcountinhibit, RISCVCPU), VMSTATE_STRUCT_ARRAY(env.pmu_ctrs, RISCVCPU, RV_MAX_MHPMCOUNTERS, 0, vmstate_pmu_ctr_state, PMUCTRState), - VMSTATE_UINTTL_ARRAY(env.mhpmevent_val, RISCVCPU, RV_MAX_MHPMEVENTS), - VMSTATE_UINTTL_ARRAY(env.mhpmeventh_val, RISCVCPU, RV_MAX_MHPMEVENTS), + VMSTATE_UINT64_ARRAY(env.mhpmevent_val, RISCVCPU, RV_MAX_MHPMEVENTS), VMSTATE_UINT64(env.sscratch, RISCVCPU), VMSTATE_UINT64(env.mscratch, RISCVCPU), VMSTATE_UINT64(env.stimecmp, RISCVCPU), diff --git a/target/riscv/pmu.c b/target/riscv/pmu.c index XXXXXXX..XXXXXXX 100644 --- a/target/riscv/pmu.c +++ b/target/riscv/pmu.c @@ -XXX,XX +XXX,XX @@ static int riscv_pmu_incr_ctr_rv32(RISCVCPU *cpu, uint32_t ctr_idx) /* Privilege mode filtering */ if ((env->priv == PRV_M && - (env->mhpmeventh_val[ctr_idx] & MHPMEVENTH_BIT_MINH)) || + (env->mhpmevent_val[ctr_idx] & MHPMEVENT_BIT_MINH)) || (env->priv == PRV_S && virt_on && - (env->mhpmeventh_val[ctr_idx] & MHPMEVENTH_BIT_VSINH)) || + (env->mhpmevent_val[ctr_idx] & MHPMEVENT_BIT_VSINH)) || (env->priv == PRV_U && virt_on && - (env->mhpmeventh_val[ctr_idx] & MHPMEVENTH_BIT_VUINH)) || + (env->mhpmevent_val[ctr_idx] & MHPMEVENT_BIT_VUINH)) || (env->priv == PRV_S && !virt_on && - (env->mhpmeventh_val[ctr_idx] & MHPMEVENTH_BIT_SINH)) || + (env->mhpmevent_val[ctr_idx] & MHPMEVENT_BIT_SINH)) || (env->priv == PRV_U && !virt_on && - (env->mhpmeventh_val[ctr_idx] & MHPMEVENTH_BIT_UINH))) { + (env->mhpmevent_val[ctr_idx] & MHPMEVENT_BIT_UINH))) { return 0; } @@ -XXX,XX +XXX,XX @@ static int riscv_pmu_incr_ctr_rv32(RISCVCPU *cpu, uint32_t ctr_idx) counter->mhpmcounter_val = 0; counter->mhpmcounterh_val = 0; /* Generate interrupt only if OF bit is clear */ - if (!(env->mhpmeventh_val[ctr_idx] & MHPMEVENTH_BIT_OF)) { - env->mhpmeventh_val[ctr_idx] |= MHPMEVENTH_BIT_OF; + if (!(env->mhpmevent_val[ctr_idx] & MHPMEVENT_BIT_OF)) { + env->mhpmevent_val[ctr_idx] |= MHPMEVENT_BIT_OF; riscv_cpu_update_mip(env, MIP_LCOFIP, BOOL_TO_MASK(1)); } } else { @@ -XXX,XX +XXX,XX @@ int riscv_pmu_update_event_map(CPURISCVState *env, uint64_t value, return 0; } -static bool pmu_hpmevent_is_of_set(CPURISCVState *env, uint32_t ctr_idx) -{ - target_ulong mhpmevent_val; - uint64_t of_bit_mask; - - if (riscv_cpu_mxl(env) == MXL_RV32) { - mhpmevent_val = env->mhpmeventh_val[ctr_idx]; - of_bit_mask = MHPMEVENTH_BIT_OF; - } else { - mhpmevent_val = env->mhpmevent_val[ctr_idx]; - of_bit_mask = MHPMEVENT_BIT_OF; - } - - return get_field(mhpmevent_val, of_bit_mask); -} - static bool pmu_hpmevent_set_of_if_clear(CPURISCVState *env, uint32_t ctr_idx) { - target_ulong *mhpmevent_val; - uint64_t of_bit_mask; - - if (riscv_cpu_mxl(env) == MXL_RV32) { - mhpmevent_val = &env->mhpmeventh_val[ctr_idx]; - of_bit_mask = MHPMEVENTH_BIT_OF; - } else { - mhpmevent_val = &env->mhpmevent_val[ctr_idx]; - of_bit_mask = MHPMEVENT_BIT_OF; - } - - if (!get_field(*mhpmevent_val, of_bit_mask)) { - *mhpmevent_val |= of_bit_mask; + if (!get_field(env->mhpmevent_val[ctr_idx], MHPMEVENT_BIT_OF)) { + env->mhpmevent_val[ctr_idx] |= MHPMEVENT_BIT_OF; return true; + } else { + return false; } - - return false; } static void pmu_timer_trigger_irq(RISCVCPU *cpu, @@ -XXX,XX +XXX,XX @@ static void pmu_timer_trigger_irq(RISCVCPU *cpu, } /* Generate interrupt only if OF bit is clear */ - if (pmu_hpmevent_is_of_set(env, ctr_idx)) { + if (get_field(env->mhpmevent_val[ctr_idx], MHPMEVENT_BIT_OF)) { return; } @@ -XXX,XX +XXX,XX @@ int riscv_pmu_setup_timer(CPURISCVState *env, uint64_t value, uint32_t ctr_idx) /* No need to setup a timer if LCOFI is disabled when OF is set */ if (!riscv_pmu_counter_valid(cpu, ctr_idx) || !cpu->cfg.ext_sscofpmf || - pmu_hpmevent_is_of_set(env, ctr_idx)) { + get_field(env->mhpmevent_val[ctr_idx], MHPMEVENT_BIT_OF)) { return -1; } -- 2.52.0
From: Anton Johansson <anjo@rev.ng> According to version 20250508 of the privileged specification, mcyclecfg is a 64-bit register and mcyclecfgh refers to the top 32 bits of this register when XLEN == 32. No real advantage is gained by keeping them separate, and combining them allows for slight simplification. Signed-off-by: Anton Johansson <anjo@rev.ng> Reviewed-by: Alistair Francis <alistair.francis@wdc.com> Reviewed-by: Pierrick Bouvier <pierrick.bouvier@linaro.org> Message-ID: <20251027181831.27016-7-anjo@rev.ng> Signed-off-by: Alistair Francis <alistair.francis@wdc.com> Message-ID: <20251103033713.904455-6-alistair.francis@wdc.com> Signed-off-by: Alistair Francis <alistair.francis@wdc.com> --- target/riscv/cpu.h | 3 +-- target/riscv/csr.c | 28 +++++++++++++++++----------- 2 files changed, 18 insertions(+), 13 deletions(-) diff --git a/target/riscv/cpu.h b/target/riscv/cpu.h index XXXXXXX..XXXXXXX 100644 --- a/target/riscv/cpu.h +++ b/target/riscv/cpu.h @@ -XXX,XX +XXX,XX @@ struct CPUArchState { uint32_t mcountinhibit; /* PMU cycle & instret privilege mode filtering */ - target_ulong mcyclecfg; - target_ulong mcyclecfgh; + uint64_t mcyclecfg; target_ulong minstretcfg; target_ulong minstretcfgh; diff --git a/target/riscv/csr.c b/target/riscv/csr.c index XXXXXXX..XXXXXXX 100644 --- a/target/riscv/csr.c +++ b/target/riscv/csr.c @@ -XXX,XX +XXX,XX @@ static RISCVException read_hpmcounterh(CPURISCVState *env, int csrno, static RISCVException read_mcyclecfg(CPURISCVState *env, int csrno, target_ulong *val) { - *val = env->mcyclecfg; + bool rv32 = riscv_cpu_mxl(env) == MXL_RV32; + *val = extract64(env->mcyclecfg, 0, rv32 ? 32 : 64); return RISCV_EXCP_NONE; } @@ -XXX,XX +XXX,XX @@ static RISCVException write_mcyclecfg(CPURISCVState *env, int csrno, uint64_t inh_avail_mask; if (riscv_cpu_mxl(env) == MXL_RV32) { - env->mcyclecfg = val; + env->mcyclecfg = deposit64(env->mcyclecfg, 0, 32, val); } else { /* Set xINH fields if priv mode supported */ inh_avail_mask = ~MHPMEVENT_FILTER_MASK | MCYCLECFG_BIT_MINH; @@ -XXX,XX +XXX,XX @@ static RISCVException write_mcyclecfg(CPURISCVState *env, int csrno, static RISCVException read_mcyclecfgh(CPURISCVState *env, int csrno, target_ulong *val) { - *val = env->mcyclecfgh; + *val = extract64(env->mcyclecfg, 32, 32); return RISCV_EXCP_NONE; } @@ -XXX,XX +XXX,XX @@ static RISCVException write_mcyclecfgh(CPURISCVState *env, int csrno, inh_avail_mask |= (riscv_has_ext(env, RVH) && riscv_has_ext(env, RVS)) ? MCYCLECFGH_BIT_VSINH : 0; - env->mcyclecfgh = val & inh_avail_mask; + env->mcyclecfg = deposit64(env->mcyclecfg, 32, 32, val & inh_avail_mask); return RISCV_EXCP_NONE; } @@ -XXX,XX +XXX,XX @@ static target_ulong riscv_pmu_ctr_get_fixed_counters_val(CPURISCVState *env, uint64_t cfg_val = 0; if (counter_idx == 0) { - cfg_val = upper_half ? ((uint64_t)env->mcyclecfgh << 32) : - env->mcyclecfg; + cfg_val = env->mcyclecfg; } else if (counter_idx == 2) { cfg_val = upper_half ? ((uint64_t)env->minstretcfgh << 32) : env->minstretcfg; @@ -XXX,XX +XXX,XX @@ static int rmw_cd_mhpmeventh(CPURISCVState *env, int evt_index, } static int rmw_cd_ctr_cfg(CPURISCVState *env, int cfg_index, target_ulong *val, - target_ulong new_val, target_ulong wr_mask) + target_ulong new_val, uint64_t wr_mask) { + /* + * wr_mask is 64-bit so upper 32 bits of mcyclecfg and minstretcfg + * are retained. + */ switch (cfg_index) { case 0: /* CYCLECFG */ if (wr_mask) { @@ -XXX,XX +XXX,XX @@ static int rmw_cd_ctr_cfg(CPURISCVState *env, int cfg_index, target_ulong *val, } static int rmw_cd_ctr_cfgh(CPURISCVState *env, int cfg_index, target_ulong *val, - target_ulong new_val, target_ulong wr_mask) + target_ulong new_val, target_ulong wr_mask) { + uint64_t cfgh; if (riscv_cpu_mxl(env) != MXL_RV32) { return RISCV_EXCP_ILLEGAL_INST; @@ -XXX,XX +XXX,XX @@ static int rmw_cd_ctr_cfgh(CPURISCVState *env, int cfg_index, target_ulong *val, switch (cfg_index) { case 0: /* CYCLECFGH */ + cfgh = extract64(env->mcyclecfg, 32, 32); if (wr_mask) { wr_mask &= ~MCYCLECFGH_BIT_MINH; - env->mcyclecfgh = (new_val & wr_mask) | - (env->mcyclecfgh & ~wr_mask); + cfgh = (new_val & wr_mask) | (cfgh & ~wr_mask); + env->mcyclecfg = deposit64(env->mcyclecfg, 32, 32, cfgh); } else { - *val = env->mcyclecfgh; + *val = cfgh; } break; case 2: /* INSTRETCFGH */ -- 2.52.0
From: Anton Johansson <anjo@rev.ng> According to version 20250508 of the privileged specification, minstretcfg is a 64-bit register and minstretcfgh refers to the top 32 bits of this register when XLEN == 32. No real advantage is gained by keeping them separate, and combining them allows for slight simplification. Signed-off-by: Anton Johansson <anjo@rev.ng> Reviewed-by: Alistair Francis <alistair.francis@wdc.com> Reviewed-by: Pierrick Bouvier <pierrick.bouvier@linaro.org> Message-ID: <20251027181831.27016-8-anjo@rev.ng> Signed-off-by: Alistair Francis <alistair.francis@wdc.com> Message-ID: <20251103033713.904455-7-alistair.francis@wdc.com> Signed-off-by: Alistair Francis <alistair.francis@wdc.com> --- target/riscv/cpu.h | 3 +-- target/riscv/csr.c | 18 ++++++++++-------- 2 files changed, 11 insertions(+), 10 deletions(-) diff --git a/target/riscv/cpu.h b/target/riscv/cpu.h index XXXXXXX..XXXXXXX 100644 --- a/target/riscv/cpu.h +++ b/target/riscv/cpu.h @@ -XXX,XX +XXX,XX @@ struct CPUArchState { /* PMU cycle & instret privilege mode filtering */ uint64_t mcyclecfg; - target_ulong minstretcfg; - target_ulong minstretcfgh; + uint64_t minstretcfg; /* PMU counter state */ PMUCTRState pmu_ctrs[RV_MAX_MHPMCOUNTERS]; diff --git a/target/riscv/csr.c b/target/riscv/csr.c index XXXXXXX..XXXXXXX 100644 --- a/target/riscv/csr.c +++ b/target/riscv/csr.c @@ -XXX,XX +XXX,XX @@ static RISCVException write_mcyclecfgh(CPURISCVState *env, int csrno, static RISCVException read_minstretcfg(CPURISCVState *env, int csrno, target_ulong *val) { - *val = env->minstretcfg; + bool rv32 = riscv_cpu_mxl(env) == MXL_RV32; + *val = extract64(env->minstretcfg, 0, rv32 ? 32 : 64); return RISCV_EXCP_NONE; } @@ -XXX,XX +XXX,XX @@ static RISCVException write_minstretcfg(CPURISCVState *env, int csrno, static RISCVException read_minstretcfgh(CPURISCVState *env, int csrno, target_ulong *val) { - *val = env->minstretcfgh; + *val = extract64(env->minstretcfg, 32, 32); return RISCV_EXCP_NONE; } @@ -XXX,XX +XXX,XX @@ static RISCVException write_minstretcfgh(CPURISCVState *env, int csrno, inh_avail_mask |= (riscv_has_ext(env, RVH) && riscv_has_ext(env, RVS)) ? MINSTRETCFGH_BIT_VSINH : 0; - env->minstretcfgh = val & inh_avail_mask; + env->minstretcfg = deposit64(env->minstretcfg, 32, 32, + val & inh_avail_mask); return RISCV_EXCP_NONE; } @@ -XXX,XX +XXX,XX @@ static target_ulong riscv_pmu_ctr_get_fixed_counters_val(CPURISCVState *env, if (counter_idx == 0) { cfg_val = env->mcyclecfg; } else if (counter_idx == 2) { - cfg_val = upper_half ? ((uint64_t)env->minstretcfgh << 32) : - env->minstretcfg; + cfg_val = env->minstretcfg; } else { cfg_val = env->mhpmevent_val[counter_idx]; cfg_val &= MHPMEVENT_FILTER_MASK; @@ -XXX,XX +XXX,XX @@ static int rmw_cd_ctr_cfgh(CPURISCVState *env, int cfg_index, target_ulong *val, } break; case 2: /* INSTRETCFGH */ + cfgh = extract64(env->minstretcfg, 32, 32); if (wr_mask) { wr_mask &= ~MINSTRETCFGH_BIT_MINH; - env->minstretcfgh = (new_val & wr_mask) | - (env->minstretcfgh & ~wr_mask); + cfgh = (new_val & wr_mask) | (cfgh & ~wr_mask); + env->minstretcfg = deposit64(env->minstretcfg, 32, 32, cfgh); } else { - *val = env->minstretcfgh; + *val = cfgh; } break; default: -- 2.52.0
From: Anton Johansson <anjo@rev.ng> According to version 20250508 of the privileged specification, mhpmconter is a 64-bit register and mhpmcounterh refers to the top 32 bits of this register when XLEN == 32. No real advantage is gained by keeping them separate, and combining allows for slight simplification. Note, the cpu/pmu VMSTATE version is bumped breaking migration from older versions. Signed-off-by: Anton Johansson <anjo@rev.ng> Reviewed-by: Pierrick Bouvier <pierrick.bouvier@linaro.org> Reviewed-by: Alistair Francis <alistair.francis@wdc.com> Message-ID: <20251027181831.27016-9-anjo@rev.ng> Signed-off-by: Alistair Francis <alistair.francis@wdc.com> Message-ID: <20251103033713.904455-8-alistair.francis@wdc.com> Signed-off-by: Alistair Francis <alistair.francis@wdc.com> --- target/riscv/cpu.h | 10 ++-- target/riscv/csr.c | 76 ++++++++++++++-------------- target/riscv/machine.c | 10 ++-- target/riscv/pmu.c | 111 +++++++++++------------------------------ 4 files changed, 73 insertions(+), 134 deletions(-) diff --git a/target/riscv/cpu.h b/target/riscv/cpu.h index XXXXXXX..XXXXXXX 100644 --- a/target/riscv/cpu.h +++ b/target/riscv/cpu.h @@ -XXX,XX +XXX,XX @@ FIELD(VTYPE, RESERVED, 10, sizeof(target_ulong) * 8 - 11) typedef struct PMUCTRState { /* Current value of a counter */ - target_ulong mhpmcounter_val; - /* Current value of a counter in RV32 */ - target_ulong mhpmcounterh_val; - /* Snapshot values of counter */ - target_ulong mhpmcounter_prev; - /* Snapshort value of a counter in RV32 */ - target_ulong mhpmcounterh_prev; + uint64_t mhpmcounter_val; + /* Snapshot value of a counter */ + uint64_t mhpmcounter_prev; /* Value beyond UINT32_MAX/UINT64_MAX before overflow interrupt trigger */ target_ulong irq_overflow_left; } PMUCTRState; diff --git a/target/riscv/csr.c b/target/riscv/csr.c index XXXXXXX..XXXXXXX 100644 --- a/target/riscv/csr.c +++ b/target/riscv/csr.c @@ -XXX,XX +XXX,XX @@ static RISCVException riscv_pmu_write_ctr(CPURISCVState *env, target_ulong val, uint32_t ctr_idx) { PMUCTRState *counter = &env->pmu_ctrs[ctr_idx]; - uint64_t mhpmctr_val = val; + bool rv32 = riscv_cpu_mxl(env) == MXL_RV32; + int deposit_size = rv32 ? 32 : 64; + uint64_t ctr; + + counter->mhpmcounter_val = deposit64(counter->mhpmcounter_val, + 0, deposit_size, val); - counter->mhpmcounter_val = val; if (!get_field(env->mcountinhibit, BIT(ctr_idx)) && (riscv_pmu_ctr_monitor_cycles(env, ctr_idx) || riscv_pmu_ctr_monitor_instructions(env, ctr_idx))) { - counter->mhpmcounter_prev = riscv_pmu_ctr_get_fixed_counters_val(env, - ctr_idx, false); + ctr = riscv_pmu_ctr_get_fixed_counters_val(env, ctr_idx, false); + counter->mhpmcounter_prev = deposit64(counter->mhpmcounter_prev, + 0, deposit_size, ctr); if (ctr_idx > 2) { - if (riscv_cpu_mxl(env) == MXL_RV32) { - mhpmctr_val = mhpmctr_val | - ((uint64_t)counter->mhpmcounterh_val << 32); - } - riscv_pmu_setup_timer(env, mhpmctr_val, ctr_idx); + riscv_pmu_setup_timer(env, counter->mhpmcounter_val, ctr_idx); } } else { /* Other counters can keep incrementing from the given value */ - counter->mhpmcounter_prev = val; + counter->mhpmcounter_prev = deposit64(counter->mhpmcounter_prev, + 0, deposit_size, val); + } return RISCV_EXCP_NONE; @@ -XXX,XX +XXX,XX @@ static RISCVException riscv_pmu_write_ctrh(CPURISCVState *env, target_ulong val, uint32_t ctr_idx) { PMUCTRState *counter = &env->pmu_ctrs[ctr_idx]; - uint64_t mhpmctr_val = counter->mhpmcounter_val; - uint64_t mhpmctrh_val = val; + uint64_t ctrh; - counter->mhpmcounterh_val = val; - mhpmctr_val = mhpmctr_val | (mhpmctrh_val << 32); + counter->mhpmcounter_val = deposit64(counter->mhpmcounter_val, + 32, 32, val); if (!get_field(env->mcountinhibit, BIT(ctr_idx)) && (riscv_pmu_ctr_monitor_cycles(env, ctr_idx) || riscv_pmu_ctr_monitor_instructions(env, ctr_idx))) { - counter->mhpmcounterh_prev = riscv_pmu_ctr_get_fixed_counters_val(env, - ctr_idx, true); + ctrh = riscv_pmu_ctr_get_fixed_counters_val(env, ctr_idx, true); + counter->mhpmcounter_prev = deposit64(counter->mhpmcounter_prev, + 32, 32, ctrh); if (ctr_idx > 2) { - riscv_pmu_setup_timer(env, mhpmctr_val, ctr_idx); + riscv_pmu_setup_timer(env, counter->mhpmcounter_val, ctr_idx); } } else { - counter->mhpmcounterh_prev = val; + counter->mhpmcounter_prev = deposit64(counter->mhpmcounter_prev, + 32, 32, val); } return RISCV_EXCP_NONE; @@ -XXX,XX +XXX,XX @@ static RISCVException write_mhpmcounterh(CPURISCVState *env, int csrno, } RISCVException riscv_pmu_read_ctr(CPURISCVState *env, target_ulong *val, - bool upper_half, uint32_t ctr_idx) + bool upper_half, uint32_t ctr_idx) { PMUCTRState *counter = &env->pmu_ctrs[ctr_idx]; - target_ulong ctr_prev = upper_half ? counter->mhpmcounterh_prev : - counter->mhpmcounter_prev; - target_ulong ctr_val = upper_half ? counter->mhpmcounterh_val : - counter->mhpmcounter_val; + bool rv32 = riscv_cpu_mxl(env) == MXL_RV32; + int start = upper_half ? 32 : 0; + int length = rv32 ? 32 : 64; + uint64_t ctr_prev, ctr_val; + + /* Ensure upper_half is only set for XLEN == 32 */ + g_assert(rv32 || !upper_half); + + ctr_prev = extract64(counter->mhpmcounter_prev, start, length); + ctr_val = extract64(counter->mhpmcounter_val, start, length); if (get_field(env->mcountinhibit, BIT(ctr_idx))) { /* @@ -XXX,XX +XXX,XX @@ static RISCVException write_mcountinhibit(CPURISCVState *env, int csrno, uint32_t present_ctrs = cpu->pmu_avail_ctrs | COUNTEREN_CY | COUNTEREN_IR; target_ulong updated_ctrs = (env->mcountinhibit ^ val) & present_ctrs; uint64_t mhpmctr_val, prev_count, curr_count; + uint64_t ctrh; /* WARL register - disable unavailable counters; TM bit is always 0 */ env->mcountinhibit = val & present_ctrs; @@ -XXX,XX +XXX,XX @@ static RISCVException write_mcountinhibit(CPURISCVState *env, int csrno, counter->mhpmcounter_prev = riscv_pmu_ctr_get_fixed_counters_val(env, cidx, false); if (riscv_cpu_mxl(env) == MXL_RV32) { - counter->mhpmcounterh_prev = - riscv_pmu_ctr_get_fixed_counters_val(env, cidx, true); + ctrh = riscv_pmu_ctr_get_fixed_counters_val(env, cidx, true); + counter->mhpmcounter_prev = deposit64(counter->mhpmcounter_prev, + 32, 32, ctrh); } if (cidx > 2) { - mhpmctr_val = counter->mhpmcounter_val; - if (riscv_cpu_mxl(env) == MXL_RV32) { - mhpmctr_val = mhpmctr_val | - ((uint64_t)counter->mhpmcounterh_val << 32); - } - riscv_pmu_setup_timer(env, mhpmctr_val, cidx); + riscv_pmu_setup_timer(env, counter->mhpmcounter_val, cidx); } } else { curr_count = riscv_pmu_ctr_get_fixed_counters_val(env, cidx, false); @@ -XXX,XX +XXX,XX @@ static RISCVException write_mcountinhibit(CPURISCVState *env, int csrno, riscv_pmu_ctr_get_fixed_counters_val(env, cidx, true); curr_count = curr_count | (tmp << 32); - mhpmctr_val = mhpmctr_val | - ((uint64_t)counter->mhpmcounterh_val << 32); - prev_count = prev_count | - ((uint64_t)counter->mhpmcounterh_prev << 32); } /* Adjust the counter for later reads. */ mhpmctr_val = curr_count - prev_count + mhpmctr_val; counter->mhpmcounter_val = mhpmctr_val; - if (riscv_cpu_mxl(env) == MXL_RV32) { - counter->mhpmcounterh_val = mhpmctr_val >> 32; - } } } diff --git a/target/riscv/machine.c b/target/riscv/machine.c index XXXXXXX..XXXXXXX 100644 --- a/target/riscv/machine.c +++ b/target/riscv/machine.c @@ -XXX,XX +XXX,XX @@ static bool pmu_needed(void *opaque) static const VMStateDescription vmstate_pmu_ctr_state = { .name = "cpu/pmu", - .version_id = 2, - .minimum_version_id = 2, + .version_id = 3, + .minimum_version_id = 3, .needed = pmu_needed, .fields = (const VMStateField[]) { - VMSTATE_UINTTL(mhpmcounter_val, PMUCTRState), - VMSTATE_UINTTL(mhpmcounterh_val, PMUCTRState), - VMSTATE_UINTTL(mhpmcounter_prev, PMUCTRState), - VMSTATE_UINTTL(mhpmcounterh_prev, PMUCTRState), + VMSTATE_UINT64(mhpmcounter_val, PMUCTRState), + VMSTATE_UINT64(mhpmcounter_prev, PMUCTRState), VMSTATE_END_OF_LIST() } }; diff --git a/target/riscv/pmu.c b/target/riscv/pmu.c index XXXXXXX..XXXXXXX 100644 --- a/target/riscv/pmu.c +++ b/target/riscv/pmu.c @@ -XXX,XX +XXX,XX @@ static bool riscv_pmu_counter_enabled(RISCVCPU *cpu, uint32_t ctr_idx) } } -static int riscv_pmu_incr_ctr_rv32(RISCVCPU *cpu, uint32_t ctr_idx) -{ - CPURISCVState *env = &cpu->env; - target_ulong max_val = UINT32_MAX; - PMUCTRState *counter = &env->pmu_ctrs[ctr_idx]; - bool virt_on = env->virt_enabled; - - /* Privilege mode filtering */ - if ((env->priv == PRV_M && - (env->mhpmevent_val[ctr_idx] & MHPMEVENT_BIT_MINH)) || - (env->priv == PRV_S && virt_on && - (env->mhpmevent_val[ctr_idx] & MHPMEVENT_BIT_VSINH)) || - (env->priv == PRV_U && virt_on && - (env->mhpmevent_val[ctr_idx] & MHPMEVENT_BIT_VUINH)) || - (env->priv == PRV_S && !virt_on && - (env->mhpmevent_val[ctr_idx] & MHPMEVENT_BIT_SINH)) || - (env->priv == PRV_U && !virt_on && - (env->mhpmevent_val[ctr_idx] & MHPMEVENT_BIT_UINH))) { - return 0; - } - - /* Handle the overflow scenario */ - if (counter->mhpmcounter_val == max_val) { - if (counter->mhpmcounterh_val == max_val) { - counter->mhpmcounter_val = 0; - counter->mhpmcounterh_val = 0; - /* Generate interrupt only if OF bit is clear */ - if (!(env->mhpmevent_val[ctr_idx] & MHPMEVENT_BIT_OF)) { - env->mhpmevent_val[ctr_idx] |= MHPMEVENT_BIT_OF; - riscv_cpu_update_mip(env, MIP_LCOFIP, BOOL_TO_MASK(1)); - } - } else { - counter->mhpmcounterh_val++; - } - } else { - counter->mhpmcounter_val++; - } - - return 0; -} - -static int riscv_pmu_incr_ctr_rv64(RISCVCPU *cpu, uint32_t ctr_idx) -{ - CPURISCVState *env = &cpu->env; - PMUCTRState *counter = &env->pmu_ctrs[ctr_idx]; - uint64_t max_val = UINT64_MAX; - bool virt_on = env->virt_enabled; - - /* Privilege mode filtering */ - if ((env->priv == PRV_M && - (env->mhpmevent_val[ctr_idx] & MHPMEVENT_BIT_MINH)) || - (env->priv == PRV_S && virt_on && - (env->mhpmevent_val[ctr_idx] & MHPMEVENT_BIT_VSINH)) || - (env->priv == PRV_U && virt_on && - (env->mhpmevent_val[ctr_idx] & MHPMEVENT_BIT_VUINH)) || - (env->priv == PRV_S && !virt_on && - (env->mhpmevent_val[ctr_idx] & MHPMEVENT_BIT_SINH)) || - (env->priv == PRV_U && !virt_on && - (env->mhpmevent_val[ctr_idx] & MHPMEVENT_BIT_UINH))) { - return 0; - } - - /* Handle the overflow scenario */ - if (counter->mhpmcounter_val == max_val) { - counter->mhpmcounter_val = 0; - /* Generate interrupt only if OF bit is clear */ - if (!(env->mhpmevent_val[ctr_idx] & MHPMEVENT_BIT_OF)) { - env->mhpmevent_val[ctr_idx] |= MHPMEVENT_BIT_OF; - riscv_cpu_update_mip(env, MIP_LCOFIP, BOOL_TO_MASK(1)); - } - } else { - counter->mhpmcounter_val++; - } - return 0; -} - /* * Information needed to update counters: * new_priv, new_virt: To correctly save starting snapshot for the newly @@ -XXX,XX +XXX,XX @@ void riscv_pmu_update_fixed_ctrs(CPURISCVState *env, target_ulong newpriv, int riscv_pmu_incr_ctr(RISCVCPU *cpu, enum riscv_pmu_event_idx event_idx) { uint32_t ctr_idx; - int ret; CPURISCVState *env = &cpu->env; + uint64_t max_val = UINT64_MAX; + bool virt_on = env->virt_enabled; + PMUCTRState *counter; gpointer value; if (!cpu->cfg.pmu_mask) { @@ -XXX,XX +XXX,XX @@ int riscv_pmu_incr_ctr(RISCVCPU *cpu, enum riscv_pmu_event_idx event_idx) return -1; } - if (riscv_cpu_mxl(env) == MXL_RV32) { - ret = riscv_pmu_incr_ctr_rv32(cpu, ctr_idx); + /* Privilege mode filtering */ + if ((env->priv == PRV_M && + (env->mhpmevent_val[ctr_idx] & MHPMEVENT_BIT_MINH)) || + (env->priv == PRV_S && virt_on && + (env->mhpmevent_val[ctr_idx] & MHPMEVENT_BIT_VSINH)) || + (env->priv == PRV_U && virt_on && + (env->mhpmevent_val[ctr_idx] & MHPMEVENT_BIT_VUINH)) || + (env->priv == PRV_S && !virt_on && + (env->mhpmevent_val[ctr_idx] & MHPMEVENT_BIT_SINH)) || + (env->priv == PRV_U && !virt_on && + (env->mhpmevent_val[ctr_idx] & MHPMEVENT_BIT_UINH))) { + return 0; + } + + /* Handle the overflow scenario */ + counter = &env->pmu_ctrs[ctr_idx]; + if (counter->mhpmcounter_val == max_val) { + counter->mhpmcounter_val = 0; + /* Generate interrupt only if OF bit is clear */ + if (!(env->mhpmevent_val[ctr_idx] & MHPMEVENT_BIT_OF)) { + env->mhpmevent_val[ctr_idx] |= MHPMEVENT_BIT_OF; + riscv_cpu_update_mip(env, MIP_LCOFIP, BOOL_TO_MASK(1)); + } } else { - ret = riscv_pmu_incr_ctr_rv64(cpu, ctr_idx); + counter->mhpmcounter_val++; } - return ret; + return 0; } bool riscv_pmu_ctr_monitor_instructions(CPURISCVState *env, @@ -XXX,XX +XXX,XX @@ static void pmu_timer_trigger_irq(RISCVCPU *cpu, if (riscv_cpu_mxl(env) == MXL_RV32) { riscv_pmu_read_ctr(env, (target_ulong *)&curr_ctrh_val, true, ctr_idx); curr_ctr_val = curr_ctr_val | (curr_ctrh_val << 32); - ctr_val = ctr_val | - ((uint64_t)counter->mhpmcounterh_val << 32); } /* -- 2.52.0
From: Alistair Francis <alistair.francis@wdc.com> Now that mhpmcounter is always a 64-bit value we can remove the upper_half argument from riscv_pmu_ctr_get_fixed_counters_val() and always return a 64-bit value. Signed-off-by: Alistair Francis <alistair.francis@wdc.com> Reviewed-by: Anton Johansson <anjo@rev.ng> Reviewed-by: Philippe Mathieu-Daudé <philmd@linaro.org> Message-ID: <20251103033713.904455-9-alistair.francis@wdc.com> Signed-off-by: Alistair Francis <alistair.francis@wdc.com> --- target/riscv/csr.c | 40 +++++++++------------------------------- 1 file changed, 9 insertions(+), 31 deletions(-) diff --git a/target/riscv/csr.c b/target/riscv/csr.c index XXXXXXX..XXXXXXX 100644 --- a/target/riscv/csr.c +++ b/target/riscv/csr.c @@ -XXX,XX +XXX,XX @@ static RISCVException write_mhpmeventh(CPURISCVState *env, int csrno, return RISCV_EXCP_NONE; } -static target_ulong riscv_pmu_ctr_get_fixed_counters_val(CPURISCVState *env, - int counter_idx, - bool upper_half) +static uint64_t riscv_pmu_ctr_get_fixed_counters_val(CPURISCVState *env, + int counter_idx) { int inst = riscv_pmu_ctr_monitor_instructions(env, counter_idx); uint64_t *counter_arr_virt = env->pmu_fixed_ctrs[inst].counter_virt; uint64_t *counter_arr = env->pmu_fixed_ctrs[inst].counter; - target_ulong result = 0; uint64_t curr_val = 0; uint64_t cfg_val = 0; @@ -XXX,XX +XXX,XX @@ static target_ulong riscv_pmu_ctr_get_fixed_counters_val(CPURISCVState *env, curr_val = cpu_get_host_ticks(); } - goto done; + return curr_val; } /* Update counter before reading. */ @@ -XXX,XX +XXX,XX @@ static target_ulong riscv_pmu_ctr_get_fixed_counters_val(CPURISCVState *env, curr_val += counter_arr_virt[PRV_U]; } -done: - if (riscv_cpu_mxl(env) == MXL_RV32) { - result = upper_half ? curr_val >> 32 : curr_val; - } else { - result = curr_val; - } - - return result; + return curr_val; } static RISCVException riscv_pmu_write_ctr(CPURISCVState *env, target_ulong val, @@ -XXX,XX +XXX,XX @@ static RISCVException riscv_pmu_write_ctr(CPURISCVState *env, target_ulong val, if (!get_field(env->mcountinhibit, BIT(ctr_idx)) && (riscv_pmu_ctr_monitor_cycles(env, ctr_idx) || riscv_pmu_ctr_monitor_instructions(env, ctr_idx))) { - ctr = riscv_pmu_ctr_get_fixed_counters_val(env, ctr_idx, false); + ctr = riscv_pmu_ctr_get_fixed_counters_val(env, ctr_idx); counter->mhpmcounter_prev = deposit64(counter->mhpmcounter_prev, 0, deposit_size, ctr); if (ctr_idx > 2) { @@ -XXX,XX +XXX,XX @@ static RISCVException riscv_pmu_write_ctrh(CPURISCVState *env, target_ulong val, if (!get_field(env->mcountinhibit, BIT(ctr_idx)) && (riscv_pmu_ctr_monitor_cycles(env, ctr_idx) || riscv_pmu_ctr_monitor_instructions(env, ctr_idx))) { - ctrh = riscv_pmu_ctr_get_fixed_counters_val(env, ctr_idx, true); + ctrh = riscv_pmu_ctr_get_fixed_counters_val(env, ctr_idx); counter->mhpmcounter_prev = deposit64(counter->mhpmcounter_prev, 32, 32, ctrh); if (ctr_idx > 2) { @@ -XXX,XX +XXX,XX @@ RISCVException riscv_pmu_read_ctr(CPURISCVState *env, target_ulong *val, */ if (riscv_pmu_ctr_monitor_cycles(env, ctr_idx) || riscv_pmu_ctr_monitor_instructions(env, ctr_idx)) { - *val = riscv_pmu_ctr_get_fixed_counters_val(env, ctr_idx, upper_half) - + *val = riscv_pmu_ctr_get_fixed_counters_val(env, ctr_idx) - ctr_prev + ctr_val; } else { *val = ctr_val; @@ -XXX,XX +XXX,XX @@ static RISCVException write_mcountinhibit(CPURISCVState *env, int csrno, uint32_t present_ctrs = cpu->pmu_avail_ctrs | COUNTEREN_CY | COUNTEREN_IR; target_ulong updated_ctrs = (env->mcountinhibit ^ val) & present_ctrs; uint64_t mhpmctr_val, prev_count, curr_count; - uint64_t ctrh; /* WARL register - disable unavailable counters; TM bit is always 0 */ env->mcountinhibit = val & present_ctrs; @@ -XXX,XX +XXX,XX @@ static RISCVException write_mcountinhibit(CPURISCVState *env, int csrno, counter = &env->pmu_ctrs[cidx]; if (!get_field(env->mcountinhibit, BIT(cidx))) { - counter->mhpmcounter_prev = - riscv_pmu_ctr_get_fixed_counters_val(env, cidx, false); - if (riscv_cpu_mxl(env) == MXL_RV32) { - ctrh = riscv_pmu_ctr_get_fixed_counters_val(env, cidx, true); - counter->mhpmcounter_prev = deposit64(counter->mhpmcounter_prev, - 32, 32, ctrh); - } + counter->mhpmcounter_prev = riscv_pmu_ctr_get_fixed_counters_val(env, cidx); if (cidx > 2) { riscv_pmu_setup_timer(env, counter->mhpmcounter_val, cidx); } } else { - curr_count = riscv_pmu_ctr_get_fixed_counters_val(env, cidx, false); + curr_count = riscv_pmu_ctr_get_fixed_counters_val(env, cidx); mhpmctr_val = counter->mhpmcounter_val; prev_count = counter->mhpmcounter_prev; - if (riscv_cpu_mxl(env) == MXL_RV32) { - uint64_t tmp = - riscv_pmu_ctr_get_fixed_counters_val(env, cidx, true); - - curr_count = curr_count | (tmp << 32); - } /* Adjust the counter for later reads. */ mhpmctr_val = curr_count - prev_count + mhpmctr_val; -- 2.52.0
From: Nikita Novikov <n.novikov@syntacore.com> According to the RISC-V AIA v1.0, section 4.5.2 ("Source configurations"), register target[i] shall be read-only zero when interrupt source i is inactive in this domain. A source is inactive if it is delegated to a child domain or its source mode is INACTIVE. The previous implementation only checked SM == INACTIVE. This patch adds full compliance: - Return zero on read if D == 1 or SM == INACTIVE - Ignore writes in both cases Fixes: b6f1244678 ("intc/riscv_aplic: Fix target register read when source is inactive") Signed-off-by: Nikita Novikov <n.novikov@syntacore.com> Acked-by: Alistair Francis <alistair.francis@wdc.com> Reviewed-by: Daniel Henrique Barboza <dbarboza@ventanamicro.com> Message-ID: <20251029-n-novikov-aplic_aia_ro-v1-1-39fec74c918a@syntacore.com> Signed-off-by: Alistair Francis <alistair.francis@wdc.com> --- hw/intc/riscv_aplic.c | 28 +++++++++++++++++++++++++--- 1 file changed, 25 insertions(+), 3 deletions(-) diff --git a/hw/intc/riscv_aplic.c b/hw/intc/riscv_aplic.c index XXXXXXX..XXXXXXX 100644 --- a/hw/intc/riscv_aplic.c +++ b/hw/intc/riscv_aplic.c @@ -XXX,XX +XXX,XX @@ void riscv_aplic_set_kvm_msicfgaddr(RISCVAPLICState *aplic, hwaddr addr) #endif } +/* + * APLIC target[i] must be read-only zero if the source i is inactive + * in this domain (delegated or SM == INACTIVE) + */ +static inline bool riscv_aplic_source_active(RISCVAPLICState *aplic, + uint32_t irq) +{ + uint32_t sc, sm; + + if ((irq == 0) || (aplic->num_irqs <= irq)) { + return false; + } + sc = aplic->sourcecfg[irq]; + if (sc & APLIC_SOURCECFG_D) { + return false; + } + sm = sc & APLIC_SOURCECFG_SM_MASK; + return sm != APLIC_SOURCECFG_SM_INACTIVE; +} + static bool riscv_aplic_irq_rectified_val(RISCVAPLICState *aplic, uint32_t irq) { @@ -XXX,XX +XXX,XX @@ static void riscv_aplic_request(void *opaque, int irq, int level) static uint64_t riscv_aplic_read(void *opaque, hwaddr addr, unsigned size) { - uint32_t irq, word, idc, sm; + uint32_t irq, word, idc; RISCVAPLICState *aplic = opaque; /* Reads must be 4 byte words */ @@ -XXX,XX +XXX,XX @@ static uint64_t riscv_aplic_read(void *opaque, hwaddr addr, unsigned size) } else if ((APLIC_TARGET_BASE <= addr) && (addr < (APLIC_TARGET_BASE + (aplic->num_irqs - 1) * 4))) { irq = ((addr - APLIC_TARGET_BASE) >> 2) + 1; - sm = aplic->sourcecfg[irq] & APLIC_SOURCECFG_SM_MASK; - if (sm == APLIC_SOURCECFG_SM_INACTIVE) { + if (!riscv_aplic_source_active(aplic, irq)) { return 0; } return aplic->target[irq]; @@ -XXX,XX +XXX,XX @@ static void riscv_aplic_write(void *opaque, hwaddr addr, uint64_t value, } else if ((APLIC_TARGET_BASE <= addr) && (addr < (APLIC_TARGET_BASE + (aplic->num_irqs - 1) * 4))) { irq = ((addr - APLIC_TARGET_BASE) >> 2) + 1; + if (!riscv_aplic_source_active(aplic, irq)) { + return; + } if (aplic->msimode) { aplic->target[irq] = value; } else { -- 2.52.0
From: Nikita Novikov <n.novikov@syntacore.com> Refactor the APLIC code to consolidate repeated conditions checking whether an interrupt source is valid, delegated, or inactive. Signed-off-by: Nikita Novikov <n.novikov@syntacore.com> Reviewed-by: Alistair Francis <alistair.francis@wdc.com> Reviewed-by: Daniel Henrique Barboza <dbarboza@ventanamicro.com> Message-ID: <20251029-n-novikov-aplic_aia_ro-v1-2-39fec74c918a@syntacore.com> Signed-off-by: Alistair Francis <alistair.francis@wdc.com> --- hw/intc/riscv_aplic.c | 44 +++++++------------------------------------ 1 file changed, 7 insertions(+), 37 deletions(-) diff --git a/hw/intc/riscv_aplic.c b/hw/intc/riscv_aplic.c index XXXXXXX..XXXXXXX 100644 --- a/hw/intc/riscv_aplic.c +++ b/hw/intc/riscv_aplic.c @@ -XXX,XX +XXX,XX @@ static inline bool riscv_aplic_source_active(RISCVAPLICState *aplic, static bool riscv_aplic_irq_rectified_val(RISCVAPLICState *aplic, uint32_t irq) { - uint32_t sourcecfg, sm, raw_input, irq_inverted; + uint32_t sm, raw_input, irq_inverted; - if (!irq || aplic->num_irqs <= irq) { - return false; - } - - sourcecfg = aplic->sourcecfg[irq]; - if (sourcecfg & APLIC_SOURCECFG_D) { - return false; - } - - sm = sourcecfg & APLIC_SOURCECFG_SM_MASK; - if (sm == APLIC_SOURCECFG_SM_INACTIVE) { + if (!riscv_aplic_source_active(aplic, irq)) { return false; } + sm = aplic->sourcecfg[irq] & APLIC_SOURCECFG_SM_MASK; raw_input = (aplic->state[irq] & APLIC_ISTATE_INPUT) ? 1 : 0; irq_inverted = (sm == APLIC_SOURCECFG_SM_LEVEL_LOW || sm == APLIC_SOURCECFG_SM_EDGE_FALL) ? 1 : 0; @@ -XXX,XX +XXX,XX @@ static void riscv_aplic_set_pending_raw(RISCVAPLICState *aplic, static void riscv_aplic_set_pending(RISCVAPLICState *aplic, uint32_t irq, bool pending) { - uint32_t sourcecfg, sm; + uint32_t sm; - if ((irq <= 0) || (aplic->num_irqs <= irq)) { - return; - } - - sourcecfg = aplic->sourcecfg[irq]; - if (sourcecfg & APLIC_SOURCECFG_D) { - return; - } - - sm = sourcecfg & APLIC_SOURCECFG_SM_MASK; - if (sm == APLIC_SOURCECFG_SM_INACTIVE) { + if (!riscv_aplic_source_active(aplic, irq)) { return; } + sm = aplic->sourcecfg[irq] & APLIC_SOURCECFG_SM_MASK; if ((sm == APLIC_SOURCECFG_SM_LEVEL_HIGH) || (sm == APLIC_SOURCECFG_SM_LEVEL_LOW)) { if (!aplic->msimode) { @@ -XXX,XX +XXX,XX @@ static void riscv_aplic_set_enabled_raw(RISCVAPLICState *aplic, static void riscv_aplic_set_enabled(RISCVAPLICState *aplic, uint32_t irq, bool enabled) { - uint32_t sourcecfg, sm; - - if ((irq <= 0) || (aplic->num_irqs <= irq)) { - return; - } - - sourcecfg = aplic->sourcecfg[irq]; - if (sourcecfg & APLIC_SOURCECFG_D) { - return; - } - - sm = sourcecfg & APLIC_SOURCECFG_SM_MASK; - if (sm == APLIC_SOURCECFG_SM_INACTIVE) { + if (!riscv_aplic_source_active(aplic, irq)) { return; } -- 2.52.0
From: Frank Chang <frank.chang@sifive.com> According to the RISC-V IOMMU specification: * When ddtp.iommu_mode is set to Off, there is no DDT look-up, and an "All inbound transactions disallowed" fault (cause = 256) is reported for any inbound transaction. * When ddtp.iommu_mode is set to Bare, there is no DDT look-up, and the translated address is the same as the IOVA, unless the transaction type is disallowed (cause = 260). In the current implementation, the DDT cache is incorrectly looked up even when ddtp.iommu_mode is set to Off or Bare. This may result in unintended cache hits. Therefore, the DDT cache must not be looked up when ddtp.iommu_mode is set to Off or Bare. For other modes, software is required to issue cache invalidation commands before any inbound transactions. Signed-off-by: Frank Chang <frank.chang@sifive.com> Acked-by: Alistair Francis <alistair.francis@wdc.com> Reviewed-by: Daniel Henrique Barboza <dbarboza@ventanamicro.com> Reviewed-by: Jim Shu <jim.shu@sifive.com> Message-ID: <20251028085032.2053569-1-frank.chang@sifive.com> Signed-off-by: Alistair Francis <alistair.francis@wdc.com> --- hw/riscv/riscv-iommu.c | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/hw/riscv/riscv-iommu.c b/hw/riscv/riscv-iommu.c index XXXXXXX..XXXXXXX 100644 --- a/hw/riscv/riscv-iommu.c +++ b/hw/riscv/riscv-iommu.c @@ -XXX,XX +XXX,XX @@ static RISCVIOMMUContext *riscv_iommu_ctx(RISCVIOMMUState *s, .devid = devid, .process_id = process_id, }; + unsigned mode = get_field(s->ddtp, RISCV_IOMMU_DDTP_MODE); ctx_cache = g_hash_table_ref(s->ctx_cache); - ctx = g_hash_table_lookup(ctx_cache, &key); - if (ctx && (ctx->tc & RISCV_IOMMU_DC_TC_V)) { - *ref = ctx_cache; - return ctx; + if (mode != RISCV_IOMMU_DDTP_MODE_OFF && + mode != RISCV_IOMMU_DDTP_MODE_BARE) { + ctx = g_hash_table_lookup(ctx_cache, &key); + + if (ctx && (ctx->tc & RISCV_IOMMU_DC_TC_V)) { + *ref = ctx_cache; + return ctx; + } } ctx = g_new0(RISCVIOMMUContext, 1); -- 2.52.0
From: lxx <1733205434@qq.com> This patch adds support for the Zilsd and Zclsd extension, which is documented at https://github.com/riscv/riscv-zilsd/releases/tag/v1.0 Signed-off-by: LIU Xu <liuxu@nucleisys.com> Co-developed-by: SUN Dongya <sundongya@nucleisys.com> Co-developed-by: ZHAO Fujin <zhaofujin@nucleisys.com> Reviewed-by: Alistair Francis <alistair.francis@wdc.com> Message-ID: <176154834968.21563.217396575391240410-1@git.sr.ht> Signed-off-by: Alistair Francis <alistair.francis@wdc.com> --- target/riscv/cpu_cfg_fields.h.inc | 2 + target/riscv/insn16.decode | 8 ++ target/riscv/insn32.decode | 12 ++- target/riscv/cpu.c | 4 + target/riscv/tcg/tcg-cpu.c | 33 +++++++ target/riscv/translate.c | 1 + target/riscv/insn_trans/trans_zilsd.c.inc | 105 ++++++++++++++++++++++ 7 files changed, 163 insertions(+), 2 deletions(-) create mode 100644 target/riscv/insn_trans/trans_zilsd.c.inc diff --git a/target/riscv/cpu_cfg_fields.h.inc b/target/riscv/cpu_cfg_fields.h.inc index XXXXXXX..XXXXXXX 100644 --- a/target/riscv/cpu_cfg_fields.h.inc +++ b/target/riscv/cpu_cfg_fields.h.inc @@ -XXX,XX +XXX,XX @@ BOOL_FIELD(ext_zce) BOOL_FIELD(ext_zcf) BOOL_FIELD(ext_zcmp) BOOL_FIELD(ext_zcmt) +BOOL_FIELD(ext_zclsd) BOOL_FIELD(ext_zk) BOOL_FIELD(ext_zkn) BOOL_FIELD(ext_zknd) @@ -XXX,XX +XXX,XX @@ BOOL_FIELD(ext_zicond) BOOL_FIELD(ext_zihintntl) BOOL_FIELD(ext_zihintpause) BOOL_FIELD(ext_zihpm) +BOOL_FIELD(ext_zilsd) BOOL_FIELD(ext_zimop) BOOL_FIELD(ext_zcmop) BOOL_FIELD(ext_ztso) diff --git a/target/riscv/insn16.decode b/target/riscv/insn16.decode index XXXXXXX..XXXXXXX 100644 --- a/target/riscv/insn16.decode +++ b/target/riscv/insn16.decode @@ -XXX,XX +XXX,XX @@ sw 110 ... ... .. ... 00 @cs_w { ld 011 ... ... .. ... 00 @cl_d c_flw 011 ... ... .. ... 00 @cl_w + # *** Zclsd Extension *** + zclsd_ld 011 ... ... .. ... 00 @cl_d } { sd 111 ... ... .. ... 00 @cs_d c_fsw 111 ... ... .. ... 00 @cs_w + # *** Zclsd Extension *** + zclsd_sd 111 ... ... .. ... 00 @cs_d } # *** RV32/64C Standard Extension (Quadrant 1) *** @@ -XXX,XX +XXX,XX @@ sw 110 . ..... ..... 10 @c_swsp c64_illegal 011 - 00000 ----- 10 # c.ldsp, RES rd=0 ld 011 . ..... ..... 10 @c_ldsp c_flw 011 . ..... ..... 10 @c_lwsp + # *** Zclsd Extension *** + zclsd_ldsp 011 . ..... ..... 10 @c_ldsp } { sd 111 . ..... ..... 10 @c_sdsp c_fsw 111 . ..... ..... 10 @c_swsp + # *** Zclsd Extension *** + zclsd_sd 111 . ..... ..... 10 @c_sdsp } # *** RV64 and RV32 Zcb Extension *** diff --git a/target/riscv/insn32.decode b/target/riscv/insn32.decode index XXXXXXX..XXXXXXX 100644 --- a/target/riscv/insn32.decode +++ b/target/riscv/insn32.decode @@ -XXX,XX +XXX,XX @@ csrrci ............ ..... 111 ..... 1110011 @csr # *** RV64I Base Instruction Set (in addition to RV32I) *** lwu ............ ..... 110 ..... 0000011 @i -ld ............ ..... 011 ..... 0000011 @i -sd ....... ..... ..... 011 ..... 0100011 @s +{ + ld ............ ..... 011 ..... 0000011 @i + # *** Zilsd instructions *** + zilsd_ld ............ ..... 011 ..... 0000011 @i +} +{ + sd ....... ..... ..... 011 ..... 0100011 @s + # *** Zilsd instructions *** + zilsd_sd ....... ..... ..... 011 ..... 0100011 @s +} addiw ............ ..... 000 ..... 0011011 @i slliw 0000000 ..... ..... 001 ..... 0011011 @sh5 srliw 0000000 ..... ..... 101 ..... 0011011 @sh5 diff --git a/target/riscv/cpu.c b/target/riscv/cpu.c index XXXXXXX..XXXXXXX 100644 --- a/target/riscv/cpu.c +++ b/target/riscv/cpu.c @@ -XXX,XX +XXX,XX @@ const RISCVIsaExtData isa_edata_arr[] = { ISA_EXT_DATA_ENTRY(zihintntl, PRIV_VERSION_1_10_0, ext_zihintntl), ISA_EXT_DATA_ENTRY(zihintpause, PRIV_VERSION_1_10_0, ext_zihintpause), ISA_EXT_DATA_ENTRY(zihpm, PRIV_VERSION_1_12_0, ext_zihpm), + ISA_EXT_DATA_ENTRY(zilsd, PRIV_VERSION_1_12_0, ext_zilsd), ISA_EXT_DATA_ENTRY(zimop, PRIV_VERSION_1_13_0, ext_zimop), ISA_EXT_DATA_ENTRY(zmmul, PRIV_VERSION_1_12_0, ext_zmmul), ISA_EXT_DATA_ENTRY(za64rs, PRIV_VERSION_1_12_0, has_priv_1_12), @@ -XXX,XX +XXX,XX @@ const RISCVIsaExtData isa_edata_arr[] = { ISA_EXT_DATA_ENTRY(zcmop, PRIV_VERSION_1_13_0, ext_zcmop), ISA_EXT_DATA_ENTRY(zcmp, PRIV_VERSION_1_12_0, ext_zcmp), ISA_EXT_DATA_ENTRY(zcmt, PRIV_VERSION_1_12_0, ext_zcmt), + ISA_EXT_DATA_ENTRY(zclsd, PRIV_VERSION_1_12_0, ext_zclsd), ISA_EXT_DATA_ENTRY(zba, PRIV_VERSION_1_12_0, ext_zba), ISA_EXT_DATA_ENTRY(zbb, PRIV_VERSION_1_12_0, ext_zbb), ISA_EXT_DATA_ENTRY(zbc, PRIV_VERSION_1_12_0, ext_zbc), @@ -XXX,XX +XXX,XX @@ const RISCVCPUMultiExtConfig riscv_cpu_extensions[] = { MULTI_EXT_CFG_BOOL("zicntr", ext_zicntr, true), MULTI_EXT_CFG_BOOL("zihpm", ext_zihpm, true), + MULTI_EXT_CFG_BOOL("zilsd", ext_zilsd, false), MULTI_EXT_CFG_BOOL("zba", ext_zba, true), MULTI_EXT_CFG_BOOL("zbb", ext_zbb, true), @@ -XXX,XX +XXX,XX @@ const RISCVCPUMultiExtConfig riscv_cpu_extensions[] = { MULTI_EXT_CFG_BOOL("zcmp", ext_zcmp, false), MULTI_EXT_CFG_BOOL("zcmt", ext_zcmt, false), MULTI_EXT_CFG_BOOL("zicond", ext_zicond, false), + MULTI_EXT_CFG_BOOL("zclsd", ext_zclsd, false), /* Vector cryptography extensions */ MULTI_EXT_CFG_BOOL("zvbb", ext_zvbb, false), diff --git a/target/riscv/tcg/tcg-cpu.c b/target/riscv/tcg/tcg-cpu.c index XXXXXXX..XXXXXXX 100644 --- a/target/riscv/tcg/tcg-cpu.c +++ b/target/riscv/tcg/tcg-cpu.c @@ -XXX,XX +XXX,XX @@ void riscv_cpu_validate_set_extensions(RISCVCPU *cpu, Error **errp) cpu->pmu_avail_ctrs = 0; } + if (cpu->cfg.ext_zclsd) { + if (riscv_has_ext(env, RVC) && riscv_has_ext(env, RVF)) { + error_setg(errp, + "Zclsd cannot be supported together with C and F extension"); + return; + } + if (cpu->cfg.ext_zcf) { + error_setg(errp, + "Zclsd cannot be supported together with Zcf extension"); + return; + } + } + if (cpu->cfg.ext_zicfilp && !cpu->cfg.ext_zicsr) { error_setg(errp, "zicfilp extension requires zicsr extension"); return; @@ -XXX,XX +XXX,XX @@ static void cpu_enable_zc_implied_rules(RISCVCPU *cpu) } } +static void cpu_enable_zilsd_implied_rules(RISCVCPU *cpu) +{ + CPURISCVState *env = &cpu->env; + + if (cpu->cfg.ext_zilsd && riscv_has_ext(env, RVC)) { + cpu_cfg_ext_auto_update(cpu, CPU_CFG_OFFSET(ext_zclsd), true); + } + + if (cpu->cfg.ext_zclsd) { + cpu_cfg_ext_auto_update(cpu, CPU_CFG_OFFSET(ext_zca), true); + cpu_cfg_ext_auto_update(cpu, CPU_CFG_OFFSET(ext_zilsd), true); + } +} + static void riscv_cpu_enable_implied_rules(RISCVCPU *cpu) { RISCVCPUImpliedExtsRule *rule; @@ -XXX,XX +XXX,XX @@ static void riscv_cpu_enable_implied_rules(RISCVCPU *cpu) /* Enable the implied extensions for Zc. */ cpu_enable_zc_implied_rules(cpu); + /* Enable the implied extensions for Zilsd. */ + cpu_enable_zilsd_implied_rules(cpu); + /* Enable the implied MISAs. */ for (i = 0; (rule = riscv_misa_ext_implied_rules[i]); i++) { if (riscv_has_ext(&cpu->env, rule->ext)) { @@ -XXX,XX +XXX,XX @@ static void riscv_init_max_cpu_extensions(Object *obj) isa_ext_update_enabled(cpu, CPU_CFG_OFFSET(ext_zcmp), false); isa_ext_update_enabled(cpu, CPU_CFG_OFFSET(ext_zcmt), false); + isa_ext_update_enabled(cpu, CPU_CFG_OFFSET(ext_zilsd), false); + isa_ext_update_enabled(cpu, CPU_CFG_OFFSET(ext_zclsd), false); + if (env->misa_mxl != MXL_RV32) { isa_ext_update_enabled(cpu, CPU_CFG_OFFSET(ext_zcf), false); } else { diff --git a/target/riscv/translate.c b/target/riscv/translate.c index XXXXXXX..XXXXXXX 100644 --- a/target/riscv/translate.c +++ b/target/riscv/translate.c @@ -XXX,XX +XXX,XX @@ static uint32_t opcode_at(DisasContextBase *dcbase, target_ulong pc) /* Include the auto-generated decoder for 16 bit insn */ #include "decode-insn16.c.inc" #include "insn_trans/trans_rvzce.c.inc" +#include "insn_trans/trans_zilsd.c.inc" #include "insn_trans/trans_rvzcmop.c.inc" #include "insn_trans/trans_rvzicfiss.c.inc" diff --git a/target/riscv/insn_trans/trans_zilsd.c.inc b/target/riscv/insn_trans/trans_zilsd.c.inc new file mode 100644 index XXXXXXX..XXXXXXX --- /dev/null +++ b/target/riscv/insn_trans/trans_zilsd.c.inc @@ -XXX,XX +XXX,XX @@ +/* + * RISC-V translation routines for the Zilsd & Zclsd Extension. + * + * Copyright (c) 2025 Nucleisys, Inc. + * + * SPDX-License-Identifier: GPL-2.0-or-later + * + * The documentation of the ISA extensions can be found here: + * https://github.com/riscv/riscv-zilsd/releases/tag/v1.0 + */ + +#define REQUIRE_ZILSD(ctx) do { \ + if (!ctx->cfg_ptr->ext_zilsd) \ + return false; \ +} while (0) + +#define REQUIRE_ZCLSD(ctx) do { \ + if (!ctx->cfg_ptr->ext_zclsd) \ + return false; \ +} while (0) + +static bool gen_load_i64(DisasContext *ctx, arg_ld *a) +{ + if ((a->rd) % 2) { + return false; + } + + TCGv dest_low = dest_gpr(ctx, a->rd); + TCGv dest_high = dest_gpr(ctx, a->rd + 1); + TCGv addr = get_address(ctx, a->rs1, a->imm); + TCGv_i64 tmp = tcg_temp_new_i64(); + + tcg_gen_qemu_ld_i64(tmp, addr, ctx->mem_idx, MO_TESQ); + + if (a->rd == 0) { + return true; + } + + tcg_gen_extr_i64_tl(dest_low, dest_high, tmp); + + gen_set_gpr(ctx, a->rd, dest_low); + gen_set_gpr(ctx, a->rd + 1, dest_high); + + return true; +} + +static bool trans_zilsd_ld(DisasContext *ctx, arg_zilsd_ld *a) +{ + REQUIRE_32BIT(ctx); + REQUIRE_ZILSD(ctx); + return gen_load_i64(ctx, a); +} + +static bool trans_zclsd_ld(DisasContext *ctx, arg_zclsd_ld *a) +{ + REQUIRE_32BIT(ctx); + REQUIRE_ZCLSD(ctx); + return gen_load_i64(ctx, a); +} + +static bool trans_zclsd_ldsp(DisasContext *ctx, arg_zclsd_ldsp *a) +{ + REQUIRE_32BIT(ctx); + REQUIRE_ZCLSD(ctx); + + if (a->rd == 0) { + return false; + } + return gen_load_i64(ctx, a); +} + +static bool gen_store_i64(DisasContext *ctx, arg_sd *a) +{ + if ((a->rs2) % 2) { + return false; + } + + TCGv data_low = get_gpr(ctx, a->rs2, EXT_NONE); + TCGv data_high = get_gpr(ctx, a->rs2 + 1, EXT_NONE); + TCGv addr = get_address(ctx, a->rs1, a->imm); + TCGv_i64 tmp = tcg_temp_new_i64(); + + if (a->rs2 == 0) { + tmp = tcg_constant_i64(0); + } else { + tcg_gen_concat_tl_i64(tmp, data_low, data_high); + } + tcg_gen_qemu_st_i64(tmp, addr, ctx->mem_idx, MO_TESQ); + + return true; +} + +static bool trans_zilsd_sd(DisasContext *ctx, arg_zilsd_sd *a) +{ + REQUIRE_32BIT(ctx); + REQUIRE_ZILSD(ctx); + return gen_store_i64(ctx, a); +} + +static bool trans_zclsd_sd(DisasContext *ctx, arg_zclsd_sd *a) +{ + REQUIRE_32BIT(ctx); + REQUIRE_ZCLSD(ctx); + return gen_store_i64(ctx, a); +} -- 2.52.0
From: Roan Richmond <roan.richmond@codethink.co.uk> This is based on version v0.9 of the ZALASR specification [1]. The specification is listed as in Ratified state [2]. [1]: https://github.com/riscv/riscv-zalasr/tree/v0.9 [2]: https://lf-riscv.atlassian.net/wiki/spaces/HOME/pages/16154882/All+RISC-V+Specifications+Under+Active+Development Reviewed-by: Alistair Francis <alistair.francis@wdc.com> Signed-off-by: Roan Richmond <roan.richmond@codethink.co.uk> Message-ID: <20251112162923.311714-1-roan.richmond@codethink.co.uk> Signed-off-by: Alistair Francis <alistair.francis@wdc.com> --- target/riscv/cpu_cfg_fields.h.inc | 1 + target/riscv/insn32.decode | 10 ++ target/riscv/cpu.c | 2 + target/riscv/translate.c | 1 + target/riscv/insn_trans/trans_rvzalasr.c.inc | 113 +++++++++++++++++++ 5 files changed, 127 insertions(+) create mode 100644 target/riscv/insn_trans/trans_rvzalasr.c.inc diff --git a/target/riscv/cpu_cfg_fields.h.inc b/target/riscv/cpu_cfg_fields.h.inc index XXXXXXX..XXXXXXX 100644 --- a/target/riscv/cpu_cfg_fields.h.inc +++ b/target/riscv/cpu_cfg_fields.h.inc @@ -XXX,XX +XXX,XX @@ BOOL_FIELD(ext_zaamo) BOOL_FIELD(ext_zacas) BOOL_FIELD(ext_zama16b) BOOL_FIELD(ext_zabha) +BOOL_FIELD(ext_zalasr) BOOL_FIELD(ext_zalrsc) BOOL_FIELD(ext_zawrs) BOOL_FIELD(ext_zfa) diff --git a/target/riscv/insn32.decode b/target/riscv/insn32.decode index XXXXXXX..XXXXXXX 100644 --- a/target/riscv/insn32.decode +++ b/target/riscv/insn32.decode @@ -XXX,XX +XXX,XX @@ amominu_h 11000 . . ..... ..... 001 ..... 0101111 @atom_st amomaxu_h 11100 . . ..... ..... 001 ..... 0101111 @atom_st amocas_b 00101 . . ..... ..... 000 ..... 0101111 @atom_st amocas_h 00101 . . ..... ..... 001 ..... 0101111 @atom_st + +# *** Zalasr Standard Extension *** +lb_aqrl 00110 . . ..... ..... 000 ..... 0101111 @atom_st +lh_aqrl 00110 . . ..... ..... 001 ..... 0101111 @atom_st +lw_aqrl 00110 . . ..... ..... 010 ..... 0101111 @atom_st +ld_aqrl 00110 . . ..... ..... 011 ..... 0101111 @atom_st +sb_aqrl 00111 . . ..... ..... 000 ..... 0101111 @atom_st +sh_aqrl 00111 . . ..... ..... 001 ..... 0101111 @atom_st +sw_aqrl 00111 . . ..... ..... 010 ..... 0101111 @atom_st +sd_aqrl 00111 . . ..... ..... 011 ..... 0101111 @atom_st diff --git a/target/riscv/cpu.c b/target/riscv/cpu.c index XXXXXXX..XXXXXXX 100644 --- a/target/riscv/cpu.c +++ b/target/riscv/cpu.c @@ -XXX,XX +XXX,XX @@ const RISCVIsaExtData isa_edata_arr[] = { ISA_EXT_DATA_ENTRY(zaamo, PRIV_VERSION_1_12_0, ext_zaamo), ISA_EXT_DATA_ENTRY(zabha, PRIV_VERSION_1_13_0, ext_zabha), ISA_EXT_DATA_ENTRY(zacas, PRIV_VERSION_1_12_0, ext_zacas), + ISA_EXT_DATA_ENTRY(zalasr, PRIV_VERSION_1_12_0, ext_zalasr), ISA_EXT_DATA_ENTRY(zalrsc, PRIV_VERSION_1_12_0, ext_zalrsc), ISA_EXT_DATA_ENTRY(zama16b, PRIV_VERSION_1_13_0, ext_zama16b), ISA_EXT_DATA_ENTRY(zawrs, PRIV_VERSION_1_12_0, ext_zawrs), @@ -XXX,XX +XXX,XX @@ const RISCVCPUMultiExtConfig riscv_cpu_extensions[] = { MULTI_EXT_CFG_BOOL("zama16b", ext_zama16b, false), MULTI_EXT_CFG_BOOL("zabha", ext_zabha, false), MULTI_EXT_CFG_BOOL("zaamo", ext_zaamo, false), + MULTI_EXT_CFG_BOOL("zalasr", ext_zalasr, false), MULTI_EXT_CFG_BOOL("zalrsc", ext_zalrsc, false), MULTI_EXT_CFG_BOOL("zawrs", ext_zawrs, true), MULTI_EXT_CFG_BOOL("zfa", ext_zfa, true), diff --git a/target/riscv/translate.c b/target/riscv/translate.c index XXXXXXX..XXXXXXX 100644 --- a/target/riscv/translate.c +++ b/target/riscv/translate.c @@ -XXX,XX +XXX,XX @@ static uint32_t opcode_at(DisasContextBase *dcbase, target_ulong pc) #include "insn_trans/trans_rvzicond.c.inc" #include "insn_trans/trans_rvzacas.c.inc" #include "insn_trans/trans_rvzabha.c.inc" +#include "insn_trans/trans_rvzalasr.c.inc" #include "insn_trans/trans_rvzawrs.c.inc" #include "insn_trans/trans_rvzicbo.c.inc" #include "insn_trans/trans_rvzimop.c.inc" diff --git a/target/riscv/insn_trans/trans_rvzalasr.c.inc b/target/riscv/insn_trans/trans_rvzalasr.c.inc new file mode 100644 index XXXXXXX..XXXXXXX --- /dev/null +++ b/target/riscv/insn_trans/trans_rvzalasr.c.inc @@ -XXX,XX +XXX,XX @@ +/* + * RISC-V translation routines for the ZALASR (Load-Aquire and Store-Release) + * Extension. + * + * Copyright (c) 2025 Roan Richmond, roan.richmond@codethink.co.uk + * + * SPDX-License-Identifier: GPL-2.0-or-later + * + * The documentation of the ISA extension can be found here: + * https://github.com/riscv/riscv-zalasr/tree/v0.9 + */ + +#define REQUIRE_ZALASR(ctx) do { \ + if (!ctx->cfg_ptr->ext_zalasr) { \ + return false; \ + } \ +} while (0) + +static bool gen_load_acquire(DisasContext *ctx, arg_lb_aqrl *a, MemOp memop) +{ + decode_save_opc(ctx, 0); + + TCGv addr = get_address(ctx, a->rs1, 0); + TCGv dest = get_gpr(ctx, a->rd, EXT_NONE); + TCGBar bar = (a->rl) ? TCG_BAR_STRL : 0; + + /* Check that AQ is set, as this is mandatory */ + if (!a->aq) { + return false; + } + + memop |= (ctx->cfg_ptr->ext_zama16b) ? MO_ATOM_WITHIN16 : 0; + + tcg_gen_qemu_ld_tl(dest, addr, ctx->mem_idx, memop); + gen_set_gpr(ctx, a->rd, dest); + + /* Add a memory barrier implied by AQ (mandatory) and RL (optional) */ + tcg_gen_mb(TCG_MO_ALL | TCG_BAR_LDAQ | bar); + + return true; +} + +static bool trans_lb_aqrl(DisasContext *ctx, arg_lb_aqrl *a) +{ + REQUIRE_ZALASR(ctx); + return gen_load_acquire(ctx, a, (MO_ALIGN | MO_SB)); +} + +static bool trans_lh_aqrl(DisasContext *ctx, arg_lh_aqrl *a) +{ + REQUIRE_ZALASR(ctx); + return gen_load_acquire(ctx, a, (MO_ALIGN | MO_TESW)); +} + +static bool trans_lw_aqrl(DisasContext *ctx, arg_lw_aqrl *a) +{ + REQUIRE_ZALASR(ctx); + return gen_load_acquire(ctx, a, (MO_ALIGN | MO_TESL)); +} + +static bool trans_ld_aqrl(DisasContext *ctx, arg_ld_aqrl *a) +{ + REQUIRE_64BIT(ctx); + REQUIRE_ZALASR(ctx); + return gen_load_acquire(ctx, a, (MO_ALIGN | MO_TEUQ)); +} + +static bool gen_store_release(DisasContext *ctx, arg_sb_aqrl *a, MemOp memop) +{ + decode_save_opc(ctx, 0); + + TCGv addr = get_address(ctx, a->rs1, 0); + TCGv data = get_gpr(ctx, a->rs2, EXT_NONE); + TCGBar bar = (a->aq) ? TCG_BAR_LDAQ : 0; + + /* Check that RL is set, as this is mandatory */ + if (!a->rl) { + return false; + } + + memop |= (ctx->cfg_ptr->ext_zama16b) ? MO_ATOM_WITHIN16 : 0; + + /* Add a memory barrier implied by RL (mandatory) and AQ (optional) */ + tcg_gen_mb(TCG_MO_ALL | TCG_BAR_STRL | bar); + + tcg_gen_qemu_st_tl(data, addr, ctx->mem_idx, memop); + return true; +} + +static bool trans_sb_aqrl(DisasContext *ctx, arg_sb_aqrl *a) +{ + REQUIRE_ZALASR(ctx); + return gen_store_release(ctx, a, (MO_ALIGN | MO_SB)); +} + +static bool trans_sh_aqrl(DisasContext *ctx, arg_sh_aqrl *a) +{ + REQUIRE_ZALASR(ctx); + return gen_store_release(ctx, a, (MO_ALIGN | MO_TESW)); +} + +static bool trans_sw_aqrl(DisasContext *ctx, arg_sw_aqrl *a) +{ + REQUIRE_ZALASR(ctx); + return gen_store_release(ctx, a, (MO_ALIGN | MO_TESL)); +} + +static bool trans_sd_aqrl(DisasContext *ctx, arg_sd_aqrl *a) +{ + REQUIRE_64BIT(ctx); + REQUIRE_ZALASR(ctx); + return gen_store_release(ctx, a, (MO_ALIGN | MO_TEUQ)); +} -- 2.52.0
From: Djordje Todorovic <Djordje.Todorovic@htecgroup.com> Add a new function, so we can change reset vector from platforms during runtime. Signed-off-by: Chao-ying Fu <cfu@mips.com> Signed-off-by: Djordje Todorovic <djordje.todorovic@htecgroup.com> Reviewed-by: Daniel Henrique Barboza <dbarboza@ventanamicro.com> Reviewed-by: Alistair Francis <alistair.francis@wdc.com> Message-ID: <20260108134128.2218102-2-djordje.todorovic@htecgroup.com> Signed-off-by: Alistair Francis <alistair.francis@wdc.com> --- target/riscv/cpu.h | 4 ++++ target/riscv/cpu.c | 16 ++++++++++++++++ 2 files changed, 20 insertions(+) diff --git a/target/riscv/cpu.h b/target/riscv/cpu.h index XXXXXXX..XXXXXXX 100644 --- a/target/riscv/cpu.h +++ b/target/riscv/cpu.h @@ -XXX,XX +XXX,XX @@ G_NORETURN void riscv_raise_exception(CPURISCVState *env, target_ulong riscv_cpu_get_fflags(CPURISCVState *env); void riscv_cpu_set_fflags(CPURISCVState *env, target_ulong); +#ifndef CONFIG_USER_ONLY +void cpu_set_exception_base(int vp_index, target_ulong address); +#endif + FIELD(TB_FLAGS, MEM_IDX, 0, 3) FIELD(TB_FLAGS, FS, 3, 2) /* Vector flags */ diff --git a/target/riscv/cpu.c b/target/riscv/cpu.c index XXXXXXX..XXXXXXX 100644 --- a/target/riscv/cpu.c +++ b/target/riscv/cpu.c @@ -XXX,XX +XXX,XX @@ bool riscv_cpu_option_set(const char *optname) return g_hash_table_contains(general_user_opts, optname); } +#ifndef CONFIG_USER_ONLY +/* This is used in runtime only. */ +void cpu_set_exception_base(int vp_index, target_ulong address) +{ + RISCVCPU *cpu; + CPUState *cs = qemu_get_cpu(vp_index); + if (cs == NULL) { + qemu_log_mask(LOG_GUEST_ERROR, + "cpu_set_exception_base: invalid vp_index: %u", + vp_index); + } + cpu = RISCV_CPU(cs); + cpu->env.resetvec = address; +} +#endif + static void riscv_cpu_cfg_merge(RISCVCPUConfig *dest, const RISCVCPUConfig *src) { #define BOOL_FIELD(x) dest->x |= src->x; -- 2.52.0
From: Djordje Todorovic <Djordje.Todorovic@htecgroup.com> Introduce P8700 CPU by MIPS. Signed-off-by: Chao-ying Fu <cfu@mips.com> Signed-off-by: Djordje Todorovic <djordje.todorovic@htecgroup.com> Reviewed-by: Daniel Henrique Barboza <dbarboza@ventanamicro.com> Reviewed-by: Alistair Francis <alistair.francis@wdc.com> Message-ID: <20260108134128.2218102-3-djordje.todorovic@htecgroup.com> Signed-off-by: Alistair Francis <alistair.francis@wdc.com> --- target/riscv/cpu-qom.h | 1 + target/riscv/cpu_vendorid.h | 1 + target/riscv/cpu.c | 16 ++++++++++++++++ 3 files changed, 18 insertions(+) diff --git a/target/riscv/cpu-qom.h b/target/riscv/cpu-qom.h index XXXXXXX..XXXXXXX 100644 --- a/target/riscv/cpu-qom.h +++ b/target/riscv/cpu-qom.h @@ -XXX,XX +XXX,XX @@ #define TYPE_RISCV_CPU_TT_ASCALON RISCV_CPU_TYPE_NAME("tt-ascalon") #define TYPE_RISCV_CPU_XIANGSHAN_NANHU RISCV_CPU_TYPE_NAME("xiangshan-nanhu") #define TYPE_RISCV_CPU_XIANGSHAN_KMH RISCV_CPU_TYPE_NAME("xiangshan-kunminghu") +#define TYPE_RISCV_CPU_MIPS_P8700 RISCV_CPU_TYPE_NAME("mips-p8700") #define TYPE_RISCV_CPU_HOST RISCV_CPU_TYPE_NAME("host") OBJECT_DECLARE_CPU_TYPE(RISCVCPU, RISCVCPUClass, RISCV_CPU) diff --git a/target/riscv/cpu_vendorid.h b/target/riscv/cpu_vendorid.h index XXXXXXX..XXXXXXX 100644 --- a/target/riscv/cpu_vendorid.h +++ b/target/riscv/cpu_vendorid.h @@ -XXX,XX +XXX,XX @@ #define TARGET_RISCV_CPU_VENDORID_H #define THEAD_VENDOR_ID 0x5b7 +#define MIPS_VENDOR_ID 0x127 #define VEYRON_V1_MARCHID 0x8000000000010000 #define VEYRON_V1_MIMPID 0x111 diff --git a/target/riscv/cpu.c b/target/riscv/cpu.c index XXXXXXX..XXXXXXX 100644 --- a/target/riscv/cpu.c +++ b/target/riscv/cpu.c @@ -XXX,XX +XXX,XX @@ static const TypeInfo riscv_cpu_type_infos[] = { .cfg.max_satp_mode = VM_1_10_SV48, ), + /* https://mips.com/products/hardware/p8700/ */ + DEFINE_RISCV_CPU(TYPE_RISCV_CPU_MIPS_P8700, TYPE_RISCV_VENDOR_CPU, + .misa_mxl_max = MXL_RV64, + .misa_ext = RVI | RVM | RVA | RVF | RVD | RVC | RVS | RVU, + .priv_spec = PRIV_VERSION_1_12_0, + .cfg.max_satp_mode = VM_1_10_SV48, + .cfg.ext_zifencei = true, + .cfg.ext_zicsr = true, + .cfg.mmu = true, + .cfg.pmp = true, + .cfg.ext_zba = true, + .cfg.ext_zbb = true, + .cfg.marchid = 0x8000000000000201, + .cfg.mvendorid = MIPS_VENDOR_ID, + ), + #if defined(CONFIG_TCG) && !defined(CONFIG_USER_ONLY) DEFINE_RISCV_CPU(TYPE_RISCV_CPU_BASE128, TYPE_RISCV_DYNAMIC_CPU, .cfg.max_satp_mode = VM_1_10_SV57, -- 2.52.0
From: Djordje Todorovic <Djordje.Todorovic@htecgroup.com> Define MIPS CSRs used for P8700 CPU. Signed-off-by: Chao-ying Fu <cfu@mips.com> Signed-off-by: Djordje Todorovic <djordje.todorovic@htecgroup.com> Reviewed-by: Daniel Henrique Barboza <dbarboza@ventanamicro.com> Reviewed-by: Alistair Francis <alistair.francis@wdc.com> Message-ID: <20260108134128.2218102-4-djordje.todorovic@htecgroup.com> Signed-off-by: Alistair Francis <alistair.francis@wdc.com> --- target/riscv/cpu.h | 3 + target/riscv/cpu.c | 3 + target/riscv/mips_csr.c | 217 +++++++++++++++++++++++++++++++++++++++ target/riscv/meson.build | 1 + 4 files changed, 224 insertions(+) create mode 100644 target/riscv/mips_csr.c diff --git a/target/riscv/cpu.h b/target/riscv/cpu.h index XXXXXXX..XXXXXXX 100644 --- a/target/riscv/cpu.h +++ b/target/riscv/cpu.h @@ -XXX,XX +XXX,XX @@ const char *satp_mode_str(uint8_t satp_mode, bool is_32_bit); /* In th_csr.c */ extern const RISCVCSR th_csr_list[]; +/* Implemented in mips_csr.c */ +extern const RISCVCSR mips_csr_list[]; + const char *priv_spec_to_str(int priv_version); #endif /* RISCV_CPU_H */ diff --git a/target/riscv/cpu.c b/target/riscv/cpu.c index XXXXXXX..XXXXXXX 100644 --- a/target/riscv/cpu.c +++ b/target/riscv/cpu.c @@ -XXX,XX +XXX,XX @@ static const TypeInfo riscv_cpu_type_infos[] = { .cfg.ext_zbb = true, .cfg.marchid = 0x8000000000000201, .cfg.mvendorid = MIPS_VENDOR_ID, +#ifndef CONFIG_USER_ONLY + .custom_csrs = mips_csr_list, +#endif ), #if defined(CONFIG_TCG) && !defined(CONFIG_USER_ONLY) diff --git a/target/riscv/mips_csr.c b/target/riscv/mips_csr.c new file mode 100644 index XXXXXXX..XXXXXXX --- /dev/null +++ b/target/riscv/mips_csr.c @@ -XXX,XX +XXX,XX @@ +/* + * MIPS-specific CSRs. + * + * Copyright (c) 2025 MIPS + * + * SPDX-License-Identifier: GPL-2.0-or-later + * + */ + +#include "qemu/osdep.h" +#include "cpu.h" +#include "cpu_vendorid.h" + +/* Static MIPS CSR state storage */ +static struct { + uint64_t tvec; + uint64_t config[12]; + uint64_t pmacfg[16]; +} mips_csr_state; + +/* MIPS CSR */ +#define CSR_MIPSTVEC 0x7c0 +#define CSR_MIPSCONFIG0 0x7d0 +#define CSR_MIPSCONFIG1 0x7d1 +#define CSR_MIPSCONFIG2 0x7d2 +#define CSR_MIPSCONFIG3 0x7d3 +#define CSR_MIPSCONFIG4 0x7d4 +#define CSR_MIPSCONFIG5 0x7d5 +#define CSR_MIPSCONFIG6 0x7d6 +#define CSR_MIPSCONFIG7 0x7d7 +#define CSR_MIPSCONFIG8 0x7d8 +#define CSR_MIPSCONFIG9 0x7d9 +#define CSR_MIPSCONFIG10 0x7da +#define CSR_MIPSCONFIG11 0x7db +#define CSR_MIPSPMACFG0 0x7e0 +#define CSR_MIPSPMACFG1 0x7e1 +#define CSR_MIPSPMACFG2 0x7e2 +#define CSR_MIPSPMACFG3 0x7e3 +#define CSR_MIPSPMACFG4 0x7e4 +#define CSR_MIPSPMACFG5 0x7e5 +#define CSR_MIPSPMACFG6 0x7e6 +#define CSR_MIPSPMACFG7 0x7e7 +#define CSR_MIPSPMACFG8 0x7e8 +#define CSR_MIPSPMACFG9 0x7e9 +#define CSR_MIPSPMACFG10 0x7ea +#define CSR_MIPSPMACFG11 0x7eb +#define CSR_MIPSPMACFG12 0x7ec +#define CSR_MIPSPMACFG13 0x7ed +#define CSR_MIPSPMACFG14 0x7ee +#define CSR_MIPSPMACFG15 0x7ef + +static RISCVException any(CPURISCVState *env, int csrno) +{ + return RISCV_EXCP_NONE; +} + +static RISCVException read_mipstvec(CPURISCVState *env, int csrno, + target_ulong *val) +{ + *val = mips_csr_state.tvec; + return RISCV_EXCP_NONE; +} + +static RISCVException write_mipstvec(CPURISCVState *env, int csrno, + target_ulong val, uintptr_t ra) +{ + mips_csr_state.tvec = val; + return RISCV_EXCP_NONE; +} + +static RISCVException read_mipsconfig(CPURISCVState *env, int csrno, + target_ulong *val) +{ + *val = mips_csr_state.config[csrno - CSR_MIPSCONFIG0]; + return RISCV_EXCP_NONE; +} + +static RISCVException write_mipsconfig(CPURISCVState *env, int csrno, + target_ulong val, uintptr_t ra) +{ + mips_csr_state.config[csrno - CSR_MIPSCONFIG0] = val; + return RISCV_EXCP_NONE; +} + +static RISCVException read_mipspmacfg(CPURISCVState *env, int csrno, + target_ulong *val) +{ + *val = mips_csr_state.pmacfg[csrno - CSR_MIPSPMACFG0]; + return RISCV_EXCP_NONE; +} + +static RISCVException write_mipspmacfg(CPURISCVState *env, int csrno, + target_ulong val, uintptr_t ra) +{ + mips_csr_state.pmacfg[csrno - CSR_MIPSPMACFG0] = val; + return RISCV_EXCP_NONE; +} + +const RISCVCSR mips_csr_list[] = { + { + .csrno = CSR_MIPSTVEC, + .csr_ops = { "mipstvec", any, read_mipstvec, write_mipstvec } + }, + { + .csrno = CSR_MIPSCONFIG0, + .csr_ops = { "mipsconfig0", any, read_mipsconfig, write_mipsconfig } + }, + { + .csrno = CSR_MIPSCONFIG1, + .csr_ops = { "mipsconfig1", any, read_mipsconfig, write_mipsconfig } + }, + { + .csrno = CSR_MIPSCONFIG2, + .csr_ops = { "mipsconfig2", any, read_mipsconfig, write_mipsconfig } + }, + { + .csrno = CSR_MIPSCONFIG3, + .csr_ops = { "mipsconfig3", any, read_mipsconfig, write_mipsconfig } + }, + { + .csrno = CSR_MIPSCONFIG4, + .csr_ops = { "mipsconfig4", any, read_mipsconfig, write_mipsconfig } + }, + { + .csrno = CSR_MIPSCONFIG5, + .csr_ops = { "mipsconfig5", any, read_mipsconfig, write_mipsconfig } + }, + { + .csrno = CSR_MIPSCONFIG6, + .csr_ops = { "mipsconfig6", any, read_mipsconfig, write_mipsconfig } + }, + { + .csrno = CSR_MIPSCONFIG7, + .csr_ops = { "mipsconfig7", any, read_mipsconfig, write_mipsconfig } + }, + { + .csrno = CSR_MIPSCONFIG8, + .csr_ops = { "mipsconfig8", any, read_mipsconfig, write_mipsconfig } + }, + { + .csrno = CSR_MIPSCONFIG9, + .csr_ops = { "mipsconfig9", any, read_mipsconfig, write_mipsconfig } + }, + { + .csrno = CSR_MIPSCONFIG10, + .csr_ops = { "mipsconfig10", any, read_mipsconfig, write_mipsconfig } + }, + { + .csrno = CSR_MIPSCONFIG11, + .csr_ops = { "mipsconfig11", any, read_mipsconfig, write_mipsconfig } + }, + { + .csrno = CSR_MIPSPMACFG0, + .csr_ops = { "mipspmacfg0", any, read_mipspmacfg, write_mipspmacfg } + }, + { + .csrno = CSR_MIPSPMACFG1, + .csr_ops = { "mipspmacfg1", any, read_mipspmacfg, write_mipspmacfg } + }, + { + .csrno = CSR_MIPSPMACFG2, + .csr_ops = { "mipspmacfg2", any, read_mipspmacfg, write_mipspmacfg } + }, + { + .csrno = CSR_MIPSPMACFG3, + .csr_ops = { "mipspmacfg3", any, read_mipspmacfg, write_mipspmacfg } + }, + { + .csrno = CSR_MIPSPMACFG4, + .csr_ops = { "mipspmacfg4", any, read_mipspmacfg, write_mipspmacfg } + }, + { + .csrno = CSR_MIPSPMACFG5, + .csr_ops = { "mipspmacfg5", any, read_mipspmacfg, write_mipspmacfg } + }, + { + .csrno = CSR_MIPSPMACFG6, + .csr_ops = { "mipspmacfg6", any, read_mipspmacfg, write_mipspmacfg } + }, + { + .csrno = CSR_MIPSPMACFG7, + .csr_ops = { "mipspmacfg7", any, read_mipspmacfg, write_mipspmacfg } + }, + { + .csrno = CSR_MIPSPMACFG8, + .csr_ops = { "mipspmacfg8", any, read_mipspmacfg, write_mipspmacfg } + }, + { + .csrno = CSR_MIPSPMACFG9, + .csr_ops = { "mipspmacfg9", any, read_mipspmacfg, write_mipspmacfg } + }, + { + .csrno = CSR_MIPSPMACFG10, + .csr_ops = { "mipspmacfg10", any, read_mipspmacfg, write_mipspmacfg } + }, + { + .csrno = CSR_MIPSPMACFG11, + .csr_ops = { "mipspmacfg11", any, read_mipspmacfg, write_mipspmacfg } + }, + { + .csrno = CSR_MIPSPMACFG12, + .csr_ops = { "mipspmacfg12", any, read_mipspmacfg, write_mipspmacfg } + }, + { + .csrno = CSR_MIPSPMACFG13, + .csr_ops = { "mipspmacfg13", any, read_mipspmacfg, write_mipspmacfg } + }, + { + .csrno = CSR_MIPSPMACFG14, + .csr_ops = { "mipspmacfg14", any, read_mipspmacfg, write_mipspmacfg } + }, + { + .csrno = CSR_MIPSPMACFG15, + .csr_ops = { "mipspmacfg15", any, read_mipspmacfg, write_mipspmacfg } + }, + { }, +}; diff --git a/target/riscv/meson.build b/target/riscv/meson.build index XXXXXXX..XXXXXXX 100644 --- a/target/riscv/meson.build +++ b/target/riscv/meson.build @@ -XXX,XX +XXX,XX @@ riscv_system_ss.add(files( 'debug.c', 'monitor.c', 'machine.c', + 'mips_csr.c', 'pmu.c', 'th_csr.c', 'time_helper.c', -- 2.52.0
From: Djordje Todorovic <Djordje.Todorovic@htecgroup.com> Add mips.ccmov defined by Xmipscmov. Signed-off-by: Chao-ying Fu <cfu@mips.com> Signed-off-by: Djordje Todorovic <djordje.todorovic@htecgroup.com> Acked-by: Daniel Henrique Barboza <dbarboza@ventanamicro.com> Acked-by: Alistair Francis <alistair.francis@wdc.com> Message-ID: <20260108134128.2218102-5-djordje.todorovic@htecgroup.com> Signed-off-by: Alistair Francis <alistair.francis@wdc.com> --- target/riscv/cpu_cfg.h | 5 ++++ target/riscv/cpu_cfg_fields.h.inc | 1 + target/riscv/xmips.decode | 11 ++++++++ target/riscv/cpu.c | 3 +++ target/riscv/translate.c | 3 +++ target/riscv/insn_trans/trans_xmips.c.inc | 33 +++++++++++++++++++++++ target/riscv/meson.build | 1 + 7 files changed, 57 insertions(+) create mode 100644 target/riscv/xmips.decode create mode 100644 target/riscv/insn_trans/trans_xmips.c.inc diff --git a/target/riscv/cpu_cfg.h b/target/riscv/cpu_cfg.h index XXXXXXX..XXXXXXX 100644 --- a/target/riscv/cpu_cfg.h +++ b/target/riscv/cpu_cfg.h @@ -XXX,XX +XXX,XX @@ static inline bool always_true_p(const RISCVCPUConfig *cfg __attribute__((__unus return true; } +static inline bool has_xmips_p(const RISCVCPUConfig *cfg) +{ + return cfg->ext_xmipscmov; +} + static inline bool has_xthead_p(const RISCVCPUConfig *cfg) { return cfg->ext_xtheadba || cfg->ext_xtheadbb || diff --git a/target/riscv/cpu_cfg_fields.h.inc b/target/riscv/cpu_cfg_fields.h.inc index XXXXXXX..XXXXXXX 100644 --- a/target/riscv/cpu_cfg_fields.h.inc +++ b/target/riscv/cpu_cfg_fields.h.inc @@ -XXX,XX +XXX,XX @@ BOOL_FIELD(ext_xtheadmemidx) BOOL_FIELD(ext_xtheadmempair) BOOL_FIELD(ext_xtheadsync) BOOL_FIELD(ext_XVentanaCondOps) +BOOL_FIELD(ext_xmipscmov) BOOL_FIELD(mmu) BOOL_FIELD(pmp) diff --git a/target/riscv/xmips.decode b/target/riscv/xmips.decode new file mode 100644 index XXXXXXX..XXXXXXX --- /dev/null +++ b/target/riscv/xmips.decode @@ -XXX,XX +XXX,XX @@ +# +# RISC-V translation routines for the MIPS extension +# +# Copyright (c) 2025 MIPS +# +# SPDX-License-Identifier: GPL-2.0-or-later +# +# Reference: MIPS P8700 instructions +# (https://mips.com/products/hardware/p8700/) + +ccmov rs3:5 11 rs2:5 rs1:5 011 rd:5 0001011 diff --git a/target/riscv/cpu.c b/target/riscv/cpu.c index XXXXXXX..XXXXXXX 100644 --- a/target/riscv/cpu.c +++ b/target/riscv/cpu.c @@ -XXX,XX +XXX,XX @@ const RISCVIsaExtData isa_edata_arr[] = { ISA_EXT_DATA_ENTRY(svrsw60t59b, PRIV_VERSION_1_13_0, ext_svrsw60t59b), ISA_EXT_DATA_ENTRY(svukte, PRIV_VERSION_1_13_0, ext_svukte), ISA_EXT_DATA_ENTRY(svvptc, PRIV_VERSION_1_13_0, ext_svvptc), + ISA_EXT_DATA_ENTRY(xmipscmov, PRIV_VERSION_1_12_0, ext_xmipscmov), ISA_EXT_DATA_ENTRY(xtheadba, PRIV_VERSION_1_11_0, ext_xtheadba), ISA_EXT_DATA_ENTRY(xtheadbb, PRIV_VERSION_1_11_0, ext_xtheadbb), ISA_EXT_DATA_ENTRY(xtheadbs, PRIV_VERSION_1_11_0, ext_xtheadbs), @@ -XXX,XX +XXX,XX @@ const RISCVCPUMultiExtConfig riscv_cpu_vendor_exts[] = { MULTI_EXT_CFG_BOOL("xtheadmempair", ext_xtheadmempair, false), MULTI_EXT_CFG_BOOL("xtheadsync", ext_xtheadsync, false), MULTI_EXT_CFG_BOOL("xventanacondops", ext_XVentanaCondOps, false), + MULTI_EXT_CFG_BOOL("xmipscmov", ext_xmipscmov, false), { }, }; @@ -XXX,XX +XXX,XX @@ static const TypeInfo riscv_cpu_type_infos[] = { .cfg.pmp = true, .cfg.ext_zba = true, .cfg.ext_zbb = true, + .cfg.ext_xmipscmov = true, .cfg.marchid = 0x8000000000000201, .cfg.mvendorid = MIPS_VENDOR_ID, #ifndef CONFIG_USER_ONLY diff --git a/target/riscv/translate.c b/target/riscv/translate.c index XXXXXXX..XXXXXXX 100644 --- a/target/riscv/translate.c +++ b/target/riscv/translate.c @@ -XXX,XX +XXX,XX @@ static uint32_t opcode_at(DisasContextBase *dcbase, target_ulong pc) #include "insn_trans/trans_svinval.c.inc" #include "insn_trans/trans_rvbf16.c.inc" #include "decode-xthead.c.inc" +#include "decode-xmips.c.inc" #include "insn_trans/trans_xthead.c.inc" #include "insn_trans/trans_xventanacondops.c.inc" +#include "insn_trans/trans_xmips.c.inc" /* Include the auto-generated decoder for 16 bit insn */ #include "decode-insn16.c.inc" @@ -XXX,XX +XXX,XX @@ static uint32_t opcode_at(DisasContextBase *dcbase, target_ulong pc) const RISCVDecoder decoder_table[] = { { always_true_p, decode_insn32 }, + { has_xmips_p, decode_xmips}, { has_xthead_p, decode_xthead}, { has_XVentanaCondOps_p, decode_XVentanaCodeOps}, }; diff --git a/target/riscv/insn_trans/trans_xmips.c.inc b/target/riscv/insn_trans/trans_xmips.c.inc new file mode 100644 index XXXXXXX..XXXXXXX --- /dev/null +++ b/target/riscv/insn_trans/trans_xmips.c.inc @@ -XXX,XX +XXX,XX @@ +/* + * RISC-V translation routines for the MIPS extensions (xmips*). + * + * Copyright (c) 2025 MIPS + * + * SPDX-License-Identifier: GPL-2.0-or-later + * + * Reference: MIPS P8700 instructions + * (https://mips.com/products/hardware/p8700/) + */ + +#define REQUIRE_XMIPSCMOV(ctx) do { \ + if (!ctx->cfg_ptr->ext_xmipscmov) { \ + return false; \ + } \ +} while (0) + +/* Conditional move by MIPS. */ +static bool trans_ccmov(DisasContext *ctx, arg_ccmov *a) +{ + REQUIRE_XMIPSCMOV(ctx); + + TCGv zero, source1, source2, source3; + zero = tcg_constant_tl(0); + source1 = get_gpr(ctx, a->rs1, EXT_NONE); + source2 = get_gpr(ctx, a->rs2, EXT_NONE); + source3 = get_gpr(ctx, a->rs3, EXT_NONE); + + tcg_gen_movcond_tl(TCG_COND_NE, cpu_gpr[a->rd], + source2, zero, source1, source3); + + return true; +} diff --git a/target/riscv/meson.build b/target/riscv/meson.build index XXXXXXX..XXXXXXX 100644 --- a/target/riscv/meson.build +++ b/target/riscv/meson.build @@ -XXX,XX +XXX,XX @@ gen = [ decodetree.process('insn32.decode', extra_args: '--static-decode=decode_insn32'), decodetree.process('xthead.decode', extra_args: '--static-decode=decode_xthead'), decodetree.process('XVentanaCondOps.decode', extra_args: '--static-decode=decode_XVentanaCodeOps'), + decodetree.process('xmips.decode', extra_args: '--static-decode=decode_xmips'), ] riscv_ss = ss.source_set() -- 2.52.0
From: Djordje Todorovic <Djordje.Todorovic@htecgroup.com> Add MIPS P8700 prefetch instruction defined by Xmipscbop. Signed-off-by: Chao-ying Fu <cfu@mips.com> Signed-off-by: Djordje Todorovic <djordje.todorovic@htecgroup.com> Reviewed-by: Daniel Henrique Barboza <dbarboza@ventanamicro.com> Acked-by: Alistair Francis <alistair.francis@wdc.com> Message-ID: <20260108134128.2218102-6-djordje.todorovic@htecgroup.com> Signed-off-by: Alistair Francis <alistair.francis@wdc.com> --- target/riscv/cpu_cfg.h | 2 +- target/riscv/cpu_cfg_fields.h.inc | 1 + target/riscv/xmips.decode | 1 + target/riscv/cpu.c | 3 +++ target/riscv/insn_trans/trans_xmips.c.inc | 15 +++++++++++++++ 5 files changed, 21 insertions(+), 1 deletion(-) diff --git a/target/riscv/cpu_cfg.h b/target/riscv/cpu_cfg.h index XXXXXXX..XXXXXXX 100644 --- a/target/riscv/cpu_cfg.h +++ b/target/riscv/cpu_cfg.h @@ -XXX,XX +XXX,XX @@ static inline bool always_true_p(const RISCVCPUConfig *cfg __attribute__((__unus static inline bool has_xmips_p(const RISCVCPUConfig *cfg) { - return cfg->ext_xmipscmov; + return cfg->ext_xmipscbop || cfg->ext_xmipscmov; } static inline bool has_xthead_p(const RISCVCPUConfig *cfg) diff --git a/target/riscv/cpu_cfg_fields.h.inc b/target/riscv/cpu_cfg_fields.h.inc index XXXXXXX..XXXXXXX 100644 --- a/target/riscv/cpu_cfg_fields.h.inc +++ b/target/riscv/cpu_cfg_fields.h.inc @@ -XXX,XX +XXX,XX @@ BOOL_FIELD(ext_xtheadmemidx) BOOL_FIELD(ext_xtheadmempair) BOOL_FIELD(ext_xtheadsync) BOOL_FIELD(ext_XVentanaCondOps) +BOOL_FIELD(ext_xmipscbop) BOOL_FIELD(ext_xmipscmov) BOOL_FIELD(mmu) diff --git a/target/riscv/xmips.decode b/target/riscv/xmips.decode index XXXXXXX..XXXXXXX 100644 --- a/target/riscv/xmips.decode +++ b/target/riscv/xmips.decode @@ -XXX,XX +XXX,XX @@ # (https://mips.com/products/hardware/p8700/) ccmov rs3:5 11 rs2:5 rs1:5 011 rd:5 0001011 +pref 000 imm_9:9 rs1:5 000 imm_hint:5 0001011 diff --git a/target/riscv/cpu.c b/target/riscv/cpu.c index XXXXXXX..XXXXXXX 100644 --- a/target/riscv/cpu.c +++ b/target/riscv/cpu.c @@ -XXX,XX +XXX,XX @@ const RISCVIsaExtData isa_edata_arr[] = { ISA_EXT_DATA_ENTRY(svrsw60t59b, PRIV_VERSION_1_13_0, ext_svrsw60t59b), ISA_EXT_DATA_ENTRY(svukte, PRIV_VERSION_1_13_0, ext_svukte), ISA_EXT_DATA_ENTRY(svvptc, PRIV_VERSION_1_13_0, ext_svvptc), + ISA_EXT_DATA_ENTRY(xmipscbop, PRIV_VERSION_1_12_0, ext_xmipscbop), ISA_EXT_DATA_ENTRY(xmipscmov, PRIV_VERSION_1_12_0, ext_xmipscmov), ISA_EXT_DATA_ENTRY(xtheadba, PRIV_VERSION_1_11_0, ext_xtheadba), ISA_EXT_DATA_ENTRY(xtheadbb, PRIV_VERSION_1_11_0, ext_xtheadbb), @@ -XXX,XX +XXX,XX @@ const RISCVCPUMultiExtConfig riscv_cpu_vendor_exts[] = { MULTI_EXT_CFG_BOOL("xtheadmempair", ext_xtheadmempair, false), MULTI_EXT_CFG_BOOL("xtheadsync", ext_xtheadsync, false), MULTI_EXT_CFG_BOOL("xventanacondops", ext_XVentanaCondOps, false), + MULTI_EXT_CFG_BOOL("xmipscbop", ext_xmipscbop, false), MULTI_EXT_CFG_BOOL("xmipscmov", ext_xmipscmov, false), { }, @@ -XXX,XX +XXX,XX @@ static const TypeInfo riscv_cpu_type_infos[] = { .cfg.pmp = true, .cfg.ext_zba = true, .cfg.ext_zbb = true, + .cfg.ext_xmipscbop = true, .cfg.ext_xmipscmov = true, .cfg.marchid = 0x8000000000000201, .cfg.mvendorid = MIPS_VENDOR_ID, diff --git a/target/riscv/insn_trans/trans_xmips.c.inc b/target/riscv/insn_trans/trans_xmips.c.inc index XXXXXXX..XXXXXXX 100644 --- a/target/riscv/insn_trans/trans_xmips.c.inc +++ b/target/riscv/insn_trans/trans_xmips.c.inc @@ -XXX,XX +XXX,XX @@ * (https://mips.com/products/hardware/p8700/) */ +#define REQUIRE_XMIPSCBOP(ctx) do { \ + if (!ctx->cfg_ptr->ext_xmipscbop) { \ + return false; \ + } \ +} while (0) + #define REQUIRE_XMIPSCMOV(ctx) do { \ if (!ctx->cfg_ptr->ext_xmipscmov) { \ return false; \ @@ -XXX,XX +XXX,XX @@ static bool trans_ccmov(DisasContext *ctx, arg_ccmov *a) return true; } + +/* Move data from memory into cache. */ +static bool trans_pref(DisasContext *ctx, arg_pref *a) +{ + REQUIRE_XMIPSCBOP(ctx); + + /* Nop */ + return true; +} -- 2.52.0
From: Djordje Todorovic <Djordje.Todorovic@htecgroup.com> Add MIPS P8700 ldp, lwp, sdp, swp instructions. Signed-off-by: Chao-ying Fu <cfu@mips.com> Signed-off-by: Djordje Todorovic <djordje.todorovic@htecgroup.com> Acked-by: Daniel Henrique Barboza <dbarboza@ventanamicro.com> Acked-by: Alistair Francis <alistair.francis@wdc.com> Message-ID: <20260108134128.2218102-7-djordje.todorovic@htecgroup.com> Signed-off-by: Alistair Francis <alistair.francis@wdc.com> --- target/riscv/cpu_cfg.h | 2 +- target/riscv/cpu_cfg_fields.h.inc | 1 + target/riscv/xmips.decode | 23 ++++++ target/riscv/cpu.c | 3 + target/riscv/insn_trans/trans_xmips.c.inc | 88 +++++++++++++++++++++++ 5 files changed, 116 insertions(+), 1 deletion(-) diff --git a/target/riscv/cpu_cfg.h b/target/riscv/cpu_cfg.h index XXXXXXX..XXXXXXX 100644 --- a/target/riscv/cpu_cfg.h +++ b/target/riscv/cpu_cfg.h @@ -XXX,XX +XXX,XX @@ static inline bool always_true_p(const RISCVCPUConfig *cfg __attribute__((__unus static inline bool has_xmips_p(const RISCVCPUConfig *cfg) { - return cfg->ext_xmipscbop || cfg->ext_xmipscmov; + return cfg->ext_xmipscbop || cfg->ext_xmipscmov || cfg->ext_xmipslsp; } static inline bool has_xthead_p(const RISCVCPUConfig *cfg) diff --git a/target/riscv/cpu_cfg_fields.h.inc b/target/riscv/cpu_cfg_fields.h.inc index XXXXXXX..XXXXXXX 100644 --- a/target/riscv/cpu_cfg_fields.h.inc +++ b/target/riscv/cpu_cfg_fields.h.inc @@ -XXX,XX +XXX,XX @@ BOOL_FIELD(ext_xtheadsync) BOOL_FIELD(ext_XVentanaCondOps) BOOL_FIELD(ext_xmipscbop) BOOL_FIELD(ext_xmipscmov) +BOOL_FIELD(ext_xmipslsp) BOOL_FIELD(mmu) BOOL_FIELD(pmp) diff --git a/target/riscv/xmips.decode b/target/riscv/xmips.decode index XXXXXXX..XXXXXXX 100644 --- a/target/riscv/xmips.decode +++ b/target/riscv/xmips.decode @@ -XXX,XX +XXX,XX @@ # Reference: MIPS P8700 instructions # (https://mips.com/products/hardware/p8700/) +# Fields +%rs3 27:5 +%rs2 20:5 +%rs1 15:5 +%rd 7:5 +%imm_9 20:9 +%imm_hint 7:5 +%imm_v 25:2 9:3 !function=ex_shift_2 +%imm_w 25:2 10:2 !function=ex_shift_3 +%imm_x 22:5 !function=ex_shift_2 +%imm_y 23:4 !function=ex_shift_3 + +# Formats +@r4_immv ..... .. ..... ..... ... ... .. ....... %rs2 %rs3 %imm_v %rs1 +@r4_immw ..... .. ..... ..... ... .. ... ....... %rs2 %rs3 %imm_w %rs1 +@r4_immx ..... ..... .. ..... ... ..... ....... %rs3 %imm_x %rs1 %rd +@r4_immy ..... .... ... ..... ... ..... ....... %rs3 %imm_y %rs1 %rd + +# *** RV64 MIPS Extension *** ccmov rs3:5 11 rs2:5 rs1:5 011 rd:5 0001011 pref 000 imm_9:9 rs1:5 000 imm_hint:5 0001011 +ldp ..... .... 000 ..... 100 ..... 0001011 @r4_immy +lwp ..... ..... 01 ..... 100 ..... 0001011 @r4_immx +sdp ..... .. ..... ..... 101 .. 0000001011 @r4_immw +swp ..... .. ..... ..... 101 ... 010001011 @r4_immv diff --git a/target/riscv/cpu.c b/target/riscv/cpu.c index XXXXXXX..XXXXXXX 100644 --- a/target/riscv/cpu.c +++ b/target/riscv/cpu.c @@ -XXX,XX +XXX,XX @@ const RISCVIsaExtData isa_edata_arr[] = { ISA_EXT_DATA_ENTRY(svvptc, PRIV_VERSION_1_13_0, ext_svvptc), ISA_EXT_DATA_ENTRY(xmipscbop, PRIV_VERSION_1_12_0, ext_xmipscbop), ISA_EXT_DATA_ENTRY(xmipscmov, PRIV_VERSION_1_12_0, ext_xmipscmov), + ISA_EXT_DATA_ENTRY(xmipslsp, PRIV_VERSION_1_12_0, ext_xmipslsp), ISA_EXT_DATA_ENTRY(xtheadba, PRIV_VERSION_1_11_0, ext_xtheadba), ISA_EXT_DATA_ENTRY(xtheadbb, PRIV_VERSION_1_11_0, ext_xtheadbb), ISA_EXT_DATA_ENTRY(xtheadbs, PRIV_VERSION_1_11_0, ext_xtheadbs), @@ -XXX,XX +XXX,XX @@ const RISCVCPUMultiExtConfig riscv_cpu_vendor_exts[] = { MULTI_EXT_CFG_BOOL("xventanacondops", ext_XVentanaCondOps, false), MULTI_EXT_CFG_BOOL("xmipscbop", ext_xmipscbop, false), MULTI_EXT_CFG_BOOL("xmipscmov", ext_xmipscmov, false), + MULTI_EXT_CFG_BOOL("xmipslsp", ext_xmipslsp, false), { }, }; @@ -XXX,XX +XXX,XX @@ static const TypeInfo riscv_cpu_type_infos[] = { .cfg.pmp = true, .cfg.ext_zba = true, .cfg.ext_zbb = true, + .cfg.ext_xmipslsp = true, .cfg.ext_xmipscbop = true, .cfg.ext_xmipscmov = true, .cfg.marchid = 0x8000000000000201, diff --git a/target/riscv/insn_trans/trans_xmips.c.inc b/target/riscv/insn_trans/trans_xmips.c.inc index XXXXXXX..XXXXXXX 100644 --- a/target/riscv/insn_trans/trans_xmips.c.inc +++ b/target/riscv/insn_trans/trans_xmips.c.inc @@ -XXX,XX +XXX,XX @@ } \ } while (0) +#define REQUIRE_XMIPSLSP(ctx) do { \ + if (!ctx->cfg_ptr->ext_xmipslsp) { \ + return false; \ + } \ +} while (0) + /* Conditional move by MIPS. */ static bool trans_ccmov(DisasContext *ctx, arg_ccmov *a) { @@ -XXX,XX +XXX,XX @@ static bool trans_ccmov(DisasContext *ctx, arg_ccmov *a) return true; } +/* Load Doubleword Pair. */ +static bool trans_ldp(DisasContext *ctx, arg_ldp *a) +{ + REQUIRE_XMIPSLSP(ctx); + REQUIRE_64_OR_128BIT(ctx); + + TCGv src = get_gpr(ctx, a->rs1, EXT_NONE); + TCGv dest0 = dest_gpr(ctx, a->rd); + TCGv dest1 = dest_gpr(ctx, a->rs3); + TCGv addr = tcg_temp_new(); + + tcg_gen_addi_tl(addr, src, a->imm_y); + tcg_gen_qemu_ld_tl(dest0, addr, ctx->mem_idx, MO_TESQ); + gen_set_gpr(ctx, a->rd, dest0); + + tcg_gen_addi_tl(addr, addr, 8); + tcg_gen_qemu_ld_tl(dest1, addr, ctx->mem_idx, MO_TESQ); + gen_set_gpr(ctx, a->rs3, dest1); + + return true; +} + +/* Load Word Pair. */ +static bool trans_lwp(DisasContext *ctx, arg_lwp *a) +{ + REQUIRE_XMIPSLSP(ctx); + + TCGv src = get_gpr(ctx, a->rs1, EXT_NONE); + TCGv dest0 = dest_gpr(ctx, a->rd); + TCGv dest1 = dest_gpr(ctx, a->rs3); + TCGv addr = tcg_temp_new(); + + tcg_gen_addi_tl(addr, src, a->imm_x); + tcg_gen_qemu_ld_tl(dest0, addr, ctx->mem_idx, MO_TESL); + gen_set_gpr(ctx, a->rd, dest0); + + tcg_gen_addi_tl(addr, addr, 4); + tcg_gen_qemu_ld_tl(dest1, addr, ctx->mem_idx, MO_TESL); + gen_set_gpr(ctx, a->rs3, dest1); + + return true; +} + +/* Store Doubleword Pair. */ +static bool trans_sdp(DisasContext *ctx, arg_sdp *a) +{ + REQUIRE_XMIPSLSP(ctx); + REQUIRE_64_OR_128BIT(ctx); + + TCGv src = get_gpr(ctx, a->rs1, EXT_NONE); + TCGv data0 = get_gpr(ctx, a->rs2, EXT_NONE); + TCGv data1 = get_gpr(ctx, a->rs3, EXT_NONE); + TCGv addr = tcg_temp_new(); + + tcg_gen_addi_tl(addr, src, a->imm_w); + tcg_gen_qemu_st_tl(data0, addr, ctx->mem_idx, MO_TEUQ); + + tcg_gen_addi_tl(addr, addr, 8); + tcg_gen_qemu_st_tl(data1, addr, ctx->mem_idx, MO_TEUQ); + + return true; +} + +/* Store Word Pair. */ +static bool trans_swp(DisasContext *ctx, arg_swp *a) +{ + REQUIRE_XMIPSLSP(ctx); + + TCGv src = get_gpr(ctx, a->rs1, EXT_NONE); + TCGv data0 = get_gpr(ctx, a->rs2, EXT_NONE); + TCGv data1 = get_gpr(ctx, a->rs3, EXT_NONE); + TCGv addr = tcg_temp_new(); + + tcg_gen_addi_tl(addr, src, a->imm_v); + tcg_gen_qemu_st_tl(data0, addr, ctx->mem_idx, MO_TESL); + + tcg_gen_addi_tl(addr, addr, 4); + tcg_gen_qemu_st_tl(data1, addr, ctx->mem_idx, MO_TESL); + + return true; +} + /* Move data from memory into cache. */ static bool trans_pref(DisasContext *ctx, arg_pref *a) { -- 2.52.0
From: Djordje Todorovic <Djordje.Todorovic@htecgroup.com> Add RISC-V implementation of the Coherent Manager Global Control Register (CMGCR) device. It is based on the existing MIPS CMGCR implementation but adapted for RISC-V systems. The CMGCR device provides global system control for multi-core configurations in RISC-V systems. This is needed for the MIPS BOSTON AIA board. Signed-off-by: Chao-ying Fu <cfu@mips.com> Signed-off-by: Djordje Todorovic <djordje.todorovic@htecgroup.com> Reviewed-by: Daniel Henrique Barboza <dbarboza@ventanamicro.com> Message-ID: <20260108134128.2218102-8-djordje.todorovic@htecgroup.com> Signed-off-by: Alistair Francis <alistair.francis@wdc.com> --- include/hw/misc/riscv_cmgcr.h | 48 +++++++ hw/misc/riscv_cmgcr.c | 243 ++++++++++++++++++++++++++++++++++ hw/misc/Kconfig | 9 ++ hw/misc/meson.build | 2 + 4 files changed, 302 insertions(+) create mode 100644 include/hw/misc/riscv_cmgcr.h create mode 100644 hw/misc/riscv_cmgcr.c diff --git a/include/hw/misc/riscv_cmgcr.h b/include/hw/misc/riscv_cmgcr.h new file mode 100644 index XXXXXXX..XXXXXXX --- /dev/null +++ b/include/hw/misc/riscv_cmgcr.h @@ -XXX,XX +XXX,XX @@ +/* + * Coherent Manager Global Control Register + * + * Copyright (C) 2015 Imagination Technologies + * + * Copyright (C) 2025 MIPS + * + * SPDX-License-Identifier: GPL-2.0-or-later + * + */ + +#ifndef RISCV_CMGCR_H +#define RISCV_CMGCR_H + +#include "hw/core/sysbus.h" +#include "qom/object.h" + +#define TYPE_RISCV_GCR "riscv-gcr" +OBJECT_DECLARE_SIMPLE_TYPE(RISCVGCRState, RISCV_GCR) + +#define GCR_BASE_ADDR 0x1fb80000ULL +#define GCR_MAX_VPS 256 + +typedef struct RISCVGCRVPState RISCVGCRVPState; +struct RISCVGCRVPState { + uint64_t reset_base; +}; + +typedef struct RISCVGCRState RISCVGCRState; +struct RISCVGCRState { + SysBusDevice parent_obj; + + int32_t gcr_rev; + uint32_t cluster_id; + uint32_t num_vps; + uint32_t num_hart; + uint32_t num_core; + hwaddr gcr_base; + MemoryRegion iomem; + MemoryRegion *cpc_mr; + + uint64_t cpc_base; + + /* VP Local/Other Registers */ + RISCVGCRVPState *vps; +}; + +#endif /* RISCV_CMGCR_H */ diff --git a/hw/misc/riscv_cmgcr.c b/hw/misc/riscv_cmgcr.c new file mode 100644 index XXXXXXX..XXXXXXX --- /dev/null +++ b/hw/misc/riscv_cmgcr.c @@ -XXX,XX +XXX,XX @@ +/* + * Coherent Manager Global Control Register + * + * Copyright (C) 2015 Imagination Technologies + * + * Copyright (C) 2025 MIPS + * + * SPDX-License-Identifier: GPL-2.0-or-later + * + * Reference: MIPS P8700 documentation + * (https://mips.com/products/hardware/p8700/) + */ + +#include "qemu/osdep.h" +#include "qemu/log.h" +#include "qemu/module.h" +#include "qapi/error.h" +#include "hw/core/sysbus.h" +#include "migration/vmstate.h" +#include "hw/misc/riscv_cmgcr.h" +#include "hw/core/qdev-properties.h" + +#include "cpu.h" + +#define CM_RESET_VEC 0x1FC00000 +#define GCR_ADDRSPACE_SZ 0x8000 + +/* Offsets to register blocks */ +#define RISCV_GCB_OFS 0x0000 /* Global Control Block */ +#define RISCV_CLCB_OFS 0x2000 /* Core Control Block */ +#define RISCV_CORE_REG_STRIDE 0x100 /* Stride between core-specific registers */ + +/* Global Control Block Register Map */ +#define GCR_CONFIG_OFS 0x0000 +#define GCR_BASE_OFS 0x0008 +#define GCR_REV_OFS 0x0030 +#define GCR_CPC_STATUS_OFS 0x00F0 +#define GCR_L2_CONFIG_OFS 0x0130 + +/* GCR_L2_CONFIG register fields */ +#define GCR_L2_CONFIG_BYPASS_SHF 20 +#define GCR_L2_CONFIG_BYPASS_MSK ((0x1ULL) << GCR_L2_CONFIG_BYPASS_SHF) + +/* GCR_BASE register fields */ +#define GCR_BASE_GCRBASE_MSK 0xffffffff8000ULL + +/* GCR_CPC_BASE register fields */ +#define GCR_CPC_BASE_CPCEN_MSK 1 +#define GCR_CPC_BASE_CPCBASE_MSK 0xFFFFFFFF8000ULL +#define GCR_CPC_BASE_MSK (GCR_CPC_BASE_CPCEN_MSK | GCR_CPC_BASE_CPCBASE_MSK) + +/* GCR_CL_RESETBASE_OFS register fields */ +#define GCR_CL_RESET_BASE_RESETBASE_MSK 0xFFFFFFFFFFFFF000U +#define GCR_CL_RESET_BASE_MSK GCR_CL_RESET_BASE_RESETBASE_MSK + +static inline bool is_cpc_connected(RISCVGCRState *s) +{ + return s->cpc_mr != NULL; +} + +static inline void update_cpc_base(RISCVGCRState *gcr, uint64_t val) +{ + if (is_cpc_connected(gcr)) { + gcr->cpc_base = val & GCR_CPC_BASE_MSK; + memory_region_transaction_begin(); + memory_region_set_address(gcr->cpc_mr, + gcr->cpc_base & GCR_CPC_BASE_CPCBASE_MSK); + memory_region_set_enabled(gcr->cpc_mr, + gcr->cpc_base & GCR_CPC_BASE_CPCEN_MSK); + memory_region_transaction_commit(); + } +} + +static inline void update_gcr_base(RISCVGCRState *gcr, uint64_t val) +{ + gcr->gcr_base = val & GCR_BASE_GCRBASE_MSK; + memory_region_set_address(&gcr->iomem, gcr->gcr_base); + + /* + * For boston-aia, cpc_base is set to gcr_base + 0x8001 to enable + * cpc automatically. + */ + update_cpc_base(gcr, val + 0x8001); +} + +/* Read GCR registers */ +static uint64_t gcr_read(void *opaque, hwaddr addr, unsigned size) +{ + RISCVGCRState *gcr = (RISCVGCRState *) opaque; + + switch (addr) { + /* Global Control Block Register */ + case GCR_CONFIG_OFS: + /* Set PCORES to 0 */ + return 0; + case GCR_BASE_OFS: + return gcr->gcr_base; + case GCR_REV_OFS: + return gcr->gcr_rev; + case GCR_CPC_STATUS_OFS: + return is_cpc_connected(gcr); + case GCR_L2_CONFIG_OFS: + /* L2 BYPASS */ + return GCR_L2_CONFIG_BYPASS_MSK; + default: + qemu_log_mask(LOG_UNIMP, "Read %d bytes at GCR offset 0x%" HWADDR_PRIx + "\n", size, addr); + } + return 0; +} + +static inline target_ulong get_exception_base(RISCVGCRVPState *vps) +{ + return vps->reset_base & GCR_CL_RESET_BASE_RESETBASE_MSK; +} + +/* Write GCR registers */ +static void gcr_write(void *opaque, hwaddr addr, uint64_t data, unsigned size) +{ + RISCVGCRState *gcr = (RISCVGCRState *)opaque; + RISCVGCRVPState *current_vps; + int cpu_index, c, h; + + for (c = 0; c < gcr->num_core; c++) { + for (h = 0; h < gcr->num_hart; h++) { + if (addr == RISCV_CLCB_OFS + c * RISCV_CORE_REG_STRIDE + h * 8) { + cpu_index = c * gcr->num_hart + h; + current_vps = &gcr->vps[cpu_index]; + current_vps->reset_base = data & GCR_CL_RESET_BASE_MSK; + cpu_set_exception_base(cpu_index + gcr->cluster_id * + gcr->num_core * gcr->num_hart, + get_exception_base(current_vps)); + return; + } + } + } + + switch (addr) { + case GCR_BASE_OFS: + update_gcr_base(gcr, data); + break; + default: + qemu_log_mask(LOG_UNIMP, "Write %d bytes at GCR offset 0x%" HWADDR_PRIx + " 0x%" PRIx64 "\n", size, addr, data); + break; + } +} + +static const MemoryRegionOps gcr_ops = { + .read = gcr_read, + .write = gcr_write, + .endianness = DEVICE_LITTLE_ENDIAN, + .impl = { + .max_access_size = 8, + }, +}; + +static void riscv_gcr_init(Object *obj) +{ + SysBusDevice *sbd = SYS_BUS_DEVICE(obj); + RISCVGCRState *s = RISCV_GCR(obj); + + memory_region_init_io(&s->iomem, OBJECT(s), &gcr_ops, s, + "riscv-gcr", GCR_ADDRSPACE_SZ); + sysbus_init_mmio(sbd, &s->iomem); +} + +static void riscv_gcr_reset(DeviceState *dev) +{ + RISCVGCRState *s = RISCV_GCR(dev); + int i; + + /* Update cpc_base to gcr_base + 0x8001 to enable cpc automatically. */ + update_cpc_base(s, s->gcr_base + 0x8001); + + for (i = 0; i < s->num_vps; i++) { + s->vps[i].reset_base = CM_RESET_VEC & GCR_CL_RESET_BASE_MSK; + cpu_set_exception_base(i, get_exception_base(&s->vps[i])); + } +} + +static const VMStateDescription vmstate_riscv_gcr = { + .name = "riscv-gcr", + .version_id = 0, + .minimum_version_id = 0, + .fields = (VMStateField[]) { + VMSTATE_UINT64(cpc_base, RISCVGCRState), + VMSTATE_END_OF_LIST() + }, +}; + +static const Property riscv_gcr_properties[] = { + DEFINE_PROP_UINT32("cluster-id", RISCVGCRState, cluster_id, 0), + DEFINE_PROP_UINT32("num-vp", RISCVGCRState, num_vps, 1), + DEFINE_PROP_UINT32("num-hart", RISCVGCRState, num_hart, 1), + DEFINE_PROP_UINT32("num-core", RISCVGCRState, num_core, 1), + DEFINE_PROP_INT32("gcr-rev", RISCVGCRState, gcr_rev, 0xa00), + DEFINE_PROP_UINT64("gcr-base", RISCVGCRState, gcr_base, GCR_BASE_ADDR), + DEFINE_PROP_LINK("cpc", RISCVGCRState, cpc_mr, TYPE_MEMORY_REGION, + MemoryRegion *), +}; + +static void riscv_gcr_realize(DeviceState *dev, Error **errp) +{ + RISCVGCRState *s = RISCV_GCR(dev); + + /* Validate num_vps */ + if (s->num_vps == 0) { + error_setg(errp, "num-vp must be at least 1"); + return; + } + if (s->num_vps > GCR_MAX_VPS) { + error_setg(errp, "num-vp cannot exceed %d", GCR_MAX_VPS); + return; + } + + /* Create local set of registers for each VP */ + s->vps = g_new(RISCVGCRVPState, s->num_vps); +} + +static void riscv_gcr_class_init(ObjectClass *klass, const void *data) +{ + DeviceClass *dc = DEVICE_CLASS(klass); + device_class_set_props(dc, riscv_gcr_properties); + dc->vmsd = &vmstate_riscv_gcr; + device_class_set_legacy_reset(dc, riscv_gcr_reset); + dc->realize = riscv_gcr_realize; +} + +static const TypeInfo riscv_gcr_info = { + .name = TYPE_RISCV_GCR, + .parent = TYPE_SYS_BUS_DEVICE, + .instance_size = sizeof(RISCVGCRState), + .instance_init = riscv_gcr_init, + .class_init = riscv_gcr_class_init, +}; + +static void riscv_gcr_register_types(void) +{ + type_register_static(&riscv_gcr_info); +} + +type_init(riscv_gcr_register_types) diff --git a/hw/misc/Kconfig b/hw/misc/Kconfig index XXXXXXX..XXXXXXX 100644 --- a/hw/misc/Kconfig +++ b/hw/misc/Kconfig @@ -XXX,XX +XXX,XX @@ config MIPS_ITU bool depends on TCG +config RISCV_MIPS_CMGCR + bool + +config MIPS_BOSTON_AIA + bool + default y + depends on RISCV64 + select RISCV_MIPS_CMGCR + config MPS2_FPGAIO bool select LED diff --git a/hw/misc/meson.build b/hw/misc/meson.build index XXXXXXX..XXXXXXX 100644 --- a/hw/misc/meson.build +++ b/hw/misc/meson.build @@ -XXX,XX +XXX,XX @@ specific_ss.add(when: 'CONFIG_MAC_VIA', if_true: files('mac_via.c')) specific_ss.add(when: 'CONFIG_MIPS_CPS', if_true: files('mips_cmgcr.c', 'mips_cpc.c')) specific_ss.add(when: 'CONFIG_MIPS_ITU', if_true: files('mips_itu.c')) +specific_ss.add(when: 'CONFIG_RISCV_MIPS_CMGCR', if_true: files('riscv_cmgcr.c')) + system_ss.add(when: 'CONFIG_SBSA_REF', if_true: files('sbsa_ec.c')) # HPPA devices -- 2.52.0
From: Djordje Todorovic <Djordje.Todorovic@htecgroup.com> Add RISC-V implementation of the Cluster Power Controller (CPC) device. It is based on the existing MIPS CPC implementations but adapted for RISC-V systems. The CPC device manages power control for CPU clusters in RISC-V systems. This is needed for the MIPS BOSTON AIA board. Signed-off-by: Chao-ying Fu <cfu@mips.com> Signed-off-by: Djordje Todorovic <djordje.todorovic@htecgroup.com> Reviewed-by: Daniel Henrique Barboza <dbarboza@ventanamicro.com> Message-ID: <20260108134128.2218102-9-djordje.todorovic@htecgroup.com> Signed-off-by: Alistair Francis <alistair.francis@wdc.com> --- include/hw/misc/riscv_cpc.h | 64 +++++++++ hw/misc/riscv_cpc.c | 265 ++++++++++++++++++++++++++++++++++++ hw/misc/Kconfig | 4 + hw/misc/meson.build | 1 + 4 files changed, 334 insertions(+) create mode 100644 include/hw/misc/riscv_cpc.h create mode 100644 hw/misc/riscv_cpc.c diff --git a/include/hw/misc/riscv_cpc.h b/include/hw/misc/riscv_cpc.h new file mode 100644 index XXXXXXX..XXXXXXX --- /dev/null +++ b/include/hw/misc/riscv_cpc.h @@ -XXX,XX +XXX,XX @@ +/* + * Cluster Power Controller emulation + * + * Copyright (c) 2016 Imagination Technologies + * + * Copyright (c) 2025 MIPS + * + * SPDX-License-Identifier: GPL-2.0-or-later + * + */ + +#ifndef RISCV_CPC_H +#define RISCV_CPC_H + +#include "hw/core/sysbus.h" +#include "qom/object.h" + +#define CPC_ADDRSPACE_SZ 0x6000 + +/* CPC global register offsets relative to base address */ +#define CPC_MTIME_REG_OFS 0x50 + +#define CPC_CM_STAT_CONF_OFS 0x1008 + +/* CPC blocks offsets relative to base address */ +#define CPC_CL_BASE_OFS 0x2000 +#define CPC_CORE_REG_STRIDE 0x100 /* Stride between core-specific registers */ + +/* CPC register offsets relative to block offsets */ +#define CPC_STAT_CONF_OFS 0x08 +#define CPC_VP_STOP_OFS 0x20 +#define CPC_VP_RUN_OFS 0x28 +#define CPC_VP_RUNNING_OFS 0x30 + +#define SEQ_STATE_BIT 19 +#define SEQ_STATE_U5 0x6 +#define SEQ_STATE_U6 0x7 +#define CPC_Cx_STAT_CONF_SEQ_STATE_U5 (SEQ_STATE_U5 << SEQ_STATE_BIT) +#define CPC_Cx_STAT_CONF_SEQ_STATE_U6 (SEQ_STATE_U6 << SEQ_STATE_BIT) + +#define TYPE_RISCV_CPC "xmips-cpc" +OBJECT_DECLARE_SIMPLE_TYPE(RISCVCPCState, RISCV_CPC) + +typedef struct RISCVCPCState { + SysBusDevice parent_obj; + + uint32_t cluster_id; + uint32_t num_vp; + uint32_t num_hart; + uint32_t num_core; + /* VPs running from restart mask */ + uint64_t vps_start_running_mask; + + MemoryRegion mr; + /* Indicates which VPs are in the run state mask */ + uint64_t vps_running_mask; + + /* Array of CPUs managed by this CPC */ + CPUState **cpus; +} RISCVCPCState; + +#define CPC_MAX_VPS 64 /* Maximum number of VPs supported */ + +#endif /* RISCV_CPC_H */ diff --git a/hw/misc/riscv_cpc.c b/hw/misc/riscv_cpc.c new file mode 100644 index XXXXXXX..XXXXXXX --- /dev/null +++ b/hw/misc/riscv_cpc.c @@ -XXX,XX +XXX,XX @@ +/* + * Cluster Power Controller emulation + * + * Copyright (c) 2016 Imagination Technologies + * + * Copyright (c) 2025 MIPS + * + * SPDX-License-Identifier: GPL-2.0-or-later + * + * Reference: MIPS P8700 documentation + * (https://mips.com/products/hardware/p8700/) + */ + +#include "qemu/osdep.h" +#include "qapi/error.h" +#include "cpu.h" +#include "qemu/log.h" +#include "qemu/module.h" +#include "qemu/timer.h" +#include "qemu/bitops.h" +#include "hw/core/sysbus.h" +#include "migration/vmstate.h" + +#include "hw/misc/riscv_cpc.h" +#include "hw/core/qdev-properties.h" +#include "hw/intc/riscv_aclint.h" +#include "hw/core/resettable.h" + +static inline uint64_t cpc_vp_run_mask(RISCVCPCState *cpc) +{ + return MAKE_64BIT_MASK(0, cpc->num_vp); +} + +static void riscv_cpu_reset_async_work(CPUState *cs, run_on_cpu_data data) +{ + RISCVCPCState *cpc = (RISCVCPCState *) data.host_ptr; + int i; + + cpu_reset(cs); + cs->halted = 0; + + /* Find this CPU's index in the CPC's CPU array */ + for (i = 0; i < cpc->num_vp; i++) { + if (cpc->cpus[i] == cs) { + cpc->vps_running_mask |= BIT_ULL(i); + break; + } + } +} + +static void cpc_run_vp(RISCVCPCState *cpc, uint64_t vps_run_mask) +{ + int vp; + + for (vp = 0; vp < cpc->num_vp; vp++) { + CPUState *cs = cpc->cpus[vp]; + + if (!extract64(vps_run_mask, vp, 1)) { + continue; + } + + if (extract64(cpc->vps_running_mask, vp, 1)) { + continue; + } + + /* + * To avoid racing with a CPU we are just kicking off. + * We do the final bit of preparation for the work in + * the target CPUs context. + */ + async_safe_run_on_cpu(cs, riscv_cpu_reset_async_work, + RUN_ON_CPU_HOST_PTR(cpc)); + } +} + +static void cpc_stop_vp(RISCVCPCState *cpc, uint64_t vps_stop_mask) +{ + int vp; + + for (vp = 0; vp < cpc->num_vp; vp++) { + CPUState *cs = cpc->cpus[vp]; + + if (!extract64(vps_stop_mask, vp, 1)) { + continue; + } + + if (!extract64(cpc->vps_running_mask, vp, 1)) { + continue; + } + + cpu_interrupt(cs, CPU_INTERRUPT_HALT); + cpc->vps_running_mask &= ~BIT_ULL(vp); + } +} + +static void cpc_write(void *opaque, hwaddr offset, uint64_t data, + unsigned size) +{ + RISCVCPCState *s = opaque; + int cpu_index, c; + + for (c = 0; c < s->num_core; c++) { + cpu_index = c * s->num_hart + + s->cluster_id * s->num_core * s->num_hart; + if (offset == + CPC_CL_BASE_OFS + CPC_VP_RUN_OFS + c * CPC_CORE_REG_STRIDE) { + cpc_run_vp(s, (data << cpu_index) & cpc_vp_run_mask(s)); + return; + } + if (offset == + CPC_CL_BASE_OFS + CPC_VP_STOP_OFS + c * CPC_CORE_REG_STRIDE) { + cpc_stop_vp(s, (data << cpu_index) & cpc_vp_run_mask(s)); + return; + } + } + + switch (offset) { + default: + qemu_log_mask(LOG_UNIMP, + "%s: Bad offset 0x%x\n", __func__, (int)offset); + break; + } + + return; +} + +static uint64_t cpc_read(void *opaque, hwaddr offset, unsigned size) +{ + RISCVCPCState *s = opaque; + int c; + + for (c = 0; c < s->num_core; c++) { + if (offset == + CPC_CL_BASE_OFS + CPC_STAT_CONF_OFS + c * CPC_CORE_REG_STRIDE) { + /* Return the state as U6. */ + return CPC_Cx_STAT_CONF_SEQ_STATE_U6; + } + } + + switch (offset) { + case CPC_CM_STAT_CONF_OFS: + return CPC_Cx_STAT_CONF_SEQ_STATE_U5; + case CPC_MTIME_REG_OFS: + return muldiv64(qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL), + RISCV_ACLINT_DEFAULT_TIMEBASE_FREQ, + NANOSECONDS_PER_SECOND); + return 0; + default: + qemu_log_mask(LOG_UNIMP, + "%s: Bad offset 0x%x\n", __func__, (int)offset); + return 0; + } +} + +static const MemoryRegionOps cpc_ops = { + .read = cpc_read, + .write = cpc_write, + .endianness = DEVICE_LITTLE_ENDIAN, + .impl = { + .min_access_size = 8, + }, +}; + +static void riscv_cpc_init(Object *obj) +{ + SysBusDevice *sbd = SYS_BUS_DEVICE(obj); + RISCVCPCState *s = RISCV_CPC(obj); + int i; + + memory_region_init_io(&s->mr, OBJECT(s), &cpc_ops, s, "xmips-cpc", + CPC_ADDRSPACE_SZ); + sysbus_init_mmio(sbd, &s->mr); + + /* Allocate CPU array */ + s->cpus = g_new0(CPUState *, CPC_MAX_VPS); + + /* Create link properties for each possible CPU slot */ + for (i = 0; i < CPC_MAX_VPS; i++) { + char *propname = g_strdup_printf("cpu[%d]", i); + object_property_add_link(obj, propname, TYPE_CPU, + (Object **)&s->cpus[i], + qdev_prop_allow_set_link_before_realize, + OBJ_PROP_LINK_STRONG); + g_free(propname); + } +} + +static void riscv_cpc_realize(DeviceState *dev, Error **errp) +{ + RISCVCPCState *s = RISCV_CPC(dev); + int i; + + if (s->vps_start_running_mask & ~cpc_vp_run_mask(s)) { + error_setg(errp, + "incorrect vps-start-running-mask 0x%" PRIx64 + " for num_vp = %d", + s->vps_start_running_mask, s->num_vp); + return; + } + + /* Verify that required CPUs have been linked */ + for (i = 0; i < s->num_vp; i++) { + if (!s->cpus[i]) { + error_setg(errp, "CPU %d has not been linked", i); + return; + } + } +} + +static void riscv_cpc_reset_hold(Object *obj, ResetType type) +{ + RISCVCPCState *s = RISCV_CPC(obj); + + /* Reflect the fact that all VPs are halted on reset */ + s->vps_running_mask = 0; + + /* Put selected VPs into run state */ + cpc_run_vp(s, s->vps_start_running_mask); +} + +static const VMStateDescription vmstate_riscv_cpc = { + .name = "xmips-cpc", + .version_id = 0, + .minimum_version_id = 0, + .fields = (VMStateField[]) { + VMSTATE_UINT64(vps_running_mask, RISCVCPCState), + VMSTATE_END_OF_LIST() + }, +}; + +static const Property riscv_cpc_properties[] = { + DEFINE_PROP_UINT32("cluster-id", RISCVCPCState, cluster_id, 0x0), + DEFINE_PROP_UINT32("num-vp", RISCVCPCState, num_vp, 0x1), + DEFINE_PROP_UINT32("num-hart", RISCVCPCState, num_hart, 0x1), + DEFINE_PROP_UINT32("num-core", RISCVCPCState, num_core, 0x1), + DEFINE_PROP_UINT64("vps-start-running-mask", RISCVCPCState, + vps_start_running_mask, 0x1), +}; + +static void riscv_cpc_class_init(ObjectClass *klass, const void *data) +{ + DeviceClass *dc = DEVICE_CLASS(klass); + ResettableClass *rc = RESETTABLE_CLASS(klass); + + dc->realize = riscv_cpc_realize; + rc->phases.hold = riscv_cpc_reset_hold; + dc->vmsd = &vmstate_riscv_cpc; + device_class_set_props(dc, riscv_cpc_properties); + dc->user_creatable = false; +} + +static const TypeInfo riscv_cpc_info = { + .name = TYPE_RISCV_CPC, + .parent = TYPE_SYS_BUS_DEVICE, + .instance_size = sizeof(RISCVCPCState), + .instance_init = riscv_cpc_init, + .class_init = riscv_cpc_class_init, +}; + +static void riscv_cpc_register_types(void) +{ + type_register_static(&riscv_cpc_info); +} + +type_init(riscv_cpc_register_types) diff --git a/hw/misc/Kconfig b/hw/misc/Kconfig index XXXXXXX..XXXXXXX 100644 --- a/hw/misc/Kconfig +++ b/hw/misc/Kconfig @@ -XXX,XX +XXX,XX @@ config MIPS_ITU config RISCV_MIPS_CMGCR bool +config RISCV_MIPS_CPC + bool + config MIPS_BOSTON_AIA bool default y depends on RISCV64 select RISCV_MIPS_CMGCR + select RISCV_MIPS_CPC config MPS2_FPGAIO bool diff --git a/hw/misc/meson.build b/hw/misc/meson.build index XXXXXXX..XXXXXXX 100644 --- a/hw/misc/meson.build +++ b/hw/misc/meson.build @@ -XXX,XX +XXX,XX @@ specific_ss.add(when: 'CONFIG_MIPS_CPS', if_true: files('mips_cmgcr.c', 'mips_cp specific_ss.add(when: 'CONFIG_MIPS_ITU', if_true: files('mips_itu.c')) specific_ss.add(when: 'CONFIG_RISCV_MIPS_CMGCR', if_true: files('riscv_cmgcr.c')) +specific_ss.add(when: 'CONFIG_RISCV_MIPS_CPC', if_true: files('riscv_cpc.c')) system_ss.add(when: 'CONFIG_SBSA_REF', if_true: files('sbsa_ec.c')) -- 2.52.0
From: Djordje Todorovic <Djordje.Todorovic@htecgroup.com> Add support for the Coherent Processing System for RISC-V. This enables SMP support for RISC-V boards that require cache-coherent multiprocessor systems. Signed-off-by: Chao-ying Fu <cfu@mips.com> Signed-off-by: Djordje Todorovic <djordje.todorovic@htecgroup.com> Acked-by: Daniel Henrique Barboza <dbarboza@ventanamicro.com> Message-ID: <20260108134128.2218102-10-djordje.todorovic@htecgroup.com> Signed-off-by: Alistair Francis <alistair.francis@wdc.com> --- include/hw/riscv/cps.h | 66 ++++++++++++++ hw/riscv/cps.c | 196 +++++++++++++++++++++++++++++++++++++++++ hw/misc/Kconfig | 4 + hw/riscv/meson.build | 2 + 4 files changed, 268 insertions(+) create mode 100644 include/hw/riscv/cps.h create mode 100644 hw/riscv/cps.c diff --git a/include/hw/riscv/cps.h b/include/hw/riscv/cps.h new file mode 100644 index XXXXXXX..XXXXXXX --- /dev/null +++ b/include/hw/riscv/cps.h @@ -XXX,XX +XXX,XX @@ +/* + * Coherent Processing System emulation. + * + * Copyright (c) 2016 Imagination Technologies + * + * Copyright (c) 2025 MIPS + * + * SPDX-License-Identifier: GPL-2.0-or-later + * + */ + +#ifndef RISCV_CPS_H +#define RISCV_CPS_H + +#include "hw/core/sysbus.h" +#include "hw/misc/riscv_cmgcr.h" +#include "hw/misc/riscv_cpc.h" +#include "target/riscv/cpu.h" +#include "qom/object.h" + +#define TYPE_RISCV_CPS "riscv-cps" +OBJECT_DECLARE_SIMPLE_TYPE(RISCVCPSState, RISCV_CPS) + +/* The model supports up to 64 harts. */ +#define MAX_HARTS 64 + +/* The global CM base for the boston-aia model. */ +#define GLOBAL_CM_BASE 0x16100000 +/* The CM block is 512 KiB. */ +#define CM_SIZE (1 << 19) + +/* + * The mhartid bits has cluster at bit 16, core at bit 4, and hart at + * bit 0. + */ + +#define MHARTID_CLUSTER_SHIFT 16 +#define MHARTID_CORE_SHIFT 4 +#define MHARTID_HART_SHIFT 0 + +#define APLIC_NUM_SOURCES 0x35 /* Arbitray maximum number of interrupts. */ +#define APLIC_NUM_PRIO_BITS 3 +#define AIA_PLIC_M_OFFSET 0x40000 +#define AIA_PLIC_M_SIZE 0x8000 +#define AIA_PLIC_S_OFFSET 0x60000 +#define AIA_PLIC_S_SIZE 0x8000 +#define AIA_CLINT_OFFSET 0x50000 + +typedef struct RISCVCPSState { + SysBusDevice parent_obj; + + uint32_t num_vp; + uint32_t num_hart; + uint32_t num_core; + uint64_t gcr_base; + char *cpu_type; + + MemoryRegion container; + RISCVGCRState gcr; + RISCVCPCState cpc; + + DeviceState *aplic; + CPUState **cpus; +} RISCVCPSState; + +#endif diff --git a/hw/riscv/cps.c b/hw/riscv/cps.c new file mode 100644 index XXXXXXX..XXXXXXX --- /dev/null +++ b/hw/riscv/cps.c @@ -XXX,XX +XXX,XX @@ +/* + * Coherent Processing System emulation. + * + * Copyright (c) 2016 Imagination Technologies + * + * Copyright (c) 2025 MIPS + * + * SPDX-License-Identifier: GPL-2.0-or-later + * + */ + +#include "qemu/osdep.h" +#include "qapi/error.h" +#include "qemu/module.h" +#include "hw/riscv/cps.h" +#include "hw/core/qdev-properties.h" +#include "system/reset.h" +#include "hw/intc/riscv_aclint.h" +#include "hw/intc/riscv_aplic.h" +#include "hw/intc/riscv_imsic.h" +#include "hw/pci/msi.h" + +static void riscv_cps_init(Object *obj) +{ + SysBusDevice *sbd = SYS_BUS_DEVICE(obj); + RISCVCPSState *s = RISCV_CPS(obj); + + /* + * Cover entire address space as there do not seem to be any + * constraints for the base address of CPC . + */ + memory_region_init(&s->container, obj, "mips-cps-container", UINT64_MAX); + sysbus_init_mmio(sbd, &s->container); +} + +static void main_cpu_reset(void *opaque) +{ + CPUState *cs = opaque; + + cpu_reset(cs); +} + +static void riscv_cps_realize(DeviceState *dev, Error **errp) +{ + RISCVCPSState *s = RISCV_CPS(dev); + RISCVCPU *cpu; + int i; + + /* Validate num_vp */ + if (s->num_vp == 0) { + error_setg(errp, "num-vp must be at least 1"); + return; + } + if (s->num_vp > MAX_HARTS) { + error_setg(errp, "num-vp cannot exceed %d", MAX_HARTS); + return; + } + + /* Allocate CPU array */ + s->cpus = g_new0(CPUState *, s->num_vp); + + /* Set up cpu_index and mhartid for avaiable CPUs. */ + int harts_in_cluster = s->num_hart * s->num_core; + int num_of_clusters = s->num_vp / harts_in_cluster; + for (i = 0; i < s->num_vp; i++) { + cpu = RISCV_CPU(object_new(s->cpu_type)); + + /* All VPs are halted on reset. Leave powering up to CPC. */ + object_property_set_bool(OBJECT(cpu), "start-powered-off", true, + &error_abort); + + if (!qdev_realize_and_unref(DEVICE(cpu), NULL, errp)) { + return; + } + + /* Store CPU in array */ + s->cpus[i] = CPU(cpu); + + /* Set up mhartid */ + int cluster_id = i / harts_in_cluster; + int hart_id = (i % harts_in_cluster) % s->num_hart; + int core_id = (i % harts_in_cluster) / s->num_hart; + int mhartid = (cluster_id << MHARTID_CLUSTER_SHIFT) + + (core_id << MHARTID_CORE_SHIFT) + + (hart_id << MHARTID_HART_SHIFT); + cpu->env.mhartid = mhartid; + qemu_register_reset(main_cpu_reset, s->cpus[i]); + } + + /* Cluster Power Controller */ + object_initialize_child(OBJECT(dev), "cpc", &s->cpc, TYPE_RISCV_CPC); + object_property_set_uint(OBJECT(&s->cpc), "cluster-id", 0, + &error_abort); + object_property_set_uint(OBJECT(&s->cpc), "num-vp", s->num_vp, + &error_abort); + object_property_set_uint(OBJECT(&s->cpc), "num-hart", s->num_hart, + &error_abort); + object_property_set_uint(OBJECT(&s->cpc), "num-core", s->num_core, + &error_abort); + + /* Pass CPUs to CPC using link properties */ + for (i = 0; i < s->num_vp; i++) { + char *propname = g_strdup_printf("cpu[%d]", i); + object_property_set_link(OBJECT(&s->cpc), propname, + OBJECT(s->cpus[i]), &error_abort); + g_free(propname); + } + + if (!sysbus_realize(SYS_BUS_DEVICE(&s->cpc), errp)) { + return; + } + + memory_region_add_subregion(&s->container, 0, + sysbus_mmio_get_region(SYS_BUS_DEVICE(&s->cpc), 0)); + + /* Global Configuration Registers */ + object_initialize_child(OBJECT(dev), "gcr", &s->gcr, TYPE_RISCV_GCR); + object_property_set_uint(OBJECT(&s->gcr), "cluster-id", 0, + &error_abort); + object_property_set_uint(OBJECT(&s->gcr), "num-vp", s->num_vp, + &error_abort); + object_property_set_int(OBJECT(&s->gcr), "gcr-rev", 0xa00, + &error_abort); + object_property_set_int(OBJECT(&s->gcr), "gcr-base", s->gcr_base, + &error_abort); + object_property_set_link(OBJECT(&s->gcr), "cpc", OBJECT(&s->cpc.mr), + &error_abort); + if (!sysbus_realize(SYS_BUS_DEVICE(&s->gcr), errp)) { + return; + } + + memory_region_add_subregion(&s->container, s->gcr_base, + sysbus_mmio_get_region(SYS_BUS_DEVICE(&s->gcr), 0)); + + for (i = 0; i < num_of_clusters; i++) { + uint64_t cm_base = GLOBAL_CM_BASE + (CM_SIZE * i); + uint32_t hartid_base = i << MHARTID_CLUSTER_SHIFT; + s->aplic = riscv_aplic_create(cm_base + AIA_PLIC_M_OFFSET, + AIA_PLIC_M_SIZE, + hartid_base, /* hartid_base */ + MAX_HARTS, /* num_harts */ + APLIC_NUM_SOURCES, + APLIC_NUM_PRIO_BITS, + false, true, NULL); + riscv_aplic_create(cm_base + AIA_PLIC_S_OFFSET, + AIA_PLIC_S_SIZE, + hartid_base, /* hartid_base */ + MAX_HARTS, /* num_harts */ + APLIC_NUM_SOURCES, + APLIC_NUM_PRIO_BITS, + false, false, s->aplic); + /* PLIC changes msi_nonbroken to ture. We revert the change. */ + msi_nonbroken = false; + riscv_aclint_swi_create(cm_base + AIA_CLINT_OFFSET, + hartid_base, MAX_HARTS, false); + riscv_aclint_mtimer_create(cm_base + AIA_CLINT_OFFSET + + RISCV_ACLINT_SWI_SIZE, + RISCV_ACLINT_DEFAULT_MTIMER_SIZE, + hartid_base, + MAX_HARTS, + RISCV_ACLINT_DEFAULT_MTIMECMP, + RISCV_ACLINT_DEFAULT_MTIME, + RISCV_ACLINT_DEFAULT_TIMEBASE_FREQ, false); + } +} + +static const Property riscv_cps_properties[] = { + DEFINE_PROP_UINT32("num-vp", RISCVCPSState, num_vp, 1), + DEFINE_PROP_UINT32("num-hart", RISCVCPSState, num_hart, 1), + DEFINE_PROP_UINT32("num-core", RISCVCPSState, num_core, 1), + DEFINE_PROP_UINT64("gcr-base", RISCVCPSState, gcr_base, GCR_BASE_ADDR), + DEFINE_PROP_STRING("cpu-type", RISCVCPSState, cpu_type), +}; + +static void riscv_cps_class_init(ObjectClass *klass, const void *data) +{ + DeviceClass *dc = DEVICE_CLASS(klass); + + dc->realize = riscv_cps_realize; + device_class_set_props(dc, riscv_cps_properties); +} + +static const TypeInfo riscv_cps_info = { + .name = TYPE_RISCV_CPS, + .parent = TYPE_SYS_BUS_DEVICE, + .instance_size = sizeof(RISCVCPSState), + .instance_init = riscv_cps_init, + .class_init = riscv_cps_class_init, +}; + +static void riscv_cps_register_types(void) +{ + type_register_static(&riscv_cps_info); +} + +type_init(riscv_cps_register_types) diff --git a/hw/misc/Kconfig b/hw/misc/Kconfig index XXXXXXX..XXXXXXX 100644 --- a/hw/misc/Kconfig +++ b/hw/misc/Kconfig @@ -XXX,XX +XXX,XX @@ config RISCV_MIPS_CMGCR config RISCV_MIPS_CPC bool +config RISCV_MIPS_CPS + bool + config MIPS_BOSTON_AIA bool default y depends on RISCV64 select RISCV_MIPS_CMGCR select RISCV_MIPS_CPC + select RISCV_MIPS_CPS config MPS2_FPGAIO bool diff --git a/hw/riscv/meson.build b/hw/riscv/meson.build index XXXXXXX..XXXXXXX 100644 --- a/hw/riscv/meson.build +++ b/hw/riscv/meson.build @@ -XXX,XX +XXX,XX @@ riscv_ss.add(when: 'CONFIG_RISCV_IOMMU', if_true: files( riscv_ss.add(when: 'CONFIG_MICROBLAZE_V', if_true: files('microblaze-v-generic.c')) riscv_ss.add(when: 'CONFIG_XIANGSHAN_KUNMINGHU', if_true: files('xiangshan_kmh.c')) +riscv_ss.add(when: 'CONFIG_RISCV_MIPS_CPS', if_true: files('cps.c')) + hw_arch += {'riscv': riscv_ss} -- 2.52.0
From: Djordje Todorovic <Djordje.Todorovic@htecgroup.com> The board model supports up to 64 harts with MIPS CPS, MIPS GCR, MIPS CPC, AIA plic, and AIA clint devices. The model can create boot code, if there is no -bios parameter. We can specify -smp x, cores=y,thread=z. Ex: Use 4 cores and 2 threads with each core to have 8 smp cpus as follows. qemu-system-riscv64 -cpu mips-p8700 \ -m 2G -M boston-aia \ -smp 8,cores=4,threads=2 -kernel fw_payload.bin \ -drive file=rootfs.ext2,format=raw -serial stdio Signed-off-by: Chao-ying Fu <cfu@mips.com> Signed-off-by: Djordje Todorovic <djordje.todorovic@htecgroup.com> Acked-by: Daniel Henrique Barboza <dbarboza@ventanamicro.com> Acked-by: Alistair Francis <alistair.francis@wdc.com> Message-ID: <20260108134128.2218102-11-djordje.todorovic@htecgroup.com> Signed-off-by: Alistair Francis <alistair.francis@wdc.com> --- docs/system/riscv/mips.rst | 20 + docs/system/target-riscv.rst | 1 + configs/devices/riscv64-softmmu/default.mak | 1 + hw/riscv/boston-aia.c | 471 ++++++++++++++++++++ hw/riscv/Kconfig | 6 + hw/riscv/meson.build | 1 + 6 files changed, 500 insertions(+) create mode 100644 docs/system/riscv/mips.rst create mode 100644 hw/riscv/boston-aia.c diff --git a/docs/system/riscv/mips.rst b/docs/system/riscv/mips.rst new file mode 100644 index XXXXXXX..XXXXXXX --- /dev/null +++ b/docs/system/riscv/mips.rst @@ -XXX,XX +XXX,XX @@ +Boards for RISC-V Processors by MIPS +==================================== + +RISC-V processors developed by MIPS support Boston-aia board model. The board +model supports up to 64 harts with MIPS CPS, MIPS GCR, MIPS CPC, AIA plic, +and AIA clint devices. The model can create boot code, if there is no +```-bios``` parameter. Also, we can specify ```-smp x,cores=y,thread=z```. + +Running Linux kernel +-------------------- + +For example, to use 4 cores and 2 threads with each core to have 8 smp cpus, +that runs on the ```mips-p8700``` CPU, run qemu as follows: + +.. code-block:: bash + + qemu-system-riscv64 -cpu mips-p8700 \ + -m 2G -M boston-aia \ + -smp 8,cores=4,threads=2 -kernel fw_payload.bin \ + -drive file=rootfs.ext2,format=raw -serial stdio diff --git a/docs/system/target-riscv.rst b/docs/system/target-riscv.rst index XXXXXXX..XXXXXXX 100644 --- a/docs/system/target-riscv.rst +++ b/docs/system/target-riscv.rst @@ -XXX,XX +XXX,XX @@ undocumented; you can get a complete list by running riscv/microblaze-v-generic riscv/microchip-icicle-kit + riscv/mips riscv/shakti-c riscv/sifive_u riscv/virt diff --git a/configs/devices/riscv64-softmmu/default.mak b/configs/devices/riscv64-softmmu/default.mak index XXXXXXX..XXXXXXX 100644 --- a/configs/devices/riscv64-softmmu/default.mak +++ b/configs/devices/riscv64-softmmu/default.mak @@ -XXX,XX +XXX,XX @@ # CONFIG_MICROCHIP_PFSOC=n # CONFIG_SHAKTI_C=n # CONFIG_XIANGSHAN_KUNMINGHU=n +# CONFIG_MIPS_BOSTON_AIA=n diff --git a/hw/riscv/boston-aia.c b/hw/riscv/boston-aia.c new file mode 100644 index XXXXXXX..XXXXXXX --- /dev/null +++ b/hw/riscv/boston-aia.c @@ -XXX,XX +XXX,XX @@ +/* + * MIPS Boston-aia development board emulation. + * + * Copyright (c) 2016 Imagination Technologies + * + * Copyright (c) 2025 MIPS + * + * SPDX-License-Identifier: GPL-2.0-or-later + * + */ + +#include "qemu/osdep.h" +#include "qemu/units.h" + +#include "hw/core/boards.h" +#include "hw/char/serial-mm.h" +#include "hw/ide/pci.h" +#include "hw/ide/ahci-pci.h" +#include "hw/core/loader.h" +#include "hw/riscv/cps.h" +#include "hw/pci-host/xilinx-pcie.h" +#include "hw/core/qdev-properties.h" +#include "qapi/error.h" +#include "qemu/error-report.h" +#include "qemu/log.h" +#include "chardev/char.h" +#include "system/address-spaces.h" +#include "system/device_tree.h" +#include "system/system.h" +#include "system/qtest.h" +#include "system/runstate.h" + +#include <libfdt.h> +#include "qom/object.h" + +#define TYPE_MIPS_BOSTON_AIA "mips-boston-aia" +typedef struct BostonState BostonState; +DECLARE_INSTANCE_CHECKER(BostonState, BOSTON, + TYPE_MIPS_BOSTON_AIA) + +enum { + BOSTON_PCIE2, + BOSTON_PCIE2_MMIO, + BOSTON_PLATREG, + BOSTON_UART, + BOSTON_LCD, + BOSTON_FLASH, + BOSTON_HIGHDDR, +}; + +static const MemMapEntry boston_memmap[] = { + [BOSTON_PCIE2] = { 0x14000000, 0x2000000 }, + [BOSTON_PCIE2_MMIO] = { 0x16000000, 0x100000 }, + [BOSTON_PLATREG] = { 0x17ffd000, 0x1000 }, + [BOSTON_UART] = { 0x17ffe000, 0x20 }, + [BOSTON_LCD] = { 0x17fff000, 0x8 }, + [BOSTON_FLASH] = { 0x18000000, 0x8000000 }, + [BOSTON_HIGHDDR] = { 0x80000000, 0x0 }, +}; + +/* Interrupt numbers for APLIC. */ +#define UART_INT 4 +#define PCIE2_INT 7 + +struct BostonState { + SysBusDevice parent_obj; + + MachineState *mach; + RISCVCPSState cps; + SerialMM *uart; + + CharFrontend lcd_display; + char lcd_content[8]; + bool lcd_inited; +}; + +enum boston_plat_reg { + PLAT_FPGA_BUILD = 0x00, + PLAT_CORE_CL = 0x04, + PLAT_WRAPPER_CL = 0x08, + PLAT_SYSCLK_STATUS = 0x0c, + PLAT_SOFTRST_CTL = 0x10, +#define PLAT_SOFTRST_CTL_SYSRESET (1 << 4) + PLAT_DDR3_STATUS = 0x14, +#define PLAT_DDR3_STATUS_LOCKED (1 << 0) +#define PLAT_DDR3_STATUS_CALIBRATED (1 << 2) +#define PLAT_DDR3_INTERFACE_RESET (1 << 3) + PLAT_PCIE_STATUS = 0x18, +#define PLAT_PCIE_STATUS_PCIE0_LOCKED (1 << 0) +#define PLAT_PCIE_STATUS_PCIE1_LOCKED (1 << 8) +#define PLAT_PCIE_STATUS_PCIE2_LOCKED (1 << 16) + PLAT_FLASH_CTL = 0x1c, + PLAT_SPARE0 = 0x20, + PLAT_SPARE1 = 0x24, + PLAT_SPARE2 = 0x28, + PLAT_SPARE3 = 0x2c, + PLAT_MMCM_DIV = 0x30, +#define PLAT_MMCM_DIV_CLK0DIV_SHIFT 0 +#define PLAT_MMCM_DIV_INPUT_SHIFT 8 +#define PLAT_MMCM_DIV_MUL_SHIFT 16 +#define PLAT_MMCM_DIV_CLK1DIV_SHIFT 24 + PLAT_BUILD_CFG = 0x34, +#define PLAT_BUILD_CFG_IOCU_EN (1 << 0) +#define PLAT_BUILD_CFG_PCIE0_EN (1 << 1) +#define PLAT_BUILD_CFG_PCIE1_EN (1 << 2) +#define PLAT_BUILD_CFG_PCIE2_EN (1 << 3) + PLAT_DDR_CFG = 0x38, +#define PLAT_DDR_CFG_SIZE (0xf << 0) +#define PLAT_DDR_CFG_MHZ (0xfff << 4) + PLAT_NOC_PCIE0_ADDR = 0x3c, + PLAT_NOC_PCIE1_ADDR = 0x40, + PLAT_NOC_PCIE2_ADDR = 0x44, + PLAT_SYS_CTL = 0x48, +}; + +static void boston_lcd_event(void *opaque, QEMUChrEvent event) +{ + BostonState *s = opaque; + if (event == CHR_EVENT_OPENED && !s->lcd_inited) { + qemu_chr_fe_printf(&s->lcd_display, " "); + s->lcd_inited = true; + } +} + +static uint64_t boston_lcd_read(void *opaque, hwaddr addr, + unsigned size) +{ + BostonState *s = opaque; + uint64_t val = 0; + + switch (size) { + case 8: + val |= (uint64_t)s->lcd_content[(addr + 7) & 0x7] << 56; + val |= (uint64_t)s->lcd_content[(addr + 6) & 0x7] << 48; + val |= (uint64_t)s->lcd_content[(addr + 5) & 0x7] << 40; + val |= (uint64_t)s->lcd_content[(addr + 4) & 0x7] << 32; + /* fall through */ + case 4: + val |= (uint64_t)s->lcd_content[(addr + 3) & 0x7] << 24; + val |= (uint64_t)s->lcd_content[(addr + 2) & 0x7] << 16; + /* fall through */ + case 2: + val |= (uint64_t)s->lcd_content[(addr + 1) & 0x7] << 8; + /* fall through */ + case 1: + val |= (uint64_t)s->lcd_content[(addr + 0) & 0x7]; + break; + } + + return val; +} + +static void boston_lcd_write(void *opaque, hwaddr addr, + uint64_t val, unsigned size) +{ + BostonState *s = opaque; + + switch (size) { + case 8: + s->lcd_content[(addr + 7) & 0x7] = val >> 56; + s->lcd_content[(addr + 6) & 0x7] = val >> 48; + s->lcd_content[(addr + 5) & 0x7] = val >> 40; + s->lcd_content[(addr + 4) & 0x7] = val >> 32; + /* fall through */ + case 4: + s->lcd_content[(addr + 3) & 0x7] = val >> 24; + s->lcd_content[(addr + 2) & 0x7] = val >> 16; + /* fall through */ + case 2: + s->lcd_content[(addr + 1) & 0x7] = val >> 8; + /* fall through */ + case 1: + s->lcd_content[(addr + 0) & 0x7] = val; + break; + } + + qemu_chr_fe_printf(&s->lcd_display, + "\r%-8.8s", s->lcd_content); +} + +static const MemoryRegionOps boston_lcd_ops = { + .read = boston_lcd_read, + .write = boston_lcd_write, + .endianness = DEVICE_LITTLE_ENDIAN, +}; + +static uint64_t boston_platreg_read(void *opaque, hwaddr addr, + unsigned size) +{ + BostonState *s = opaque; + uint32_t gic_freq, val; + + switch (addr & 0xffff) { + case PLAT_FPGA_BUILD: + case PLAT_CORE_CL: + case PLAT_WRAPPER_CL: + return 0; + case PLAT_DDR3_STATUS: + return PLAT_DDR3_STATUS_LOCKED | PLAT_DDR3_STATUS_CALIBRATED + | PLAT_DDR3_INTERFACE_RESET; + case PLAT_MMCM_DIV: + gic_freq = 25000000 / 1000000; + val = gic_freq << PLAT_MMCM_DIV_INPUT_SHIFT; + val |= 1 << PLAT_MMCM_DIV_MUL_SHIFT; + val |= 1 << PLAT_MMCM_DIV_CLK0DIV_SHIFT; + val |= 1 << PLAT_MMCM_DIV_CLK1DIV_SHIFT; + return val; + case PLAT_BUILD_CFG: + val = PLAT_BUILD_CFG_PCIE0_EN; + val |= PLAT_BUILD_CFG_PCIE1_EN; + val |= PLAT_BUILD_CFG_PCIE2_EN; + return val; + case PLAT_DDR_CFG: + val = s->mach->ram_size / GiB; + assert(!(val & ~PLAT_DDR_CFG_SIZE)); + val |= PLAT_DDR_CFG_MHZ; + return val; + default: + qemu_log_mask(LOG_UNIMP, "Read platform register 0x%" HWADDR_PRIx "\n", + addr & 0xffff); + return 0; + } +} + +static void boston_platreg_write(void *opaque, hwaddr addr, + uint64_t val, unsigned size) +{ + if (size != 4) { + qemu_log_mask(LOG_UNIMP, "%uB platform register write\n", size); + return; + } + + switch (addr & 0xffff) { + case PLAT_FPGA_BUILD: + case PLAT_CORE_CL: + case PLAT_WRAPPER_CL: + case PLAT_DDR3_STATUS: + case PLAT_PCIE_STATUS: + case PLAT_MMCM_DIV: + case PLAT_BUILD_CFG: + case PLAT_DDR_CFG: + /* read only */ + break; + case PLAT_SOFTRST_CTL: + if (val & PLAT_SOFTRST_CTL_SYSRESET) { + qemu_system_reset_request(SHUTDOWN_CAUSE_GUEST_RESET); + } + break; + default: + qemu_log_mask(LOG_UNIMP, "Write platform register 0x%" HWADDR_PRIx + " = 0x%" PRIx64 "\n", addr & 0xffff, val); + break; + } +} + +static const MemoryRegionOps boston_platreg_ops = { + .read = boston_platreg_read, + .write = boston_platreg_write, + .endianness = DEVICE_LITTLE_ENDIAN, + .impl = { + .min_access_size = 4, + .max_access_size = 4, + }, +}; + +static const TypeInfo boston_device = { + .name = TYPE_MIPS_BOSTON_AIA, + .parent = TYPE_SYS_BUS_DEVICE, + .instance_size = sizeof(BostonState), +}; + +static void boston_register_types(void) +{ + type_register_static(&boston_device); +} +type_init(boston_register_types) + +#define NUM_INSNS 6 +static void gen_firmware(uint32_t *p) +{ + int i; + uint32_t reset_vec[NUM_INSNS] = { + /* CM relocate */ + 0x1fb802b7, /* li t0,0x1fb80000 */ + 0x16100337, /* li t1,0x16100000 */ + 0x0062b423, /* sd t1,8(t0) */ + /* Jump to 0x80000000 */ + 0x00100293, /* li t0,1 */ + 0x01f29293, /* slli t0,t0,1f */ + 0x00028067 /* jr t0 */ + }; + + for (i = 0; i < NUM_INSNS; i++) { + *p++ = reset_vec[i]; + } +} + +static inline XilinxPCIEHost * +xilinx_pcie_init(MemoryRegion *sys_mem, uint32_t bus_nr, + hwaddr cfg_base, uint64_t cfg_size, + hwaddr mmio_base, uint64_t mmio_size, + qemu_irq irq) +{ + DeviceState *dev; + MemoryRegion *cfg, *mmio; + + dev = qdev_new(TYPE_XILINX_PCIE_HOST); + + qdev_prop_set_uint32(dev, "bus_nr", bus_nr); + qdev_prop_set_uint64(dev, "cfg_base", cfg_base); + qdev_prop_set_uint64(dev, "cfg_size", cfg_size); + qdev_prop_set_uint64(dev, "mmio_base", mmio_base); + qdev_prop_set_uint64(dev, "mmio_size", mmio_size); + + sysbus_realize_and_unref(SYS_BUS_DEVICE(dev), &error_fatal); + + cfg = sysbus_mmio_get_region(SYS_BUS_DEVICE(dev), 0); + memory_region_add_subregion_overlap(sys_mem, cfg_base, cfg, 0); + + mmio = sysbus_mmio_get_region(SYS_BUS_DEVICE(dev), 1); + memory_region_add_subregion_overlap(sys_mem, 0, mmio, 0); + + qdev_connect_gpio_out_named(dev, "interrupt_out", 0, irq); + + return XILINX_PCIE_HOST(dev); +} + +static void boston_mach_init(MachineState *machine) +{ + DeviceState *dev; + BostonState *s; + MemoryRegion *flash, *ddr_low_alias, *lcd, *platreg; + MemoryRegion *sys_mem = get_system_memory(); + XilinxPCIEHost *pcie2; + PCIDevice *pdev; + AHCIPCIState *ich9; + DriveInfo *hd[6]; + Chardev *chr; + int fw_size; + + if ((machine->ram_size % GiB) || + (machine->ram_size > (4 * GiB))) { + error_report("Memory size must be 1GB, 2GB, 3GB, or 4GB"); + exit(1); + } + + if (machine->smp.cpus / machine->smp.cores / machine->smp.threads > 1) { + error_report( + "Invalid -smp x,cores=y,threads=z. The max number of clusters " + "supported is 1"); + exit(1); + } + + dev = qdev_new(TYPE_MIPS_BOSTON_AIA); + sysbus_realize_and_unref(SYS_BUS_DEVICE(dev), &error_fatal); + + s = BOSTON(dev); + s->mach = machine; + + object_initialize_child(OBJECT(machine), "cps", &s->cps, TYPE_RISCV_CPS); + object_property_set_str(OBJECT(&s->cps), "cpu-type", machine->cpu_type, + &error_fatal); + object_property_set_uint(OBJECT(&s->cps), "num-vp", machine->smp.cpus, + &error_fatal); + object_property_set_uint(OBJECT(&s->cps), "num-hart", machine->smp.threads, + &error_fatal); + object_property_set_uint(OBJECT(&s->cps), "num-core", machine->smp.cores, + &error_fatal); + object_property_set_uint(OBJECT(&s->cps), "gcr-base", GCR_BASE_ADDR, + &error_fatal); + sysbus_realize(SYS_BUS_DEVICE(&s->cps), &error_fatal); + + sysbus_mmio_map_overlap(SYS_BUS_DEVICE(&s->cps), 0, 0, 1); + + flash = g_new(MemoryRegion, 1); + memory_region_init_rom(flash, NULL, "boston.flash", + boston_memmap[BOSTON_FLASH].size, &error_fatal); + memory_region_add_subregion_overlap(sys_mem, + boston_memmap[BOSTON_FLASH].base, + flash, 0); + + memory_region_add_subregion_overlap(sys_mem, + boston_memmap[BOSTON_HIGHDDR].base, + machine->ram, 0); + + ddr_low_alias = g_new(MemoryRegion, 1); + memory_region_init_alias(ddr_low_alias, NULL, "boston_low.ddr", + machine->ram, 0, + MIN(machine->ram_size, (256 * MiB))); + memory_region_add_subregion_overlap(sys_mem, 0, ddr_low_alias, 0); + + pcie2 = xilinx_pcie_init(sys_mem, 2, + boston_memmap[BOSTON_PCIE2].base, + boston_memmap[BOSTON_PCIE2].size, + boston_memmap[BOSTON_PCIE2_MMIO].base, + boston_memmap[BOSTON_PCIE2_MMIO].size, + qdev_get_gpio_in(s->cps.aplic, PCIE2_INT)); + + platreg = g_new(MemoryRegion, 1); + memory_region_init_io(platreg, NULL, &boston_platreg_ops, s, + "boston-platregs", + boston_memmap[BOSTON_PLATREG].size); + memory_region_add_subregion_overlap(sys_mem, + boston_memmap[BOSTON_PLATREG].base, platreg, 0); + + s->uart = serial_mm_init(sys_mem, boston_memmap[BOSTON_UART].base, 2, + qdev_get_gpio_in(s->cps.aplic, UART_INT), 10000000, + serial_hd(0), DEVICE_LITTLE_ENDIAN); + + lcd = g_new(MemoryRegion, 1); + memory_region_init_io(lcd, NULL, &boston_lcd_ops, s, "boston-lcd", 0x8); + memory_region_add_subregion_overlap(sys_mem, + boston_memmap[BOSTON_LCD].base, lcd, 0); + + chr = qemu_chr_new("lcd", "vc:320x240", NULL); + qemu_chr_fe_init(&s->lcd_display, chr, NULL); + qemu_chr_fe_set_handlers(&s->lcd_display, NULL, NULL, + boston_lcd_event, NULL, s, NULL, true); + + pdev = pci_create_simple_multifunction(&PCI_BRIDGE(&pcie2->root)->sec_bus, + PCI_DEVFN(0, 0), TYPE_ICH9_AHCI); + ich9 = ICH9_AHCI(pdev); + g_assert(ARRAY_SIZE(hd) == ich9->ahci.ports); + ide_drive_get(hd, ich9->ahci.ports); + ahci_ide_create_devs(&ich9->ahci, hd); + + if (machine->firmware) { + fw_size = load_image_targphys(machine->firmware, + 0x1fc00000, 4 * MiB, NULL); + if (fw_size == -1) { + error_report("unable to load firmware image '%s'", + machine->firmware); + exit(1); + } + if (machine->kernel_filename) { + fw_size = load_image_targphys(machine->kernel_filename, + 0x80000000, 64 * MiB, NULL); + if (fw_size == -1) { + error_report("unable to load kernel image '%s'", + machine->kernel_filename); + exit(1); + } + } + } else if (machine->kernel_filename) { + fw_size = load_image_targphys(machine->kernel_filename, + 0x80000000, 64 * MiB, NULL); + if (fw_size == -1) { + error_report("unable to load kernel image '%s'", + machine->kernel_filename); + exit(1); + } + + gen_firmware(memory_region_get_ram_ptr(flash) + 0x7c00000); + } else if (!qtest_enabled()) { + error_report("Please provide either a -kernel or -bios argument"); + exit(1); + } +} + +static void boston_mach_class_init(MachineClass *mc) +{ + mc->desc = "MIPS Boston-aia"; + mc->init = boston_mach_init; + mc->block_default_type = IF_IDE; + mc->default_ram_size = 2 * GiB; + mc->default_ram_id = "boston.ddr"; + mc->max_cpus = MAX_HARTS; + mc->default_cpu_type = TYPE_RISCV_CPU_MIPS_P8700; +} + +DEFINE_MACHINE("boston-aia", boston_mach_class_init) diff --git a/hw/riscv/Kconfig b/hw/riscv/Kconfig index XXXXXXX..XXXXXXX 100644 --- a/hw/riscv/Kconfig +++ b/hw/riscv/Kconfig @@ -XXX,XX +XXX,XX @@ config XIANGSHAN_KUNMINGHU select RISCV_APLIC select RISCV_IMSIC select SERIAL_MM + +config MIPS_BOSTON_AIA + bool + default y + select PCI_EXPRESS + select PCI_EXPRESS_XILINX diff --git a/hw/riscv/meson.build b/hw/riscv/meson.build index XXXXXXX..XXXXXXX 100644 --- a/hw/riscv/meson.build +++ b/hw/riscv/meson.build @@ -XXX,XX +XXX,XX @@ riscv_ss.add(when: 'CONFIG_MICROBLAZE_V', if_true: files('microblaze-v-generic.c riscv_ss.add(when: 'CONFIG_XIANGSHAN_KUNMINGHU', if_true: files('xiangshan_kmh.c')) riscv_ss.add(when: 'CONFIG_RISCV_MIPS_CPS', if_true: files('cps.c')) +riscv_ss.add(when: 'CONFIG_MIPS_BOSTON_AIA', if_true: files('boston-aia.c')) hw_arch += {'riscv': riscv_ss} -- 2.52.0
From: Djordje Todorovic <Djordje.Todorovic@htecgroup.com> The Boston AIA board needs a basic GbE NIC. There is no PCH GbE device emulation, so use an `e1000e` instead. We place it in **slot 0, function 1** in order not to conflict with the existing AHCI device in slot 0 func 0. Signed-off-by: Chao-ying Fu <cfu@mips.com> Signed-off-by: Djordje Todorovic <djordje.todorovic@htecgroup.com> Reviewed-by: Daniel Henrique Barboza <dbarboza@ventanamicro.com> Message-ID: <20260108134128.2218102-12-djordje.todorovic@htecgroup.com> Signed-off-by: Alistair Francis <alistair.francis@wdc.com> --- hw/riscv/boston-aia.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/hw/riscv/boston-aia.c b/hw/riscv/boston-aia.c index XXXXXXX..XXXXXXX 100644 --- a/hw/riscv/boston-aia.c +++ b/hw/riscv/boston-aia.c @@ -XXX,XX +XXX,XX @@ static void boston_mach_init(MachineState *machine) ide_drive_get(hd, ich9->ahci.ports); ahci_ide_create_devs(&ich9->ahci, hd); + /* Create e1000e using slot 0 func 1 */ + pci_init_nic_in_slot(&PCI_BRIDGE(&pcie2->root)->sec_bus, "e1000e", NULL, + "00.1"); + pci_init_nic_devices(&PCI_BRIDGE(&pcie2->root)->sec_bus, "e1000e"); + if (machine->firmware) { fw_size = load_image_targphys(machine->firmware, 0x1fc00000, 4 * MiB, NULL); -- 2.52.0
From: Djordje Todorovic <Djordje.Todorovic@htecgroup.com> Add functional test for Boston AIA board. The P8700 RISC-V based CPU by MIPS supports it at the moment. Signed-off-by: Chao-ying Fu <cfu@mips.com> Signed-off-by: Djordje Todorovic <djordje.todorovic@htecgroup.com> Acked-by: Alistair Francis <alistair.francis@wdc.com> Reviewed-by: Thomas Huth <thuth@redhat.com> Message-ID: <20260108134128.2218102-13-djordje.todorovic@htecgroup.com> Signed-off-by: Alistair Francis <alistair.francis@wdc.com> --- tests/functional/riscv64/meson.build | 2 + tests/functional/riscv64/test_boston.py | 123 ++++++++++++++++++++++++ 2 files changed, 125 insertions(+) create mode 100755 tests/functional/riscv64/test_boston.py diff --git a/tests/functional/riscv64/meson.build b/tests/functional/riscv64/meson.build index XXXXXXX..XXXXXXX 100644 --- a/tests/functional/riscv64/meson.build +++ b/tests/functional/riscv64/meson.build @@ -XXX,XX +XXX,XX @@ # SPDX-License-Identifier: GPL-2.0-or-later test_riscv64_timeouts = { + 'boston' : 120, 'tuxrun' : 120, } @@ -XXX,XX +XXX,XX @@ tests_riscv64_system_quick = [ ] tests_riscv64_system_thorough = [ + 'boston', 'sifive_u', 'tuxrun', ] diff --git a/tests/functional/riscv64/test_boston.py b/tests/functional/riscv64/test_boston.py new file mode 100755 index XXXXXXX..XXXXXXX --- /dev/null +++ b/tests/functional/riscv64/test_boston.py @@ -XXX,XX +XXX,XX @@ +#!/usr/bin/env python3 +# +# Boston board test for RISC-V P8700 processor by MIPS +# +# Copyright (c) 2025 MIPS +# +# SPDX-License-Identifier: GPL-2.0-or-later +# + +from qemu_test import QemuSystemTest, Asset +from qemu_test import wait_for_console_pattern + + +class RiscvBostonTest(QemuSystemTest): + """ + Test the boston-aia board with P8700 processor + """ + + ASSET_FW_PAYLOAD = Asset( + 'https://github.com/MIPS/linux-test-downloads/raw/main/p8700/fw_payload.bin', + 'd6f4ae14d0c178c1d0bb38ddf64557536ca8602a588b220729a8aa17caa383aa') + + ASSET_ROOTFS = Asset( + 'https://github.com/MIPS/linux-test-downloads/raw/main/p8700/rootfs.ext2', + 'f937e21b588f0d1d17d10a063053979686897bbbbc5e9617a5582f7c1f48e565') + + def _boot_linux_test(self, smp_count): + """Common setup and boot test for Linux on Boston board + + Args: + smp_count: Number of CPUs to use for SMP + """ + self.set_machine('boston-aia') + fw_payload_path = self.ASSET_FW_PAYLOAD.fetch() + rootfs_path = self.ASSET_ROOTFS.fetch() + + self.vm.add_args('-cpu', 'mips-p8700') + self.vm.add_args('-m', '2G') + self.vm.add_args('-smp', str(smp_count)) + self.vm.add_args('-kernel', fw_payload_path) + self.vm.add_args('-drive', f'file={rootfs_path},format=raw,snapshot=on') + + self.vm.set_console() + self.vm.launch() + + # Wait for OpenSBI + wait_for_console_pattern(self, 'OpenSBI') + + # Wait for Linux kernel boot + wait_for_console_pattern(self, 'Linux version') + wait_for_console_pattern(self, 'Machine model: MIPS P8700') + + # Test e1000e network card functionality + wait_for_console_pattern(self, 'e1000e') + wait_for_console_pattern(self, 'Network Connection') + + # Wait for boot to complete - system reaches login prompt + wait_for_console_pattern(self, 'Run /sbin/init as init process') + + def test_boston_boot_linux_min_cpus(self): + """ + Test Linux kernel boot with minimum CPU count (2) + """ + self._boot_linux_test(smp_count=2) + + def test_boston_boot_linux_7_cpus(self): + """ + Test Linux kernel boot with 7 CPUs + + 7 CPUs is a special configuration that tests odd CPU count + handling and ensures proper core distribution across clusters. + """ + self._boot_linux_test(smp_count=7) + + def test_boston_boot_linux_35_cpus(self): + """ + Test Linux kernel boot with 35 CPUs + + 35 CPUs is a special configuration that tests a non-power-of-2 + CPU count above 32, validating proper handling of larger + asymmetric SMP configurations. + """ + self._boot_linux_test(smp_count=35) + + def test_boston_boot_linux_max_cpus(self): + """ + Test Linux kernel boot with maximum supported CPU count (64) + """ + self._boot_linux_test(smp_count=64) + + def test_boston_invalid_cpu_count(self): + """ + Test that 65 CPUs is rejected as invalid (negative test case) + """ + from subprocess import run, PIPE + + fw_payload_path = self.ASSET_FW_PAYLOAD.fetch() + rootfs_path = self.ASSET_ROOTFS.fetch() + + cmd = [ + self.qemu_bin, + '-M', 'boston-aia', + '-cpu', 'mips-p8700', + '-m', '2G', + '-smp', '65', + '-kernel', fw_payload_path, + '-drive', f'file={rootfs_path},format=raw,snapshot=on', + '-nographic' + ] + + # Run QEMU and expect it to fail immediately. + result = run(cmd, capture_output=True, text=True, timeout=5) + + # Check that QEMU exited with error code 1 + self.assertEqual(result.returncode, 1, + "QEMU should exit with code 1 for invalid SMP count") + + # Check error message + self.assertIn('Invalid SMP CPUs 65', result.stderr, + "Error message should indicate invalid SMP CPU count") + +if __name__ == '__main__': + QemuSystemTest.main() -- 2.52.0
From: Alistair Francis <alistair.francis@wdc.com> The following changes since commit f5a2438405d4ae8b62de7c9b39fac0b2155ee544: Merge tag 'pull-qapi-2026-05-21' of https://repo.or.cz/qemu/armbru into staging (2026-05-21 09:00:22 -0400) are available in the Git repository at: https://github.com/alistair23/qemu.git tags/pull-riscv-to-apply-20260522 for you to fetch changes up to b7d87fb10d53a918e9c4a3dfe1fb06ce42c52526: hw/riscv: riscv-iommu: Re-process command queue after clearing CMD_ILL (2026-05-22 09:59:21 +1000) ---------------------------------------------------------------- RISC-V PR for 11.1. * Remove spike as default machine * Deprecate the shakti_c machine * Set MISA.[C|X] based on the selected extensions * Update Maintainers for OpenSBI Firmware * Update OpenSBI to v1.8.1 * Avoid RISCVCPU copy in PMU FDT setup * A collection of specification compliance improvements * Fix Svnapot 64KB pages * Handle source overlap of vector widening reduction instructions * Check interrupt in SiFive UART after txctrl register is written * Fix medeleg[11] read-only zero bit for M-mode ECALL * Fix tail handling for vmv.s.x and vfmv.s.f * Update the local AIA interrupt mask * Add KVM support for Zicbop and BFloat16 extensions * Fix the IOMMU FSC SV32 capability check * Avoid caching PCI device IDs in the IOMMU * Implement Microchip mpfs ioscb PLLs and sysreg clock dividers * Remove the internal CPU riscv_cpu_* arrays * Fix IOCOUNTINH.CY toggle detection * Fix the read of pmpaddr(0-63) CSRs * Make hpmcounterh return the upper 32-bits * Minor fixes and enhancements of RISC-V AIA devices * Re-process IOMMU command queue after clearing CMD_ILL ---------------------------------------------------------------- Abhigyan Kumar (1): target/riscv: Fix medeleg[11] read-only zero bit for M-mode ECALL Alistair Francis (4): target/riscv: Remove spike as default machine target/riscv: Deprecate the shakti_c machine MAINTAINERS: Maintain OpenSBI Firmware target/riscv: Update the local interrupt mask Andrew Jones (1): hw/riscv/riscv-iommu: Fix Svnapot 64KB pages Anton Blanchard (1): target/riscv: rvv: Handle source overlap of vector widening reduction instructions Chengbo Gao (1): hw/riscv/riscv-iommu: Avoid caching PCI device IDs Daniel Henrique Barboza (16): roms/opensbi: Update to v1.8.1 target/riscv/cpu.c: add xlrbr isa_edata_arr[] entry target/riscv/cpu.c: fix smctr/ssctr isa_edata_arr[] order target/riscv: make riscv-qmp-cmds use isa_data_arr[] target/riscv/tcg: treat all exts equally in cpu_disable_priv_spec_isa_exts target/riscv/tcg: use only isa_edata_arr[] in cpu_cfg_ext_get_name() target/riscv/cpu.c: remove riscv_cpu_enable_named_feat() target/riscv: remove riscv_cpu_named_features[] target/riscv/tcg: use isa_edata_arr[] in riscv_cpu_update_misa_x() target/riscv/kvm: use isa_edata_arr[] for unavailable props target/riscv/tcg: use isa_edata_arr[] to enable max exts target/riscv/tcg: use cfg_offset as cpu_set_multi_ext cb opaque target/riscv: do not set defaults in cpu prop callback target/riscv/tcg: use isa_edata_arr[] to create user props target/riscv/cpu: remove riscv_cpu_* arrays target/riscv/csr.c: fix read of pmpaddr(0-63) CSRs Fangyu Yu (1): hw/riscv/riscv-iommu: Fix IOCOUNTINH.CY toggle detection Frank Chang (3): target/riscv: Update MISA.C for Zc* extensions target/riscv: Update MISA.X for non-standard extensions hw/char: Check interrupt after txctrl register is written Guenter Roeck (1): hw: misc: Implement Microchip mpfs ioscb PLLs and sysreg clock dividers Jay Chang (1): hw/riscv: riscv-iommu: Re-process command queue after clearing CMD_ILL Jim Shu (4): hw/intc: riscv_aplic: Fix level trigger IRQ in direct delivery mode hw/intc: riscv_aplic: Add reset API to APLIC hw/intc: riscv_imsic: Add reset API to IMSIC hw/intc: riscv_aplic: add trace events of APLIC read/write function Mohamed Ayman (1): riscv: virt: avoid RISCVCPU copy in PMU FDT setup Portia Stephens (1): target/riscv: Make hpmcounterh return the upper 32-bits Zishun Yi (9): target/riscv: Allow mseccfg access based on ext_zicfilp target/riscv: add Zvknha as an implied extension for Zvknhb target/riscv: Remove unconditional MENVCFG_CDE from mask target/riscv: Fix missing CDE check for scountinhibit target/riscv/pmp: Fix integer overflow in TOR and NA4 address computation target/riscv: Add mseccfg to VMStateDescription target/riscv: clear mseccfg on reset for all dependent extensions hw/riscv/riscv-iommu: fix FSC SV32 capability check hw/riscv/virt-acpi-build: Fix off-by-one error in RIMT ID mapping Zongmin Zhou (2): target/riscv/kvm: add KVM support for Zicbop extension target/riscv/kvm: Add BFloat16 extensions support chen.zhongyao@zte.com.cn (1): target/riscv: Fix tail handling for vmv.s.x and vfmv.s.f MAINTAINERS | 2 + docs/about/deprecated.rst | 21 +- docs/about/removed-features.rst | 14 ++ include/hw/misc/mchp_pfsoc_ioscb.h | 2 + target/riscv/cpu.h | 13 +- target/riscv/helper.h | 4 + hw/char/sifive_uart.c | 1 + hw/intc/riscv_aplic.c | 116 ++++++--- hw/intc/riscv_imsic.c | 19 ++ hw/misc/mchp_pfsoc_ioscb.c | 47 +++- hw/misc/mchp_pfsoc_sysreg.c | 13 + hw/riscv/riscv-iommu-hpm.c | 3 +- hw/riscv/riscv-iommu.c | 96 ++++++-- hw/riscv/shakti_c.c | 1 + hw/riscv/spike.c | 1 - hw/riscv/virt-acpi-build.c | 3 +- hw/riscv/virt.c | 4 +- target/riscv/cpu.c | 327 +++++++++---------------- target/riscv/csr.c | 36 ++- target/riscv/kvm/kvm-cpu.c | 62 +++-- target/riscv/machine.c | 20 ++ target/riscv/pmp.c | 4 +- target/riscv/riscv-qmp-cmds.c | 30 +-- target/riscv/tcg/tcg-cpu.c | 192 +++++++-------- target/riscv/vector_helper.c | 18 ++ target/riscv/insn_trans/trans_rvv.c.inc | 45 ++-- hw/intc/trace-events | 4 + pc-bios/opensbi-riscv32-generic-fw_dynamic.bin | Bin 268752 -> 270384 bytes pc-bios/opensbi-riscv64-generic-fw_dynamic.bin | Bin 273048 -> 275928 bytes roms/opensbi | 2 +- 30 files changed, 613 insertions(+), 487 deletions(-)
From: Alistair Francis <alistair.francis@wdc.com> In QEMU 10.0 we deprecated the default spike machine, let's finally remove spike as the default and require users to specify the machine. Signed-off-by: Alistair Francis <alistair.francis@wdc.com> Reviewed-by: Daniel Henrique Barboza <daniel.barboza@oss.qualcomm.com> Reviewed-by: Philippe Mathieu-Daudé <philmd@linaro.org> Reviewed-by: Chao Liu <chao.liu.zevorn@gmail.com> Message-ID: <20260430052218.771358-2-alistair.francis@wdc.com> Signed-off-by: Alistair Francis <alistair.francis@wdc.com> --- docs/about/deprecated.rst | 18 ------------------ docs/about/removed-features.rst | 14 ++++++++++++++ hw/riscv/spike.c | 1 - 3 files changed, 14 insertions(+), 19 deletions(-) diff --git a/docs/about/deprecated.rst b/docs/about/deprecated.rst index XXXXXXX..XXXXXXX 100644 --- a/docs/about/deprecated.rst +++ b/docs/about/deprecated.rst @@ -XXX,XX +XXX,XX @@ better reflects the way this property affects all random data within the device tree blob, not just the ``kaslr-seed`` node. -RISC-V default machine option (since 10.0) -'''''''''''''''''''''''''''''''''''''''''' - -RISC-V defines ``spike`` as the default machine if no machine option is -given in the command line. This happens because ``spike`` is the first -RISC-V machine implemented in QEMU and setting it as default was -convenient at that time. Now we have 7 riscv64 and 6 riscv32 machines -and having ``spike`` as a default is no longer justified. This default -will also promote situations where users think they're running ``virt`` -(the most used RISC-V machine type in 10.0) when in fact they're -running ``spike``. - -Removing the default machine option forces users to always set the machine -they want to use and avoids confusion. Existing users of the ``spike`` -machine must ensure that they're setting the ``spike`` machine in the -command line (``-M spike``). - - Backend options --------------- diff --git a/docs/about/removed-features.rst b/docs/about/removed-features.rst index XXXXXXX..XXXXXXX 100644 --- a/docs/about/removed-features.rst +++ b/docs/about/removed-features.rst @@ -XXX,XX +XXX,XX @@ firmware is available to boot it. It can be replaced by the ``ast2700fc``, another multi-SoC machine based on the newer AST2700 SoCs which are excepted to receive better support in the future. +RISC-V default machine (removed in 11.1) +'''''''''''''''''''''''''''''''''''''''' + +RISC-V used to define ``spike`` as the default machine if no machine option +was given via the command line. This happend because ``spike`` was the first +RISC-V machine implemented in QEMU and setting it as default was +convenient at that time. Now we have 7 riscv64 and 6 riscv32 machines +and having ``spike`` as a default is no longer justified. + +The default machine option has been removed, forcing users to always set the +machine they want to use to avoid confusion. Existing users of the ``spike`` +machine must ensure that they're setting the ``spike`` machine in the +command line (``-M spike``). + linux-user mode CPUs -------------------- 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 spike_machine_class_init(ObjectClass *oc, const void *data) mc->desc = "RISC-V Spike board"; mc->init = spike_board_init; mc->max_cpus = SPIKE_CPUS_MAX; - mc->is_default = true; mc->default_cpu_type = TYPE_RISCV_CPU_BASE; mc->possible_cpu_arch_ids = riscv_numa_possible_cpu_arch_ids; mc->cpu_index_to_instance_props = riscv_numa_cpu_index_to_props; -- 2.53.0
From: Alistair Francis <alistair.francis@wdc.com> The RISC-V shakti_c machine hasn't had meaningful contributions since 2021 and is currently unmaintained. The machine is scheduled to be removed as it appears to have no users. Signed-off-by: Alistair Francis <alistair.francis@wdc.com> Reviewed-by: Daniel Henrique Barboza <daniel.barboza@oss.qualcomm.com> Reviewed-by: Philippe Mathieu-Daudé <philmd@linaro.org> Reviewed-by: Richard Henderson <richard.henderson@linaro.org> Reviewed-by: Chao Liu <chao.liu.zevorn@gmail.com> Message-ID: <20260430052218.771358-3-alistair.francis@wdc.com> Signed-off-by: Alistair Francis <alistair.francis@wdc.com> --- docs/about/deprecated.rst | 7 +++++++ hw/riscv/shakti_c.c | 1 + 2 files changed, 8 insertions(+) diff --git a/docs/about/deprecated.rst b/docs/about/deprecated.rst index XXXXXXX..XXXXXXX 100644 --- a/docs/about/deprecated.rst +++ b/docs/about/deprecated.rst @@ -XXX,XX +XXX,XX @@ deprecated; use the new name ``dtb-randomness`` instead. The new name better reflects the way this property affects all random data within the device tree blob, not just the ``kaslr-seed`` node. +RISC-V Shakti machine (since 11.1) +'''''''''''''''''''''''''''''''''' + +The RISC-V ``shakti_c`` machine hasn't had meaningful contributions since 2021 +and is currently unmaintained. The machine is scheduled to be removed as it +appears to have no users. + Backend options --------------- diff --git a/hw/riscv/shakti_c.c b/hw/riscv/shakti_c.c index XXXXXXX..XXXXXXX 100644 --- a/hw/riscv/shakti_c.c +++ b/hw/riscv/shakti_c.c @@ -XXX,XX +XXX,XX @@ static void shakti_c_machine_class_init(ObjectClass *klass, const void *data) mc->init = shakti_c_machine_state_init; mc->default_cpu_type = TYPE_RISCV_CPU_SHAKTI_C; mc->valid_cpu_types = valid_cpu_types; + mc->deprecation_reason = "Currently unmaintained with no known users"; mc->default_ram_id = "riscv.shakti.c.ram"; } -- 2.53.0
From: Frank Chang <frank.chang@sifive.com> MISA.C is set if the following extensions are selected: * Zca and not F. * Zca, Zcf and F (but not D) is specified (RV32 only). * Zca, Zcf and Zcd if D is specified (RV32 only). * Zca, Zcd if D is specified (RV64 only). Therefore, MISA.C must be set according to the Zc* extension rules. Warn the user if RVC is explicitly disabled but MISA.C is required by the rules above. Signed-off-by: Frank Chang <frank.chang@sifive.com> Reviewed-by: Max Chou <max.chou@sifive.com> Reviewed-by: Alistair Francis <alistair.francis@wdc.com> Message-ID: <20260424050509.3935180-2-frank.chang@sifive.com> Signed-off-by: Alistair Francis <alistair.francis@wdc.com> --- target/riscv/tcg/tcg-cpu.c | 39 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 39 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_enable_implied_rules(RISCVCPU *cpu) } } +/* + * MISA.C is set if the following extensions are selected: + * - Zca and not F. + * - Zca, Zcf and F (but not D) is specified on RV32. + * - Zca, Zcf and Zcd if D is specified on RV32. + * - Zca, Zcd if D is specified on RV64. + */ +static void riscv_cpu_update_misa_c(RISCVCPU *cpu) +{ + CPURISCVState *env = &cpu->env; + bool set_misa_c = false; + + if (riscv_has_ext(env, RVC)) { + return; + } + + if (cpu->cfg.ext_zca && !riscv_has_ext(env, RVF)) { + set_misa_c = true; + } else if (riscv_cpu_mxl(env) == MXL_RV32 && + cpu->cfg.ext_zca && cpu->cfg.ext_zcf && + (riscv_has_ext(env, RVD) ? cpu->cfg.ext_zcd : + riscv_has_ext(env, RVF))) { + set_misa_c = true; + } else if (riscv_cpu_mxl(env) == MXL_RV64 && + cpu->cfg.ext_zca && cpu->cfg.ext_zcd) { + set_misa_c = true; + } + + if (set_misa_c) { + if (cpu_misa_ext_is_user_set(RVC)) { + warn_report("RVC mandated by Zca/Zcf/Zcd extensions"); + return; + } + + riscv_cpu_set_misa_ext(env, env->misa_ext | RVC); + } +} + void riscv_tcg_cpu_finalize_features(RISCVCPU *cpu, Error **errp) { CPURISCVState *env = &cpu->env; @@ -XXX,XX +XXX,XX @@ void riscv_tcg_cpu_finalize_features(RISCVCPU *cpu, Error **errp) riscv_cpu_init_implied_exts_rules(); riscv_cpu_enable_implied_rules(cpu); + riscv_cpu_update_misa_c(cpu); riscv_cpu_validate_misa_priv(env, &local_err); if (local_err != NULL) { -- 2.53.0
From: Frank Chang <frank.chang@sifive.com> MISA.X is set if there are any non-standard extensions. We should set MISA.X when any of the vendor extensions is enabled. Signed-off-by: Frank Chang <frank.chang@sifive.com> Reviewed-by: Max Chou <max.chou@sifive.com> Reviewed-by: Daniel Henrique Barboza <dbarboza@ventanamicro.com> Reviewed-by: Alistair Francis <alistair.francis@wdc.com> Message-ID: <20260424050509.3935180-3-frank.chang@sifive.com> Signed-off-by: Alistair Francis <alistair.francis@wdc.com> --- target/riscv/cpu.h | 1 + target/riscv/tcg/tcg-cpu.c | 15 +++++++++++++++ 2 files changed, 16 insertions(+) diff --git a/target/riscv/cpu.h b/target/riscv/cpu.h index XXXXXXX..XXXXXXX 100644 --- a/target/riscv/cpu.h +++ b/target/riscv/cpu.h @@ -XXX,XX +XXX,XX @@ typedef struct CPUArchState CPURISCVState; #define RVH RV('H') #define RVG RV('G') #define RVB RV('B') +#define RVX RV('X') extern const uint32_t misa_bits[]; const char *riscv_get_misa_ext_name(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 void riscv_cpu_update_misa_c(RISCVCPU *cpu) } } +/* MISA.X is set when any of the non-standard extensions is enabled. */ +static void riscv_cpu_update_misa_x(RISCVCPU *cpu) +{ + CPURISCVState *env = &cpu->env; + const RISCVCPUMultiExtConfig *arr = riscv_cpu_vendor_exts; + + for (int i = 0; arr[i].name != NULL; i++) { + if (isa_ext_is_enabled(cpu, arr[i].offset)) { + riscv_cpu_set_misa_ext(env, env->misa_ext | RVX); + break; + } + } +} + void riscv_tcg_cpu_finalize_features(RISCVCPU *cpu, Error **errp) { CPURISCVState *env = &cpu->env; @@ -XXX,XX +XXX,XX @@ void riscv_tcg_cpu_finalize_features(RISCVCPU *cpu, Error **errp) riscv_cpu_init_implied_exts_rules(); riscv_cpu_enable_implied_rules(cpu); riscv_cpu_update_misa_c(cpu); + riscv_cpu_update_misa_x(cpu); riscv_cpu_validate_misa_priv(env, &local_err); if (local_err != NULL) { -- 2.53.0
From: Alistair Francis <alistair.francis@wdc.com> Mark the OpenSBI Firmware as maintained by me (Alistair Francis) and add Daniel Henrique Barboza as a reviewer. Signed-off-by: Alistair Francis <alistair.francis@wdc.com> Reviewed-by: Daniel Henrique Barboza <daniel.barboza@oss.qualcomm.com> Reviewed-by: Philippe Mathieu-Daudé <philmd@linaro.org> Message-ID: <20260506234243.1873782-1-alistair.francis@wdc.com> Signed-off-by: Alistair Francis <alistair.francis@wdc.com> --- MAINTAINERS | 2 ++ 1 file changed, 2 insertions(+) diff --git a/MAINTAINERS b/MAINTAINERS index XXXXXXX..XXXXXXX 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -XXX,XX +XXX,XX @@ S: Supported F: hw/i386/amd_iommu* OpenSBI Firmware +M: Alistair Francis <Alistair.Francis@wdc.com> +R: Daniel Henrique Barboza <daniel.barboza@oss.qualcomm.com> L: qemu-riscv@nongnu.org S: Supported F: pc-bios/opensbi-* -- 2.53.0
From: Daniel Henrique Barboza <daniel.barboza@oss.qualcomm.com> Update OpenSBI and the pre-built opensbi32 and opensbi64 images to version 1.8.1. We're going for the intermediate/bug fix release 1.8.1 directly due to a PMP related fix that was impacting QEMU profile CPUs. Changelog for v1.8.1: * Typo fix in comments of sbi_hartindex_to_hartid() * Fix hart protection abstraction for platforms without PMP Changelog for v1.8 includes, among other things: - IPI device ratings - SiFive CLINT v2 support - SiFive PL2 cache controller driver - SiFive Extensible Cache (EC) driver - SiFive TMC0 based HSM driver - SiFive SMC0 based system suspend driver - MPXY RPMI mailbox driver for voltage service group - MPXY RPMI mailbox driver for device power service group - MPXY RPMI mailbox driver for performance service group Check out the full release log at [1] for more info. [1] https://github.com/riscv-software-src/opensbi/releases/tag/v1.8 Signed-off-by: Daniel Henrique Barboza <daniel.barboza@oss.qualcomm.com> Reviewed-by: Alistair Francis <alistair.francis@wdc.com> Message-ID: <20260108160825.171794-1-daniel.barboza@oss.qualcomm.com> Signed-off-by: Alistair Francis <alistair.francis@wdc.com> --- .../opensbi-riscv32-generic-fw_dynamic.bin | Bin 268752 -> 270384 bytes .../opensbi-riscv64-generic-fw_dynamic.bin | Bin 273048 -> 275928 bytes roms/opensbi | 2 +- 3 files changed, 1 insertion(+), 1 deletion(-) diff --git a/pc-bios/opensbi-riscv32-generic-fw_dynamic.bin b/pc-bios/opensbi-riscv32-generic-fw_dynamic.bin index XXXXXXX..XXXXXXX 100644 Binary files a/pc-bios/opensbi-riscv32-generic-fw_dynamic.bin and b/pc-bios/opensbi-riscv32-generic-fw_dynamic.bin differ diff --git a/pc-bios/opensbi-riscv64-generic-fw_dynamic.bin b/pc-bios/opensbi-riscv64-generic-fw_dynamic.bin index XXXXXXX..XXXXXXX 100644 Binary files a/pc-bios/opensbi-riscv64-generic-fw_dynamic.bin and b/pc-bios/opensbi-riscv64-generic-fw_dynamic.bin differ diff --git a/roms/opensbi b/roms/opensbi index XXXXXXX..XXXXXXX 160000 --- a/roms/opensbi +++ b/roms/opensbi @@ -1 +1 @@ -Subproject commit a32a91069119e7a5aa31e6bc51d5e00860be3d80 +Subproject commit 74434f255873d74e56cc50aa762d1caf24c099f8 -- 2.53.0
From: Mohamed Ayman <mohamedaymanworkspace@gmail.com> Use a pointer to the hart instead of copying RISCVCPU when passing pmu_avail_ctrs to riscv_pmu_generate_fdt_node(). Signed-off-by: Mohamed Ayman <mohamedaymanworkspace@gmail.com> Reviewed-by: Alistair Francis <alistair.francis@wdc.com> Message-ID: <20260503180252.1122776-1-mohamedaymanworkspace@gmail.com> 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_pmu(RISCVVirtState *s) { g_autofree char *pmu_name = g_strdup_printf("/pmu"); MachineState *ms = MACHINE(s); - RISCVCPU hart = s->soc[0].harts[0]; + RISCVCPU *hart = &s->soc[0].harts[0]; 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); + riscv_pmu_generate_fdt_node(ms->fdt, hart->pmu_avail_ctrs, pmu_name); } static void create_fdt_sockets(RISCVVirtState *s, -- 2.53.0
From: Zishun Yi <vulab@iscas.ac.cn> The Zicfilp extension adds the MLPE field to the mseccfg CSR. According to the RISC-V Privileged Specification, mseccfg exists if any extension that adds a field to it is implemented. Currently, the `have_mseccfg()` predicate function checks for Smepmp, Zkr, and Smmpm, but misses Zicfilp. As a result, if a CPU is configured with `zicfilp=true` but without the other extensions, accessing the mseccfg CSR will incorrectly raise an illegal instruction exception. This patch adds the missing check for `ext_zicfilp` to ensure the CSR is properly accessible when the Zicfilp extension is enabled. This issue was discovered and reported by SpecHunter, an AI-driven architecture specification analysis tool. Link: https://github.com/yizishun/rv-isa-sec/blob/master/output/riscv-isa-manual/pr-2561/qemu.txt Signed-off-by: Zishun Yi <vulab@iscas.ac.cn> Reviewed-by: Chao Liu <chao.liu.zevorn@gmail.com> Reviewed-by: Daniel Henrique Barboza <daniel.barboza@oss.qualcomm.com> Reviewed-by: Alistair Francis <alistair.francis@wdc.com> Message-ID: <20260511072705.3015986-1-vulab@iscas.ac.cn> Signed-off-by: Alistair Francis <alistair.francis@wdc.com> --- target/riscv/csr.c | 3 +++ 1 file changed, 3 insertions(+) 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 have_mseccfg(CPURISCVState *env, int csrno) if (riscv_cpu_cfg(env)->ext_smmpm) { return RISCV_EXCP_NONE; } + if (riscv_cpu_cfg(env)->ext_zicfilp) { + return RISCV_EXCP_NONE; + } return RISCV_EXCP_ILLEGAL_INST; } -- 2.53.0
From: Andrew Jones <andrew.jones@oss.qualcomm.com> The Svnapot extension encodes a 64KB leaf PTE by setting PTE_N and storing bits [3:0] of the PPN as a NAPOT size indicator. The IOMMU model wasn't checking PTE_N and therefore was using the raw (NAPOT- encoded) PPN directly in the physical address, yielding an address 32 KB above the correct base. Fix both riscv_iommu_spa_fetch() and pdt_memory_read() by mirroring the Svnapot handling already present in target/riscv/cpu_helper.c: napot_bits = ctz64(ppn) + 1 /* 4 for 64KB */ napot_mask = (1 << napot_bits) - 1 /* 0xF */ phys_base = PPN_PHYS(ppn & ~napot_mask) page_offset = addr & (PPN_PHYS(napot_mask) | (TARGET_PAGE_SIZE - 1)) The spec only defines napot_bits == 4 (64KB); any other value is treated as a reserved encoding. This is a fix, rather than new feature support, because the spec says "IOMMU implementations must support the Svnapot standard extension for NAPOT Translation Contiguity." Fixes: 0c54acb8243d ("hw/riscv: add RISC-V IOMMU base emulation") Cc: qemu-stable@nongnu.org Signed-off-by: Andrew Jones <andrew.jones@oss.qualcomm.com> Reviewed-by: Daniel Henrique Barboza <daniel.barboza@oss.qualcomm.com> Reviewed-by: Nutty Liu <nutty.liu@hotmail.com> Reviewed-by: Tomasz Jeznach <tjeznach@rivosinc.com> Message-ID: <20260508205129.377032-1-andrew.jones@oss.qualcomm.com> Signed-off-by: Alistair Francis <alistair.francis@wdc.com> --- hw/riscv/riscv-iommu.c | 44 ++++++++++++++++++++++++++++++++++++++---- 1 file changed, 40 insertions(+), 4 deletions(-) diff --git a/hw/riscv/riscv-iommu.c b/hw/riscv/riscv-iommu.c index XXXXXXX..XXXXXXX 100644 --- a/hw/riscv/riscv-iommu.c +++ b/hw/riscv/riscv-iommu.c @@ -XXX,XX +XXX,XX @@ static bool riscv_iommu_msi_check(RISCVIOMMUState *s, RISCVIOMMUContext *ctx, return true; } +/* Returns the NAPOT page mask, or 0 for reserved encodings. */ +static hwaddr riscv_iommu_napot_page_mask(hwaddr ppn, hwaddr addr, hwaddr *out) +{ + int napot_bits = ctz64(ppn) + 1; + hwaddr napot_mask, page_mask; + + /* The spec only defines 64KB (napot_bits == 4) */ + if (napot_bits != 4) { + return 0; + } + + napot_mask = (1ULL << napot_bits) - 1; + page_mask = PPN_PHYS(napot_mask) | (TARGET_PAGE_SIZE - 1); + + *out = PPN_PHYS(ppn & ~napot_mask) | (addr & page_mask); + + return page_mask; +} + /* * RISCV IOMMU Address Translation Lookup - Page Table Walk * @@ -XXX,XX +XXX,XX @@ static int riscv_iommu_spa_fetch(RISCVIOMMUState *s, RISCVIOMMUContext *ctx, } else { /* Leaf PTE, translation completed. */ sc[pass].step = sc[pass].levels; - base = PPN_PHYS(ppn) | (addr & ((1ULL << va_skip) - 1)); - /* Update address mask based on smallest translation granularity */ - iotlb->addr_mask &= (1ULL << va_skip) - 1; + + if (pte & PTE_N) { + hwaddr mask = riscv_iommu_napot_page_mask(ppn, addr, &base); + + if (!mask) { + break; + } + iotlb->addr_mask &= mask; + } else { + base = PPN_PHYS(ppn) | (addr & ((1ULL << va_skip) - 1)); + /* Update address mask based on smallest translation granularity */ + iotlb->addr_mask &= (1ULL << va_skip) - 1; + } + /* Continue with S-Stage translation? */ if (pass && sc[0].step != sc[0].levels) { pass = S_STAGE; @@ -XXX,XX +XXX,XX @@ static MemTxResult pdt_memory_read(RISCVIOMMUState *s, return MEMTX_ACCESS_ERROR; /* Misaligned PPN */ } else { /* Leaf PTE, translation completed. */ - base = PPN_PHYS(ppn) | (addr & ((1ULL << va_skip) - 1)); + if (pte & PTE_N) { + if (!riscv_iommu_napot_page_mask(ppn, addr, &base)) { + return MEMTX_ACCESS_ERROR; + } + } else { + base = PPN_PHYS(ppn) | (addr & ((1ULL << va_skip) - 1)); + } break; } -- 2.53.0
From: Anton Blanchard <antonb@tenstorrent.com> Widening reductions read vs2 as a vector of SEW elements and vs1[0] as a scalar of 2*SEW. The ISA does not allow the same vector register to be read with different EEWs, so they must not overlap. vs1 is read as a scalar from element 0, so it is treated as a single vector register (independent of LMUL) when checking overlap. Resolves: https://gitlab.com/qemu-project/qemu/-/work_items/3208 Signed-off-by: Anton Blanchard <antonb@tenstorrent.com> Acked-by: Alistair Francis <alistair.francis@wdc.com> Message-ID: <20260417080328.31918-1-antonb@tenstorrent.com> Signed-off-by: Alistair Francis <alistair.francis@wdc.com> --- target/riscv/insn_trans/trans_rvv.c.inc | 1 + 1 file changed, 1 insertion(+) 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_OPIVV_TRANS(vredxor_vs, reduction_check) static bool reduction_widen_check(DisasContext *s, arg_rmrr *a) { return reduction_check(s, a) && (s->sew < MO_64) && + !is_overlapped(a->rs1, 1, a->rs2, 1 << MAX(s->lmul, 0)) && ((s->sew + 1) <= (s->cfg_ptr->elen >> 4)); } -- 2.53.0
From: Frank Chang <frank.chang@sifive.com> It's possible that the transmit watermark level (txctrl.txcnt) is updated when the user writes to txctrl register, which may decrease the transmit watermark level to less than the number of entries in the transmit FIFO. In such a case, the interrupt should be raised so we need to call sifive_uart_update_irq() to check and update interrupt when txctrl register is written. Otherwise, the interrupt will have to be delayed until next TX FIFO transmission is processed. Suggested-by: Chao Liu <chao.liu.zevorn@gmail.com> Signed-off-by: Frank Chang <frank.chang@sifive.com> Reviewed-by: Jim Shu <jim.shu@sifive.com> Reviewed-by: Alistair Francis <alistair.francis@wdc.com> Message-ID: <20260513030503.3665414-1-frank.chang@sifive.com> Signed-off-by: Alistair Francis <alistair.francis@wdc.com> --- hw/char/sifive_uart.c | 1 + 1 file changed, 1 insertion(+) 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 @@ sifive_uart_write(void *opaque, hwaddr addr, if (SIFIVE_UART_TXEN(s->txctrl) && !fifo8_is_empty(&s->tx_fifo)) { sifive_uart_trigger_tx_fifo(s); } + sifive_uart_update_irq(s); return; case SIFIVE_UART_RXCTRL: s->rxctrl = val64; -- 2.53.0
From: Abhigyan Kumar <314abh@gmail.com> RISC-V Privileged Specification 3.1.8 (Machine Trap Delegation Registers (medeleg and mideleg)) mentions: "For exceptions that cannot occur in less privileged modes, the corresponding medeleg bits should be read-only zero. In particular, medeleg[11] is read-only zero." QEMU incorrectly included RISCV_EXCP_M_ECALL in DELEGABLE_EXCPS. It allowed the 11th bit to be written and read as set. Fixed by removing it from the DELEGABLE_EXCPS mask, adhering to the specification. Resolves: https://gitlab.com/qemu-project/qemu/-/work_items/3438 Signed-off-by: Abhigyan Kumar <314abh@gmail.com> Reviewed-by: Alistair Francis <alistair.francis@wdc.com> Message-ID: <20260427060849.749179-2-314abh@gmail.com> [ Changes by AF: - Remove comment ] Signed-off-by: Alistair Francis <alistair.francis@wdc.com> --- target/riscv/csr.c | 1 - 1 file changed, 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 const uint64_t all_ints = M_MODE_INTERRUPTS | S_MODE_INTERRUPTS | (1ULL << (RISCV_EXCP_U_ECALL)) | \ (1ULL << (RISCV_EXCP_S_ECALL)) | \ (1ULL << (RISCV_EXCP_VS_ECALL)) | \ - (1ULL << (RISCV_EXCP_M_ECALL)) | \ (1ULL << (RISCV_EXCP_INST_PAGE_FAULT)) | \ (1ULL << (RISCV_EXCP_LOAD_PAGE_FAULT)) | \ (1ULL << (RISCV_EXCP_STORE_PAGE_FAULT)) | \ -- 2.53.0
From: "chen.zhongyao@zte.com.cn" <chen.zhongyao@zte.com.cn> The risc-v vector spec defines vmv.s.x and vfmv.s.f as writing element 0 of the destination register while the remaining destination elements follow the current tail policy. When QEMU runs with rvv_ta_all_1s enabled, those elements must therefore become all 1s. QEMU handled both instructions as translation-time special cases that directly wrote vd[0] and skipped the usual tail processing. As a result, vmv.s.x and vfmv.s.f left the remaining destination elements unchanged instead of applying the configured tail policy. Fix this by routing both instructions through a helper that writes vd[0] and then treats the rest of the destination register as tail, reusing the existing agnostic-element fill logic. Signed-off-by: Zhongyao Chen <chen.zhongyao@zte.com.cn> Acked-by: Alistair Francis <alistair.francis@wdc.com> Message-ID: <202605061005.646A537u037157@mse-fl1.zte.com.cn> Signed-off-by: Alistair Francis <alistair.francis@wdc.com> --- target/riscv/helper.h | 4 +++ target/riscv/vector_helper.c | 18 ++++++++++ target/riscv/insn_trans/trans_rvv.c.inc | 44 ++++++++----------------- 3 files changed, 36 insertions(+), 30 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_4(vmv_v_x_b, void, ptr, i64, env, i32) DEF_HELPER_4(vmv_v_x_h, void, ptr, i64, env, i32) DEF_HELPER_4(vmv_v_x_w, void, ptr, i64, env, i32) DEF_HELPER_4(vmv_v_x_d, void, ptr, i64, env, i32) +DEF_HELPER_4(vset_velem0_b, void, ptr, i64, env, i32) +DEF_HELPER_4(vset_velem0_h, void, ptr, i64, env, i32) +DEF_HELPER_4(vset_velem0_w, void, ptr, i64, env, i32) +DEF_HELPER_4(vset_velem0_d, void, ptr, i64, env, i32) DEF_HELPER_6(vsaddu_vv_b, void, ptr, ptr, ptr, ptr, env, i32) DEF_HELPER_6(vsaddu_vv_h, void, ptr, ptr, ptr, ptr, env, i32) 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 @@ GEN_VEXT_VMV_VX(vmv_v_x_h, int16_t, H2) GEN_VEXT_VMV_VX(vmv_v_x_w, int32_t, H4) GEN_VEXT_VMV_VX(vmv_v_x_d, int64_t, H8) +#define GEN_VEXT_SET_VELEM0(NAME, ETYPE, H) \ +void HELPER(NAME)(void *vd, uint64_t s1, CPURISCVState *env, \ + uint32_t desc) \ +{ \ + uint32_t esz = sizeof(ETYPE); \ + uint32_t vlenb = riscv_cpu_cfg(env)->vlenb; \ + uint32_t vta = vext_vta(desc); \ + \ + *((ETYPE *)vd + H(0)) = (ETYPE)s1; \ + /* Treat every element past vd[0] as tail for scalar-to-vector moves. */ \ + vext_set_elems_1s(vd, vta, esz, vlenb); \ +} + +GEN_VEXT_SET_VELEM0(vset_velem0_b, int8_t, H1) +GEN_VEXT_SET_VELEM0(vset_velem0_h, int16_t, H2) +GEN_VEXT_SET_VELEM0(vset_velem0_w, int32_t, H4) +GEN_VEXT_SET_VELEM0(vset_velem0_d, int64_t, H8) + #define GEN_VEXT_VMERGE_VV(NAME, ETYPE, H) \ void HELPER(NAME)(void *vd, void *v0, void *vs1, void *vs2, \ CPURISCVState *env, uint32_t desc) \ 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 void vec_element_loadi(DisasContext *s, TCGv_i64 dest, load_element(dest, tcg_env, endian_ofs(s, vreg, idx), s->sew, sign); } -/* Integer Scalar Move Instruction */ +typedef void gen_helper_vset_velem0(TCGv_ptr, TCGv_i64, TCGv_env, TCGv_i32); -static void store_element(TCGv_i64 val, TCGv_ptr base, - int ofs, int sew) +static void vec_element_storei_tail(DisasContext *s, int vreg, TCGv_i64 val) { - switch (sew) { - case MO_8: - tcg_gen_st8_i64(val, base, ofs); - break; - case MO_16: - tcg_gen_st16_i64(val, base, ofs); - break; - case MO_32: - tcg_gen_st32_i64(val, base, ofs); - break; - case MO_64: - tcg_gen_st_i64(val, base, ofs); - break; - default: - g_assert_not_reached(); - } -} + static gen_helper_vset_velem0 * const fns[4] = { + gen_helper_vset_velem0_b, gen_helper_vset_velem0_h, + gen_helper_vset_velem0_w, gen_helper_vset_velem0_d, + }; + TCGv_ptr dest = tcg_temp_new_ptr(); + uint32_t data = FIELD_DP32(0, VDATA, VTA, s->vta); + TCGv_i32 desc = tcg_constant_i32(simd_desc(s->cfg_ptr->vlenb, + s->cfg_ptr->vlenb, data)); -/* - * Store vreg[idx] = val. - * The index must be in range of VLMAX. - */ -static void vec_element_storei(DisasContext *s, int vreg, - int idx, TCGv_i64 val) -{ - store_element(val, tcg_env, endian_ofs(s, vreg, idx), s->sew); + tcg_gen_addi_ptr(dest, tcg_env, vreg_ofs(s, vreg)); + fns[s->sew](dest, val, tcg_env, desc); } /* vmv.x.s rd, vs2 # x[rd] = vs2[0] */ @@ -XXX,XX +XXX,XX @@ static bool trans_vmv_s_x(DisasContext *s, arg_vmv_s_x *a) */ s1 = get_gpr(s, a->rs1, EXT_NONE); tcg_gen_ext_tl_i64(t1, s1); - vec_element_storei(s, a->rd, 0, t1); + vec_element_storei_tail(s, a->rd, t1); gen_set_label(over); tcg_gen_movi_tl(cpu_vstart, 0); finalize_rvv_inst(s); @@ -XXX,XX +XXX,XX @@ static bool trans_vfmv_s_f(DisasContext *s, arg_vfmv_s_f *a) t1 = tcg_temp_new_i64(); do_nanbox(s, t1, cpu_fpr[a->rs1]); - vec_element_storei(s, a->rd, 0, t1); + vec_element_storei_tail(s, a->rd, t1); gen_set_label(over); tcg_gen_movi_tl(cpu_vstart, 0); -- 2.53.0
From: Zishun Yi <vulab@iscas.ac.cn> The RISC-V unpriv specification (zvk.adoc) states that "Zvknhb implies Zvknha". This means that enabling Zvknhb should automatically enable Zvknha. Add Zvknha to ZVKNHB_IMPLIED to ensure the dependency is correctly enforced. This issue was discovered and reported by SpecHunter, an AI-driven architecture specification analysis tool. Link:https://github.com/yizishun/rv-isa-sec/blob/master/output/riscv-isa-manual/pr-2635/qemu.txt Signed-off-by: Zishun Yi <vulab@iscas.ac.cn> Reviewed-by: Daniel Henrique Barboza <daniel.barboza@oss.qualcomm.com> Message-ID: <20260511051736.2916225-1-vulab@iscas.ac.cn> 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 @@ static RISCVCPUImpliedExtsRule ZVKNG_IMPLIED = { static RISCVCPUImpliedExtsRule ZVKNHB_IMPLIED = { .ext = CPU_CFG_OFFSET(ext_zvknhb), .implied_multi_exts = { - CPU_CFG_OFFSET(ext_zve64x), + CPU_CFG_OFFSET(ext_zve64x), CPU_CFG_OFFSET(ext_zvknha), RISCV_IMPLIED_EXTS_RULE_END }, -- 2.53.0
From: Zishun Yi <vulab@iscas.ac.cn> Currently, the MENVCFG_CDE (Counter Delegation Enable) bit is unconditionally included in the base write mask for CSR_MENVCFG. This make the subsequent conditional check `(cfg->ext_smcdeleg ? MENVCFG_CDE : 0)` completely ineffective, as a bitwise OR cannot clear a bit that is already set. Fix this by removing MENVCFG_CDE from the initial base mask. The bit will now only be writable when explicitly granted by the `ext_smcdeleg` configuration. This issue was discovered and reported by SpecHunter, an AI-driven architecture specification analysis tool. Link: https://github.com/yizishun/rv-isa-sec/blob/master/output/riscv-isa-manual/pr-2601/qemu.txt Signed-off-by: Zishun Yi <vulab@iscas.ac.cn> Reviewed-by: Daniel Henrique Barboza <daniel.barboza@oss.qualcomm.com> Message-ID: <20260511040534.2862443-1-vulab@iscas.ac.cn> Signed-off-by: Alistair Francis <alistair.francis@wdc.com> --- target/riscv/csr.c | 2 +- 1 file changed, 1 insertion(+), 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 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; + MENVCFG_CBZE; bool stce_changed = false; if (riscv_cpu_mxl(env) == MXL_RV64) { -- 2.53.0
From: Zishun Yi <vulab@iscas.ac.cn> According to the RISC-V smcdeleg specification: "When menvcfg.CDE=0, attempts to access scountinhibit raise an illegal-instruction exception." The current implementation of scountinhibit_pred() only checks the hardware extensions (ext_ssccfg, ext_smcdeleg) and virtualization status, but completely misses the runtime environment configuration check (menvcfg.CDE). This allows S-mode to access scountinhibit even when the M-mode has explicitly disabled counter delegation. This issue was discovered by the SpecHunter tool (https://github.com/yizishun/rv-isa-sec/blob/master/output/riscv-isa-manual/pr-2571/qemu.txt). Fixes: 6247dc2ef70b ("target/riscv: Add counter delegation/configuration support") Signed-off-by: Zishun Yi <vulab@iscas.ac.cn> Reviewed-by: Daniel Henrique Barboza <daniel.barboza@oss.qualcomm.com> Message-ID: <20260508174917.371667-1-vulab@iscas.ac.cn> Signed-off-by: Alistair Francis <alistair.francis@wdc.com> --- target/riscv/csr.c | 4 ++++ 1 file changed, 4 insertions(+) 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 scountinhibit_pred(CPURISCVState *env, int csrno) return RISCV_EXCP_ILLEGAL_INST; } + if (!get_field(env->menvcfg, MENVCFG_CDE)) { + return RISCV_EXCP_ILLEGAL_INST; + } + if (env->virt_enabled) { return RISCV_EXCP_VIRT_INSTRUCTION_FAULT; } -- 2.53.0
From: Zishun Yi <vulab@iscas.ac.cn> According to the RISC-V Privileged Manual: "The Sv32 page-based virtual-memory scheme described in sv32 supports 34-bit physical addresses for RV32, so the PMP scheme must support addresses wider than XLEN for RV32." However, the current QEMU implementation uses `target_ulong` (which resolves to `uint32_t` on RV32) for PMP address variables. When shifting these addresses left (e.g., `this_addr << 2`), an integer overflow occurs, truncating the high bits of the 34-bit physical address. Fix this issue by changing the types of PMP address variables (`this_addr` and `prev_addr`) to `hwaddr`. This issue was discovered and reported by SpecHunter, an AI-driven architecture specification analysis tool. Link: https://github.com/yizishun/rv-isa-sec/blob/master/output/riscv-isa-manual/pr-2472/qemu.txt Signed-off-by: Zishun Yi <vulab@iscas.ac.cn> Reviewed-by: Alistair Francis <alistair.francis@wdc.com> Reviewed-by: Daniel Henrique Barboza <daniel.barboza@oss.qualcomm.com> Message-ID: <20260511102627.3120140-1-vulab@iscas.ac.cn> Signed-off-by: Alistair Francis <alistair.francis@wdc.com> --- target/riscv/pmp.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) 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 @@ static void pmp_decode_napot(hwaddr a, hwaddr *sa, hwaddr *ea) void pmp_update_rule_addr(CPURISCVState *env, uint32_t pmp_index) { uint8_t this_cfg = env->pmp_state.pmp[pmp_index].cfg_reg; - target_ulong this_addr = env->pmp_state.pmp[pmp_index].addr_reg; - target_ulong prev_addr = 0u; + hwaddr this_addr = env->pmp_state.pmp[pmp_index].addr_reg; + hwaddr prev_addr = 0u; hwaddr sa = 0u; hwaddr ea = 0u; int g = pmp_get_granularity_g(env); -- 2.53.0
From: Zishun Yi <vulab@iscas.ac.cn> Currently, the Machine Security Configuration Register (mseccfg) was missing from the live migration state. This omission causes the register to be reset to zero on the destination host after migration. Fixed by adding vmstate_mseccfg subsection This vulnerability was discovered and reported by SpecHunter, an AI-driven architecture specification analysis tool. Link: https://github.com/yizishun/rv-isa-sec/blob/a22e4459cd026ae970791dfbd9cfe5d110fbd46b/output/riscv-isa-manual/pr-1879/qemu.txt#L121 Signed-off-by: Zishun Yi <vulab@iscas.ac.cn> Reviewed-by: Alistair Francis <alistair.francis@wdc.com> Message-ID: <20260511124828.3210477-1-vulab@iscas.ac.cn> Signed-off-by: Alistair Francis <alistair.francis@wdc.com> --- target/riscv/machine.c | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) 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_sstc = { } }; +static bool mseccfg_needed(void *opaque) +{ + RISCVCPU *cpu = opaque; + + return cpu->cfg.ext_smepmp || cpu->cfg.ext_zkr + || cpu->cfg.ext_smmpm || cpu->cfg.ext_zicfilp; +} + +static const VMStateDescription vmstate_mseccfg = { + .name = "cpu/mseccfg", + .version_id = 1, + .minimum_version_id = 1, + .needed = mseccfg_needed, + .fields = (const VMStateField[]) { + VMSTATE_UINTTL(env.mseccfg, RISCVCPU), + VMSTATE_END_OF_LIST() + } +}; + const VMStateDescription vmstate_riscv_cpu = { .name = "cpu", .version_id = 11, @@ -XXX,XX +XXX,XX @@ const VMStateDescription vmstate_riscv_cpu = { &vmstate_ssp, &vmstate_ctr, &vmstate_sstc, + &vmstate_mseccfg, NULL } }; -- 2.53.0
From: Alistair Francis <alistair.francis@wdc.com> The RISC-V spec describes bits 0-15 as standard fixed interrupts. The AIA spec on the other hand describes bits 0-12 as standard fixed interrupts. This conflict causes issues for us as we don't dynamically determine if AIA is enabled when setting the *delegable_ints consts. This means currently we incorrectly treat the LCOFIP bit as delegable, even if AIA is disabled, which is incorrect (see the issues mentioned below). The AIA spec indicates that implementations can determine which bits of 13-63 in mvien are writable, so let's just make it bits 15-63 to match the main spec. Resolves: https://gitlab.com/qemu-project/qemu/-/work_items/3133 Resolves: https://gitlab.com/qemu-project/qemu/-/work_items/3134 Resolves: https://gitlab.com/qemu-project/qemu/-/work_items/3135 Resolves: https://gitlab.com/qemu-project/qemu/-/work_items/3138 Resolves: https://gitlab.com/qemu-project/qemu/-/work_items/3140 Signed-off-by: Alistair Francis <alistair.francis@wdc.com> Reviewed-by: Daniel Henrique Barboza <daniel.barboza@oss.qualcomm.com> Message-ID: <20260513051841.1671987-1-alistair.francis@wdc.com> Signed-off-by: Alistair Francis <alistair.francis@wdc.com> --- target/riscv/csr.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/target/riscv/csr.c b/target/riscv/csr.c index XXXXXXX..XXXXXXX 100644 --- a/target/riscv/csr.c +++ b/target/riscv/csr.c @@ -XXX,XX +XXX,XX @@ static RISCVException write_stimecmph(CPURISCVState *env, int csrno, #define VSTOPI_NUM_SRCS 5 /* - * All core local interrupts except the fixed ones 0:12. This macro is for + * All core local interrupts except the fixed ones 0:15. This macro is for * virtual interrupts logic so please don't change this to avoid messing up * the whole support, For reference see AIA spec: `5.3 Interrupt filtering and * virtual interrupts for supervisor level` and `6.3.2 Virtual interrupts for * VS level`. */ -#define LOCAL_INTERRUPTS (~0x1FFFULL) +#define LOCAL_INTERRUPTS (~0xFFFFULL) static const uint64_t delegable_ints = S_MODE_INTERRUPTS | VS_MODE_INTERRUPTS | MIP_LCOFIP; -- 2.53.0
From: Zishun Yi <vulab@iscas.ac.cn> Currently, the `mseccfg` CSR is only cleared to 0 during reset if the `ext_smepmp` is enabled. However, this register is now shared by several other extensions such as `zkr`, `smmpm`, and `zicfilp`. Fix by clearing `mseccfg` if any dependent extension is present, and adjusting the relevant comments. This vulnerability was discovered and reported by SpecHunter, an AI-driven architecture specification analysis tool. Link: https://github.com/yizishun/rv-isa-sec/blob/master/output/riscv-svvptc/pr-134/qemu.txt Signed-off-by: Zishun Yi <vulab@iscas.ac.cn> Reviewed-by: Daniel Henrique Barboza <daniel.barboza@oss.qualcomm.com> Message-ID: <20260512052240.330815-1-vulab@iscas.ac.cn> Signed-off-by: Alistair Francis <alistair.francis@wdc.com> --- target/riscv/cpu.c | 10 +++++++--- 1 file changed, 7 insertions(+), 3 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_reset_hold(Object *obj, ResetType type) /* * Clear mseccfg and unlock all the PMP entries upon reset. - * This is allowed as per the priv and smepmp specifications - * and is needed to clear stale entries across reboots. + * This is required as per the priv, smepmp, and other security + * extension specifications that share this CSR, and is needed + * to clear stale entries across reboots. */ - if (riscv_cpu_cfg(env)->ext_smepmp) { + if (riscv_cpu_cfg(env)->ext_smepmp || + riscv_cpu_cfg(env)->ext_zkr || + riscv_cpu_cfg(env)->ext_smmpm || + riscv_cpu_cfg(env)->ext_zicfilp) { env->mseccfg = 0; } -- 2.53.0
From: Zongmin Zhou <zhouzongmin@kylinos.cn> When the Zicbop extension is available expose it to the KVM guest. Also read and validate cbop_blocksize from the host via KVM interface. Signed-off-by: Zongmin Zhou <zhouzongmin@kylinos.cn> Reviewed-by: Daniel Henrique Barboza <daniel.barboza@oss.qualcomm.com> Message-ID: <9e388aa9984ea9d3d0c85e1630c9195023938952.1778653159.git.zhouzongmin@kylinos.cn> Signed-off-by: Alistair Francis <alistair.francis@wdc.com> --- target/riscv/kvm/kvm-cpu.c | 34 ++++++++++++++++++++++++++++++++-- 1 file changed, 32 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 void kvm_cpu_csr_set_u64(RISCVCPU *cpu, KVMCPUConfig *csr_cfg, static KVMCPUConfig kvm_multi_ext_cfgs[] = { KVM_EXT_CFG("zicbom", ext_zicbom, KVM_RISCV_ISA_EXT_ZICBOM), + KVM_EXT_CFG("zicbop", ext_zicbop, KVM_RISCV_ISA_EXT_ZICBOP), KVM_EXT_CFG("zicboz", ext_zicboz, KVM_RISCV_ISA_EXT_ZICBOZ), KVM_EXT_CFG("ziccrse", ext_ziccrse, KVM_RISCV_ISA_EXT_ZICCRSE), KVM_EXT_CFG("zicntr", ext_zicntr, KVM_RISCV_ISA_EXT_ZICNTR), @@ -XXX,XX +XXX,XX @@ static KVMCPUConfig kvm_cboz_blocksize = { .kvm_reg_id = KVM_REG_RISCV_CONFIG_REG(zicboz_block_size) }; +static KVMCPUConfig kvm_cbop_blocksize = { + .name = "cbop_blocksize", + .offset = CPU_CFG_OFFSET(cbop_blocksize), + .kvm_reg_id = KVM_REG_RISCV_CONFIG_REG(zicbop_block_size) +}; + static KVMCPUConfig kvm_v_vlenb = { .name = "vlenb", .offset = CPU_CFG_OFFSET(vlenb), @@ -XXX,XX +XXX,XX @@ static void kvm_riscv_init_cfg(RISCVCPU *cpu, KVMScratchCPU *kvmcpu) kvm_riscv_read_cbomz_blksize(cpu, kvmcpu, &kvm_cbom_blocksize); } + if (cpu->cfg.ext_zicbop) { + kvm_riscv_read_cbomz_blksize(cpu, kvmcpu, &kvm_cbop_blocksize); + } + if (cpu->cfg.ext_zicboz) { kvm_riscv_read_cbomz_blksize(cpu, kvmcpu, &kvm_cboz_blocksize); } @@ -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 && - !riscv_has_ext(env, RVV)) { + if (!cpu->cfg.ext_zicbom && !cpu->cfg.ext_zicbop && + !cpu->cfg.ext_zicboz && !riscv_has_ext(env, RVV)) { return; } @@ -XXX,XX +XXX,XX @@ void riscv_kvm_cpu_finalize_features(RISCVCPU *cpu, Error **errp) } } + if (cpu->cfg.ext_zicbop && + riscv_cpu_option_set(kvm_cbop_blocksize.name)) { + + reg.id = KVM_RISCV_REG_ID_ULONG(KVM_REG_RISCV_CONFIG, + kvm_cbop_blocksize.kvm_reg_id); + reg.addr = (uint64_t)&val; + ret = ioctl(kvmcpu.cpufd, KVM_GET_ONE_REG, ®); + if (ret != 0) { + error_setg_errno(errp, errno, "Unable to read cbop_blocksize"); + return; + } + + if (cpu->cfg.cbop_blocksize != val) { + error_setg(errp, "Unable to set cbop_blocksize to a different " + "value than the host (%lu)", val); + return; + } + } + /* Users are setting vlen, not vlenb */ if (riscv_has_ext(env, RVV) && riscv_cpu_option_set("vlen")) { if (!kvm_v_vlenb.supported) { -- 2.53.0
From: Zongmin Zhou <zhouzongmin@kylinos.cn> Expose the BFloat16 extensions (Zfbfmin, Zvfbfmin, Zvfbfwma) to KVM guests when available in hardware. Signed-off-by: Zongmin Zhou <zhouzongmin@kylinos.cn> Reviewed-by: Daniel Henrique Barboza <daniel.barboza@oss.qualcomm.com> Message-ID: <1258febb0eeb4ee286eb88f70b077a7f1ece507f.1778653159.git.zhouzongmin@kylinos.cn> Signed-off-by: Alistair Francis <alistair.francis@wdc.com> --- target/riscv/kvm/kvm-cpu.c | 3 +++ 1 file changed, 3 insertions(+) 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_multi_ext_cfgs[] = { KVM_EXT_CFG("zacas", ext_zacas, KVM_RISCV_ISA_EXT_ZACAS), KVM_EXT_CFG("zawrs", ext_zawrs, KVM_RISCV_ISA_EXT_ZAWRS), KVM_EXT_CFG("zfa", ext_zfa, KVM_RISCV_ISA_EXT_ZFA), + KVM_EXT_CFG("zfbfmin", ext_zfbfmin, KVM_RISCV_ISA_EXT_ZFBFMIN), KVM_EXT_CFG("zfh", ext_zfh, KVM_RISCV_ISA_EXT_ZFH), KVM_EXT_CFG("zfhmin", ext_zfhmin, KVM_RISCV_ISA_EXT_ZFHMIN), KVM_EXT_CFG("zba", ext_zba, KVM_RISCV_ISA_EXT_ZBA), @@ -XXX,XX +XXX,XX @@ static KVMCPUConfig kvm_multi_ext_cfgs[] = { KVM_EXT_CFG("zvbc", ext_zvbc, KVM_RISCV_ISA_EXT_ZVBC), KVM_EXT_CFG("zvfh", ext_zvfh, KVM_RISCV_ISA_EXT_ZVFH), KVM_EXT_CFG("zvfhmin", ext_zvfhmin, KVM_RISCV_ISA_EXT_ZVFHMIN), + KVM_EXT_CFG("zvfbfmin", ext_zvfbfmin, KVM_RISCV_ISA_EXT_ZVFBFMIN), + KVM_EXT_CFG("zvfbfwma", ext_zvfbfwma, KVM_RISCV_ISA_EXT_ZVFBFWMA), KVM_EXT_CFG("zvkb", ext_zvkb, KVM_RISCV_ISA_EXT_ZVKB), KVM_EXT_CFG("zvkg", ext_zvkg, KVM_RISCV_ISA_EXT_ZVKG), KVM_EXT_CFG("zvkned", ext_zvkned, KVM_RISCV_ISA_EXT_ZVKNED), -- 2.53.0
From: Zishun Yi <vulab@iscas.ac.cn> Fix a mode-to-capability comparison error in riscv_iommu_validate_device_ctx. The code was comparing fsc_mode (a value) against a capability bitmask, making the SV32 support check ineffective. This issue was discovered and reported by SpecHunter, an AI-driven architecture specification analysis tool. Link: https://github.com/yizishun/rv-isa-sec/blob/master/output/riscv-iommu/pr-694/qemu.txt Signed-off-by: Zishun Yi <vulab@iscas.ac.cn> Reviewed-by: Daniel Henrique Barboza <daniel.barboza@oss.qualcomm.com> Message-ID: <20260511080904.3049446-1-vulab@iscas.ac.cn> Signed-off-by: Alistair Francis <alistair.francis@wdc.com> --- hw/riscv/riscv-iommu.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/hw/riscv/riscv-iommu.c b/hw/riscv/riscv-iommu.c index XXXXXXX..XXXXXXX 100644 --- a/hw/riscv/riscv-iommu.c +++ b/hw/riscv/riscv-iommu.c @@ -XXX,XX +XXX,XX @@ static bool riscv_iommu_validate_device_ctx(RISCVIOMMUState *s, } if (ctx->tc & RISCV_IOMMU_DC_TC_SXL) { - if (fsc_mode == RISCV_IOMMU_CAP_SV32 && + if (fsc_mode == RISCV_IOMMU_DC_FSC_IOSATP_MODE_SV32 && !(s->cap & RISCV_IOMMU_CAP_SV32)) { return false; } -- 2.53.0
From: Chengbo Gao <gaochengbo@bosc.ac.cn> PCI bus numbers may still be unassigned when QEMU initializes a PCI device's bus-master address space. For devices behind bridges, pci_bus_num() can return 0 at that point because the guest has not yet programmed the bridge Secondary Bus Number register. The RISC-V IOMMU currently stores a fixed device_id in RISCVIOMMUSpace when the address space is created. If the guest later enumerates the device on a non-zero bus, DMA translation still uses the stale device_id and may look up the wrong device context in the DDT. Store the stable PCIBus pointer and devfn in RISCVIOMMUSpace instead, and compute the device_id from the current bus number when it is needed. This keeps DMA translation and ATS invalidation in sync with guest PCI bus enumeration. Signed-off-by: Chengbo Gao <gaochengbo@bosc.ac.cn> Reviewed-by: Daniel Henrique Barboza <daniel.barboza@oss.qualcomm.com> Message-ID: <20260514020637.2819308-1-gaochengbo@bosc.ac.cn> Signed-off-by: Alistair Francis <alistair.francis@wdc.com> --- hw/riscv/riscv-iommu.c | 40 +++++++++++++++++++++++++--------------- 1 file changed, 25 insertions(+), 15 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 @@ struct RISCVIOMMUSpace { IOMMUMemoryRegion iova_mr; /* IOVA memory region for attached device */ AddressSpace iova_as; /* IOVA address space for attached device */ RISCVIOMMUState *iommu; /* Managing IOMMU device state */ - uint32_t devid; /* Requester identifier, AKA device_id */ + PCIBus *bus; /* PCI bus of the requester */ + uint8_t devfn; /* Requester identifier, AKA device_id */ bool notifier; /* IOMMU unmap notifier enabled */ QLIST_ENTRY(RISCVIOMMUSpace) list; }; @@ -XXX,XX +XXX,XX @@ struct RISCVIOMMUEntry { /* IOMMU index for transactions without process_id specified. */ #define RISCV_IOMMU_NOPROCID 0 +static uint32_t riscv_iommu_space_devid(RISCVIOMMUSpace *as) +{ + uint32_t devid = PCI_BUILD_BDF(pci_bus_num(as->bus), as->devfn); + + /* FIXME: PCIe bus remapping for attached endpoints. */ + devid |= as->iommu->bus << 8; + return devid; +} + static uint8_t riscv_iommu_get_icvec_vector(uint32_t icvec, uint32_t vec_type) { switch (vec_type) { @@ -XXX,XX +XXX,XX @@ static void riscv_iommu_ctx_put(RISCVIOMMUState *s, void *ref) } /* Find or allocate address space for a given device */ -static AddressSpace *riscv_iommu_space(RISCVIOMMUState *s, uint32_t devid) +static AddressSpace *riscv_iommu_space(RISCVIOMMUState *s, PCIBus *bus, + int devfn) { RISCVIOMMUSpace *as; - /* FIXME: PCIe bus remapping for attached endpoints. */ - devid |= s->bus << 8; - QLIST_FOREACH(as, &s->spaces, list) { - if (as->devid == devid) { + if (as->bus == bus && as->devfn == devfn) { break; } } @@ -XXX,XX +XXX,XX @@ static AddressSpace *riscv_iommu_space(RISCVIOMMUState *s, uint32_t devid) as = g_new0(RISCVIOMMUSpace, 1); as->iommu = s; - as->devid = devid; + as->bus = bus; + as->devfn = devfn; snprintf(name, sizeof(name), "riscv-iommu-%04x:%02x.%d-iova", - PCI_BUS_NUM(as->devid), PCI_SLOT(as->devid), PCI_FUNC(as->devid)); + pci_bus_num(bus), PCI_SLOT(devfn), PCI_FUNC(devfn)); /* IOVA address space, untranslated addresses */ memory_region_init_iommu(&as->iova_mr, sizeof(as->iova_mr), @@ -XXX,XX +XXX,XX @@ static AddressSpace *riscv_iommu_space(RISCVIOMMUState *s, uint32_t devid) QLIST_INSERT_HEAD(&s->spaces, as, list); - trace_riscv_iommu_new(s->parent_obj.id, PCI_BUS_NUM(as->devid), - PCI_SLOT(as->devid), PCI_FUNC(as->devid)); + trace_riscv_iommu_new(s->parent_obj.id, pci_bus_num(bus), + PCI_SLOT(devfn), PCI_FUNC(devfn)); } return &as->iova_as; } @@ -XXX,XX +XXX,XX @@ static void riscv_iommu_ats(RISCVIOMMUState *s, pid = get_field(cmd->dword0, RISCV_IOMMU_CMD_ATS_PID); QLIST_FOREACH(as, &s->spaces, list) { - if (as->devid == devid) { + if (riscv_iommu_space_devid(as) == devid) { break; } } @@ -XXX,XX +XXX,XX @@ static IOMMUTLBEntry riscv_iommu_memory_region_translate( .addr_mask = ~0ULL, .perm = flag, }; + uint32_t devid = riscv_iommu_space_devid(as); - ctx = riscv_iommu_ctx(as->iommu, as->devid, iommu_idx, &ref); + ctx = riscv_iommu_ctx(as->iommu, devid, iommu_idx, &ref); if (ctx == NULL) { /* Translation disabled or invalid. */ iotlb.addr_mask = 0; @@ -XXX,XX +XXX,XX @@ static IOMMUTLBEntry riscv_iommu_memory_region_translate( } /* Trace all dma translations with original access flags. */ - trace_riscv_iommu_dma(as->iommu->parent_obj.id, PCI_BUS_NUM(as->devid), - PCI_SLOT(as->devid), PCI_FUNC(as->devid), iommu_idx, + trace_riscv_iommu_dma(as->iommu->parent_obj.id, PCI_BUS_NUM(devid), + PCI_SLOT(devid), PCI_FUNC(devid), iommu_idx, IOMMU_FLAG_STR[flag & IOMMU_RW], iotlb.iova, iotlb.translated_addr); @@ -XXX,XX +XXX,XX @@ static AddressSpace *riscv_iommu_find_as(PCIBus *bus, void *opaque, int devfn) /* Find first matching IOMMU */ while (s != NULL && as == NULL) { - as = riscv_iommu_space(s, PCI_BUILD_BDF(pci_bus_num(bus), devfn)); + as = riscv_iommu_space(s, bus, devfn); s = s->iommus.le_next; } -- 2.53.0
From: Guenter Roeck <linux@roeck-us.net> Minimal clock register configuration required to boot Linux without backtraces in the clock code. Signed-off-by: Guenter Roeck <linux@roeck-us.net> Signed-off-by: Conor Dooley <conor.dooley@microchip.com> Acked-by: Alistair Francis <alistair.francis@wdc.com> Message-ID: <20260514-reference-overhand-749149e36a88@spud> [ Changes by AF: - Fixup checkpatch errors ] Signed-off-by: Alistair Francis <alistair.francis@wdc.com> --- include/hw/misc/mchp_pfsoc_ioscb.h | 2 ++ hw/misc/mchp_pfsoc_ioscb.c | 47 +++++++++++++++++++++++++++++- hw/misc/mchp_pfsoc_sysreg.c | 13 +++++++++ 3 files changed, 61 insertions(+), 1 deletion(-) diff --git a/include/hw/misc/mchp_pfsoc_ioscb.h b/include/hw/misc/mchp_pfsoc_ioscb.h index XXXXXXX..XXXXXXX 100644 --- a/include/hw/misc/mchp_pfsoc_ioscb.h +++ b/include/hw/misc/mchp_pfsoc_ioscb.h @@ -XXX,XX +XXX,XX @@ typedef struct MchpPfSoCIoscbState { MemoryRegion mailbox; MemoryRegion cfg; MemoryRegion ccc; + MemoryRegion pll_nw_0; + MemoryRegion pll_nw_1; MemoryRegion pll_mss; MemoryRegion cfm_mss; MemoryRegion pll_ddr; diff --git a/hw/misc/mchp_pfsoc_ioscb.c b/hw/misc/mchp_pfsoc_ioscb.c index XXXXXXX..XXXXXXX 100644 --- a/hw/misc/mchp_pfsoc_ioscb.c +++ b/hw/misc/mchp_pfsoc_ioscb.c @@ -XXX,XX +XXX,XX @@ #define IOSCB_MAILBOX_BASE 0x07020800 #define IOSCB_CFG_BASE 0x07080000 #define IOSCB_CCC_BASE 0x08000000 +#define IOSCB_PLL_NW0_BASE 0x08100000 +#define IOSCB_PLL_NW1_BASE 0x08200000 #define IOSCB_PLL_MSS_BASE 0x0E001000 #define IOSCB_CFM_MSS_BASE 0x0E002000 #define IOSCB_PLL_DDR_BASE 0x0E010000 @@ -XXX,XX +XXX,XX @@ static const MemoryRegionOps mchp_pfsoc_dummy_ops = { /* All PLL modules in IOSCB have the same register layout */ #define PLL_CTRL 0x04 +#define PLL_REF_FB 0x08 +#define PLL_DIV_0_1 0x10 +#define PLL_DIV_2_3 0x14 +#define PLL_CTRL2 0x18 +#define PLL_CAL 0x1c +#define PLL_PHADJ 0x20 +#define SSCG_REG_0 0x24 +#define SSCG_REG_1 0x28 +#define SSCG_REG_2 0x2c +#define SSCG_REG_3 0x30 static uint64_t mchp_pfsoc_pll_read(void *opaque, hwaddr offset, unsigned size) @@ -XXX,XX +XXX,XX @@ static uint64_t mchp_pfsoc_pll_read(void *opaque, hwaddr offset, /* PLL is locked */ val = BIT(25); break; + case PLL_DIV_0_1: + case PLL_DIV_2_3: + val = 0x01000100; /* return valid post divider values */ + break; + case PLL_CTRL2: + val = 0x00001110; + break; + case PLL_REF_FB: + val = 0x00000100; /* RFDIV := 1 */ + break; + case SSCG_REG_2: + val = 0x00000001; /* INTIN := 1 */ + break; + case PLL_PHADJ: + val = 0x00000401; + break; default: qemu_log_mask(LOG_UNIMP, "%s: unimplemented device read " "(size %d, offset 0x%" HWADDR_PRIx ")\n", @@ -XXX,XX +XXX,XX @@ static uint64_t mchp_pfsoc_pll_read(void *opaque, hwaddr offset, return val; } +static void mchp_pfsoc_pll_write(void *opaque, hwaddr offset, + uint64_t value, unsigned size) +{ + qemu_log_mask(LOG_UNIMP, "%s: unimplemented device write " + "(size %d, value 0x%" PRIx64 + ", offset 0x%" HWADDR_PRIx ")\n", + __func__, size, value, offset); +} + static const MemoryRegionOps mchp_pfsoc_pll_ops = { .read = mchp_pfsoc_pll_read, - .write = mchp_pfsoc_dummy_write, + .write = mchp_pfsoc_pll_write, .endianness = DEVICE_LITTLE_ENDIAN, }; @@ -XXX,XX +XXX,XX @@ static void mchp_pfsoc_ioscb_realize(DeviceState *dev, Error **errp) "mchp.pfsoc.ioscb.ccc", IOSCB_CCC_REG_SIZE); memory_region_add_subregion(&s->container, IOSCB_CCC_BASE, &s->ccc); + memory_region_init_io(&s->pll_nw_0, OBJECT(s), &mchp_pfsoc_pll_ops, s, + "mchp.pfsoc.ioscb.pll_nw_0", IOSCB_SUBMOD_REG_SIZE); + memory_region_add_subregion(&s->container, IOSCB_PLL_NW0_BASE, &s->pll_nw_0); + + memory_region_init_io(&s->pll_nw_1, OBJECT(s), &mchp_pfsoc_pll_ops, s, + "mchp.pfsoc.ioscb.pll_nw_1", IOSCB_SUBMOD_REG_SIZE); + memory_region_add_subregion(&s->container, IOSCB_PLL_NW1_BASE, &s->pll_nw_1); + memory_region_init_io(&s->pll_mss, OBJECT(s), &mchp_pfsoc_pll_ops, s, "mchp.pfsoc.ioscb.pll_mss", IOSCB_SUBMOD_REG_SIZE); memory_region_add_subregion(&s->container, IOSCB_PLL_MSS_BASE, &s->pll_mss); diff --git a/hw/misc/mchp_pfsoc_sysreg.c b/hw/misc/mchp_pfsoc_sysreg.c index XXXXXXX..XXXXXXX 100644 --- a/hw/misc/mchp_pfsoc_sysreg.c +++ b/hw/misc/mchp_pfsoc_sysreg.c @@ -XXX,XX +XXX,XX @@ #include "hw/misc/mchp_pfsoc_sysreg.h" #include "system/runstate.h" +#define CLOCK_CONFIG_CR 0x8 +#define RTC_CLOCK_CR 0xc #define MSS_RESET_CR 0x18 #define ENVM_CR 0xb8 #define MESSAGE_INT 0x118c @@ -XXX,XX +XXX,XX @@ static uint64_t mchp_pfsoc_sysreg_read(void *opaque, hwaddr offset, uint32_t val = 0; switch (offset) { + case CLOCK_CONFIG_CR: + /* Icicle kit reference design cpu/axi/ahb divider setting */ + val = 0x24; + break; + case RTC_CLOCK_CR: + /* + * Bit 16 enables the RTC clock, 0x7d is the required divider + * setting for a 125 MHz reference. + */ + val = BIT(16) | 0x7d; + break; case ENVM_CR: /* Indicate the eNVM is running at the configured divider rate */ val = BIT(6); -- 2.53.0
From: Daniel Henrique Barboza <daniel.barboza@oss.qualcomm.com> The entry was missing from isa_edata_arr[]. Fixes: 32bbab666 ("target/riscv: add draft RISC-V Zbr ext as xbr0p93") Signed-off-by: Daniel Henrique Barboza <daniel.barboza@oss.qualcomm.com> Reviewed-by: Alistair Francis <alistair.francis@wdc.com> Message-ID: <20260512032926.1978818-2-daniel.barboza@oss.qualcomm.com> Signed-off-by: Alistair Francis <alistair.francis@wdc.com> --- target/riscv/cpu.c | 1 + 1 file 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(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(xlrbr, PRIV_VERSION_1_13_0, ext_xlrbr), ISA_EXT_DATA_ENTRY(xmipscbop, PRIV_VERSION_1_12_0, ext_xmipscbop), ISA_EXT_DATA_ENTRY(xmipscmov, PRIV_VERSION_1_12_0, ext_xmipscmov), ISA_EXT_DATA_ENTRY(xmipslsp, PRIV_VERSION_1_12_0, ext_xmipslsp), -- 2.53.0
From: Daniel Henrique Barboza <daniel.barboza@oss.qualcomm.com> Noticed when realizing that 'svadu' was too far apart from 'svade'. Signed-off-by: Daniel Henrique Barboza <daniel.barboza@oss.qualcomm.com> Reviewed-by: Alistair Francis <alistair.francis@wdc.com> Message-ID: <20260512032926.1978818-3-daniel.barboza@oss.qualcomm.com> Signed-off-by: Alistair Francis <alistair.francis@wdc.com> --- target/riscv/cpu.c | 4 ++-- 1 file changed, 2 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 RISCVIsaExtData isa_edata_arr[] = { ISA_EXT_DATA_ENTRY(smcdeleg, PRIV_VERSION_1_13_0, ext_smcdeleg), ISA_EXT_DATA_ENTRY(smcntrpmf, PRIV_VERSION_1_12_0, ext_smcntrpmf), ISA_EXT_DATA_ENTRY(smcsrind, PRIV_VERSION_1_13_0, ext_smcsrind), + ISA_EXT_DATA_ENTRY(smctr, PRIV_VERSION_1_12_0, ext_smctr), ISA_EXT_DATA_ENTRY(smdbltrp, PRIV_VERSION_1_13_0, ext_smdbltrp), ISA_EXT_DATA_ENTRY(smepmp, PRIV_VERSION_1_12_0, ext_smepmp), ISA_EXT_DATA_ENTRY(smpmpmt, PRIV_VERSION_1_12_0, ext_smpmpmt), @@ -XXX,XX +XXX,XX @@ const RISCVIsaExtData isa_edata_arr[] = { ISA_EXT_DATA_ENTRY(sscofpmf, PRIV_VERSION_1_12_0, ext_sscofpmf), ISA_EXT_DATA_ENTRY(sscounterenw, PRIV_VERSION_1_12_0, has_priv_1_12), ISA_EXT_DATA_ENTRY(sscsrind, PRIV_VERSION_1_12_0, ext_sscsrind), + ISA_EXT_DATA_ENTRY(ssctr, PRIV_VERSION_1_12_0, ext_ssctr), ISA_EXT_DATA_ENTRY(ssdbltrp, PRIV_VERSION_1_13_0, ext_ssdbltrp), ISA_EXT_DATA_ENTRY(ssnpm, PRIV_VERSION_1_13_0, ext_ssnpm), ISA_EXT_DATA_ENTRY(sspm, PRIV_VERSION_1_13_0, ext_sspm), @@ -XXX,XX +XXX,XX @@ const RISCVIsaExtData isa_edata_arr[] = { ISA_EXT_DATA_ENTRY(ssu64xl, PRIV_VERSION_1_12_0, has_priv_1_12), ISA_EXT_DATA_ENTRY(supm, PRIV_VERSION_1_13_0, ext_supm), ISA_EXT_DATA_ENTRY(svade, PRIV_VERSION_1_11_0, ext_svade), - ISA_EXT_DATA_ENTRY(smctr, PRIV_VERSION_1_12_0, ext_smctr), - ISA_EXT_DATA_ENTRY(ssctr, PRIV_VERSION_1_12_0, ext_ssctr), ISA_EXT_DATA_ENTRY(svadu, PRIV_VERSION_1_12_0, ext_svadu), ISA_EXT_DATA_ENTRY(svinval, PRIV_VERSION_1_12_0, ext_svinval), ISA_EXT_DATA_ENTRY(svnapot, PRIV_VERSION_1_12_0, ext_svnapot), -- 2.53.0
From: Daniel Henrique Barboza <daniel.barboza@oss.qualcomm.com> We want to reduce the usage of the riscv_cpu_* arrays in target/riscv/cpu.c, centering everything in isa_edata_arr[] instead, to reduce data duplication and make our lives a bit easier when adding new extensions. To do that we'll have to make isa_edata_arr[] do what the other arrays are currently doing, not breaking existing semantics in the process. The riscv_cpu_* arrays have a few exclusive uses: - set default extensions for rv32 and rv64; - create user CPU properties; - misc uses around tcg-cpu.c and kvm-cpu.c. We'll slowly make isa_edata_arr[] supersede these arrays. Start by adding a new 'prop_name' field in RISCVIsaExtData. This field is needed because not all extensions have properties and not all properties match the riscv,isa string name. Create two additional macros and reclassify existing isa_edata_arr[] entries as follows: - ISA_EXT_DATA_ENTRY creates an entry where prop_name == riscv,isa. Most of our regular extensions fall into this category; - ISA_EXPERIMENTAL_EXT_DATA_ENTRY: same as above but add a "x-" to the prop name, i.e. prop_name == "x-" + riscv,isa; - ISA_INTERNAL_EXT_DATA_ENTRY: used to declared internal extensions. By 'internal' we mean users/management can't set them on or off. With these new macros we can start our simplification by changing riscv-qmp-cmds to use isa_edata_arr[]. We'll just scroll through it once and gather what we need. Signed-off-by: Daniel Henrique Barboza <daniel.barboza@oss.qualcomm.com> Acked-by: Alistair Francis <alistair.francis@wdc.com> Message-ID: <20260512032926.1978818-4-daniel.barboza@oss.qualcomm.com> Signed-off-by: Alistair Francis <alistair.francis@wdc.com> --- target/riscv/cpu.h | 1 + target/riscv/cpu.c | 60 +++++++++++++++++++++++------------ target/riscv/riscv-qmp-cmds.c | 30 ++++-------------- 3 files changed, 47 insertions(+), 44 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_named_features[]; typedef struct isa_ext_data { const char *name; + const char *prop_name; int min_version; int ext_enable_offset; } RISCVIsaExtData; 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_cfg_merge(RISCVCPUConfig *dest, const RISCVCPUConfig *src) #include "cpu_cfg_fields.h.inc" } +/* Use this for regular user facing extensions */ #define ISA_EXT_DATA_ENTRY(_name, _min_ver, _prop) \ - {#_name, _min_ver, CPU_CFG_OFFSET(_prop)} + {#_name, #_name, _min_ver, CPU_CFG_OFFSET(_prop)} + +/* + * Same as above but for experimental extensions. We'll add a + * "x-" right after "_name" when creating the user property. + */ +#define ISA_EXPERIMENTAL_EXT_DATA_ENTRY(_name, _min_ver, _prop) \ + {#_name, "x-" #_name, _min_ver, CPU_CFG_OFFSET(_prop)} + +/* + * Internal extensions are extensions we will declare in the + * riscv,isa DT but they don't have an user property, i.e. + * users/management can't enable/disable them. + */ +#define ISA_INTERNAL_EXT_DATA_ENTRY(_name, _min_ver, _prop) \ + {#_name, NULL, _min_ver, CPU_CFG_OFFSET(_prop)} /* * Here are the ordering rules of extension naming defined by RISC-V @@ -XXX,XX +XXX,XX @@ static void riscv_cpu_cfg_merge(RISCVCPUConfig *dest, const RISCVCPUConfig *src) * instead. */ const RISCVIsaExtData isa_edata_arr[] = { - ISA_EXT_DATA_ENTRY(zic64b, PRIV_VERSION_1_12_0, ext_zic64b), + ISA_INTERNAL_EXT_DATA_ENTRY(zic64b, PRIV_VERSION_1_12_0, ext_zic64b), ISA_EXT_DATA_ENTRY(zicbom, PRIV_VERSION_1_12_0, ext_zicbom), ISA_EXT_DATA_ENTRY(zicbop, PRIV_VERSION_1_12_0, ext_zicbop), ISA_EXT_DATA_ENTRY(zicboz, PRIV_VERSION_1_12_0, ext_zicboz), - ISA_EXT_DATA_ENTRY(ziccamoa, PRIV_VERSION_1_11_0, has_priv_1_11), - ISA_EXT_DATA_ENTRY(ziccif, PRIV_VERSION_1_11_0, has_priv_1_11), - ISA_EXT_DATA_ENTRY(zicclsm, PRIV_VERSION_1_11_0, has_priv_1_11), + ISA_INTERNAL_EXT_DATA_ENTRY(ziccamoa, PRIV_VERSION_1_11_0, has_priv_1_11), + ISA_INTERNAL_EXT_DATA_ENTRY(ziccif, PRIV_VERSION_1_11_0, has_priv_1_11), + ISA_INTERNAL_EXT_DATA_ENTRY(zicclsm, PRIV_VERSION_1_11_0, has_priv_1_11), ISA_EXT_DATA_ENTRY(ziccrse, PRIV_VERSION_1_11_0, ext_ziccrse), ISA_EXT_DATA_ENTRY(zicfilp, PRIV_VERSION_1_12_0, ext_zicfilp), ISA_EXT_DATA_ENTRY(zicfiss, PRIV_VERSION_1_13_0, ext_zicfiss), @@ -XXX,XX +XXX,XX @@ const RISCVIsaExtData isa_edata_arr[] = { ISA_EXT_DATA_ENTRY(zilsd, PRIV_VERSION_1_12_0, ext_zilsd), ISA_EXT_DATA_ENTRY(zimop, PRIV_VERSION_1_13_0, ext_zimop), ISA_EXT_DATA_ENTRY(zmmul, PRIV_VERSION_1_12_0, ext_zmmul), - ISA_EXT_DATA_ENTRY(za64rs, PRIV_VERSION_1_12_0, has_priv_1_12), + ISA_INTERNAL_EXT_DATA_ENTRY(za64rs, PRIV_VERSION_1_12_0, has_priv_1_12), 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), @@ -XXX,XX +XXX,XX @@ const RISCVIsaExtData isa_edata_arr[] = { 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), - ISA_EXT_DATA_ENTRY(shtvala, PRIV_VERSION_1_12_0, has_priv_1_12), - ISA_EXT_DATA_ENTRY(shvsatpa, PRIV_VERSION_1_12_0, has_priv_1_12), - ISA_EXT_DATA_ENTRY(shvstvala, PRIV_VERSION_1_12_0, has_priv_1_12), - ISA_EXT_DATA_ENTRY(shvstvecd, PRIV_VERSION_1_12_0, has_priv_1_12), + ISA_INTERNAL_EXT_DATA_ENTRY(shcounterenw, PRIV_VERSION_1_12_0, + has_priv_1_12), + ISA_INTERNAL_EXT_DATA_ENTRY(sha, PRIV_VERSION_1_12_0, ext_sha), + ISA_INTERNAL_EXT_DATA_ENTRY(shgatpa, PRIV_VERSION_1_12_0, has_priv_1_12), + ISA_INTERNAL_EXT_DATA_ENTRY(shtvala, PRIV_VERSION_1_12_0, has_priv_1_12), + ISA_INTERNAL_EXT_DATA_ENTRY(shvsatpa, PRIV_VERSION_1_12_0, has_priv_1_12), + ISA_INTERNAL_EXT_DATA_ENTRY(shvstvala, PRIV_VERSION_1_12_0, has_priv_1_12), + ISA_INTERNAL_EXT_DATA_ENTRY(shvstvecd, PRIV_VERSION_1_12_0, has_priv_1_12), ISA_EXT_DATA_ENTRY(smaia, PRIV_VERSION_1_12_0, ext_smaia), ISA_EXT_DATA_ENTRY(smcdeleg, PRIV_VERSION_1_13_0, ext_smcdeleg), ISA_EXT_DATA_ENTRY(smcntrpmf, PRIV_VERSION_1_12_0, ext_smcntrpmf), @@ -XXX,XX +XXX,XX @@ const RISCVIsaExtData isa_edata_arr[] = { ISA_EXT_DATA_ENTRY(smstateen, PRIV_VERSION_1_12_0, ext_smstateen), ISA_EXT_DATA_ENTRY(ssaia, PRIV_VERSION_1_12_0, ext_ssaia), ISA_EXT_DATA_ENTRY(ssccfg, PRIV_VERSION_1_13_0, ext_ssccfg), - ISA_EXT_DATA_ENTRY(ssccptr, PRIV_VERSION_1_11_0, has_priv_1_11), + ISA_INTERNAL_EXT_DATA_ENTRY(ssccptr, PRIV_VERSION_1_11_0, has_priv_1_11), ISA_EXT_DATA_ENTRY(sscofpmf, PRIV_VERSION_1_12_0, ext_sscofpmf), - ISA_EXT_DATA_ENTRY(sscounterenw, PRIV_VERSION_1_12_0, has_priv_1_12), + ISA_INTERNAL_EXT_DATA_ENTRY(sscounterenw, PRIV_VERSION_1_12_0, + has_priv_1_12), ISA_EXT_DATA_ENTRY(sscsrind, PRIV_VERSION_1_12_0, ext_sscsrind), ISA_EXT_DATA_ENTRY(ssctr, PRIV_VERSION_1_12_0, ext_ssctr), ISA_EXT_DATA_ENTRY(ssdbltrp, PRIV_VERSION_1_13_0, ext_ssdbltrp), 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_INTERNAL_EXT_DATA_ENTRY(ssstateen, PRIV_VERSION_1_12_0, ext_ssstateen), + ISA_INTERNAL_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), - ISA_EXT_DATA_ENTRY(ssu64xl, PRIV_VERSION_1_12_0, has_priv_1_12), + ISA_INTERNAL_EXT_DATA_ENTRY(sstvala, PRIV_VERSION_1_12_0, has_priv_1_12), + ISA_INTERNAL_EXT_DATA_ENTRY(sstvecd, PRIV_VERSION_1_12_0, has_priv_1_12), + ISA_INTERNAL_EXT_DATA_ENTRY(ssu64xl, PRIV_VERSION_1_12_0, has_priv_1_12), ISA_EXT_DATA_ENTRY(supm, PRIV_VERSION_1_13_0, ext_supm), ISA_EXT_DATA_ENTRY(svade, PRIV_VERSION_1_11_0, ext_svade), ISA_EXT_DATA_ENTRY(svadu, PRIV_VERSION_1_12_0, ext_svadu), @@ -XXX,XX +XXX,XX @@ const RISCVIsaExtData isa_edata_arr[] = { 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_EXPERIMENTAL_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(xlrbr, PRIV_VERSION_1_13_0, ext_xlrbr), ISA_EXT_DATA_ENTRY(xmipscbop, PRIV_VERSION_1_12_0, ext_xmipscbop), 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_qdict_prop(Object *obj, QDict *qdict_out, } } -static void riscv_obj_add_multiext_props(Object *obj, QDict *qdict_out, - const RISCVCPUMultiExtConfig *arr) +static void riscv_obj_add_multiext_props(Object *obj, QDict *qdict_out) { - for (int i = 0; arr[i].name != NULL; i++) { - riscv_obj_add_qdict_prop(obj, qdict_out, arr[i].name); - } -} + const RISCVIsaExtData *edata; -static void riscv_obj_add_named_feats_qdict(Object *obj, QDict *qdict_out) -{ - const RISCVCPUMultiExtConfig *named_cfg; - RISCVCPU *cpu = RISCV_CPU(obj); - QObject *value; - bool flag_val; - - for (int i = 0; riscv_cpu_named_features[i].name != NULL; i++) { - named_cfg = &riscv_cpu_named_features[i]; - flag_val = isa_ext_is_enabled(cpu, named_cfg->offset); - value = QOBJECT(qbool_from_bool(flag_val)); - - qdict_put_obj(qdict_out, named_cfg->name, value); + for (edata = isa_edata_arr; edata && edata->name; edata++) { + if (edata->prop_name) { + riscv_obj_add_qdict_prop(obj, qdict_out, edata->prop_name); + } } } @@ -XXX,XX +XXX,XX @@ CpuModelExpansionInfo *qmp_query_cpu_model_expansion(CpuModelExpansionType type, qdict_out = qdict_new(); - riscv_obj_add_multiext_props(obj, qdict_out, riscv_cpu_extensions); - riscv_obj_add_multiext_props(obj, qdict_out, riscv_cpu_experimental_exts); - riscv_obj_add_multiext_props(obj, qdict_out, riscv_cpu_vendor_exts); - riscv_obj_add_named_feats_qdict(obj, qdict_out); + riscv_obj_add_multiext_props(obj, qdict_out); riscv_obj_add_profiles_qdict(obj, qdict_out); /* Add our CPU boolean options too */ -- 2.53.0
From: Daniel Henrique Barboza <daniel.barboza@oss.qualcomm.com> Commit 7e4f75cadf ("target/riscv/tcg: hide warn for named feats when disabling via priv_ver") changed the design of disable_priv_spec_isa_exts to not warn when disabling what we were calling "named features" at that time. Back in that time we were adding RVA22 profile support and we were dealing with a RVI innovation: named features. These can be define as cute names for pre-existing behavior/parameters, e.g. 'zic64b' means all cache blocks must have 64 bytes. They do get inserted in the riscv,isa but they are not "real" extensions because users shouldn't be setting them in the command line, or so we thought back then, and we attempted to model that by calling it "named features". This didn't age that well: ziccrse is a so called named feature as far as TCG goes, but then KVM had to treat it as a regular extension that can be user set and we made an exception: ziccrse is a named feature that is user set by KVM. "Named features" are regular extensions that might or might not be user set, and might or might not warrant special handling during realize() by setting other parameters. And we'll being treating them as such, which will culminate in the end of riscv_cpu_named_features[] array in the end. This reverts commit 7e4f75cadf44ee67809c7ca82645a289a5268966. Signed-off-by: Daniel Henrique Barboza <daniel.barboza@oss.qualcomm.com> Acked-by: Alistair Francis <alistair.francis@wdc.com> Message-ID: <20260512032926.1978818-5-daniel.barboza@oss.qualcomm.com> Signed-off-by: Alistair Francis <alistair.francis@wdc.com> --- target/riscv/tcg/tcg-cpu.c | 13 +++---------- 1 file changed, 3 insertions(+), 10 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_disable_priv_spec_isa_exts(RISCVCPU *cpu) } isa_ext_update_enabled(cpu, edata->ext_enable_offset, false); - - /* - * Do not show user warnings for named features that users - * can't enable/disable in the command line. See commit - * 68c9e54bea for more info. - */ - if (cpu_cfg_offset_is_named_feat(edata->ext_enable_offset)) { - continue; - } #ifndef CONFIG_USER_ONLY warn_report("disabling %s extension for hart 0x%" PRIx64 " because privilege spec version does not match", @@ -XXX,XX +XXX,XX @@ static void riscv_cpu_update_named_features(RISCVCPU *cpu) cpu->cfg.has_priv_1_13 = true; } + /* zic64b is 1.12 or later */ cpu->cfg.ext_zic64b = cpu->cfg.cbom_blocksize == 64 && cpu->cfg.cbop_blocksize == 64 && - cpu->cfg.cboz_blocksize == 64; + cpu->cfg.cboz_blocksize == 64 && + cpu->cfg.has_priv_1_12; cpu->cfg.ext_ssstateen = cpu->cfg.ext_smstateen; -- 2.53.0
From: Daniel Henrique Barboza <daniel.barboza@oss.qualcomm.com> We're using both isa_edata_arr[] and riscv_cpu_named_features[] to find an extension name based on a cfg offset. This is reminiscent of a past where isa_edata_arr[] didn't include entries for internal extensions. At this point we can use just isa_edata_arr[]. Signed-off-by: Daniel Henrique Barboza <daniel.barboza@oss.qualcomm.com> Acked-by: Alistair Francis <alistair.francis@wdc.com> Message-ID: <20260512032926.1978818-6-daniel.barboza@oss.qualcomm.com> Signed-off-by: Alistair Francis <alistair.francis@wdc.com> --- target/riscv/tcg/tcg-cpu.c | 7 ------- 1 file changed, 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 int cpu_cfg_ext_get_min_version(uint32_t ext_offset) static const char *cpu_cfg_ext_get_name(uint32_t ext_offset) { - const RISCVCPUMultiExtConfig *feat; const RISCVIsaExtData *edata; for (edata = isa_edata_arr; edata->name != NULL; edata++) { @@ -XXX,XX +XXX,XX @@ static const char *cpu_cfg_ext_get_name(uint32_t ext_offset) } } - for (feat = riscv_cpu_named_features; feat->name != NULL; feat++) { - if (feat->offset == ext_offset) { - return feat->name; - } - } - g_assert_not_reached(); } -- 2.53.0
From: Daniel Henrique Barboza <daniel.barboza@oss.qualcomm.com> Deprecate riscv_cpu_enable_named_feat() by creating implied rules for 'sha' and 'ssstateen'. 'zic64' is always true given that our default block size is set to 64. With this change we homogeneize extension handling when enabling profiles. Signed-off-by: Daniel Henrique Barboza <daniel.barboza@oss.qualcomm.com> Acked-by: Alistair Francis <alistair.francis@wdc.com> Message-ID: <20260512032926.1978818-7-daniel.barboza@oss.qualcomm.com> Signed-off-by: Alistair Francis <alistair.francis@wdc.com> --- target/riscv/cpu.c | 25 ++++++++++++++++++++++-- target/riscv/tcg/tcg-cpu.c | 40 -------------------------------------- 2 files changed, 23 insertions(+), 42 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 RISCVCPUImpliedExtsRule ZVKSG_IMPLIED = { }, }; +static RISCVCPUImpliedExtsRule SHA_IMPLIED = { + .ext = CPU_CFG_OFFSET(ext_sha), + .implied_misa_exts = RVH, + .implied_multi_exts = { + CPU_CFG_OFFSET(ext_smstateen), + CPU_CFG_OFFSET(ext_ssstateen), + + RISCV_IMPLIED_EXTS_RULE_END + }, +}; + static RISCVCPUImpliedExtsRule SSCFG_IMPLIED = { .ext = CPU_CFG_OFFSET(ext_ssccfg), .implied_multi_exts = { @@ -XXX,XX +XXX,XX @@ static RISCVCPUImpliedExtsRule SSCTR_IMPLIED = { }, }; +static RISCVCPUImpliedExtsRule SSSTATEEN_IMPLIED = { + .ext = CPU_CFG_OFFSET(ext_ssstateen), + .implied_multi_exts = { + CPU_CFG_OFFSET(ext_smstateen), + + RISCV_IMPLIED_EXTS_RULE_END + }, +}; + static RISCVCPUImpliedExtsRule ZVFBFA_IMPLIED = { .ext = CPU_CFG_OFFSET(ext_zvfbfa), .implied_multi_exts = { @@ -XXX,XX +XXX,XX @@ RISCVCPUImpliedExtsRule *riscv_multi_ext_implied_rules[] = { &ZVFBFA_IMPLIED, &ZVFBFMIN_IMPLIED, &ZVFBFWMA_IMPLIED, &ZVFH_IMPLIED, &ZVFHMIN_IMPLIED, &ZVKN_IMPLIED, &ZVKNC_IMPLIED, &ZVKNG_IMPLIED, &ZVKNHB_IMPLIED, - &ZVKS_IMPLIED, &ZVKSC_IMPLIED, &ZVKSG_IMPLIED, &SSCFG_IMPLIED, - &SUPM_IMPLIED, &SSPM_IMPLIED, &SMCTR_IMPLIED, &SSCTR_IMPLIED, + &ZVKS_IMPLIED, &ZVKSC_IMPLIED, &ZVKSG_IMPLIED, &SHA_IMPLIED, + &SSCFG_IMPLIED, &SUPM_IMPLIED, &SSPM_IMPLIED, &SMCTR_IMPLIED, + &SSCTR_IMPLIED, &SSSTATEEN_IMPLIED, NULL }; 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 char *cpu_cfg_ext_get_name(uint32_t ext_offset) g_assert_not_reached(); } -static bool cpu_cfg_offset_is_named_feat(uint32_t ext_offset) -{ - const RISCVCPUMultiExtConfig *feat; - - for (feat = riscv_cpu_named_features; feat->name != NULL; feat++) { - if (feat->offset == ext_offset) { - return true; - } - } - - return false; -} - -static void riscv_cpu_enable_named_feat(RISCVCPU *cpu, uint32_t feat_offset) -{ - /* - * All other named features are already enabled - * in riscv_tcg_cpu_instance_init(). - */ - switch (feat_offset) { - case CPU_CFG_OFFSET(ext_zic64b): - cpu->cfg.cbom_blocksize = 64; - cpu->cfg.cbop_blocksize = 64; - cpu->cfg.cboz_blocksize = 64; - break; - case CPU_CFG_OFFSET(ext_sha): - if (!cpu_misa_ext_is_user_set(RVH)) { - riscv_cpu_write_misa_bit(cpu, RVH, true); - } - /* fallthrough */ - case CPU_CFG_OFFSET(ext_ssstateen): - cpu->cfg.ext_smstateen = true; - break; - } -} - static void cpu_bump_multi_ext_priv_ver(CPURISCVState *env, uint32_t ext_offset) { @@ -XXX,XX +XXX,XX @@ static void riscv_cpu_set_profile(RISCVCPU *cpu, 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); } -- 2.53.0
From: Daniel Henrique Barboza <daniel.barboza@oss.qualcomm.com> This array has no uses left. Signed-off-by: Daniel Henrique Barboza <daniel.barboza@oss.qualcomm.com> Acked-by: Alistair Francis <alistair.francis@wdc.com> Message-ID: <20260512032926.1978818-8-daniel.barboza@oss.qualcomm.com> Signed-off-by: Alistair Francis <alistair.francis@wdc.com> --- target/riscv/cpu.h | 1 - target/riscv/cpu.c | 26 -------------------------- target/riscv/tcg/tcg-cpu.c | 4 ++-- 3 files changed, 2 insertions(+), 29 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 RISCVCPUMultiExtConfig { 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[]; 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_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. - * - * 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), - - { }, -}; - 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_disable_priv_spec_isa_exts(RISCVCPU *cpu) } } -static void riscv_cpu_update_named_features(RISCVCPU *cpu) +static void riscv_cpu_update_cfg(RISCVCPU *cpu) { if (cpu->env.priv_ver >= PRIV_VERSION_1_11_0) { cpu->cfg.has_priv_1_11 = true; @@ -XXX,XX +XXX,XX @@ void riscv_tcg_cpu_finalize_features(RISCVCPU *cpu, Error **errp) return; } - riscv_cpu_update_named_features(cpu); + riscv_cpu_update_cfg(cpu); riscv_cpu_validate_profiles(cpu); if (cpu->cfg.ext_smepmp && !cpu->cfg.pmp) { -- 2.53.0
From: Daniel Henrique Barboza <daniel.barboza@oss.qualcomm.com> The non-standard extensions, in this particular function the vendor extensions, are all riscv,isa names that starts with 'x'. In theory this is a bit slower than using riscv_cpu_vendor_exts (isa_edata_arr is longer) but riscv_cpu_update_misa_x() is executed only once during finalize(), i.e. not a hot path. We're accepting a tiny performance hit as as a tradeoff for the code simplication we'll have later by removing all riscv_cpu_* arrays. Signed-off-by: Daniel Henrique Barboza <daniel.barboza@oss.qualcomm.com> Acked-by: Alistair Francis <alistair.francis@wdc.com> Message-ID: <20260512032926.1978818-9-daniel.barboza@oss.qualcomm.com> Signed-off-by: Alistair Francis <alistair.francis@wdc.com> --- target/riscv/tcg/tcg-cpu.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 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_update_misa_c(RISCVCPU *cpu) static void riscv_cpu_update_misa_x(RISCVCPU *cpu) { CPURISCVState *env = &cpu->env; - const RISCVCPUMultiExtConfig *arr = riscv_cpu_vendor_exts; + const RISCVIsaExtData *edata; - for (int i = 0; arr[i].name != NULL; i++) { - if (isa_ext_is_enabled(cpu, arr[i].offset)) { + for (edata = isa_edata_arr; edata && edata->name; edata++) { + if (edata->name[0] == 'x' + && isa_ext_is_enabled(cpu, edata->ext_enable_offset)) { riscv_cpu_set_misa_ext(env, env->misa_ext | RVX); break; } -- 2.53.0
From: Daniel Henrique Barboza <daniel.barboza@oss.qualcomm.com> Use isa_edata_arr[] directly instead of going through 3 different arrays to populate the unavailable KVM properties. Signed-off-by: Daniel Henrique Barboza <daniel.barboza@oss.qualcomm.com> Acked-by: Alistair Francis <alistair.francis@wdc.com> Message-ID: <20260512032926.1978818-10-daniel.barboza@oss.qualcomm.com> Signed-off-by: Alistair Francis <alistair.francis@wdc.com> --- target/riscv/kvm/kvm-cpu.c | 25 ++++++++++--------------- 1 file changed, 10 insertions(+), 15 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 void riscv_cpu_add_kvm_unavail_prop(Object *obj, const char *prop_name) NULL, (void *)prop_name); } -static void riscv_cpu_add_kvm_unavail_prop_array(Object *obj, - const RISCVCPUMultiExtConfig *array) -{ - const RISCVCPUMultiExtConfig *prop; - - g_assert(array); - - for (prop = array; prop && prop->name; prop++) { - riscv_cpu_add_kvm_unavail_prop(obj, prop->name); - } -} - static void kvm_riscv_add_cpu_user_properties(Object *cpu_obj) { + const RISCVIsaExtData *edata; int i; riscv_add_satp_mode_properties(cpu_obj); @@ -XXX,XX +XXX,XX @@ static void kvm_riscv_add_cpu_user_properties(Object *cpu_obj) NULL, multi_cfg); } - 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); + /* + * Mark all isa_edata_arr properties that collides with + * a KVM property as unavailable. + */ + for (edata = isa_edata_arr; edata && edata->name; edata++) { + if (edata->prop_name) { + riscv_cpu_add_kvm_unavail_prop(cpu_obj, edata->prop_name); + } + } /* We don't have the needed KVM support for profiles */ for (i = 0; riscv_profiles[i] != NULL; i++) { -- 2.53.0
From: Daniel Henrique Barboza <daniel.barboza@oss.qualcomm.com> Use isa_edata_arr[] to enable all feasible extensions. Filter experimental and vendor extensions by checking if the riscv,isa or the prop name starts with 'x'. Signed-off-by: Daniel Henrique Barboza <daniel.barboza@oss.qualcomm.com> Acked-by: Alistair Francis <alistair.francis@wdc.com> Message-ID: <20260512032926.1978818-11-daniel.barboza@oss.qualcomm.com> Signed-off-by: Alistair Francis <alistair.francis@wdc.com> --- target/riscv/tcg/tcg-cpu.c | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 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_init_max_cpu_extensions(Object *obj) { RISCVCPU *cpu = RISCV_CPU(obj); CPURISCVState *env = &cpu->env; - const RISCVCPUMultiExtConfig *prop; + const RISCVIsaExtData *edata; /* Enable RVG and RVV that are disabled by default */ riscv_cpu_set_misa_ext(env, env->misa_ext | RVB | RVG | RVV); - for (prop = riscv_cpu_extensions; prop && prop->name; prop++) { - isa_ext_update_enabled(cpu, prop->offset, true); + for (edata = isa_edata_arr; edata && edata->name; edata++) { + if (edata->name[0] == 'x' + || (edata->prop_name && edata->prop_name[0] == 'x')) { + continue; + } + + isa_ext_update_enabled(cpu, edata->ext_enable_offset, true); } /* -- 2.53.0
From: Daniel Henrique Barboza <daniel.barboza@oss.qualcomm.com> The cpu_get_multi_ext_cfg/cpu_set_multi_ext_cfg callbacks are using a RISCVCPUMultiExtConfig pointer as opaque, but internally we're just using multi_ext_cfg->offset. Use multi_ext_cfg->offset as opaque instead. Signed-off-by: Daniel Henrique Barboza <daniel.barboza@oss.qualcomm.com> Acked-by: Alistair Francis <alistair.francis@wdc.com> Message-ID: <20260512032926.1978818-12-daniel.barboza@oss.qualcomm.com> Signed-off-by: Alistair Francis <alistair.francis@wdc.com> --- target/riscv/tcg/tcg-cpu.c | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 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_add_profiles(Object *cpu_obj) static void cpu_set_multi_ext_cfg(Object *obj, Visitor *v, const char *name, void *opaque, Error **errp) { - const RISCVCPUMultiExtConfig *multi_ext_cfg = opaque; RISCVCPU *cpu = RISCV_CPU(obj); + uint32_t cfg_offset = *(uint32_t *)opaque; bool vendor_cpu = riscv_cpu_is_vendor(obj); bool prev_val, value; @@ -XXX,XX +XXX,XX @@ static void cpu_set_multi_ext_cfg(Object *obj, Visitor *v, const char *name, return; } - cpu_cfg_ext_add_user_opt(multi_ext_cfg->offset, value); + cpu_cfg_ext_add_user_opt(cfg_offset, value); - prev_val = isa_ext_is_enabled(cpu, multi_ext_cfg->offset); + prev_val = isa_ext_is_enabled(cpu, cfg_offset); if (value == prev_val) { return; @@ -XXX,XX +XXX,XX @@ static void cpu_set_multi_ext_cfg(Object *obj, Visitor *v, const char *name, } if (value) { - cpu_bump_multi_ext_priv_ver(&cpu->env, multi_ext_cfg->offset); + cpu_bump_multi_ext_priv_ver(&cpu->env, cfg_offset); } - isa_ext_update_enabled(cpu, multi_ext_cfg->offset, value); + isa_ext_update_enabled(cpu, cfg_offset, value); } static void cpu_get_multi_ext_cfg(Object *obj, Visitor *v, const char *name, void *opaque, Error **errp) { - const RISCVCPUMultiExtConfig *multi_ext_cfg = opaque; - bool value = isa_ext_is_enabled(RISCV_CPU(obj), multi_ext_cfg->offset); + uint32_t cfg_offset = *(uint32_t *)opaque; + bool value = isa_ext_is_enabled(RISCV_CPU(obj), cfg_offset); visit_type_bool(v, name, &value, errp); } @@ -XXX,XX +XXX,XX @@ static void cpu_add_multi_ext_prop(Object *cpu_obj, object_property_add(cpu_obj, multi_cfg->name, "bool", cpu_get_multi_ext_cfg, cpu_set_multi_ext_cfg, - NULL, (void *)multi_cfg); + NULL, (void *)&multi_cfg->offset); if (!generic_cpu) { return; -- 2.53.0
From: Daniel Henrique Barboza <daniel.barboza@oss.qualcomm.com> Do not rely on riscv_cpu_* arrays to set rv32/rv64 CPU defaults - add them to the CPU definition like we do with all other CPUs (aside from 'max'). Signed-off-by: Daniel Henrique Barboza <daniel.barboza@oss.qualcomm.com> Acked-by: Alistair Francis <alistair.francis@wdc.com> Message-ID: <20260512032926.1978818-13-daniel.barboza@oss.qualcomm.com> Signed-off-by: Alistair Francis <alistair.francis@wdc.com> --- target/riscv/cpu.c | 40 ++++++++++++++++++++++++++++++++++++++ target/riscv/tcg/tcg-cpu.c | 14 ------------- 2 files changed, 40 insertions(+), 14 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 TypeInfo riscv_cpu_type_infos[] = { DEFINE_RISCV_CPU(TYPE_RISCV_CPU_BASE32, TYPE_RISCV_DYNAMIC_CPU, .cfg.max_satp_mode = VM_1_10_SV32, .misa_mxl_max = MXL_RV32, + + /* Default extensions as of QEMU 11.1. */ + .cfg.ext_zicbom = true, + .cfg.ext_zicbop = true, + .cfg.ext_zicboz = true, + .cfg.ext_zicntr = true, + .cfg.ext_zicsr = true, + .cfg.ext_zifencei = true, + .cfg.ext_zihintntl = true, + .cfg.ext_zihintpause = true, + .cfg.ext_zihpm = true, + .cfg.ext_zawrs = true, + .cfg.ext_zfa = true, + .cfg.ext_zba = true, + .cfg.ext_zbb = true, + .cfg.ext_zbc = true, + .cfg.ext_zbs = true, + .cfg.ext_sstc = true, + .cfg.ext_svadu = true, + .cfg.ext_svvptc = true, ), DEFINE_RISCV_CPU(TYPE_RISCV_CPU_IBEX, TYPE_RISCV_VENDOR_CPU, @@ -XXX,XX +XXX,XX @@ static const TypeInfo riscv_cpu_type_infos[] = { DEFINE_RISCV_CPU(TYPE_RISCV_CPU_BASE64, TYPE_RISCV_DYNAMIC_CPU, .cfg.max_satp_mode = VM_1_10_SV57, .misa_mxl_max = MXL_RV64, + + /* Default extensions as of QEMU 11.1. */ + .cfg.ext_zicbom = true, + .cfg.ext_zicbop = true, + .cfg.ext_zicboz = true, + .cfg.ext_zicntr = true, + .cfg.ext_zicsr = true, + .cfg.ext_zifencei = true, + .cfg.ext_zihintntl = true, + .cfg.ext_zihintpause = true, + .cfg.ext_zihpm = true, + .cfg.ext_zawrs = true, + .cfg.ext_zfa = true, + .cfg.ext_zba = true, + .cfg.ext_zbb = true, + .cfg.ext_zbc = true, + .cfg.ext_zbs = true, + .cfg.ext_sstc = true, + .cfg.ext_svadu = true, + .cfg.ext_svvptc = true, ), DEFINE_RISCV_CPU(TYPE_RISCV_CPU_SIFIVE_E51, TYPE_RISCV_CPU_SIFIVE_E, 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_get_multi_ext_cfg(Object *obj, Visitor *v, const char *name, static void cpu_add_multi_ext_prop(Object *cpu_obj, const RISCVCPUMultiExtConfig *multi_cfg) { - bool generic_cpu = riscv_cpu_is_generic(cpu_obj); - object_property_add(cpu_obj, multi_cfg->name, "bool", cpu_get_multi_ext_cfg, cpu_set_multi_ext_cfg, NULL, (void *)&multi_cfg->offset); - - if (!generic_cpu) { - return; - } - - /* - * Set def val directly instead of using - * object_property_set_bool() to save the set() - * callback hash for user inputs. - */ - isa_ext_update_enabled(RISCV_CPU(cpu_obj), multi_cfg->offset, - multi_cfg->enabled); } static void riscv_cpu_add_multiext_prop_array(Object *obj, -- 2.53.0
From: Daniel Henrique Barboza <daniel.barboza@oss.qualcomm.com> This change has been done twice now: one in riscv-qmp-cmds, another in the KVM. We're now ready to do it for TCG. Signed-off-by: Daniel Henrique Barboza <daniel.barboza@oss.qualcomm.com> Acked-by: Alistair Francis <alistair.francis@wdc.com> Message-ID: <20260512032926.1978818-14-daniel.barboza@oss.qualcomm.com> Signed-off-by: Alistair Francis <alistair.francis@wdc.com> --- target/riscv/tcg/tcg-cpu.c | 34 ++++++++++------------------------ 1 file changed, 10 insertions(+), 24 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_get_multi_ext_cfg(Object *obj, Visitor *v, const char *name, visit_type_bool(v, name, &value, errp); } -static void cpu_add_multi_ext_prop(Object *cpu_obj, - const RISCVCPUMultiExtConfig *multi_cfg) -{ - object_property_add(cpu_obj, multi_cfg->name, "bool", - cpu_get_multi_ext_cfg, - cpu_set_multi_ext_cfg, - NULL, (void *)&multi_cfg->offset); -} - -static void riscv_cpu_add_multiext_prop_array(Object *obj, - const RISCVCPUMultiExtConfig *array) -{ - const RISCVCPUMultiExtConfig *prop; - - g_assert(array); - - for (prop = array; prop && prop->name; prop++) { - cpu_add_multi_ext_prop(obj, prop); - } -} - /* * Add CPU properties with user-facing flags. * @@ -XXX,XX +XXX,XX @@ static void riscv_cpu_add_multiext_prop_array(Object *obj, */ static void riscv_cpu_add_user_properties(Object *obj) { + const RISCVIsaExtData *edata; + #ifndef CONFIG_USER_ONLY riscv_add_satp_mode_properties(obj); #endif riscv_cpu_add_misa_properties(obj); - riscv_cpu_add_multiext_prop_array(obj, riscv_cpu_extensions); - riscv_cpu_add_multiext_prop_array(obj, riscv_cpu_vendor_exts); - riscv_cpu_add_multiext_prop_array(obj, riscv_cpu_experimental_exts); + for (edata = isa_edata_arr; edata && edata->name; edata++) { + if (edata->prop_name) { + object_property_add(obj, edata->prop_name, "bool", + cpu_get_multi_ext_cfg, + cpu_set_multi_ext_cfg, + NULL, (void *)&edata->ext_enable_offset); + } + } riscv_cpu_add_profiles(obj); } -- 2.53.0
From: Daniel Henrique Barboza <daniel.barboza@oss.qualcomm.com> There is no more uses left for these arrays. isa_edata_arr[] is doing everything we need, making our lives a little easier when adding new extensions. Signed-off-by: Daniel Henrique Barboza <daniel.barboza@oss.qualcomm.com> Acked-by: Alistair Francis <alistair.francis@wdc.com> Message-ID: <20260512032926.1978818-15-daniel.barboza@oss.qualcomm.com> Signed-off-by: Alistair Francis <alistair.francis@wdc.com> --- target/riscv/cpu.h | 10 --- target/riscv/cpu.c | 159 --------------------------------------------- 2 files changed, 169 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 isa_ext_is_enabled(RISCVCPU *cpu, uint32_t ext_offset); void riscv_cpu_set_misa_ext(CPURISCVState *env, uint32_t ext); bool riscv_cpu_is_vendor(Object *cpu_obj); -typedef struct RISCVCPUMultiExtConfig { - const char *name; - uint32_t offset; - bool enabled; -} RISCVCPUMultiExtConfig; - -extern const RISCVCPUMultiExtConfig riscv_cpu_extensions[]; -extern const RISCVCPUMultiExtConfig riscv_cpu_vendor_exts[]; -extern const RISCVCPUMultiExtConfig riscv_cpu_experimental_exts[]; - typedef struct isa_ext_data { const char *name; const char *prop_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 char *riscv_get_misa_ext_description(uint32_t bit) return val; } -#define MULTI_EXT_CFG_BOOL(_name, _prop, _defval) \ - {.name = _name, .offset = CPU_CFG_OFFSET(_prop), \ - .enabled = _defval} - -const RISCVCPUMultiExtConfig riscv_cpu_extensions[] = { - /* Defaults for standard extensions */ - MULTI_EXT_CFG_BOOL("sscofpmf", ext_sscofpmf, false), - MULTI_EXT_CFG_BOOL("smcntrpmf", ext_smcntrpmf, false), - MULTI_EXT_CFG_BOOL("smcsrind", ext_smcsrind, false), - MULTI_EXT_CFG_BOOL("smcdeleg", ext_smcdeleg, false), - MULTI_EXT_CFG_BOOL("sscsrind", ext_sscsrind, false), - MULTI_EXT_CFG_BOOL("ssccfg", ext_ssccfg, false), - MULTI_EXT_CFG_BOOL("smctr", ext_smctr, false), - MULTI_EXT_CFG_BOOL("ssctr", ext_ssctr, false), - MULTI_EXT_CFG_BOOL("zifencei", ext_zifencei, true), - MULTI_EXT_CFG_BOOL("zicfilp", ext_zicfilp, false), - MULTI_EXT_CFG_BOOL("zicfiss", ext_zicfiss, false), - 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("zimop", ext_zimop, false), - MULTI_EXT_CFG_BOOL("zcmop", ext_zcmop, false), - MULTI_EXT_CFG_BOOL("zacas", ext_zacas, false), - MULTI_EXT_CFG_BOOL("zama16b", ext_zama16b, false), - MULTI_EXT_CFG_BOOL("zabha", ext_zabha, false), - MULTI_EXT_CFG_BOOL("zaamo", ext_zaamo, false), - MULTI_EXT_CFG_BOOL("zalasr", ext_zalasr, false), - MULTI_EXT_CFG_BOOL("zalrsc", ext_zalrsc, false), - MULTI_EXT_CFG_BOOL("zawrs", ext_zawrs, true), - MULTI_EXT_CFG_BOOL("zfa", ext_zfa, true), - MULTI_EXT_CFG_BOOL("zfbfmin", ext_zfbfmin, false), - 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("zve32x", ext_zve32x, false), - MULTI_EXT_CFG_BOOL("zve64f", ext_zve64f, false), - MULTI_EXT_CFG_BOOL("zve64d", ext_zve64d, false), - MULTI_EXT_CFG_BOOL("zve64x", ext_zve64x, false), - MULTI_EXT_CFG_BOOL("zvfbfa", ext_zvfbfa, false), - MULTI_EXT_CFG_BOOL("zvfbfmin", ext_zvfbfmin, false), - MULTI_EXT_CFG_BOOL("zvfbfwma", ext_zvfbfwma, false), - MULTI_EXT_CFG_BOOL("zvfh", ext_zvfh, false), - MULTI_EXT_CFG_BOOL("zvfhmin", ext_zvfhmin, false), - MULTI_EXT_CFG_BOOL("sstc", ext_sstc, true), - MULTI_EXT_CFG_BOOL("ssnpm", ext_ssnpm, false), - MULTI_EXT_CFG_BOOL("sspm", ext_sspm, false), - MULTI_EXT_CFG_BOOL("supm", ext_supm, false), - - MULTI_EXT_CFG_BOOL("smaia", ext_smaia, false), - MULTI_EXT_CFG_BOOL("smdbltrp", ext_smdbltrp, false), - MULTI_EXT_CFG_BOOL("smepmp", ext_smepmp, false), - MULTI_EXT_CFG_BOOL("smpmpmt", ext_smpmpmt, false), - MULTI_EXT_CFG_BOOL("smrnmi", ext_smrnmi, false), - MULTI_EXT_CFG_BOOL("smmpm", ext_smmpm, false), - MULTI_EXT_CFG_BOOL("smnpm", ext_smnpm, false), - MULTI_EXT_CFG_BOOL("smstateen", ext_smstateen, false), - MULTI_EXT_CFG_BOOL("ssaia", ext_ssaia, false), - MULTI_EXT_CFG_BOOL("ssdbltrp", ext_ssdbltrp, false), - MULTI_EXT_CFG_BOOL("svade", ext_svade, false), - MULTI_EXT_CFG_BOOL("svadu", ext_svadu, true), - 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), - MULTI_EXT_CFG_BOOL("zihpm", ext_zihpm, true), - MULTI_EXT_CFG_BOOL("zilsd", ext_zilsd, false), - - MULTI_EXT_CFG_BOOL("zba", ext_zba, true), - MULTI_EXT_CFG_BOOL("zbb", ext_zbb, true), - MULTI_EXT_CFG_BOOL("zbc", ext_zbc, true), - MULTI_EXT_CFG_BOOL("zbkb", ext_zbkb, false), - MULTI_EXT_CFG_BOOL("zbkc", ext_zbkc, false), - MULTI_EXT_CFG_BOOL("zbkx", ext_zbkx, false), - MULTI_EXT_CFG_BOOL("zbs", ext_zbs, true), - MULTI_EXT_CFG_BOOL("zk", ext_zk, false), - MULTI_EXT_CFG_BOOL("zkn", ext_zkn, false), - MULTI_EXT_CFG_BOOL("zknd", ext_zknd, false), - MULTI_EXT_CFG_BOOL("zkne", ext_zkne, false), - MULTI_EXT_CFG_BOOL("zknh", ext_zknh, false), - MULTI_EXT_CFG_BOOL("zkr", ext_zkr, false), - MULTI_EXT_CFG_BOOL("zks", ext_zks, false), - MULTI_EXT_CFG_BOOL("zksed", ext_zksed, false), - MULTI_EXT_CFG_BOOL("zksh", ext_zksh, false), - MULTI_EXT_CFG_BOOL("zkt", ext_zkt, false), - MULTI_EXT_CFG_BOOL("ztso", ext_ztso, false), - - MULTI_EXT_CFG_BOOL("zdinx", ext_zdinx, false), - MULTI_EXT_CFG_BOOL("zfinx", ext_zfinx, false), - MULTI_EXT_CFG_BOOL("zhinx", ext_zhinx, false), - MULTI_EXT_CFG_BOOL("zhinxmin", ext_zhinxmin, false), - - MULTI_EXT_CFG_BOOL("zicbom", ext_zicbom, true), - MULTI_EXT_CFG_BOOL("zicbop", ext_zicbop, true), - MULTI_EXT_CFG_BOOL("zicboz", ext_zicboz, true), - - MULTI_EXT_CFG_BOOL("zmmul", ext_zmmul, false), - - MULTI_EXT_CFG_BOOL("zca", ext_zca, false), - MULTI_EXT_CFG_BOOL("zcb", ext_zcb, false), - MULTI_EXT_CFG_BOOL("zcd", ext_zcd, false), - MULTI_EXT_CFG_BOOL("zce", ext_zce, false), - MULTI_EXT_CFG_BOOL("zcf", ext_zcf, false), - MULTI_EXT_CFG_BOOL("zcmp", ext_zcmp, false), - MULTI_EXT_CFG_BOOL("zcmt", ext_zcmt, false), - MULTI_EXT_CFG_BOOL("zicond", ext_zicond, false), - MULTI_EXT_CFG_BOOL("zclsd", ext_zclsd, false), - - /* Vector cryptography extensions */ - MULTI_EXT_CFG_BOOL("zvbb", ext_zvbb, false), - MULTI_EXT_CFG_BOOL("zvbc", ext_zvbc, false), - MULTI_EXT_CFG_BOOL("zvkb", ext_zvkb, false), - MULTI_EXT_CFG_BOOL("zvkg", ext_zvkg, false), - MULTI_EXT_CFG_BOOL("zvkned", ext_zvkned, false), - MULTI_EXT_CFG_BOOL("zvknha", ext_zvknha, false), - MULTI_EXT_CFG_BOOL("zvknhb", ext_zvknhb, false), - MULTI_EXT_CFG_BOOL("zvksed", ext_zvksed, false), - MULTI_EXT_CFG_BOOL("zvksh", ext_zvksh, false), - MULTI_EXT_CFG_BOOL("zvkt", ext_zvkt, false), - MULTI_EXT_CFG_BOOL("zvkn", ext_zvkn, false), - MULTI_EXT_CFG_BOOL("zvknc", ext_zvknc, false), - MULTI_EXT_CFG_BOOL("zvkng", ext_zvkng, false), - MULTI_EXT_CFG_BOOL("zvks", ext_zvks, false), - MULTI_EXT_CFG_BOOL("zvksc", ext_zvksc, false), - MULTI_EXT_CFG_BOOL("zvksg", ext_zvksg, false), - - { }, -}; - -const RISCVCPUMultiExtConfig riscv_cpu_vendor_exts[] = { - MULTI_EXT_CFG_BOOL("xtheadba", ext_xtheadba, false), - MULTI_EXT_CFG_BOOL("xtheadbb", ext_xtheadbb, false), - MULTI_EXT_CFG_BOOL("xtheadbs", ext_xtheadbs, false), - MULTI_EXT_CFG_BOOL("xtheadcmo", ext_xtheadcmo, false), - MULTI_EXT_CFG_BOOL("xtheadcondmov", ext_xtheadcondmov, false), - MULTI_EXT_CFG_BOOL("xtheadfmemidx", ext_xtheadfmemidx, false), - MULTI_EXT_CFG_BOOL("xtheadfmv", ext_xtheadfmv, false), - MULTI_EXT_CFG_BOOL("xtheadmac", ext_xtheadmac, false), - MULTI_EXT_CFG_BOOL("xtheadmemidx", ext_xtheadmemidx, false), - MULTI_EXT_CFG_BOOL("xtheadmempair", ext_xtheadmempair, false), - MULTI_EXT_CFG_BOOL("xtheadsync", ext_xtheadsync, false), - MULTI_EXT_CFG_BOOL("xventanacondops", ext_XVentanaCondOps, false), - MULTI_EXT_CFG_BOOL("xmipscbop", ext_xmipscbop, false), - MULTI_EXT_CFG_BOOL("xmipscmov", ext_xmipscmov, false), - MULTI_EXT_CFG_BOOL("xmipslsp", ext_xmipslsp, false), - MULTI_EXT_CFG_BOOL("xlrbr", ext_xlrbr, false), - - { }, -}; - -/* These are experimental so mark with 'x-' */ -const RISCVCPUMultiExtConfig riscv_cpu_experimental_exts[] = { - MULTI_EXT_CFG_BOOL("x-svukte", ext_svukte, false), - - { }, -}; - static void cpu_set_prop_err(RISCVCPU *cpu, const char *propname, Error **errp) { -- 2.53.0
From: Fangyu Yu <fangyu.yu@linux.alibaba.com> Fix IOCOUNTINH.CY toggle detection by comparing normalized CY bit rather than XORing whole register with boolean. Fixes: 2cf2a6c027ba ("hw/riscv/riscv-iommu: add IOCOUNTINH mmio writes") Signed-off-by: Fangyu Yu <fangyu.yu@linux.alibaba.com> Reviewed-by: Daniel Henrique Barboza <daniel.barboza@oss.qualcomm.com> Reviewed-by: Nutty Liu <nutty.liu@hotmail.com> Message-ID: <20260509074941.99295-1-fangyu.yu@linux.alibaba.com> Signed-off-by: Alistair Francis <alistair.francis@wdc.com> --- hw/riscv/riscv-iommu-hpm.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/hw/riscv/riscv-iommu-hpm.c b/hw/riscv/riscv-iommu-hpm.c index XXXXXXX..XXXXXXX 100644 --- a/hw/riscv/riscv-iommu-hpm.c +++ b/hw/riscv/riscv-iommu-hpm.c @@ -XXX,XX +XXX,XX @@ void riscv_iommu_process_iocntinh_cy(RISCVIOMMUState *s, bool prev_cy_inh) s, RISCV_IOMMU_REG_IOCOUNTINH); /* We only need to process CY bit toggle. */ - if (!(inhibit ^ prev_cy_inh)) { + bool cy_inh = !!(inhibit & RISCV_IOMMU_IOCOUNTINH_CY); + if (cy_inh == prev_cy_inh) { return; } -- 2.53.0
From: Daniel Henrique Barboza <daniel.barboza@oss.qualcomm.com> The priv spec defines, for RV64, that the upper 10 bits of pmpaddr0-pmpaddr63 are WARL and are supposed to be cleared. After this patch, using the bug reproducer in [1], writing ffffffffffffffff in pmpaddr0 and reading it back now results in 003fffffffffffff. Here's the 'diff -cp' dump before and after this change: *************** IN: *** 5272,5278 **** pmpcfg10 0000000000000000 pmpcfg12 0000000000000000 pmpcfg14 0000000000000000 ! pmpaddr0 ffffffffffffffff pmpaddr1 0000000000000000 pmpaddr2 0000000000000000 pmpaddr3 0000000000000000 Reviewed-by: Alistair Francis <alistair.francis@wdc.com> Message-ID: <20260514123342.2139464-1-daniel.barboza@oss.qualcomm.com> Signed-off-by: Alistair Francis <alistair.francis@wdc.com> --- target/riscv/csr.c | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) 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_pmpaddr(CPURISCVState *env, int csrno, target_ulong *val) { *val = pmpaddr_csr_read(env, csrno - CSR_PMPADDR0); + + /* + * For RV64, bits 54-63 of the address registers + * PMPAADDR(0-63) is a WARL zero field (priv spec, + * section "Physical Memory Protection CSRs"). + * + * We'll have to add an annoying TARGET_RISCV64 gate + * here to avoid complaints about masking bits 0-53 + * of a potential 32 bit target_ulong '*var'. + */ +#ifdef TARGET_RISCV64 + if (env->misa_mxl == MXL_RV64 + && csrno >= CSR_PMPADDR0 && csrno <= CSR_PMPADDR63) { + target_ulong read_mask = MAKE_64BIT_MASK(0, 54); + *val &= read_mask; + } +#endif return RISCV_EXCP_NONE; } -- 2.53.0
From: Zishun Yi <vulab@iscas.ac.cn> In build_rimt(), the calculation of `num_ids` for the ID mapping array incorrectly uses the same formula (`0xffff - s->pci_iommu_bdf`) for both System IOMMU and PCI IOMMU topologies. For a System IOMMU, `s->pci_iommu_bdf` is 0. This results in a `num_ids` value of 0xffff. Since the source ID base starts at 0, the mapping only covers Requester IDs from 0 to 0xfffe. The final valid PCI Requester ID (0xffff) is erroneously omitted from the RIMT table. Fix this by decoupling the `num_ids` calculation. For System IOMMUs, explicitly set `num_ids` to 0x10000 to cover the entire PCI Requester ID space. This issue was discovered and reported by SpecHunter, an AI-driven architecture specification analysis tool. Link: https://github.com/yizishun/rv-isa-sec/blob/c78dacf66c8acd677b3538c837fde310bb71a97b/output/riscv-server-platform/pr-102/qemu.txt#L32 Signed-off-by: Zishun Yi <vulab@iscas.ac.cn> Acked-by: Alistair Francis <alistair.francis@wdc.com> Message-ID: <20260512062310.348208-1-vulab@iscas.ac.cn> Signed-off-by: Alistair Francis <alistair.francis@wdc.com> --- hw/riscv/virt-acpi-build.c | 3 ++- 1 file changed, 2 insertions(+), 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_rimt(GArray *table_data, BIOSLinker *linker, range = &g_array_index(iommu_idmaps, AcpiRimtIdMapping, i); if (virt_is_iommu_sys_enabled(s)) { range->source_id_base = 0; + range->num_ids = 0x10000; } else { range->source_id_base = s->pci_iommu_bdf + 1; + range->num_ids = 0xffff - s->pci_iommu_bdf; } - range->num_ids = 0xffff - s->pci_iommu_bdf; build_rimt_id_mapping(table_data, range->source_id_base, range->num_ids, iommu_offset); } -- 2.53.0
From: Portia Stephens <portias@oss.tenstorrent.com> The counter value was not being bitshifted for a hpmcounterh read resulting in hpmcounterh returning the bottom 32-bits. Fixes: cfc96df65e01 ("target/riscv: Remove upper_half from riscv_pmu_ctr_get_fixed_counters_val") Resolves: https://gitlab.com/qemu-project/qemu/-/work_items/3498 Cc: qemu-stable@nongnu.org Signed-off-by: Portia Stephens <portias@oss.tenstorrent.com> Reviewed-by: Alistair Francis <alistair.francis@wdc.com> Message-ID: <20260519043352.3685866-1-stephensportia@gmail.com> Signed-off-by: Alistair Francis <alistair.francis@wdc.com> --- target/riscv/csr.c | 5 +++-- 1 file changed, 3 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 @@ RISCVException riscv_pmu_read_ctr(CPURISCVState *env, target_ulong *val, */ if (riscv_pmu_ctr_monitor_cycles(env, ctr_idx) || riscv_pmu_ctr_monitor_instructions(env, ctr_idx)) { - *val = riscv_pmu_ctr_get_fixed_counters_val(env, ctr_idx) - - ctr_prev + ctr_val; + uint64_t cntr = riscv_pmu_ctr_get_fixed_counters_val(env, ctr_idx) - + ctr_prev + ctr_val; + *val = extract64(cntr, start, length); } else { *val = ctr_val; } -- 2.53.0
From: Jim Shu <jim.shu@sifive.com> According to the AIA spec ch4.7 ("Precise effects on interrupt-pending bits"), pending bit of APLIC should be set/cleared whenever the rectified input value is high/low in the both level-trigger mode and direct delivery mode. Currently, QEMU APLIC only clears the pending bit when interrupt is claimed in APLIC, but not clears it when the rectified input value is low. (e.g. IRQ source signal is low in the LEVEL_HIGH/Level1 mode). The software may receive an additional IRQ if the peripheral triggers one after the software clears the APLIC IRQ but before it clears the peripheral's IRQ. Thus, we also clear the pending bit via the rectified input value in the level-trigger mode. This change doesn't affect MSI delivery mode. Calling riscv_aplic_msi_irq_update() when IRQ pending is low will do nothing. Signed-off-by: Jim Shu <jim.shu@sifive.com> Reviewed-by: Chao Liu <chao.liu.zevorn@gmail.com> Reviewed-by: Daniel Henrique Barboza <daniel.barboza@oss.qualcomm.com> Message-ID: <20260428160103.3551125-2-jim.shu@sifive.com> Signed-off-by: Alistair Francis <alistair.francis@wdc.com> --- hw/intc/riscv_aplic.c | 8 ++++---- 1 file changed, 4 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 void riscv_aplic_request(void *opaque, int irq, int level) } break; case APLIC_SOURCECFG_SM_LEVEL_HIGH: - if ((level > 0) && !(state & APLIC_ISTATE_PENDING)) { - riscv_aplic_set_pending_raw(aplic, irq, true); + if ((level > 0) != !!(state & APLIC_ISTATE_PENDING)) { + riscv_aplic_set_pending_raw(aplic, irq, level > 0); update = true; } break; case APLIC_SOURCECFG_SM_LEVEL_LOW: - if ((level <= 0) && !(state & APLIC_ISTATE_PENDING)) { - riscv_aplic_set_pending_raw(aplic, irq, true); + if ((level <= 0) != !!(state & APLIC_ISTATE_PENDING)) { + riscv_aplic_set_pending_raw(aplic, irq, level <= 0); update = true; } break; -- 2.53.0
From: Jim Shu <jim.shu@sifive.com> Clearing APLIC registers and qemu_irq in the reset function Signed-off-by: Jim Shu <jim.shu@sifive.com> Signed-off-by: Fea.Wang <fea.wang@sifive.com> Reviewed-by: Daniel Henrique Barboza <daniel.barboza@oss.qualcomm.com> Message-ID: <20260428160103.3551125-3-jim.shu@sifive.com> Signed-off-by: Alistair Francis <alistair.francis@wdc.com> --- hw/intc/riscv_aplic.c | 45 ++++++++++++++++++++++++++++++++++++++----- 1 file changed, 40 insertions(+), 5 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 MemoryRegionOps riscv_aplic_ops = { } }; +static void riscv_aplic_reset_enter(Object *obj, ResetType type) +{ + RISCVAPLICState *aplic = RISCV_APLIC(obj); + int i; + + aplic->domaincfg = 0; + memset(aplic->sourcecfg, 0, sizeof(uint32_t) * aplic->num_irqs); + memset(aplic->target, 0, sizeof(uint32_t) * aplic->num_irqs); + if (!aplic->msimode) { + for (i = 0; i < aplic->num_irqs; i++) { + aplic->target[i] = 1; + } + } + + for (i = 0; i < aplic->num_irqs ; i++) { + riscv_aplic_set_enabled_raw(aplic, i, false); + } + + /* Need to unlock [ms]msicfgaddrh.L */ + aplic->mmsicfgaddr = 0; + aplic->mmsicfgaddrH = 0; + aplic->smsicfgaddr = 0; + aplic->smsicfgaddrH = 0; + + if (!aplic->msimode) { + /* Reset IDC registers only in non-MSI mode */ + for (i = 0; i < aplic->num_harts; i++) { + aplic->idelivery[i] = 0; + aplic->iforce[i] = 0; + aplic->ithreshold[i] = 0; + } + + for (i = 0; i < aplic->num_harts; i++) { + qemu_irq_lower(aplic->external_irqs[i]); + } + } +} + static void riscv_aplic_realize(DeviceState *dev, Error **errp) { uint32_t i; @@ -XXX,XX +XXX,XX @@ static void riscv_aplic_realize(DeviceState *dev, Error **errp) aplic->sourcecfg = g_new0(uint32_t, aplic->num_irqs); aplic->state = g_new0(uint32_t, aplic->num_irqs); aplic->target = g_new0(uint32_t, aplic->num_irqs); - if (!aplic->msimode) { - for (i = 0; i < aplic->num_irqs; i++) { - aplic->target[i] = 1; - } - } aplic->idelivery = g_new0(uint32_t, aplic->num_harts); aplic->iforce = g_new0(uint32_t, aplic->num_harts); aplic->ithreshold = g_new0(uint32_t, aplic->num_harts); @@ -XXX,XX +XXX,XX @@ static const VMStateDescription vmstate_riscv_aplic = { static void riscv_aplic_class_init(ObjectClass *klass, const void *data) { DeviceClass *dc = DEVICE_CLASS(klass); + ResettableClass *rc = RESETTABLE_CLASS(klass); device_class_set_props(dc, riscv_aplic_properties); dc->realize = riscv_aplic_realize; + rc->phases.enter = riscv_aplic_reset_enter; dc->vmsd = &vmstate_riscv_aplic; } -- 2.53.0
From: Jim Shu <jim.shu@sifive.com> Clearing IMSIC registers and qemu_irq in the reset function Signed-off-by: Jim Shu <jim.shu@sifive.com> Reviewed-by: Daniel Henrique Barboza <daniel.barboza@oss.qualcomm.com> Message-ID: <20260428160103.3551125-4-jim.shu@sifive.com> Signed-off-by: Alistair Francis <alistair.francis@wdc.com> --- hw/intc/riscv_imsic.c | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) 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 MemoryRegionOps riscv_imsic_ops = { } }; +static void riscv_imsic_reset_enter(Object *obj, ResetType type) +{ + RISCVIMSICState *imsic = RISCV_IMSIC(obj); + int i; + + memset(imsic->eidelivery, 0, sizeof(uint32_t) * imsic->num_pages); + memset(imsic->eithreshold, 0, sizeof(uint32_t) * imsic->num_pages); + + for (i = 0; i < imsic->num_eistate; i++) { + imsic->eistate[i] &= ~IMSIC_EISTATE_ENABLED; + } + + for (i = 0; i < imsic->num_pages; i++) { + qemu_irq_lower(imsic->external_irqs[i]); + } +} + static void riscv_imsic_realize(DeviceState *dev, Error **errp) { RISCVIMSICState *imsic = RISCV_IMSIC(dev); @@ -XXX,XX +XXX,XX @@ static const VMStateDescription vmstate_riscv_imsic = { static void riscv_imsic_class_init(ObjectClass *klass, const void *data) { DeviceClass *dc = DEVICE_CLASS(klass); + ResettableClass *rc = RESETTABLE_CLASS(klass); device_class_set_props(dc, riscv_imsic_properties); dc->realize = riscv_imsic_realize; + rc->phases.enter = riscv_imsic_reset_enter; dc->vmsd = &vmstate_riscv_imsic; } -- 2.53.0
From: Jim Shu <jim.shu@sifive.com> Add the trace events for APLIC read/write functions. Signed-off-by: Jim Shu <jim.shu@sifive.com> Reviewed-by: Daniel Henrique Barboza <daniel.barboza@oss.qualcomm.com> Message-ID: <20260428160103.3551125-5-jim.shu@sifive.com> [ Changes by AF: - Init val to zero to avoid uninitialised build errors ] Signed-off-by: Alistair Francis <alistair.francis@wdc.com> --- hw/intc/riscv_aplic.c | 63 ++++++++++++++++++++++++++----------------- hw/intc/trace-events | 4 +++ 2 files changed, 42 insertions(+), 25 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 @@ #include "system/tcg.h" #include "kvm/kvm_riscv.h" #include "migration/vmstate.h" +#include "trace.h" #define APLIC_MAX_IDC (1UL << 14) #define APLIC_MAX_SOURCE 1024 @@ -XXX,XX +XXX,XX @@ static void riscv_aplic_request(void *opaque, int irq, int level) static uint64_t riscv_aplic_read(void *opaque, hwaddr addr, unsigned size) { uint32_t irq, word, idc; + uint64_t val = 0; RISCVAPLICState *aplic = opaque; /* Reads must be 4 byte words */ @@ -XXX,XX +XXX,XX @@ static uint64_t riscv_aplic_read(void *opaque, hwaddr addr, unsigned size) } if (addr == APLIC_DOMAINCFG) { - return APLIC_DOMAINCFG_RDONLY | aplic->domaincfg | - (aplic->msimode ? APLIC_DOMAINCFG_DM : 0); + val = APLIC_DOMAINCFG_RDONLY | aplic->domaincfg | + (aplic->msimode ? APLIC_DOMAINCFG_DM : 0); } else if ((APLIC_SOURCECFG_BASE <= addr) && (addr < (APLIC_SOURCECFG_BASE + (aplic->num_irqs - 1) * 4))) { irq = ((addr - APLIC_SOURCECFG_BASE) >> 2) + 1; - return aplic->sourcecfg[irq]; + val = aplic->sourcecfg[irq]; } else if (aplic->mmode && aplic->msimode && (addr == APLIC_MMSICFGADDR)) { - return aplic->mmsicfgaddr; + val = aplic->mmsicfgaddr; } else if (aplic->mmode && aplic->msimode && (addr == APLIC_MMSICFGADDRH)) { - return aplic->mmsicfgaddrH; + val = aplic->mmsicfgaddrH; } else if (aplic->mmode && aplic->msimode && (addr == APLIC_SMSICFGADDR)) { /* @@ -XXX,XX +XXX,XX @@ static uint64_t riscv_aplic_read(void *opaque, hwaddr addr, unsigned size) * only zero in at least one of the supervisor-level child * domains). */ - return (aplic->num_children) ? aplic->smsicfgaddr : 0; + val = (aplic->num_children) ? aplic->smsicfgaddr : 0; } else if (aplic->mmode && aplic->msimode && (addr == APLIC_SMSICFGADDRH)) { - return (aplic->num_children) ? aplic->smsicfgaddrH : 0; + val = (aplic->num_children) ? aplic->smsicfgaddrH : 0; } else if ((APLIC_SETIP_BASE <= addr) && (addr < (APLIC_SETIP_BASE + aplic->bitfield_words * 4))) { word = (addr - APLIC_SETIP_BASE) >> 2; - return riscv_aplic_read_pending_word(aplic, word); + val = riscv_aplic_read_pending_word(aplic, word); } else if (addr == APLIC_SETIPNUM) { - return 0; + val = 0; } else if ((APLIC_CLRIP_BASE <= addr) && (addr < (APLIC_CLRIP_BASE + aplic->bitfield_words * 4))) { word = (addr - APLIC_CLRIP_BASE) >> 2; - return riscv_aplic_read_input_word(aplic, word); + val = riscv_aplic_read_input_word(aplic, word); } else if (addr == APLIC_CLRIPNUM) { - return 0; + val = 0; } else if ((APLIC_SETIE_BASE <= addr) && (addr < (APLIC_SETIE_BASE + aplic->bitfield_words * 4))) { word = (addr - APLIC_SETIE_BASE) >> 2; - return riscv_aplic_read_enabled_word(aplic, word); + val = riscv_aplic_read_enabled_word(aplic, word); } else if (addr == APLIC_SETIENUM) { - return 0; + val = 0; } else if ((APLIC_CLRIE_BASE <= addr) && (addr < (APLIC_CLRIE_BASE + aplic->bitfield_words * 4))) { - return 0; + val = 0; } else if (addr == APLIC_CLRIENUM) { - return 0; + val = 0; } else if (addr == APLIC_SETIPNUM_LE) { - return 0; + val = 0; } else if (addr == APLIC_SETIPNUM_BE) { - return 0; + val = 0; } else if (addr == APLIC_GENMSI) { - return (aplic->msimode) ? aplic->genmsi : 0; + val = (aplic->msimode) ? aplic->genmsi : 0; } else if ((APLIC_TARGET_BASE <= addr) && (addr < (APLIC_TARGET_BASE + (aplic->num_irqs - 1) * 4))) { irq = ((addr - APLIC_TARGET_BASE) >> 2) + 1; if (!riscv_aplic_source_active(aplic, irq)) { - return 0; + val = 0; + } else { + val = aplic->target[irq]; } - return aplic->target[irq]; } else if (!aplic->msimode && (APLIC_IDC_BASE <= addr) && (addr < (APLIC_IDC_BASE + aplic->num_harts * APLIC_IDC_SIZE))) { idc = (addr - APLIC_IDC_BASE) / APLIC_IDC_SIZE; switch (addr - (APLIC_IDC_BASE + idc * APLIC_IDC_SIZE)) { case APLIC_IDC_IDELIVERY: - return aplic->idelivery[idc]; + val = aplic->idelivery[idc]; + break; case APLIC_IDC_IFORCE: - return aplic->iforce[idc]; + val = aplic->iforce[idc]; + break; case APLIC_IDC_ITHRESHOLD: - return aplic->ithreshold[idc]; + val = aplic->ithreshold[idc]; + break; case APLIC_IDC_TOPI: - return riscv_aplic_idc_topi(aplic, idc); + val = riscv_aplic_idc_topi(aplic, idc); + break; case APLIC_IDC_CLAIMI: - return riscv_aplic_idc_claimi(aplic, idc); + val = riscv_aplic_idc_claimi(aplic, idc); + break; default: goto err; }; } + trace_riscv_aplic_read(addr, size, val); + return val; + err: qemu_log_mask(LOG_GUEST_ERROR, "%s: Invalid register read 0x%" HWADDR_PRIx "\n", @@ -XXX,XX +XXX,XX @@ static void riscv_aplic_write(void *opaque, hwaddr addr, uint64_t value, goto err; } + trace_riscv_aplic_write(addr, size, value); + if (addr == APLIC_DOMAINCFG) { /* Only IE bit writable at the moment */ value &= APLIC_DOMAINCFG_IE; diff --git a/hw/intc/trace-events b/hw/intc/trace-events index XXXXXXX..XXXXXXX 100644 --- a/hw/intc/trace-events +++ b/hw/intc/trace-events @@ -XXX,XX +XXX,XX @@ loongarch_msi_set_irq(int irq_num) "set msi irq %d" loongarch_extioi_setirq(int irq, int level) "set extirq irq %d level %d" loongarch_extioi_readw(uint64_t addr, uint64_t val) "addr: 0x%"PRIx64 "val: 0x%" PRIx64 loongarch_extioi_writew(uint64_t addr, uint64_t val) "addr: 0x%"PRIx64 "val: 0x%" PRIx64 + +# riscv_aplic.c +riscv_aplic_read(uint64_t offset, unsigned size, uint64_t value) "offset: 0x%" PRIx64 ", size: %u, value: 0x%" PRIx64 +riscv_aplic_write(uint64_t offset, unsigned size, uint64_t value) "offset: 0x%" PRIx64 ", size: %u, value: 0x%" PRIx64 -- 2.53.0
From: Jay Chang <jay.chang@sifive.com> When software clears CMD_ILL or CQMF error bits by writing 1 to CQCSR, the IOMMU should re-check the command queue and continue processing pending commands if head != tail. Per RISC-V IOMMU specification : If command-queue access leads to a memory fault then the command-queue-memory-fault bit is set to 1 and the commandqueue stalls until this bit is cleared. To re-enable command processing, software should clear this bit by writing 1. Signed-off-by: Jay Chang <jay.chang@sifive.com> Reviewed-by: Frank Chang <frank.chang@sifive.com> Reviewed-by: Daniel Henrique Barboza <daniel.barboza@oss.qualcomm.com> Reviewed-by: Nutty Liu <nutty.liu@hotmail.com> Message-ID: <20260518070143.8405-1-jay.chang@sifive.com> Signed-off-by: Alistair Francis <alistair.francis@wdc.com> --- hw/riscv/riscv-iommu.c | 10 ++++++++++ 1 file changed, 10 insertions(+) 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_cq_control(RISCVIOMMUState *s) } riscv_iommu_reg_mod32(s, RISCV_IOMMU_REG_CQCSR, ctrl_set, ctrl_clr); + + /* + * After clearing error bits (CMD_ILL, CQMF), if queue is still active, + * re-process pending command. + */ + ctrl_set = riscv_iommu_reg_get32(s, RISCV_IOMMU_REG_CQCSR); + if ((ctrl_set & RISCV_IOMMU_CQCSR_CQON) && + !(ctrl_set & (RISCV_IOMMU_CQCSR_CMD_ILL | RISCV_IOMMU_CQCSR_CQMF))) { + riscv_iommu_process_cq_tail(s); + } } static void riscv_iommu_process_fq_control(RISCVIOMMUState *s) -- 2.53.0