From c0c2344c4354180edf2476ae5764548a36fa9b67 Mon Sep 17 00:00:00 2001 From: Eric Auger Date: Tue, 1 Jul 2025 15:08:28 +0100 Subject: arm/cpu: Store id_isar0-7 into the idregs array Reviewed-by: Richard Henderson Reviewed-by: Sebastian Ott Signed-off-by: Eric Auger Signed-off-by: Cornelia Huck Message-id: 20250617153931.1330449-9-cohuck@redhat.com Signed-off-by: Peter Maydell --- hw/intc/armv7m_nvic.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) (limited to 'hw') diff --git a/hw/intc/armv7m_nvic.c b/hw/intc/armv7m_nvic.c index 83ff74f..fdb7f58 100644 --- a/hw/intc/armv7m_nvic.c +++ b/hw/intc/armv7m_nvic.c @@ -1303,32 +1303,32 @@ static uint32_t nvic_readl(NVICState *s, uint32_t offset, MemTxAttrs attrs) if (!arm_feature(&cpu->env, ARM_FEATURE_M_MAIN)) { goto bad_offset; } - return cpu->isar.id_isar0; + return GET_IDREG(&cpu->isar, ID_ISAR0); case 0xd64: /* ISAR1. */ if (!arm_feature(&cpu->env, ARM_FEATURE_M_MAIN)) { goto bad_offset; } - return cpu->isar.id_isar1; + return GET_IDREG(&cpu->isar, ID_ISAR1); case 0xd68: /* ISAR2. */ if (!arm_feature(&cpu->env, ARM_FEATURE_M_MAIN)) { goto bad_offset; } - return cpu->isar.id_isar2; + return GET_IDREG(&cpu->isar, ID_ISAR2); case 0xd6c: /* ISAR3. */ if (!arm_feature(&cpu->env, ARM_FEATURE_M_MAIN)) { goto bad_offset; } - return cpu->isar.id_isar3; + return GET_IDREG(&cpu->isar, ID_ISAR3); case 0xd70: /* ISAR4. */ if (!arm_feature(&cpu->env, ARM_FEATURE_M_MAIN)) { goto bad_offset; } - return cpu->isar.id_isar4; + return GET_IDREG(&cpu->isar, ID_ISAR4); case 0xd74: /* ISAR5. */ if (!arm_feature(&cpu->env, ARM_FEATURE_M_MAIN)) { goto bad_offset; } - return cpu->isar.id_isar5; + return GET_IDREG(&cpu->isar, ID_ISAR5); case 0xd78: /* CLIDR */ return cpu->clidr; case 0xd7c: /* CTR */ -- cgit v1.1 From 30ca689900c8c47bc4ca46be00ec9a7f1a78ccda Mon Sep 17 00:00:00 2001 From: Eric Auger Date: Tue, 1 Jul 2025 15:08:28 +0100 Subject: arm/cpu: Store id_pfr0/1/2 into the idregs array Reviewed-by: Richard Henderson Reviewed-by: Sebastian Ott Signed-off-by: Eric Auger Signed-off-by: Cornelia Huck Message-id: 20250617153931.1330449-10-cohuck@redhat.com Signed-off-by: Peter Maydell --- hw/intc/armv7m_nvic.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) (limited to 'hw') diff --git a/hw/intc/armv7m_nvic.c b/hw/intc/armv7m_nvic.c index fdb7f58..330205f 100644 --- a/hw/intc/armv7m_nvic.c +++ b/hw/intc/armv7m_nvic.c @@ -988,6 +988,7 @@ static void nvic_nmi_trigger(void *opaque, int n, int level) static uint32_t nvic_readl(NVICState *s, uint32_t offset, MemTxAttrs attrs) { ARMCPU *cpu = s->cpu; + ARMISARegisters *isar = &cpu->isar; uint32_t val; switch (offset) { @@ -1263,12 +1264,12 @@ static uint32_t nvic_readl(NVICState *s, uint32_t offset, MemTxAttrs attrs) if (!arm_feature(&cpu->env, ARM_FEATURE_M_MAIN)) { goto bad_offset; } - return cpu->isar.id_pfr0; + return GET_IDREG(isar, ID_PFR0); case 0xd44: /* PFR1. */ if (!arm_feature(&cpu->env, ARM_FEATURE_M_MAIN)) { goto bad_offset; } - return cpu->isar.id_pfr1; + return GET_IDREG(isar, ID_PFR1); case 0xd48: /* DFR0. */ if (!arm_feature(&cpu->env, ARM_FEATURE_M_MAIN)) { goto bad_offset; -- cgit v1.1 From 33801d9bd0947042f223966bbb04f7528e1443f2 Mon Sep 17 00:00:00 2001 From: Eric Auger Date: Tue, 1 Jul 2025 15:08:28 +0100 Subject: arm/cpu: Store id_dfr0/1 into the idregs array Reviewed-by: Richard Henderson Reviewed-by: Sebastian Ott Signed-off-by: Eric Auger Signed-off-by: Cornelia Huck Message-id: 20250617153931.1330449-11-cohuck@redhat.com Signed-off-by: Peter Maydell --- hw/intc/armv7m_nvic.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'hw') diff --git a/hw/intc/armv7m_nvic.c b/hw/intc/armv7m_nvic.c index 330205f..2566dd6 100644 --- a/hw/intc/armv7m_nvic.c +++ b/hw/intc/armv7m_nvic.c @@ -1274,7 +1274,7 @@ static uint32_t nvic_readl(NVICState *s, uint32_t offset, MemTxAttrs attrs) if (!arm_feature(&cpu->env, ARM_FEATURE_M_MAIN)) { goto bad_offset; } - return cpu->isar.id_dfr0; + return GET_IDREG(isar, ID_DFR0); case 0xd4c: /* AFR0. */ if (!arm_feature(&cpu->env, ARM_FEATURE_M_MAIN)) { goto bad_offset; -- cgit v1.1 From 987fa88a11cefe0058326c49dd190ab329635fe0 Mon Sep 17 00:00:00 2001 From: Eric Auger Date: Tue, 1 Jul 2025 15:08:29 +0100 Subject: arm/cpu: Store id_mmfr0-5 into the idregs array Reviewed-by: Richard Henderson Reviewed-by: Sebastian Ott Signed-off-by: Eric Auger Signed-off-by: Cornelia Huck Message-id: 20250617153931.1330449-12-cohuck@redhat.com Signed-off-by: Peter Maydell --- hw/intc/armv7m_nvic.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'hw') diff --git a/hw/intc/armv7m_nvic.c b/hw/intc/armv7m_nvic.c index 2566dd6..6d85720 100644 --- a/hw/intc/armv7m_nvic.c +++ b/hw/intc/armv7m_nvic.c @@ -1284,22 +1284,22 @@ static uint32_t nvic_readl(NVICState *s, uint32_t offset, MemTxAttrs attrs) if (!arm_feature(&cpu->env, ARM_FEATURE_M_MAIN)) { goto bad_offset; } - return cpu->isar.id_mmfr0; + return GET_IDREG(isar, ID_MMFR0); case 0xd54: /* MMFR1. */ if (!arm_feature(&cpu->env, ARM_FEATURE_M_MAIN)) { goto bad_offset; } - return cpu->isar.id_mmfr1; + return GET_IDREG(isar, ID_MMFR1); case 0xd58: /* MMFR2. */ if (!arm_feature(&cpu->env, ARM_FEATURE_M_MAIN)) { goto bad_offset; } - return cpu->isar.id_mmfr2; + return GET_IDREG(isar, ID_MMFR2); case 0xd5c: /* MMFR3. */ if (!arm_feature(&cpu->env, ARM_FEATURE_M_MAIN)) { goto bad_offset; } - return cpu->isar.id_mmfr3; + return GET_IDREG(isar, ID_MMFR3); case 0xd60: /* ISAR0. */ if (!arm_feature(&cpu->env, ARM_FEATURE_M_MAIN)) { goto bad_offset; -- cgit v1.1 From 374d766da75ab89749f59813f7ae55d913c37b58 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Tue, 1 Jul 2025 15:08:29 +0100 Subject: hw/intc/gicv3_its: Do not check its_class_name() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Since commit cc5e719e2c8 ("kvm: require KVM_CAP_SIGNAL_MSI"), the single implementation of its_class_name() no longer returns NULL (it now always returns a valid char pointer). Hence, update the prototype docstring and remove the tautological checks that use the its_class_name() returned value. Signed-off-by: Philippe Mathieu-Daudé Signed-off-by: Gustavo Romero Reviewed-by: Richard Henderson Reviewed-by: Eric Auger Message-id: 20250628195722.977078-2-gustavo.romero@linaro.org Signed-off-by: Peter Maydell --- hw/arm/virt-acpi-build.c | 32 ++++++++++++++------------------ 1 file changed, 14 insertions(+), 18 deletions(-) (limited to 'hw') diff --git a/hw/arm/virt-acpi-build.c b/hw/arm/virt-acpi-build.c index 7e8e0f0..9eee284 100644 --- a/hw/arm/virt-acpi-build.c +++ b/hw/arm/virt-acpi-build.c @@ -737,20 +737,18 @@ build_madt(GArray *table_data, BIOSLinker *linker, VirtMachineState *vms) memmap[VIRT_HIGH_GIC_REDIST2].size); } - if (its_class_name()) { - /* - * ACPI spec, Revision 6.0 Errata A - * (original 6.0 definition has invalid Length) - * 5.2.12.18 GIC ITS Structure - */ - build_append_int_noprefix(table_data, 0xF, 1); /* Type */ - build_append_int_noprefix(table_data, 20, 1); /* Length */ - build_append_int_noprefix(table_data, 0, 2); /* Reserved */ - build_append_int_noprefix(table_data, 0, 4); /* GIC ITS ID */ - /* Physical Base Address */ - build_append_int_noprefix(table_data, memmap[VIRT_GIC_ITS].base, 8); - build_append_int_noprefix(table_data, 0, 4); /* Reserved */ - } + /* + * ACPI spec, Revision 6.0 Errata A + * (original 6.0 definition has invalid Length) + * 5.2.12.18 GIC ITS Structure + */ + build_append_int_noprefix(table_data, 0xF, 1); /* Type */ + build_append_int_noprefix(table_data, 20, 1); /* Length */ + build_append_int_noprefix(table_data, 0, 2); /* Reserved */ + build_append_int_noprefix(table_data, 0, 4); /* GIC ITS ID */ + /* Physical Base Address */ + build_append_int_noprefix(table_data, memmap[VIRT_GIC_ITS].base, 8); + build_append_int_noprefix(table_data, 0, 4); /* Reserved */ } else { const uint16_t spi_base = vms->irqmap[VIRT_GIC_V2M] + ARM_SPI_BASE; @@ -969,10 +967,8 @@ void virt_acpi_build(VirtMachineState *vms, AcpiBuildTables *tables) vms->oem_table_id); } - if (its_class_name()) { - acpi_add_table(table_offsets, tables_blob); - build_iort(tables_blob, tables->linker, vms); - } + acpi_add_table(table_offsets, tables_blob); + build_iort(tables_blob, tables->linker, vms); #ifdef CONFIG_TPM if (tpm_get_version(tpm_find()) == TPM_VERSION_2_0) { -- cgit v1.1 From 43eb1805437e1c904fcb5d8ce93096301128a4d0 Mon Sep 17 00:00:00 2001 From: Gustavo Romero Date: Tue, 1 Jul 2025 15:08:29 +0100 Subject: hw/arm/virt: Simplify logic for setting instance's 'tcg_its' variable MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Because 'tcg_its' in the machine instance is set based on the machine class’s negated variable 'no_tcg_its', 'tcg_its' is the opposite of 'no_tcg_its' and hence the code in question can be simplified as: tcg_its = !no_tcg_its. Signed-off-by: Gustavo Romero Reviewed-by: Eric Auger Message-id: 20250628195722.977078-3-gustavo.romero@linaro.org Signed-off-by: Peter Maydell --- hw/arm/virt.c | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) (limited to 'hw') diff --git a/hw/arm/virt.c b/hw/arm/virt.c index 99fde58..6d9256a 100644 --- a/hw/arm/virt.c +++ b/hw/arm/virt.c @@ -3342,12 +3342,8 @@ static void virt_instance_init(Object *obj) /* Default allows ITS instantiation */ vms->its = true; - - if (vmc->no_tcg_its) { - vms->tcg_its = false; - } else { - vms->tcg_its = true; - } + /* Allow ITS emulation if the machine version supports it */ + vms->tcg_its = !vmc->no_tcg_its; /* Default disallows iommu instantiation */ vms->iommu = VIRT_IOMMU_NONE; -- cgit v1.1 From 029cd5d6d1b6fea5d3280c7093e2adbd7d9e32f4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Tue, 1 Jul 2025 15:08:30 +0100 Subject: hw/arm/virt: Simplify create_its() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit No need to strstr() check the class name when we can use kvm_irqchip_in_kernel() to check if the ITS from the host can be used. Signed-off-by: Philippe Mathieu-Daudé Reviewed-by: Richard Henderson Reviewed-by: Eric Auger Reviewed-by: Gustavo Romero Message-id: 20250628195722.977078-4-gustavo.romero@linaro.org Signed-off-by: Peter Maydell --- hw/arm/virt.c | 17 +++++++---------- 1 file changed, 7 insertions(+), 10 deletions(-) (limited to 'hw') diff --git a/hw/arm/virt.c b/hw/arm/virt.c index 6d9256a..ae419e8 100644 --- a/hw/arm/virt.c +++ b/hw/arm/virt.c @@ -705,21 +705,18 @@ static inline DeviceState *create_acpi_ged(VirtMachineState *vms) static void create_its(VirtMachineState *vms) { - const char *itsclass = its_class_name(); DeviceState *dev; - if (!strcmp(itsclass, "arm-gicv3-its")) { - if (!vms->tcg_its) { - itsclass = NULL; - } - } - - if (!itsclass) { - /* Do nothing if not supported */ + assert(vms->its); + if (!kvm_irqchip_in_kernel() && !vms->tcg_its) { + /* + * Do nothing if ITS is neither supported by the host nor emulated by + * the machine. + */ return; } - dev = qdev_new(itsclass); + dev = qdev_new(its_class_name()); object_property_set_link(OBJECT(dev), "parent-gicv3", OBJECT(vms->gic), &error_abort); -- cgit v1.1 From 67473d32f020a3c62e24790ab93eb6086a8c8283 Mon Sep 17 00:00:00 2001 From: Gustavo Romero Date: Tue, 1 Jul 2025 15:08:30 +0100 Subject: hw/arm/virt-acpi-build: Improve comment in build_iort When building the Root Complex table, the comment about the code that maps the RC node to SMMU node is misleading because it reads "RC -> SMMUv3 -> ITS", but the code is only mapping the RCs IDs to the SMMUv3 node. The step of mapping from the SMMUv3 IDs to the ITS Group node is actually defined in another table (in the SMMUv3 node). So change the comment to read "RC -> SMMUv3" instead. Signed-off-by Gustavo Romero Reviewed-by: Eric Auger Message-id: 20250628195722.977078-5-gustavo.romero@linaro.org Signed-off-by: Peter Maydell --- hw/arm/virt-acpi-build.c | 25 +++++++++++++++++++------ 1 file changed, 19 insertions(+), 6 deletions(-) (limited to 'hw') diff --git a/hw/arm/virt-acpi-build.c b/hw/arm/virt-acpi-build.c index 9eee284..e9cd3fb 100644 --- a/hw/arm/virt-acpi-build.c +++ b/hw/arm/virt-acpi-build.c @@ -370,7 +370,7 @@ build_iort(GArray *table_data, BIOSLinker *linker, VirtMachineState *vms) /* DeviceID mapping index (ignored since interrupts are GSIV based) */ build_append_int_noprefix(table_data, 0, 4); - /* output IORT node is the ITS group node (the first node) */ + /* Output IORT node is the ITS Group node (the first node) */ build_iort_id_mapping(table_data, 0, 0x10000, IORT_NODE_OFFSET); } @@ -407,23 +407,36 @@ build_iort(GArray *table_data, BIOSLinker *linker, VirtMachineState *vms) if (vms->iommu == VIRT_IOMMU_SMMUV3) { AcpiIortIdMapping *range; - /* translated RIDs connect to SMMUv3 node: RC -> SMMUv3 -> ITS */ + /* + * Map RIDs (input) from RC to SMMUv3 nodes: RC -> SMMUv3. + * + * N.B.: The mapping from SMMUv3 to ITS Group node (SMMUv3 -> ITS) is + * defined in the SMMUv3 table, where all SMMUv3 IDs are mapped to the + * ITS Group node. + */ for (i = 0; i < smmu_idmaps->len; i++) { range = &g_array_index(smmu_idmaps, AcpiIortIdMapping, i); - /* output IORT node is the smmuv3 node */ + /* Output IORT node is the SMMUv3 node. */ build_iort_id_mapping(table_data, range->input_base, range->id_count, smmu_offset); } - /* bypassed RIDs connect to ITS group node directly: RC -> ITS */ + /* + * Map bypassed (don't go throught the SMMU) RIDs (input) to ITS Group + * node directly: RC -> ITS. + */ for (i = 0; i < its_idmaps->len; i++) { range = &g_array_index(its_idmaps, AcpiIortIdMapping, i); - /* output IORT node is the ITS group node (the first node) */ + /* Output IORT node is the ITS Group node (the first node). */ build_iort_id_mapping(table_data, range->input_base, range->id_count, IORT_NODE_OFFSET); } } else { - /* output IORT node is the ITS group node (the first node) */ + /* + * Map all RIDs (input) to ITS Group node directly, since there is no + * SMMU: RC -> ITS. + * Output IORT node is the ITS Group node (the first node). + */ build_iort_id_mapping(table_data, 0, 0x10000, IORT_NODE_OFFSET); } -- cgit v1.1 From 1c41eaa5fe03cbe9f60edb8f0414c1ad6d7fd786 Mon Sep 17 00:00:00 2001 From: Gustavo Romero Date: Tue, 1 Jul 2025 15:08:30 +0100 Subject: hw/arm/virt-acpi-build: Factor out create_its_idmaps Factor out a new function, create_its_idmaps(), from the current build_iort code. Add proper comments to it clarifying how the ID ranges that go directly to the ITS Group node are computed based on the ones that are directed to the SMMU node. Suggested-by: Eric Auger Signed-off-by: Gustavo Romero Message-id: 20250628195722.977078-6-gustavo.romero@linaro.org [PMM: drop hardcoded tabs] Signed-off-by: Peter Maydell --- hw/arm/virt-acpi-build.c | 61 +++++++++++++++++++++++++++++++----------------- 1 file changed, 40 insertions(+), 21 deletions(-) (limited to 'hw') diff --git a/hw/arm/virt-acpi-build.c b/hw/arm/virt-acpi-build.c index e9cd3fb..5886192 100644 --- a/hw/arm/virt-acpi-build.c +++ b/hw/arm/virt-acpi-build.c @@ -266,6 +266,43 @@ static int iort_idmap_compare(gconstpointer a, gconstpointer b) return idmap_a->input_base - idmap_b->input_base; } +/* Compute ID ranges (RIDs) from RC that are directed to the ITS Group node */ +static void create_its_idmaps(GArray *its_idmaps, GArray *smmu_idmaps) +{ + AcpiIortIdMapping *idmap; + AcpiIortIdMapping next_range = {0}; + + /* + * Based on the RID ranges that are directed to the SMMU, determine the + * bypassed RID ranges, i.e., the ones that are directed to the ITS Group + * node and do not pass through the SMMU, by subtracting the SMMU-bound + * ranges from the full RID range (0x0000–0xFFFF). + */ + for (int i = 0; i < smmu_idmaps->len; i++) { + idmap = &g_array_index(smmu_idmaps, AcpiIortIdMapping, i); + + if (next_range.input_base < idmap->input_base) { + next_range.id_count = idmap->input_base - next_range.input_base; + g_array_append_val(its_idmaps, next_range); + } + + next_range.input_base = idmap->input_base + idmap->id_count; + } + + /* + * Append the last RC -> ITS ID mapping. + * + * RIDs are 16-bit, according to the PCI Express 2.0 Base Specification, rev + * 0.9, section 2.2.6.2, "Transaction Descriptor - Transaction ID Field", + * hence the end of the range is 0x10000. + */ + if (next_range.input_base < 0x10000) { + next_range.id_count = 0x10000 - next_range.input_base; + g_array_append_val(its_idmaps, next_range); + } +} + + /* * Input Output Remapping Table (IORT) * Conforms to "IO Remapping Table System Software on ARM Platforms", @@ -276,7 +313,6 @@ build_iort(GArray *table_data, BIOSLinker *linker, VirtMachineState *vms) { int i, nb_nodes, rc_mapping_count; size_t node_size, smmu_offset = 0; - AcpiIortIdMapping *idmap; uint32_t id = 0; GArray *smmu_idmaps = g_array_new(false, true, sizeof(AcpiIortIdMapping)); GArray *its_idmaps = g_array_new(false, true, sizeof(AcpiIortIdMapping)); @@ -287,8 +323,6 @@ build_iort(GArray *table_data, BIOSLinker *linker, VirtMachineState *vms) acpi_table_begin(&table, table_data); if (vms->iommu == VIRT_IOMMU_SMMUV3) { - AcpiIortIdMapping next_range = {0}; - object_child_foreach_recursive(object_get_root(), iort_host_bridges, smmu_idmaps); @@ -296,25 +330,10 @@ build_iort(GArray *table_data, BIOSLinker *linker, VirtMachineState *vms) g_array_sort(smmu_idmaps, iort_idmap_compare); /* - * Split the whole RIDs by mapping from RC to SMMU, - * build the ID mapping from RC to ITS directly. + * Knowing the ID ranges from the RC to the SMMU, it's possible to + * determine the ID ranges from RC that are directed to the ITS. */ - for (i = 0; i < smmu_idmaps->len; i++) { - idmap = &g_array_index(smmu_idmaps, AcpiIortIdMapping, i); - - if (next_range.input_base < idmap->input_base) { - next_range.id_count = idmap->input_base - next_range.input_base; - g_array_append_val(its_idmaps, next_range); - } - - next_range.input_base = idmap->input_base + idmap->id_count; - } - - /* Append the last RC -> ITS ID mapping */ - if (next_range.input_base < 0x10000) { - next_range.id_count = 0x10000 - next_range.input_base; - g_array_append_val(its_idmaps, next_range); - } + create_its_idmaps(its_idmaps, smmu_idmaps); nb_nodes = 3; /* RC, ITS, SMMUv3 */ rc_mapping_count = smmu_idmaps->len + its_idmaps->len; -- cgit v1.1 From d6afe18b7242111a71916a962fbd1876a77dc755 Mon Sep 17 00:00:00 2001 From: Gustavo Romero Date: Tue, 1 Jul 2025 15:08:31 +0100 Subject: hw/arm/virt-acpi-build: Fix ACPI IORT and MADT tables when its=off MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Currently, the ITS Group nodes in the IORT table and the GIC ITS Struct in the MADT table are always generated, even if GIC ITS is not available on the machine. This commit fixes it by not generating the ITS Group nodes, not mapping any other node to them, and not advertising the GIC ITS in the MADT table, when GIC ITS is not available on the machine. Since the fix changes the MADT and IORT tables, add the blobs for the "its=off" test to the allow list and update them in the next commit. This commit also renames the smmu_idmaps and its_idmaps variables in build_iort() to rc_smmu_idmaps and rc_its_idmaps, respectively, to make it clearer which nodes are involved in the mappings associated with these variables. Reported-by: Udo Steinberg Signed-off-by: Gustavo Romero Message-id: 20250628195722.977078-9-gustavo.romero@linaro.org Resolves: https://gitlab.com/qemu-project/qemu/-/issues/2886 Signed-off-by: Gustavo Romero Co-authored-by: Philippe Mathieu-Daudé [PMM: wrapped an overlong comment] Signed-off-by: Peter Maydell --- hw/arm/virt-acpi-build.c | 142 +++++++++++++++++++++++++++++------------------ 1 file changed, 88 insertions(+), 54 deletions(-) (limited to 'hw') diff --git a/hw/arm/virt-acpi-build.c b/hw/arm/virt-acpi-build.c index 5886192..cd90c47 100644 --- a/hw/arm/virt-acpi-build.c +++ b/hw/arm/virt-acpi-build.c @@ -267,7 +267,7 @@ static int iort_idmap_compare(gconstpointer a, gconstpointer b) } /* Compute ID ranges (RIDs) from RC that are directed to the ITS Group node */ -static void create_its_idmaps(GArray *its_idmaps, GArray *smmu_idmaps) +static void create_rc_its_idmaps(GArray *its_idmaps, GArray *smmu_idmaps) { AcpiIortIdMapping *idmap; AcpiIortIdMapping next_range = {0}; @@ -314,8 +314,8 @@ build_iort(GArray *table_data, BIOSLinker *linker, VirtMachineState *vms) int i, nb_nodes, rc_mapping_count; size_t node_size, smmu_offset = 0; uint32_t id = 0; - GArray *smmu_idmaps = g_array_new(false, true, sizeof(AcpiIortIdMapping)); - GArray *its_idmaps = g_array_new(false, true, sizeof(AcpiIortIdMapping)); + GArray *rc_smmu_idmaps = g_array_new(false, true, sizeof(AcpiIortIdMapping)); + GArray *rc_its_idmaps = g_array_new(false, true, sizeof(AcpiIortIdMapping)); AcpiTable table = { .sig = "IORT", .rev = 3, .oem_id = vms->oem_id, .oem_table_id = vms->oem_table_id }; @@ -324,22 +324,38 @@ build_iort(GArray *table_data, BIOSLinker *linker, VirtMachineState *vms) if (vms->iommu == VIRT_IOMMU_SMMUV3) { object_child_foreach_recursive(object_get_root(), - iort_host_bridges, smmu_idmaps); + iort_host_bridges, rc_smmu_idmaps); /* Sort the smmu idmap by input_base */ - g_array_sort(smmu_idmaps, iort_idmap_compare); + g_array_sort(rc_smmu_idmaps, iort_idmap_compare); /* * Knowing the ID ranges from the RC to the SMMU, it's possible to * determine the ID ranges from RC that are directed to the ITS. */ - create_its_idmaps(its_idmaps, smmu_idmaps); + create_rc_its_idmaps(rc_its_idmaps, rc_smmu_idmaps); - nb_nodes = 3; /* RC, ITS, SMMUv3 */ - rc_mapping_count = smmu_idmaps->len + its_idmaps->len; + nb_nodes = 2; /* RC and SMMUv3 */ + rc_mapping_count = rc_smmu_idmaps->len; + + if (vms->its) { + /* + * Knowing the ID ranges from the RC to the SMMU, it's possible to + * determine the ID ranges from RC that go directly to ITS. + */ + create_rc_its_idmaps(rc_its_idmaps, rc_smmu_idmaps); + + nb_nodes++; /* ITS */ + rc_mapping_count += rc_its_idmaps->len; + } } else { - nb_nodes = 2; /* RC, ITS */ - rc_mapping_count = 1; + if (vms->its) { + nb_nodes = 2; /* RC and ITS */ + rc_mapping_count = 1; /* Direct map to ITS */ + } else { + nb_nodes = 1; /* RC only */ + rc_mapping_count = 0; /* No output mapping */ + } } /* Number of IORT Nodes */ build_append_int_noprefix(table_data, nb_nodes, 4); @@ -348,31 +364,43 @@ build_iort(GArray *table_data, BIOSLinker *linker, VirtMachineState *vms) build_append_int_noprefix(table_data, IORT_NODE_OFFSET, 4); build_append_int_noprefix(table_data, 0, 4); /* Reserved */ - /* Table 12 ITS Group Format */ - build_append_int_noprefix(table_data, 0 /* ITS Group */, 1); /* Type */ - node_size = 20 /* fixed header size */ + 4 /* 1 GIC ITS Identifier */; - build_append_int_noprefix(table_data, node_size, 2); /* Length */ - build_append_int_noprefix(table_data, 1, 1); /* Revision */ - build_append_int_noprefix(table_data, id++, 4); /* Identifier */ - build_append_int_noprefix(table_data, 0, 4); /* Number of ID mappings */ - build_append_int_noprefix(table_data, 0, 4); /* Reference to ID Array */ - build_append_int_noprefix(table_data, 1, 4); /* Number of ITSs */ - /* GIC ITS Identifier Array */ - build_append_int_noprefix(table_data, 0 /* MADT translation_id */, 4); + if (vms->its) { + /* Table 12 ITS Group Format */ + build_append_int_noprefix(table_data, 0 /* ITS Group */, 1); /* Type */ + node_size = 20 /* fixed header size */ + 4 /* 1 GIC ITS Identifier */; + build_append_int_noprefix(table_data, node_size, 2); /* Length */ + build_append_int_noprefix(table_data, 1, 1); /* Revision */ + build_append_int_noprefix(table_data, id++, 4); /* Identifier */ + build_append_int_noprefix(table_data, 0, 4); /* Number of ID mappings */ + build_append_int_noprefix(table_data, 0, 4); /* Reference to ID Array */ + build_append_int_noprefix(table_data, 1, 4); /* Number of ITSs */ + /* GIC ITS Identifier Array */ + build_append_int_noprefix(table_data, 0 /* MADT translation_id */, 4); + } if (vms->iommu == VIRT_IOMMU_SMMUV3) { int irq = vms->irqmap[VIRT_SMMU] + ARM_SPI_BASE; - + int smmu_mapping_count, offset_to_id_array; + + if (vms->its) { + smmu_mapping_count = 1; /* ITS Group node */ + offset_to_id_array = SMMU_V3_ENTRY_SIZE; /* Just after the header */ + } else { + smmu_mapping_count = 0; /* No ID mappings */ + offset_to_id_array = 0; /* No ID mappings array */ + } smmu_offset = table_data->len - table.table_offset; /* Table 9 SMMUv3 Format */ build_append_int_noprefix(table_data, 4 /* SMMUv3 */, 1); /* Type */ - node_size = SMMU_V3_ENTRY_SIZE + ID_MAPPING_ENTRY_SIZE; + node_size = SMMU_V3_ENTRY_SIZE + + (ID_MAPPING_ENTRY_SIZE * smmu_mapping_count); build_append_int_noprefix(table_data, node_size, 2); /* Length */ build_append_int_noprefix(table_data, 4, 1); /* Revision */ build_append_int_noprefix(table_data, id++, 4); /* Identifier */ - build_append_int_noprefix(table_data, 1, 4); /* Number of ID mappings */ + /* Number of ID mappings */ + build_append_int_noprefix(table_data, smmu_mapping_count, 4); /* Reference to ID Array */ - build_append_int_noprefix(table_data, SMMU_V3_ENTRY_SIZE, 4); + build_append_int_noprefix(table_data, offset_to_id_array, 4); /* Base address */ build_append_int_noprefix(table_data, vms->memmap[VIRT_SMMU].base, 8); /* Flags */ @@ -388,9 +416,11 @@ build_iort(GArray *table_data, BIOSLinker *linker, VirtMachineState *vms) build_append_int_noprefix(table_data, 0, 4); /* Proximity domain */ /* DeviceID mapping index (ignored since interrupts are GSIV based) */ build_append_int_noprefix(table_data, 0, 4); - - /* Output IORT node is the ITS Group node (the first node) */ - build_iort_id_mapping(table_data, 0, 0x10000, IORT_NODE_OFFSET); + /* Array of ID mappings */ + if (smmu_mapping_count) { + /* Output IORT node is the ITS Group node (the first node). */ + build_iort_id_mapping(table_data, 0, 0x10000, IORT_NODE_OFFSET); + } } /* Table 17 Root Complex Node */ @@ -431,24 +461,26 @@ build_iort(GArray *table_data, BIOSLinker *linker, VirtMachineState *vms) * * N.B.: The mapping from SMMUv3 to ITS Group node (SMMUv3 -> ITS) is * defined in the SMMUv3 table, where all SMMUv3 IDs are mapped to the - * ITS Group node. + * ITS Group node, if ITS is available. */ - for (i = 0; i < smmu_idmaps->len; i++) { - range = &g_array_index(smmu_idmaps, AcpiIortIdMapping, i); + for (i = 0; i < rc_smmu_idmaps->len; i++) { + range = &g_array_index(rc_smmu_idmaps, AcpiIortIdMapping, i); /* Output IORT node is the SMMUv3 node. */ build_iort_id_mapping(table_data, range->input_base, range->id_count, smmu_offset); } - /* - * Map bypassed (don't go throught the SMMU) RIDs (input) to ITS Group - * node directly: RC -> ITS. - */ - for (i = 0; i < its_idmaps->len; i++) { - range = &g_array_index(its_idmaps, AcpiIortIdMapping, i); - /* Output IORT node is the ITS Group node (the first node). */ - build_iort_id_mapping(table_data, range->input_base, - range->id_count, IORT_NODE_OFFSET); + if (vms->its) { + /* + * Map bypassed (don't go through the SMMU) RIDs (input) to + * ITS Group node directly: RC -> ITS. + */ + for (i = 0; i < rc_its_idmaps->len; i++) { + range = &g_array_index(rc_its_idmaps, AcpiIortIdMapping, i); + /* Output IORT node is the ITS Group node (the first node). */ + build_iort_id_mapping(table_data, range->input_base, + range->id_count, IORT_NODE_OFFSET); + } } } else { /* @@ -460,8 +492,8 @@ build_iort(GArray *table_data, BIOSLinker *linker, VirtMachineState *vms) } acpi_table_end(linker, &table); - g_array_free(smmu_idmaps, true); - g_array_free(its_idmaps, true); + g_array_free(rc_smmu_idmaps, true); + g_array_free(rc_its_idmaps, true); } /* @@ -769,18 +801,20 @@ build_madt(GArray *table_data, BIOSLinker *linker, VirtMachineState *vms) memmap[VIRT_HIGH_GIC_REDIST2].size); } - /* - * ACPI spec, Revision 6.0 Errata A - * (original 6.0 definition has invalid Length) - * 5.2.12.18 GIC ITS Structure - */ - build_append_int_noprefix(table_data, 0xF, 1); /* Type */ - build_append_int_noprefix(table_data, 20, 1); /* Length */ - build_append_int_noprefix(table_data, 0, 2); /* Reserved */ - build_append_int_noprefix(table_data, 0, 4); /* GIC ITS ID */ - /* Physical Base Address */ - build_append_int_noprefix(table_data, memmap[VIRT_GIC_ITS].base, 8); - build_append_int_noprefix(table_data, 0, 4); /* Reserved */ + if (vms->its) { + /* + * ACPI spec, Revision 6.0 Errata A + * (original 6.0 definition has invalid Length) + * 5.2.12.18 GIC ITS Structure + */ + build_append_int_noprefix(table_data, 0xF, 1); /* Type */ + build_append_int_noprefix(table_data, 20, 1); /* Length */ + build_append_int_noprefix(table_data, 0, 2); /* Reserved */ + build_append_int_noprefix(table_data, 0, 4); /* GIC ITS ID */ + /* Physical Base Address */ + build_append_int_noprefix(table_data, memmap[VIRT_GIC_ITS].base, 8); + build_append_int_noprefix(table_data, 0, 4); /* Reserved */ + } } else { const uint16_t spi_base = vms->irqmap[VIRT_GIC_V2M] + ARM_SPI_BASE; -- cgit v1.1 From 1370fd56ec771f16197f255c25c910e9386ac587 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Tue, 1 Jul 2025 15:08:34 +0100 Subject: hw/arm/virt: Make EL3-guest accel check an accept-list MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Currently only the TCG and qtest accelerators can handle an EL3 guest. Instead of making the condition check be "fail if KVM or HVF" (an exclude-list), make it a be "allow if TCG or qtest" (an accept-list). This is better for if/when we add new accelerators, as it makes the default be that we forbid an EL3 guest. This is the most likely to be correct and also "fails safe"; if the new accelerator really can support EL3 guests then the implementor will see that they need to add it to the accept-list. Reported-by: Alex Bennée Signed-off-by: Philippe Mathieu-Daudé Reviewed-by: Richard Henderson Message-id: 20250623121845.7214-19-philmd@linaro.org [PMM: rewrote commit message] Signed-off-by: Peter Maydell --- hw/arm/virt.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'hw') diff --git a/hw/arm/virt.c b/hw/arm/virt.c index ae419e8..b3b1c6d 100644 --- a/hw/arm/virt.c +++ b/hw/arm/virt.c @@ -2200,7 +2200,7 @@ static void machvirt_init(MachineState *machine) exit(1); } - if (vms->secure && (kvm_enabled() || hvf_enabled())) { + if (vms->secure && !tcg_enabled() && !qtest_enabled()) { error_report("mach-virt: %s does not support providing " "Security extensions (TrustZone) to the guest CPU", current_accel_name()); -- cgit v1.1 From 164258da4a24464a502b6ece6fce9fc6ca1c0207 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Tue, 1 Jul 2025 15:08:34 +0100 Subject: hw/arm/virt: Make EL2 accelerator check an accept-list MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Currently only the TCG and qtest accelerators can handle an EL2 guest. Instead of making the condition check be "fail if KVM or HVF" (an exclude-list), make it a be "allow if TCG or qtest" (an accept-list). This is better for if/when we add new accelerators, as it makes the default be that we forbid an EL2 guest. This is the most likely to be correct and also "fails safe"; if the new accelerator really can support EL2 guests then the implementor will see that they need to add it to the accept-list. Signed-off-by: Philippe Mathieu-Daudé Reviewed-by: Richard Henderson Reviewed-by: Alex Bennée Message-id: 20250623121845.7214-20-philmd@linaro.org [PMM: rewrote commit message] Signed-off-by: Peter Maydell --- hw/arm/virt.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'hw') diff --git a/hw/arm/virt.c b/hw/arm/virt.c index b3b1c6d..30f91bc 100644 --- a/hw/arm/virt.c +++ b/hw/arm/virt.c @@ -2207,7 +2207,7 @@ static void machvirt_init(MachineState *machine) exit(1); } - if (vms->virt && (kvm_enabled() || hvf_enabled())) { + if (vms->virt && !tcg_enabled() && !qtest_enabled()) { error_report("mach-virt: %s does not support providing " "Virtualization extensions to the guest CPU", current_accel_name()); -- cgit v1.1 From c6a613094e48fc83ee5c65464dccd90fae637516 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Tue, 1 Jul 2025 15:08:35 +0100 Subject: hw/arm/virt: Rename cpu_post_init() -> post_cpus_gic_realized() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit QDev uses _post_init() during instance creation, before being realized. Since here both vCPUs and GIC are REALIZED, rename as virt_post_cpus_gic_realized() for clarity. Signed-off-by: Philippe Mathieu-Daudé Reviewed-by: Richard Henderson Message-id: 20250623121845.7214-21-philmd@linaro.org [PMM: also fixed up comment] Signed-off-by: Peter Maydell --- hw/arm/virt.c | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) (limited to 'hw') diff --git a/hw/arm/virt.c b/hw/arm/virt.c index 30f91bc..3bcdf92 100644 --- a/hw/arm/virt.c +++ b/hw/arm/virt.c @@ -2026,10 +2026,11 @@ static void finalize_gic_version(VirtMachineState *vms) } /* - * virt_cpu_post_init() must be called after the CPUs have - * been realized and the GIC has been created. + * virt_post_cpus_gic_realized() must be called after the CPUs and + * the GIC have both been realized. */ -static void virt_cpu_post_init(VirtMachineState *vms, MemoryRegion *sysmem) +static void virt_post_cpus_gic_realized(VirtMachineState *vms, + MemoryRegion *sysmem) { int max_cpus = MACHINE(vms)->smp.max_cpus; bool aarch64, pmu, steal_time; @@ -2346,7 +2347,7 @@ static void machvirt_init(MachineState *machine) create_gic(vms, sysmem); - virt_cpu_post_init(vms, sysmem); + virt_post_cpus_gic_realized(vms, sysmem); fdt_add_pmu_nodes(vms); -- cgit v1.1 From 4e24ea43a126822d0c3d28d57b500ac9bbce5735 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Tue, 1 Jul 2025 15:08:35 +0100 Subject: hw/arm/sbsa-ref: Tidy up use of RAMLIMIT_GB definition MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Define RAMLIMIT_BYTES using the TiB definition and display the error parsed with size_to_str(): $ qemu-system-aarch64-unsigned -M sbsa-ref -m 9T qemu-system-aarch64-unsigned: sbsa-ref: cannot model more than 8 TiB of RAM Signed-off-by: Philippe Mathieu-Daudé Reviewed-by: Richard Henderson Message-id: 20250623121845.7214-22-philmd@linaro.org Signed-off-by: Peter Maydell --- hw/arm/sbsa-ref.c | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) (limited to 'hw') diff --git a/hw/arm/sbsa-ref.c b/hw/arm/sbsa-ref.c index deae5cf..15c1ff4 100644 --- a/hw/arm/sbsa-ref.c +++ b/hw/arm/sbsa-ref.c @@ -19,6 +19,7 @@ */ #include "qemu/osdep.h" +#include "qemu/cutils.h" #include "qemu/datadir.h" #include "qapi/error.h" #include "qemu/error-report.h" @@ -53,8 +54,7 @@ #include "target/arm/cpu-qom.h" #include "target/arm/gtimer.h" -#define RAMLIMIT_GB 8192 -#define RAMLIMIT_BYTES (RAMLIMIT_GB * GiB) +#define RAMLIMIT_BYTES (8 * TiB) #define NUM_IRQS 256 #define NUM_SMMU_IRQS 4 @@ -756,7 +756,9 @@ static void sbsa_ref_init(MachineState *machine) sms->smp_cpus = smp_cpus; if (machine->ram_size > sbsa_ref_memmap[SBSA_MEM].size) { - error_report("sbsa-ref: cannot model more than %dGB RAM", RAMLIMIT_GB); + char *size_str = size_to_str(RAMLIMIT_BYTES); + + error_report("sbsa-ref: cannot model more than %s of RAM", size_str); exit(1); } -- cgit v1.1