:p
atchew
Login
From: Alistair Francis <alistair.francis@wdc.com> The following changes since commit 757a34115e7491744a63dfc3d291fd1de5297ee2: Merge tag 'pull-nvme-20250515' of https://gitlab.com/birkelund/qemu into staging (2025-05-15 13:42:27 -0400) are available in the Git repository at: https://github.com/alistair23/qemu.git tags/pull-riscv-to-apply-20250519 for you to fetch changes up to e7cb99bfd1afc5cf2265a122bcfeab36eff7489a: hw/riscv/virt.c: remove 'long' casts in fmt strings (2025-05-19 13:42:56 +1000) ---------------------------------------------------------------- First RISC-V PR for 10.1 * Add support for RIMT to virt machine ACPI * Don't allow PMP RLB to bypass rule privileges * Fix checks on writes to pmpcfg in Smepmp MML mode * Generate strided vector loads/stores with tcg nodes * Improve Microchip Polarfire SoC customization * Use tcg ops generation to emulate whole reg rvv loads/stores * Expand the probe_pages helper function to handle probe flags * Fix type conflict of GLib function pointers * Fix endless translation loop on big endian systems * Use tail pseudoinstruction for calling tail * Fix some RISC-V vector instruction corner cases * MAINTAINERS: Add common-user/host/riscv to RISC-V section * Fix write_misa vs aligned next_pc * KVM CSR fixes * Virt machine memmap usage cleanup ---------------------------------------------------------------- Alistair Francis (1): MAINTAINERS: Add common-user/host/riscv to RISC-V section Anton Blanchard (3): target/riscv: rvv: Source vector registers cannot overlap mask register target/riscv: rvv: Add CHECK arg to GEN_OPFVF_WIDEN_TRANS target/riscv: Fix vslidedown with rvv_ta_all_1s Daniel Henrique Barboza (18): target/riscv/kvm: minor fixes/tweaks target/riscv/kvm: fix leak in kvm_riscv_init_multiext_cfg() target/riscv/kvm: turn u32/u64 reg functions into macros target/riscv/kvm: turn kvm_riscv_reg_id_ulong() into a macro target/riscv/kvm: add kvm_csr_cfgs[] target/riscv/kvm: do not read unavailable CSRs target/riscv/kvm: add senvcfg CSR target/riscv/kvm: read/write KVM regs via env size target/riscv/kvm: add scounteren CSR hw/riscv/virt.c: enforce s->memmap use in machine_init() hw/riscv/virt.c: remove trivial virt_memmap references hw/riscv/virt.c: use s->memmap in virt_machine_done() hw/riscv/virt.c: add 'base' arg in create_fw_cfg() hw/riscv/virt.c: use s->memmap in create_fdt() path hw/riscv/virt.c: use s->memmap in create_fdt_sockets() path hw/riscv/virt.c: use s->memmap in create_fdt_virtio() hw/riscv/virt.c: use s->memmap in finalize_fdt() functions hw/riscv/virt.c: remove 'long' casts in fmt strings Icenowy Zheng (1): common-user/host/riscv: use tail pseudoinstruction for calling tail Loïc Lefort (5): target/riscv: pmp: don't allow RLB to bypass rule privileges target/riscv: pmp: move Smepmp operation conversion into a function target/riscv: pmp: fix checks on writes to pmpcfg in Smepmp MML mode target/riscv: pmp: exit csr writes early if value was not changed target/riscv: pmp: remove redundant check in pmp_is_locked Max Chou (8): target/riscv: rvv: Apply vext_check_input_eew to vrgather instructions to check mismatched input EEWs encoding constraint target/riscv: rvv: Apply vext_check_input_eew to OPIVI/OPIVX/OPFVF(vext_check_ss) instructions target/riscv: rvv: Apply vext_check_input_eew to OPIVV/OPFVV(vext_check_sss) instructions target/riscv: rvv: Apply vext_check_input_eew to vector slide instructions(OPIVI/OPIVX) target/riscv: rvv: Apply vext_check_input_eew to vector integer extension instructions(OPMVV) target/riscv: rvv: Apply vext_check_input_eew to vector narrow/widen instructions target/riscv: rvv: Apply vext_check_input_eew to vector indexed load/store instructions target/riscv: Fix the rvv reserved encoding of unmasked instructions Paolo Bonzini (1): hw/riscv: Fix type conflict of GLib function pointers Paolo Savini (3): Generate strided vector loads/stores with tcg nodes. target/riscv: use tcg ops generation to emulate whole reg rvv loads/stores. Expand the probe_pages helper function to handle probe flags. Richard Henderson (7): target/riscv: Pass ra to riscv_csr_write_fn target/riscv: Pass ra to riscv_csrrw_do64 target/riscv: Pass ra to riscv_csrrw_do128 target/riscv: Pass ra to riscv_csrrw target/riscv: Pass ra to riscv_csrrw_i128 target/riscv: Move insn_len to internals.h target/riscv: Fix write_misa vs aligned next_pc Sebastian Huber (6): hw/misc: Add MPFS system reset support hw/riscv: More flexible FDT placement for MPFS hw/riscv: Make FDT optional for MPFS hw/riscv: Allow direct start of kernel for MPFS hw/riscv: Configurable MPFS CLINT timebase freq hw/riscv: microchip_pfsoc: Rework documentation Sunil V L (2): hw/riscv/virt: Add the BDF of IOMMU to RISCVVirtState structure hw/riscv/virt-acpi-build: Add support for RIMT Ziqiao Kong (1): target/riscv: fix endless translation loop on big endian systems MAINTAINERS | 1 + docs/system/riscv/microchip-icicle-kit.rst | 124 ++---- include/hw/riscv/microchip_pfsoc.h | 1 + include/hw/riscv/virt.h | 1 + target/riscv/cpu.h | 16 +- target/riscv/internals.h | 5 + target/riscv/insn32.decode | 18 +- hw/misc/mchp_pfsoc_sysreg.c | 7 + hw/riscv/microchip_pfsoc.c | 153 +++++-- hw/riscv/riscv_hart.c | 9 +- hw/riscv/virt-acpi-build.c | 215 ++++++++++ hw/riscv/virt.c | 273 ++++++------ target/riscv/cpu_helper.c | 6 +- target/riscv/csr.c | 278 +++++++------ target/riscv/kvm/kvm-cpu.c | 333 +++++++++------ target/riscv/op_helper.c | 13 +- target/riscv/pmp.c | 147 ++++--- target/riscv/translate.c | 5 - target/riscv/vector_helper.c | 63 ++- target/riscv/insn_trans/trans_rvbf16.c.inc | 9 +- target/riscv/insn_trans/trans_rvv.c.inc | 644 +++++++++++++++++++++++------ common-user/host/riscv/safe-syscall.inc.S | 4 +- 22 files changed, 1570 insertions(+), 755 deletions(-)
From: Sunil V L <sunilvl@ventanamicro.com> When the IOMMU is implemented as a PCI device, its BDF is created locally in virt.c. However, the same BDF is also required in virt-acpi-build.c to support ACPI. Therefore, make this information part of the global RISCVVirtState structure so that it can be accessed outside of virt.c as well. Signed-off-by: Sunil V L <sunilvl@ventanamicro.com> Reviewed-by: Daniel Henrique Barboza <dbarboza@ventanamicro.com> Message-ID: <20250322043139.2003479-2-sunilvl@ventanamicro.com> Signed-off-by: Alistair Francis <alistair.francis@wdc.com> --- include/hw/riscv/virt.h | 1 + hw/riscv/virt.c | 1 + 2 files changed, 2 insertions(+) diff --git a/include/hw/riscv/virt.h b/include/hw/riscv/virt.h index XXXXXXX..XXXXXXX 100644 --- a/include/hw/riscv/virt.h +++ b/include/hw/riscv/virt.h @@ -XXX,XX +XXX,XX @@ struct RISCVVirtState { const MemMapEntry *memmap; struct GPEXHost *gpex_host; OnOffAuto iommu_sys; + uint16_t pci_iommu_bdf; }; enum { diff --git a/hw/riscv/virt.c b/hw/riscv/virt.c index XXXXXXX..XXXXXXX 100644 --- a/hw/riscv/virt.c +++ b/hw/riscv/virt.c @@ -XXX,XX +XXX,XX @@ static void create_fdt_iommu(RISCVVirtState *s, uint16_t bdf) qemu_fdt_setprop_cells(fdt, pci_node, "iommu-map", 0, iommu_phandle, 0, bdf, bdf + 1, iommu_phandle, bdf + 1, 0xffff - bdf); + s->pci_iommu_bdf = bdf; } static void finalize_fdt(RISCVVirtState *s) -- 2.49.0
From: Sunil V L <sunilvl@ventanamicro.com> RISC-V IO Mapping Table (RIMT) is a new static ACPI table used to communicate IOMMU information to the OS. Add support for creating this table when the IOMMU is present. The specification is frozen and available at [1]. [1] - https://github.com/riscv-non-isa/riscv-acpi-rimt/releases/download/v0.99/rimt-spec.pdf Signed-off-by: Sunil V L <sunilvl@ventanamicro.com> Reviewed-by: Daniel Henrique Barboza <dbarboza@ventanamicro.com> Message-ID: <20250322043139.2003479-3-sunilvl@ventanamicro.com> Signed-off-by: Alistair Francis <alistair.francis@wdc.com> --- hw/riscv/virt-acpi-build.c | 215 +++++++++++++++++++++++++++++++++++++ 1 file changed, 215 insertions(+) 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 @@ acpi_dsdt_add_uart(Aml *scope, const MemMapEntry *uart_memmap, aml_append(scope, dev); } +/* + * Add DSDT entry for the IOMMU platform device. + * ACPI ID for IOMMU is defined in the section 6.2 of RISC-V BRS spec. + * https://github.com/riscv-non-isa/riscv-brs/releases/download/v0.8/riscv-brs-spec.pdf + */ +static void acpi_dsdt_add_iommu_sys(Aml *scope, const MemMapEntry *iommu_memmap, + uint32_t iommu_irq) +{ + uint32_t i; + + Aml *dev = aml_device("IMU0"); + aml_append(dev, aml_name_decl("_HID", aml_string("RSCV0004"))); + aml_append(dev, aml_name_decl("_UID", aml_int(0))); + + Aml *crs = aml_resource_template(); + aml_append(crs, aml_memory32_fixed(iommu_memmap->base, + iommu_memmap->size, AML_READ_WRITE)); + for (i = iommu_irq; i < iommu_irq + 4; i++) { + aml_append(crs, aml_interrupt(AML_CONSUMER, AML_EDGE, AML_ACTIVE_LOW, + AML_EXCLUSIVE, &i, 1)); + } + + aml_append(dev, aml_name_decl("_CRS", crs)); + aml_append(scope, dev); +} + /* * Serial Port Console Redirection Table (SPCR) * Rev: 1.10 @@ -XXX,XX +XXX,XX @@ static void build_dsdt(GArray *table_data, } acpi_dsdt_add_uart(scope, &memmap[VIRT_UART0], UART0_IRQ); + if (virt_is_iommu_sys_enabled(s)) { + acpi_dsdt_add_iommu_sys(scope, &memmap[VIRT_IOMMU_SYS], IOMMU_SYS_IRQ); + } if (socket_count == 1) { virtio_acpi_dsdt_add(scope, memmap[VIRT_VIRTIO].base, @@ -XXX,XX +XXX,XX @@ static void build_madt(GArray *table_data, acpi_table_end(linker, &table); } +#define ID_MAPPING_ENTRY_SIZE 20 +#define IOMMU_ENTRY_SIZE 40 +#define RISCV_INTERRUPT_WIRE_OFFSSET 40 +#define ROOT_COMPLEX_ENTRY_SIZE 20 +#define RIMT_NODE_OFFSET 48 + +/* + * ID Mapping Structure + */ +static void build_rimt_id_mapping(GArray *table_data, uint32_t source_id_base, + uint32_t num_ids, uint32_t dest_id_base) +{ + /* Source ID Base */ + build_append_int_noprefix(table_data, source_id_base, 4); + /* Number of IDs */ + build_append_int_noprefix(table_data, num_ids, 4); + /* Destination Device ID Base */ + build_append_int_noprefix(table_data, source_id_base, 4); + /* Destination IOMMU Offset */ + build_append_int_noprefix(table_data, dest_id_base, 4); + /* Flags */ + build_append_int_noprefix(table_data, 0, 4); +} + +struct AcpiRimtIdMapping { + uint32_t source_id_base; + uint32_t num_ids; +}; +typedef struct AcpiRimtIdMapping AcpiRimtIdMapping; + +/* Build the rimt ID mapping to IOMMU for a given PCI host bridge */ +static int rimt_host_bridges(Object *obj, void *opaque) +{ + GArray *idmap_blob = opaque; + + if (object_dynamic_cast(obj, TYPE_PCI_HOST_BRIDGE)) { + PCIBus *bus = PCI_HOST_BRIDGE(obj)->bus; + + if (bus && !pci_bus_bypass_iommu(bus)) { + int min_bus, max_bus; + + pci_bus_range(bus, &min_bus, &max_bus); + + AcpiRimtIdMapping idmap = { + .source_id_base = min_bus << 8, + .num_ids = (max_bus - min_bus + 1) << 8, + }; + g_array_append_val(idmap_blob, idmap); + } + } + + return 0; +} + +static int rimt_idmap_compare(gconstpointer a, gconstpointer b) +{ + AcpiRimtIdMapping *idmap_a = (AcpiRimtIdMapping *)a; + AcpiRimtIdMapping *idmap_b = (AcpiRimtIdMapping *)b; + + return idmap_a->source_id_base - idmap_b->source_id_base; +} + +/* + * RISC-V IO Mapping Table (RIMT) + * https://github.com/riscv-non-isa/riscv-acpi-rimt/releases/download/v0.99/rimt-spec.pdf + */ +static void build_rimt(GArray *table_data, BIOSLinker *linker, + RISCVVirtState *s) +{ + int i, nb_nodes, rc_mapping_count; + size_t node_size, iommu_offset = 0; + uint32_t id = 0; + g_autoptr(GArray) iommu_idmaps = g_array_new(false, true, + sizeof(AcpiRimtIdMapping)); + + AcpiTable table = { .sig = "RIMT", .rev = 1, .oem_id = s->oem_id, + .oem_table_id = s->oem_table_id }; + + acpi_table_begin(&table, table_data); + + object_child_foreach_recursive(object_get_root(), + rimt_host_bridges, iommu_idmaps); + + /* Sort the ID mapping by Source ID Base*/ + g_array_sort(iommu_idmaps, rimt_idmap_compare); + + nb_nodes = 2; /* RC, IOMMU */ + rc_mapping_count = iommu_idmaps->len; + /* Number of RIMT Nodes */ + build_append_int_noprefix(table_data, nb_nodes, 4); + + /* Offset to Array of RIMT Nodes */ + build_append_int_noprefix(table_data, RIMT_NODE_OFFSET, 4); + build_append_int_noprefix(table_data, 0, 4); /* Reserved */ + + iommu_offset = table_data->len - table.table_offset; + /* IOMMU Device Structure */ + build_append_int_noprefix(table_data, 0, 1); /* Type - IOMMU*/ + build_append_int_noprefix(table_data, 1, 1); /* Revision */ + node_size = IOMMU_ENTRY_SIZE; + build_append_int_noprefix(table_data, node_size, 2); /* Length */ + build_append_int_noprefix(table_data, 0, 2); /* Reserved */ + build_append_int_noprefix(table_data, id++, 2); /* ID */ + if (virt_is_iommu_sys_enabled(s)) { + /* Hardware ID */ + build_append_int_noprefix(table_data, 'R', 1); + build_append_int_noprefix(table_data, 'S', 1); + build_append_int_noprefix(table_data, 'C', 1); + build_append_int_noprefix(table_data, 'V', 1); + build_append_int_noprefix(table_data, '0', 1); + build_append_int_noprefix(table_data, '0', 1); + build_append_int_noprefix(table_data, '0', 1); + build_append_int_noprefix(table_data, '4', 1); + /* Base Address */ + build_append_int_noprefix(table_data, + s->memmap[VIRT_IOMMU_SYS].base, 8); + build_append_int_noprefix(table_data, 0, 4); /* Flags */ + } else { + /* Hardware ID */ + build_append_int_noprefix(table_data, '0', 1); + build_append_int_noprefix(table_data, '0', 1); + build_append_int_noprefix(table_data, '1', 1); + build_append_int_noprefix(table_data, '0', 1); + build_append_int_noprefix(table_data, '0', 1); + build_append_int_noprefix(table_data, '0', 1); + build_append_int_noprefix(table_data, '1', 1); + build_append_int_noprefix(table_data, '4', 1); + + build_append_int_noprefix(table_data, 0, 8); /* Base Address */ + build_append_int_noprefix(table_data, 1, 4); /* Flags */ + } + + build_append_int_noprefix(table_data, 0, 4); /* Proximity Domain */ + build_append_int_noprefix(table_data, 0, 2); /* PCI Segment number */ + /* PCIe B/D/F */ + if (virt_is_iommu_sys_enabled(s)) { + build_append_int_noprefix(table_data, 0, 2); + } else { + build_append_int_noprefix(table_data, s->pci_iommu_bdf, 2); + } + /* Number of interrupt wires */ + build_append_int_noprefix(table_data, 0, 2); + /* Interrupt wire array offset */ + build_append_int_noprefix(table_data, RISCV_INTERRUPT_WIRE_OFFSSET, 2); + + /* PCIe Root Complex Node */ + build_append_int_noprefix(table_data, 1, 1); /* Type */ + build_append_int_noprefix(table_data, 1, 1); /* Revision */ + node_size = ROOT_COMPLEX_ENTRY_SIZE + + ID_MAPPING_ENTRY_SIZE * rc_mapping_count; + build_append_int_noprefix(table_data, node_size, 2); /* Length */ + build_append_int_noprefix(table_data, 0, 2); /* Reserved */ + build_append_int_noprefix(table_data, id++, 2); /* ID */ + build_append_int_noprefix(table_data, 0, 4); /* Flags */ + build_append_int_noprefix(table_data, 0, 2); /* Reserved */ + /* PCI Segment number */ + build_append_int_noprefix(table_data, 0, 2); + /* ID mapping array offset */ + build_append_int_noprefix(table_data, ROOT_COMPLEX_ENTRY_SIZE, 2); + /* Number of ID mappings */ + build_append_int_noprefix(table_data, rc_mapping_count, 2); + + /* Output Reference */ + AcpiRimtIdMapping *range; + + /* ID mapping array */ + for (i = 0; i < iommu_idmaps->len; i++) { + range = &g_array_index(iommu_idmaps, AcpiRimtIdMapping, i); + if (virt_is_iommu_sys_enabled(s)) { + range->source_id_base = 0; + } else { + range->source_id_base = s->pci_iommu_bdf + 1; + } + range->num_ids = 0xffff - s->pci_iommu_bdf; + build_rimt_id_mapping(table_data, range->source_id_base, + range->num_ids, iommu_offset); + } + + acpi_table_end(linker, &table); +} + /* * ACPI spec, Revision 6.5+ * 5.2.16 System Resource Affinity Table (SRAT) @@ -XXX,XX +XXX,XX @@ static void virt_acpi_build(RISCVVirtState *s, AcpiBuildTables *tables) acpi_add_table(table_offsets, tables_blob); build_rhct(tables_blob, tables->linker, s); + if (virt_is_iommu_sys_enabled(s) || s->pci_iommu_bdf) { + acpi_add_table(table_offsets, tables_blob); + build_rimt(tables_blob, tables->linker, s); + } + acpi_add_table(table_offsets, tables_blob); spcr_setup(tables_blob, tables->linker, s); -- 2.49.0
From: Loïc Lefort <loic@rivosinc.com> When Smepmp is supported, mseccfg.RLB allows bypassing locks when writing CSRs but should not affect interpretation of actual PMP rules. This is not the case with the current implementation where pmp_hart_has_privs calls pmp_is_locked which implements mseccfg.RLB bypass. This commit implements the correct behavior by removing mseccfg.RLB bypass from pmp_is_locked. RLB bypass when writing CSRs is implemented by adding a new pmp_is_readonly function that calls pmp_is_locked and check mseccfg.RLB. pmp_write_cfg and pmpaddr_csr_write are changed to use this new function. Signed-off-by: Loïc Lefort <loic@rivosinc.com> Reviewed-by: Alistair Francis <alistair.francis@wdc.com> Reviewed-by: Daniel Henrique Barboza <dbarboza@ventanamicro.com> Reviewed-by: LIU Zhiwei <zhiwei_liu@linux.alibaba.com> Message-ID: <20250313193011.720075-2-loic@rivosinc.com> Signed-off-by: Alistair Francis <alistair.francis@wdc.com> Cc: qemu-stable@nongnu.org --- target/riscv/pmp.c | 43 +++++++++++++++++++++++-------------------- 1 file changed, 23 insertions(+), 20 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 inline uint8_t pmp_get_a_field(uint8_t cfg) */ static inline int pmp_is_locked(CPURISCVState *env, uint32_t pmp_index) { - /* mseccfg.RLB is set */ - if (MSECCFG_RLB_ISSET(env)) { - return 0; - } - if (env->pmp_state.pmp[pmp_index].cfg_reg & PMP_LOCK) { return 1; } @@ -XXX,XX +XXX,XX @@ static inline int pmp_is_locked(CPURISCVState *env, uint32_t pmp_index) return 0; } +/* + * Check whether a PMP is locked for writing or not. + * (i.e. has LOCK flag and mseccfg.RLB is unset) + */ +static int pmp_is_readonly(CPURISCVState *env, uint32_t pmp_index) +{ + return pmp_is_locked(env, pmp_index) && !MSECCFG_RLB_ISSET(env); +} + /* * Count the number of active rules. */ @@ -XXX,XX +XXX,XX @@ static inline uint8_t pmp_read_cfg(CPURISCVState *env, uint32_t pmp_index) static bool pmp_write_cfg(CPURISCVState *env, uint32_t pmp_index, uint8_t val) { if (pmp_index < MAX_RISCV_PMPS) { - bool locked = true; + bool readonly = true; if (riscv_cpu_cfg(env)->ext_smepmp) { /* mseccfg.RLB is set */ if (MSECCFG_RLB_ISSET(env)) { - locked = false; + readonly = false; } /* mseccfg.MML is not set */ - if (!MSECCFG_MML_ISSET(env) && !pmp_is_locked(env, pmp_index)) { - locked = false; + if (!MSECCFG_MML_ISSET(env) && !pmp_is_readonly(env, pmp_index)) { + readonly = false; } /* mseccfg.MML is set */ if (MSECCFG_MML_ISSET(env)) { /* not adding execute bit */ if ((val & PMP_LOCK) != 0 && (val & PMP_EXEC) != PMP_EXEC) { - locked = false; + readonly = false; } /* shared region and not adding X bit */ if ((val & PMP_LOCK) != PMP_LOCK && (val & 0x7) != (PMP_WRITE | PMP_EXEC)) { - locked = false; + readonly = false; } } } else { - if (!pmp_is_locked(env, pmp_index)) { - locked = false; - } + readonly = pmp_is_readonly(env, pmp_index); } - if (locked) { - qemu_log_mask(LOG_GUEST_ERROR, "ignoring pmpcfg write - locked\n"); + if (readonly) { + qemu_log_mask(LOG_GUEST_ERROR, + "ignoring pmpcfg write - read only\n"); } else if (env->pmp_state.pmp[pmp_index].cfg_reg != val) { /* If !mseccfg.MML then ignore writes with encoding RW=01 */ if ((val & PMP_WRITE) && !(val & PMP_READ) && @@ -XXX,XX +XXX,XX @@ void pmpaddr_csr_write(CPURISCVState *env, uint32_t addr_index, uint8_t pmp_cfg = env->pmp_state.pmp[addr_index + 1].cfg_reg; is_next_cfg_tor = PMP_AMATCH_TOR == pmp_get_a_field(pmp_cfg); - if (pmp_is_locked(env, addr_index + 1) && is_next_cfg_tor) { + if (pmp_is_readonly(env, addr_index + 1) && is_next_cfg_tor) { qemu_log_mask(LOG_GUEST_ERROR, - "ignoring pmpaddr write - pmpcfg + 1 locked\n"); + "ignoring pmpaddr write - pmpcfg+1 read only\n"); return; } } - if (!pmp_is_locked(env, addr_index)) { + if (!pmp_is_readonly(env, addr_index)) { if (env->pmp_state.pmp[addr_index].addr_reg != val) { env->pmp_state.pmp[addr_index].addr_reg = val; pmp_update_rule_addr(env, addr_index); @@ -XXX,XX +XXX,XX @@ void pmpaddr_csr_write(CPURISCVState *env, uint32_t addr_index, } } else { qemu_log_mask(LOG_GUEST_ERROR, - "ignoring pmpaddr write - locked\n"); + "ignoring pmpaddr write - read only\n"); } } else { qemu_log_mask(LOG_GUEST_ERROR, -- 2.49.0
From: Loïc Lefort <loic@rivosinc.com> Signed-off-by: Loïc Lefort <loic@rivosinc.com> Reviewed-by: Daniel Henrique Barboza <dbarboza@ventanamicro.com> Reviewed-by: Alistair Francis <alistair.francis@wdc.com> Reviewed-by: LIU Zhiwei <zhiwei_liu@linux.alibaba.com> Message-ID: <20250313193011.720075-3-loic@rivosinc.com> Signed-off-by: Alistair Francis <alistair.francis@wdc.com> Cc: qemu-stable@nongnu.org --- target/riscv/pmp.c | 22 ++++++++++++---------- 1 file changed, 12 insertions(+), 10 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 bool pmp_write_cfg(CPURISCVState *env, uint32_t addr_index, uint8_t val); static uint8_t pmp_read_cfg(CPURISCVState *env, uint32_t addr_index); +/* + * Convert the PMP permissions to match the truth table in the Smepmp spec. + */ +static inline uint8_t pmp_get_smepmp_operation(uint8_t cfg) +{ + return ((cfg & PMP_LOCK) >> 4) | ((cfg & PMP_READ) << 2) | + (cfg & PMP_WRITE) | ((cfg & PMP_EXEC) >> 2); +} + /* * Accessor method to extract address matching type 'a field' from cfg reg */ @@ -XXX,XX +XXX,XX @@ bool pmp_hart_has_privs(CPURISCVState *env, hwaddr addr, const uint8_t a_field = pmp_get_a_field(env->pmp_state.pmp[i].cfg_reg); - /* - * Convert the PMP permissions to match the truth table in the - * Smepmp spec. - */ - const uint8_t smepmp_operation = - ((env->pmp_state.pmp[i].cfg_reg & PMP_LOCK) >> 4) | - ((env->pmp_state.pmp[i].cfg_reg & PMP_READ) << 2) | - (env->pmp_state.pmp[i].cfg_reg & PMP_WRITE) | - ((env->pmp_state.pmp[i].cfg_reg & PMP_EXEC) >> 2); - if (((s + e) == 2) && (PMP_AMATCH_OFF != a_field)) { /* * If the PMP entry is not off and the address is in range, @@ -XXX,XX +XXX,XX @@ bool pmp_hart_has_privs(CPURISCVState *env, hwaddr addr, /* * If mseccfg.MML Bit set, do the enhanced pmp priv check */ + const uint8_t smepmp_operation = + pmp_get_smepmp_operation(env->pmp_state.pmp[i].cfg_reg); + if (mode == PRV_M) { switch (smepmp_operation) { case 0: -- 2.49.0
From: Loïc Lefort <loic@rivosinc.com> With Machine Mode Lockdown (mseccfg.MML) set and RLB not set, checks on pmpcfg writes would match the wrong cases of Smepmp truth table. The existing code allows writes for the following cases: - L=1, X=0: cases 8, 10, 12, 14 - L=0, RWX!=WX: cases 0-2, 4-6 This leaves cases 3, 7, 9, 11, 13, 15 for which writes are ignored. From the Smepmp specification: "Adding a rule with executable privileges that either is M-mode-only or a locked Shared-Region is not possible (...)" This description matches cases 9-11, 13 of the truth table. This commit implements an explicit check for these cases by using pmp_get_epmp_operation to convert between PMP configuration and Smepmp truth table cases. Signed-off-by: Loïc Lefort <loic@rivosinc.com> Reviewed-by: Daniel Henrique Barboza <dbarboza@ventanamicro.com> Reviewed-by: LIU Zhiwei <zhiwei_liu@linux.alibaba.com> Message-ID: <20250313193011.720075-4-loic@rivosinc.com> Signed-off-by: Alistair Francis <alistair.francis@wdc.com> Cc: qemu-stable@nongnu.org --- target/riscv/pmp.c | 79 +++++++++++++++++++++++++--------------------- 1 file changed, 43 insertions(+), 36 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 int pmp_is_readonly(CPURISCVState *env, uint32_t pmp_index) return pmp_is_locked(env, pmp_index) && !MSECCFG_RLB_ISSET(env); } +/* + * Check whether `val` is an invalid Smepmp config value + */ +static int pmp_is_invalid_smepmp_cfg(CPURISCVState *env, uint8_t val) +{ + /* No check if mseccfg.MML is not set or if mseccfg.RLB is set */ + if (!MSECCFG_MML_ISSET(env) || MSECCFG_RLB_ISSET(env)) { + return 0; + } + + /* + * Adding a rule with executable privileges that either is M-mode-only + * or a locked Shared-Region is not possible + */ + switch (pmp_get_smepmp_operation(val)) { + case 0: + case 1: + case 2: + case 3: + case 4: + case 5: + case 6: + case 7: + case 8: + case 12: + case 14: + case 15: + return 0; + case 9: + case 10: + case 11: + case 13: + return 1; + default: + g_assert_not_reached(); + } +} + /* * Count the number of active rules. */ @@ -XXX,XX +XXX,XX @@ static inline uint8_t pmp_read_cfg(CPURISCVState *env, uint32_t pmp_index) static bool pmp_write_cfg(CPURISCVState *env, uint32_t pmp_index, uint8_t val) { if (pmp_index < MAX_RISCV_PMPS) { - bool readonly = true; - - if (riscv_cpu_cfg(env)->ext_smepmp) { - /* mseccfg.RLB is set */ - if (MSECCFG_RLB_ISSET(env)) { - readonly = false; - } - - /* mseccfg.MML is not set */ - if (!MSECCFG_MML_ISSET(env) && !pmp_is_readonly(env, pmp_index)) { - readonly = false; - } - - /* mseccfg.MML is set */ - if (MSECCFG_MML_ISSET(env)) { - /* not adding execute bit */ - if ((val & PMP_LOCK) != 0 && (val & PMP_EXEC) != PMP_EXEC) { - readonly = false; - } - /* shared region and not adding X bit */ - if ((val & PMP_LOCK) != PMP_LOCK && - (val & 0x7) != (PMP_WRITE | PMP_EXEC)) { - readonly = false; - } - } - } else { - readonly = pmp_is_readonly(env, pmp_index); - } - - if (readonly) { + if (pmp_is_readonly(env, pmp_index)) { qemu_log_mask(LOG_GUEST_ERROR, "ignoring pmpcfg write - read only\n"); - } else if (env->pmp_state.pmp[pmp_index].cfg_reg != val) { - /* If !mseccfg.MML then ignore writes with encoding RW=01 */ - if ((val & PMP_WRITE) && !(val & PMP_READ) && - !MSECCFG_MML_ISSET(env)) { - return false; - } + } else if (pmp_is_invalid_smepmp_cfg(env, val)) { + qemu_log_mask(LOG_GUEST_ERROR, + "ignoring pmpcfg write - invalid\n"); + } else { env->pmp_state.pmp[pmp_index].cfg_reg = val; pmp_update_rule_addr(env, pmp_index); return true; -- 2.49.0
From: Loïc Lefort <loic@rivosinc.com> Signed-off-by: Loïc Lefort <loic@rivosinc.com> Reviewed-by: Daniel Henrique Barboza <dbarboza@ventanamicro.com> Reviewed-by: Alistair Francis <alistair.francis@wdc.com> Reviewed-by: LIU Zhiwei <zhiwei_liu@linux.alibaba.com> Message-ID: <20250313193011.720075-5-loic@rivosinc.com> Signed-off-by: Alistair Francis <alistair.francis@wdc.com> --- target/riscv/pmp.c | 22 +++++++++++++++------- 1 file changed, 15 insertions(+), 7 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 inline uint8_t pmp_read_cfg(CPURISCVState *env, uint32_t pmp_index) static bool pmp_write_cfg(CPURISCVState *env, uint32_t pmp_index, uint8_t val) { if (pmp_index < MAX_RISCV_PMPS) { + if (env->pmp_state.pmp[pmp_index].cfg_reg == val) { + /* no change */ + return false; + } + if (pmp_is_readonly(env, pmp_index)) { qemu_log_mask(LOG_GUEST_ERROR, "ignoring pmpcfg write - read only\n"); @@ -XXX,XX +XXX,XX @@ void pmpaddr_csr_write(CPURISCVState *env, uint32_t addr_index, bool is_next_cfg_tor = false; if (addr_index < MAX_RISCV_PMPS) { + if (env->pmp_state.pmp[addr_index].addr_reg == val) { + /* no change */ + return; + } + /* * In TOR mode, need to check the lock bit of the next pmp * (if there is a next). @@ -XXX,XX +XXX,XX @@ void pmpaddr_csr_write(CPURISCVState *env, uint32_t addr_index, } if (!pmp_is_readonly(env, addr_index)) { - if (env->pmp_state.pmp[addr_index].addr_reg != val) { - env->pmp_state.pmp[addr_index].addr_reg = val; - pmp_update_rule_addr(env, addr_index); - if (is_next_cfg_tor) { - pmp_update_rule_addr(env, addr_index + 1); - } - tlb_flush(env_cpu(env)); + env->pmp_state.pmp[addr_index].addr_reg = val; + pmp_update_rule_addr(env, addr_index); + if (is_next_cfg_tor) { + pmp_update_rule_addr(env, addr_index + 1); } + tlb_flush(env_cpu(env)); } else { qemu_log_mask(LOG_GUEST_ERROR, "ignoring pmpaddr write - read only\n"); -- 2.49.0
From: Loïc Lefort <loic@rivosinc.com> Remove useless check in pmp_is_locked, the function will return 0 in either case. Signed-off-by: Loïc Lefort <loic@rivosinc.com> Reviewed-by: Daniel Henrique Barboza <dbarboza@ventanamicro.com> Reviewed-by: Alistair Francis <alistair.francis@wdc.com> Reviewed-by: LIU Zhiwei <zhiwei_liu@linux.alibaba.com> Message-ID: <20250313193011.720075-6-loic@rivosinc.com> Signed-off-by: Alistair Francis <alistair.francis@wdc.com> --- target/riscv/pmp.c | 5 ----- 1 file changed, 5 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 inline int pmp_is_locked(CPURISCVState *env, uint32_t pmp_index) return 1; } - /* Top PMP has no 'next' to check */ - if ((pmp_index + 1u) >= MAX_RISCV_PMPS) { - return 0; - } - return 0; } -- 2.49.0
From: Paolo Savini <paolo.savini@embecosm.com> This commit improves the performance of QEMU when emulating strided vector loads and stores by substituting the call for the helper function with the generation of equivalent TCG operations. Signed-off-by: Paolo Savini <paolo.savini@embecosm.com> Reviewed-by: Daniel Henrique Barboza <dbarboza@ventanamicro.com> Message-ID: <20250312155547.289642-2-paolo.savini@embecosm.com> Signed-off-by: Alistair Francis <alistair.francis@wdc.com> --- target/riscv/insn_trans/trans_rvv.c.inc | 323 ++++++++++++++++++++---- 1 file changed, 273 insertions(+), 50 deletions(-) diff --git a/target/riscv/insn_trans/trans_rvv.c.inc b/target/riscv/insn_trans/trans_rvv.c.inc index XXXXXXX..XXXXXXX 100644 --- a/target/riscv/insn_trans/trans_rvv.c.inc +++ b/target/riscv/insn_trans/trans_rvv.c.inc @@ -XXX,XX +XXX,XX @@ GEN_VEXT_TRANS(vlm_v, MO_8, vlm_v, ld_us_mask_op, ld_us_mask_check) GEN_VEXT_TRANS(vsm_v, MO_8, vsm_v, st_us_mask_op, st_us_mask_check) /* - *** stride load and store + * MAXSZ returns the maximum vector size can be operated in bytes, + * which is used in GVEC IR when vl_eq_vlmax flag is set to true + * to accelerate vector operation. + */ +static inline uint32_t MAXSZ(DisasContext *s) +{ + int max_sz = s->cfg_ptr->vlenb << 3; + return max_sz >> (3 - s->lmul); +} + +static inline uint32_t get_log2(uint32_t a) +{ + uint32_t i = 0; + for (; a > 0;) { + a >>= 1; + i++; + } + return i; +} + +typedef void gen_tl_ldst(TCGv, TCGv_ptr, tcg_target_long); + +/* + * Simulate the strided load/store main loop: + * + * for (i = env->vstart; i < env->vl; env->vstart = ++i) { + * k = 0; + * while (k < nf) { + * if (!vm && !vext_elem_mask(v0, i)) { + * vext_set_elems_1s(vd, vma, (i + k * max_elems) * esz, + * (i + k * max_elems + 1) * esz); + * k++; + * continue; + * } + * target_ulong addr = base + stride * i + (k << log2_esz); + * ldst(env, adjust_addr(env, addr), i + k * max_elems, vd, ra); + * k++; + * } + * } + */ +static void gen_ldst_stride_main_loop(DisasContext *s, TCGv dest, uint32_t rs1, + uint32_t rs2, uint32_t vm, uint32_t nf, + gen_tl_ldst *ld_fn, gen_tl_ldst *st_fn, + bool is_load) +{ + TCGv addr = tcg_temp_new(); + TCGv base = get_gpr(s, rs1, EXT_NONE); + TCGv stride = get_gpr(s, rs2, EXT_NONE); + + TCGv i = tcg_temp_new(); + TCGv i_esz = tcg_temp_new(); + TCGv k = tcg_temp_new(); + TCGv k_esz = tcg_temp_new(); + TCGv k_max = tcg_temp_new(); + TCGv mask = tcg_temp_new(); + TCGv mask_offs = tcg_temp_new(); + TCGv mask_offs_64 = tcg_temp_new(); + TCGv mask_elem = tcg_temp_new(); + TCGv mask_offs_rem = tcg_temp_new(); + TCGv vreg = tcg_temp_new(); + TCGv dest_offs = tcg_temp_new(); + TCGv stride_offs = tcg_temp_new(); + + uint32_t max_elems = MAXSZ(s) >> s->sew; + + TCGLabel *start = gen_new_label(); + TCGLabel *end = gen_new_label(); + TCGLabel *start_k = gen_new_label(); + TCGLabel *inc_k = gen_new_label(); + TCGLabel *end_k = gen_new_label(); + + MemOp atomicity = MO_ATOM_NONE; + if (s->sew == 0) { + atomicity = MO_ATOM_NONE; + } else { + atomicity = MO_ATOM_IFALIGN_PAIR; + } + + mark_vs_dirty(s); + + tcg_gen_addi_tl(mask, (TCGv)tcg_env, vreg_ofs(s, 0)); + + /* Start of outer loop. */ + tcg_gen_mov_tl(i, cpu_vstart); + gen_set_label(start); + tcg_gen_brcond_tl(TCG_COND_GE, i, cpu_vl, end); + tcg_gen_shli_tl(i_esz, i, s->sew); + /* Start of inner loop. */ + tcg_gen_movi_tl(k, 0); + gen_set_label(start_k); + tcg_gen_brcond_tl(TCG_COND_GE, k, tcg_constant_tl(nf), end_k); + /* + * If we are in mask agnostic regime and the operation is not unmasked we + * set the inactive elements to 1. + */ + if (!vm && s->vma) { + TCGLabel *active_element = gen_new_label(); + /* (i + k * max_elems) * esz */ + tcg_gen_shli_tl(mask_offs, k, get_log2(max_elems << s->sew)); + tcg_gen_add_tl(mask_offs, mask_offs, i_esz); + + /* + * Check whether the i bit of the mask is 0 or 1. + * + * static inline int vext_elem_mask(void *v0, int index) + * { + * int idx = index / 64; + * int pos = index % 64; + * return (((uint64_t *)v0)[idx] >> pos) & 1; + * } + */ + tcg_gen_shri_tl(mask_offs_64, mask_offs, 3); + tcg_gen_add_tl(mask_offs_64, mask_offs_64, mask); + tcg_gen_ld_i64((TCGv_i64)mask_elem, (TCGv_ptr)mask_offs_64, 0); + tcg_gen_rem_tl(mask_offs_rem, mask_offs, tcg_constant_tl(8)); + tcg_gen_shr_tl(mask_elem, mask_elem, mask_offs_rem); + tcg_gen_andi_tl(mask_elem, mask_elem, 1); + tcg_gen_brcond_tl(TCG_COND_NE, mask_elem, tcg_constant_tl(0), + active_element); + /* + * Set masked-off elements in the destination vector register to 1s. + * Store instructions simply skip this bit as memory ops access memory + * only for active elements. + */ + if (is_load) { + tcg_gen_shli_tl(mask_offs, mask_offs, s->sew); + tcg_gen_add_tl(mask_offs, mask_offs, dest); + st_fn(tcg_constant_tl(-1), (TCGv_ptr)mask_offs, 0); + } + tcg_gen_br(inc_k); + gen_set_label(active_element); + } + /* + * The element is active, calculate the address with stride: + * target_ulong addr = base + stride * i + (k << log2_esz); + */ + tcg_gen_mul_tl(stride_offs, stride, i); + tcg_gen_shli_tl(k_esz, k, s->sew); + tcg_gen_add_tl(stride_offs, stride_offs, k_esz); + tcg_gen_add_tl(addr, base, stride_offs); + /* Calculate the offset in the dst/src vector register. */ + tcg_gen_shli_tl(k_max, k, get_log2(max_elems)); + tcg_gen_add_tl(dest_offs, i, k_max); + tcg_gen_shli_tl(dest_offs, dest_offs, s->sew); + tcg_gen_add_tl(dest_offs, dest_offs, dest); + if (is_load) { + tcg_gen_qemu_ld_tl(vreg, addr, s->mem_idx, MO_LE | s->sew | atomicity); + st_fn((TCGv)vreg, (TCGv_ptr)dest_offs, 0); + } else { + ld_fn((TCGv)vreg, (TCGv_ptr)dest_offs, 0); + tcg_gen_qemu_st_tl(vreg, addr, s->mem_idx, MO_LE | s->sew | atomicity); + } + /* + * We don't execute the load/store above if the element was inactive. + * We jump instead directly to incrementing k and continuing the loop. + */ + if (!vm && s->vma) { + gen_set_label(inc_k); + } + tcg_gen_addi_tl(k, k, 1); + tcg_gen_br(start_k); + /* End of the inner loop. */ + gen_set_label(end_k); + + tcg_gen_addi_tl(i, i, 1); + tcg_gen_mov_tl(cpu_vstart, i); + tcg_gen_br(start); + + /* End of the outer loop. */ + gen_set_label(end); + + return; +} + + +/* + * Set the tail bytes of the strided loads/stores to 1: + * + * for (k = 0; k < nf; ++k) { + * cnt = (k * max_elems + vl) * esz; + * tot = (k * max_elems + max_elems) * esz; + * for (i = cnt; i < tot; i += esz) { + * store_1s(-1, vd[vl+i]); + * } + * } */ -typedef void gen_helper_ldst_stride(TCGv_ptr, TCGv_ptr, TCGv, - TCGv, TCGv_env, TCGv_i32); +static void gen_ldst_stride_tail_loop(DisasContext *s, TCGv dest, uint32_t nf, + gen_tl_ldst *st_fn) +{ + TCGv i = tcg_temp_new(); + TCGv k = tcg_temp_new(); + TCGv tail_cnt = tcg_temp_new(); + TCGv tail_tot = tcg_temp_new(); + TCGv tail_addr = tcg_temp_new(); + + TCGLabel *start = gen_new_label(); + TCGLabel *end = gen_new_label(); + TCGLabel *start_i = gen_new_label(); + TCGLabel *end_i = gen_new_label(); + + uint32_t max_elems_b = MAXSZ(s); + uint32_t esz = 1 << s->sew; + + /* Start of the outer loop. */ + tcg_gen_movi_tl(k, 0); + tcg_gen_shli_tl(tail_cnt, cpu_vl, s->sew); + tcg_gen_movi_tl(tail_tot, max_elems_b); + tcg_gen_add_tl(tail_addr, dest, tail_cnt); + gen_set_label(start); + tcg_gen_brcond_tl(TCG_COND_GE, k, tcg_constant_tl(nf), end); + /* Start of the inner loop. */ + tcg_gen_mov_tl(i, tail_cnt); + gen_set_label(start_i); + tcg_gen_brcond_tl(TCG_COND_GE, i, tail_tot, end_i); + /* store_1s(-1, vd[vl+i]); */ + st_fn(tcg_constant_tl(-1), (TCGv_ptr)tail_addr, 0); + tcg_gen_addi_tl(tail_addr, tail_addr, esz); + tcg_gen_addi_tl(i, i, esz); + tcg_gen_br(start_i); + /* End of the inner loop. */ + gen_set_label(end_i); + /* Update the counts */ + tcg_gen_addi_tl(tail_cnt, tail_cnt, max_elems_b); + tcg_gen_addi_tl(tail_tot, tail_cnt, max_elems_b); + tcg_gen_addi_tl(k, k, 1); + tcg_gen_br(start); + /* End of the outer loop. */ + gen_set_label(end); + + return; +} static bool ldst_stride_trans(uint32_t vd, uint32_t rs1, uint32_t rs2, - uint32_t data, gen_helper_ldst_stride *fn, - DisasContext *s) + uint32_t data, DisasContext *s, bool is_load) { - TCGv_ptr dest, mask; - TCGv base, stride; - TCGv_i32 desc; + if (!s->vstart_eq_zero) { + return false; + } - dest = tcg_temp_new_ptr(); - mask = tcg_temp_new_ptr(); - base = get_gpr(s, rs1, EXT_NONE); - stride = get_gpr(s, rs2, EXT_NONE); - desc = tcg_constant_i32(simd_desc(s->cfg_ptr->vlenb, - s->cfg_ptr->vlenb, data)); + TCGv dest = tcg_temp_new(); - tcg_gen_addi_ptr(dest, tcg_env, vreg_ofs(s, vd)); - tcg_gen_addi_ptr(mask, tcg_env, vreg_ofs(s, 0)); + uint32_t nf = FIELD_EX32(data, VDATA, NF); + uint32_t vm = FIELD_EX32(data, VDATA, VM); + + /* Destination register and mask register */ + tcg_gen_addi_tl(dest, (TCGv)tcg_env, vreg_ofs(s, vd)); + + /* + * Select the appropriate load/tore to retrieve data from the vector + * register given a specific sew. + */ + static gen_tl_ldst * const ld_fns[4] = { + tcg_gen_ld8u_tl, tcg_gen_ld16u_tl, + tcg_gen_ld32u_tl, tcg_gen_ld_tl + }; + + static gen_tl_ldst * const st_fns[4] = { + tcg_gen_st8_tl, tcg_gen_st16_tl, + tcg_gen_st32_tl, tcg_gen_st_tl + }; + + gen_tl_ldst *ld_fn = ld_fns[s->sew]; + gen_tl_ldst *st_fn = st_fns[s->sew]; + + if (ld_fn == NULL || st_fn == NULL) { + return false; + } mark_vs_dirty(s); - fn(dest, mask, base, stride, tcg_env, desc); + gen_ldst_stride_main_loop(s, dest, rs1, rs2, vm, nf, ld_fn, st_fn, is_load); + + tcg_gen_movi_tl(cpu_vstart, 0); + + /* + * Set the tail bytes to 1 if tail agnostic: + */ + if (s->vta != 0 && is_load) { + gen_ldst_stride_tail_loop(s, dest, nf, st_fn); + } finalize_rvv_inst(s); return true; @@ -XXX,XX +XXX,XX @@ static bool ldst_stride_trans(uint32_t vd, uint32_t rs1, uint32_t rs2, static bool ld_stride_op(DisasContext *s, arg_rnfvm *a, uint8_t eew) { uint32_t data = 0; - gen_helper_ldst_stride *fn; - static gen_helper_ldst_stride * const fns[4] = { - gen_helper_vlse8_v, gen_helper_vlse16_v, - gen_helper_vlse32_v, gen_helper_vlse64_v - }; - - fn = fns[eew]; - if (fn == NULL) { - return false; - } uint8_t emul = vext_get_emul(s, eew); data = FIELD_DP32(data, VDATA, VM, a->vm); @@ -XXX,XX +XXX,XX @@ static bool ld_stride_op(DisasContext *s, arg_rnfvm *a, uint8_t eew) data = FIELD_DP32(data, VDATA, NF, a->nf); data = FIELD_DP32(data, VDATA, VTA, s->vta); data = FIELD_DP32(data, VDATA, VMA, s->vma); - return ldst_stride_trans(a->rd, a->rs1, a->rs2, data, fn, s); + return ldst_stride_trans(a->rd, a->rs1, a->rs2, data, s, true); } static bool ld_stride_check(DisasContext *s, arg_rnfvm* a, uint8_t eew) @@ -XXX,XX +XXX,XX @@ GEN_VEXT_TRANS(vlse64_v, MO_64, rnfvm, ld_stride_op, ld_stride_check) static bool st_stride_op(DisasContext *s, arg_rnfvm *a, uint8_t eew) { uint32_t data = 0; - gen_helper_ldst_stride *fn; - static gen_helper_ldst_stride * const fns[4] = { - /* masked stride store */ - gen_helper_vsse8_v, gen_helper_vsse16_v, - gen_helper_vsse32_v, gen_helper_vsse64_v - }; uint8_t emul = vext_get_emul(s, eew); data = FIELD_DP32(data, VDATA, VM, a->vm); data = FIELD_DP32(data, VDATA, LMUL, emul); data = FIELD_DP32(data, VDATA, NF, a->nf); - fn = fns[eew]; - if (fn == NULL) { - return false; - } - return ldst_stride_trans(a->rd, a->rs1, a->rs2, data, fn, s); + return ldst_stride_trans(a->rd, a->rs1, a->rs2, data, s, false); } static bool st_stride_check(DisasContext *s, arg_rnfvm* a, uint8_t eew) @@ -XXX,XX +XXX,XX @@ GEN_LDST_WHOLE_TRANS(vs8r_v, 8) *** Vector Integer Arithmetic Instructions */ -/* - * MAXSZ returns the maximum vector size can be operated in bytes, - * which is used in GVEC IR when vl_eq_vlmax flag is set to true - * to accelerate vector operation. - */ -static inline uint32_t MAXSZ(DisasContext *s) -{ - int max_sz = s->cfg_ptr->vlenb * 8; - return max_sz >> (3 - s->lmul); -} - static bool opivv_check(DisasContext *s, arg_rmrr *a) { return require_rvv(s) && -- 2.49.0
From: Sebastian Huber <sebastian.huber@embedded-brains.de> Signed-off-by: Sebastian Huber <sebastian.huber@embedded-brains.de> Acked-by: Alistair Francis <alistair.francis@wdc.com> Message-ID: <20250319061342.26435-2-sebastian.huber@embedded-brains.de> Signed-off-by: Alistair Francis <alistair.francis@wdc.com> --- hw/misc/mchp_pfsoc_sysreg.c | 7 +++++++ 1 file changed, 7 insertions(+) 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/irq.h" #include "hw/sysbus.h" #include "hw/misc/mchp_pfsoc_sysreg.h" +#include "system/runstate.h" +#define MSS_RESET_CR 0x18 #define ENVM_CR 0xb8 #define MESSAGE_INT 0x118c @@ -XXX,XX +XXX,XX @@ static void mchp_pfsoc_sysreg_write(void *opaque, hwaddr offset, { MchpPfSoCSysregState *s = opaque; switch (offset) { + case MSS_RESET_CR: + if (value == 0xdead) { + qemu_system_reset_request(SHUTDOWN_CAUSE_GUEST_RESET); + } + break; case MESSAGE_INT: qemu_irq_lower(s->irq); break; -- 2.49.0
From: Sebastian Huber <sebastian.huber@embedded-brains.de> If the kernel entry is in the high DRAM area, place the FDT into this area. Signed-off-by: Sebastian Huber <sebastian.huber@embedded-brains.de> Reviewed-by: Alistair Francis <alistair.francis@wdc.com> Message-ID: <20250319061342.26435-3-sebastian.huber@embedded-brains.de> Signed-off-by: Alistair Francis <alistair.francis@wdc.com> --- hw/riscv/microchip_pfsoc.c | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/hw/riscv/microchip_pfsoc.c b/hw/riscv/microchip_pfsoc.c index XXXXXXX..XXXXXXX 100644 --- a/hw/riscv/microchip_pfsoc.c +++ b/hw/riscv/microchip_pfsoc.c @@ -XXX,XX +XXX,XX @@ static void microchip_icicle_kit_machine_init(MachineState *machine) kernel_entry = boot_info.image_low_addr; /* Compute the fdt load address in dram */ - fdt_load_addr = riscv_compute_fdt_addr(memmap[MICROCHIP_PFSOC_DRAM_LO].base, - memmap[MICROCHIP_PFSOC_DRAM_LO].size, + hwaddr kernel_ram_base = memmap[MICROCHIP_PFSOC_DRAM_LO].base; + hwaddr kernel_ram_size = memmap[MICROCHIP_PFSOC_DRAM_LO].size; + + if (kernel_entry - kernel_ram_base >= kernel_ram_size) { + kernel_ram_base = memmap[MICROCHIP_PFSOC_DRAM_HI].base; + kernel_ram_size = mem_high_size; + } + + fdt_load_addr = riscv_compute_fdt_addr(kernel_ram_base, kernel_ram_size, machine, &boot_info); riscv_load_fdt(fdt_load_addr, machine->fdt); -- 2.49.0
From: Sebastian Huber <sebastian.huber@embedded-brains.de> Real-time kernels such as RTEMS or Zephyr may use a static device tree built into the kernel image. Do not require to use the -dtb option if -kernel is used for the microchip-icicle-kit machine. Issue a warning if no device tree is provided by the user since the machine does not generate one. Signed-off-by: Sebastian Huber <sebastian.huber@embedded-brains.de> Reviewed-by: Alistair Francis <alistair.francis@wdc.com> Message-ID: <20250319061342.26435-4-sebastian.huber@embedded-brains.de> Signed-off-by: Alistair Francis <alistair.francis@wdc.com> --- hw/riscv/microchip_pfsoc.c | 56 +++++++++++++++++++------------------- 1 file changed, 28 insertions(+), 28 deletions(-) diff --git a/hw/riscv/microchip_pfsoc.c b/hw/riscv/microchip_pfsoc.c index XXXXXXX..XXXXXXX 100644 --- a/hw/riscv/microchip_pfsoc.c +++ b/hw/riscv/microchip_pfsoc.c @@ -XXX,XX +XXX,XX @@ static void microchip_icicle_kit_machine_init(MachineState *machine) uint64_t mem_low_size, mem_high_size; hwaddr firmware_load_addr; const char *firmware_name; - bool kernel_as_payload = false; target_ulong firmware_end_addr, kernel_start_addr; uint64_t kernel_entry; uint64_t fdt_load_addr; @@ -XXX,XX +XXX,XX @@ static void microchip_icicle_kit_machine_init(MachineState *machine) * * This ensures backwards compatibility with how we used to expose -bios * to users but allows them to run through direct kernel booting as well. - * - * When -kernel is used for direct boot, -dtb must be present to provide - * a valid device tree for the board, as we don't generate device tree. */ - if (machine->kernel_filename && machine->dtb) { - int fdt_size; - machine->fdt = load_device_tree(machine->dtb, &fdt_size); - if (!machine->fdt) { - error_report("load_device_tree() failed"); - exit(1); - } - + if (machine->kernel_filename) { firmware_name = RISCV64_BIOS_BIN; firmware_load_addr = memmap[MICROCHIP_PFSOC_DRAM_LO].base; - kernel_as_payload = true; - } - - if (!kernel_as_payload) { + } else { firmware_name = BIOS_FILENAME; firmware_load_addr = RESET_VECTOR; } @@ -XXX,XX +XXX,XX @@ static void microchip_icicle_kit_machine_init(MachineState *machine) &firmware_load_addr, NULL); riscv_boot_info_init(&boot_info, &s->soc.u_cpus); - if (kernel_as_payload) { + if (machine->kernel_filename) { kernel_start_addr = riscv_calc_kernel_start_addr(&boot_info, firmware_end_addr); @@ -XXX,XX +XXX,XX @@ static void microchip_icicle_kit_machine_init(MachineState *machine) true, NULL); kernel_entry = boot_info.image_low_addr; - /* Compute the fdt load address in dram */ - hwaddr kernel_ram_base = memmap[MICROCHIP_PFSOC_DRAM_LO].base; - hwaddr kernel_ram_size = memmap[MICROCHIP_PFSOC_DRAM_LO].size; - - if (kernel_entry - kernel_ram_base >= kernel_ram_size) { - kernel_ram_base = memmap[MICROCHIP_PFSOC_DRAM_HI].base; - kernel_ram_size = mem_high_size; + if (machine->dtb) { + int fdt_size; + machine->fdt = load_device_tree(machine->dtb, &fdt_size); + if (!machine->fdt) { + error_report("load_device_tree() failed"); + exit(1); + } + + /* Compute the FDT load address in DRAM */ + hwaddr kernel_ram_base = memmap[MICROCHIP_PFSOC_DRAM_LO].base; + hwaddr kernel_ram_size = memmap[MICROCHIP_PFSOC_DRAM_LO].size; + + if (kernel_entry - kernel_ram_base >= kernel_ram_size) { + kernel_ram_base = memmap[MICROCHIP_PFSOC_DRAM_HI].base; + kernel_ram_size = mem_high_size; + } + + fdt_load_addr = riscv_compute_fdt_addr(kernel_ram_base, kernel_ram_size, + machine, &boot_info); + riscv_load_fdt(fdt_load_addr, machine->fdt); + } else { + warn_report_once("The QEMU microchip-icicle-kit machine does not " + "generate a device tree, so no device tree is " + "being provided to the guest."); + fdt_load_addr = 0; } - fdt_load_addr = riscv_compute_fdt_addr(kernel_ram_base, kernel_ram_size, - machine, &boot_info); - riscv_load_fdt(fdt_load_addr, machine->fdt); - /* Load the reset vector */ riscv_setup_rom_reset_vec(machine, &s->soc.u_cpus, firmware_load_addr, memmap[MICROCHIP_PFSOC_ENVM_DATA].base, -- 2.49.0
From: Sebastian Huber <sebastian.huber@embedded-brains.de> Further customize the -bios and -kernel options behaviour for the microchip-icicle-kit machine. If "-bios none -kernel filename" is specified, then do not load a firmware and instead only load and start the kernel image. For test runs, use an approach similar to riscv_find_and_load_firmware(). Signed-off-by: Sebastian Huber <sebastian.huber@embedded-brains.de> Reviewed-by: Alistair Francis <alistair.francis@wdc.com> Message-ID: <20250319061342.26435-5-sebastian.huber@embedded-brains.de> Signed-off-by: Alistair Francis <alistair.francis@wdc.com> --- hw/riscv/microchip_pfsoc.c | 59 +++++++++++++++++++++++++++----------- 1 file changed, 42 insertions(+), 17 deletions(-) diff --git a/hw/riscv/microchip_pfsoc.c b/hw/riscv/microchip_pfsoc.c index XXXXXXX..XXXXXXX 100644 --- a/hw/riscv/microchip_pfsoc.c +++ b/hw/riscv/microchip_pfsoc.c @@ -XXX,XX +XXX,XX @@ static void microchip_icicle_kit_machine_init(MachineState *machine) } /* - * We follow the following table to select which payload we execute. + * We follow the following table to select which firmware we use. * - * -bios | -kernel | payload - * -------+------------+-------- - * N | N | HSS - * Y | don't care | HSS - * N | Y | kernel - * - * This ensures backwards compatibility with how we used to expose -bios - * to users but allows them to run through direct kernel booting as well. + * -bios | -kernel | firmware + * --------------+------------+-------- + * none | N | error + * none | Y | kernel + * NULL, default | N | BIOS_FILENAME + * NULL, default | Y | RISCV64_BIOS_BIN + * other | don't care | other */ + if (machine->firmware && !strcmp(machine->firmware, "none")) { + if (!machine->kernel_filename) { + error_report("for -bios none, a kernel is required"); + exit(1); + } - if (machine->kernel_filename) { - firmware_name = RISCV64_BIOS_BIN; - firmware_load_addr = memmap[MICROCHIP_PFSOC_DRAM_LO].base; + firmware_name = NULL; + firmware_load_addr = RESET_VECTOR; + } else if (!machine->firmware || !strcmp(machine->firmware, "default")) { + if (machine->kernel_filename) { + firmware_name = RISCV64_BIOS_BIN; + firmware_load_addr = memmap[MICROCHIP_PFSOC_DRAM_LO].base; + } else { + firmware_name = BIOS_FILENAME; + firmware_load_addr = RESET_VECTOR; + } } else { - firmware_name = BIOS_FILENAME; + firmware_name = machine->firmware; firmware_load_addr = RESET_VECTOR; } - /* Load the firmware */ - firmware_end_addr = riscv_find_and_load_firmware(machine, firmware_name, - &firmware_load_addr, NULL); + /* Load the firmware if necessary */ + firmware_end_addr = firmware_load_addr; + if (firmware_name) { + char *filename = riscv_find_firmware(firmware_name, NULL); + if (filename) { + firmware_end_addr = riscv_load_firmware(filename, + &firmware_load_addr, NULL); + g_free(filename); + } + } riscv_boot_info_init(&boot_info, &s->soc.u_cpus); if (machine->kernel_filename) { @@ -XXX,XX +XXX,XX @@ static void microchip_icicle_kit_machine_init(MachineState *machine) fdt_load_addr = 0; } + hwaddr start_addr; + if (firmware_name) { + start_addr = firmware_load_addr; + } else { + start_addr = kernel_entry; + } + /* Load the reset vector */ - riscv_setup_rom_reset_vec(machine, &s->soc.u_cpus, firmware_load_addr, + riscv_setup_rom_reset_vec(machine, &s->soc.u_cpus, start_addr, memmap[MICROCHIP_PFSOC_ENVM_DATA].base, memmap[MICROCHIP_PFSOC_ENVM_DATA].size, kernel_entry, fdt_load_addr); -- 2.49.0
From: Sebastian Huber <sebastian.huber@embedded-brains.de> This property enables the setting of the CLINT timebase frequency through the command line, for example: -machine microchip-icicle-kit,clint-timebase-frequency=10000000 Signed-off-by: Sebastian Huber <sebastian.huber@embedded-brains.de> Reviewed-by: Philippe Mathieu-Daudé <philmd@linaro.org> Reviewed-by: Alistair Francis <alistair.francis@wdc.com> Message-ID: <20250319061342.26435-6-sebastian.huber@embedded-brains.de> Signed-off-by: Alistair Francis <alistair.francis@wdc.com> --- include/hw/riscv/microchip_pfsoc.h | 1 + hw/riscv/microchip_pfsoc.c | 49 +++++++++++++++++++++++++++--- 2 files changed, 46 insertions(+), 4 deletions(-) diff --git a/include/hw/riscv/microchip_pfsoc.h b/include/hw/riscv/microchip_pfsoc.h index XXXXXXX..XXXXXXX 100644 --- a/include/hw/riscv/microchip_pfsoc.h +++ b/include/hw/riscv/microchip_pfsoc.h @@ -XXX,XX +XXX,XX @@ typedef struct MicrochipIcicleKitState { MachineState parent_obj; /*< public >*/ + uint32_t clint_timebase_freq; MicrochipPFSoCState soc; } MicrochipIcicleKitState; diff --git a/hw/riscv/microchip_pfsoc.c b/hw/riscv/microchip_pfsoc.c index XXXXXXX..XXXXXXX 100644 --- a/hw/riscv/microchip_pfsoc.c +++ b/hw/riscv/microchip_pfsoc.c @@ -XXX,XX +XXX,XX @@ #include "qemu/units.h" #include "qemu/cutils.h" #include "qapi/error.h" +#include "qapi/visitor.h" #include "hw/boards.h" #include "hw/loader.h" #include "hw/sysbus.h" @@ -XXX,XX +XXX,XX @@ #define BIOS_FILENAME "hss.bin" #define RESET_VECTOR 0x20220000 -/* CLINT timebase frequency */ -#define CLINT_TIMEBASE_FREQ 1000000 - /* GEM version */ #define GEM_REVISION 0x0107010c @@ -XXX,XX +XXX,XX @@ static void microchip_pfsoc_soc_instance_init(Object *obj) static void microchip_pfsoc_soc_realize(DeviceState *dev, Error **errp) { MachineState *ms = MACHINE(qdev_get_machine()); + MicrochipIcicleKitState *iks = MICROCHIP_ICICLE_KIT_MACHINE(ms); MicrochipPFSoCState *s = MICROCHIP_PFSOC(dev); const MemMapEntry *memmap = microchip_pfsoc_memmap; MemoryRegion *system_memory = get_system_memory(); @@ -XXX,XX +XXX,XX @@ static void microchip_pfsoc_soc_realize(DeviceState *dev, Error **errp) memmap[MICROCHIP_PFSOC_CLINT].base + RISCV_ACLINT_SWI_SIZE, RISCV_ACLINT_DEFAULT_MTIMER_SIZE, 0, ms->smp.cpus, RISCV_ACLINT_DEFAULT_MTIMECMP, RISCV_ACLINT_DEFAULT_MTIME, - CLINT_TIMEBASE_FREQ, false); + iks->clint_timebase_freq, false); /* L2 cache controller */ create_unimplemented_device("microchip.pfsoc.l2cc", @@ -XXX,XX +XXX,XX @@ static void microchip_icicle_kit_machine_init(MachineState *machine) } } +static void microchip_icicle_kit_set_clint_timebase_freq(Object *obj, + Visitor *v, + const char *name, + void *opaque, + Error **errp) +{ + MicrochipIcicleKitState *s = MICROCHIP_ICICLE_KIT_MACHINE(obj); + uint32_t value; + + if (!visit_type_uint32(v, name, &value, errp)) { + return; + } + + s->clint_timebase_freq = value; +} + +static void microchip_icicle_kit_get_clint_timebase_freq(Object *obj, + Visitor *v, + const char *name, + void *opaque, + Error **errp) +{ + MicrochipIcicleKitState *s = MICROCHIP_ICICLE_KIT_MACHINE(obj); + uint32_t value = s->clint_timebase_freq; + + visit_type_uint32(v, name, &value, errp); +} + +static void microchip_icicle_kit_machine_instance_init(Object *obj) +{ + MicrochipIcicleKitState *m = MICROCHIP_ICICLE_KIT_MACHINE(obj); + m->clint_timebase_freq = 1000000; +} + static void microchip_icicle_kit_machine_class_init(ObjectClass *oc, const void *data) { @@ -XXX,XX +XXX,XX @@ static void microchip_icicle_kit_machine_class_init(ObjectClass *oc, * See memory_tests() in mss_ddr.c in the HSS source code. */ mc->default_ram_size = 1537 * MiB; + + object_class_property_add(oc, "clint-timebase-frequency", "uint32_t", + microchip_icicle_kit_get_clint_timebase_freq, + microchip_icicle_kit_set_clint_timebase_freq, + NULL, NULL); + object_class_property_set_description(oc, "clint-timebase-frequency", + "Set CLINT timebase frequency in Hz."); } static const TypeInfo microchip_icicle_kit_machine_typeinfo = { .name = MACHINE_TYPE_NAME("microchip-icicle-kit"), .parent = TYPE_MACHINE, .class_init = microchip_icicle_kit_machine_class_init, + .instance_init = microchip_icicle_kit_machine_instance_init, .instance_size = sizeof(MicrochipIcicleKitState), }; -- 2.49.0
From: Sebastian Huber <sebastian.huber@embedded-brains.de> Mention that running the HSS no longer works. Document the changed boot options. Reorder documentation blocks. Update URLs. Signed-off-by: Sebastian Huber <sebastian.huber@embedded-brains.de> Reviewed-by: Alistair Francis <alistair.francis@wdc.com> Message-ID: <20250319061342.26435-7-sebastian.huber@embedded-brains.de> Signed-off-by: Alistair Francis <alistair.francis@wdc.com> --- docs/system/riscv/microchip-icicle-kit.rst | 124 +++++++-------------- 1 file changed, 43 insertions(+), 81 deletions(-) diff --git a/docs/system/riscv/microchip-icicle-kit.rst b/docs/system/riscv/microchip-icicle-kit.rst index XXXXXXX..XXXXXXX 100644 --- a/docs/system/riscv/microchip-icicle-kit.rst +++ b/docs/system/riscv/microchip-icicle-kit.rst @@ -XXX,XX +XXX,XX @@ Microchip PolarFire SoC Icicle Kit integrates a PolarFire SoC, with one SiFive's E51 plus four U54 cores and many on-chip peripherals and an FPGA. For more details about Microchip PolarFire SoC, please see: -https://www.microsemi.com/product-directory/soc-fpgas/5498-polarfire-soc-fpga +https://www.microchip.com/en-us/products/fpgas-and-plds/system-on-chip-fpgas/polarfire-soc-fpgas The Icicle Kit board information can be found here: -https://www.microsemi.com/existing-parts/parts/152514 +https://www.microchip.com/en-us/development-tool/mpfs-icicle-kit-es Supported devices ----------------- @@ -XXX,XX +XXX,XX @@ The ``microchip-icicle-kit`` machine supports the following devices: * 2 GEM Ethernet controllers * 1 SDHC storage controller +The memory is set to 1537 MiB by default. A sanity check on RAM size is +performed in the machine init routine to prompt user to increase the RAM size +to > 1537 MiB when less than 1537 MiB RAM is detected. + Boot options ------------ -The ``microchip-icicle-kit`` machine can start using the standard -bios -functionality for loading its BIOS image, aka Hart Software Services (HSS_). -HSS loads the second stage bootloader U-Boot from an SD card. Then a kernel -can be loaded from U-Boot. It also supports direct kernel booting via the --kernel option along with the device tree blob via -dtb. When direct kernel -boot is used, the OpenSBI fw_dynamic BIOS image is used to boot a payload -like U-Boot or OS kernel directly. - -The user provided DTB should have the following requirements: - -* The /cpus node should contain at least one subnode for E51 and the number - of subnodes should match QEMU's ``-smp`` option -* The /memory reg size should match QEMU’s selected ram_size via ``-m`` -* Should contain a node for the CLINT device with a compatible string - "riscv,clint0" - -QEMU follows below truth table to select which payload to execute: - -===== ========== ========== ======= --bios -kernel -dtb payload -===== ========== ========== ======= - N N don't care HSS - Y don't care don't care HSS - N Y Y kernel -===== ========== ========== ======= - -The memory is set to 1537 MiB by default which is the minimum required high -memory size by HSS. A sanity check on ram size is performed in the machine -init routine to prompt user to increase the RAM size to > 1537 MiB when less -than 1537 MiB ram is detected. - -Running HSS ------------ - -HSS 2020.12 release is tested at the time of writing. To build an HSS image -that can be booted by the ``microchip-icicle-kit`` machine, type the following -in the HSS source tree: - -.. code-block:: bash - - $ export CROSS_COMPILE=riscv64-linux- - $ cp boards/mpfs-icicle-kit-es/def_config .config - $ make BOARD=mpfs-icicle-kit-es - -Download the official SD card image released by Microchip and prepare it for -QEMU usage: - -.. code-block:: bash - - $ wget ftp://ftpsoc.microsemi.com/outgoing/core-image-minimal-dev-icicle-kit-es-sd-20201009141623.rootfs.wic.gz - $ gunzip core-image-minimal-dev-icicle-kit-es-sd-20201009141623.rootfs.wic.gz - $ qemu-img resize core-image-minimal-dev-icicle-kit-es-sd-20201009141623.rootfs.wic 4G - -Then we can boot the machine by: - -.. code-block:: bash - - $ qemu-system-riscv64 -M microchip-icicle-kit -smp 5 \ - -bios path/to/hss.bin -sd path/to/sdcard.img \ - -nic user,model=cadence_gem \ - -nic tap,ifname=tap,model=cadence_gem,script=no \ - -display none -serial stdio \ - -chardev socket,id=serial1,path=serial1.sock,server=on,wait=on \ - -serial chardev:serial1 +The ``microchip-icicle-kit`` machine provides some options to run a firmware +(BIOS) or a kernel image. QEMU follows below truth table to select the +firmware: -With above command line, current terminal session will be used for the first -serial port. Open another terminal window, and use ``minicom`` to connect the -second serial port. +============= =========== ====================================== +-bios -kernel firmware +============= =========== ====================================== +none N this is an error +none Y the kernel image +NULL, default N hss.bin +NULL, default Y opensbi-riscv64-generic-fw_dynamic.bin +other don't care the BIOS image +============= =========== ====================================== -.. code-block:: bash +Direct Kernel Boot +------------------ - $ minicom -D unix\#serial1.sock +Use the ``-kernel`` option to directly run a kernel image. When a direct +kernel boot is requested, a device tree blob may be specified via the ``-dtb`` +option. Unlike other QEMU machines, this machine does not generate a device +tree for the kernel. It shall be provided by the user. The user provided DTB +should meet the following requirements: -HSS output is on the first serial port (stdio) and U-Boot outputs on the -second serial port. U-Boot will automatically load the Linux kernel from -the SD card image. +* The ``/cpus`` node should contain at least one subnode for E51 and the number + of subnodes should match QEMU's ``-smp`` option. -Direct Kernel Boot ------------------- +* The ``/memory`` reg size should match QEMU’s selected RAM size via the ``-m`` + option. -Sometimes we just want to test booting a new kernel, and transforming the -kernel image to the format required by the HSS bootflow is tedious. We can -use '-kernel' for direct kernel booting just like other RISC-V machines do. +* It should contain a node for the CLINT device with a compatible string + "riscv,clint0". -In this mode, the OpenSBI fw_dynamic BIOS image for 'generic' platform is -used to boot an S-mode payload like U-Boot or OS kernel directly. +When ``-bios`` is not specified or set to ``default``, the OpenSBI +``fw_dynamic`` BIOS image for the ``generic`` platform is used to boot an +S-mode payload like U-Boot or OS kernel directly. For example, the following commands show building a U-Boot image from U-Boot mainline v2021.07 for the Microchip Icicle Kit board: @@ -XXX,XX +XXX,XX @@ CAVEATS: ``u-boot.bin`` has to be used which does contain one. To use the ELF image, we need to change to CONFIG_OF_EMBED or CONFIG_OF_PRIOR_STAGE. +Running HSS +----------- + +The machine ``microchip-icicle-kit`` used to run the Hart Software Services +(HSS_), however, the HSS development progressed and the QEMU machine +implementation lacks behind. Currently, running the HSS no longer works. +There is missing support in the clock and memory controller devices. In +particular, reading from the SD card does not work. + .. _HSS: https://github.com/polarfire-soc/hart-software-services -- 2.49.0
From: Paolo Savini <paolo.savini@embecosm.com> This patch replaces the use of a helper function with direct tcg ops generation in order to emulate whole register loads and stores. This is done in order to improve the performance of QEMU. We still use the helper function when vstart is not 0 at the beginning of the emulation of the whole register load or store or when we would end up generating partial loads or stores of vector elements (e.g. emulating 64 bits element loads with pairs of 32 bits loads on hosts with 32 bits registers). The latter condition ensures that we are not surprised by a trap in mid-element and consecutively that we can update vstart correctly. We also use the helper function when it performs better than tcg for specific combinations of vector length, number of fields and element size. Signed-off-by: Paolo Savini <paolo.savini@embecosm.com> Reviewed-by: Daniel Henrique Barboza <dbarboza@ventanamicro.com> Reviewed-by: Richard Handerson <richard.henderson@linaro.org> Reviewed-by: Max Chou <max.chou@sifive.com> Reviewed-by: "Alex Bennée" <alex.bennee@linaro.org> Message-ID: <20250313152330.398396-2-paolo.savini@embecosm.com> Signed-off-by: Alistair Francis <alistair.francis@wdc.com> --- target/riscv/insn_trans/trans_rvv.c.inc | 155 +++++++++++++++++------- 1 file changed, 108 insertions(+), 47 deletions(-) diff --git a/target/riscv/insn_trans/trans_rvv.c.inc b/target/riscv/insn_trans/trans_rvv.c.inc index XXXXXXX..XXXXXXX 100644 --- a/target/riscv/insn_trans/trans_rvv.c.inc +++ b/target/riscv/insn_trans/trans_rvv.c.inc @@ -XXX,XX +XXX,XX @@ GEN_VEXT_TRANS(vle64ff_v, MO_64, r2nfvm, ldff_op, ld_us_check) typedef void gen_helper_ldst_whole(TCGv_ptr, TCGv, TCGv_env, TCGv_i32); static bool ldst_whole_trans(uint32_t vd, uint32_t rs1, uint32_t nf, - gen_helper_ldst_whole *fn, - DisasContext *s) + uint32_t log2_esz, gen_helper_ldst_whole *fn, + DisasContext *s, bool is_load) { - TCGv_ptr dest; - TCGv base; - TCGv_i32 desc; - - uint32_t data = FIELD_DP32(0, VDATA, NF, nf); - data = FIELD_DP32(data, VDATA, VM, 1); - dest = tcg_temp_new_ptr(); - desc = tcg_constant_i32(simd_desc(s->cfg_ptr->vlenb, - s->cfg_ptr->vlenb, data)); - - base = get_gpr(s, rs1, EXT_NONE); - tcg_gen_addi_ptr(dest, tcg_env, vreg_ofs(s, vd)); - mark_vs_dirty(s); - fn(dest, base, tcg_env, desc); + /* + * Load/store multiple bytes per iteration. + * When possible do this atomically. + * Update vstart with the number of processed elements. + * Use the helper function if either: + * - vstart is not 0. + * - the target has 32 bit registers and we are loading/storing 64 bit long + * elements. This is to ensure that we process every element with a single + * memory instruction. + */ + + bool use_helper_fn = !(s->vstart_eq_zero) || + (TCG_TARGET_REG_BITS == 32 && log2_esz == 3); + + if (!use_helper_fn) { + TCGv addr = tcg_temp_new(); + uint32_t size = s->cfg_ptr->vlenb * nf; + TCGv_i64 t8 = tcg_temp_new_i64(); + TCGv_i32 t4 = tcg_temp_new_i32(); + MemOp atomicity = MO_ATOM_NONE; + if (log2_esz == 0) { + atomicity = MO_ATOM_NONE; + } else { + atomicity = MO_ATOM_IFALIGN_PAIR; + } + if (TCG_TARGET_REG_BITS == 64) { + for (int i = 0; i < size; i += 8) { + addr = get_address(s, rs1, i); + if (is_load) { + tcg_gen_qemu_ld_i64(t8, addr, s->mem_idx, + MO_LE | MO_64 | atomicity); + tcg_gen_st_i64(t8, tcg_env, vreg_ofs(s, vd) + i); + } else { + tcg_gen_ld_i64(t8, tcg_env, vreg_ofs(s, vd) + i); + tcg_gen_qemu_st_i64(t8, addr, s->mem_idx, + MO_LE | MO_64 | atomicity); + } + if (i == size - 8) { + tcg_gen_movi_tl(cpu_vstart, 0); + } else { + tcg_gen_addi_tl(cpu_vstart, cpu_vstart, 8 >> log2_esz); + } + } + } else { + for (int i = 0; i < size; i += 4) { + addr = get_address(s, rs1, i); + if (is_load) { + tcg_gen_qemu_ld_i32(t4, addr, s->mem_idx, + MO_LE | MO_32 | atomicity); + tcg_gen_st_i32(t4, tcg_env, vreg_ofs(s, vd) + i); + } else { + tcg_gen_ld_i32(t4, tcg_env, vreg_ofs(s, vd) + i); + tcg_gen_qemu_st_i32(t4, addr, s->mem_idx, + MO_LE | MO_32 | atomicity); + } + if (i == size - 4) { + tcg_gen_movi_tl(cpu_vstart, 0); + } else { + tcg_gen_addi_tl(cpu_vstart, cpu_vstart, 4 >> log2_esz); + } + } + } + } else { + TCGv_ptr dest; + TCGv base; + TCGv_i32 desc; + uint32_t data = FIELD_DP32(0, VDATA, NF, nf); + data = FIELD_DP32(data, VDATA, VM, 1); + dest = tcg_temp_new_ptr(); + desc = tcg_constant_i32(simd_desc(s->cfg_ptr->vlenb, + s->cfg_ptr->vlenb, data)); + base = get_gpr(s, rs1, EXT_NONE); + tcg_gen_addi_ptr(dest, tcg_env, vreg_ofs(s, vd)); + fn(dest, base, tcg_env, desc); + } finalize_rvv_inst(s); return true; @@ -XXX,XX +XXX,XX @@ static bool ldst_whole_trans(uint32_t vd, uint32_t rs1, uint32_t nf, * load and store whole register instructions ignore vtype and vl setting. * Thus, we don't need to check vill bit. (Section 7.9) */ -#define GEN_LDST_WHOLE_TRANS(NAME, ARG_NF) \ -static bool trans_##NAME(DisasContext *s, arg_##NAME * a) \ -{ \ - if (require_rvv(s) && \ - QEMU_IS_ALIGNED(a->rd, ARG_NF)) { \ - return ldst_whole_trans(a->rd, a->rs1, ARG_NF, \ - gen_helper_##NAME, s); \ - } \ - return false; \ -} - -GEN_LDST_WHOLE_TRANS(vl1re8_v, 1) -GEN_LDST_WHOLE_TRANS(vl1re16_v, 1) -GEN_LDST_WHOLE_TRANS(vl1re32_v, 1) -GEN_LDST_WHOLE_TRANS(vl1re64_v, 1) -GEN_LDST_WHOLE_TRANS(vl2re8_v, 2) -GEN_LDST_WHOLE_TRANS(vl2re16_v, 2) -GEN_LDST_WHOLE_TRANS(vl2re32_v, 2) -GEN_LDST_WHOLE_TRANS(vl2re64_v, 2) -GEN_LDST_WHOLE_TRANS(vl4re8_v, 4) -GEN_LDST_WHOLE_TRANS(vl4re16_v, 4) -GEN_LDST_WHOLE_TRANS(vl4re32_v, 4) -GEN_LDST_WHOLE_TRANS(vl4re64_v, 4) -GEN_LDST_WHOLE_TRANS(vl8re8_v, 8) -GEN_LDST_WHOLE_TRANS(vl8re16_v, 8) -GEN_LDST_WHOLE_TRANS(vl8re32_v, 8) -GEN_LDST_WHOLE_TRANS(vl8re64_v, 8) +#define GEN_LDST_WHOLE_TRANS(NAME, ETYPE, ARG_NF, IS_LOAD) \ +static bool trans_##NAME(DisasContext *s, arg_##NAME * a) \ +{ \ + if (require_rvv(s) && \ + QEMU_IS_ALIGNED(a->rd, ARG_NF)) { \ + return ldst_whole_trans(a->rd, a->rs1, ARG_NF, ctzl(sizeof(ETYPE)), \ + gen_helper_##NAME, s, IS_LOAD); \ + } \ + return false; \ +} + +GEN_LDST_WHOLE_TRANS(vl1re8_v, int8_t, 1, true) +GEN_LDST_WHOLE_TRANS(vl1re16_v, int16_t, 1, true) +GEN_LDST_WHOLE_TRANS(vl1re32_v, int32_t, 1, true) +GEN_LDST_WHOLE_TRANS(vl1re64_v, int64_t, 1, true) +GEN_LDST_WHOLE_TRANS(vl2re8_v, int8_t, 2, true) +GEN_LDST_WHOLE_TRANS(vl2re16_v, int16_t, 2, true) +GEN_LDST_WHOLE_TRANS(vl2re32_v, int32_t, 2, true) +GEN_LDST_WHOLE_TRANS(vl2re64_v, int64_t, 2, true) +GEN_LDST_WHOLE_TRANS(vl4re8_v, int8_t, 4, true) +GEN_LDST_WHOLE_TRANS(vl4re16_v, int16_t, 4, true) +GEN_LDST_WHOLE_TRANS(vl4re32_v, int32_t, 4, true) +GEN_LDST_WHOLE_TRANS(vl4re64_v, int64_t, 4, true) +GEN_LDST_WHOLE_TRANS(vl8re8_v, int8_t, 8, true) +GEN_LDST_WHOLE_TRANS(vl8re16_v, int16_t, 8, true) +GEN_LDST_WHOLE_TRANS(vl8re32_v, int32_t, 8, true) +GEN_LDST_WHOLE_TRANS(vl8re64_v, int64_t, 8, true) /* * The vector whole register store instructions are encoded similar to * unmasked unit-stride store of elements with EEW=8. */ -GEN_LDST_WHOLE_TRANS(vs1r_v, 1) -GEN_LDST_WHOLE_TRANS(vs2r_v, 2) -GEN_LDST_WHOLE_TRANS(vs4r_v, 4) -GEN_LDST_WHOLE_TRANS(vs8r_v, 8) +GEN_LDST_WHOLE_TRANS(vs1r_v, int8_t, 1, false) +GEN_LDST_WHOLE_TRANS(vs2r_v, int8_t, 2, false) +GEN_LDST_WHOLE_TRANS(vs4r_v, int8_t, 4, false) +GEN_LDST_WHOLE_TRANS(vs8r_v, int8_t, 8, false) /* *** Vector Integer Arithmetic Instructions -- 2.49.0
From: Paolo Savini <paolo.savini@embecosm.com> This commit expands the probe_pages helper function in target/riscv/vector_helper.c to handle also the cases in which we need access to the flags raised while probing the memory and the host address. This is done in order to provide a unified interface to probe_access and probe_access_flags. The new version of probe_pages can now act as a regular call to probe_access as before and as a call to probe_access_flags. In the latter case the user need to pass pointers to flags and host address and a boolean value for nonfault. The flags and host address will be set and made available as for a direct call to probe_access_flags. Signed-off-by: Paolo Savini <paolo.savini@embecosm.com> Reviewed-by: Daniel Henrique Barboza <dbarboza@ventanamicro.com> Message-ID: <20250313123926.374878-2-paolo.savini@embecosm.com> Signed-off-by: Alistair Francis <alistair.francis@wdc.com> --- target/riscv/vector_helper.c | 57 +++++++++++++++++++++++------------- 1 file changed, 37 insertions(+), 20 deletions(-) diff --git a/target/riscv/vector_helper.c b/target/riscv/vector_helper.c index XXXXXXX..XXXXXXX 100644 --- a/target/riscv/vector_helper.c +++ b/target/riscv/vector_helper.c @@ -XXX,XX +XXX,XX @@ static inline uint32_t vext_max_elems(uint32_t desc, uint32_t log2_esz) * It will trigger an exception if there is no mapping in TLB * and page table walk can't fill the TLB entry. Then the guest * software can return here after process the exception or never return. + * + * This function can also be used when direct access to probe_access_flags is + * needed in order to access the flags. If a pointer to a flags operand is + * provided the function will call probe_access_flags instead, use nonfault + * and update host and flags. */ -static void probe_pages(CPURISCVState *env, target_ulong addr, - target_ulong len, uintptr_t ra, - MMUAccessType access_type) +static void probe_pages(CPURISCVState *env, target_ulong addr, target_ulong len, + uintptr_t ra, MMUAccessType access_type, int mmu_index, + void **host, int *flags, bool nonfault) { target_ulong pagelen = -(addr | TARGET_PAGE_MASK); target_ulong curlen = MIN(pagelen, len); - int mmu_index = riscv_env_mmu_index(env, false); - probe_access(env, adjust_addr(env, addr), curlen, access_type, - mmu_index, ra); + if (flags != NULL) { + *flags = probe_access_flags(env, adjust_addr(env, addr), curlen, + access_type, mmu_index, nonfault, host, ra); + } else { + probe_access(env, adjust_addr(env, addr), curlen, access_type, + mmu_index, ra); + } + if (len > curlen) { addr += curlen; curlen = len - curlen; - probe_access(env, adjust_addr(env, addr), curlen, access_type, - mmu_index, ra); + if (flags != NULL) { + *flags = probe_access_flags(env, adjust_addr(env, addr), curlen, + access_type, mmu_index, nonfault, + host, ra); + } else { + probe_access(env, adjust_addr(env, addr), curlen, access_type, + mmu_index, ra); + } } } + static inline void vext_set_elem_mask(void *v0, int index, uint8_t value) { @@ -XXX,XX +XXX,XX @@ vext_page_ldst_us(CPURISCVState *env, void *vd, target_ulong addr, MMUAccessType access_type = is_load ? MMU_DATA_LOAD : MMU_DATA_STORE; /* Check page permission/pmp/watchpoint/etc. */ - flags = probe_access_flags(env, adjust_addr(env, addr), size, access_type, - mmu_index, true, &host, ra); + probe_pages(env, addr, size, ra, access_type, mmu_index, &host, &flags, + true); if (flags == 0) { if (nf == 1) { @@ -XXX,XX +XXX,XX @@ vext_ldff(void *vd, void *v0, target_ulong base, CPURISCVState *env, uint32_t vma = vext_vma(desc); target_ulong addr, addr_probe, addr_i, offset, remain, page_split, elems; int mmu_index = riscv_env_mmu_index(env, false); - int flags; + int flags, probe_flags; void *host; VSTART_CHECK_EARLY_EXIT(env, env->vl); @@ -XXX,XX +XXX,XX @@ vext_ldff(void *vd, void *v0, target_ulong base, CPURISCVState *env, } /* Check page permission/pmp/watchpoint/etc. */ - flags = probe_access_flags(env, adjust_addr(env, addr), elems * msize, - MMU_DATA_LOAD, mmu_index, true, &host, ra); + probe_pages(env, addr, elems * msize, ra, MMU_DATA_LOAD, mmu_index, &host, + &flags, true); /* If we are crossing a page check also the second page. */ if (env->vl > elems) { addr_probe = addr + (elems << log2_esz); - flags |= probe_access_flags(env, adjust_addr(env, addr_probe), - elems * msize, MMU_DATA_LOAD, mmu_index, - true, &host, ra); + probe_pages(env, addr_probe, elems * msize, ra, MMU_DATA_LOAD, + mmu_index, &host, &probe_flags, true); + flags |= probe_flags; } if (flags & ~TLB_WATCHPOINT) { @@ -XXX,XX +XXX,XX @@ vext_ldff(void *vd, void *v0, target_ulong base, CPURISCVState *env, addr_i = adjust_addr(env, base + i * (nf << log2_esz)); if (i == 0) { /* Allow fault on first element. */ - probe_pages(env, addr_i, nf << log2_esz, ra, MMU_DATA_LOAD); + probe_pages(env, addr_i, nf << log2_esz, ra, MMU_DATA_LOAD, + mmu_index, &host, NULL, false); } else { remain = nf << log2_esz; while (remain > 0) { offset = -(addr_i | TARGET_PAGE_MASK); /* Probe nonfault on subsequent elements. */ - flags = probe_access_flags(env, addr_i, offset, - MMU_DATA_LOAD, mmu_index, true, - &host, 0); + probe_pages(env, addr_i, offset, 0, MMU_DATA_LOAD, + mmu_index, &host, &flags, true); /* * Stop if invalid (unmapped) or mmio (transaction may -- 2.49.0
From: Paolo Bonzini <pbonzini@redhat.com> qtest_set_command_cb passed to g_once should match GThreadFunc, which it does not. But using g_once is actually unnecessary, because the function is called by riscv_harts_realize() under the Big QEMU Lock. Reported-by: Kohei Tokunaga <ktokunaga.mail@gmail.com> Signed-off-by: Paolo Bonzini <pbonzini@redhat.com> Reviewed-by: Alistair Francis <alistair.francis@wdc.com> Reviewed-by: Kohei Tokunaga <ktokunaga.mail@gmail.com> Reviewed-by: Philippe Mathieu-Daudé <philmd@linaro.org> Message-ID: <20250410161722.595634-1-pbonzini@redhat.com> Signed-off-by: Alistair Francis <alistair.francis@wdc.com> Cc: qemu-stable@nongnu.org --- hw/riscv/riscv_hart.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/hw/riscv/riscv_hart.c b/hw/riscv/riscv_hart.c index XXXXXXX..XXXXXXX 100644 --- a/hw/riscv/riscv_hart.c +++ b/hw/riscv/riscv_hart.c @@ -XXX,XX +XXX,XX @@ static bool csr_qtest_callback(CharBackend *chr, gchar **words) static void riscv_cpu_register_csr_qtest_callback(void) { - static GOnce once; - g_once(&once, (GThreadFunc)qtest_set_command_cb, csr_qtest_callback); + static bool first = true; + if (first) { + first = false; + qtest_set_command_cb(csr_qtest_callback); + } } #endif -- 2.49.0
From: Ziqiao Kong <ziqiaokong@gmail.com> On big endian systems, pte and updated_pte hold big endian host data while pte_pa points to little endian target data. This means the branch at cpu_helper.c:1669 will be always satisfied and restart translation, causing an endless translation loop. The correctness of this patch can be deduced by: old_pte will hold value either from cpu_to_le32/64(pte) or cpu_to_le32/64(updated_pte), both of wich is litte endian. After that, an in-place conversion by le32/64_to_cpu(old_pte) ensures that old_pte now is in native endian, same with pte. Therefore, the endianness of the both side of if (old_pte != pte) is correct. Signed-off-by: Ziqiao Kong <ziqiaokong@gmail.com> Reviewed-by: Alistair Francis <alistair.francis@wdc.com> Reviewed-by: Richard Henderson <richard.henderson@linaro.org> Message-ID: <20250415080254.3667878-2-ziqiaokong@gmail.com> Signed-off-by: Alistair Francis <alistair.francis@wdc.com> Cc: qemu-stable@nongnu.org --- target/riscv/cpu_helper.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/target/riscv/cpu_helper.c b/target/riscv/cpu_helper.c index XXXXXXX..XXXXXXX 100644 --- a/target/riscv/cpu_helper.c +++ b/target/riscv/cpu_helper.c @@ -XXX,XX +XXX,XX @@ static int get_physical_address(CPURISCVState *env, hwaddr *physical, target_ulong *pte_pa = qemu_map_ram_ptr(mr->ram_block, addr1); target_ulong old_pte; if (riscv_cpu_sxl(env) == MXL_RV32) { - old_pte = qatomic_cmpxchg((uint32_t *)pte_pa, pte, updated_pte); + old_pte = qatomic_cmpxchg((uint32_t *)pte_pa, cpu_to_le32(pte), cpu_to_le32(updated_pte)); + old_pte = le32_to_cpu(old_pte); } else { - old_pte = qatomic_cmpxchg(pte_pa, pte, updated_pte); + old_pte = qatomic_cmpxchg(pte_pa, cpu_to_le64(pte), cpu_to_le64(updated_pte)); + old_pte = le64_to_cpu(old_pte); } if (old_pte != pte) { goto restart; -- 2.49.0
From: Icenowy Zheng <uwu@icenowy.me> The j pseudoinstruction maps to a JAL instruction, which can only handle a jump to somewhere with a signed 20-bit destination. In case of static linking and LTO'ing this easily leads to "relocation truncated to fit" error. Switch to use tail pseudoinstruction, which is the standard way to tail-call a function in medium code model (emits AUIPC+JALR). Signed-off-by: Icenowy Zheng <uwu@icenowy.me> Reviewed-by: Richard Henderson <richard.henderson@linaro.org> Message-ID: <20250417072206.364008-1-uwu@icenowy.me> Signed-off-by: Alistair Francis <alistair.francis@wdc.com> Cc: qemu-stable@nongnu.org --- common-user/host/riscv/safe-syscall.inc.S | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/common-user/host/riscv/safe-syscall.inc.S b/common-user/host/riscv/safe-syscall.inc.S index XXXXXXX..XXXXXXX 100644 --- a/common-user/host/riscv/safe-syscall.inc.S +++ b/common-user/host/riscv/safe-syscall.inc.S @@ -XXX,XX +XXX,XX @@ safe_syscall_end: /* code path setting errno */ 0: neg a0, a0 - j safe_syscall_set_errno_tail + tail safe_syscall_set_errno_tail /* code path when we didn't execute the syscall */ 2: li a0, QEMU_ERESTARTSYS - j safe_syscall_set_errno_tail + tail safe_syscall_set_errno_tail .cfi_endproc .size safe_syscall_base, .-safe_syscall_base -- 2.49.0
From: Anton Blanchard <antonb@tenstorrent.com> Add the relevant ISA paragraphs explaining why source (and destination) registers cannot overlap the mask register. Signed-off-by: Anton Blanchard <antonb@tenstorrent.com> Reviewed-by: Daniel Henrique Barboza <dbarboza@ventanamicro.com> Reviewed-by: Max Chou <max.chou@sifive.com> Signed-off-by: Max Chou <max.chou@sifive.com> Message-ID: <20250408103938.3623486-2-max.chou@sifive.com> Signed-off-by: Alistair Francis <alistair.francis@wdc.com> Cc: qemu-stable@nongnu.org --- target/riscv/insn_trans/trans_rvv.c.inc | 29 ++++++++++++++++++++++--- 1 file changed, 26 insertions(+), 3 deletions(-) diff --git a/target/riscv/insn_trans/trans_rvv.c.inc b/target/riscv/insn_trans/trans_rvv.c.inc index XXXXXXX..XXXXXXX 100644 --- a/target/riscv/insn_trans/trans_rvv.c.inc +++ b/target/riscv/insn_trans/trans_rvv.c.inc @@ -XXX,XX +XXX,XX @@ static bool require_scale_rvfmin(DisasContext *s) } } -/* Destination vector register group cannot overlap source mask register. */ -static bool require_vm(int vm, int vd) +/* + * Source and destination vector register groups cannot overlap source mask + * register: + * + * A vector register cannot be used to provide source operands with more than + * one EEW for a single instruction. A mask register source is considered to + * have EEW=1 for this constraint. An encoding that would result in the same + * vector register being read with two or more different EEWs, including when + * the vector register appears at different positions within two or more vector + * register groups, is reserved. + * (Section 5.2) + * + * A destination vector register group can overlap a source vector + * register group only if one of the following holds: + * 1. The destination EEW equals the source EEW. + * 2. The destination EEW is smaller than the source EEW and the overlap + * is in the lowest-numbered part of the source register group. + * 3. The destination EEW is greater than the source EEW, the source EMUL + * is at least 1, and the overlap is in the highest-numbered part of + * the destination register group. + * For the purpose of determining register group overlap constraints, mask + * elements have EEW=1. + * (Section 5.2) + */ +static bool require_vm(int vm, int v) { - return (vm != 0 || vd != 0); + return (vm != 0 || v != 0); } static bool require_nf(int vd, int nf, int lmul) -- 2.49.0
From: Anton Blanchard <antonb@tenstorrent.com> Signed-off-by: Anton Blanchard <antonb@tenstorrent.com> Reviewed-by: Daniel Henrique Barboza <dbarboza@ventanamicro.com> Reviewed-by: Max Chou <max.chou@sifive.com> Signed-off-by: Max Chou <max.chou@sifive.com> Message-ID: <20250408103938.3623486-3-max.chou@sifive.com> Signed-off-by: Alistair Francis <alistair.francis@wdc.com> Cc: qemu-stable@nongnu.org --- target/riscv/insn_trans/trans_rvv.c.inc | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/target/riscv/insn_trans/trans_rvv.c.inc b/target/riscv/insn_trans/trans_rvv.c.inc index XXXXXXX..XXXXXXX 100644 --- a/target/riscv/insn_trans/trans_rvv.c.inc +++ b/target/riscv/insn_trans/trans_rvv.c.inc @@ -XXX,XX +XXX,XX @@ static bool opfvf_widen_check(DisasContext *s, arg_rmrr *a) } /* OPFVF with WIDEN */ -#define GEN_OPFVF_WIDEN_TRANS(NAME) \ +#define GEN_OPFVF_WIDEN_TRANS(NAME, CHECK) \ static bool trans_##NAME(DisasContext *s, arg_rmrr *a) \ { \ - if (opfvf_widen_check(s, a)) { \ + if (CHECK(s, a)) { \ uint32_t data = 0; \ static gen_helper_opfvf *const fns[2] = { \ gen_helper_##NAME##_h, gen_helper_##NAME##_w, \ @@ -XXX,XX +XXX,XX @@ static bool trans_##NAME(DisasContext *s, arg_rmrr *a) \ return false; \ } -GEN_OPFVF_WIDEN_TRANS(vfwadd_vf) -GEN_OPFVF_WIDEN_TRANS(vfwsub_vf) +GEN_OPFVF_WIDEN_TRANS(vfwadd_vf, opfvf_widen_check) +GEN_OPFVF_WIDEN_TRANS(vfwsub_vf, opfvf_widen_check) static bool opfwv_widen_check(DisasContext *s, arg_rmrr *a) { @@ -XXX,XX +XXX,XX @@ GEN_OPFVF_TRANS(vfrdiv_vf, opfvf_check) /* Vector Widening Floating-Point Multiply */ GEN_OPFVV_WIDEN_TRANS(vfwmul_vv, opfvv_widen_check) -GEN_OPFVF_WIDEN_TRANS(vfwmul_vf) +GEN_OPFVF_WIDEN_TRANS(vfwmul_vf, opfvf_widen_check) /* Vector Single-Width Floating-Point Fused Multiply-Add Instructions */ GEN_OPFVV_TRANS(vfmacc_vv, opfvv_check) @@ -XXX,XX +XXX,XX @@ GEN_OPFVV_WIDEN_TRANS(vfwmacc_vv, opfvv_widen_check) GEN_OPFVV_WIDEN_TRANS(vfwnmacc_vv, opfvv_widen_check) GEN_OPFVV_WIDEN_TRANS(vfwmsac_vv, opfvv_widen_check) GEN_OPFVV_WIDEN_TRANS(vfwnmsac_vv, opfvv_widen_check) -GEN_OPFVF_WIDEN_TRANS(vfwmacc_vf) -GEN_OPFVF_WIDEN_TRANS(vfwnmacc_vf) -GEN_OPFVF_WIDEN_TRANS(vfwmsac_vf) -GEN_OPFVF_WIDEN_TRANS(vfwnmsac_vf) +GEN_OPFVF_WIDEN_TRANS(vfwmacc_vf, opfvf_widen_check) +GEN_OPFVF_WIDEN_TRANS(vfwnmacc_vf, opfvf_widen_check) +GEN_OPFVF_WIDEN_TRANS(vfwmsac_vf, opfvf_widen_check) +GEN_OPFVF_WIDEN_TRANS(vfwnmsac_vf, opfvf_widen_check) /* Vector Floating-Point Square-Root Instruction */ -- 2.49.0
From: Max Chou <max.chou@sifive.com> According to the v spec, a vector register cannot be used to provide source operands with more than one EEW for a single instruction. The vs1 EEW of vrgatherei16.vv is 16. Co-authored-by: Anton Blanchard <antonb@tenstorrent.com> Reviewed-by: Daniel Henrique Barboza <dbarboza@ventanamicro.com> Signed-off-by: Max Chou <max.chou@sifive.com> Message-ID: <20250408103938.3623486-4-max.chou@sifive.com> Signed-off-by: Alistair Francis <alistair.francis@wdc.com> Cc: qemu-stable@nongnu.org --- target/riscv/insn_trans/trans_rvv.c.inc | 32 +++++++++++++++++++++++++ 1 file changed, 32 insertions(+) diff --git a/target/riscv/insn_trans/trans_rvv.c.inc b/target/riscv/insn_trans/trans_rvv.c.inc index XXXXXXX..XXXXXXX 100644 --- a/target/riscv/insn_trans/trans_rvv.c.inc +++ b/target/riscv/insn_trans/trans_rvv.c.inc @@ -XXX,XX +XXX,XX @@ static bool vext_check_ld_index(DisasContext *s, int vd, int vs2, return ret; } +/* + * Check whether a vector register is used to provide source operands with + * more than one EEW for the vector instruction. + * Returns true if the instruction has valid encoding + * Returns false if encoding violates the mismatched input EEWs constraint + */ +static bool vext_check_input_eew(DisasContext *s, int vs1, uint8_t eew_vs1, + int vs2, uint8_t eew_vs2, int vm) +{ + bool is_valid = true; + int8_t emul_vs1 = eew_vs1 - s->sew + s->lmul; + int8_t emul_vs2 = eew_vs2 - s->sew + s->lmul; + + /* When vm is 0, vs1 & vs2(EEW!=1) group can't overlap v0 (EEW=1) */ + if ((vs1 != -1 && !require_vm(vm, vs1)) || + (vs2 != -1 && !require_vm(vm, vs2))) { + is_valid = false; + } + + /* When eew_vs1 != eew_vs2, check whether vs1 and vs2 are overlapped */ + if ((vs1 != -1 && vs2 != -1) && (eew_vs1 != eew_vs2) && + is_overlapped(vs1, 1 << MAX(emul_vs1, 0), + vs2, 1 << MAX(emul_vs2, 0))) { + is_valid = false; + } + + return is_valid; +} + static bool vext_check_ss(DisasContext *s, int vd, int vs, int vm) { return require_vm(vm, vd) && @@ -XXX,XX +XXX,XX @@ static bool vrgather_vv_check(DisasContext *s, arg_rmrr *a) { return require_rvv(s) && vext_check_isa_ill(s) && + vext_check_input_eew(s, a->rs1, s->sew, a->rs2, s->sew, a->vm) && require_align(a->rd, s->lmul) && require_align(a->rs1, s->lmul) && require_align(a->rs2, s->lmul) && @@ -XXX,XX +XXX,XX @@ static bool vrgatherei16_vv_check(DisasContext *s, arg_rmrr *a) int8_t emul = MO_16 - s->sew + s->lmul; return require_rvv(s) && vext_check_isa_ill(s) && + vext_check_input_eew(s, a->rs1, MO_16, a->rs2, s->sew, a->vm) && (emul >= -3 && emul <= 3) && require_align(a->rd, s->lmul) && require_align(a->rs1, emul) && @@ -XXX,XX +XXX,XX @@ static bool vrgather_vx_check(DisasContext *s, arg_rmrr *a) { return require_rvv(s) && vext_check_isa_ill(s) && + vext_check_input_eew(s, -1, MO_64, a->rs2, s->sew, a->vm) && require_align(a->rd, s->lmul) && require_align(a->rs2, s->lmul) && (a->rd != a->rs2) && -- 2.49.0
From: Max Chou <max.chou@sifive.com> Handle the overlap of source registers with different EEWs. Co-authored-by: Anton Blanchard <antonb@tenstorrent.com> Reviewed-by: Daniel Henrique Barboza <dbarboza@ventanamicro.com> Signed-off-by: Max Chou <max.chou@sifive.com> Message-ID: <20250408103938.3623486-5-max.chou@sifive.com> Signed-off-by: Alistair Francis <alistair.francis@wdc.com> Cc: qemu-stable@nongnu.org --- target/riscv/insn_trans/trans_rvv.c.inc | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/target/riscv/insn_trans/trans_rvv.c.inc b/target/riscv/insn_trans/trans_rvv.c.inc index XXXXXXX..XXXXXXX 100644 --- a/target/riscv/insn_trans/trans_rvv.c.inc +++ b/target/riscv/insn_trans/trans_rvv.c.inc @@ -XXX,XX +XXX,XX @@ static bool vext_check_ss(DisasContext *s, int vd, int vs, int vm) { return require_vm(vm, vd) && require_align(vd, s->lmul) && - require_align(vs, s->lmul); + require_align(vs, s->lmul) && + vext_check_input_eew(s, vs, s->sew, -1, s->sew, vm); } /* -- 2.49.0
From: Max Chou <max.chou@sifive.com> Handle the overlap of source registers with different EEWs. Co-authored-by: Anton Blanchard <antonb@tenstorrent.com> Reviewed-by: Daniel Henrique Barboza <dbarboza@ventanamicro.com> Signed-off-by: Max Chou <max.chou@sifive.com> Message-ID: <20250408103938.3623486-6-max.chou@sifive.com> Signed-off-by: Alistair Francis <alistair.francis@wdc.com> Cc: qemu-stable@nongnu.org --- 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 @@ static bool vext_check_ss(DisasContext *s, int vd, int vs, int vm) static bool vext_check_sss(DisasContext *s, int vd, int vs1, int vs2, int vm) { return vext_check_ss(s, vd, vs2, vm) && + vext_check_input_eew(s, vs1, s->sew, vs2, s->sew, vm) && require_align(vs1, s->lmul); } -- 2.49.0
From: Max Chou <max.chou@sifive.com> Handle the overlap of source registers with different EEWs. Co-authored-by: Anton Blanchard <antonb@tenstorrent.com> Reviewed-by: Daniel Henrique Barboza <dbarboza@ventanamicro.com> Signed-off-by: Max Chou <max.chou@sifive.com> Message-ID: <20250408103938.3623486-7-max.chou@sifive.com> Signed-off-by: Alistair Francis <alistair.francis@wdc.com> Cc: qemu-stable@nongnu.org --- target/riscv/insn_trans/trans_rvv.c.inc | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/target/riscv/insn_trans/trans_rvv.c.inc b/target/riscv/insn_trans/trans_rvv.c.inc index XXXXXXX..XXXXXXX 100644 --- a/target/riscv/insn_trans/trans_rvv.c.inc +++ b/target/riscv/insn_trans/trans_rvv.c.inc @@ -XXX,XX +XXX,XX @@ static bool vext_check_slide(DisasContext *s, int vd, int vs2, { bool ret = require_align(vs2, s->lmul) && require_align(vd, s->lmul) && - require_vm(vm, vd); + require_vm(vm, vd) && + vext_check_input_eew(s, -1, 0, vs2, s->sew, vm); + if (is_over) { ret &= (vd != vs2); } -- 2.49.0
From: Max Chou <max.chou@sifive.com> Handle the overlap of source registers with different EEWs. Co-authored-by: Anton Blanchard <antonb@tenstorrent.com> Reviewed-by: Daniel Henrique Barboza <dbarboza@ventanamicro.com> Signed-off-by: Max Chou <max.chou@sifive.com> Message-ID: <20250408103938.3623486-8-max.chou@sifive.com> Signed-off-by: Alistair Francis <alistair.francis@wdc.com> Cc: qemu-stable@nongnu.org --- target/riscv/insn_trans/trans_rvv.c.inc | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/target/riscv/insn_trans/trans_rvv.c.inc b/target/riscv/insn_trans/trans_rvv.c.inc index XXXXXXX..XXXXXXX 100644 --- a/target/riscv/insn_trans/trans_rvv.c.inc +++ b/target/riscv/insn_trans/trans_rvv.c.inc @@ -XXX,XX +XXX,XX @@ static bool int_ext_check(DisasContext *s, arg_rmr *a, uint8_t div) require_align(a->rd, s->lmul) && require_align(a->rs2, s->lmul - div) && require_vm(a->vm, a->rd) && - require_noover(a->rd, s->lmul, a->rs2, s->lmul - div); + require_noover(a->rd, s->lmul, a->rs2, s->lmul - div) && + vext_check_input_eew(s, -1, 0, a->rs2, s->sew, a->vm); + return ret; } -- 2.49.0
From: Max Chou <max.chou@sifive.com> Handle the overlap of source registers with different EEWs. The vd of vector widening mul-add instructions is one of the input operands. Co-authored-by: Anton Blanchard <antonb@tenstorrent.com> Reviewed-by: Daniel Henrique Barboza <dbarboza@ventanamicro.com> Signed-off-by: Max Chou <max.chou@sifive.com> Message-ID: <20250408103938.3623486-9-max.chou@sifive.com> Signed-off-by: Alistair Francis <alistair.francis@wdc.com> Cc: qemu-stable@nongnu.org --- target/riscv/insn_trans/trans_rvbf16.c.inc | 9 ++- target/riscv/insn_trans/trans_rvv.c.inc | 77 +++++++++++++++++----- 2 files changed, 68 insertions(+), 18 deletions(-) diff --git a/target/riscv/insn_trans/trans_rvbf16.c.inc b/target/riscv/insn_trans/trans_rvbf16.c.inc index XXXXXXX..XXXXXXX 100644 --- a/target/riscv/insn_trans/trans_rvbf16.c.inc +++ b/target/riscv/insn_trans/trans_rvbf16.c.inc @@ -XXX,XX +XXX,XX @@ static bool trans_vfwmaccbf16_vv(DisasContext *ctx, arg_vfwmaccbf16_vv *a) REQUIRE_FPU; REQUIRE_ZVFBFWMA(ctx); + uint8_t sew = ctx->sew; if (require_rvv(ctx) && vext_check_isa_ill(ctx) && (ctx->sew == MO_16) && - vext_check_dss(ctx, a->rd, a->rs1, a->rs2, a->vm)) { + vext_check_dss(ctx, a->rd, a->rs1, a->rs2, a->vm) && + vext_check_input_eew(ctx, a->rd, sew + 1, a->rs1, sew, a->vm) && + vext_check_input_eew(ctx, a->rd, sew + 1, a->rs2, sew, a->vm)) { uint32_t data = 0; gen_set_rm_chkfrm(ctx, RISCV_FRM_DYN); @@ -XXX,XX +XXX,XX @@ static bool trans_vfwmaccbf16_vf(DisasContext *ctx, arg_vfwmaccbf16_vf *a) REQUIRE_FPU; REQUIRE_ZVFBFWMA(ctx); + uint8_t sew = ctx->sew; if (require_rvv(ctx) && (ctx->sew == MO_16) && vext_check_isa_ill(ctx) && - vext_check_ds(ctx, a->rd, a->rs2, a->vm)) { + vext_check_ds(ctx, a->rd, a->rs2, a->vm) && + vext_check_input_eew(ctx, a->rd, sew + 1, a->rs2, sew, a->vm)) { uint32_t data = 0; gen_set_rm(ctx, RISCV_FRM_DYN); diff --git a/target/riscv/insn_trans/trans_rvv.c.inc b/target/riscv/insn_trans/trans_rvv.c.inc index XXXXXXX..XXXXXXX 100644 --- a/target/riscv/insn_trans/trans_rvv.c.inc +++ b/target/riscv/insn_trans/trans_rvv.c.inc @@ -XXX,XX +XXX,XX @@ static bool vext_narrow_check_common(DisasContext *s, int vd, int vs2, static bool vext_check_ds(DisasContext *s, int vd, int vs, int vm) { return vext_wide_check_common(s, vd, vm) && + vext_check_input_eew(s, vs, s->sew, -1, 0, vm) && require_align(vs, s->lmul) && require_noover(vd, s->lmul + 1, vs, s->lmul); } @@ -XXX,XX +XXX,XX @@ static bool vext_check_ds(DisasContext *s, int vd, int vs, int vm) static bool vext_check_dd(DisasContext *s, int vd, int vs, int vm) { return vext_wide_check_common(s, vd, vm) && + vext_check_input_eew(s, vs, s->sew + 1, -1, 0, vm) && require_align(vs, s->lmul + 1); } @@ -XXX,XX +XXX,XX @@ static bool vext_check_dd(DisasContext *s, int vd, int vs, int vm) static bool vext_check_dss(DisasContext *s, int vd, int vs1, int vs2, int vm) { return vext_check_ds(s, vd, vs2, vm) && + vext_check_input_eew(s, vs1, s->sew, vs2, s->sew, vm) && require_align(vs1, s->lmul) && require_noover(vd, s->lmul + 1, vs1, s->lmul); } @@ -XXX,XX +XXX,XX @@ static bool vext_check_dss(DisasContext *s, int vd, int vs1, int vs2, int vm) static bool vext_check_dds(DisasContext *s, int vd, int vs1, int vs2, int vm) { return vext_check_ds(s, vd, vs1, vm) && + vext_check_input_eew(s, vs1, s->sew, vs2, s->sew + 1, vm) && require_align(vs2, s->lmul + 1); } static bool vext_check_sd(DisasContext *s, int vd, int vs, int vm) { - bool ret = vext_narrow_check_common(s, vd, vs, vm); + bool ret = vext_narrow_check_common(s, vd, vs, vm) && + vext_check_input_eew(s, vs, s->sew + 1, -1, 0, vm); if (vd != vs) { ret &= require_noover(vd, s->lmul, vs, s->lmul + 1); } @@ -XXX,XX +XXX,XX @@ static bool vext_check_sd(DisasContext *s, int vd, int vs, int vm) static bool vext_check_sds(DisasContext *s, int vd, int vs1, int vs2, int vm) { return vext_check_sd(s, vd, vs2, vm) && + vext_check_input_eew(s, vs1, s->sew, vs2, s->sew + 1, vm) && require_align(vs1, s->lmul); } @@ -XXX,XX +XXX,XX @@ static bool opivv_widen_check(DisasContext *s, arg_rmrr *a) vext_check_dss(s, a->rd, a->rs1, a->rs2, a->vm); } +/* OPIVV with overwrite and WIDEN */ +static bool opivv_overwrite_widen_check(DisasContext *s, arg_rmrr *a) +{ + return require_rvv(s) && + vext_check_isa_ill(s) && + vext_check_dss(s, a->rd, a->rs1, a->rs2, a->vm) && + vext_check_input_eew(s, a->rd, s->sew + 1, a->rs1, s->sew, a->vm) && + vext_check_input_eew(s, a->rd, s->sew + 1, a->rs2, s->sew, a->vm); +} + static bool do_opivv_widen(DisasContext *s, arg_rmrr *a, gen_helper_gvec_4_ptr *fn, bool (*checkfn)(DisasContext *, arg_rmrr *)) @@ -XXX,XX +XXX,XX @@ static bool opivx_widen_check(DisasContext *s, arg_rmrr *a) vext_check_ds(s, a->rd, a->rs2, a->vm); } +static bool opivx_overwrite_widen_check(DisasContext *s, arg_rmrr *a) +{ + return require_rvv(s) && + vext_check_isa_ill(s) && + vext_check_ds(s, a->rd, a->rs2, a->vm) && + vext_check_input_eew(s, a->rd, s->sew + 1, a->rs2, s->sew, a->vm); +} + #define GEN_OPIVX_WIDEN_TRANS(NAME, CHECK) \ static bool trans_##NAME(DisasContext *s, arg_rmrr *a) \ { \ @@ -XXX,XX +XXX,XX @@ GEN_OPIVX_TRANS(vmadd_vx, opivx_check) GEN_OPIVX_TRANS(vnmsub_vx, opivx_check) /* Vector Widening Integer Multiply-Add Instructions */ -GEN_OPIVV_WIDEN_TRANS(vwmaccu_vv, opivv_widen_check) -GEN_OPIVV_WIDEN_TRANS(vwmacc_vv, opivv_widen_check) -GEN_OPIVV_WIDEN_TRANS(vwmaccsu_vv, opivv_widen_check) -GEN_OPIVX_WIDEN_TRANS(vwmaccu_vx, opivx_widen_check) -GEN_OPIVX_WIDEN_TRANS(vwmacc_vx, opivx_widen_check) -GEN_OPIVX_WIDEN_TRANS(vwmaccsu_vx, opivx_widen_check) -GEN_OPIVX_WIDEN_TRANS(vwmaccus_vx, opivx_widen_check) +GEN_OPIVV_WIDEN_TRANS(vwmaccu_vv, opivv_overwrite_widen_check) +GEN_OPIVV_WIDEN_TRANS(vwmacc_vv, opivv_overwrite_widen_check) +GEN_OPIVV_WIDEN_TRANS(vwmaccsu_vv, opivv_overwrite_widen_check) +GEN_OPIVX_WIDEN_TRANS(vwmaccu_vx, opivx_overwrite_widen_check) +GEN_OPIVX_WIDEN_TRANS(vwmacc_vx, opivx_overwrite_widen_check) +GEN_OPIVX_WIDEN_TRANS(vwmaccsu_vx, opivx_overwrite_widen_check) +GEN_OPIVX_WIDEN_TRANS(vwmaccus_vx, opivx_overwrite_widen_check) /* Vector Integer Merge and Move Instructions */ static bool trans_vmv_v_v(DisasContext *s, arg_vmv_v_v *a) @@ -XXX,XX +XXX,XX @@ static bool opfvv_widen_check(DisasContext *s, arg_rmrr *a) vext_check_dss(s, a->rd, a->rs1, a->rs2, a->vm); } +static bool opfvv_overwrite_widen_check(DisasContext *s, arg_rmrr *a) +{ + return require_rvv(s) && + require_rvf(s) && + require_scale_rvf(s) && + vext_check_isa_ill(s) && + vext_check_dss(s, a->rd, a->rs1, a->rs2, a->vm) && + vext_check_input_eew(s, a->rd, s->sew + 1, a->rs1, s->sew, a->vm) && + vext_check_input_eew(s, a->rd, s->sew + 1, a->rs2, s->sew, a->vm); +} + /* OPFVV with WIDEN */ #define GEN_OPFVV_WIDEN_TRANS(NAME, CHECK) \ static bool trans_##NAME(DisasContext *s, arg_rmrr *a) \ @@ -XXX,XX +XXX,XX @@ static bool opfvf_widen_check(DisasContext *s, arg_rmrr *a) vext_check_ds(s, a->rd, a->rs2, a->vm); } +static bool opfvf_overwrite_widen_check(DisasContext *s, arg_rmrr *a) +{ + return require_rvv(s) && + require_rvf(s) && + require_scale_rvf(s) && + vext_check_isa_ill(s) && + vext_check_ds(s, a->rd, a->rs2, a->vm) && + vext_check_input_eew(s, a->rd, s->sew + 1, a->rs2, s->sew, a->vm); +} + /* OPFVF with WIDEN */ #define GEN_OPFVF_WIDEN_TRANS(NAME, CHECK) \ static bool trans_##NAME(DisasContext *s, arg_rmrr *a) \ @@ -XXX,XX +XXX,XX @@ GEN_OPFVF_TRANS(vfmsub_vf, opfvf_check) GEN_OPFVF_TRANS(vfnmsub_vf, opfvf_check) /* Vector Widening Floating-Point Fused Multiply-Add Instructions */ -GEN_OPFVV_WIDEN_TRANS(vfwmacc_vv, opfvv_widen_check) -GEN_OPFVV_WIDEN_TRANS(vfwnmacc_vv, opfvv_widen_check) -GEN_OPFVV_WIDEN_TRANS(vfwmsac_vv, opfvv_widen_check) -GEN_OPFVV_WIDEN_TRANS(vfwnmsac_vv, opfvv_widen_check) -GEN_OPFVF_WIDEN_TRANS(vfwmacc_vf, opfvf_widen_check) -GEN_OPFVF_WIDEN_TRANS(vfwnmacc_vf, opfvf_widen_check) -GEN_OPFVF_WIDEN_TRANS(vfwmsac_vf, opfvf_widen_check) -GEN_OPFVF_WIDEN_TRANS(vfwnmsac_vf, opfvf_widen_check) +GEN_OPFVV_WIDEN_TRANS(vfwmacc_vv, opfvv_overwrite_widen_check) +GEN_OPFVV_WIDEN_TRANS(vfwnmacc_vv, opfvv_overwrite_widen_check) +GEN_OPFVV_WIDEN_TRANS(vfwmsac_vv, opfvv_overwrite_widen_check) +GEN_OPFVV_WIDEN_TRANS(vfwnmsac_vv, opfvv_overwrite_widen_check) +GEN_OPFVF_WIDEN_TRANS(vfwmacc_vf, opfvf_overwrite_widen_check) +GEN_OPFVF_WIDEN_TRANS(vfwnmacc_vf, opfvf_overwrite_widen_check) +GEN_OPFVF_WIDEN_TRANS(vfwmsac_vf, opfvf_overwrite_widen_check) +GEN_OPFVF_WIDEN_TRANS(vfwnmsac_vf, opfvf_overwrite_widen_check) /* Vector Floating-Point Square-Root Instruction */ -- 2.49.0
From: Max Chou <max.chou@sifive.com> Handle the overlap of source registers with different EEWs. Co-authored-by: Anton Blanchard <antonb@tenstorrent.com> Reviewed-by: Daniel Henrique Barboza <dbarboza@ventanamicro.com> Signed-off-by: Max Chou <max.chou@sifive.com> Message-ID: <20250408103938.3623486-10-max.chou@sifive.com> Signed-off-by: Alistair Francis <alistair.francis@wdc.com> Cc: qemu-stable@nongnu.org --- target/riscv/insn_trans/trans_rvv.c.inc | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/target/riscv/insn_trans/trans_rvv.c.inc b/target/riscv/insn_trans/trans_rvv.c.inc index XXXXXXX..XXXXXXX 100644 --- a/target/riscv/insn_trans/trans_rvv.c.inc +++ b/target/riscv/insn_trans/trans_rvv.c.inc @@ -XXX,XX +XXX,XX @@ static bool ld_index_check(DisasContext *s, arg_rnfvm* a, uint8_t eew) { return require_rvv(s) && vext_check_isa_ill(s) && - vext_check_ld_index(s, a->rd, a->rs2, a->nf, a->vm, eew); + vext_check_ld_index(s, a->rd, a->rs2, a->nf, a->vm, eew) && + vext_check_input_eew(s, -1, 0, a->rs2, eew, a->vm); } GEN_VEXT_TRANS(vlxei8_v, MO_8, rnfvm, ld_index_op, ld_index_check) @@ -XXX,XX +XXX,XX @@ static bool st_index_check(DisasContext *s, arg_rnfvm* a, uint8_t eew) { return require_rvv(s) && vext_check_isa_ill(s) && - vext_check_st_index(s, a->rd, a->rs2, a->nf, eew); + vext_check_st_index(s, a->rd, a->rs2, a->nf, eew) && + vext_check_input_eew(s, a->rd, s->sew, a->rs2, eew, a->vm); } GEN_VEXT_TRANS(vsxei8_v, MO_8, rnfvm, st_index_op, st_index_check) -- 2.49.0
From: Max Chou <max.chou@sifive.com> According to the v spec, the encodings of vcomoress.vm and vector mask-register logical instructions with vm=0 are reserved. Reviewed-by: Daniel Henrique Barboza <dbarboza@ventanamicro.com> Signed-off-by: Max Chou <max.chou@sifive.com> Message-ID: <20250408103938.3623486-11-max.chou@sifive.com> Signed-off-by: Alistair Francis <alistair.francis@wdc.com> Cc: qemu-stable@nongnu.org --- target/riscv/insn32.decode | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) 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 @@ vfredmax_vs 000111 . ..... ..... 001 ..... 1010111 @r_vm # Vector widening ordered and unordered float reduction sum vfwredusum_vs 110001 . ..... ..... 001 ..... 1010111 @r_vm vfwredosum_vs 110011 . ..... ..... 001 ..... 1010111 @r_vm -vmand_mm 011001 - ..... ..... 010 ..... 1010111 @r -vmnand_mm 011101 - ..... ..... 010 ..... 1010111 @r -vmandn_mm 011000 - ..... ..... 010 ..... 1010111 @r -vmxor_mm 011011 - ..... ..... 010 ..... 1010111 @r -vmor_mm 011010 - ..... ..... 010 ..... 1010111 @r -vmnor_mm 011110 - ..... ..... 010 ..... 1010111 @r -vmorn_mm 011100 - ..... ..... 010 ..... 1010111 @r -vmxnor_mm 011111 - ..... ..... 010 ..... 1010111 @r +vmand_mm 011001 1 ..... ..... 010 ..... 1010111 @r +vmnand_mm 011101 1 ..... ..... 010 ..... 1010111 @r +vmandn_mm 011000 1 ..... ..... 010 ..... 1010111 @r +vmxor_mm 011011 1 ..... ..... 010 ..... 1010111 @r +vmor_mm 011010 1 ..... ..... 010 ..... 1010111 @r +vmnor_mm 011110 1 ..... ..... 010 ..... 1010111 @r +vmorn_mm 011100 1 ..... ..... 010 ..... 1010111 @r +vmxnor_mm 011111 1 ..... ..... 010 ..... 1010111 @r vcpop_m 010000 . ..... 10000 010 ..... 1010111 @r2_vm vfirst_m 010000 . ..... 10001 010 ..... 1010111 @r2_vm vmsbf_m 010100 . ..... 00001 010 ..... 1010111 @r2_vm @@ -XXX,XX +XXX,XX @@ vrgather_vv 001100 . ..... ..... 000 ..... 1010111 @r_vm vrgatherei16_vv 001110 . ..... ..... 000 ..... 1010111 @r_vm vrgather_vx 001100 . ..... ..... 100 ..... 1010111 @r_vm vrgather_vi 001100 . ..... ..... 011 ..... 1010111 @r_vm -vcompress_vm 010111 - ..... ..... 010 ..... 1010111 @r +vcompress_vm 010111 1 ..... ..... 010 ..... 1010111 @r vmv1r_v 100111 1 ..... 00000 011 ..... 1010111 @r2rd vmv2r_v 100111 1 ..... 00001 011 ..... 1010111 @r2rd vmv4r_v 100111 1 ..... 00011 011 ..... 1010111 @r2rd -- 2.49.0
From: Anton Blanchard <antonb@tenstorrent.com> vslidedown always zeroes elements past vl, where it should use the tail policy. Signed-off-by: Anton Blanchard <antonb@tenstorrent.com> Reviewed-by: Alistair Francis <alistair.francis@wdc.com> Message-ID: <20250414213006.3509058-1-antonb@tenstorrent.com> Signed-off-by: Alistair Francis <alistair.francis@wdc.com> Cc: qemu-stable@nongnu.org --- target/riscv/vector_helper.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/target/riscv/vector_helper.c b/target/riscv/vector_helper.c index XXXXXXX..XXXXXXX 100644 --- a/target/riscv/vector_helper.c +++ b/target/riscv/vector_helper.c @@ -XXX,XX +XXX,XX @@ void HELPER(NAME)(void *vd, void *v0, target_ulong s1, void *vs2, \ } \ \ for (i = i_max; i < vl; ++i) { \ - if (vm || vext_elem_mask(v0, i)) { \ - *((ETYPE *)vd + H(i)) = 0; \ + if (!vm && !vext_elem_mask(v0, i)) { \ + vext_set_elems_1s(vd, vma, i * esz, (i + 1) * esz); \ + continue; \ } \ + *((ETYPE *)vd + H(i)) = 0; \ } \ \ env->vstart = 0; \ -- 2.49.0
From: Alistair Francis <alistair23@gmail.com> Signed-off-by: Alistair Francis <alistair.francis@wdc.com> Reviewed-by: Philippe Mathieu-Daudé <philmd@linaro.org> Message-ID: <20250422024752.2060289-1-alistair.francis@wdc.com> Signed-off-by: Alistair Francis <alistair.francis@wdc.com> --- MAINTAINERS | 1 + 1 file changed, 1 insertion(+) diff --git a/MAINTAINERS b/MAINTAINERS index XXXXXXX..XXXXXXX 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -XXX,XX +XXX,XX @@ F: include/hw/char/riscv_htif.h F: include/hw/riscv/ F: linux-user/host/riscv32/ F: linux-user/host/riscv64/ +F: common-user/host/riscv* F: tests/functional/test_riscv* F: tests/tcg/riscv64/ -- 2.49.0
From: Richard Henderson <richard.henderson@linaro.org> Signed-off-by: Richard Henderson <richard.henderson@linaro.org> Reviewed-by: Alistair Francis <alistair.francis@wdc.com> Reviewed-by: Daniel Henrique Barboza <dbarboza@ventanamicro.com> Reviewed-by: Philippe Mathieu-Daudé <philmd@linaro.org> Message-ID: <20250425152311.804338-2-richard.henderson@linaro.org> Signed-off-by: Alistair Francis <alistair.francis@wdc.com> --- target/riscv/cpu.h | 3 +- target/riscv/csr.c | 226 +++++++++++++++++++++++---------------------- 2 files changed, 118 insertions(+), 111 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 RISCVException (*riscv_csr_predicate_fn)(CPURISCVState *env, typedef RISCVException (*riscv_csr_read_fn)(CPURISCVState *env, int csrno, target_ulong *ret_value); typedef RISCVException (*riscv_csr_write_fn)(CPURISCVState *env, int csrno, - target_ulong new_value); + target_ulong new_value, + uintptr_t ra); typedef RISCVException (*riscv_csr_op_fn)(CPURISCVState *env, int csrno, target_ulong *ret_value, target_ulong new_value, 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 seed(CPURISCVState *env, int csrno) } /* zicfiss CSR_SSP read and write */ -static int read_ssp(CPURISCVState *env, int csrno, target_ulong *val) +static RISCVException read_ssp(CPURISCVState *env, int csrno, + target_ulong *val) { *val = env->ssp; return RISCV_EXCP_NONE; } -static int write_ssp(CPURISCVState *env, int csrno, target_ulong val) +static RISCVException write_ssp(CPURISCVState *env, int csrno, + target_ulong val, uintptr_t ra) { env->ssp = val; return RISCV_EXCP_NONE; @@ -XXX,XX +XXX,XX @@ static RISCVException read_fflags(CPURISCVState *env, int csrno, } static RISCVException write_fflags(CPURISCVState *env, int csrno, - target_ulong val) + target_ulong val, uintptr_t ra) { #if !defined(CONFIG_USER_ONLY) if (riscv_has_ext(env, RVF)) { @@ -XXX,XX +XXX,XX @@ static RISCVException read_frm(CPURISCVState *env, int csrno, } static RISCVException write_frm(CPURISCVState *env, int csrno, - target_ulong val) + target_ulong val, uintptr_t ra) { #if !defined(CONFIG_USER_ONLY) if (riscv_has_ext(env, RVF)) { @@ -XXX,XX +XXX,XX @@ static RISCVException read_fcsr(CPURISCVState *env, int csrno, } static RISCVException write_fcsr(CPURISCVState *env, int csrno, - target_ulong val) + target_ulong val, uintptr_t ra) { #if !defined(CONFIG_USER_ONLY) if (riscv_has_ext(env, RVF)) { @@ -XXX,XX +XXX,XX @@ static RISCVException read_vxrm(CPURISCVState *env, int csrno, } static RISCVException write_vxrm(CPURISCVState *env, int csrno, - target_ulong val) + target_ulong val, uintptr_t ra) { #if !defined(CONFIG_USER_ONLY) env->mstatus |= MSTATUS_VS; @@ -XXX,XX +XXX,XX @@ static RISCVException read_vxsat(CPURISCVState *env, int csrno, } static RISCVException write_vxsat(CPURISCVState *env, int csrno, - target_ulong val) + target_ulong val, uintptr_t ra) { #if !defined(CONFIG_USER_ONLY) env->mstatus |= MSTATUS_VS; @@ -XXX,XX +XXX,XX @@ static RISCVException read_vstart(CPURISCVState *env, int csrno, } static RISCVException write_vstart(CPURISCVState *env, int csrno, - target_ulong val) + target_ulong val, uintptr_t ra) { #if !defined(CONFIG_USER_ONLY) env->mstatus |= MSTATUS_VS; @@ -XXX,XX +XXX,XX @@ static RISCVException read_vcsr(CPURISCVState *env, int csrno, } static RISCVException write_vcsr(CPURISCVState *env, int csrno, - target_ulong val) + target_ulong val, uintptr_t ra) { #if !defined(CONFIG_USER_ONLY) env->mstatus |= MSTATUS_VS; @@ -XXX,XX +XXX,XX @@ static RISCVException read_mcyclecfg(CPURISCVState *env, int csrno, } static RISCVException write_mcyclecfg(CPURISCVState *env, int csrno, - target_ulong val) + target_ulong val, uintptr_t ra) { uint64_t inh_avail_mask; @@ -XXX,XX +XXX,XX @@ static RISCVException read_mcyclecfgh(CPURISCVState *env, int csrno, } static RISCVException write_mcyclecfgh(CPURISCVState *env, int csrno, - target_ulong val) + target_ulong val, uintptr_t ra) { target_ulong inh_avail_mask = (target_ulong)(~MHPMEVENTH_FILTER_MASK | MCYCLECFGH_BIT_MINH); @@ -XXX,XX +XXX,XX @@ static RISCVException read_minstretcfg(CPURISCVState *env, int csrno, } static RISCVException write_minstretcfg(CPURISCVState *env, int csrno, - target_ulong val) + target_ulong val, uintptr_t ra) { uint64_t inh_avail_mask; @@ -XXX,XX +XXX,XX @@ static RISCVException read_minstretcfgh(CPURISCVState *env, int csrno, } static RISCVException write_minstretcfgh(CPURISCVState *env, int csrno, - target_ulong val) + target_ulong val, uintptr_t ra) { target_ulong inh_avail_mask = (target_ulong)(~MHPMEVENTH_FILTER_MASK | MINSTRETCFGH_BIT_MINH); @@ -XXX,XX +XXX,XX @@ static RISCVException read_mhpmevent(CPURISCVState *env, int csrno, } static RISCVException write_mhpmevent(CPURISCVState *env, int csrno, - target_ulong val) + target_ulong val, uintptr_t ra) { int evt_index = csrno - CSR_MCOUNTINHIBIT; uint64_t mhpmevt_val = val; @@ -XXX,XX +XXX,XX @@ static RISCVException read_mhpmeventh(CPURISCVState *env, int csrno, } static RISCVException write_mhpmeventh(CPURISCVState *env, int csrno, - target_ulong val) + target_ulong val, uintptr_t ra) { int evt_index = csrno - CSR_MHPMEVENT3H + 3; uint64_t mhpmevth_val; @@ -XXX,XX +XXX,XX @@ static RISCVException riscv_pmu_write_ctrh(CPURISCVState *env, target_ulong val, return RISCV_EXCP_NONE; } -static int write_mhpmcounter(CPURISCVState *env, int csrno, target_ulong val) +static RISCVException write_mhpmcounter(CPURISCVState *env, int csrno, + target_ulong val, uintptr_t ra) { int ctr_idx = csrno - CSR_MCYCLE; return riscv_pmu_write_ctr(env, val, ctr_idx); } -static int write_mhpmcounterh(CPURISCVState *env, int csrno, target_ulong val) +static RISCVException write_mhpmcounterh(CPURISCVState *env, int csrno, + target_ulong val, uintptr_t ra) { int ctr_idx = csrno - CSR_MCYCLEH; @@ -XXX,XX +XXX,XX @@ static RISCVException read_vstimecmph(CPURISCVState *env, int csrno, } static RISCVException write_vstimecmp(CPURISCVState *env, int csrno, - target_ulong val) + target_ulong val, uintptr_t ra) { if (riscv_cpu_mxl(env) == MXL_RV32) { env->vstimecmp = deposit64(env->vstimecmp, 0, 32, (uint64_t)val); @@ -XXX,XX +XXX,XX @@ static RISCVException write_vstimecmp(CPURISCVState *env, int csrno, } static RISCVException write_vstimecmph(CPURISCVState *env, int csrno, - target_ulong val) + target_ulong val, uintptr_t ra) { env->vstimecmp = deposit64(env->vstimecmp, 32, 32, (uint64_t)val); riscv_timer_write_timecmp(env, env->vstimer, env->vstimecmp, @@ -XXX,XX +XXX,XX @@ static RISCVException read_stimecmph(CPURISCVState *env, int csrno, } static RISCVException write_stimecmp(CPURISCVState *env, int csrno, - target_ulong val) + target_ulong val, uintptr_t ra) { if (env->virt_enabled) { if (env->hvictl & HVICTL_VTI) { return RISCV_EXCP_VIRT_INSTRUCTION_FAULT; } - return write_vstimecmp(env, csrno, val); + return write_vstimecmp(env, csrno, val, ra); } if (riscv_cpu_mxl(env) == MXL_RV32) { @@ -XXX,XX +XXX,XX @@ static RISCVException write_stimecmp(CPURISCVState *env, int csrno, } static RISCVException write_stimecmph(CPURISCVState *env, int csrno, - target_ulong val) + target_ulong val, uintptr_t ra) { if (env->virt_enabled) { if (env->hvictl & HVICTL_VTI) { return RISCV_EXCP_VIRT_INSTRUCTION_FAULT; } - return write_vstimecmph(env, csrno, val); + return write_vstimecmph(env, csrno, val, ra); } env->stimecmp = deposit64(env->stimecmp, 32, 32, (uint64_t)val); @@ -XXX,XX +XXX,XX @@ static RISCVException read_zero(CPURISCVState *env, int csrno, } static RISCVException write_ignore(CPURISCVState *env, int csrno, - target_ulong val) + target_ulong val, uintptr_t ra) { return RISCV_EXCP_NONE; } @@ -XXX,XX +XXX,XX @@ static target_ulong legalize_mpp(CPURISCVState *env, target_ulong old_mpp, } static RISCVException write_mstatus(CPURISCVState *env, int csrno, - target_ulong val) + target_ulong val, uintptr_t ra) { uint64_t mstatus = env->mstatus; uint64_t mask = 0; @@ -XXX,XX +XXX,XX @@ static RISCVException read_mstatush(CPURISCVState *env, int csrno, } static RISCVException write_mstatush(CPURISCVState *env, int csrno, - target_ulong val) + target_ulong val, uintptr_t ra) { uint64_t valh = (uint64_t)val << 32; uint64_t mask = riscv_has_ext(env, RVH) ? MSTATUS_MPV | MSTATUS_GVA : 0; @@ -XXX,XX +XXX,XX @@ static RISCVException read_misa(CPURISCVState *env, int csrno, } static RISCVException write_misa(CPURISCVState *env, int csrno, - target_ulong val) + target_ulong val, uintptr_t ra) { RISCVCPU *cpu = env_archcpu(env); uint32_t orig_misa_ext = env->misa_ext; @@ -XXX,XX +XXX,XX @@ static RISCVException read_medeleg(CPURISCVState *env, int csrno, } static RISCVException write_medeleg(CPURISCVState *env, int csrno, - target_ulong val) + target_ulong val, uintptr_t ra) { env->medeleg = (env->medeleg & ~DELEGABLE_EXCPS) | (val & DELEGABLE_EXCPS); return RISCV_EXCP_NONE; @@ -XXX,XX +XXX,XX @@ static RISCVException read_mtvec(CPURISCVState *env, int csrno, } static RISCVException write_mtvec(CPURISCVState *env, int csrno, - target_ulong val) + target_ulong val, uintptr_t ra) { /* bits [1:0] encode mode; 0 = direct, 1 = vectored, 2 >= reserved */ if ((val & 3) < 2) { @@ -XXX,XX +XXX,XX @@ static RISCVException read_mcountinhibit(CPURISCVState *env, int csrno, } static RISCVException write_mcountinhibit(CPURISCVState *env, int csrno, - target_ulong val) + target_ulong val, uintptr_t ra) { int cidx; PMUCTRState *counter; @@ -XXX,XX +XXX,XX @@ static RISCVException read_scountinhibit(CPURISCVState *env, int csrno, } static RISCVException write_scountinhibit(CPURISCVState *env, int csrno, - target_ulong val) + target_ulong val, uintptr_t ra) { - write_mcountinhibit(env, csrno, val & env->mcounteren); - return RISCV_EXCP_NONE; + return write_mcountinhibit(env, csrno, val & env->mcounteren, ra); } static RISCVException read_mcounteren(CPURISCVState *env, int csrno, @@ -XXX,XX +XXX,XX @@ static RISCVException read_mcounteren(CPURISCVState *env, int csrno, } static RISCVException write_mcounteren(CPURISCVState *env, int csrno, - target_ulong val) + target_ulong val, uintptr_t ra) { RISCVCPU *cpu = env_archcpu(env); @@ -XXX,XX +XXX,XX @@ static RISCVException read_mscratch(CPURISCVState *env, int csrno, } static RISCVException write_mscratch(CPURISCVState *env, int csrno, - target_ulong val) + target_ulong val, uintptr_t ra) { env->mscratch = val; return RISCV_EXCP_NONE; @@ -XXX,XX +XXX,XX @@ static RISCVException read_mepc(CPURISCVState *env, int csrno, } static RISCVException write_mepc(CPURISCVState *env, int csrno, - target_ulong val) + target_ulong val, uintptr_t ra) { env->mepc = val; return RISCV_EXCP_NONE; @@ -XXX,XX +XXX,XX @@ static RISCVException read_mcause(CPURISCVState *env, int csrno, } static RISCVException write_mcause(CPURISCVState *env, int csrno, - target_ulong val) + target_ulong val, uintptr_t ra) { env->mcause = val; return RISCV_EXCP_NONE; @@ -XXX,XX +XXX,XX @@ static RISCVException read_mtval(CPURISCVState *env, int csrno, } static RISCVException write_mtval(CPURISCVState *env, int csrno, - target_ulong val) + target_ulong val, uintptr_t ra) { env->mtval = val; return RISCV_EXCP_NONE; @@ -XXX,XX +XXX,XX @@ static RISCVException read_menvcfg(CPURISCVState *env, int csrno, } static RISCVException write_henvcfg(CPURISCVState *env, int csrno, - target_ulong val); + target_ulong val, uintptr_t ra); static RISCVException write_menvcfg(CPURISCVState *env, int csrno, - target_ulong val) + target_ulong val, uintptr_t ra) { const RISCVCPUConfig *cfg = riscv_cpu_cfg(env); uint64_t mask = MENVCFG_FIOM | MENVCFG_CBIE | MENVCFG_CBCFE | @@ -XXX,XX +XXX,XX @@ static RISCVException write_menvcfg(CPURISCVState *env, int csrno, } } env->menvcfg = (env->menvcfg & ~mask) | (val & mask); - write_henvcfg(env, CSR_HENVCFG, env->henvcfg); - - return RISCV_EXCP_NONE; + return write_henvcfg(env, CSR_HENVCFG, env->henvcfg, ra); } static RISCVException read_menvcfgh(CPURISCVState *env, int csrno, @@ -XXX,XX +XXX,XX @@ static RISCVException read_menvcfgh(CPURISCVState *env, int csrno, } static RISCVException write_henvcfgh(CPURISCVState *env, int csrno, - target_ulong val); + target_ulong val, uintptr_t ra); static RISCVException write_menvcfgh(CPURISCVState *env, int csrno, - target_ulong val) + target_ulong val, uintptr_t ra) { const RISCVCPUConfig *cfg = riscv_cpu_cfg(env); uint64_t mask = (cfg->ext_svpbmt ? MENVCFG_PBMTE : 0) | @@ -XXX,XX +XXX,XX @@ static RISCVException write_menvcfgh(CPURISCVState *env, int csrno, } env->menvcfg = (env->menvcfg & ~mask) | (valh & mask); - write_henvcfgh(env, CSR_HENVCFGH, env->henvcfg >> 32); - - return RISCV_EXCP_NONE; + return write_henvcfgh(env, CSR_HENVCFGH, env->henvcfg >> 32, ra); } static RISCVException read_senvcfg(CPURISCVState *env, int csrno, @@ -XXX,XX +XXX,XX @@ static RISCVException read_senvcfg(CPURISCVState *env, int csrno, } static RISCVException write_senvcfg(CPURISCVState *env, int csrno, - target_ulong val) + target_ulong val, uintptr_t ra) { uint64_t mask = SENVCFG_FIOM | SENVCFG_CBIE | SENVCFG_CBCFE | SENVCFG_CBZE; RISCVException ret; @@ -XXX,XX +XXX,XX @@ static RISCVException read_henvcfg(CPURISCVState *env, int csrno, } static RISCVException write_henvcfg(CPURISCVState *env, int csrno, - target_ulong val) + target_ulong val, uintptr_t ra) { uint64_t mask = HENVCFG_FIOM | HENVCFG_CBIE | HENVCFG_CBCFE | HENVCFG_CBZE; RISCVException ret; @@ -XXX,XX +XXX,XX @@ static RISCVException read_henvcfgh(CPURISCVState *env, int csrno, } static RISCVException write_henvcfgh(CPURISCVState *env, int csrno, - target_ulong val) + target_ulong val, uintptr_t ra) { uint64_t mask = env->menvcfg & (HENVCFG_PBMTE | HENVCFG_STCE | HENVCFG_ADUE | HENVCFG_DTE); @@ -XXX,XX +XXX,XX @@ static RISCVException write_mstateen(CPURISCVState *env, int csrno, } static RISCVException write_mstateen0(CPURISCVState *env, int csrno, - target_ulong new_val) + target_ulong new_val, uintptr_t ra) { uint64_t wr_mask = SMSTATEEN_STATEEN | SMSTATEEN0_HSENVCFG; if (!riscv_has_ext(env, RVF)) { @@ -XXX,XX +XXX,XX @@ static RISCVException write_mstateen0(CPURISCVState *env, int csrno, } static RISCVException write_mstateen_1_3(CPURISCVState *env, int csrno, - target_ulong new_val) + target_ulong new_val, uintptr_t ra) { return write_mstateen(env, csrno, SMSTATEEN_STATEEN, new_val); } @@ -XXX,XX +XXX,XX @@ static RISCVException write_mstateenh(CPURISCVState *env, int csrno, } static RISCVException write_mstateen0h(CPURISCVState *env, int csrno, - target_ulong new_val) + target_ulong new_val, uintptr_t ra) { uint64_t wr_mask = SMSTATEEN_STATEEN | SMSTATEEN0_HSENVCFG; @@ -XXX,XX +XXX,XX @@ static RISCVException write_mstateen0h(CPURISCVState *env, int csrno, } static RISCVException write_mstateenh_1_3(CPURISCVState *env, int csrno, - target_ulong new_val) + target_ulong new_val, uintptr_t ra) { return write_mstateenh(env, csrno, SMSTATEEN_STATEEN, new_val); } @@ -XXX,XX +XXX,XX @@ static RISCVException write_hstateen(CPURISCVState *env, int csrno, } static RISCVException write_hstateen0(CPURISCVState *env, int csrno, - target_ulong new_val) + target_ulong new_val, uintptr_t ra) { uint64_t wr_mask = SMSTATEEN_STATEEN | SMSTATEEN0_HSENVCFG; @@ -XXX,XX +XXX,XX @@ static RISCVException write_hstateen0(CPURISCVState *env, int csrno, } static RISCVException write_hstateen_1_3(CPURISCVState *env, int csrno, - target_ulong new_val) + target_ulong new_val, uintptr_t ra) { return write_hstateen(env, csrno, SMSTATEEN_STATEEN, new_val); } @@ -XXX,XX +XXX,XX @@ static RISCVException write_hstateenh(CPURISCVState *env, int csrno, } static RISCVException write_hstateen0h(CPURISCVState *env, int csrno, - target_ulong new_val) + target_ulong new_val, uintptr_t ra) { uint64_t wr_mask = SMSTATEEN_STATEEN | SMSTATEEN0_HSENVCFG; @@ -XXX,XX +XXX,XX @@ static RISCVException write_hstateen0h(CPURISCVState *env, int csrno, } static RISCVException write_hstateenh_1_3(CPURISCVState *env, int csrno, - target_ulong new_val) + target_ulong new_val, uintptr_t ra) { return write_hstateenh(env, csrno, SMSTATEEN_STATEEN, new_val); } @@ -XXX,XX +XXX,XX @@ static RISCVException write_sstateen(CPURISCVState *env, int csrno, } static RISCVException write_sstateen0(CPURISCVState *env, int csrno, - target_ulong new_val) + target_ulong new_val, uintptr_t ra) { uint64_t wr_mask = SMSTATEEN_STATEEN | SMSTATEEN0_HSENVCFG; @@ -XXX,XX +XXX,XX @@ static RISCVException write_sstateen0(CPURISCVState *env, int csrno, } static RISCVException write_sstateen_1_3(CPURISCVState *env, int csrno, - target_ulong new_val) + target_ulong new_val, uintptr_t ra) { return write_sstateen(env, csrno, SMSTATEEN_STATEEN, new_val); } @@ -XXX,XX +XXX,XX @@ static RISCVException read_sstatus(CPURISCVState *env, int csrno, } static RISCVException write_sstatus(CPURISCVState *env, int csrno, - target_ulong val) + target_ulong val, uintptr_t ra) { target_ulong mask = (sstatus_v1_10_mask); @@ -XXX,XX +XXX,XX @@ static RISCVException write_sstatus(CPURISCVState *env, int csrno, mask |= SSTATUS_SDT; } target_ulong newval = (env->mstatus & ~mask) | (val & mask); - return write_mstatus(env, CSR_MSTATUS, newval); + return write_mstatus(env, CSR_MSTATUS, newval, ra); } static RISCVException rmw_vsie64(CPURISCVState *env, int csrno, @@ -XXX,XX +XXX,XX @@ static RISCVException read_stvec(CPURISCVState *env, int csrno, } static RISCVException write_stvec(CPURISCVState *env, int csrno, - target_ulong val) + target_ulong val, uintptr_t ra) { /* bits [1:0] encode mode; 0 = direct, 1 = vectored, 2 >= reserved */ if ((val & 3) < 2) { @@ -XXX,XX +XXX,XX @@ static RISCVException read_scounteren(CPURISCVState *env, int csrno, } static RISCVException write_scounteren(CPURISCVState *env, int csrno, - target_ulong val) + target_ulong val, uintptr_t ra) { RISCVCPU *cpu = env_archcpu(env); @@ -XXX,XX +XXX,XX @@ static RISCVException read_sscratch(CPURISCVState *env, int csrno, } static RISCVException write_sscratch(CPURISCVState *env, int csrno, - target_ulong val) + target_ulong val, uintptr_t ra) { env->sscratch = val; return RISCV_EXCP_NONE; @@ -XXX,XX +XXX,XX @@ static RISCVException read_sepc(CPURISCVState *env, int csrno, } static RISCVException write_sepc(CPURISCVState *env, int csrno, - target_ulong val) + target_ulong val, uintptr_t ra) { env->sepc = val; return RISCV_EXCP_NONE; @@ -XXX,XX +XXX,XX @@ static RISCVException read_scause(CPURISCVState *env, int csrno, } static RISCVException write_scause(CPURISCVState *env, int csrno, - target_ulong val) + target_ulong val, uintptr_t ra) { env->scause = val; return RISCV_EXCP_NONE; @@ -XXX,XX +XXX,XX @@ static RISCVException read_stval(CPURISCVState *env, int csrno, } static RISCVException write_stval(CPURISCVState *env, int csrno, - target_ulong val) + target_ulong val, uintptr_t ra) { env->stval = val; return RISCV_EXCP_NONE; @@ -XXX,XX +XXX,XX @@ static RISCVException read_satp(CPURISCVState *env, int csrno, } static RISCVException write_satp(CPURISCVState *env, int csrno, - target_ulong val) + target_ulong val, uintptr_t ra) { if (!riscv_cpu_cfg(env)->mmu) { return RISCV_EXCP_NONE; @@ -XXX,XX +XXX,XX @@ static RISCVException read_hstatus(CPURISCVState *env, int csrno, } static RISCVException write_hstatus(CPURISCVState *env, int csrno, - target_ulong val) + target_ulong val, uintptr_t ra) { uint64_t mask = (target_ulong)-1; if (!env_archcpu(env)->cfg.ext_svukte) { @@ -XXX,XX +XXX,XX @@ static RISCVException read_hedeleg(CPURISCVState *env, int csrno, } static RISCVException write_hedeleg(CPURISCVState *env, int csrno, - target_ulong val) + target_ulong val, uintptr_t ra) { env->hedeleg = val & vs_delegable_excps; return RISCV_EXCP_NONE; @@ -XXX,XX +XXX,XX @@ static RISCVException read_hedelegh(CPURISCVState *env, int csrno, } static RISCVException write_hedelegh(CPURISCVState *env, int csrno, - target_ulong val) + target_ulong val, uintptr_t ra) { RISCVException ret; ret = smstateen_acc_ok(env, 0, SMSTATEEN0_P1P13); @@ -XXX,XX +XXX,XX @@ static RISCVException read_hcounteren(CPURISCVState *env, int csrno, } static RISCVException write_hcounteren(CPURISCVState *env, int csrno, - target_ulong val) + target_ulong val, uintptr_t ra) { RISCVCPU *cpu = env_archcpu(env); @@ -XXX,XX +XXX,XX @@ static RISCVException read_hgeie(CPURISCVState *env, int csrno, } static RISCVException write_hgeie(CPURISCVState *env, int csrno, - target_ulong val) + target_ulong val, uintptr_t ra) { /* Only GEILEN:1 bits implemented and BIT0 is never implemented */ val &= ((((target_ulong)1) << env->geilen) - 1) << 1; @@ -XXX,XX +XXX,XX @@ static RISCVException read_htval(CPURISCVState *env, int csrno, } static RISCVException write_htval(CPURISCVState *env, int csrno, - target_ulong val) + target_ulong val, uintptr_t ra) { env->htval = val; return RISCV_EXCP_NONE; @@ -XXX,XX +XXX,XX @@ static RISCVException read_htinst(CPURISCVState *env, int csrno, } static RISCVException write_htinst(CPURISCVState *env, int csrno, - target_ulong val) + target_ulong val, uintptr_t ra) { return RISCV_EXCP_NONE; } @@ -XXX,XX +XXX,XX @@ static RISCVException read_hgatp(CPURISCVState *env, int csrno, } static RISCVException write_hgatp(CPURISCVState *env, int csrno, - target_ulong val) + target_ulong val, uintptr_t ra) { env->hgatp = legalize_xatp(env, env->hgatp, val); return RISCV_EXCP_NONE; @@ -XXX,XX +XXX,XX @@ static RISCVException read_htimedelta(CPURISCVState *env, int csrno, } static RISCVException write_htimedelta(CPURISCVState *env, int csrno, - target_ulong val) + target_ulong val, uintptr_t ra) { if (!env->rdtime_fn) { return RISCV_EXCP_ILLEGAL_INST; @@ -XXX,XX +XXX,XX @@ static RISCVException read_htimedeltah(CPURISCVState *env, int csrno, } static RISCVException write_htimedeltah(CPURISCVState *env, int csrno, - target_ulong val) + target_ulong val, uintptr_t ra) { if (!env->rdtime_fn) { return RISCV_EXCP_ILLEGAL_INST; @@ -XXX,XX +XXX,XX @@ static RISCVException read_hvictl(CPURISCVState *env, int csrno, } static RISCVException write_hvictl(CPURISCVState *env, int csrno, - target_ulong val) + target_ulong val, uintptr_t ra) { env->hvictl = val & HVICTL_VALID_MASK; return RISCV_EXCP_NONE; @@ -XXX,XX +XXX,XX @@ static RISCVException read_hviprio1(CPURISCVState *env, int csrno, } static RISCVException write_hviprio1(CPURISCVState *env, int csrno, - target_ulong val) + target_ulong val, uintptr_t ra) { return write_hvipriox(env, 0, env->hviprio, val); } @@ -XXX,XX +XXX,XX @@ static RISCVException read_hviprio1h(CPURISCVState *env, int csrno, } static RISCVException write_hviprio1h(CPURISCVState *env, int csrno, - target_ulong val) + target_ulong val, uintptr_t ra) { return write_hvipriox(env, 4, env->hviprio, val); } @@ -XXX,XX +XXX,XX @@ static RISCVException read_hviprio2(CPURISCVState *env, int csrno, } static RISCVException write_hviprio2(CPURISCVState *env, int csrno, - target_ulong val) + target_ulong val, uintptr_t ra) { return write_hvipriox(env, 8, env->hviprio, val); } @@ -XXX,XX +XXX,XX @@ static RISCVException read_hviprio2h(CPURISCVState *env, int csrno, } static RISCVException write_hviprio2h(CPURISCVState *env, int csrno, - target_ulong val) + target_ulong val, uintptr_t ra) { return write_hvipriox(env, 12, env->hviprio, val); } @@ -XXX,XX +XXX,XX @@ static RISCVException read_vsstatus(CPURISCVState *env, int csrno, } static RISCVException write_vsstatus(CPURISCVState *env, int csrno, - target_ulong val) + target_ulong val, uintptr_t ra) { uint64_t mask = (target_ulong)-1; if ((val & VSSTATUS64_UXL) == 0) { @@ -XXX,XX +XXX,XX @@ static RISCVException read_vstvec(CPURISCVState *env, int csrno, } static RISCVException write_vstvec(CPURISCVState *env, int csrno, - target_ulong val) + target_ulong val, uintptr_t ra) { /* bits [1:0] encode mode; 0 = direct, 1 = vectored, 2 >= reserved */ if ((val & 3) < 2) { @@ -XXX,XX +XXX,XX @@ static RISCVException read_vsscratch(CPURISCVState *env, int csrno, } static RISCVException write_vsscratch(CPURISCVState *env, int csrno, - target_ulong val) + target_ulong val, uintptr_t ra) { env->vsscratch = val; return RISCV_EXCP_NONE; @@ -XXX,XX +XXX,XX @@ static RISCVException read_vsepc(CPURISCVState *env, int csrno, } static RISCVException write_vsepc(CPURISCVState *env, int csrno, - target_ulong val) + target_ulong val, uintptr_t ra) { env->vsepc = val; return RISCV_EXCP_NONE; @@ -XXX,XX +XXX,XX @@ static RISCVException read_vscause(CPURISCVState *env, int csrno, } static RISCVException write_vscause(CPURISCVState *env, int csrno, - target_ulong val) + target_ulong val, uintptr_t ra) { env->vscause = val; return RISCV_EXCP_NONE; @@ -XXX,XX +XXX,XX @@ static RISCVException read_vstval(CPURISCVState *env, int csrno, } static RISCVException write_vstval(CPURISCVState *env, int csrno, - target_ulong val) + target_ulong val, uintptr_t ra) { env->vstval = val; return RISCV_EXCP_NONE; @@ -XXX,XX +XXX,XX @@ static RISCVException read_vsatp(CPURISCVState *env, int csrno, } static RISCVException write_vsatp(CPURISCVState *env, int csrno, - target_ulong val) + target_ulong val, uintptr_t ra) { env->vsatp = legalize_xatp(env, env->vsatp, val); return RISCV_EXCP_NONE; @@ -XXX,XX +XXX,XX @@ static RISCVException read_mtval2(CPURISCVState *env, int csrno, } static RISCVException write_mtval2(CPURISCVState *env, int csrno, - target_ulong val) + target_ulong val, uintptr_t ra) { env->mtval2 = val; return RISCV_EXCP_NONE; @@ -XXX,XX +XXX,XX @@ static RISCVException read_mtinst(CPURISCVState *env, int csrno, } static RISCVException write_mtinst(CPURISCVState *env, int csrno, - target_ulong val) + target_ulong val, uintptr_t ra) { env->mtinst = val; return RISCV_EXCP_NONE; @@ -XXX,XX +XXX,XX @@ static RISCVException read_mseccfg(CPURISCVState *env, int csrno, } static RISCVException write_mseccfg(CPURISCVState *env, int csrno, - target_ulong val) + target_ulong val, uintptr_t ra) { mseccfg_csr_write(env, val); return RISCV_EXCP_NONE; @@ -XXX,XX +XXX,XX @@ static RISCVException read_pmpcfg(CPURISCVState *env, int csrno, } static RISCVException write_pmpcfg(CPURISCVState *env, int csrno, - target_ulong val) + target_ulong val, uintptr_t ra) { uint32_t reg_index = csrno - CSR_PMPCFG0; @@ -XXX,XX +XXX,XX @@ static RISCVException read_pmpaddr(CPURISCVState *env, int csrno, } static RISCVException write_pmpaddr(CPURISCVState *env, int csrno, - target_ulong val) + target_ulong val, uintptr_t ra) { pmpaddr_csr_write(env, csrno - CSR_PMPADDR0, val); return RISCV_EXCP_NONE; @@ -XXX,XX +XXX,XX @@ static RISCVException read_tselect(CPURISCVState *env, int csrno, } static RISCVException write_tselect(CPURISCVState *env, int csrno, - target_ulong val) + target_ulong val, uintptr_t ra) { tselect_csr_write(env, val); return RISCV_EXCP_NONE; @@ -XXX,XX +XXX,XX @@ static RISCVException read_tdata(CPURISCVState *env, int csrno, } static RISCVException write_tdata(CPURISCVState *env, int csrno, - target_ulong val) + target_ulong val, uintptr_t ra) { if (!tdata_available(env, csrno - CSR_TDATA1)) { return RISCV_EXCP_ILLEGAL_INST; @@ -XXX,XX +XXX,XX @@ static RISCVException read_mcontext(CPURISCVState *env, int csrno, } static RISCVException write_mcontext(CPURISCVState *env, int csrno, - target_ulong val) + target_ulong val, uintptr_t ra) { bool rv32 = riscv_cpu_mxl(env) == MXL_RV32 ? true : false; int32_t mask; @@ -XXX,XX +XXX,XX @@ static RISCVException read_mnscratch(CPURISCVState *env, int csrno, return RISCV_EXCP_NONE; } -static int write_mnscratch(CPURISCVState *env, int csrno, target_ulong val) +static RISCVException write_mnscratch(CPURISCVState *env, int csrno, + target_ulong val, uintptr_t ra) { env->mnscratch = val; return RISCV_EXCP_NONE; } -static int read_mnepc(CPURISCVState *env, int csrno, target_ulong *val) +static RISCVException read_mnepc(CPURISCVState *env, int csrno, + target_ulong *val) { *val = env->mnepc; return RISCV_EXCP_NONE; } -static int write_mnepc(CPURISCVState *env, int csrno, target_ulong val) +static RISCVException write_mnepc(CPURISCVState *env, int csrno, + target_ulong val, uintptr_t ra) { env->mnepc = val; return RISCV_EXCP_NONE; } -static int read_mncause(CPURISCVState *env, int csrno, target_ulong *val) +static RISCVException read_mncause(CPURISCVState *env, int csrno, + target_ulong *val) { *val = env->mncause; return RISCV_EXCP_NONE; } -static int write_mncause(CPURISCVState *env, int csrno, target_ulong val) +static RISCVException write_mncause(CPURISCVState *env, int csrno, + target_ulong val, uintptr_t ra) { env->mncause = val; return RISCV_EXCP_NONE; } -static int read_mnstatus(CPURISCVState *env, int csrno, target_ulong *val) +static RISCVException read_mnstatus(CPURISCVState *env, int csrno, + target_ulong *val) { *val = env->mnstatus; return RISCV_EXCP_NONE; } -static int write_mnstatus(CPURISCVState *env, int csrno, target_ulong val) +static RISCVException write_mnstatus(CPURISCVState *env, int csrno, + target_ulong val, uintptr_t ra) { target_ulong mask = (MNSTATUS_NMIE | MNSTATUS_MNPP); @@ -XXX,XX +XXX,XX @@ static RISCVException riscv_csrrw_do64(CPURISCVState *env, int csrno, if (write_mask) { new_value = (old_value & ~write_mask) | (new_value & write_mask); if (csr_ops[csrno].write) { - ret = csr_ops[csrno].write(env, csrno, new_value); + ret = csr_ops[csrno].write(env, csrno, new_value, 0); if (ret != RISCV_EXCP_NONE) { return ret; } @@ -XXX,XX +XXX,XX @@ static RISCVException riscv_csrrw_do128(CPURISCVState *env, int csrno, } } else if (csr_ops[csrno].write) { /* avoids having to write wrappers for all registers */ - ret = csr_ops[csrno].write(env, csrno, int128_getlo(new_value)); + ret = csr_ops[csrno].write(env, csrno, int128_getlo(new_value), 0); if (ret != RISCV_EXCP_NONE) { return ret; } @@ -XXX,XX +XXX,XX @@ static RISCVException read_jvt(CPURISCVState *env, int csrno, } static RISCVException write_jvt(CPURISCVState *env, int csrno, - target_ulong val) + target_ulong val, uintptr_t ra) { env->jvt = val; return RISCV_EXCP_NONE; -- 2.49.0
From: Richard Henderson <richard.henderson@linaro.org> Signed-off-by: Richard Henderson <richard.henderson@linaro.org> Reviewed-by: Alistair Francis <alistair.francis@wdc.com> Reviewed-by: Daniel Henrique Barboza <dbarboza@ventanamicro.com> Reviewed-by: Philippe Mathieu-Daudé <philmd@linaro.org> Message-ID: <20250425152311.804338-3-richard.henderson@linaro.org> Signed-off-by: Alistair Francis <alistair.francis@wdc.com> --- target/riscv/csr.c | 15 +++++++-------- 1 file changed, 7 insertions(+), 8 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 inline RISCVException riscv_csrrw_check(CPURISCVState *env, static RISCVException riscv_csrrw_do64(CPURISCVState *env, int csrno, target_ulong *ret_value, target_ulong new_value, - target_ulong write_mask) + target_ulong write_mask, + uintptr_t ra) { RISCVException ret; target_ulong old_value = 0; @@ -XXX,XX +XXX,XX @@ static RISCVException riscv_csrrw_do64(CPURISCVState *env, int csrno, if (write_mask) { new_value = (old_value & ~write_mask) | (new_value & write_mask); if (csr_ops[csrno].write) { - ret = csr_ops[csrno].write(env, csrno, new_value, 0); + ret = csr_ops[csrno].write(env, csrno, new_value, ra); if (ret != RISCV_EXCP_NONE) { return ret; } @@ -XXX,XX +XXX,XX @@ RISCVException riscv_csrr(CPURISCVState *env, int csrno, return ret; } - return riscv_csrrw_do64(env, csrno, ret_value, 0, 0); + return riscv_csrrw_do64(env, csrno, ret_value, 0, 0, 0); } RISCVException riscv_csrrw(CPURISCVState *env, int csrno, @@ -XXX,XX +XXX,XX @@ RISCVException riscv_csrrw(CPURISCVState *env, int csrno, return ret; } - return riscv_csrrw_do64(env, csrno, ret_value, new_value, write_mask); + return riscv_csrrw_do64(env, csrno, ret_value, new_value, write_mask, 0); } static RISCVException riscv_csrrw_do128(CPURISCVState *env, int csrno, @@ -XXX,XX +XXX,XX @@ RISCVException riscv_csrr_i128(CPURISCVState *env, int csrno, * accesses */ target_ulong old_value; - ret = riscv_csrrw_do64(env, csrno, &old_value, - (target_ulong)0, - (target_ulong)0); + ret = riscv_csrrw_do64(env, csrno, &old_value, 0, 0, 0); if (ret == RISCV_EXCP_NONE && ret_value) { *ret_value = int128_make64(old_value); } @@ -XXX,XX +XXX,XX @@ RISCVException riscv_csrrw_i128(CPURISCVState *env, int csrno, target_ulong old_value; ret = riscv_csrrw_do64(env, csrno, &old_value, int128_getlo(new_value), - int128_getlo(write_mask)); + int128_getlo(write_mask), 0); if (ret == RISCV_EXCP_NONE && ret_value) { *ret_value = int128_make64(old_value); } -- 2.49.0
From: Richard Henderson <richard.henderson@linaro.org> Signed-off-by: Richard Henderson <richard.henderson@linaro.org> Reviewed-by: Alistair Francis <alistair.francis@wdc.com> Reviewed-by: Daniel Henrique Barboza <dbarboza@ventanamicro.com> Reviewed-by: Philippe Mathieu-Daudé <philmd@linaro.org> Message-ID: <20250425152311.804338-4-richard.henderson@linaro.org> Signed-off-by: Alistair Francis <alistair.francis@wdc.com> --- target/riscv/csr.c | 9 +++++---- 1 file changed, 5 insertions(+), 4 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_csrrw(CPURISCVState *env, int csrno, static RISCVException riscv_csrrw_do128(CPURISCVState *env, int csrno, Int128 *ret_value, Int128 new_value, - Int128 write_mask) + Int128 write_mask, uintptr_t ra) { RISCVException ret; Int128 old_value; @@ -XXX,XX +XXX,XX @@ static RISCVException riscv_csrrw_do128(CPURISCVState *env, int csrno, } } else if (csr_ops[csrno].write) { /* avoids having to write wrappers for all registers */ - ret = csr_ops[csrno].write(env, csrno, int128_getlo(new_value), 0); + ret = csr_ops[csrno].write(env, csrno, int128_getlo(new_value), ra); if (ret != RISCV_EXCP_NONE) { return ret; } @@ -XXX,XX +XXX,XX @@ RISCVException riscv_csrr_i128(CPURISCVState *env, int csrno, if (csr_ops[csrno].read128) { return riscv_csrrw_do128(env, csrno, ret_value, - int128_zero(), int128_zero()); + int128_zero(), int128_zero(), 0); } /* @@ -XXX,XX +XXX,XX @@ RISCVException riscv_csrrw_i128(CPURISCVState *env, int csrno, } if (csr_ops[csrno].read128) { - return riscv_csrrw_do128(env, csrno, ret_value, new_value, write_mask); + return riscv_csrrw_do128(env, csrno, ret_value, + new_value, write_mask, 0); } /* -- 2.49.0
From: Richard Henderson <richard.henderson@linaro.org> Signed-off-by: Richard Henderson <richard.henderson@linaro.org> Reviewed-by: Alistair Francis <alistair.francis@wdc.com> Reviewed-by: Daniel Henrique Barboza <dbarboza@ventanamicro.com> Reviewed-by: Philippe Mathieu-Daudé <philmd@linaro.org> Message-ID: <20250425152311.804338-5-richard.henderson@linaro.org> Signed-off-by: Alistair Francis <alistair.francis@wdc.com> --- target/riscv/cpu.h | 8 ++++---- hw/riscv/riscv_hart.c | 2 +- target/riscv/csr.c | 8 ++++---- target/riscv/op_helper.c | 4 ++-- 4 files changed, 11 insertions(+), 11 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 @@ RISCVException riscv_csrr(CPURISCVState *env, int csrno, target_ulong *ret_value); RISCVException riscv_csrrw(CPURISCVState *env, int csrno, - target_ulong *ret_value, - target_ulong new_value, target_ulong write_mask); + target_ulong *ret_value, target_ulong new_value, + target_ulong write_mask, uintptr_t ra); RISCVException riscv_csrrw_debug(CPURISCVState *env, int csrno, target_ulong *ret_value, target_ulong new_value, @@ -XXX,XX +XXX,XX @@ RISCVException riscv_csrrw_debug(CPURISCVState *env, int csrno, static inline void riscv_csr_write(CPURISCVState *env, int csrno, target_ulong val) { - riscv_csrrw(env, csrno, NULL, val, MAKE_64BIT_MASK(0, TARGET_LONG_BITS)); + riscv_csrrw(env, csrno, NULL, val, MAKE_64BIT_MASK(0, TARGET_LONG_BITS), 0); } static inline target_ulong riscv_csr_read(CPURISCVState *env, int csrno) { target_ulong val = 0; - riscv_csrrw(env, csrno, &val, 0, 0); + riscv_csrrw(env, csrno, &val, 0, 0, 0); return val; } diff --git a/hw/riscv/riscv_hart.c b/hw/riscv/riscv_hart.c index XXXXXXX..XXXXXXX 100644 --- a/hw/riscv/riscv_hart.c +++ b/hw/riscv/riscv_hart.c @@ -XXX,XX +XXX,XX @@ static void csr_call(char *cmd, uint64_t cpu_num, int csrno, uint64_t *val) ret = riscv_csrr(env, csrno, (target_ulong *)val); } else if (strcmp(cmd, "set_csr") == 0) { ret = riscv_csrrw(env, csrno, NULL, *(target_ulong *)val, - MAKE_64BIT_MASK(0, TARGET_LONG_BITS)); + MAKE_64BIT_MASK(0, TARGET_LONG_BITS), 0); } g_assert(ret == RISCV_EXCP_NONE); 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_csrr(CPURISCVState *env, int csrno, } RISCVException riscv_csrrw(CPURISCVState *env, int csrno, - target_ulong *ret_value, - target_ulong new_value, target_ulong write_mask) + target_ulong *ret_value, target_ulong new_value, + target_ulong write_mask, uintptr_t ra) { RISCVException ret = riscv_csrrw_check(env, csrno, true); if (ret != RISCV_EXCP_NONE) { return ret; } - return riscv_csrrw_do64(env, csrno, ret_value, new_value, write_mask, 0); + return riscv_csrrw_do64(env, csrno, ret_value, new_value, write_mask, ra); } static RISCVException riscv_csrrw_do128(CPURISCVState *env, int csrno, @@ -XXX,XX +XXX,XX @@ RISCVException riscv_csrrw_debug(CPURISCVState *env, int csrno, if (!write_mask) { ret = riscv_csrr(env, csrno, ret_value); } else { - ret = riscv_csrrw(env, csrno, ret_value, new_value, write_mask); + ret = riscv_csrrw(env, csrno, ret_value, new_value, write_mask, 0); } #if !defined(CONFIG_USER_ONLY) env->debugger = false; diff --git a/target/riscv/op_helper.c b/target/riscv/op_helper.c index XXXXXXX..XXXXXXX 100644 --- a/target/riscv/op_helper.c +++ b/target/riscv/op_helper.c @@ -XXX,XX +XXX,XX @@ target_ulong helper_csrr(CPURISCVState *env, int csr) void helper_csrw(CPURISCVState *env, int csr, target_ulong src) { target_ulong mask = env->xl == MXL_RV32 ? UINT32_MAX : (target_ulong)-1; - RISCVException ret = riscv_csrrw(env, csr, NULL, src, mask); + RISCVException ret = riscv_csrrw(env, csr, NULL, src, mask, GETPC()); if (ret != RISCV_EXCP_NONE) { riscv_raise_exception(env, ret, GETPC()); @@ -XXX,XX +XXX,XX @@ target_ulong helper_csrrw(CPURISCVState *env, int csr, target_ulong src, target_ulong write_mask) { target_ulong val = 0; - RISCVException ret = riscv_csrrw(env, csr, &val, src, write_mask); + RISCVException ret = riscv_csrrw(env, csr, &val, src, write_mask, GETPC()); if (ret != RISCV_EXCP_NONE) { riscv_raise_exception(env, ret, GETPC()); -- 2.49.0
From: Richard Henderson <richard.henderson@linaro.org> Signed-off-by: Richard Henderson <richard.henderson@linaro.org> Reviewed-by: Alistair Francis <alistair.francis@wdc.com> Reviewed-by: Daniel Henrique Barboza <dbarboza@ventanamicro.com> Reviewed-by: Philippe Mathieu-Daudé <philmd@linaro.org> Message-ID: <20250425152311.804338-6-richard.henderson@linaro.org> Signed-off-by: Alistair Francis <alistair.francis@wdc.com> --- target/riscv/cpu.h | 4 ++-- target/riscv/csr.c | 8 ++++---- target/riscv/op_helper.c | 9 +++++---- 3 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 @@ typedef RISCVException (*riscv_csr_op_fn)(CPURISCVState *env, int csrno, RISCVException riscv_csrr_i128(CPURISCVState *env, int csrno, Int128 *ret_value); RISCVException riscv_csrrw_i128(CPURISCVState *env, int csrno, - Int128 *ret_value, - Int128 new_value, Int128 write_mask); + Int128 *ret_value, Int128 new_value, + Int128 write_mask, uintptr_t ra); typedef RISCVException (*riscv_csr_read128_fn)(CPURISCVState *env, int csrno, Int128 *ret_value); 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_csrr_i128(CPURISCVState *env, int csrno, } RISCVException riscv_csrrw_i128(CPURISCVState *env, int csrno, - Int128 *ret_value, - Int128 new_value, Int128 write_mask) + Int128 *ret_value, Int128 new_value, + Int128 write_mask, uintptr_t ra) { RISCVException ret; @@ -XXX,XX +XXX,XX @@ RISCVException riscv_csrrw_i128(CPURISCVState *env, int csrno, if (csr_ops[csrno].read128) { return riscv_csrrw_do128(env, csrno, ret_value, - new_value, write_mask, 0); + new_value, write_mask, ra); } /* @@ -XXX,XX +XXX,XX @@ RISCVException riscv_csrrw_i128(CPURISCVState *env, int csrno, target_ulong old_value; ret = riscv_csrrw_do64(env, csrno, &old_value, int128_getlo(new_value), - int128_getlo(write_mask), 0); + int128_getlo(write_mask), ra); if (ret == RISCV_EXCP_NONE && ret_value) { *ret_value = int128_make64(old_value); } diff --git a/target/riscv/op_helper.c b/target/riscv/op_helper.c index XXXXXXX..XXXXXXX 100644 --- a/target/riscv/op_helper.c +++ b/target/riscv/op_helper.c @@ -XXX,XX +XXX,XX @@ void helper_csrw_i128(CPURISCVState *env, int csr, { RISCVException ret = riscv_csrrw_i128(env, csr, NULL, int128_make128(srcl, srch), - UINT128_MAX); + UINT128_MAX, GETPC()); if (ret != RISCV_EXCP_NONE) { riscv_raise_exception(env, ret, GETPC()); @@ -XXX,XX +XXX,XX @@ void helper_csrw_i128(CPURISCVState *env, int csr, } target_ulong helper_csrrw_i128(CPURISCVState *env, int csr, - target_ulong srcl, target_ulong srch, - target_ulong maskl, target_ulong maskh) + target_ulong srcl, target_ulong srch, + target_ulong maskl, target_ulong maskh) { Int128 rv = int128_zero(); RISCVException ret = riscv_csrrw_i128(env, csr, &rv, int128_make128(srcl, srch), - int128_make128(maskl, maskh)); + int128_make128(maskl, maskh), + GETPC()); if (ret != RISCV_EXCP_NONE) { riscv_raise_exception(env, ret, GETPC()); -- 2.49.0
From: Richard Henderson <richard.henderson@linaro.org> Signed-off-by: Richard Henderson <richard.henderson@linaro.org> Reviewed-by: Alistair Francis <alistair.francis@wdc.com> Reviewed-by: Daniel Henrique Barboza <dbarboza@ventanamicro.com> Reviewed-by: Philippe Mathieu-Daudé <philmd@linaro.org> Message-ID: <20250425152311.804338-7-richard.henderson@linaro.org> Signed-off-by: Alistair Francis <alistair.francis@wdc.com> --- target/riscv/internals.h | 5 +++++ target/riscv/translate.c | 5 ----- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/target/riscv/internals.h b/target/riscv/internals.h index XXXXXXX..XXXXXXX 100644 --- a/target/riscv/internals.h +++ b/target/riscv/internals.h @@ -XXX,XX +XXX,XX @@ static inline target_ulong adjust_addr_virt(CPURISCVState *env, return adjust_addr_body(env, addr, true); } +static inline int insn_len(uint16_t first_word) +{ + return (first_word & 3) == 3 ? 4 : 2; +} + #endif 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) /* The specification allows for longer insns, but not supported by qemu. */ #define MAX_INSN_LEN 4 -static inline int insn_len(uint16_t first_word) -{ - return (first_word & 3) == 3 ? 4 : 2; -} - const RISCVDecoder decoder_table[] = { { always_true_p, decode_insn32 }, { has_xthead_p, decode_xthead}, -- 2.49.0
From: Richard Henderson <richard.henderson@linaro.org> Do not examine a random host return address, but properly compute the next pc for the guest cpu. Fixes: f18637cd611 ("RISC-V: Add misa runtime write support") Signed-off-by: Richard Henderson <richard.henderson@linaro.org> Reviewed-by: Alistair Francis <alistair.francis@wdc.com> Reviewed-by: Daniel Henrique Barboza <dbarboza@ventanamicro.com> Reviewed-by: Philippe Mathieu-Daudé <philmd@linaro.org> Message-ID: <20250425152311.804338-8-richard.henderson@linaro.org> [ Changes by AF: - Change `& ~3` to `& 3` ] Signed-off-by: Alistair Francis <alistair.francis@wdc.com> --- target/riscv/csr.c | 22 +++++++++++++++++----- 1 file changed, 17 insertions(+), 5 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 @@ #include "accel/tcg/getpc.h" #include "qemu/guest-random.h" #include "qapi/error.h" +#include "tcg/insn-start-words.h" +#include "internals.h" #include <stdbool.h> /* CSR function table public API */ @@ -XXX,XX +XXX,XX @@ static RISCVException read_misa(CPURISCVState *env, int csrno, return RISCV_EXCP_NONE; } +static target_ulong get_next_pc(CPURISCVState *env, uintptr_t ra) +{ + uint64_t data[INSN_START_WORDS]; + + /* Outside of a running cpu, env contains the next pc. */ + if (ra == 0 || !cpu_unwind_state_data(env_cpu(env), ra, data)) { + return env->pc; + } + + /* Within unwind data, [0] is pc and [1] is the opcode. */ + return data[0] + insn_len(data[1]); +} + static RISCVException write_misa(CPURISCVState *env, int csrno, target_ulong val, uintptr_t ra) { @@ -XXX,XX +XXX,XX @@ static RISCVException write_misa(CPURISCVState *env, int csrno, /* Mask extensions that are not supported by this hart */ val &= env->misa_ext_mask; - /* - * Suppress 'C' if next instruction is not aligned - * TODO: this should check next_pc - */ - if ((val & RVC) && (GETPC() & ~3) != 0) { + /* Suppress 'C' if next instruction is not aligned. */ + if ((val & RVC) && (get_next_pc(env, ra) & 3) != 0) { val &= ~RVC; } -- 2.49.0
From: Daniel Henrique Barboza <dbarboza@ventanamicro.com> Remove an unused 'KVMScratchCPU' pointer argument in kvm_riscv_check_sbi_dbcn_support(). Put kvm_riscv_reset_regs_csr() after kvm_riscv_put_regs_csr(). This will make a future patch diff easier to read, when changes in kvm_riscv_reset_regs_csr() and kvm_riscv_get_regs_csr() will be made. Fixes: a6b53378f5 ("target/riscv/kvm: implement SBI debug console (DBCN) calls") Signed-off-by: Daniel Henrique Barboza <dbarboza@ventanamicro.com> Reviewed-by: Andrew Jones <ajones@ventanamicro.com> Reviewed-by: Alistair Francis <alistair.francis@wdc.com> Message-ID: <20250429124421.223883-2-dbarboza@ventanamicro.com> Signed-off-by: Alistair Francis <alistair.francis@wdc.com> Cc: qemu-stable@nongnu.org --- target/riscv/kvm/kvm-cpu.c | 29 ++++++++++++++--------------- 1 file changed, 14 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 int kvm_riscv_put_regs_core(CPUState *cs) return ret; } -static void kvm_riscv_reset_regs_csr(CPURISCVState *env) -{ - env->mstatus = 0; - env->mie = 0; - env->stvec = 0; - env->sscratch = 0; - env->sepc = 0; - env->scause = 0; - env->stval = 0; - env->mip = 0; - env->satp = 0; -} - static int kvm_riscv_get_regs_csr(CPUState *cs) { CPURISCVState *env = &RISCV_CPU(cs)->env; @@ -XXX,XX +XXX,XX @@ static int kvm_riscv_put_regs_csr(CPUState *cs) return 0; } +static void kvm_riscv_reset_regs_csr(CPURISCVState *env) +{ + env->mstatus = 0; + env->mie = 0; + env->stvec = 0; + env->sscratch = 0; + env->sepc = 0; + env->scause = 0; + env->stval = 0; + env->mip = 0; + env->satp = 0; +} + static int kvm_riscv_get_regs_fp(CPUState *cs) { int ret = 0; @@ -XXX,XX +XXX,XX @@ static int uint64_cmp(const void *a, const void *b) } static void kvm_riscv_check_sbi_dbcn_support(RISCVCPU *cpu, - KVMScratchCPU *kvmcpu, struct kvm_reg_list *reglist) { struct kvm_reg_list *reg_search; @@ -XXX,XX +XXX,XX @@ static void kvm_riscv_init_multiext_cfg(RISCVCPU *cpu, KVMScratchCPU *kvmcpu) kvm_riscv_read_vlenb(cpu, kvmcpu, reglist); } - kvm_riscv_check_sbi_dbcn_support(cpu, kvmcpu, reglist); + kvm_riscv_check_sbi_dbcn_support(cpu, reglist); } static void riscv_init_kvm_registers(Object *cpu_obj) -- 2.49.0
From: Daniel Henrique Barboza <dbarboza@ventanamicro.com> 'reglist' is being g-malloc'ed but never freed. Reported-by: Andrew Jones <ajones@ventanamicro.com> Signed-off-by: Daniel Henrique Barboza <dbarboza@ventanamicro.com> Reviewed-by: Andrew Jones <ajones@ventanamicro.com> Reviewed-by: Alistair Francis <alistair.francis@wdc.com> Message-ID: <20250429124421.223883-3-dbarboza@ventanamicro.com> Signed-off-by: Alistair Francis <alistair.francis@wdc.com> Cc: qemu-stable@nongnu.org --- target/riscv/kvm/kvm-cpu.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/target/riscv/kvm/kvm-cpu.c b/target/riscv/kvm/kvm-cpu.c index XXXXXXX..XXXXXXX 100644 --- a/target/riscv/kvm/kvm-cpu.c +++ b/target/riscv/kvm/kvm-cpu.c @@ -XXX,XX +XXX,XX @@ static void kvm_riscv_read_vlenb(RISCVCPU *cpu, KVMScratchCPU *kvmcpu, static void kvm_riscv_init_multiext_cfg(RISCVCPU *cpu, KVMScratchCPU *kvmcpu) { + g_autofree struct kvm_reg_list *reglist = NULL; KVMCPUConfig *multi_ext_cfg; struct kvm_one_reg reg; struct kvm_reg_list rl_struct; - struct kvm_reg_list *reglist; uint64_t val, reg_id, *reg_search; int i, ret; -- 2.49.0
From: Daniel Henrique Barboza <dbarboza@ventanamicro.com> This change is motivated by a future change w.r.t CSRs management. We want to handle them the same way as KVM extensions, i.e. a static array with KVMCPUConfig objs that will be read/write during init and so on. But to do that properly we must be able to declare a static array that hold KVM regs. C does not allow to init static arrays and use functions as initializers, e.g. we can't do: .kvm_reg_id = kvm_riscv_reg_id_ulong(...) When instantiating the array. We can do that with macros though, so our goal is turn kvm_riscv_reg_ulong() in a macro. It is cleaner to turn every other reg_id_*() function in macros, and ulong will end up using the macros for u32 and u64, so we'll start with them. Signed-off-by: Daniel Henrique Barboza <dbarboza@ventanamicro.com> Reviewed-by: Andrew Jones <ajones@ventanamicro.com> Reviewed-by: Alistair Francis <alistair.francis@wdc.com> Message-ID: <20250429124421.223883-4-dbarboza@ventanamicro.com> Signed-off-by: Alistair Francis <alistair.francis@wdc.com> Cc: qemu-stable@nongnu.org --- target/riscv/kvm/kvm-cpu.c | 22 +++++++++------------- 1 file changed, 9 insertions(+), 13 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 @@ void riscv_kvm_aplic_request(void *opaque, int irq, int level) static bool cap_has_mp_state; +#define KVM_RISCV_REG_ID_U32(type, idx) (KVM_REG_RISCV | KVM_REG_SIZE_U32 | \ + type | idx) + +#define KVM_RISCV_REG_ID_U64(type, idx) (KVM_REG_RISCV | KVM_REG_SIZE_U64 | \ + type | idx) + static uint64_t kvm_riscv_reg_id_ulong(CPURISCVState *env, uint64_t type, uint64_t idx) { @@ -XXX,XX +XXX,XX @@ static uint64_t kvm_riscv_reg_id_ulong(CPURISCVState *env, uint64_t type, return id; } -static uint64_t kvm_riscv_reg_id_u32(uint64_t type, uint64_t idx) -{ - return KVM_REG_RISCV | KVM_REG_SIZE_U32 | type | idx; -} - -static uint64_t kvm_riscv_reg_id_u64(uint64_t type, uint64_t idx) -{ - return KVM_REG_RISCV | KVM_REG_SIZE_U64 | type | idx; -} - static uint64_t kvm_encode_reg_size_id(uint64_t id, size_t size_b) { uint64_t size_ctz = __builtin_ctz(size_b); @@ -XXX,XX +XXX,XX @@ static uint64_t kvm_riscv_vector_reg_id(RISCVCPU *cpu, kvm_riscv_reg_id_ulong(env, KVM_REG_RISCV_CONFIG, \ KVM_REG_RISCV_CONFIG_REG(name)) -#define RISCV_TIMER_REG(name) kvm_riscv_reg_id_u64(KVM_REG_RISCV_TIMER, \ +#define RISCV_TIMER_REG(name) KVM_RISCV_REG_ID_U64(KVM_REG_RISCV_TIMER, \ KVM_REG_RISCV_TIMER_REG(name)) -#define RISCV_FP_F_REG(idx) kvm_riscv_reg_id_u32(KVM_REG_RISCV_FP_F, idx) +#define RISCV_FP_F_REG(idx) KVM_RISCV_REG_ID_U32(KVM_REG_RISCV_FP_F, idx) -#define RISCV_FP_D_REG(idx) kvm_riscv_reg_id_u64(KVM_REG_RISCV_FP_D, idx) +#define RISCV_FP_D_REG(idx) KVM_RISCV_REG_ID_U64(KVM_REG_RISCV_FP_D, idx) #define RISCV_VECTOR_CSR_REG(env, name) \ kvm_riscv_reg_id_ulong(env, KVM_REG_RISCV_VECTOR, \ -- 2.49.0
From: Daniel Henrique Barboza <dbarboza@ventanamicro.com> We need the reg_id_ulong() helper to be a macro to be able to create a static array of KVMCPUConfig that will hold CSR information. Despite the amount of changes all of them are tedious/trivial: - replace instances of "kvm_riscv_reg_id_ulong" with "KVM_RISCV_REG_ID_ULONG"; - RISCV_CORE_REG(), RISCV_CSR_REG(), RISCV_CONFIG_REG() and RISCV_VECTOR_CSR_REG() only receives one 'name' arg. Remove unneeded 'env' variables when applicable. Signed-off-by: Daniel Henrique Barboza <dbarboza@ventanamicro.com> Reviewed-by: Andrew Jones <ajones@ventanamicro.com> Reviewed-by: Alistair Francis <alistair.francis@wdc.com> Message-ID: <20250429124421.223883-5-dbarboza@ventanamicro.com> Signed-off-by: Alistair Francis <alistair.francis@wdc.com> Cc: qemu-stable@nongnu.org --- target/riscv/kvm/kvm-cpu.c | 99 ++++++++++++++++---------------------- 1 file changed, 41 insertions(+), 58 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 bool cap_has_mp_state; #define KVM_RISCV_REG_ID_U64(type, idx) (KVM_REG_RISCV | KVM_REG_SIZE_U64 | \ type | idx) -static uint64_t kvm_riscv_reg_id_ulong(CPURISCVState *env, uint64_t type, - uint64_t idx) -{ - uint64_t id = KVM_REG_RISCV | type | idx; - - switch (riscv_cpu_mxl(env)) { - case MXL_RV32: - id |= KVM_REG_SIZE_U32; - break; - case MXL_RV64: - id |= KVM_REG_SIZE_U64; - break; - default: - g_assert_not_reached(); - } - return id; -} +#if defined(TARGET_RISCV64) +#define KVM_RISCV_REG_ID_ULONG(type, idx) KVM_RISCV_REG_ID_U64(type, idx) +#else +#define KVM_RISCV_REG_ID_ULONG(type, idx) KVM_RISCV_REG_ID_U32(type, idx) +#endif static uint64_t kvm_encode_reg_size_id(uint64_t id, size_t size_b) { @@ -XXX,XX +XXX,XX @@ static uint64_t kvm_riscv_vector_reg_id(RISCVCPU *cpu, return kvm_encode_reg_size_id(id, size_b); } -#define RISCV_CORE_REG(env, name) \ - kvm_riscv_reg_id_ulong(env, KVM_REG_RISCV_CORE, \ +#define RISCV_CORE_REG(name) \ + KVM_RISCV_REG_ID_ULONG(KVM_REG_RISCV_CORE, \ KVM_REG_RISCV_CORE_REG(name)) -#define RISCV_CSR_REG(env, name) \ - kvm_riscv_reg_id_ulong(env, KVM_REG_RISCV_CSR, \ +#define RISCV_CSR_REG(name) \ + KVM_RISCV_REG_ID_ULONG(KVM_REG_RISCV_CSR, \ KVM_REG_RISCV_CSR_REG(name)) -#define RISCV_CONFIG_REG(env, name) \ - kvm_riscv_reg_id_ulong(env, KVM_REG_RISCV_CONFIG, \ +#define RISCV_CONFIG_REG(name) \ + KVM_RISCV_REG_ID_ULONG(KVM_REG_RISCV_CONFIG, \ KVM_REG_RISCV_CONFIG_REG(name)) #define RISCV_TIMER_REG(name) KVM_RISCV_REG_ID_U64(KVM_REG_RISCV_TIMER, \ @@ -XXX,XX +XXX,XX @@ static uint64_t kvm_riscv_vector_reg_id(RISCVCPU *cpu, #define RISCV_FP_D_REG(idx) KVM_RISCV_REG_ID_U64(KVM_REG_RISCV_FP_D, idx) -#define RISCV_VECTOR_CSR_REG(env, name) \ - kvm_riscv_reg_id_ulong(env, KVM_REG_RISCV_VECTOR, \ +#define RISCV_VECTOR_CSR_REG(name) \ + KVM_RISCV_REG_ID_ULONG(KVM_REG_RISCV_VECTOR, \ KVM_REG_RISCV_VECTOR_CSR_REG(name)) #define KVM_RISCV_GET_CSR(cs, env, csr, reg) \ do { \ - int _ret = kvm_get_one_reg(cs, RISCV_CSR_REG(env, csr), ®); \ + int _ret = kvm_get_one_reg(cs, RISCV_CSR_REG(csr), ®); \ if (_ret) { \ return _ret; \ } \ @@ -XXX,XX +XXX,XX @@ static uint64_t kvm_riscv_vector_reg_id(RISCVCPU *cpu, #define KVM_RISCV_SET_CSR(cs, env, csr, reg) \ do { \ - int _ret = kvm_set_one_reg(cs, RISCV_CSR_REG(env, csr), ®); \ + int _ret = kvm_set_one_reg(cs, RISCV_CSR_REG(csr), ®); \ if (_ret) { \ return _ret; \ } \ @@ -XXX,XX +XXX,XX @@ static void kvm_riscv_update_cpu_misa_ext(RISCVCPU *cpu, CPUState *cs) /* If we're here we're going to disable the MISA bit */ reg = 0; - id = kvm_riscv_reg_id_ulong(env, KVM_REG_RISCV_ISA_EXT, + id = KVM_RISCV_REG_ID_ULONG(KVM_REG_RISCV_ISA_EXT, misa_cfg->kvm_reg_id); ret = kvm_set_one_reg(cs, id, ®); if (ret != 0) { @@ -XXX,XX +XXX,XX @@ static KVMCPUConfig kvm_sbi_dbcn = { static void kvm_riscv_update_cpu_cfg_isa_ext(RISCVCPU *cpu, CPUState *cs) { - CPURISCVState *env = &cpu->env; uint64_t id, reg; int i, ret; @@ -XXX,XX +XXX,XX @@ static void kvm_riscv_update_cpu_cfg_isa_ext(RISCVCPU *cpu, CPUState *cs) continue; } - id = kvm_riscv_reg_id_ulong(env, KVM_REG_RISCV_ISA_EXT, + id = KVM_RISCV_REG_ID_ULONG(KVM_REG_RISCV_ISA_EXT, multi_ext_cfg->kvm_reg_id); reg = kvm_cpu_cfg_get(cpu, multi_ext_cfg); ret = kvm_set_one_reg(cs, id, ®); @@ -XXX,XX +XXX,XX @@ static int kvm_riscv_get_regs_core(CPUState *cs) target_ulong reg; CPURISCVState *env = &RISCV_CPU(cs)->env; - ret = kvm_get_one_reg(cs, RISCV_CORE_REG(env, regs.pc), ®); + ret = kvm_get_one_reg(cs, RISCV_CORE_REG(regs.pc), ®); if (ret) { return ret; } env->pc = reg; for (i = 1; i < 32; i++) { - uint64_t id = kvm_riscv_reg_id_ulong(env, KVM_REG_RISCV_CORE, i); + uint64_t id = KVM_RISCV_REG_ID_ULONG(KVM_REG_RISCV_CORE, i); ret = kvm_get_one_reg(cs, id, ®); if (ret) { return ret; @@ -XXX,XX +XXX,XX @@ static int kvm_riscv_put_regs_core(CPUState *cs) CPURISCVState *env = &RISCV_CPU(cs)->env; reg = env->pc; - ret = kvm_set_one_reg(cs, RISCV_CORE_REG(env, regs.pc), ®); + ret = kvm_set_one_reg(cs, RISCV_CORE_REG(regs.pc), ®); if (ret) { return ret; } for (i = 1; i < 32; i++) { - uint64_t id = kvm_riscv_reg_id_ulong(env, KVM_REG_RISCV_CORE, i); + uint64_t id = KVM_RISCV_REG_ID_ULONG(KVM_REG_RISCV_CORE, i); reg = env->gpr[i]; ret = kvm_set_one_reg(cs, id, ®); if (ret) { @@ -XXX,XX +XXX,XX @@ static int kvm_riscv_get_regs_vector(CPUState *cs) return 0; } - ret = kvm_get_one_reg(cs, RISCV_VECTOR_CSR_REG(env, vstart), ®); + ret = kvm_get_one_reg(cs, RISCV_VECTOR_CSR_REG(vstart), ®); if (ret) { return ret; } env->vstart = reg; - ret = kvm_get_one_reg(cs, RISCV_VECTOR_CSR_REG(env, vl), ®); + ret = kvm_get_one_reg(cs, RISCV_VECTOR_CSR_REG(vl), ®); if (ret) { return ret; } env->vl = reg; - ret = kvm_get_one_reg(cs, RISCV_VECTOR_CSR_REG(env, vtype), ®); + ret = kvm_get_one_reg(cs, RISCV_VECTOR_CSR_REG(vtype), ®); if (ret) { return ret; } env->vtype = reg; if (kvm_v_vlenb.supported) { - ret = kvm_get_one_reg(cs, RISCV_VECTOR_CSR_REG(env, vlenb), ®); + ret = kvm_get_one_reg(cs, RISCV_VECTOR_CSR_REG(vlenb), ®); if (ret) { return ret; } @@ -XXX,XX +XXX,XX @@ static int kvm_riscv_put_regs_vector(CPUState *cs) } reg = env->vstart; - ret = kvm_set_one_reg(cs, RISCV_VECTOR_CSR_REG(env, vstart), ®); + ret = kvm_set_one_reg(cs, RISCV_VECTOR_CSR_REG(vstart), ®); if (ret) { return ret; } reg = env->vl; - ret = kvm_set_one_reg(cs, RISCV_VECTOR_CSR_REG(env, vl), ®); + ret = kvm_set_one_reg(cs, RISCV_VECTOR_CSR_REG(vl), ®); if (ret) { return ret; } reg = env->vtype; - ret = kvm_set_one_reg(cs, RISCV_VECTOR_CSR_REG(env, vtype), ®); + ret = kvm_set_one_reg(cs, RISCV_VECTOR_CSR_REG(vtype), ®); if (ret) { return ret; } if (kvm_v_vlenb.supported) { reg = cpu->cfg.vlenb; - ret = kvm_set_one_reg(cs, RISCV_VECTOR_CSR_REG(env, vlenb), ®); + ret = kvm_set_one_reg(cs, RISCV_VECTOR_CSR_REG(vlenb), ®); for (int i = 0; i < 32; i++) { /* @@ -XXX,XX +XXX,XX @@ static void kvm_riscv_destroy_scratch_vcpu(KVMScratchCPU *scratch) static void kvm_riscv_init_machine_ids(RISCVCPU *cpu, KVMScratchCPU *kvmcpu) { - CPURISCVState *env = &cpu->env; struct kvm_one_reg reg; int ret; - reg.id = RISCV_CONFIG_REG(env, mvendorid); + reg.id = RISCV_CONFIG_REG(mvendorid); reg.addr = (uint64_t)&cpu->cfg.mvendorid; ret = ioctl(kvmcpu->cpufd, KVM_GET_ONE_REG, ®); if (ret != 0) { error_report("Unable to retrieve mvendorid from host, error %d", ret); } - reg.id = RISCV_CONFIG_REG(env, marchid); + reg.id = RISCV_CONFIG_REG(marchid); reg.addr = (uint64_t)&cpu->cfg.marchid; ret = ioctl(kvmcpu->cpufd, KVM_GET_ONE_REG, ®); if (ret != 0) { error_report("Unable to retrieve marchid from host, error %d", ret); } - reg.id = RISCV_CONFIG_REG(env, mimpid); + reg.id = RISCV_CONFIG_REG(mimpid); reg.addr = (uint64_t)&cpu->cfg.mimpid; ret = ioctl(kvmcpu->cpufd, KVM_GET_ONE_REG, ®); if (ret != 0) { @@ -XXX,XX +XXX,XX @@ static void kvm_riscv_init_misa_ext_mask(RISCVCPU *cpu, struct kvm_one_reg reg; int ret; - reg.id = RISCV_CONFIG_REG(env, isa); + reg.id = RISCV_CONFIG_REG(isa); reg.addr = (uint64_t)&env->misa_ext_mask; ret = ioctl(kvmcpu->cpufd, KVM_GET_ONE_REG, ®); @@ -XXX,XX +XXX,XX @@ static void kvm_riscv_init_misa_ext_mask(RISCVCPU *cpu, static void kvm_riscv_read_cbomz_blksize(RISCVCPU *cpu, KVMScratchCPU *kvmcpu, KVMCPUConfig *cbomz_cfg) { - CPURISCVState *env = &cpu->env; struct kvm_one_reg reg; int ret; - reg.id = kvm_riscv_reg_id_ulong(env, KVM_REG_RISCV_CONFIG, + reg.id = KVM_RISCV_REG_ID_ULONG(KVM_REG_RISCV_CONFIG, cbomz_cfg->kvm_reg_id); reg.addr = (uint64_t)kvmconfig_get_cfg_addr(cpu, cbomz_cfg); ret = ioctl(kvmcpu->cpufd, KVM_GET_ONE_REG, ®); @@ -XXX,XX +XXX,XX @@ static void kvm_riscv_read_cbomz_blksize(RISCVCPU *cpu, KVMScratchCPU *kvmcpu, static void kvm_riscv_read_multiext_legacy(RISCVCPU *cpu, KVMScratchCPU *kvmcpu) { - CPURISCVState *env = &cpu->env; uint64_t val; int i, ret; @@ -XXX,XX +XXX,XX @@ static void kvm_riscv_read_multiext_legacy(RISCVCPU *cpu, KVMCPUConfig *multi_ext_cfg = &kvm_multi_ext_cfgs[i]; struct kvm_one_reg reg; - reg.id = kvm_riscv_reg_id_ulong(env, KVM_REG_RISCV_ISA_EXT, + reg.id = KVM_RISCV_REG_ID_ULONG(KVM_REG_RISCV_ISA_EXT, multi_ext_cfg->kvm_reg_id); reg.addr = (uint64_t)&val; ret = ioctl(kvmcpu->cpufd, KVM_GET_ONE_REG, ®); @@ -XXX,XX +XXX,XX @@ static void kvm_riscv_init_multiext_cfg(RISCVCPU *cpu, KVMScratchCPU *kvmcpu) for (i = 0; i < ARRAY_SIZE(kvm_multi_ext_cfgs); i++) { multi_ext_cfg = &kvm_multi_ext_cfgs[i]; - reg_id = kvm_riscv_reg_id_ulong(&cpu->env, KVM_REG_RISCV_ISA_EXT, + reg_id = KVM_RISCV_REG_ID_ULONG(KVM_REG_RISCV_ISA_EXT, multi_ext_cfg->kvm_reg_id); reg_search = bsearch(®_id, reglist->reg, reglist->n, sizeof(uint64_t), uint64_cmp); @@ -XXX,XX +XXX,XX @@ void kvm_arch_init_irq_routing(KVMState *s) static int kvm_vcpu_set_machine_ids(RISCVCPU *cpu, CPUState *cs) { - CPURISCVState *env = &cpu->env; target_ulong reg; uint64_t id; int ret; - id = RISCV_CONFIG_REG(env, mvendorid); + id = RISCV_CONFIG_REG(mvendorid); /* * cfg.mvendorid is an uint32 but a target_ulong will * be written. Assign it to a target_ulong var to avoid @@ -XXX,XX +XXX,XX @@ static int kvm_vcpu_set_machine_ids(RISCVCPU *cpu, CPUState *cs) return ret; } - id = RISCV_CONFIG_REG(env, marchid); + id = RISCV_CONFIG_REG(marchid); ret = kvm_set_one_reg(cs, id, &cpu->cfg.marchid); if (ret != 0) { return ret; } - id = RISCV_CONFIG_REG(env, mimpid); + id = RISCV_CONFIG_REG(mimpid); ret = kvm_set_one_reg(cs, id, &cpu->cfg.mimpid); return ret; @@ -XXX,XX +XXX,XX @@ void riscv_kvm_cpu_finalize_features(RISCVCPU *cpu, Error **errp) if (cpu->cfg.ext_zicbom && riscv_cpu_option_set(kvm_cbom_blocksize.name)) { - reg.id = kvm_riscv_reg_id_ulong(env, KVM_REG_RISCV_CONFIG, + reg.id = KVM_RISCV_REG_ID_ULONG(KVM_REG_RISCV_CONFIG, kvm_cbom_blocksize.kvm_reg_id); reg.addr = (uint64_t)&val; ret = ioctl(kvmcpu.cpufd, KVM_GET_ONE_REG, ®); @@ -XXX,XX +XXX,XX @@ void riscv_kvm_cpu_finalize_features(RISCVCPU *cpu, Error **errp) if (cpu->cfg.ext_zicboz && riscv_cpu_option_set(kvm_cboz_blocksize.name)) { - reg.id = kvm_riscv_reg_id_ulong(env, KVM_REG_RISCV_CONFIG, + reg.id = KVM_RISCV_REG_ID_ULONG(KVM_REG_RISCV_CONFIG, kvm_cboz_blocksize.kvm_reg_id); reg.addr = (uint64_t)&val; ret = ioctl(kvmcpu.cpufd, KVM_GET_ONE_REG, ®); -- 2.49.0
From: Daniel Henrique Barboza <dbarboza@ventanamicro.com> At this moment we're not checking if the host has support for any specific CSR before doing get/put regs. This will cause problems if the host KVM doesn't support it (see [1] as an example). We'll use the same approach done with the CPU extensions: read all known KVM CSRs during init() to check for availability, then read/write them if they are present. This will be made by either using get-reglist or by directly reading the CSRs. For now we'll just convert the CSRs to use a kvm_csr_cfg[] array, reusing the same KVMCPUConfig abstraction we use for extensions, and use the array in (get|put)_csr_regs() instead of manually listing them. A lot of boilerplate will be added but at least we'll automate the get/put procedure for CSRs, i.e. adding a new CSR in the future will be a matter of adding it in kvm_csr_regs[] and everything else will be taken care of. Despite all the code changes no behavioral change is made. [1] https://lore.kernel.org/qemu-riscv/CABJz62OfUDHYkQ0T3rGHStQprf1c7_E0qBLbLKhfv=+jb0SYAw@mail.gmail.com/ Signed-off-by: Daniel Henrique Barboza <dbarboza@ventanamicro.com> Reviewed-by: Andrew Jones <ajones@ventanamicro.com> Acked-by: Alistair Francis <alistair.francis@wdc.com> Message-ID: <20250429124421.223883-6-dbarboza@ventanamicro.com> Signed-off-by: Alistair Francis <alistair.francis@wdc.com> Cc: qemu-stable@nongnu.org --- target/riscv/cpu.h | 1 + target/riscv/kvm/kvm-cpu.c | 121 ++++++++++++++++++++++++++----------- 2 files changed, 86 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 @@ const char *riscv_get_misa_ext_name(uint32_t bit); const char *riscv_get_misa_ext_description(uint32_t bit); #define CPU_CFG_OFFSET(_prop) offsetof(struct RISCVCPUConfig, _prop) +#define ENV_CSR_OFFSET(_csr) offsetof(CPURISCVState, _csr) typedef struct riscv_cpu_profile { struct riscv_cpu_profile *u_parent; diff --git a/target/riscv/kvm/kvm-cpu.c b/target/riscv/kvm/kvm-cpu.c index XXXXXXX..XXXXXXX 100644 --- a/target/riscv/kvm/kvm-cpu.c +++ b/target/riscv/kvm/kvm-cpu.c @@ -XXX,XX +XXX,XX @@ static uint64_t kvm_riscv_vector_reg_id(RISCVCPU *cpu, KVM_RISCV_REG_ID_ULONG(KVM_REG_RISCV_VECTOR, \ KVM_REG_RISCV_VECTOR_CSR_REG(name)) -#define KVM_RISCV_GET_CSR(cs, env, csr, reg) \ - do { \ - int _ret = kvm_get_one_reg(cs, RISCV_CSR_REG(csr), ®); \ - if (_ret) { \ - return _ret; \ - } \ - } while (0) - -#define KVM_RISCV_SET_CSR(cs, env, csr, reg) \ - do { \ - int _ret = kvm_set_one_reg(cs, RISCV_CSR_REG(csr), ®); \ - if (_ret) { \ - return _ret; \ - } \ - } while (0) - #define KVM_RISCV_GET_TIMER(cs, name, reg) \ do { \ int ret = kvm_get_one_reg(cs, RISCV_TIMER_REG(name), ®); \ @@ -XXX,XX +XXX,XX @@ static void kvm_riscv_update_cpu_misa_ext(RISCVCPU *cpu, CPUState *cs) } } +#define KVM_CSR_CFG(_name, _env_prop, reg_id) \ + {.name = _name, .offset = ENV_CSR_OFFSET(_env_prop), \ + .kvm_reg_id = reg_id} + +static KVMCPUConfig kvm_csr_cfgs[] = { + KVM_CSR_CFG("sstatus", mstatus, RISCV_CSR_REG(sstatus)), + KVM_CSR_CFG("sie", mie, RISCV_CSR_REG(sie)), + KVM_CSR_CFG("stvec", stvec, RISCV_CSR_REG(stvec)), + KVM_CSR_CFG("sscratch", sscratch, RISCV_CSR_REG(sscratch)), + KVM_CSR_CFG("sepc", sepc, RISCV_CSR_REG(sepc)), + KVM_CSR_CFG("scause", scause, RISCV_CSR_REG(scause)), + KVM_CSR_CFG("stval", stval, RISCV_CSR_REG(stval)), + KVM_CSR_CFG("sip", mip, RISCV_CSR_REG(sip)), + KVM_CSR_CFG("satp", satp, RISCV_CSR_REG(satp)), +}; + +static void *kvmconfig_get_env_addr(RISCVCPU *cpu, KVMCPUConfig *csr_cfg) +{ + return (void *)&cpu->env + csr_cfg->offset; +} + +static uint32_t kvm_cpu_csr_get_u32(RISCVCPU *cpu, KVMCPUConfig *csr_cfg) +{ + uint32_t *val32 = kvmconfig_get_env_addr(cpu, csr_cfg); + return *val32; +} + +static uint64_t kvm_cpu_csr_get_u64(RISCVCPU *cpu, KVMCPUConfig *csr_cfg) +{ + uint64_t *val64 = kvmconfig_get_env_addr(cpu, csr_cfg); + return *val64; +} + +static void kvm_cpu_csr_set_u32(RISCVCPU *cpu, KVMCPUConfig *csr_cfg, + uint32_t val) +{ + uint32_t *val32 = kvmconfig_get_env_addr(cpu, csr_cfg); + *val32 = val; +} + +static void kvm_cpu_csr_set_u64(RISCVCPU *cpu, KVMCPUConfig *csr_cfg, + uint64_t val) +{ + uint64_t *val64 = kvmconfig_get_env_addr(cpu, csr_cfg); + *val64 = val; +} + #define KVM_EXT_CFG(_name, _prop, _reg_id) \ {.name = _name, .offset = CPU_CFG_OFFSET(_prop), \ .kvm_reg_id = _reg_id} @@ -XXX,XX +XXX,XX @@ static int kvm_riscv_put_regs_core(CPUState *cs) static int kvm_riscv_get_regs_csr(CPUState *cs) { - CPURISCVState *env = &RISCV_CPU(cs)->env; + RISCVCPU *cpu = RISCV_CPU(cs); + uint64_t reg; + int i, ret; + + for (i = 0; i < ARRAY_SIZE(kvm_csr_cfgs); i++) { + KVMCPUConfig *csr_cfg = &kvm_csr_cfgs[i]; - KVM_RISCV_GET_CSR(cs, env, sstatus, env->mstatus); - KVM_RISCV_GET_CSR(cs, env, sie, env->mie); - KVM_RISCV_GET_CSR(cs, env, stvec, env->stvec); - KVM_RISCV_GET_CSR(cs, env, sscratch, env->sscratch); - KVM_RISCV_GET_CSR(cs, env, sepc, env->sepc); - KVM_RISCV_GET_CSR(cs, env, scause, env->scause); - KVM_RISCV_GET_CSR(cs, env, stval, env->stval); - KVM_RISCV_GET_CSR(cs, env, sip, env->mip); - KVM_RISCV_GET_CSR(cs, env, satp, env->satp); + ret = kvm_get_one_reg(cs, csr_cfg->kvm_reg_id, ®); + if (ret) { + return ret; + } + + if (KVM_REG_SIZE(csr_cfg->kvm_reg_id) == sizeof(uint32_t)) { + kvm_cpu_csr_set_u32(cpu, csr_cfg, reg); + } else if (KVM_REG_SIZE(csr_cfg->kvm_reg_id) == sizeof(uint64_t)) { + kvm_cpu_csr_set_u64(cpu, csr_cfg, reg); + } else { + g_assert_not_reached(); + } + } return 0; } static int kvm_riscv_put_regs_csr(CPUState *cs) { - CPURISCVState *env = &RISCV_CPU(cs)->env; + RISCVCPU *cpu = RISCV_CPU(cs); + uint64_t reg; + int i, ret; + + for (i = 0; i < ARRAY_SIZE(kvm_csr_cfgs); i++) { + KVMCPUConfig *csr_cfg = &kvm_csr_cfgs[i]; + + if (KVM_REG_SIZE(csr_cfg->kvm_reg_id) == sizeof(uint32_t)) { + reg = kvm_cpu_csr_get_u32(cpu, csr_cfg); + } else if (KVM_REG_SIZE(csr_cfg->kvm_reg_id) == sizeof(uint64_t)) { + reg = kvm_cpu_csr_get_u64(cpu, csr_cfg); + } else { + g_assert_not_reached(); + } - KVM_RISCV_SET_CSR(cs, env, sstatus, env->mstatus); - KVM_RISCV_SET_CSR(cs, env, sie, env->mie); - KVM_RISCV_SET_CSR(cs, env, stvec, env->stvec); - KVM_RISCV_SET_CSR(cs, env, sscratch, env->sscratch); - KVM_RISCV_SET_CSR(cs, env, sepc, env->sepc); - KVM_RISCV_SET_CSR(cs, env, scause, env->scause); - KVM_RISCV_SET_CSR(cs, env, stval, env->stval); - KVM_RISCV_SET_CSR(cs, env, sip, env->mip); - KVM_RISCV_SET_CSR(cs, env, satp, env->satp); + ret = kvm_set_one_reg(cs, csr_cfg->kvm_reg_id, ®); + if (ret) { + return ret; + } + } return 0; } -- 2.49.0
From: Daniel Henrique Barboza <dbarboza@ventanamicro.com> [1] reports that commit 4db19d5b21 broke a KVM guest running kernel 6.6. This happens because the kernel does not know 'senvcfg', making it unable to boot because QEMU is reading/wriiting it without any checks. After converting the CSRs to do "automated" get/put reg procedures in the previous patch we can now scan for availability. Two functions are created: - kvm_riscv_read_csr_cfg_legacy() will check if the CSR exists by brute forcing KVM_GET_ONE_REG in each one of them, interpreting an EINVAL return as indication that the CSR isn't available. This will be use in absence of KVM_GET_REG_LIST; - kvm_riscv_read_csr_cfg() will use the existing result of get_reg_list to check if the CSRs ids are present. kvm_riscv_init_multiext_cfg() is now kvm_riscv_init_cfg() to reflect that the function is also dealing with CSRs. [1] https://lore.kernel.org/qemu-riscv/CABJz62OfUDHYkQ0T3rGHStQprf1c7_E0qBLbLKhfv=+jb0SYAw@mail.gmail.com/ Fixes: 4db19d5b21 ("target/riscv/kvm: add missing KVM CSRs") Reported-by: Andrea Bolognani <abologna@redhat.com> Signed-off-by: Daniel Henrique Barboza <dbarboza@ventanamicro.com> Reviewed-by: Andrew Jones <ajones@ventanamicro.com> Acked-by: Alistair Francis <alistair.francis@wdc.com> Message-ID: <20250429124421.223883-7-dbarboza@ventanamicro.com> Signed-off-by: Alistair Francis <alistair.francis@wdc.com> Cc: qemu-stable@nongnu.org --- target/riscv/kvm/kvm-cpu.c | 62 ++++++++++++++++++++++++++++++++++++-- 1 file changed, 59 insertions(+), 3 deletions(-) diff --git a/target/riscv/kvm/kvm-cpu.c b/target/riscv/kvm/kvm-cpu.c index XXXXXXX..XXXXXXX 100644 --- a/target/riscv/kvm/kvm-cpu.c +++ b/target/riscv/kvm/kvm-cpu.c @@ -XXX,XX +XXX,XX @@ static int kvm_riscv_get_regs_csr(CPUState *cs) for (i = 0; i < ARRAY_SIZE(kvm_csr_cfgs); i++) { KVMCPUConfig *csr_cfg = &kvm_csr_cfgs[i]; + if (!csr_cfg->supported) { + continue; + } + ret = kvm_get_one_reg(cs, csr_cfg->kvm_reg_id, ®); if (ret) { return ret; @@ -XXX,XX +XXX,XX @@ static int kvm_riscv_put_regs_csr(CPUState *cs) for (i = 0; i < ARRAY_SIZE(kvm_csr_cfgs); i++) { KVMCPUConfig *csr_cfg = &kvm_csr_cfgs[i]; + if (!csr_cfg->supported) { + continue; + } + if (KVM_REG_SIZE(csr_cfg->kvm_reg_id) == sizeof(uint32_t)) { reg = kvm_cpu_csr_get_u32(cpu, csr_cfg); } else if (KVM_REG_SIZE(csr_cfg->kvm_reg_id) == sizeof(uint64_t)) { @@ -XXX,XX +XXX,XX @@ static void kvm_riscv_read_multiext_legacy(RISCVCPU *cpu, } } +static void kvm_riscv_read_csr_cfg_legacy(KVMScratchCPU *kvmcpu) +{ + uint64_t val; + int i, ret; + + for (i = 0; i < ARRAY_SIZE(kvm_csr_cfgs); i++) { + KVMCPUConfig *csr_cfg = &kvm_csr_cfgs[i]; + struct kvm_one_reg reg; + + reg.id = csr_cfg->kvm_reg_id; + reg.addr = (uint64_t)&val; + ret = ioctl(kvmcpu->cpufd, KVM_GET_ONE_REG, ®); + if (ret != 0) { + if (errno == EINVAL) { + csr_cfg->supported = false; + } else { + error_report("Unable to read KVM CSR %s: %s", + csr_cfg->name, strerror(errno)); + exit(EXIT_FAILURE); + } + } else { + csr_cfg->supported = true; + } + } +} + static int uint64_cmp(const void *a, const void *b) { uint64_t val1 = *(const uint64_t *)a; @@ -XXX,XX +XXX,XX @@ static void kvm_riscv_read_vlenb(RISCVCPU *cpu, KVMScratchCPU *kvmcpu, } } -static void kvm_riscv_init_multiext_cfg(RISCVCPU *cpu, KVMScratchCPU *kvmcpu) +static void kvm_riscv_read_csr_cfg(struct kvm_reg_list *reglist) +{ + struct kvm_reg_list *reg_search; + uint64_t reg_id; + + for (int i = 0; i < ARRAY_SIZE(kvm_csr_cfgs); i++) { + KVMCPUConfig *csr_cfg = &kvm_csr_cfgs[i]; + + reg_id = csr_cfg->kvm_reg_id; + reg_search = bsearch(®_id, reglist->reg, reglist->n, + sizeof(uint64_t), uint64_cmp); + if (!reg_search) { + continue; + } + + csr_cfg->supported = true; + } +} + +static void kvm_riscv_init_cfg(RISCVCPU *cpu, KVMScratchCPU *kvmcpu) { g_autofree struct kvm_reg_list *reglist = NULL; KVMCPUConfig *multi_ext_cfg; @@ -XXX,XX +XXX,XX @@ static void kvm_riscv_init_multiext_cfg(RISCVCPU *cpu, KVMScratchCPU *kvmcpu) * (EINVAL). Use read_legacy() in this case. */ if (errno == EINVAL) { - return kvm_riscv_read_multiext_legacy(cpu, kvmcpu); + kvm_riscv_read_multiext_legacy(cpu, kvmcpu); + kvm_riscv_read_csr_cfg_legacy(kvmcpu); + return; } else if (errno != E2BIG) { /* * E2BIG is an expected error message for the API since we @@ -XXX,XX +XXX,XX @@ static void kvm_riscv_init_multiext_cfg(RISCVCPU *cpu, KVMScratchCPU *kvmcpu) } kvm_riscv_check_sbi_dbcn_support(cpu, reglist); + kvm_riscv_read_csr_cfg(reglist); } static void riscv_init_kvm_registers(Object *cpu_obj) @@ -XXX,XX +XXX,XX @@ static void riscv_init_kvm_registers(Object *cpu_obj) kvm_riscv_init_machine_ids(cpu, &kvmcpu); kvm_riscv_init_misa_ext_mask(cpu, &kvmcpu); - kvm_riscv_init_multiext_cfg(cpu, &kvmcpu); + kvm_riscv_init_cfg(cpu, &kvmcpu); kvm_riscv_destroy_scratch_vcpu(&kvmcpu); } -- 2.49.0
From: Daniel Henrique Barboza <dbarboza@ventanamicro.com> We're missing the senvcfg CSRs which is already present in the KVM UAPI. Reported-by: Andrew Jones <ajones@ventanamicro.com> Signed-off-by: Daniel Henrique Barboza <dbarboza@ventanamicro.com> Reviewed-by: Andrew Jones <ajones@ventanamicro.com> Acked-by: Alistair Francis <alistair.francis@wdc.com> Message-ID: <20250429124421.223883-8-dbarboza@ventanamicro.com> Signed-off-by: Alistair Francis <alistair.francis@wdc.com> --- target/riscv/kvm/kvm-cpu.c | 2 ++ 1 file changed, 2 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_csr_cfgs[] = { KVM_CSR_CFG("stval", stval, RISCV_CSR_REG(stval)), KVM_CSR_CFG("sip", mip, RISCV_CSR_REG(sip)), KVM_CSR_CFG("satp", satp, RISCV_CSR_REG(satp)), + KVM_CSR_CFG("senvcfg", senvcfg, RISCV_CSR_REG(senvcfg)), }; static void *kvmconfig_get_env_addr(RISCVCPU *cpu, KVMCPUConfig *csr_cfg) @@ -XXX,XX +XXX,XX @@ static void kvm_riscv_reset_regs_csr(CPURISCVState *env) env->stval = 0; env->mip = 0; env->satp = 0; + env->senvcfg = 0; } static int kvm_riscv_get_regs_fp(CPUState *cs) -- 2.49.0
From: Daniel Henrique Barboza <dbarboza@ventanamicro.com> We're going to add support for scounteren in the next patch. KVM defines as a target_ulong CSR, while QEMU defines env->scounteren as a 32 bit field. This will cause the current code to read/write a 64 bit CSR in a 32 bit field when running in a 64 bit CPU. To prevent that, change the current logic to honor the size of the QEMU storage instead of the KVM CSR reg. Suggested-by: Andrew Jones <ajones@ventanamicro.com> Signed-off-by: Daniel Henrique Barboza <dbarboza@ventanamicro.com> Reviewed-by: Alistair Francis <alistair.francis@wdc.com> Reviewed-by: Andrew Jones <ajones@ventanamicro.com> Message-ID: <20250429124421.223883-9-dbarboza@ventanamicro.com> Signed-off-by: Alistair Francis <alistair.francis@wdc.com> --- target/riscv/kvm/kvm-cpu.c | 12 +++++++----- 1 file changed, 7 insertions(+), 5 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 @@ typedef struct KVMCPUConfig { const char *description; target_ulong offset; uint64_t kvm_reg_id; + uint32_t prop_size; bool user_set; bool supported; } KVMCPUConfig; @@ -XXX,XX +XXX,XX @@ static void kvm_riscv_update_cpu_misa_ext(RISCVCPU *cpu, CPUState *cs) #define KVM_CSR_CFG(_name, _env_prop, reg_id) \ {.name = _name, .offset = ENV_CSR_OFFSET(_env_prop), \ + .prop_size = sizeof(((CPURISCVState *)0)->_env_prop), \ .kvm_reg_id = reg_id} static KVMCPUConfig kvm_csr_cfgs[] = { @@ -XXX,XX +XXX,XX @@ static int kvm_riscv_get_regs_csr(CPUState *cs) return ret; } - if (KVM_REG_SIZE(csr_cfg->kvm_reg_id) == sizeof(uint32_t)) { - kvm_cpu_csr_set_u32(cpu, csr_cfg, reg); - } else if (KVM_REG_SIZE(csr_cfg->kvm_reg_id) == sizeof(uint64_t)) { + if (csr_cfg->prop_size == sizeof(uint32_t)) { + kvm_cpu_csr_set_u32(cpu, csr_cfg, (uint32_t)reg); + } else if (csr_cfg->prop_size == sizeof(uint64_t)) { kvm_cpu_csr_set_u64(cpu, csr_cfg, reg); } else { g_assert_not_reached(); @@ -XXX,XX +XXX,XX @@ static int kvm_riscv_put_regs_csr(CPUState *cs) continue; } - if (KVM_REG_SIZE(csr_cfg->kvm_reg_id) == sizeof(uint32_t)) { + if (csr_cfg->prop_size == sizeof(uint32_t)) { reg = kvm_cpu_csr_get_u32(cpu, csr_cfg); - } else if (KVM_REG_SIZE(csr_cfg->kvm_reg_id) == sizeof(uint64_t)) { + } else if (csr_cfg->prop_size == sizeof(uint64_t)) { reg = kvm_cpu_csr_get_u64(cpu, csr_cfg); } else { g_assert_not_reached(); -- 2.49.0
From: Daniel Henrique Barboza <dbarboza@ventanamicro.com> Add support for the scounteren KVM CSR. Note that env->scounteren is a 32 bit and all KVM CSRs are target_ulong, so scounteren will be capped to 32 bits read/writes. Reported-by: Andrew Jones <ajones@ventanamicro.com> Signed-off-by: Daniel Henrique Barboza <dbarboza@ventanamicro.com> Reviewed-by: Andrew Jones <ajones@ventanamicro.com> Reviewed-by: Alistair Francis <alistair.francis@wdc.com> Message-ID: <20250429124421.223883-10-dbarboza@ventanamicro.com> Signed-off-by: Alistair Francis <alistair.francis@wdc.com> --- target/riscv/kvm/kvm-cpu.c | 2 ++ 1 file changed, 2 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_csr_cfgs[] = { KVM_CSR_CFG("stval", stval, RISCV_CSR_REG(stval)), KVM_CSR_CFG("sip", mip, RISCV_CSR_REG(sip)), KVM_CSR_CFG("satp", satp, RISCV_CSR_REG(satp)), + KVM_CSR_CFG("scounteren", scounteren, RISCV_CSR_REG(scounteren)), KVM_CSR_CFG("senvcfg", senvcfg, RISCV_CSR_REG(senvcfg)), }; @@ -XXX,XX +XXX,XX @@ static void kvm_riscv_reset_regs_csr(CPURISCVState *env) env->stval = 0; env->mip = 0; env->satp = 0; + env->scounteren = 0; env->senvcfg = 0; } -- 2.49.0
From: Daniel Henrique Barboza <dbarboza@ventanamicro.com> Throughout the code we're accessing the board memmap, most of the time, by accessing it statically via 'virt_memmap'. This static map is also assigned in the machine state in s->memmap. We're also passing it as a variable to some fdt functions, which is unorthodox since we can spare a function argument by accessing it statically or via the machine state. All the current forms are valid but not all of the are scalable. In the future we will version this board, and then all this code will need rework because it should point to the updated memmap. In this case, we'll want to assign the adequate versioned memmap once during init, in s->memmap like it is being done today, and the rest of the code will access the updated map via s->memmap. We're also enforcing the pattern of using s->memmap instead of assigning it to a temp variable 'memmap'. Code is copy/pasted around all the time and being consistent is important. We'll start these rather mechanical changes with virt_machine_init(). Signed-off-by: Daniel Henrique Barboza <dbarboza@ventanamicro.com> Reviewed-by: Alistair Francis <alistair.francis@wdc.com> Reviewed-by: Joel Stanley <joel@jms.id.au> Message-ID: <20250429125811.224803-2-dbarboza@ventanamicro.com> Signed-off-by: Alistair Francis <alistair.francis@wdc.com> --- hw/riscv/virt.c | 54 ++++++++++++++++++++++++------------------------- 1 file changed, 27 insertions(+), 27 deletions(-) diff --git a/hw/riscv/virt.c b/hw/riscv/virt.c index XXXXXXX..XXXXXXX 100644 --- a/hw/riscv/virt.c +++ b/hw/riscv/virt.c @@ -XXX,XX +XXX,XX @@ static void virt_machine_done(Notifier *notifier, void *data) static void virt_machine_init(MachineState *machine) { - const MemMapEntry *memmap = virt_memmap; RISCVVirtState *s = RISCV_VIRT_MACHINE(machine); MemoryRegion *system_memory = get_system_memory(); MemoryRegion *mask_rom = g_new(MemoryRegion, 1); @@ -XXX,XX +XXX,XX @@ static void virt_machine_init(MachineState *machine) int i, base_hartid, hart_count; int socket_count = riscv_socket_count(machine); + s->memmap = virt_memmap; + /* Check socket count limit */ if (VIRT_SOCKETS_MAX < socket_count) { error_report("number of sockets/nodes should be less than %d", @@ -XXX,XX +XXX,XX @@ static void virt_machine_init(MachineState *machine) if (virt_aclint_allowed() && s->have_aclint) { if (s->aia_type == VIRT_AIA_TYPE_APLIC_IMSIC) { /* Per-socket ACLINT MTIMER */ - riscv_aclint_mtimer_create(memmap[VIRT_CLINT].base + + riscv_aclint_mtimer_create(s->memmap[VIRT_CLINT].base + i * RISCV_ACLINT_DEFAULT_MTIMER_SIZE, RISCV_ACLINT_DEFAULT_MTIMER_SIZE, base_hartid, hart_count, @@ -XXX,XX +XXX,XX @@ static void virt_machine_init(MachineState *machine) RISCV_ACLINT_DEFAULT_TIMEBASE_FREQ, true); } else { /* Per-socket ACLINT MSWI, MTIMER, and SSWI */ - riscv_aclint_swi_create(memmap[VIRT_CLINT].base + - i * memmap[VIRT_CLINT].size, + riscv_aclint_swi_create(s->memmap[VIRT_CLINT].base + + i * s->memmap[VIRT_CLINT].size, base_hartid, hart_count, false); - riscv_aclint_mtimer_create(memmap[VIRT_CLINT].base + - i * memmap[VIRT_CLINT].size + + riscv_aclint_mtimer_create(s->memmap[VIRT_CLINT].base + + i * s->memmap[VIRT_CLINT].size + RISCV_ACLINT_SWI_SIZE, RISCV_ACLINT_DEFAULT_MTIMER_SIZE, base_hartid, hart_count, RISCV_ACLINT_DEFAULT_MTIMECMP, RISCV_ACLINT_DEFAULT_MTIME, RISCV_ACLINT_DEFAULT_TIMEBASE_FREQ, true); - riscv_aclint_swi_create(memmap[VIRT_ACLINT_SSWI].base + - i * memmap[VIRT_ACLINT_SSWI].size, + riscv_aclint_swi_create(s->memmap[VIRT_ACLINT_SSWI].base + + i * s->memmap[VIRT_ACLINT_SSWI].size, base_hartid, hart_count, true); } } else if (tcg_enabled()) { /* Per-socket SiFive CLINT */ riscv_aclint_swi_create( - memmap[VIRT_CLINT].base + i * memmap[VIRT_CLINT].size, + s->memmap[VIRT_CLINT].base + i * s->memmap[VIRT_CLINT].size, base_hartid, hart_count, false); - riscv_aclint_mtimer_create(memmap[VIRT_CLINT].base + - i * memmap[VIRT_CLINT].size + RISCV_ACLINT_SWI_SIZE, + riscv_aclint_mtimer_create(s->memmap[VIRT_CLINT].base + + i * s->memmap[VIRT_CLINT].size + RISCV_ACLINT_SWI_SIZE, RISCV_ACLINT_DEFAULT_MTIMER_SIZE, base_hartid, hart_count, RISCV_ACLINT_DEFAULT_MTIMECMP, RISCV_ACLINT_DEFAULT_MTIME, RISCV_ACLINT_DEFAULT_TIMEBASE_FREQ, true); @@ -XXX,XX +XXX,XX @@ static void virt_machine_init(MachineState *machine) /* Per-socket interrupt controller */ if (s->aia_type == VIRT_AIA_TYPE_NONE) { - s->irqchip[i] = virt_create_plic(memmap, i, + s->irqchip[i] = virt_create_plic(s->memmap, i, base_hartid, hart_count); } else { s->irqchip[i] = virt_create_aia(s->aia_type, s->aia_guests, - memmap, i, base_hartid, + s->memmap, i, base_hartid, hart_count); } @@ -XXX,XX +XXX,XX @@ static void virt_machine_init(MachineState *machine) if (kvm_enabled() && virt_use_kvm_aia_aplic_imsic(s->aia_type)) { kvm_riscv_aia_create(machine, IMSIC_MMIO_GROUP_MIN_SHIFT, VIRT_IRQCHIP_NUM_SOURCES, VIRT_IRQCHIP_NUM_MSIS, - memmap[VIRT_APLIC_S].base, - memmap[VIRT_IMSIC_S].base, + s->memmap[VIRT_APLIC_S].base, + s->memmap[VIRT_IMSIC_S].base, s->aia_guests); } @@ -XXX,XX +XXX,XX @@ static void virt_machine_init(MachineState *machine) virt_high_pcie_memmap.size = VIRT32_HIGH_PCIE_MMIO_SIZE; } else { virt_high_pcie_memmap.size = VIRT64_HIGH_PCIE_MMIO_SIZE; - virt_high_pcie_memmap.base = memmap[VIRT_DRAM].base + machine->ram_size; + virt_high_pcie_memmap.base = s->memmap[VIRT_DRAM].base + + machine->ram_size; virt_high_pcie_memmap.base = ROUND_UP(virt_high_pcie_memmap.base, virt_high_pcie_memmap.size); } - s->memmap = virt_memmap; - /* register system main memory (actual RAM) */ - memory_region_add_subregion(system_memory, memmap[VIRT_DRAM].base, - machine->ram); + memory_region_add_subregion(system_memory, s->memmap[VIRT_DRAM].base, + machine->ram); /* boot rom */ memory_region_init_rom(mask_rom, NULL, "riscv_virt_board.mrom", - memmap[VIRT_MROM].size, &error_fatal); - memory_region_add_subregion(system_memory, memmap[VIRT_MROM].base, + s->memmap[VIRT_MROM].size, &error_fatal); + memory_region_add_subregion(system_memory, s->memmap[VIRT_MROM].base, mask_rom); /* @@ -XXX,XX +XXX,XX @@ static void virt_machine_init(MachineState *machine) rom_set_fw(s->fw_cfg); /* SiFive Test MMIO device */ - sifive_test_create(memmap[VIRT_TEST].base); + sifive_test_create(s->memmap[VIRT_TEST].base); /* VirtIO MMIO devices */ for (i = 0; i < VIRTIO_COUNT; i++) { sysbus_create_simple("virtio-mmio", - memmap[VIRT_VIRTIO].base + i * memmap[VIRT_VIRTIO].size, + s->memmap[VIRT_VIRTIO].base + i * s->memmap[VIRT_VIRTIO].size, qdev_get_gpio_in(virtio_irqchip, VIRTIO_IRQ + i)); } @@ -XXX,XX +XXX,XX @@ static void virt_machine_init(MachineState *machine) create_platform_bus(s, mmio_irqchip); - serial_mm_init(system_memory, memmap[VIRT_UART0].base, + serial_mm_init(system_memory, s->memmap[VIRT_UART0].base, 0, qdev_get_gpio_in(mmio_irqchip, UART0_IRQ), 399193, serial_hd(0), DEVICE_LITTLE_ENDIAN); - sysbus_create_simple("goldfish_rtc", memmap[VIRT_RTC].base, + sysbus_create_simple("goldfish_rtc", s->memmap[VIRT_RTC].base, qdev_get_gpio_in(mmio_irqchip, RTC_IRQ)); for (i = 0; i < ARRAY_SIZE(s->flash); i++) { @@ -XXX,XX +XXX,XX @@ static void virt_machine_init(MachineState *machine) exit(1); } } else { - create_fdt(s, memmap); + create_fdt(s, s->memmap); } if (virt_is_iommu_sys_enabled(s)) { -- 2.49.0
From: Daniel Henrique Barboza <dbarboza@ventanamicro.com> We should use s->memmap instead of virt_memmap to be able to use an updated memmap when we start versioning the board. Signed-off-by: Daniel Henrique Barboza <dbarboza@ventanamicro.com> Reviewed-by: Alistair Francis <alistair.francis@wdc.com> Message-ID: <20250429125811.224803-3-dbarboza@ventanamicro.com> Signed-off-by: Alistair Francis <alistair.francis@wdc.com> --- hw/riscv/virt.c | 29 ++++++++++++++--------------- 1 file changed, 14 insertions(+), 15 deletions(-) diff --git a/hw/riscv/virt.c b/hw/riscv/virt.c index XXXXXXX..XXXXXXX 100644 --- a/hw/riscv/virt.c +++ b/hw/riscv/virt.c @@ -XXX,XX +XXX,XX @@ static void virt_flash_map1(PFlashCFI01 *flash, static void virt_flash_map(RISCVVirtState *s, MemoryRegion *sysmem) { - hwaddr flashsize = virt_memmap[VIRT_FLASH].size / 2; - hwaddr flashbase = virt_memmap[VIRT_FLASH].base; + hwaddr flashsize = s->memmap[VIRT_FLASH].size / 2; + hwaddr flashbase = s->memmap[VIRT_FLASH].base; virt_flash_map1(s->flash[0], flashbase, flashsize, sysmem); @@ -XXX,XX +XXX,XX @@ static void create_fdt_rtc(RISCVVirtState *s, const MemMapEntry *memmap, static void create_fdt_flash(RISCVVirtState *s, const MemMapEntry *memmap) { MachineState *ms = MACHINE(s); - hwaddr flashsize = virt_memmap[VIRT_FLASH].size / 2; - hwaddr flashbase = virt_memmap[VIRT_FLASH].base; + hwaddr flashsize = s->memmap[VIRT_FLASH].size / 2; + hwaddr flashbase = s->memmap[VIRT_FLASH].base; g_autofree char *name = g_strdup_printf("/flash@%" PRIx64, flashbase); qemu_fdt_add_subnode(ms->fdt, name); @@ -XXX,XX +XXX,XX @@ static void create_fdt_virtio_iommu(RISCVVirtState *s, uint16_t bdf) g_autofree char *pci_node = NULL; pci_node = g_strdup_printf("/soc/pci@%lx", - (long) virt_memmap[VIRT_PCIE_ECAM].base); + (long) s->memmap[VIRT_PCIE_ECAM].base); iommu_node = g_strdup_printf("%s/virtio_iommu@%x,%x", pci_node, PCI_SLOT(bdf), PCI_FUNC(bdf)); iommu_phandle = qemu_fdt_alloc_phandle(fdt); @@ -XXX,XX +XXX,XX @@ static void create_fdt_iommu(RISCVVirtState *s, uint16_t bdf) g_autofree char *pci_node = NULL; pci_node = g_strdup_printf("/soc/pci@%lx", - (long) virt_memmap[VIRT_PCIE_ECAM].base); + (long) s->memmap[VIRT_PCIE_ECAM].base); iommu_node = g_strdup_printf("%s/iommu@%x", pci_node, bdf); iommu_phandle = qemu_fdt_alloc_phandle(fdt); qemu_fdt_add_subnode(fdt, iommu_node); @@ -XXX,XX +XXX,XX @@ static void finalize_fdt(RISCVVirtState *s) uint32_t irq_pcie_phandle = 1, irq_virtio_phandle = 1; uint32_t iommu_sys_phandle = 1; - create_fdt_sockets(s, virt_memmap, &phandle, &irq_mmio_phandle, + create_fdt_sockets(s, s->memmap, &phandle, &irq_mmio_phandle, &irq_pcie_phandle, &irq_virtio_phandle, &msi_pcie_phandle); - create_fdt_virtio(s, virt_memmap, irq_virtio_phandle); + create_fdt_virtio(s, s->memmap, irq_virtio_phandle); if (virt_is_iommu_sys_enabled(s)) { create_fdt_iommu_sys(s, irq_mmio_phandle, msi_pcie_phandle, &iommu_sys_phandle); } - create_fdt_pcie(s, virt_memmap, irq_pcie_phandle, msi_pcie_phandle, + create_fdt_pcie(s, s->memmap, irq_pcie_phandle, msi_pcie_phandle, iommu_sys_phandle); - create_fdt_reset(s, virt_memmap, &phandle); + create_fdt_reset(s, s->memmap, &phandle); - create_fdt_uart(s, virt_memmap, irq_mmio_phandle); + create_fdt_uart(s, s->memmap, irq_mmio_phandle); - create_fdt_rtc(s, virt_memmap, irq_mmio_phandle); + create_fdt_rtc(s, s->memmap, irq_mmio_phandle); } static void create_fdt(RISCVVirtState *s, const MemMapEntry *memmap) @@ -XXX,XX +XXX,XX @@ static void create_platform_bus(RISCVVirtState *s, DeviceState *irqchip) { DeviceState *dev; SysBusDevice *sysbus; - const MemMapEntry *memmap = virt_memmap; int i; MemoryRegion *sysmem = get_system_memory(); dev = qdev_new(TYPE_PLATFORM_BUS_DEVICE); dev->id = g_strdup(TYPE_PLATFORM_BUS_DEVICE); qdev_prop_set_uint32(dev, "num_irqs", VIRT_PLATFORM_BUS_NUM_IRQS); - qdev_prop_set_uint32(dev, "mmio_size", memmap[VIRT_PLATFORM_BUS].size); + qdev_prop_set_uint32(dev, "mmio_size", s->memmap[VIRT_PLATFORM_BUS].size); sysbus_realize_and_unref(SYS_BUS_DEVICE(dev), &error_fatal); s->platform_bus_dev = dev; @@ -XXX,XX +XXX,XX @@ static void create_platform_bus(RISCVVirtState *s, DeviceState *irqchip) } memory_region_add_subregion(sysmem, - memmap[VIRT_PLATFORM_BUS].base, + s->memmap[VIRT_PLATFORM_BUS].base, sysbus_mmio_get_region(sysbus, 0)); } -- 2.49.0
From: Daniel Henrique Barboza <dbarboza@ventanamicro.com> Signed-off-by: Daniel Henrique Barboza <dbarboza@ventanamicro.com> Reviewed-by: Alistair Francis <alistair.francis@wdc.com> Message-ID: <20250429125811.224803-4-dbarboza@ventanamicro.com> Signed-off-by: Alistair Francis <alistair.francis@wdc.com> --- hw/riscv/virt.c | 15 +++++++-------- 1 file changed, 7 insertions(+), 8 deletions(-) diff --git a/hw/riscv/virt.c b/hw/riscv/virt.c index XXXXXXX..XXXXXXX 100644 --- a/hw/riscv/virt.c +++ b/hw/riscv/virt.c @@ -XXX,XX +XXX,XX @@ static void virt_machine_done(Notifier *notifier, void *data) { RISCVVirtState *s = container_of(notifier, RISCVVirtState, machine_done); - const MemMapEntry *memmap = virt_memmap; MachineState *machine = MACHINE(s); - hwaddr start_addr = memmap[VIRT_DRAM].base; + hwaddr start_addr = s->memmap[VIRT_DRAM].base; target_ulong firmware_end_addr, kernel_start_addr; const char *firmware_name = riscv_default_firmware_name(&s->soc[0]); uint64_t fdt_load_addr; @@ -XXX,XX +XXX,XX @@ static void virt_machine_done(Notifier *notifier, void *data) * let's overwrite the address we jump to after reset to * the base of the flash. */ - start_addr = virt_memmap[VIRT_FLASH].base; + start_addr = s->memmap[VIRT_FLASH].base; } else { /* * Pflash was supplied but either KVM guest or bios is not none. * In this case, base of the flash would contain S-mode payload. */ riscv_setup_firmware_boot(machine); - kernel_entry = virt_memmap[VIRT_FLASH].base; + kernel_entry = s->memmap[VIRT_FLASH].base; } } @@ -XXX,XX +XXX,XX @@ static void virt_machine_done(Notifier *notifier, void *data) kernel_entry = boot_info.image_low_addr; } - fdt_load_addr = riscv_compute_fdt_addr(memmap[VIRT_DRAM].base, - memmap[VIRT_DRAM].size, + fdt_load_addr = riscv_compute_fdt_addr(s->memmap[VIRT_DRAM].base, + s->memmap[VIRT_DRAM].size, machine, &boot_info); riscv_load_fdt(fdt_load_addr, machine->fdt); /* load the reset vector */ riscv_setup_rom_reset_vec(machine, &s->soc[0], start_addr, - virt_memmap[VIRT_MROM].base, - virt_memmap[VIRT_MROM].size, kernel_entry, + s->memmap[VIRT_MROM].base, + s->memmap[VIRT_MROM].size, kernel_entry, fdt_load_addr); /* -- 2.49.0
From: Daniel Henrique Barboza <dbarboza@ventanamicro.com> The function can receive the value via s->memmap[VIRT_FW_CFG].base from the caller, avoiding the use of virt_memmap. Signed-off-by: Daniel Henrique Barboza <dbarboza@ventanamicro.com> Reviewed-by: Philippe Mathieu-Daudé <philmd@linaro.org> Reviewed-by: Alistair Francis <alistair.francis@wdc.com> Message-ID: <20250429125811.224803-5-dbarboza@ventanamicro.com> Signed-off-by: Alistair Francis <alistair.francis@wdc.com> --- hw/riscv/virt.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/hw/riscv/virt.c b/hw/riscv/virt.c index XXXXXXX..XXXXXXX 100644 --- a/hw/riscv/virt.c +++ b/hw/riscv/virt.c @@ -XXX,XX +XXX,XX @@ static inline DeviceState *gpex_pcie_init(MemoryRegion *sys_mem, return dev; } -static FWCfgState *create_fw_cfg(const MachineState *ms) +static FWCfgState *create_fw_cfg(const MachineState *ms, hwaddr base) { - hwaddr base = virt_memmap[VIRT_FW_CFG].base; FWCfgState *fw_cfg; fw_cfg = fw_cfg_init_mem_wide(base + 8, base, 8, base + 16, @@ -XXX,XX +XXX,XX @@ static void virt_machine_init(MachineState *machine) * Init fw_cfg. Must be done before riscv_load_fdt, otherwise the * device tree cannot be altered and we get FDT_ERR_NOSPACE. */ - s->fw_cfg = create_fw_cfg(machine); + s->fw_cfg = create_fw_cfg(machine, s->memmap[VIRT_FW_CFG].base); rom_set_fw(s->fw_cfg); /* SiFive Test MMIO device */ -- 2.49.0
From: Daniel Henrique Barboza <dbarboza@ventanamicro.com> create_fdt(), create_fdt_flash() and create_fdt_fw_cfg() can access the memmap via their RISCVVirtState pointers. Signed-off-by: Daniel Henrique Barboza <dbarboza@ventanamicro.com> Reviewed-by: Alistair Francis <alistair.francis@wdc.com> Message-ID: <20250429125811.224803-6-dbarboza@ventanamicro.com> Signed-off-by: Alistair Francis <alistair.francis@wdc.com> --- hw/riscv/virt.c | 19 ++++++++++--------- 1 file changed, 10 insertions(+), 9 deletions(-) diff --git a/hw/riscv/virt.c b/hw/riscv/virt.c index XXXXXXX..XXXXXXX 100644 --- a/hw/riscv/virt.c +++ b/hw/riscv/virt.c @@ -XXX,XX +XXX,XX @@ static void create_fdt_rtc(RISCVVirtState *s, const MemMapEntry *memmap, } } -static void create_fdt_flash(RISCVVirtState *s, const MemMapEntry *memmap) +static void create_fdt_flash(RISCVVirtState *s) { MachineState *ms = MACHINE(s); hwaddr flashsize = s->memmap[VIRT_FLASH].size / 2; @@ -XXX,XX +XXX,XX @@ static void create_fdt_flash(RISCVVirtState *s, const MemMapEntry *memmap) qemu_fdt_setprop_cell(ms->fdt, name, "bank-width", 4); } -static void create_fdt_fw_cfg(RISCVVirtState *s, const MemMapEntry *memmap) +static void create_fdt_fw_cfg(RISCVVirtState *s) { MachineState *ms = MACHINE(s); - hwaddr base = memmap[VIRT_FW_CFG].base; - hwaddr size = memmap[VIRT_FW_CFG].size; + hwaddr base = s->memmap[VIRT_FW_CFG].base; + hwaddr size = s->memmap[VIRT_FW_CFG].size; g_autofree char *nodename = g_strdup_printf("/fw-cfg@%" PRIx64, base); qemu_fdt_add_subnode(ms->fdt, nodename); @@ -XXX,XX +XXX,XX @@ static void finalize_fdt(RISCVVirtState *s) create_fdt_rtc(s, s->memmap, irq_mmio_phandle); } -static void create_fdt(RISCVVirtState *s, const MemMapEntry *memmap) +static void create_fdt(RISCVVirtState *s) { MachineState *ms = MACHINE(s); uint8_t rng_seed[32]; @@ -XXX,XX +XXX,XX @@ static void create_fdt(RISCVVirtState *s, const MemMapEntry *memmap) * The "/soc/pci@..." node is needed for PCIE hotplugs * that might happen before finalize_fdt(). */ - name = g_strdup_printf("/soc/pci@%lx", (long) memmap[VIRT_PCIE_ECAM].base); + name = g_strdup_printf("/soc/pci@%lx", + (long) s->memmap[VIRT_PCIE_ECAM].base); qemu_fdt_add_subnode(ms->fdt, name); qemu_fdt_add_subnode(ms->fdt, "/chosen"); @@ -XXX,XX +XXX,XX @@ static void create_fdt(RISCVVirtState *s, const MemMapEntry *memmap) qemu_fdt_add_subnode(ms->fdt, "/aliases"); - create_fdt_flash(s, memmap); - create_fdt_fw_cfg(s, memmap); + create_fdt_flash(s); + create_fdt_fw_cfg(s); create_fdt_pmu(s); } @@ -XXX,XX +XXX,XX @@ static void virt_machine_init(MachineState *machine) exit(1); } } else { - create_fdt(s, s->memmap); + create_fdt(s); } if (virt_is_iommu_sys_enabled(s)) { -- 2.49.0
From: Daniel Henrique Barboza <dbarboza@ventanamicro.com> create_fdt_sockets() and all its fdt helpers (create_fdt_socket_aplic(), create_fdt_imsic(), create_fdt_socket_plic(), create_fdt_socket_aclint() and create_fdt_socket_memory()) can use s->memmap from their RISCVVirtState pointer instead of having an extra memmap argument. Signed-off-by: Daniel Henrique Barboza <dbarboza@ventanamicro.com> Reviewed-by: Alistair Francis <alistair.francis@wdc.com> Message-ID: <20250429125811.224803-7-dbarboza@ventanamicro.com> Signed-off-by: Alistair Francis <alistair.francis@wdc.com> --- hw/riscv/virt.c | 89 ++++++++++++++++++++++++++----------------------- 1 file changed, 47 insertions(+), 42 deletions(-) diff --git a/hw/riscv/virt.c b/hw/riscv/virt.c index XXXXXXX..XXXXXXX 100644 --- a/hw/riscv/virt.c +++ b/hw/riscv/virt.c @@ -XXX,XX +XXX,XX @@ static void create_fdt_socket_cpus(RISCVVirtState *s, int socket, } } -static void create_fdt_socket_memory(RISCVVirtState *s, - const MemMapEntry *memmap, int socket) +static void create_fdt_socket_memory(RISCVVirtState *s, int socket) { g_autofree char *mem_name = NULL; uint64_t addr, size; MachineState *ms = MACHINE(s); - addr = memmap[VIRT_DRAM].base + riscv_socket_mem_offset(ms, socket); + addr = s->memmap[VIRT_DRAM].base + riscv_socket_mem_offset(ms, socket); size = riscv_socket_mem_size(ms, socket); mem_name = g_strdup_printf("/memory@%lx", (long)addr); qemu_fdt_add_subnode(ms->fdt, mem_name); @@ -XXX,XX +XXX,XX @@ static void create_fdt_socket_memory(RISCVVirtState *s, } static void create_fdt_socket_clint(RISCVVirtState *s, - const MemMapEntry *memmap, int socket, + int socket, uint32_t *intc_phandles) { int cpu; @@ -XXX,XX +XXX,XX @@ static void create_fdt_socket_clint(RISCVVirtState *s, clint_cells[cpu * 4 + 3] = cpu_to_be32(IRQ_M_TIMER); } - clint_addr = memmap[VIRT_CLINT].base + (memmap[VIRT_CLINT].size * socket); + clint_addr = s->memmap[VIRT_CLINT].base + + (s->memmap[VIRT_CLINT].size * socket); clint_name = g_strdup_printf("/soc/clint@%lx", clint_addr); qemu_fdt_add_subnode(ms->fdt, clint_name); qemu_fdt_setprop_string_array(ms->fdt, clint_name, "compatible", (char **)&clint_compat, ARRAY_SIZE(clint_compat)); qemu_fdt_setprop_cells(ms->fdt, clint_name, "reg", - 0x0, clint_addr, 0x0, memmap[VIRT_CLINT].size); + 0x0, clint_addr, 0x0, s->memmap[VIRT_CLINT].size); qemu_fdt_setprop(ms->fdt, clint_name, "interrupts-extended", clint_cells, s->soc[socket].num_harts * sizeof(uint32_t) * 4); riscv_socket_fdt_write_id(ms, clint_name, socket); } static void create_fdt_socket_aclint(RISCVVirtState *s, - const MemMapEntry *memmap, int socket, + int socket, uint32_t *intc_phandles) { int cpu; @@ -XXX,XX +XXX,XX @@ static void create_fdt_socket_aclint(RISCVVirtState *s, aclint_cells_size = s->soc[socket].num_harts * sizeof(uint32_t) * 2; if (s->aia_type != VIRT_AIA_TYPE_APLIC_IMSIC) { - addr = memmap[VIRT_CLINT].base + (memmap[VIRT_CLINT].size * socket); + addr = s->memmap[VIRT_CLINT].base + + (s->memmap[VIRT_CLINT].size * socket); name = g_strdup_printf("/soc/mswi@%lx", addr); + qemu_fdt_add_subnode(ms->fdt, name); qemu_fdt_setprop_string(ms->fdt, name, "compatible", "riscv,aclint-mswi"); @@ -XXX,XX +XXX,XX @@ static void create_fdt_socket_aclint(RISCVVirtState *s, } if (s->aia_type == VIRT_AIA_TYPE_APLIC_IMSIC) { - addr = memmap[VIRT_CLINT].base + + addr = s->memmap[VIRT_CLINT].base + (RISCV_ACLINT_DEFAULT_MTIMER_SIZE * socket); size = RISCV_ACLINT_DEFAULT_MTIMER_SIZE; } else { - addr = memmap[VIRT_CLINT].base + RISCV_ACLINT_SWI_SIZE + - (memmap[VIRT_CLINT].size * socket); - size = memmap[VIRT_CLINT].size - RISCV_ACLINT_SWI_SIZE; + addr = s->memmap[VIRT_CLINT].base + RISCV_ACLINT_SWI_SIZE + + (s->memmap[VIRT_CLINT].size * socket); + size = s->memmap[VIRT_CLINT].size - RISCV_ACLINT_SWI_SIZE; } name = g_strdup_printf("/soc/mtimer@%lx", addr); qemu_fdt_add_subnode(ms->fdt, name); @@ -XXX,XX +XXX,XX @@ static void create_fdt_socket_aclint(RISCVVirtState *s, g_free(name); if (s->aia_type != VIRT_AIA_TYPE_APLIC_IMSIC) { - addr = memmap[VIRT_ACLINT_SSWI].base + - (memmap[VIRT_ACLINT_SSWI].size * socket); + addr = s->memmap[VIRT_ACLINT_SSWI].base + + (s->memmap[VIRT_ACLINT_SSWI].size * socket); + name = g_strdup_printf("/soc/sswi@%lx", addr); qemu_fdt_add_subnode(ms->fdt, name); qemu_fdt_setprop_string(ms->fdt, name, "compatible", "riscv,aclint-sswi"); qemu_fdt_setprop_cells(ms->fdt, name, "reg", - 0x0, addr, 0x0, memmap[VIRT_ACLINT_SSWI].size); + 0x0, addr, 0x0, s->memmap[VIRT_ACLINT_SSWI].size); qemu_fdt_setprop(ms->fdt, name, "interrupts-extended", aclint_sswi_cells, aclint_cells_size); qemu_fdt_setprop(ms->fdt, name, "interrupt-controller", NULL, 0); @@ -XXX,XX +XXX,XX @@ static void create_fdt_socket_aclint(RISCVVirtState *s, } static void create_fdt_socket_plic(RISCVVirtState *s, - const MemMapEntry *memmap, int socket, + int socket, uint32_t *phandle, uint32_t *intc_phandles, uint32_t *plic_phandles) { @@ -XXX,XX +XXX,XX @@ static void create_fdt_socket_plic(RISCVVirtState *s, }; plic_phandles[socket] = (*phandle)++; - plic_addr = memmap[VIRT_PLIC].base + (memmap[VIRT_PLIC].size * socket); + plic_addr = s->memmap[VIRT_PLIC].base + + (s->memmap[VIRT_PLIC].size * socket); plic_name = g_strdup_printf("/soc/plic@%lx", plic_addr); qemu_fdt_add_subnode(ms->fdt, plic_name); qemu_fdt_setprop_cell(ms->fdt, plic_name, @@ -XXX,XX +XXX,XX @@ static void create_fdt_socket_plic(RISCVVirtState *s, } qemu_fdt_setprop_cells(ms->fdt, plic_name, "reg", - 0x0, plic_addr, 0x0, memmap[VIRT_PLIC].size); + 0x0, plic_addr, 0x0, s->memmap[VIRT_PLIC].size); qemu_fdt_setprop_cell(ms->fdt, plic_name, "riscv,ndev", VIRT_IRQCHIP_NUM_SOURCES - 1); riscv_socket_fdt_write_id(ms, plic_name, socket); @@ -XXX,XX +XXX,XX @@ static void create_fdt_socket_plic(RISCVVirtState *s, if (!socket) { platform_bus_add_all_fdt_nodes(ms->fdt, plic_name, - memmap[VIRT_PLATFORM_BUS].base, - memmap[VIRT_PLATFORM_BUS].size, + s->memmap[VIRT_PLATFORM_BUS].base, + s->memmap[VIRT_PLATFORM_BUS].size, VIRT_PLATFORM_BUS_IRQ); } } @@ -XXX,XX +XXX,XX @@ static void create_fdt_one_imsic(RISCVVirtState *s, hwaddr base_addr, qemu_fdt_setprop_cell(ms->fdt, imsic_name, "phandle", msi_phandle); } -static void create_fdt_imsic(RISCVVirtState *s, const MemMapEntry *memmap, +static void create_fdt_imsic(RISCVVirtState *s, uint32_t *phandle, uint32_t *intc_phandles, uint32_t *msi_m_phandle, uint32_t *msi_s_phandle) { @@ -XXX,XX +XXX,XX @@ static void create_fdt_imsic(RISCVVirtState *s, const MemMapEntry *memmap, if (!kvm_enabled()) { /* M-level IMSIC node */ - create_fdt_one_imsic(s, memmap[VIRT_IMSIC_M].base, intc_phandles, + create_fdt_one_imsic(s, s->memmap[VIRT_IMSIC_M].base, intc_phandles, *msi_m_phandle, true, 0); } /* S-level IMSIC node */ - create_fdt_one_imsic(s, memmap[VIRT_IMSIC_S].base, intc_phandles, + create_fdt_one_imsic(s, s->memmap[VIRT_IMSIC_S].base, intc_phandles, *msi_s_phandle, false, imsic_num_bits(s->aia_guests + 1)); @@ -XXX,XX +XXX,XX @@ static void create_fdt_one_aplic(RISCVVirtState *s, int socket, } static void create_fdt_socket_aplic(RISCVVirtState *s, - const MemMapEntry *memmap, int socket, + int socket, uint32_t msi_m_phandle, uint32_t msi_s_phandle, uint32_t *phandle, @@ -XXX,XX +XXX,XX @@ static void create_fdt_socket_aplic(RISCVVirtState *s, if (!kvm_enabled()) { /* M-level APLIC node */ - aplic_addr = memmap[VIRT_APLIC_M].base + - (memmap[VIRT_APLIC_M].size * socket); - create_fdt_one_aplic(s, socket, aplic_addr, memmap[VIRT_APLIC_M].size, + aplic_addr = s->memmap[VIRT_APLIC_M].base + + (s->memmap[VIRT_APLIC_M].size * socket); + create_fdt_one_aplic(s, socket, aplic_addr, + s->memmap[VIRT_APLIC_M].size, msi_m_phandle, intc_phandles, aplic_m_phandle, aplic_s_phandle, true, num_harts); } /* S-level APLIC node */ - aplic_addr = memmap[VIRT_APLIC_S].base + - (memmap[VIRT_APLIC_S].size * socket); - create_fdt_one_aplic(s, socket, aplic_addr, memmap[VIRT_APLIC_S].size, + aplic_addr = s->memmap[VIRT_APLIC_S].base + + (s->memmap[VIRT_APLIC_S].size * socket); + create_fdt_one_aplic(s, socket, aplic_addr, s->memmap[VIRT_APLIC_S].size, msi_s_phandle, intc_phandles, aplic_s_phandle, 0, false, num_harts); @@ -XXX,XX +XXX,XX @@ static void create_fdt_socket_aplic(RISCVVirtState *s, if (!socket) { g_autofree char *aplic_name = fdt_get_aplic_nodename(aplic_addr); platform_bus_add_all_fdt_nodes(ms->fdt, aplic_name, - memmap[VIRT_PLATFORM_BUS].base, - memmap[VIRT_PLATFORM_BUS].size, + s->memmap[VIRT_PLATFORM_BUS].base, + s->memmap[VIRT_PLATFORM_BUS].size, VIRT_PLATFORM_BUS_IRQ); } @@ -XXX,XX +XXX,XX @@ static void create_fdt_pmu(RISCVVirtState *s) riscv_pmu_generate_fdt_node(ms->fdt, hart.pmu_avail_ctrs, pmu_name); } -static void create_fdt_sockets(RISCVVirtState *s, const MemMapEntry *memmap, +static void create_fdt_sockets(RISCVVirtState *s, uint32_t *phandle, uint32_t *irq_mmio_phandle, uint32_t *irq_pcie_phandle, @@ -XXX,XX +XXX,XX @@ static void create_fdt_sockets(RISCVVirtState *s, const MemMapEntry *memmap, create_fdt_socket_cpus(s, socket, clust_name, phandle, &intc_phandles[phandle_pos]); - create_fdt_socket_memory(s, memmap, socket); + create_fdt_socket_memory(s, socket); if (virt_aclint_allowed() && s->have_aclint) { - create_fdt_socket_aclint(s, memmap, socket, + create_fdt_socket_aclint(s, socket, &intc_phandles[phandle_pos]); } else if (tcg_enabled()) { - create_fdt_socket_clint(s, memmap, socket, + create_fdt_socket_clint(s, socket, &intc_phandles[phandle_pos]); } } if (s->aia_type == VIRT_AIA_TYPE_APLIC_IMSIC) { - create_fdt_imsic(s, memmap, phandle, intc_phandles, - &msi_m_phandle, &msi_s_phandle); + create_fdt_imsic(s, phandle, intc_phandles, + &msi_m_phandle, &msi_s_phandle); *msi_pcie_phandle = msi_s_phandle; } @@ -XXX,XX +XXX,XX @@ static void create_fdt_sockets(RISCVVirtState *s, const MemMapEntry *memmap, * mode, we'll use only one APLIC instance. */ if (!virt_use_emulated_aplic(s->aia_type)) { - create_fdt_socket_aplic(s, memmap, 0, + create_fdt_socket_aplic(s, 0, msi_m_phandle, msi_s_phandle, phandle, &intc_phandles[0], xplic_phandles, ms->smp.cpus); @@ -XXX,XX +XXX,XX @@ static void create_fdt_sockets(RISCVVirtState *s, const MemMapEntry *memmap, phandle_pos -= s->soc[socket].num_harts; if (s->aia_type == VIRT_AIA_TYPE_NONE) { - create_fdt_socket_plic(s, memmap, socket, phandle, + create_fdt_socket_plic(s, socket, phandle, &intc_phandles[phandle_pos], xplic_phandles); } else { - create_fdt_socket_aplic(s, memmap, socket, + create_fdt_socket_aplic(s, socket, msi_m_phandle, msi_s_phandle, phandle, &intc_phandles[phandle_pos], xplic_phandles, @@ -XXX,XX +XXX,XX @@ static void finalize_fdt(RISCVVirtState *s) uint32_t irq_pcie_phandle = 1, irq_virtio_phandle = 1; uint32_t iommu_sys_phandle = 1; - create_fdt_sockets(s, s->memmap, &phandle, &irq_mmio_phandle, + create_fdt_sockets(s, &phandle, &irq_mmio_phandle, &irq_pcie_phandle, &irq_virtio_phandle, &msi_pcie_phandle); -- 2.49.0
From: Daniel Henrique Barboza <dbarboza@ventanamicro.com> create_fdt_virtio() can use s->memmap instead of having an extra argument for it. While we're at it rewrite it a little bit to avoid the clunky line in 'name' and code repetition: - declare 'virtio_base' out of the loop since it never changes; - declare a 'size' variable. Use it to calculate the address of the virtio device in an 'addr' variable; - use 'addr' in the 'name' g_strdup_printf(); - use 'addr' and 'size' when creating the 'reg' property. Signed-off-by: Daniel Henrique Barboza <dbarboza@ventanamicro.com> Reviewed-by: Alistair Francis <alistair.francis@wdc.com> Message-ID: <20250429125811.224803-8-dbarboza@ventanamicro.com> Signed-off-by: Alistair Francis <alistair.francis@wdc.com> --- hw/riscv/virt.c | 17 ++++++++++------- 1 file changed, 10 insertions(+), 7 deletions(-) diff --git a/hw/riscv/virt.c b/hw/riscv/virt.c index XXXXXXX..XXXXXXX 100644 --- a/hw/riscv/virt.c +++ b/hw/riscv/virt.c @@ -XXX,XX +XXX,XX @@ static void create_fdt_sockets(RISCVVirtState *s, riscv_socket_fdt_write_distance_matrix(ms); } -static void create_fdt_virtio(RISCVVirtState *s, const MemMapEntry *memmap, - uint32_t irq_virtio_phandle) +static void create_fdt_virtio(RISCVVirtState *s, uint32_t irq_virtio_phandle) { int i; MachineState *ms = MACHINE(s); + hwaddr virtio_base = s->memmap[VIRT_VIRTIO].base; for (i = 0; i < VIRTIO_COUNT; i++) { - g_autofree char *name = g_strdup_printf("/soc/virtio_mmio@%lx", - (long)(memmap[VIRT_VIRTIO].base + i * memmap[VIRT_VIRTIO].size)); + g_autofree char *name = NULL; + uint64_t size = s->memmap[VIRT_VIRTIO].size; + hwaddr addr = virtio_base + i * size; + + name = g_strdup_printf("/soc/virtio_mmio@%"HWADDR_PRIx, addr); qemu_fdt_add_subnode(ms->fdt, name); qemu_fdt_setprop_string(ms->fdt, name, "compatible", "virtio,mmio"); qemu_fdt_setprop_cells(ms->fdt, name, "reg", - 0x0, memmap[VIRT_VIRTIO].base + i * memmap[VIRT_VIRTIO].size, - 0x0, memmap[VIRT_VIRTIO].size); + 0x0, addr, + 0x0, size); qemu_fdt_setprop_cell(ms->fdt, name, "interrupt-parent", irq_virtio_phandle); if (s->aia_type == VIRT_AIA_TYPE_NONE) { @@ -XXX,XX +XXX,XX @@ static void finalize_fdt(RISCVVirtState *s) &irq_pcie_phandle, &irq_virtio_phandle, &msi_pcie_phandle); - create_fdt_virtio(s, s->memmap, irq_virtio_phandle); + create_fdt_virtio(s, irq_virtio_phandle); if (virt_is_iommu_sys_enabled(s)) { create_fdt_iommu_sys(s, irq_mmio_phandle, msi_pcie_phandle, -- 2.49.0
From: Daniel Henrique Barboza <dbarboza@ventanamicro.com> Change create_fdt_pcie(), create_fdt_reset(), create_fdt_uart() and create_fdt_rtc() to use s->memmap in their logic. Signed-off-by: Daniel Henrique Barboza <dbarboza@ventanamicro.com> Reviewed-by: Alistair Francis <alistair.francis@wdc.com> Message-ID: <20250429125811.224803-9-dbarboza@ventanamicro.com> Signed-off-by: Alistair Francis <alistair.francis@wdc.com> --- hw/riscv/virt.c | 44 ++++++++++++++++++++++---------------------- 1 file changed, 22 insertions(+), 22 deletions(-) diff --git a/hw/riscv/virt.c b/hw/riscv/virt.c index XXXXXXX..XXXXXXX 100644 --- a/hw/riscv/virt.c +++ b/hw/riscv/virt.c @@ -XXX,XX +XXX,XX @@ static void create_fdt_virtio(RISCVVirtState *s, uint32_t irq_virtio_phandle) } } -static void create_fdt_pcie(RISCVVirtState *s, const MemMapEntry *memmap, +static void create_fdt_pcie(RISCVVirtState *s, uint32_t irq_pcie_phandle, uint32_t msi_pcie_phandle, uint32_t iommu_sys_phandle) @@ -XXX,XX +XXX,XX @@ static void create_fdt_pcie(RISCVVirtState *s, const MemMapEntry *memmap, MachineState *ms = MACHINE(s); name = g_strdup_printf("/soc/pci@%lx", - (long) memmap[VIRT_PCIE_ECAM].base); + (long) s->memmap[VIRT_PCIE_ECAM].base); qemu_fdt_setprop_cell(ms->fdt, name, "#address-cells", FDT_PCI_ADDR_CELLS); qemu_fdt_setprop_cell(ms->fdt, name, "#interrupt-cells", @@ -XXX,XX +XXX,XX @@ static void create_fdt_pcie(RISCVVirtState *s, const MemMapEntry *memmap, qemu_fdt_setprop_string(ms->fdt, name, "device_type", "pci"); qemu_fdt_setprop_cell(ms->fdt, name, "linux,pci-domain", 0); qemu_fdt_setprop_cells(ms->fdt, name, "bus-range", 0, - memmap[VIRT_PCIE_ECAM].size / PCIE_MMCFG_SIZE_MIN - 1); + s->memmap[VIRT_PCIE_ECAM].size / PCIE_MMCFG_SIZE_MIN - 1); qemu_fdt_setprop(ms->fdt, name, "dma-coherent", NULL, 0); if (s->aia_type == VIRT_AIA_TYPE_APLIC_IMSIC) { qemu_fdt_setprop_cell(ms->fdt, name, "msi-parent", msi_pcie_phandle); } qemu_fdt_setprop_cells(ms->fdt, name, "reg", 0, - memmap[VIRT_PCIE_ECAM].base, 0, memmap[VIRT_PCIE_ECAM].size); + s->memmap[VIRT_PCIE_ECAM].base, 0, s->memmap[VIRT_PCIE_ECAM].size); qemu_fdt_setprop_sized_cells(ms->fdt, name, "ranges", 1, FDT_PCI_RANGE_IOPORT, 2, 0, - 2, memmap[VIRT_PCIE_PIO].base, 2, memmap[VIRT_PCIE_PIO].size, + 2, s->memmap[VIRT_PCIE_PIO].base, 2, s->memmap[VIRT_PCIE_PIO].size, 1, FDT_PCI_RANGE_MMIO, - 2, memmap[VIRT_PCIE_MMIO].base, - 2, memmap[VIRT_PCIE_MMIO].base, 2, memmap[VIRT_PCIE_MMIO].size, + 2, s->memmap[VIRT_PCIE_MMIO].base, + 2, s->memmap[VIRT_PCIE_MMIO].base, 2, s->memmap[VIRT_PCIE_MMIO].size, 1, FDT_PCI_RANGE_MMIO_64BIT, 2, virt_high_pcie_memmap.base, 2, virt_high_pcie_memmap.base, 2, virt_high_pcie_memmap.size); @@ -XXX,XX +XXX,XX @@ static void create_fdt_pcie(RISCVVirtState *s, const MemMapEntry *memmap, create_pcie_irq_map(s, ms->fdt, name, irq_pcie_phandle); } -static void create_fdt_reset(RISCVVirtState *s, const MemMapEntry *memmap, - uint32_t *phandle) +static void create_fdt_reset(RISCVVirtState *s, uint32_t *phandle) { char *name; uint32_t test_phandle; @@ -XXX,XX +XXX,XX @@ static void create_fdt_reset(RISCVVirtState *s, const MemMapEntry *memmap, test_phandle = (*phandle)++; name = g_strdup_printf("/soc/test@%lx", - (long)memmap[VIRT_TEST].base); + (long)s->memmap[VIRT_TEST].base); qemu_fdt_add_subnode(ms->fdt, name); { static const char * const compat[3] = { @@ -XXX,XX +XXX,XX @@ static void create_fdt_reset(RISCVVirtState *s, const MemMapEntry *memmap, (char **)&compat, ARRAY_SIZE(compat)); } qemu_fdt_setprop_cells(ms->fdt, name, "reg", - 0x0, memmap[VIRT_TEST].base, 0x0, memmap[VIRT_TEST].size); + 0x0, s->memmap[VIRT_TEST].base, 0x0, s->memmap[VIRT_TEST].size); qemu_fdt_setprop_cell(ms->fdt, name, "phandle", test_phandle); test_phandle = qemu_fdt_get_phandle(ms->fdt, name); g_free(name); @@ -XXX,XX +XXX,XX @@ static void create_fdt_reset(RISCVVirtState *s, const MemMapEntry *memmap, g_free(name); } -static void create_fdt_uart(RISCVVirtState *s, const MemMapEntry *memmap, +static void create_fdt_uart(RISCVVirtState *s, uint32_t irq_mmio_phandle) { g_autofree char *name = NULL; MachineState *ms = MACHINE(s); - name = g_strdup_printf("/soc/serial@%lx", (long)memmap[VIRT_UART0].base); + name = g_strdup_printf("/soc/serial@%lx", + (long)s->memmap[VIRT_UART0].base); qemu_fdt_add_subnode(ms->fdt, name); qemu_fdt_setprop_string(ms->fdt, name, "compatible", "ns16550a"); qemu_fdt_setprop_cells(ms->fdt, name, "reg", - 0x0, memmap[VIRT_UART0].base, - 0x0, memmap[VIRT_UART0].size); + 0x0, s->memmap[VIRT_UART0].base, + 0x0, s->memmap[VIRT_UART0].size); qemu_fdt_setprop_cell(ms->fdt, name, "clock-frequency", 3686400); qemu_fdt_setprop_cell(ms->fdt, name, "interrupt-parent", irq_mmio_phandle); if (s->aia_type == VIRT_AIA_TYPE_NONE) { @@ -XXX,XX +XXX,XX @@ static void create_fdt_uart(RISCVVirtState *s, const MemMapEntry *memmap, qemu_fdt_setprop_string(ms->fdt, "/aliases", "serial0", name); } -static void create_fdt_rtc(RISCVVirtState *s, const MemMapEntry *memmap, +static void create_fdt_rtc(RISCVVirtState *s, uint32_t irq_mmio_phandle) { g_autofree char *name = NULL; MachineState *ms = MACHINE(s); - name = g_strdup_printf("/soc/rtc@%lx", (long)memmap[VIRT_RTC].base); + name = g_strdup_printf("/soc/rtc@%lx", (long)s->memmap[VIRT_RTC].base); qemu_fdt_add_subnode(ms->fdt, name); qemu_fdt_setprop_string(ms->fdt, name, "compatible", "google,goldfish-rtc"); qemu_fdt_setprop_cells(ms->fdt, name, "reg", - 0x0, memmap[VIRT_RTC].base, 0x0, memmap[VIRT_RTC].size); + 0x0, s->memmap[VIRT_RTC].base, 0x0, s->memmap[VIRT_RTC].size); qemu_fdt_setprop_cell(ms->fdt, name, "interrupt-parent", irq_mmio_phandle); if (s->aia_type == VIRT_AIA_TYPE_NONE) { @@ -XXX,XX +XXX,XX @@ static void finalize_fdt(RISCVVirtState *s) create_fdt_iommu_sys(s, irq_mmio_phandle, msi_pcie_phandle, &iommu_sys_phandle); } - create_fdt_pcie(s, s->memmap, irq_pcie_phandle, msi_pcie_phandle, + create_fdt_pcie(s, irq_pcie_phandle, msi_pcie_phandle, iommu_sys_phandle); - create_fdt_reset(s, s->memmap, &phandle); + create_fdt_reset(s, &phandle); - create_fdt_uart(s, s->memmap, irq_mmio_phandle); + create_fdt_uart(s, irq_mmio_phandle); - create_fdt_rtc(s, s->memmap, irq_mmio_phandle); + create_fdt_rtc(s, irq_mmio_phandle); } static void create_fdt(RISCVVirtState *s) -- 2.49.0
From: Daniel Henrique Barboza <dbarboza@ventanamicro.com> We can avoid the 'long' casts by using PRIx64 and HWADDR_PRIx on the fmt strings for uint64_t and hwaddr types. Signed-off-by: Daniel Henrique Barboza <dbarboza@ventanamicro.com> Reviewed-by: Philippe Mathieu-Daudé <philmd@linaro.org> Reviewed-by: Alistair Francis <alistair.francis@wdc.com> Message-ID: <20250429125811.224803-10-dbarboza@ventanamicro.com> Signed-off-by: Alistair Francis <alistair.francis@wdc.com> --- hw/riscv/virt.c | 32 +++++++++++++++++--------------- 1 file changed, 17 insertions(+), 15 deletions(-) diff --git a/hw/riscv/virt.c b/hw/riscv/virt.c index XXXXXXX..XXXXXXX 100644 --- a/hw/riscv/virt.c +++ b/hw/riscv/virt.c @@ -XXX,XX +XXX,XX @@ static void create_fdt_socket_cpus(RISCVVirtState *s, int socket, static void create_fdt_socket_memory(RISCVVirtState *s, int socket) { g_autofree char *mem_name = NULL; - uint64_t addr, size; + hwaddr addr; + uint64_t size; MachineState *ms = MACHINE(s); addr = s->memmap[VIRT_DRAM].base + riscv_socket_mem_offset(ms, socket); size = riscv_socket_mem_size(ms, socket); - mem_name = g_strdup_printf("/memory@%lx", (long)addr); + mem_name = g_strdup_printf("/memory@%"HWADDR_PRIx, addr); qemu_fdt_add_subnode(ms->fdt, mem_name); qemu_fdt_setprop_cells(ms->fdt, mem_name, "reg", addr >> 32, addr, size >> 32, size); @@ -XXX,XX +XXX,XX @@ static void create_fdt_pcie(RISCVVirtState *s, g_autofree char *name = NULL; MachineState *ms = MACHINE(s); - name = g_strdup_printf("/soc/pci@%lx", - (long) s->memmap[VIRT_PCIE_ECAM].base); + name = g_strdup_printf("/soc/pci@%"HWADDR_PRIx, + s->memmap[VIRT_PCIE_ECAM].base); qemu_fdt_setprop_cell(ms->fdt, name, "#address-cells", FDT_PCI_ADDR_CELLS); qemu_fdt_setprop_cell(ms->fdt, name, "#interrupt-cells", @@ -XXX,XX +XXX,XX @@ static void create_fdt_reset(RISCVVirtState *s, uint32_t *phandle) MachineState *ms = MACHINE(s); test_phandle = (*phandle)++; - name = g_strdup_printf("/soc/test@%lx", - (long)s->memmap[VIRT_TEST].base); + name = g_strdup_printf("/soc/test@%"HWADDR_PRIx, + s->memmap[VIRT_TEST].base); qemu_fdt_add_subnode(ms->fdt, name); { static const char * const compat[3] = { @@ -XXX,XX +XXX,XX @@ static void create_fdt_uart(RISCVVirtState *s, g_autofree char *name = NULL; MachineState *ms = MACHINE(s); - name = g_strdup_printf("/soc/serial@%lx", - (long)s->memmap[VIRT_UART0].base); + name = g_strdup_printf("/soc/serial@%"HWADDR_PRIx, + s->memmap[VIRT_UART0].base); qemu_fdt_add_subnode(ms->fdt, name); qemu_fdt_setprop_string(ms->fdt, name, "compatible", "ns16550a"); qemu_fdt_setprop_cells(ms->fdt, name, "reg", @@ -XXX,XX +XXX,XX @@ static void create_fdt_rtc(RISCVVirtState *s, g_autofree char *name = NULL; MachineState *ms = MACHINE(s); - name = g_strdup_printf("/soc/rtc@%lx", (long)s->memmap[VIRT_RTC].base); + name = g_strdup_printf("/soc/rtc@%"HWADDR_PRIx, + s->memmap[VIRT_RTC].base); qemu_fdt_add_subnode(ms->fdt, name); qemu_fdt_setprop_string(ms->fdt, name, "compatible", "google,goldfish-rtc"); @@ -XXX,XX +XXX,XX @@ static void create_fdt_virtio_iommu(RISCVVirtState *s, uint16_t bdf) g_autofree char *iommu_node = NULL; g_autofree char *pci_node = NULL; - pci_node = g_strdup_printf("/soc/pci@%lx", - (long) s->memmap[VIRT_PCIE_ECAM].base); + pci_node = g_strdup_printf("/soc/pci@%"HWADDR_PRIx, + s->memmap[VIRT_PCIE_ECAM].base); iommu_node = g_strdup_printf("%s/virtio_iommu@%x,%x", pci_node, PCI_SLOT(bdf), PCI_FUNC(bdf)); iommu_phandle = qemu_fdt_alloc_phandle(fdt); @@ -XXX,XX +XXX,XX @@ static void create_fdt_iommu(RISCVVirtState *s, uint16_t bdf) g_autofree char *iommu_node = NULL; g_autofree char *pci_node = NULL; - pci_node = g_strdup_printf("/soc/pci@%lx", - (long) s->memmap[VIRT_PCIE_ECAM].base); + pci_node = g_strdup_printf("/soc/pci@%"HWADDR_PRIx, + s->memmap[VIRT_PCIE_ECAM].base); iommu_node = g_strdup_printf("%s/iommu@%x", pci_node, bdf); iommu_phandle = qemu_fdt_alloc_phandle(fdt); qemu_fdt_add_subnode(fdt, iommu_node); @@ -XXX,XX +XXX,XX @@ static void create_fdt(RISCVVirtState *s) * The "/soc/pci@..." node is needed for PCIE hotplugs * that might happen before finalize_fdt(). */ - name = g_strdup_printf("/soc/pci@%lx", - (long) s->memmap[VIRT_PCIE_ECAM].base); + name = g_strdup_printf("/soc/pci@%"HWADDR_PRIx, + s->memmap[VIRT_PCIE_ECAM].base); qemu_fdt_add_subnode(ms->fdt, name); qemu_fdt_add_subnode(ms->fdt, "/chosen"); -- 2.49.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