From 4af6b6edece5ef273d29972d53547f823d2bc1c0 Mon Sep 17 00:00:00 2001 From: Gavin Shan Date: Wed, 14 Dec 2022 14:27:04 +0000 Subject: [PATCH 01/28] hw/arm/virt: Introduce virt_set_high_memmap() helper This introduces virt_set_high_memmap() helper. The logic of high memory region address assignment is moved to the helper. The intention is to make the subsequent optimization for high memory region address assignment easier. No functional change intended. Signed-off-by: Gavin Shan Reviewed-by: Eric Auger Reviewed-by: Cornelia Huck Reviewed-by: Marc Zyngier Tested-by: Zhenyu Zhang Message-id: 20221029224307.138822-2-gshan@redhat.com Signed-off-by: Peter Maydell --- hw/arm/virt.c | 74 ++++++++++++++++++++++++++++----------------------- 1 file changed, 41 insertions(+), 33 deletions(-) diff --git a/hw/arm/virt.c b/hw/arm/virt.c index b871350856..ca30028193 100644 --- a/hw/arm/virt.c +++ b/hw/arm/virt.c @@ -1690,6 +1690,46 @@ static uint64_t virt_cpu_mp_affinity(VirtMachineState *vms, int idx) return arm_cpu_mp_affinity(idx, clustersz); } +static void virt_set_high_memmap(VirtMachineState *vms, + hwaddr base, int pa_bits) +{ + int i; + + for (i = VIRT_LOWMEMMAP_LAST; i < ARRAY_SIZE(extended_memmap); i++) { + hwaddr size = extended_memmap[i].size; + bool fits; + + base = ROUND_UP(base, size); + vms->memmap[i].base = base; + vms->memmap[i].size = size; + + /* + * Check each device to see if they fit in the PA space, + * moving highest_gpa as we go. + * + * For each device that doesn't fit, disable it. + */ + fits = (base + size) <= BIT_ULL(pa_bits); + if (fits) { + vms->highest_gpa = base + size - 1; + } + + switch (i) { + case VIRT_HIGH_GIC_REDIST2: + vms->highmem_redists &= fits; + break; + case VIRT_HIGH_PCIE_ECAM: + vms->highmem_ecam &= fits; + break; + case VIRT_HIGH_PCIE_MMIO: + vms->highmem_mmio &= fits; + break; + } + + base += size; + } +} + static void virt_set_memmap(VirtMachineState *vms, int pa_bits) { MachineState *ms = MACHINE(vms); @@ -1745,39 +1785,7 @@ static void virt_set_memmap(VirtMachineState *vms, int pa_bits) /* We know for sure that at least the memory fits in the PA space */ vms->highest_gpa = memtop - 1; - for (i = VIRT_LOWMEMMAP_LAST; i < ARRAY_SIZE(extended_memmap); i++) { - hwaddr size = extended_memmap[i].size; - bool fits; - - base = ROUND_UP(base, size); - vms->memmap[i].base = base; - vms->memmap[i].size = size; - - /* - * Check each device to see if they fit in the PA space, - * moving highest_gpa as we go. - * - * For each device that doesn't fit, disable it. - */ - fits = (base + size) <= BIT_ULL(pa_bits); - if (fits) { - vms->highest_gpa = base + size - 1; - } - - switch (i) { - case VIRT_HIGH_GIC_REDIST2: - vms->highmem_redists &= fits; - break; - case VIRT_HIGH_PCIE_ECAM: - vms->highmem_ecam &= fits; - break; - case VIRT_HIGH_PCIE_MMIO: - vms->highmem_mmio &= fits; - break; - } - - base += size; - } + virt_set_high_memmap(vms, base, pa_bits); if (device_memory_size > 0) { ms->device_memory = g_malloc0(sizeof(*ms->device_memory)); From 370bea9d1c78796eec235ed6cb4310f489931a62 Mon Sep 17 00:00:00 2001 From: Gavin Shan Date: Wed, 14 Dec 2022 14:27:05 +0000 Subject: [PATCH 02/28] hw/arm/virt: Rename variable size to region_size in virt_set_high_memmap() This renames variable 'size' to 'region_size' in virt_set_high_memmap(). Its counterpart ('region_base') will be introduced in next patch. No functional change intended. Signed-off-by: Gavin Shan Reviewed-by: Eric Auger Reviewed-by: Cornelia Huck Reviewed-by: Marc Zyngier Tested-by: Zhenyu Zhang Message-id: 20221029224307.138822-3-gshan@redhat.com Signed-off-by: Peter Maydell --- hw/arm/virt.c | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/hw/arm/virt.c b/hw/arm/virt.c index ca30028193..2659f4db15 100644 --- a/hw/arm/virt.c +++ b/hw/arm/virt.c @@ -1693,15 +1693,16 @@ static uint64_t virt_cpu_mp_affinity(VirtMachineState *vms, int idx) static void virt_set_high_memmap(VirtMachineState *vms, hwaddr base, int pa_bits) { + hwaddr region_size; + bool fits; int i; for (i = VIRT_LOWMEMMAP_LAST; i < ARRAY_SIZE(extended_memmap); i++) { - hwaddr size = extended_memmap[i].size; - bool fits; + region_size = extended_memmap[i].size; - base = ROUND_UP(base, size); + base = ROUND_UP(base, region_size); vms->memmap[i].base = base; - vms->memmap[i].size = size; + vms->memmap[i].size = region_size; /* * Check each device to see if they fit in the PA space, @@ -1709,9 +1710,9 @@ static void virt_set_high_memmap(VirtMachineState *vms, * * For each device that doesn't fit, disable it. */ - fits = (base + size) <= BIT_ULL(pa_bits); + fits = (base + region_size) <= BIT_ULL(pa_bits); if (fits) { - vms->highest_gpa = base + size - 1; + vms->highest_gpa = base + region_size - 1; } switch (i) { @@ -1726,7 +1727,7 @@ static void virt_set_high_memmap(VirtMachineState *vms, break; } - base += size; + base += region_size; } } From fa245799b9407fc7b561da185b3d889df5e16a88 Mon Sep 17 00:00:00 2001 From: Gavin Shan Date: Wed, 14 Dec 2022 14:27:05 +0000 Subject: [PATCH 03/28] hw/arm/virt: Introduce variable region_base in virt_set_high_memmap() This introduces variable 'region_base' for the base address of the specific high memory region. It's the preparatory work to optimize high memory region address assignment. No functional change intended. Signed-off-by: Gavin Shan Reviewed-by: Eric Auger Reviewed-by: Cornelia Huck Reviewed-by: Marc Zyngier Tested-by: Zhenyu Zhang Message-id: 20221029224307.138822-4-gshan@redhat.com Signed-off-by: Peter Maydell --- hw/arm/virt.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/hw/arm/virt.c b/hw/arm/virt.c index 2659f4db15..3bb1bf079f 100644 --- a/hw/arm/virt.c +++ b/hw/arm/virt.c @@ -1693,15 +1693,15 @@ static uint64_t virt_cpu_mp_affinity(VirtMachineState *vms, int idx) static void virt_set_high_memmap(VirtMachineState *vms, hwaddr base, int pa_bits) { - hwaddr region_size; + hwaddr region_base, region_size; bool fits; int i; for (i = VIRT_LOWMEMMAP_LAST; i < ARRAY_SIZE(extended_memmap); i++) { + region_base = ROUND_UP(base, extended_memmap[i].size); region_size = extended_memmap[i].size; - base = ROUND_UP(base, region_size); - vms->memmap[i].base = base; + vms->memmap[i].base = region_base; vms->memmap[i].size = region_size; /* @@ -1710,9 +1710,9 @@ static void virt_set_high_memmap(VirtMachineState *vms, * * For each device that doesn't fit, disable it. */ - fits = (base + region_size) <= BIT_ULL(pa_bits); + fits = (region_base + region_size) <= BIT_ULL(pa_bits); if (fits) { - vms->highest_gpa = base + region_size - 1; + vms->highest_gpa = region_base + region_size - 1; } switch (i) { @@ -1727,7 +1727,7 @@ static void virt_set_high_memmap(VirtMachineState *vms, break; } - base += region_size; + base = region_base + region_size; } } From a5cb1350b19a5c2a58ab4edddf609ed429c13085 Mon Sep 17 00:00:00 2001 From: Gavin Shan Date: Wed, 14 Dec 2022 14:27:05 +0000 Subject: [PATCH 04/28] hw/arm/virt: Introduce virt_get_high_memmap_enabled() helper This introduces virt_get_high_memmap_enabled() helper, which returns the pointer to vms->highmem_{redists, ecam, mmio}. The pointer will be used in the subsequent patches. No functional change intended. Signed-off-by: Gavin Shan Reviewed-by: Eric Auger Reviewed-by: Cornelia Huck Reviewed-by: Marc Zyngier Tested-by: Zhenyu Zhang Message-id: 20221029224307.138822-5-gshan@redhat.com Signed-off-by: Peter Maydell --- hw/arm/virt.c | 32 +++++++++++++++++++------------- 1 file changed, 19 insertions(+), 13 deletions(-) diff --git a/hw/arm/virt.c b/hw/arm/virt.c index 3bb1bf079f..7689337470 100644 --- a/hw/arm/virt.c +++ b/hw/arm/virt.c @@ -1690,14 +1690,31 @@ static uint64_t virt_cpu_mp_affinity(VirtMachineState *vms, int idx) return arm_cpu_mp_affinity(idx, clustersz); } +static inline bool *virt_get_high_memmap_enabled(VirtMachineState *vms, + int index) +{ + bool *enabled_array[] = { + &vms->highmem_redists, + &vms->highmem_ecam, + &vms->highmem_mmio, + }; + + assert(ARRAY_SIZE(extended_memmap) - VIRT_LOWMEMMAP_LAST == + ARRAY_SIZE(enabled_array)); + assert(index - VIRT_LOWMEMMAP_LAST < ARRAY_SIZE(enabled_array)); + + return enabled_array[index - VIRT_LOWMEMMAP_LAST]; +} + static void virt_set_high_memmap(VirtMachineState *vms, hwaddr base, int pa_bits) { hwaddr region_base, region_size; - bool fits; + bool *region_enabled, fits; int i; for (i = VIRT_LOWMEMMAP_LAST; i < ARRAY_SIZE(extended_memmap); i++) { + region_enabled = virt_get_high_memmap_enabled(vms, i); region_base = ROUND_UP(base, extended_memmap[i].size); region_size = extended_memmap[i].size; @@ -1715,18 +1732,7 @@ static void virt_set_high_memmap(VirtMachineState *vms, vms->highest_gpa = region_base + region_size - 1; } - switch (i) { - case VIRT_HIGH_GIC_REDIST2: - vms->highmem_redists &= fits; - break; - case VIRT_HIGH_PCIE_ECAM: - vms->highmem_ecam &= fits; - break; - case VIRT_HIGH_PCIE_MMIO: - vms->highmem_mmio &= fits; - break; - } - + *region_enabled &= fits; base = region_base + region_size; } } From 4a4ff9edc6a8fdc76082af5b41b059217138c09b Mon Sep 17 00:00:00 2001 From: Gavin Shan Date: Wed, 14 Dec 2022 14:27:06 +0000 Subject: [PATCH 05/28] hw/arm/virt: Improve high memory region address assignment There are three high memory regions, which are VIRT_HIGH_REDIST2, VIRT_HIGH_PCIE_ECAM and VIRT_HIGH_PCIE_MMIO. Their base addresses are floating on highest RAM address. However, they can be disabled in several cases. (1) One specific high memory region is likely to be disabled by code by toggling vms->highmem_{redists, ecam, mmio}. (2) VIRT_HIGH_PCIE_ECAM region is disabled on machine, which is 'virt-2.12' or ealier than it. (3) VIRT_HIGH_PCIE_ECAM region is disabled when firmware is loaded on 32-bits system. (4) One specific high memory region is disabled when it breaks the PA space limit. The current implementation of virt_set_{memmap, high_memmap}() isn't optimized because the high memory region's PA space is always reserved, regardless of whatever the actual state in the corresponding vms->highmem_{redists, ecam, mmio} flag. In the code, 'base' and 'vms->highest_gpa' are always increased for case (1), (2) and (3). It's unnecessary since the assigned PA space for the disabled high memory region won't be used afterwards. Improve the address assignment for those three high memory region by skipping the address assignment for one specific high memory region if it has been disabled in case (1), (2) and (3). The memory layout may be changed after the improvement is applied, which leads to potential migration breakage. So 'vms->highmem_compact' is added to control if the improvement should be applied. For now, 'vms->highmem_compact' is set to false, meaning that we don't have memory layout change until it becomes configurable through property 'compact-highmem' in next patch. Signed-off-by: Gavin Shan Reviewed-by: Eric Auger Reviewed-by: Cornelia Huck Reviewed-by: Marc Zyngier Tested-by: Zhenyu Zhang Message-id: 20221029224307.138822-6-gshan@redhat.com Signed-off-by: Peter Maydell --- hw/arm/virt.c | 15 ++++++++++----- include/hw/arm/virt.h | 1 + 2 files changed, 11 insertions(+), 5 deletions(-) diff --git a/hw/arm/virt.c b/hw/arm/virt.c index 7689337470..807175707e 100644 --- a/hw/arm/virt.c +++ b/hw/arm/virt.c @@ -1722,18 +1722,23 @@ static void virt_set_high_memmap(VirtMachineState *vms, vms->memmap[i].size = region_size; /* - * Check each device to see if they fit in the PA space, - * moving highest_gpa as we go. + * Check each device to see if it fits in the PA space, + * moving highest_gpa as we go. For compatibility, move + * highest_gpa for disabled fitting devices as well, if + * the compact layout has been disabled. * * For each device that doesn't fit, disable it. */ fits = (region_base + region_size) <= BIT_ULL(pa_bits); - if (fits) { - vms->highest_gpa = region_base + region_size - 1; + *region_enabled &= fits; + if (vms->highmem_compact && !*region_enabled) { + continue; } - *region_enabled &= fits; base = region_base + region_size; + if (fits) { + vms->highest_gpa = base - 1; + } } } diff --git a/include/hw/arm/virt.h b/include/hw/arm/virt.h index 6ec479ca2b..709f623741 100644 --- a/include/hw/arm/virt.h +++ b/include/hw/arm/virt.h @@ -144,6 +144,7 @@ struct VirtMachineState { PFlashCFI01 *flash[2]; bool secure; bool highmem; + bool highmem_compact; bool highmem_ecam; bool highmem_mmio; bool highmem_redists; From f40408a9fe5d1db70a75a33d2b26c8af8a5d57b0 Mon Sep 17 00:00:00 2001 From: Gavin Shan Date: Wed, 14 Dec 2022 14:27:06 +0000 Subject: [PATCH 06/28] hw/arm/virt: Add 'compact-highmem' property After the improvement to high memory region address assignment is applied, the memory layout can be changed, introducing possible migration breakage. For example, VIRT_HIGH_PCIE_MMIO memory region is disabled or enabled when the optimization is applied or not, with the following configuration. The configuration is only achievable by modifying the source code until more properties are added to allow users selectively disable those high memory regions. pa_bits = 40; vms->highmem_redists = false; vms->highmem_ecam = false; vms->highmem_mmio = true; # qemu-system-aarch64 -accel kvm -cpu host \ -machine virt-7.2,compact-highmem={on, off} \ -m 4G,maxmem=511G -monitor stdio Region compact-highmem=off compact-highmem=on ---------------------------------------------------------------- MEM [1GB 512GB] [1GB 512GB] HIGH_GIC_REDISTS2 [512GB 512GB+64MB] [disabled] HIGH_PCIE_ECAM [512GB+256MB 512GB+512MB] [disabled] HIGH_PCIE_MMIO [disabled] [512GB 1TB] In order to keep backwords compatibility, we need to disable the optimization on machine, which is virt-7.1 or ealier than it. It means the optimization is enabled by default from virt-7.2. Besides, 'compact-highmem' property is added so that the optimization can be explicitly enabled or disabled on all machine types by users. Signed-off-by: Gavin Shan Reviewed-by: Eric Auger Reviewed-by: Cornelia Huck Reviewed-by: Marc Zyngier Tested-by: Zhenyu Zhang Message-id: 20221029224307.138822-7-gshan@redhat.com Signed-off-by: Peter Maydell --- docs/system/arm/virt.rst | 4 ++++ hw/arm/virt.c | 32 ++++++++++++++++++++++++++++++++ include/hw/arm/virt.h | 1 + 3 files changed, 37 insertions(+) diff --git a/docs/system/arm/virt.rst b/docs/system/arm/virt.rst index 20442ea2c1..4454706392 100644 --- a/docs/system/arm/virt.rst +++ b/docs/system/arm/virt.rst @@ -94,6 +94,10 @@ highmem address space above 32 bits. The default is ``on`` for machine types later than ``virt-2.12``. +compact-highmem + Set ``on``/``off`` to enable/disable the compact layout for high memory regions. + The default is ``on`` for machine types later than ``virt-7.2``. + gic-version Specify the version of the Generic Interrupt Controller (GIC) to provide. Valid values are: diff --git a/hw/arm/virt.c b/hw/arm/virt.c index 807175707e..3d1371c05c 100644 --- a/hw/arm/virt.c +++ b/hw/arm/virt.c @@ -174,6 +174,12 @@ static const MemMapEntry base_memmap[] = { * Note the extended_memmap is sized so that it eventually also includes the * base_memmap entries (VIRT_HIGH_GIC_REDIST2 index is greater than the last * index of base_memmap). + * + * The memory map for these Highmem IO Regions can be in legacy or compact + * layout, depending on 'compact-highmem' property. With legacy layout, the + * PA space for one specific region is always reserved, even if the region + * has been disabled or doesn't fit into the PA space. However, the PA space + * for the region won't be reserved in these circumstances with compact layout. */ static MemMapEntry extended_memmap[] = { /* Additional 64 MB redist region (can contain up to 512 redistributors) */ @@ -2352,6 +2358,20 @@ static void virt_set_highmem(Object *obj, bool value, Error **errp) vms->highmem = value; } +static bool virt_get_compact_highmem(Object *obj, Error **errp) +{ + VirtMachineState *vms = VIRT_MACHINE(obj); + + return vms->highmem_compact; +} + +static void virt_set_compact_highmem(Object *obj, bool value, Error **errp) +{ + VirtMachineState *vms = VIRT_MACHINE(obj); + + vms->highmem_compact = value; +} + static bool virt_get_its(Object *obj, Error **errp) { VirtMachineState *vms = VIRT_MACHINE(obj); @@ -2970,6 +2990,13 @@ static void virt_machine_class_init(ObjectClass *oc, void *data) "Set on/off to enable/disable using " "physical address space above 32 bits"); + object_class_property_add_bool(oc, "compact-highmem", + virt_get_compact_highmem, + virt_set_compact_highmem); + object_class_property_set_description(oc, "compact-highmem", + "Set on/off to enable/disable compact " + "layout for high memory regions"); + object_class_property_add_str(oc, "gic-version", virt_get_gic_version, virt_set_gic_version); object_class_property_set_description(oc, "gic-version", @@ -3054,6 +3081,7 @@ static void virt_instance_init(Object *obj) /* High memory is enabled by default */ vms->highmem = true; + vms->highmem_compact = !vmc->no_highmem_compact; vms->gic_version = VIRT_GIC_VERSION_NOSEL; vms->highmem_ecam = !vmc->no_highmem_ecam; @@ -3123,8 +3151,12 @@ DEFINE_VIRT_MACHINE_AS_LATEST(7, 2) static void virt_machine_7_1_options(MachineClass *mc) { + VirtMachineClass *vmc = VIRT_MACHINE_CLASS(OBJECT_CLASS(mc)); + virt_machine_7_2_options(mc); compat_props_add(mc->compat_props, hw_compat_7_1, hw_compat_7_1_len); + /* Compact layout for high memory regions was introduced with 7.2 */ + vmc->no_highmem_compact = true; } DEFINE_VIRT_MACHINE(7, 1) diff --git a/include/hw/arm/virt.h b/include/hw/arm/virt.h index 709f623741..c7dd59d7f1 100644 --- a/include/hw/arm/virt.h +++ b/include/hw/arm/virt.h @@ -125,6 +125,7 @@ struct VirtMachineClass { bool no_pmu; bool claim_edge_triggered_timers; bool smbios_old_sys_ver; + bool no_highmem_compact; bool no_highmem_ecam; bool no_ged; /* Machines < 4.2 have no support for ACPI GED device */ bool kvm_no_adjvtime; From 6a48c64eec355ab1aff694eb4522d07a8e461368 Mon Sep 17 00:00:00 2001 From: Gavin Shan Date: Wed, 14 Dec 2022 14:27:06 +0000 Subject: [PATCH 07/28] hw/arm/virt: Add properties to disable high memory regions The 3 high memory regions are usually enabled by default, but they may be not used. For example, VIRT_HIGH_GIC_REDIST2 isn't needed by GICv2. This leads to waste in the PA space. Add properties ("highmem-redists", "highmem-ecam", "highmem-mmio") to allow users selectively disable them if needed. After that, the high memory region for GICv3 or GICv4 redistributor can be disabled by user, the number of maximal supported CPUs needs to be calculated based on 'vms->highmem_redists'. The follow-up error message is also improved to indicate if the high memory region for GICv3 and GICv4 has been enabled or not. Suggested-by: Marc Zyngier Signed-off-by: Gavin Shan Reviewed-by: Marc Zyngier Reviewed-by: Cornelia Huck Reviewed-by: Eric Auger Message-id: 20221029224307.138822-8-gshan@redhat.com Signed-off-by: Peter Maydell --- docs/system/arm/virt.rst | 13 +++++++ hw/arm/virt.c | 75 ++++++++++++++++++++++++++++++++++++++-- 2 files changed, 86 insertions(+), 2 deletions(-) diff --git a/docs/system/arm/virt.rst b/docs/system/arm/virt.rst index 4454706392..188a4f211f 100644 --- a/docs/system/arm/virt.rst +++ b/docs/system/arm/virt.rst @@ -98,6 +98,19 @@ compact-highmem Set ``on``/``off`` to enable/disable the compact layout for high memory regions. The default is ``on`` for machine types later than ``virt-7.2``. +highmem-redists + Set ``on``/``off`` to enable/disable the high memory region for GICv3 or + GICv4 redistributor. The default is ``on``. Setting this to ``off`` will + limit the maximum number of CPUs when GICv3 or GICv4 is used. + +highmem-ecam + Set ``on``/``off`` to enable/disable the high memory region for PCI ECAM. + The default is ``on`` for machine types later than ``virt-3.0``. + +highmem-mmio + Set ``on``/``off`` to enable/disable the high memory region for PCI MMIO. + The default is ``on``. + gic-version Specify the version of the Generic Interrupt Controller (GIC) to provide. Valid values are: diff --git a/hw/arm/virt.c b/hw/arm/virt.c index 3d1371c05c..0acb71be96 100644 --- a/hw/arm/virt.c +++ b/hw/arm/virt.c @@ -2096,14 +2096,20 @@ static void machvirt_init(MachineState *machine) if (vms->gic_version == VIRT_GIC_VERSION_2) { virt_max_cpus = GIC_NCPU; } else { - virt_max_cpus = virt_redist_capacity(vms, VIRT_GIC_REDIST) + - virt_redist_capacity(vms, VIRT_HIGH_GIC_REDIST2); + virt_max_cpus = virt_redist_capacity(vms, VIRT_GIC_REDIST); + if (vms->highmem_redists) { + virt_max_cpus += virt_redist_capacity(vms, VIRT_HIGH_GIC_REDIST2); + } } if (max_cpus > virt_max_cpus) { error_report("Number of SMP CPUs requested (%d) exceeds max CPUs " "supported by machine 'mach-virt' (%d)", max_cpus, virt_max_cpus); + if (vms->gic_version != VIRT_GIC_VERSION_2 && !vms->highmem_redists) { + error_printf("Try 'highmem-redists=on' for more CPUs\n"); + } + exit(1); } @@ -2372,6 +2378,49 @@ static void virt_set_compact_highmem(Object *obj, bool value, Error **errp) vms->highmem_compact = value; } +static bool virt_get_highmem_redists(Object *obj, Error **errp) +{ + VirtMachineState *vms = VIRT_MACHINE(obj); + + return vms->highmem_redists; +} + +static void virt_set_highmem_redists(Object *obj, bool value, Error **errp) +{ + VirtMachineState *vms = VIRT_MACHINE(obj); + + vms->highmem_redists = value; +} + +static bool virt_get_highmem_ecam(Object *obj, Error **errp) +{ + VirtMachineState *vms = VIRT_MACHINE(obj); + + return vms->highmem_ecam; +} + +static void virt_set_highmem_ecam(Object *obj, bool value, Error **errp) +{ + VirtMachineState *vms = VIRT_MACHINE(obj); + + vms->highmem_ecam = value; +} + +static bool virt_get_highmem_mmio(Object *obj, Error **errp) +{ + VirtMachineState *vms = VIRT_MACHINE(obj); + + return vms->highmem_mmio; +} + +static void virt_set_highmem_mmio(Object *obj, bool value, Error **errp) +{ + VirtMachineState *vms = VIRT_MACHINE(obj); + + vms->highmem_mmio = value; +} + + static bool virt_get_its(Object *obj, Error **errp) { VirtMachineState *vms = VIRT_MACHINE(obj); @@ -2997,6 +3046,28 @@ static void virt_machine_class_init(ObjectClass *oc, void *data) "Set on/off to enable/disable compact " "layout for high memory regions"); + object_class_property_add_bool(oc, "highmem-redists", + virt_get_highmem_redists, + virt_set_highmem_redists); + object_class_property_set_description(oc, "highmem-redists", + "Set on/off to enable/disable high " + "memory region for GICv3 or GICv4 " + "redistributor"); + + object_class_property_add_bool(oc, "highmem-ecam", + virt_get_highmem_ecam, + virt_set_highmem_ecam); + object_class_property_set_description(oc, "highmem-ecam", + "Set on/off to enable/disable high " + "memory region for PCI ECAM"); + + object_class_property_add_bool(oc, "highmem-mmio", + virt_get_highmem_mmio, + virt_set_highmem_mmio); + object_class_property_set_description(oc, "highmem-mmio", + "Set on/off to enable/disable high " + "memory region for PCI MMIO"); + object_class_property_add_str(oc, "gic-version", virt_get_gic_version, virt_set_gic_version); object_class_property_set_description(oc, "gic-version", From 0a0044b181dbf0cd9920910559a891dc56e4faed Mon Sep 17 00:00:00 2001 From: Mihai Carabas Date: Wed, 14 Dec 2022 14:27:07 +0000 Subject: [PATCH 08/28] hw/arm/virt: build SMBIOS 19 table Use the base_memmap to build the SMBIOS 19 table which provides the address mapping for a Physical Memory Array (from spec [1] chapter 7.20). This was present on i386 from commit c97294ec1b9e36887e119589d456557d72ab37b5 ("SMBIOS: Build aggregate smbios tables and entry point"). [1] https://www.dmtf.org/sites/default/files/standards/documents/DSP0134_3.5.0.pdf The absence of this table is a breach of the specs and is detected by the FirmwareTestSuite (FWTS), but it doesn't cause any known problems for guest OSes. Signed-off-by: Mihai Carabas Message-id: 1668789029-5432-1-git-send-email-mihai.carabas@oracle.com Reviewed-by: Peter Maydell Signed-off-by: Peter Maydell --- hw/arm/virt.c | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/hw/arm/virt.c b/hw/arm/virt.c index 0acb71be96..bf59784aef 100644 --- a/hw/arm/virt.c +++ b/hw/arm/virt.c @@ -1614,9 +1614,11 @@ static void *machvirt_dtb(const struct arm_boot_info *binfo, int *fdt_size) static void virt_build_smbios(VirtMachineState *vms) { MachineClass *mc = MACHINE_GET_CLASS(vms); + MachineState *ms = MACHINE(vms); VirtMachineClass *vmc = VIRT_MACHINE_GET_CLASS(vms); uint8_t *smbios_tables, *smbios_anchor; size_t smbios_tables_len, smbios_anchor_len; + struct smbios_phys_mem_area mem_array; const char *product = "QEMU Virtual Machine"; if (kvm_enabled()) { @@ -1627,7 +1629,11 @@ static void virt_build_smbios(VirtMachineState *vms) vmc->smbios_old_sys_ver ? "1.0" : mc->name, false, true, SMBIOS_ENTRY_POINT_TYPE_64); - smbios_get_tables(MACHINE(vms), NULL, 0, + /* build the array of physical mem area from base_memmap */ + mem_array.address = vms->memmap[VIRT_MEM].base; + mem_array.length = ms->ram_size; + + smbios_get_tables(ms, &mem_array, 1, &smbios_tables, &smbios_tables_len, &smbios_anchor, &smbios_anchor_len, &error_fatal); From 94bc3b067ea2a57771a4621394c1ca362b605d81 Mon Sep 17 00:00:00 2001 From: Timofey Kutergin Date: Wed, 14 Dec 2022 14:27:07 +0000 Subject: [PATCH 09/28] target/arm: Add Cortex-A55 CPU The Cortex-A55 is one of the newer armv8.2+ CPUs; in particular it supports the Privileged Access Never (PAN) feature. Add a model of this CPU, so you can use a CPU type on the virt board that models a specific real hardware CPU, rather than having to use the QEMU-specific "max" CPU type. Signed-off-by: Timofey Kutergin Message-id: 20221121150819.2782817-1-tkutergin@gmail.com [PMM: tweaked commit message] Reviewed-by: Peter Maydell Signed-off-by: Peter Maydell --- docs/system/arm/virt.rst | 1 + hw/arm/virt.c | 1 + target/arm/cpu64.c | 69 ++++++++++++++++++++++++++++++++++++++++ 3 files changed, 71 insertions(+) diff --git a/docs/system/arm/virt.rst b/docs/system/arm/virt.rst index 188a4f211f..1cab33f02e 100644 --- a/docs/system/arm/virt.rst +++ b/docs/system/arm/virt.rst @@ -54,6 +54,7 @@ Supported guest CPU types: - ``cortex-a15`` (32-bit; the default) - ``cortex-a35`` (64-bit) - ``cortex-a53`` (64-bit) +- ``cortex-a55`` (64-bit) - ``cortex-a57`` (64-bit) - ``cortex-a72`` (64-bit) - ``cortex-a76`` (64-bit) diff --git a/hw/arm/virt.c b/hw/arm/virt.c index bf59784aef..a2dd48dfb8 100644 --- a/hw/arm/virt.c +++ b/hw/arm/virt.c @@ -207,6 +207,7 @@ static const char *valid_cpus[] = { ARM_CPU_TYPE_NAME("cortex-a15"), ARM_CPU_TYPE_NAME("cortex-a35"), ARM_CPU_TYPE_NAME("cortex-a53"), + ARM_CPU_TYPE_NAME("cortex-a55"), ARM_CPU_TYPE_NAME("cortex-a57"), ARM_CPU_TYPE_NAME("cortex-a72"), ARM_CPU_TYPE_NAME("cortex-a76"), diff --git a/target/arm/cpu64.c b/target/arm/cpu64.c index 3d74f134f5..cec64471b4 100644 --- a/target/arm/cpu64.c +++ b/target/arm/cpu64.c @@ -792,6 +792,74 @@ static void aarch64_a53_initfn(Object *obj) define_cortex_a72_a57_a53_cp_reginfo(cpu); } +static void aarch64_a55_initfn(Object *obj) +{ + ARMCPU *cpu = ARM_CPU(obj); + + cpu->dtb_compatible = "arm,cortex-a55"; + set_feature(&cpu->env, ARM_FEATURE_V8); + set_feature(&cpu->env, ARM_FEATURE_NEON); + set_feature(&cpu->env, ARM_FEATURE_GENERIC_TIMER); + set_feature(&cpu->env, ARM_FEATURE_AARCH64); + set_feature(&cpu->env, ARM_FEATURE_CBAR_RO); + set_feature(&cpu->env, ARM_FEATURE_EL2); + set_feature(&cpu->env, ARM_FEATURE_EL3); + set_feature(&cpu->env, ARM_FEATURE_PMU); + + /* Ordered by B2.4 AArch64 registers by functional group */ + cpu->clidr = 0x82000023; + cpu->ctr = 0x84448004; /* L1Ip = VIPT */ + cpu->dcz_blocksize = 4; /* 64 bytes */ + cpu->isar.id_aa64dfr0 = 0x0000000010305408ull; + cpu->isar.id_aa64isar0 = 0x0000100010211120ull; + cpu->isar.id_aa64isar1 = 0x0000000000100001ull; + cpu->isar.id_aa64mmfr0 = 0x0000000000101122ull; + cpu->isar.id_aa64mmfr1 = 0x0000000010212122ull; + cpu->isar.id_aa64mmfr2 = 0x0000000000001011ull; + cpu->isar.id_aa64pfr0 = 0x0000000010112222ull; + cpu->isar.id_aa64pfr1 = 0x0000000000000010ull; + cpu->id_afr0 = 0x00000000; + cpu->isar.id_dfr0 = 0x04010088; + cpu->isar.id_isar0 = 0x02101110; + cpu->isar.id_isar1 = 0x13112111; + cpu->isar.id_isar2 = 0x21232042; + cpu->isar.id_isar3 = 0x01112131; + cpu->isar.id_isar4 = 0x00011142; + cpu->isar.id_isar5 = 0x01011121; + cpu->isar.id_isar6 = 0x00000010; + cpu->isar.id_mmfr0 = 0x10201105; + cpu->isar.id_mmfr1 = 0x40000000; + cpu->isar.id_mmfr2 = 0x01260000; + cpu->isar.id_mmfr3 = 0x02122211; + cpu->isar.id_mmfr4 = 0x00021110; + cpu->isar.id_pfr0 = 0x10010131; + cpu->isar.id_pfr1 = 0x00011011; + cpu->isar.id_pfr2 = 0x00000011; + cpu->midr = 0x412FD050; /* r2p0 */ + cpu->revidr = 0; + + /* From B2.23 CCSIDR_EL1 */ + cpu->ccsidr[0] = 0x700fe01a; /* 32KB L1 dcache */ + cpu->ccsidr[1] = 0x200fe01a; /* 32KB L1 icache */ + cpu->ccsidr[2] = 0x703fe07a; /* 512KB L2 cache */ + + /* From B2.96 SCTLR_EL3 */ + cpu->reset_sctlr = 0x30c50838; + + /* From B4.45 ICH_VTR_EL2 */ + cpu->gic_num_lrs = 4; + cpu->gic_vpribits = 5; + cpu->gic_vprebits = 5; + cpu->gic_pribits = 5; + + cpu->isar.mvfr0 = 0x10110222; + cpu->isar.mvfr1 = 0x13211111; + cpu->isar.mvfr2 = 0x00000043; + + /* From D5.4 AArch64 PMU register summary */ + cpu->isar.reset_pmcr_el0 = 0x410b3000; +} + static void aarch64_a72_initfn(Object *obj) { ARMCPU *cpu = ARM_CPU(obj); @@ -1243,6 +1311,7 @@ static const ARMCPUInfo aarch64_cpus[] = { { .name = "cortex-a35", .initfn = aarch64_a35_initfn }, { .name = "cortex-a57", .initfn = aarch64_a57_initfn }, { .name = "cortex-a53", .initfn = aarch64_a53_initfn }, + { .name = "cortex-a55", .initfn = aarch64_a55_initfn }, { .name = "cortex-a72", .initfn = aarch64_a72_initfn }, { .name = "cortex-a76", .initfn = aarch64_a76_initfn }, { .name = "a64fx", .initfn = aarch64_a64fx_initfn }, From 58dff8f7ea7aadbfacf4416c4988ad7f0f88a4c8 Mon Sep 17 00:00:00 2001 From: Luke Starrett Date: Wed, 14 Dec 2022 14:27:07 +0000 Subject: [PATCH 10/28] hw/intc/arm_gicv3: Fix GICD_TYPER ITLinesNumber advertisement The ARM GICv3 TRM describes that the ITLinesNumber field of GICD_TYPER register: "indicates the maximum SPI INTID that the GIC implementation supports" As SPI #0 is absolute IRQ #32, the max SPI INTID should have accounted for the internal 16x SGI's and 16x PPI's. However, the original GICv3 model subtracted off the SGI/PPI. Cosmetically this can be seen at OS boot (Linux) showing 32 shy of what should be there, i.e.: [ 0.000000] GICv3: 224 SPIs implemented Though in hw/arm/virt.c, the machine is configured for 256 SPI's. ARM virt machine likely doesn't have a problem with this because the upper 32 IRQ's don't actually have anything meaningful wired. But, this does become a functional issue on a custom use case which wants to make use of these IRQ's. Additionally, boot code (i.e. TF-A) will only init up to the number (blocks of 32) that it believes to actually be there. Signed-off-by: Luke Starrett Message-id: AM9P193MB168473D99B761E204E032095D40D9@AM9P193MB1684.EURP193.PROD.OUTLOOK.COM Reviewed-by: Peter Maydell Signed-off-by: Peter Maydell --- hw/intc/arm_gicv3_dist.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/hw/intc/arm_gicv3_dist.c b/hw/intc/arm_gicv3_dist.c index eea0368118..d599fefcbc 100644 --- a/hw/intc/arm_gicv3_dist.c +++ b/hw/intc/arm_gicv3_dist.c @@ -390,9 +390,9 @@ static bool gicd_readl(GICv3State *s, hwaddr offset, * MBIS == 0 (message-based SPIs not supported) * SecurityExtn == 1 if security extns supported * CPUNumber == 0 since for us ARE is always 1 - * ITLinesNumber == (num external irqs / 32) - 1 + * ITLinesNumber == (((max SPI IntID + 1) / 32) - 1) */ - int itlinesnumber = ((s->num_irq - GIC_INTERNAL) / 32) - 1; + int itlinesnumber = (s->num_irq / 32) - 1; /* * SecurityExtn must be RAZ if GICD_CTLR.DS == 1, and * "security extensions not supported" always implies DS == 1, From d2fd931362a693d988e3204ddc8068875dcf8fab Mon Sep 17 00:00:00 2001 From: Peter Maydell Date: Wed, 14 Dec 2022 14:27:08 +0000 Subject: [PATCH 11/28] target/arm: Allow relevant HCR bits to be written for FEAT_EVT FEAT_EVT adds five new bits to the HCR_EL2 register: TTLBIS, TTLBOS, TICAB, TOCU and TID4. These allow the guest to enable trapping of various EL1 instructions to EL2. In this commit, add the necessary code to allow the guest to set these bits if the feature is present; because the bit is always zero when the feature isn't present we won't need to use explicit feature checks in the "trap on condition" tests in the following commits. Note that although full implementation of the feature (mandatory from Armv8.5 onward) requires all five trap bits, the ID registers permit a value indicating that only TICAB, TOCU and TID4 are implemented, which might be the case for CPUs between Armv8.2 and Armv8.5. Signed-off-by: Peter Maydell Reviewed-by: Richard Henderson --- target/arm/cpu.h | 30 ++++++++++++++++++++++++++++++ target/arm/helper.c | 6 ++++++ 2 files changed, 36 insertions(+) diff --git a/target/arm/cpu.h b/target/arm/cpu.h index 9aeed3c848..2b4bd20f9d 100644 --- a/target/arm/cpu.h +++ b/target/arm/cpu.h @@ -3757,6 +3757,16 @@ static inline bool isar_feature_aa32_tts2uxn(const ARMISARegisters *id) return FIELD_EX32(id->id_mmfr4, ID_MMFR4, XNX) != 0; } +static inline bool isar_feature_aa32_half_evt(const ARMISARegisters *id) +{ + return FIELD_EX32(id->id_mmfr4, ID_MMFR4, EVT) >= 1; +} + +static inline bool isar_feature_aa32_evt(const ARMISARegisters *id) +{ + return FIELD_EX32(id->id_mmfr4, ID_MMFR4, EVT) >= 2; +} + static inline bool isar_feature_aa32_dit(const ARMISARegisters *id) { return FIELD_EX32(id->id_pfr0, ID_PFR0, DIT) != 0; @@ -4029,6 +4039,16 @@ static inline bool isar_feature_aa64_ids(const ARMISARegisters *id) return FIELD_EX64(id->id_aa64mmfr2, ID_AA64MMFR2, IDS) != 0; } +static inline bool isar_feature_aa64_half_evt(const ARMISARegisters *id) +{ + return FIELD_EX64(id->id_aa64mmfr2, ID_AA64MMFR2, EVT) >= 1; +} + +static inline bool isar_feature_aa64_evt(const ARMISARegisters *id) +{ + return FIELD_EX64(id->id_aa64mmfr2, ID_AA64MMFR2, EVT) >= 2; +} + static inline bool isar_feature_aa64_bti(const ARMISARegisters *id) { return FIELD_EX64(id->id_aa64pfr1, ID_AA64PFR1, BT) != 0; @@ -4313,6 +4333,16 @@ static inline bool isar_feature_any_ras(const ARMISARegisters *id) return isar_feature_aa64_ras(id) || isar_feature_aa32_ras(id); } +static inline bool isar_feature_any_half_evt(const ARMISARegisters *id) +{ + return isar_feature_aa64_half_evt(id) || isar_feature_aa32_half_evt(id); +} + +static inline bool isar_feature_any_evt(const ARMISARegisters *id) +{ + return isar_feature_aa64_evt(id) || isar_feature_aa32_evt(id); +} + /* * Forward to the above feature tests given an ARMCPU pointer. */ diff --git a/target/arm/helper.c b/target/arm/helper.c index d8c8223ec3..751c360ce4 100644 --- a/target/arm/helper.c +++ b/target/arm/helper.c @@ -5267,6 +5267,12 @@ static void do_hcr_write(CPUARMState *env, uint64_t value, uint64_t valid_mask) } } + if (cpu_isar_feature(any_evt, cpu)) { + valid_mask |= HCR_TTLBIS | HCR_TTLBOS | HCR_TICAB | HCR_TOCU | HCR_TID4; + } else if (cpu_isar_feature(any_half_evt, cpu)) { + valid_mask |= HCR_TICAB | HCR_TOCU | HCR_TID4; + } + /* Clear RES0 bits. */ value &= valid_mask; From 0f66d223e3b688a93ae02dc114d2891bbb0e09cc Mon Sep 17 00:00:00 2001 From: Peter Maydell Date: Wed, 14 Dec 2022 14:27:08 +0000 Subject: [PATCH 12/28] target/arm: Implement HCR_EL2.TTLBIS traps For FEAT_EVT, the HCR_EL2.TTLBIS bit allows trapping on EL1 use of TLB maintenance instructions that operate on the inner shareable domain: AArch64: TLBI VMALLE1IS, TLBI VAE1IS, TLBI ASIDE1IS, TLBI VAAE1IS, TLBI VALE1IS, TLBI VAALE1IS, TLBI RVAE1IS, TLBI RVAAE1IS, TLBI RVALE1IS, and TLBI RVAALE1IS. AArch32: TLBIALLIS, TLBIMVAIS, TLBIASIDIS, TLBIMVAAIS, TLBIMVALIS, and TLBIMVAALIS. Add the trapping support. Signed-off-by: Peter Maydell Reviewed-by: Richard Henderson --- target/arm/helper.c | 43 +++++++++++++++++++++++++++---------------- 1 file changed, 27 insertions(+), 16 deletions(-) diff --git a/target/arm/helper.c b/target/arm/helper.c index 751c360ce4..475b48750e 100644 --- a/target/arm/helper.c +++ b/target/arm/helper.c @@ -362,6 +362,17 @@ static CPAccessResult access_ttlb(CPUARMState *env, const ARMCPRegInfo *ri, return CP_ACCESS_OK; } +/* Check for traps from EL1 due to HCR_EL2.TTLB or TTLBIS. */ +static CPAccessResult access_ttlbis(CPUARMState *env, const ARMCPRegInfo *ri, + bool isread) +{ + if (arm_current_el(env) == 1 && + (arm_hcr_el2_eff(env) & (HCR_TTLB | HCR_TTLBIS))) { + return CP_ACCESS_TRAP_EL2; + } + return CP_ACCESS_OK; +} + static void dacr_write(CPUARMState *env, const ARMCPRegInfo *ri, uint64_t value) { ARMCPU *cpu = env_archcpu(env); @@ -2206,16 +2217,16 @@ static const ARMCPRegInfo v7_cp_reginfo[] = { static const ARMCPRegInfo v7mp_cp_reginfo[] = { /* 32 bit TLB invalidates, Inner Shareable */ { .name = "TLBIALLIS", .cp = 15, .opc1 = 0, .crn = 8, .crm = 3, .opc2 = 0, - .type = ARM_CP_NO_RAW, .access = PL1_W, .accessfn = access_ttlb, + .type = ARM_CP_NO_RAW, .access = PL1_W, .accessfn = access_ttlbis, .writefn = tlbiall_is_write }, { .name = "TLBIMVAIS", .cp = 15, .opc1 = 0, .crn = 8, .crm = 3, .opc2 = 1, - .type = ARM_CP_NO_RAW, .access = PL1_W, .accessfn = access_ttlb, + .type = ARM_CP_NO_RAW, .access = PL1_W, .accessfn = access_ttlbis, .writefn = tlbimva_is_write }, { .name = "TLBIASIDIS", .cp = 15, .opc1 = 0, .crn = 8, .crm = 3, .opc2 = 2, - .type = ARM_CP_NO_RAW, .access = PL1_W, .accessfn = access_ttlb, + .type = ARM_CP_NO_RAW, .access = PL1_W, .accessfn = access_ttlbis, .writefn = tlbiasid_is_write }, { .name = "TLBIMVAAIS", .cp = 15, .opc1 = 0, .crn = 8, .crm = 3, .opc2 = 3, - .type = ARM_CP_NO_RAW, .access = PL1_W, .accessfn = access_ttlb, + .type = ARM_CP_NO_RAW, .access = PL1_W, .accessfn = access_ttlbis, .writefn = tlbimvaa_is_write }, }; @@ -4948,27 +4959,27 @@ static const ARMCPRegInfo v8_cp_reginfo[] = { /* TLBI operations */ { .name = "TLBI_VMALLE1IS", .state = ARM_CP_STATE_AA64, .opc0 = 1, .opc1 = 0, .crn = 8, .crm = 3, .opc2 = 0, - .access = PL1_W, .accessfn = access_ttlb, .type = ARM_CP_NO_RAW, + .access = PL1_W, .accessfn = access_ttlbis, .type = ARM_CP_NO_RAW, .writefn = tlbi_aa64_vmalle1is_write }, { .name = "TLBI_VAE1IS", .state = ARM_CP_STATE_AA64, .opc0 = 1, .opc1 = 0, .crn = 8, .crm = 3, .opc2 = 1, - .access = PL1_W, .accessfn = access_ttlb, .type = ARM_CP_NO_RAW, + .access = PL1_W, .accessfn = access_ttlbis, .type = ARM_CP_NO_RAW, .writefn = tlbi_aa64_vae1is_write }, { .name = "TLBI_ASIDE1IS", .state = ARM_CP_STATE_AA64, .opc0 = 1, .opc1 = 0, .crn = 8, .crm = 3, .opc2 = 2, - .access = PL1_W, .accessfn = access_ttlb, .type = ARM_CP_NO_RAW, + .access = PL1_W, .accessfn = access_ttlbis, .type = ARM_CP_NO_RAW, .writefn = tlbi_aa64_vmalle1is_write }, { .name = "TLBI_VAAE1IS", .state = ARM_CP_STATE_AA64, .opc0 = 1, .opc1 = 0, .crn = 8, .crm = 3, .opc2 = 3, - .access = PL1_W, .accessfn = access_ttlb, .type = ARM_CP_NO_RAW, + .access = PL1_W, .accessfn = access_ttlbis, .type = ARM_CP_NO_RAW, .writefn = tlbi_aa64_vae1is_write }, { .name = "TLBI_VALE1IS", .state = ARM_CP_STATE_AA64, .opc0 = 1, .opc1 = 0, .crn = 8, .crm = 3, .opc2 = 5, - .access = PL1_W, .accessfn = access_ttlb, .type = ARM_CP_NO_RAW, + .access = PL1_W, .accessfn = access_ttlbis, .type = ARM_CP_NO_RAW, .writefn = tlbi_aa64_vae1is_write }, { .name = "TLBI_VAALE1IS", .state = ARM_CP_STATE_AA64, .opc0 = 1, .opc1 = 0, .crn = 8, .crm = 3, .opc2 = 7, - .access = PL1_W, .accessfn = access_ttlb, .type = ARM_CP_NO_RAW, + .access = PL1_W, .accessfn = access_ttlbis, .type = ARM_CP_NO_RAW, .writefn = tlbi_aa64_vae1is_write }, { .name = "TLBI_VMALLE1", .state = ARM_CP_STATE_AA64, .opc0 = 1, .opc1 = 0, .crn = 8, .crm = 7, .opc2 = 0, @@ -5078,10 +5089,10 @@ static const ARMCPRegInfo v8_cp_reginfo[] = { #endif /* TLB invalidate last level of translation table walk */ { .name = "TLBIMVALIS", .cp = 15, .opc1 = 0, .crn = 8, .crm = 3, .opc2 = 5, - .type = ARM_CP_NO_RAW, .access = PL1_W, .accessfn = access_ttlb, + .type = ARM_CP_NO_RAW, .access = PL1_W, .accessfn = access_ttlbis, .writefn = tlbimva_is_write }, { .name = "TLBIMVAALIS", .cp = 15, .opc1 = 0, .crn = 8, .crm = 3, .opc2 = 7, - .type = ARM_CP_NO_RAW, .access = PL1_W, .accessfn = access_ttlb, + .type = ARM_CP_NO_RAW, .access = PL1_W, .accessfn = access_ttlbis, .writefn = tlbimvaa_is_write }, { .name = "TLBIMVAL", .cp = 15, .opc1 = 0, .crn = 8, .crm = 7, .opc2 = 5, .type = ARM_CP_NO_RAW, .access = PL1_W, .accessfn = access_ttlb, @@ -6726,19 +6737,19 @@ static const ARMCPRegInfo pauth_reginfo[] = { static const ARMCPRegInfo tlbirange_reginfo[] = { { .name = "TLBI_RVAE1IS", .state = ARM_CP_STATE_AA64, .opc0 = 1, .opc1 = 0, .crn = 8, .crm = 2, .opc2 = 1, - .access = PL1_W, .accessfn = access_ttlb, .type = ARM_CP_NO_RAW, + .access = PL1_W, .accessfn = access_ttlbis, .type = ARM_CP_NO_RAW, .writefn = tlbi_aa64_rvae1is_write }, { .name = "TLBI_RVAAE1IS", .state = ARM_CP_STATE_AA64, .opc0 = 1, .opc1 = 0, .crn = 8, .crm = 2, .opc2 = 3, - .access = PL1_W, .accessfn = access_ttlb, .type = ARM_CP_NO_RAW, + .access = PL1_W, .accessfn = access_ttlbis, .type = ARM_CP_NO_RAW, .writefn = tlbi_aa64_rvae1is_write }, { .name = "TLBI_RVALE1IS", .state = ARM_CP_STATE_AA64, .opc0 = 1, .opc1 = 0, .crn = 8, .crm = 2, .opc2 = 5, - .access = PL1_W, .accessfn = access_ttlb, .type = ARM_CP_NO_RAW, + .access = PL1_W, .accessfn = access_ttlbis, .type = ARM_CP_NO_RAW, .writefn = tlbi_aa64_rvae1is_write }, { .name = "TLBI_RVAALE1IS", .state = ARM_CP_STATE_AA64, .opc0 = 1, .opc1 = 0, .crn = 8, .crm = 2, .opc2 = 7, - .access = PL1_W, .accessfn = access_ttlb, .type = ARM_CP_NO_RAW, + .access = PL1_W, .accessfn = access_ttlbis, .type = ARM_CP_NO_RAW, .writefn = tlbi_aa64_rvae1is_write }, { .name = "TLBI_RVAE1OS", .state = ARM_CP_STATE_AA64, .opc0 = 1, .opc1 = 0, .crn = 8, .crm = 5, .opc2 = 1, From fe3ca86c465428f738520de304e7a7a59bd0a6c2 Mon Sep 17 00:00:00 2001 From: Peter Maydell Date: Wed, 14 Dec 2022 14:27:09 +0000 Subject: [PATCH 13/28] target/arm: Implement HCR_EL2.TTLBOS traps For FEAT_EVT, the HCR_EL2.TTLBOS bit allows trapping on EL1 use of TLB maintenance instructions that operate on the outer shareable domain: TLBI VMALLE1OS, TLBI VAE1OS, TLBI ASIDE1OS,TLBI VAAE1OS, TLBI VALE1OS, TLBI VAALE1OS, TLBI RVAE1OS, TLBI RVAAE1OS, TLBI RVALE1OS, and TLBI RVAALE1OS. (There are no AArch32 outer-shareable TLB maintenance ops.) Implement the trapping. Signed-off-by: Peter Maydell Reviewed-by: Richard Henderson --- target/arm/helper.c | 33 +++++++++++++++++++++++---------- 1 file changed, 23 insertions(+), 10 deletions(-) diff --git a/target/arm/helper.c b/target/arm/helper.c index 475b48750e..0ec1c3ffbd 100644 --- a/target/arm/helper.c +++ b/target/arm/helper.c @@ -373,6 +373,19 @@ static CPAccessResult access_ttlbis(CPUARMState *env, const ARMCPRegInfo *ri, return CP_ACCESS_OK; } +#ifdef TARGET_AARCH64 +/* Check for traps from EL1 due to HCR_EL2.TTLB or TTLBOS. */ +static CPAccessResult access_ttlbos(CPUARMState *env, const ARMCPRegInfo *ri, + bool isread) +{ + if (arm_current_el(env) == 1 && + (arm_hcr_el2_eff(env) & (HCR_TTLB | HCR_TTLBOS))) { + return CP_ACCESS_TRAP_EL2; + } + return CP_ACCESS_OK; +} +#endif + static void dacr_write(CPUARMState *env, const ARMCPRegInfo *ri, uint64_t value) { ARMCPU *cpu = env_archcpu(env); @@ -6753,19 +6766,19 @@ static const ARMCPRegInfo tlbirange_reginfo[] = { .writefn = tlbi_aa64_rvae1is_write }, { .name = "TLBI_RVAE1OS", .state = ARM_CP_STATE_AA64, .opc0 = 1, .opc1 = 0, .crn = 8, .crm = 5, .opc2 = 1, - .access = PL1_W, .accessfn = access_ttlb, .type = ARM_CP_NO_RAW, + .access = PL1_W, .accessfn = access_ttlbos, .type = ARM_CP_NO_RAW, .writefn = tlbi_aa64_rvae1is_write }, { .name = "TLBI_RVAAE1OS", .state = ARM_CP_STATE_AA64, .opc0 = 1, .opc1 = 0, .crn = 8, .crm = 5, .opc2 = 3, - .access = PL1_W, .accessfn = access_ttlb, .type = ARM_CP_NO_RAW, + .access = PL1_W, .accessfn = access_ttlbos, .type = ARM_CP_NO_RAW, .writefn = tlbi_aa64_rvae1is_write }, { .name = "TLBI_RVALE1OS", .state = ARM_CP_STATE_AA64, .opc0 = 1, .opc1 = 0, .crn = 8, .crm = 5, .opc2 = 5, - .access = PL1_W, .accessfn = access_ttlb, .type = ARM_CP_NO_RAW, + .access = PL1_W, .accessfn = access_ttlbos, .type = ARM_CP_NO_RAW, .writefn = tlbi_aa64_rvae1is_write }, { .name = "TLBI_RVAALE1OS", .state = ARM_CP_STATE_AA64, .opc0 = 1, .opc1 = 0, .crn = 8, .crm = 5, .opc2 = 7, - .access = PL1_W, .accessfn = access_ttlb, .type = ARM_CP_NO_RAW, + .access = PL1_W, .accessfn = access_ttlbos, .type = ARM_CP_NO_RAW, .writefn = tlbi_aa64_rvae1is_write }, { .name = "TLBI_RVAE1", .state = ARM_CP_STATE_AA64, .opc0 = 1, .opc1 = 0, .crn = 8, .crm = 6, .opc2 = 1, @@ -6852,27 +6865,27 @@ static const ARMCPRegInfo tlbirange_reginfo[] = { static const ARMCPRegInfo tlbios_reginfo[] = { { .name = "TLBI_VMALLE1OS", .state = ARM_CP_STATE_AA64, .opc0 = 1, .opc1 = 0, .crn = 8, .crm = 1, .opc2 = 0, - .access = PL1_W, .accessfn = access_ttlb, .type = ARM_CP_NO_RAW, + .access = PL1_W, .accessfn = access_ttlbos, .type = ARM_CP_NO_RAW, .writefn = tlbi_aa64_vmalle1is_write }, { .name = "TLBI_VAE1OS", .state = ARM_CP_STATE_AA64, .opc0 = 1, .opc1 = 0, .crn = 8, .crm = 1, .opc2 = 1, - .access = PL1_W, .accessfn = access_ttlb, .type = ARM_CP_NO_RAW, + .access = PL1_W, .accessfn = access_ttlbos, .type = ARM_CP_NO_RAW, .writefn = tlbi_aa64_vae1is_write }, { .name = "TLBI_ASIDE1OS", .state = ARM_CP_STATE_AA64, .opc0 = 1, .opc1 = 0, .crn = 8, .crm = 1, .opc2 = 2, - .access = PL1_W, .accessfn = access_ttlb, .type = ARM_CP_NO_RAW, + .access = PL1_W, .accessfn = access_ttlbos, .type = ARM_CP_NO_RAW, .writefn = tlbi_aa64_vmalle1is_write }, { .name = "TLBI_VAAE1OS", .state = ARM_CP_STATE_AA64, .opc0 = 1, .opc1 = 0, .crn = 8, .crm = 1, .opc2 = 3, - .access = PL1_W, .accessfn = access_ttlb, .type = ARM_CP_NO_RAW, + .access = PL1_W, .accessfn = access_ttlbos, .type = ARM_CP_NO_RAW, .writefn = tlbi_aa64_vae1is_write }, { .name = "TLBI_VALE1OS", .state = ARM_CP_STATE_AA64, .opc0 = 1, .opc1 = 0, .crn = 8, .crm = 1, .opc2 = 5, - .access = PL1_W, .accessfn = access_ttlb, .type = ARM_CP_NO_RAW, + .access = PL1_W, .accessfn = access_ttlbos, .type = ARM_CP_NO_RAW, .writefn = tlbi_aa64_vae1is_write }, { .name = "TLBI_VAALE1OS", .state = ARM_CP_STATE_AA64, .opc0 = 1, .opc1 = 0, .crn = 8, .crm = 1, .opc2 = 7, - .access = PL1_W, .accessfn = access_ttlb, .type = ARM_CP_NO_RAW, + .access = PL1_W, .accessfn = access_ttlbos, .type = ARM_CP_NO_RAW, .writefn = tlbi_aa64_vae1is_write }, { .name = "TLBI_ALLE2OS", .state = ARM_CP_STATE_AA64, .opc0 = 1, .opc1 = 4, .crn = 8, .crm = 1, .opc2 = 0, From 2d3ce4c6f3bc66234e384355cedc6e7aa40903ac Mon Sep 17 00:00:00 2001 From: Peter Maydell Date: Wed, 14 Dec 2022 14:27:09 +0000 Subject: [PATCH 14/28] target/arm: Implement HCR_EL2.TICAB,TOCU traps For FEAT_EVT, the HCR_EL2.TICAB bit allows trapping of the ICIALLUIS and IC IALLUIS cache maintenance instructions. The HCR_EL2.TOCU bit traps all the other cache maintenance instructions that operate to the point of unification: AArch64 IC IVAU, IC IALLU, DC CVAU AArch32 ICIMVAU, ICIALLU, DCCMVAU The two trap bits between them cover all of the cache maintenance instructions which must also check the HCR_TPU flag. Turn the old aa64_cacheop_pou_access() function into a helper function which takes the set of HCR_EL2 flags to check as an argument, and call it from new access_ticab() and access_tocu() functions as appropriate for each cache op. Signed-off-by: Peter Maydell Reviewed-by: Richard Henderson --- target/arm/helper.c | 36 +++++++++++++++++++++++------------- 1 file changed, 23 insertions(+), 13 deletions(-) diff --git a/target/arm/helper.c b/target/arm/helper.c index 0ec1c3ffbd..eee95a42f7 100644 --- a/target/arm/helper.c +++ b/target/arm/helper.c @@ -4273,9 +4273,7 @@ static CPAccessResult aa64_cacheop_poc_access(CPUARMState *env, return CP_ACCESS_OK; } -static CPAccessResult aa64_cacheop_pou_access(CPUARMState *env, - const ARMCPRegInfo *ri, - bool isread) +static CPAccessResult do_cacheop_pou_access(CPUARMState *env, uint64_t hcrflags) { /* Cache invalidate/clean to Point of Unification... */ switch (arm_current_el(env)) { @@ -4286,8 +4284,8 @@ static CPAccessResult aa64_cacheop_pou_access(CPUARMState *env, } /* fall through */ case 1: - /* ... EL1 must trap to EL2 if HCR_EL2.TPU is set. */ - if (arm_hcr_el2_eff(env) & HCR_TPU) { + /* ... EL1 must trap to EL2 if relevant HCR_EL2 flags are set. */ + if (arm_hcr_el2_eff(env) & hcrflags) { return CP_ACCESS_TRAP_EL2; } break; @@ -4295,6 +4293,18 @@ static CPAccessResult aa64_cacheop_pou_access(CPUARMState *env, return CP_ACCESS_OK; } +static CPAccessResult access_ticab(CPUARMState *env, const ARMCPRegInfo *ri, + bool isread) +{ + return do_cacheop_pou_access(env, HCR_TICAB | HCR_TPU); +} + +static CPAccessResult access_tocu(CPUARMState *env, const ARMCPRegInfo *ri, + bool isread) +{ + return do_cacheop_pou_access(env, HCR_TOCU | HCR_TPU); +} + /* See: D4.7.2 TLB maintenance requirements and the TLB maintenance instructions * Page D4-1736 (DDI0487A.b) */ @@ -4935,15 +4945,15 @@ static const ARMCPRegInfo v8_cp_reginfo[] = { { .name = "IC_IALLUIS", .state = ARM_CP_STATE_AA64, .opc0 = 1, .opc1 = 0, .crn = 7, .crm = 1, .opc2 = 0, .access = PL1_W, .type = ARM_CP_NOP, - .accessfn = aa64_cacheop_pou_access }, + .accessfn = access_ticab }, { .name = "IC_IALLU", .state = ARM_CP_STATE_AA64, .opc0 = 1, .opc1 = 0, .crn = 7, .crm = 5, .opc2 = 0, .access = PL1_W, .type = ARM_CP_NOP, - .accessfn = aa64_cacheop_pou_access }, + .accessfn = access_tocu }, { .name = "IC_IVAU", .state = ARM_CP_STATE_AA64, .opc0 = 1, .opc1 = 3, .crn = 7, .crm = 5, .opc2 = 1, .access = PL0_W, .type = ARM_CP_NOP, - .accessfn = aa64_cacheop_pou_access }, + .accessfn = access_tocu }, { .name = "DC_IVAC", .state = ARM_CP_STATE_AA64, .opc0 = 1, .opc1 = 0, .crn = 7, .crm = 6, .opc2 = 1, .access = PL1_W, .accessfn = aa64_cacheop_poc_access, @@ -4961,7 +4971,7 @@ static const ARMCPRegInfo v8_cp_reginfo[] = { { .name = "DC_CVAU", .state = ARM_CP_STATE_AA64, .opc0 = 1, .opc1 = 3, .crn = 7, .crm = 11, .opc2 = 1, .access = PL0_W, .type = ARM_CP_NOP, - .accessfn = aa64_cacheop_pou_access }, + .accessfn = access_tocu }, { .name = "DC_CIVAC", .state = ARM_CP_STATE_AA64, .opc0 = 1, .opc1 = 3, .crn = 7, .crm = 14, .opc2 = 1, .access = PL0_W, .type = ARM_CP_NOP, @@ -5138,13 +5148,13 @@ static const ARMCPRegInfo v8_cp_reginfo[] = { .writefn = tlbiipas2is_hyp_write }, /* 32 bit cache operations */ { .name = "ICIALLUIS", .cp = 15, .opc1 = 0, .crn = 7, .crm = 1, .opc2 = 0, - .type = ARM_CP_NOP, .access = PL1_W, .accessfn = aa64_cacheop_pou_access }, + .type = ARM_CP_NOP, .access = PL1_W, .accessfn = access_ticab }, { .name = "BPIALLUIS", .cp = 15, .opc1 = 0, .crn = 7, .crm = 1, .opc2 = 6, .type = ARM_CP_NOP, .access = PL1_W }, { .name = "ICIALLU", .cp = 15, .opc1 = 0, .crn = 7, .crm = 5, .opc2 = 0, - .type = ARM_CP_NOP, .access = PL1_W, .accessfn = aa64_cacheop_pou_access }, + .type = ARM_CP_NOP, .access = PL1_W, .accessfn = access_tocu }, { .name = "ICIMVAU", .cp = 15, .opc1 = 0, .crn = 7, .crm = 5, .opc2 = 1, - .type = ARM_CP_NOP, .access = PL1_W, .accessfn = aa64_cacheop_pou_access }, + .type = ARM_CP_NOP, .access = PL1_W, .accessfn = access_tocu }, { .name = "BPIALL", .cp = 15, .opc1 = 0, .crn = 7, .crm = 5, .opc2 = 6, .type = ARM_CP_NOP, .access = PL1_W }, { .name = "BPIMVA", .cp = 15, .opc1 = 0, .crn = 7, .crm = 5, .opc2 = 7, @@ -5158,7 +5168,7 @@ static const ARMCPRegInfo v8_cp_reginfo[] = { { .name = "DCCSW", .cp = 15, .opc1 = 0, .crn = 7, .crm = 10, .opc2 = 2, .type = ARM_CP_NOP, .access = PL1_W, .accessfn = access_tsw }, { .name = "DCCMVAU", .cp = 15, .opc1 = 0, .crn = 7, .crm = 11, .opc2 = 1, - .type = ARM_CP_NOP, .access = PL1_W, .accessfn = aa64_cacheop_pou_access }, + .type = ARM_CP_NOP, .access = PL1_W, .accessfn = access_tocu }, { .name = "DCCIMVAC", .cp = 15, .opc1 = 0, .crn = 7, .crm = 14, .opc2 = 1, .type = ARM_CP_NOP, .access = PL1_W, .accessfn = aa64_cacheop_poc_access }, { .name = "DCCISW", .cp = 15, .opc1 = 0, .crn = 7, .crm = 14, .opc2 = 2, From e2ce5fcde468c7316b6ba3c30a970c9e50bf7211 Mon Sep 17 00:00:00 2001 From: Peter Maydell Date: Wed, 14 Dec 2022 14:27:09 +0000 Subject: [PATCH 15/28] target/arm: Implement HCR_EL2.TID4 traps For FEAT_EVT, the HCR_EL2.TID4 trap allows trapping of the cache ID registers CCSIDR_EL1, CCSIDR2_EL1, CLIDR_EL1 and CSSELR_EL1 (and their AArch32 equivalents). This is a subset of the registers trapped by HCR_EL2.TID2, which includes all of these and also the CTR_EL0 register. Our implementation already uses a separate access function for CTR_EL0 (ctr_el0_access()), so all of the registers currently using access_aa64_tid2() should also be checking TID4. Make that function check both TID2 and TID4, and rename it appropriately. Signed-off-by: Peter Maydell Reviewed-by: Richard Henderson --- target/arm/helper.c | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 deletions(-) diff --git a/target/arm/helper.c b/target/arm/helper.c index eee95a42f7..bac2ea62c4 100644 --- a/target/arm/helper.c +++ b/target/arm/helper.c @@ -1895,11 +1895,12 @@ static void scr_reset(CPUARMState *env, const ARMCPRegInfo *ri) scr_write(env, ri, 0); } -static CPAccessResult access_aa64_tid2(CPUARMState *env, - const ARMCPRegInfo *ri, - bool isread) +static CPAccessResult access_tid4(CPUARMState *env, + const ARMCPRegInfo *ri, + bool isread) { - if (arm_current_el(env) == 1 && (arm_hcr_el2_eff(env) & HCR_TID2)) { + if (arm_current_el(env) == 1 && + (arm_hcr_el2_eff(env) & (HCR_TID2 | HCR_TID4))) { return CP_ACCESS_TRAP_EL2; } @@ -2130,12 +2131,12 @@ static const ARMCPRegInfo v7_cp_reginfo[] = { { .name = "CCSIDR", .state = ARM_CP_STATE_BOTH, .opc0 = 3, .crn = 0, .crm = 0, .opc1 = 1, .opc2 = 0, .access = PL1_R, - .accessfn = access_aa64_tid2, + .accessfn = access_tid4, .readfn = ccsidr_read, .type = ARM_CP_NO_RAW }, { .name = "CSSELR", .state = ARM_CP_STATE_BOTH, .opc0 = 3, .crn = 0, .crm = 0, .opc1 = 2, .opc2 = 0, .access = PL1_RW, - .accessfn = access_aa64_tid2, + .accessfn = access_tid4, .writefn = csselr_write, .resetvalue = 0, .bank_fieldoffsets = { offsetof(CPUARMState, cp15.csselr_s), offsetof(CPUARMState, cp15.csselr_ns) } }, @@ -7281,7 +7282,7 @@ static const ARMCPRegInfo ccsidr2_reginfo[] = { { .name = "CCSIDR2", .state = ARM_CP_STATE_BOTH, .opc0 = 3, .opc1 = 1, .crn = 0, .crm = 0, .opc2 = 2, .access = PL1_R, - .accessfn = access_aa64_tid2, + .accessfn = access_tid4, .readfn = ccsidr2_read, .type = ARM_CP_NO_RAW }, }; @@ -7581,7 +7582,7 @@ void register_cp_regs_for_features(ARMCPU *cpu) .name = "CLIDR", .state = ARM_CP_STATE_BOTH, .opc0 = 3, .crn = 0, .crm = 0, .opc1 = 1, .opc2 = 1, .access = PL1_R, .type = ARM_CP_CONST, - .accessfn = access_aa64_tid2, + .accessfn = access_tid4, .resetvalue = cpu->clidr }; define_one_arm_cp_reg(cpu, &clidr); From 41654f120f535545baf91198699392376d995837 Mon Sep 17 00:00:00 2001 From: Peter Maydell Date: Wed, 14 Dec 2022 14:27:10 +0000 Subject: [PATCH 16/28] target/arm: Report FEAT_EVT for TCG '-cpu max' Update the ID registers for TCG's '-cpu max' to report the FEAT_EVT Enhanced Virtualization Traps support. Signed-off-by: Peter Maydell Reviewed-by: Richard Henderson --- docs/system/arm/emulation.rst | 1 + target/arm/cpu64.c | 1 + target/arm/cpu_tcg.c | 1 + 3 files changed, 3 insertions(+) diff --git a/docs/system/arm/emulation.rst b/docs/system/arm/emulation.rst index e3af79bb8c..b33d7c28dc 100644 --- a/docs/system/arm/emulation.rst +++ b/docs/system/arm/emulation.rst @@ -26,6 +26,7 @@ the following architecture extensions: - FEAT_DoubleFault (Double Fault Extension) - FEAT_E0PD (Preventing EL0 access to halves of address maps) - FEAT_ETS (Enhanced Translation Synchronization) +- FEAT_EVT (Enhanced Virtualization Traps) - FEAT_FCMA (Floating-point complex number instructions) - FEAT_FHM (Floating-point half-precision multiplication instructions) - FEAT_FP16 (Half-precision floating-point data processing) diff --git a/target/arm/cpu64.c b/target/arm/cpu64.c index cec64471b4..2cf2ca4ce5 100644 --- a/target/arm/cpu64.c +++ b/target/arm/cpu64.c @@ -1254,6 +1254,7 @@ static void aarch64_max_initfn(Object *obj) t = FIELD_DP64(t, ID_AA64MMFR2, FWB, 1); /* FEAT_S2FWB */ t = FIELD_DP64(t, ID_AA64MMFR2, TTL, 1); /* FEAT_TTL */ t = FIELD_DP64(t, ID_AA64MMFR2, BBM, 2); /* FEAT_BBM at level 2 */ + t = FIELD_DP64(t, ID_AA64MMFR2, EVT, 2); /* FEAT_EVT */ t = FIELD_DP64(t, ID_AA64MMFR2, E0PD, 1); /* FEAT_E0PD */ cpu->isar.id_aa64mmfr2 = t; diff --git a/target/arm/cpu_tcg.c b/target/arm/cpu_tcg.c index 9a2cef7d05..568cbcfc52 100644 --- a/target/arm/cpu_tcg.c +++ b/target/arm/cpu_tcg.c @@ -65,6 +65,7 @@ void aa32_max_features(ARMCPU *cpu) t = FIELD_DP32(t, ID_MMFR4, AC2, 1); /* ACTLR2, HACTLR2 */ t = FIELD_DP32(t, ID_MMFR4, CNP, 1); /* FEAT_TTCNP */ t = FIELD_DP32(t, ID_MMFR4, XNX, 1); /* FEAT_XNX */ + t = FIELD_DP32(t, ID_MMFR4, EVT, 2); /* FEAT_EVT */ cpu->isar.id_mmfr4 = t; t = cpu->isar.id_mmfr5; From 3c1a7c41972f92aa24cdb43e241f60e1d332bd26 Mon Sep 17 00:00:00 2001 From: Peter Maydell Date: Wed, 14 Dec 2022 14:27:10 +0000 Subject: [PATCH 17/28] hw/arm: Convert TYPE_ARM_SMMU to 3-phase reset MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Convert the TYPE_ARM_SMMU device to 3-phase reset. The legacy method doesn't do anything that's invalid in the hold phase, so the conversion is simple and not a behaviour change. Note that we must convert this base class before we can convert the TYPE_ARM_SMMUV3 subclass -- transitional support in Resettable handles "chain to parent class reset" when the base class is 3-phase and the subclass is still using legacy reset, but not the other way around. Signed-off-by: Peter Maydell Reviewed-by: Philippe Mathieu-Daudé Reviewed-by: Richard Henderson Reviewed-by: Eric Auger Message-id: 20221109161444.3397405-2-peter.maydell@linaro.org --- hw/arm/smmu-common.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/hw/arm/smmu-common.c b/hw/arm/smmu-common.c index e09b9c13b7..220838525d 100644 --- a/hw/arm/smmu-common.c +++ b/hw/arm/smmu-common.c @@ -526,9 +526,9 @@ static void smmu_base_realize(DeviceState *dev, Error **errp) } } -static void smmu_base_reset(DeviceState *dev) +static void smmu_base_reset_hold(Object *obj) { - SMMUState *s = ARM_SMMU(dev); + SMMUState *s = ARM_SMMU(obj); g_hash_table_remove_all(s->configs); g_hash_table_remove_all(s->iotlb); @@ -543,12 +543,13 @@ static Property smmu_dev_properties[] = { static void smmu_base_class_init(ObjectClass *klass, void *data) { DeviceClass *dc = DEVICE_CLASS(klass); + ResettableClass *rc = RESETTABLE_CLASS(klass); SMMUBaseClass *sbc = ARM_SMMU_CLASS(klass); device_class_set_props(dc, smmu_dev_properties); device_class_set_parent_realize(dc, smmu_base_realize, &sbc->parent_realize); - dc->reset = smmu_base_reset; + rc->phases.hold = smmu_base_reset_hold; } static const TypeInfo smmu_base_info = { From 503819a3479218f10fedbbae55686f719e47e04d Mon Sep 17 00:00:00 2001 From: Peter Maydell Date: Wed, 14 Dec 2022 14:27:10 +0000 Subject: [PATCH 18/28] hw/arm: Convert TYPE_ARM_SMMUV3 to 3-phase reset MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Convert the TYPE_ARM_SMMUV3 device to 3-phase reset. The legacy reset method doesn't do anything that's invalid in the hold phase, so the conversion only requires changing it to a hold phase method, and using the 3-phase versions of the "save the parent reset method and chain to it" code. Signed-off-by: Peter Maydell Reviewed-by: Richard Henderson Reviewed-by: Eric Auger Reviewed-by: Philippe Mathieu-Daudé Message-id: 20221109161444.3397405-3-peter.maydell@linaro.org --- hw/arm/smmuv3.c | 12 ++++++++---- include/hw/arm/smmuv3.h | 2 +- 2 files changed, 9 insertions(+), 5 deletions(-) diff --git a/hw/arm/smmuv3.c b/hw/arm/smmuv3.c index daa80e9c7b..955b89c8d5 100644 --- a/hw/arm/smmuv3.c +++ b/hw/arm/smmuv3.c @@ -1431,12 +1431,14 @@ static void smmu_init_irq(SMMUv3State *s, SysBusDevice *dev) } } -static void smmu_reset(DeviceState *dev) +static void smmu_reset_hold(Object *obj) { - SMMUv3State *s = ARM_SMMUV3(dev); + SMMUv3State *s = ARM_SMMUV3(obj); SMMUv3Class *c = ARM_SMMUV3_GET_CLASS(s); - c->parent_reset(dev); + if (c->parent_phases.hold) { + c->parent_phases.hold(obj); + } smmuv3_init_regs(s); } @@ -1520,10 +1522,12 @@ static void smmuv3_instance_init(Object *obj) static void smmuv3_class_init(ObjectClass *klass, void *data) { DeviceClass *dc = DEVICE_CLASS(klass); + ResettableClass *rc = RESETTABLE_CLASS(klass); SMMUv3Class *c = ARM_SMMUV3_CLASS(klass); dc->vmsd = &vmstate_smmuv3; - device_class_set_parent_reset(dc, smmu_reset, &c->parent_reset); + resettable_class_set_parent_phases(rc, NULL, smmu_reset_hold, NULL, + &c->parent_phases); c->parent_realize = dc->realize; dc->realize = smmu_realize; } diff --git a/include/hw/arm/smmuv3.h b/include/hw/arm/smmuv3.h index c641e60735..f1921fdf9e 100644 --- a/include/hw/arm/smmuv3.h +++ b/include/hw/arm/smmuv3.h @@ -77,7 +77,7 @@ struct SMMUv3Class { /*< public >*/ DeviceRealize parent_realize; - DeviceReset parent_reset; + ResettablePhases parent_phases; }; #define TYPE_ARM_SMMUV3 "arm-smmuv3" From fe3c6174f24205db82ff19f5cb5d374e79394233 Mon Sep 17 00:00:00 2001 From: Peter Maydell Date: Wed, 14 Dec 2022 14:27:11 +0000 Subject: [PATCH 19/28] hw/intc: Convert TYPE_ARM_GIC_COMMON to 3-phase reset MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Convert the TYPE_ARM_GIC_COMMON device to 3-phase reset. This is a simple no-behaviour-change conversion. Signed-off-by: Peter Maydell Reviewed-by: Philippe Mathieu-Daudé Reviewed-by: Richard Henderson Message-id: 20221109161444.3397405-4-peter.maydell@linaro.org --- hw/intc/arm_gic_common.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/hw/intc/arm_gic_common.c b/hw/intc/arm_gic_common.c index 7b44d5625b..a379cea395 100644 --- a/hw/intc/arm_gic_common.c +++ b/hw/intc/arm_gic_common.c @@ -261,9 +261,9 @@ static inline void arm_gic_common_reset_irq_state(GICState *s, int first_cpu, } } -static void arm_gic_common_reset(DeviceState *dev) +static void arm_gic_common_reset_hold(Object *obj) { - GICState *s = ARM_GIC_COMMON(dev); + GICState *s = ARM_GIC_COMMON(obj); int i, j; int resetprio; @@ -364,9 +364,10 @@ static Property arm_gic_common_properties[] = { static void arm_gic_common_class_init(ObjectClass *klass, void *data) { DeviceClass *dc = DEVICE_CLASS(klass); + ResettableClass *rc = RESETTABLE_CLASS(klass); ARMLinuxBootIfClass *albifc = ARM_LINUX_BOOT_IF_CLASS(klass); - dc->reset = arm_gic_common_reset; + rc->phases.hold = arm_gic_common_reset_hold; dc->realize = arm_gic_common_realize; device_class_set_props(dc, arm_gic_common_properties); dc->vmsd = &vmstate_gic; From d39270b559e7f08f768e62b9a60d478be79eb03d Mon Sep 17 00:00:00 2001 From: Peter Maydell Date: Wed, 14 Dec 2022 14:27:11 +0000 Subject: [PATCH 20/28] hw/intc: Convert TYPE_ARM_GIC_KVM to 3-phase reset MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Now we have converted TYPE_ARM_GIC_COMMON, we can convert the TYPE_ARM_GIC_KVM subclass to 3-phase reset. Signed-off-by: Peter Maydell Reviewed-by: Richard Henderson Reviewed-by: Philippe Mathieu-Daudé Message-id: 20221109161444.3397405-5-peter.maydell@linaro.org --- hw/intc/arm_gic_kvm.c | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/hw/intc/arm_gic_kvm.c b/hw/intc/arm_gic_kvm.c index 7d2a13273a..1d588946bc 100644 --- a/hw/intc/arm_gic_kvm.c +++ b/hw/intc/arm_gic_kvm.c @@ -38,7 +38,7 @@ DECLARE_OBJ_CHECKERS(GICState, KVMARMGICClass, struct KVMARMGICClass { ARMGICCommonClass parent_class; DeviceRealize parent_realize; - void (*parent_reset)(DeviceState *dev); + ResettablePhases parent_phases; }; void kvm_arm_gic_set_irq(uint32_t num_irq, int irq, int level) @@ -473,12 +473,14 @@ static void kvm_arm_gic_get(GICState *s) } } -static void kvm_arm_gic_reset(DeviceState *dev) +static void kvm_arm_gic_reset_hold(Object *obj) { - GICState *s = ARM_GIC_COMMON(dev); + GICState *s = ARM_GIC_COMMON(obj); KVMARMGICClass *kgc = KVM_ARM_GIC_GET_CLASS(s); - kgc->parent_reset(dev); + if (kgc->parent_phases.hold) { + kgc->parent_phases.hold(obj); + } if (kvm_arm_gic_can_save_restore(s)) { kvm_arm_gic_put(s); @@ -593,6 +595,7 @@ static void kvm_arm_gic_realize(DeviceState *dev, Error **errp) static void kvm_arm_gic_class_init(ObjectClass *klass, void *data) { DeviceClass *dc = DEVICE_CLASS(klass); + ResettableClass *rc = RESETTABLE_CLASS(klass); ARMGICCommonClass *agcc = ARM_GIC_COMMON_CLASS(klass); KVMARMGICClass *kgc = KVM_ARM_GIC_CLASS(klass); @@ -600,7 +603,8 @@ static void kvm_arm_gic_class_init(ObjectClass *klass, void *data) agcc->post_load = kvm_arm_gic_put; device_class_set_parent_realize(dc, kvm_arm_gic_realize, &kgc->parent_realize); - device_class_set_parent_reset(dc, kvm_arm_gic_reset, &kgc->parent_reset); + resettable_class_set_parent_phases(rc, NULL, kvm_arm_gic_reset_hold, NULL, + &kgc->parent_phases); } static const TypeInfo kvm_arm_gic_info = { From 183cac319e783bc6b7fa57904d67d28b0500c855 Mon Sep 17 00:00:00 2001 From: Peter Maydell Date: Wed, 14 Dec 2022 14:27:11 +0000 Subject: [PATCH 21/28] hw/intc: Convert TYPE_ARM_GICV3_COMMON to 3-phase reset MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Convert the TYPE_ARM_GICV3_COMMON parent class to 3-phase reset. Signed-off-by: Peter Maydell Reviewed-by: Richard Henderson Reviewed-by: Philippe Mathieu-Daudé Message-id: 20221109161444.3397405-6-peter.maydell@linaro.org --- hw/intc/arm_gicv3_common.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/hw/intc/arm_gicv3_common.c b/hw/intc/arm_gicv3_common.c index 351843db4a..642a8243ed 100644 --- a/hw/intc/arm_gicv3_common.c +++ b/hw/intc/arm_gicv3_common.c @@ -450,9 +450,9 @@ static void arm_gicv3_finalize(Object *obj) g_free(s->redist_region_count); } -static void arm_gicv3_common_reset(DeviceState *dev) +static void arm_gicv3_common_reset_hold(Object *obj) { - GICv3State *s = ARM_GICV3_COMMON(dev); + GICv3State *s = ARM_GICV3_COMMON(obj); int i; for (i = 0; i < s->num_cpu; i++) { @@ -578,9 +578,10 @@ static Property arm_gicv3_common_properties[] = { static void arm_gicv3_common_class_init(ObjectClass *klass, void *data) { DeviceClass *dc = DEVICE_CLASS(klass); + ResettableClass *rc = RESETTABLE_CLASS(klass); ARMLinuxBootIfClass *albifc = ARM_LINUX_BOOT_IF_CLASS(klass); - dc->reset = arm_gicv3_common_reset; + rc->phases.hold = arm_gicv3_common_reset_hold; dc->realize = arm_gicv3_common_realize; device_class_set_props(dc, arm_gicv3_common_properties); dc->vmsd = &vmstate_gicv3; From 823300f0fc7d374a887a4bc65f340688738de71c Mon Sep 17 00:00:00 2001 From: Peter Maydell Date: Wed, 14 Dec 2022 14:27:12 +0000 Subject: [PATCH 22/28] hw/intc: Convert TYPE_KVM_ARM_GICV3 to 3-phase reset MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Convert the TYPE_KVM_ARM_GICV3 device to 3-phase reset. Signed-off-by: Peter Maydell Reviewed-by: Richard Henderson Reviewed-by: Philippe Mathieu-Daudé Message-id: 20221109161444.3397405-7-peter.maydell@linaro.org --- hw/intc/arm_gicv3_kvm.c | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/hw/intc/arm_gicv3_kvm.c b/hw/intc/arm_gicv3_kvm.c index 3ca643ecba..72ad916d3d 100644 --- a/hw/intc/arm_gicv3_kvm.c +++ b/hw/intc/arm_gicv3_kvm.c @@ -77,7 +77,7 @@ DECLARE_OBJ_CHECKERS(GICv3State, KVMARMGICv3Class, struct KVMARMGICv3Class { ARMGICv3CommonClass parent_class; DeviceRealize parent_realize; - void (*parent_reset)(DeviceState *dev); + ResettablePhases parent_phases; }; static void kvm_arm_gicv3_set_irq(void *opaque, int irq, int level) @@ -703,14 +703,16 @@ static void arm_gicv3_icc_reset(CPUARMState *env, const ARMCPRegInfo *ri) c->icc_ctlr_el1[GICV3_S] = c->icc_ctlr_el1[GICV3_NS]; } -static void kvm_arm_gicv3_reset(DeviceState *dev) +static void kvm_arm_gicv3_reset_hold(Object *obj) { - GICv3State *s = ARM_GICV3_COMMON(dev); + GICv3State *s = ARM_GICV3_COMMON(obj); KVMARMGICv3Class *kgc = KVM_ARM_GICV3_GET_CLASS(s); DPRINTF("Reset\n"); - kgc->parent_reset(dev); + if (kgc->parent_phases.hold) { + kgc->parent_phases.hold(obj); + } if (s->migration_blocker) { DPRINTF("Cannot put kernel gic state, no kernel interface\n"); @@ -890,6 +892,7 @@ static void kvm_arm_gicv3_realize(DeviceState *dev, Error **errp) static void kvm_arm_gicv3_class_init(ObjectClass *klass, void *data) { DeviceClass *dc = DEVICE_CLASS(klass); + ResettableClass *rc = RESETTABLE_CLASS(klass); ARMGICv3CommonClass *agcc = ARM_GICV3_COMMON_CLASS(klass); KVMARMGICv3Class *kgc = KVM_ARM_GICV3_CLASS(klass); @@ -897,7 +900,8 @@ static void kvm_arm_gicv3_class_init(ObjectClass *klass, void *data) agcc->post_load = kvm_arm_gicv3_put; device_class_set_parent_realize(dc, kvm_arm_gicv3_realize, &kgc->parent_realize); - device_class_set_parent_reset(dc, kvm_arm_gicv3_reset, &kgc->parent_reset); + resettable_class_set_parent_phases(rc, NULL, kvm_arm_gicv3_reset_hold, NULL, + &kgc->parent_phases); } static const TypeInfo kvm_arm_gicv3_info = { From 1f6887616f3ca60d8d1e4e33d0a423142afded12 Mon Sep 17 00:00:00 2001 From: Peter Maydell Date: Wed, 14 Dec 2022 14:27:12 +0000 Subject: [PATCH 23/28] hw/intc: Convert TYPE_ARM_GICV3_ITS_COMMON to 3-phase reset MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Convert the TYPE_ARM_GICV3_ITS_COMMON parent class to 3-phase reset. Signed-off-by: Peter Maydell Reviewed-by: Philippe Mathieu-Daudé Reviewed-by: Richard Henderson Message-id: 20221109161444.3397405-8-peter.maydell@linaro.org --- hw/intc/arm_gicv3_its_common.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/hw/intc/arm_gicv3_its_common.c b/hw/intc/arm_gicv3_its_common.c index 90b85f1e25..d7532a7a89 100644 --- a/hw/intc/arm_gicv3_its_common.c +++ b/hw/intc/arm_gicv3_its_common.c @@ -122,9 +122,9 @@ void gicv3_its_init_mmio(GICv3ITSState *s, const MemoryRegionOps *ops, msi_nonbroken = true; } -static void gicv3_its_common_reset(DeviceState *dev) +static void gicv3_its_common_reset_hold(Object *obj) { - GICv3ITSState *s = ARM_GICV3_ITS_COMMON(dev); + GICv3ITSState *s = ARM_GICV3_ITS_COMMON(obj); s->ctlr = 0; s->cbaser = 0; @@ -137,8 +137,9 @@ static void gicv3_its_common_reset(DeviceState *dev) static void gicv3_its_common_class_init(ObjectClass *klass, void *data) { DeviceClass *dc = DEVICE_CLASS(klass); + ResettableClass *rc = RESETTABLE_CLASS(klass); - dc->reset = gicv3_its_common_reset; + rc->phases.hold = gicv3_its_common_reset_hold; dc->vmsd = &vmstate_its; } From 1bcb90762b19c96ce1193524f1c8c97ba87e1b17 Mon Sep 17 00:00:00 2001 From: Peter Maydell Date: Wed, 14 Dec 2022 14:27:12 +0000 Subject: [PATCH 24/28] hw/intc: Convert TYPE_ARM_GICV3_ITS to 3-phase reset MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Convert the TYPE_ARM_GICV3_ITS device to 3-phase reset. Signed-off-by: Peter Maydell Reviewed-by: Richard Henderson Reviewed-by: Philippe Mathieu-Daudé Message-id: 20221109161444.3397405-9-peter.maydell@linaro.org --- hw/intc/arm_gicv3_its.c | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/hw/intc/arm_gicv3_its.c b/hw/intc/arm_gicv3_its.c index 2ff21ed6bb..57c79da5c5 100644 --- a/hw/intc/arm_gicv3_its.c +++ b/hw/intc/arm_gicv3_its.c @@ -27,7 +27,7 @@ DECLARE_OBJ_CHECKERS(GICv3ITSState, GICv3ITSClass, struct GICv3ITSClass { GICv3ITSCommonClass parent_class; - void (*parent_reset)(DeviceState *dev); + ResettablePhases parent_phases; }; /* @@ -1953,12 +1953,14 @@ static void gicv3_arm_its_realize(DeviceState *dev, Error **errp) } } -static void gicv3_its_reset(DeviceState *dev) +static void gicv3_its_reset_hold(Object *obj) { - GICv3ITSState *s = ARM_GICV3_ITS_COMMON(dev); + GICv3ITSState *s = ARM_GICV3_ITS_COMMON(obj); GICv3ITSClass *c = ARM_GICV3_ITS_GET_CLASS(s); - c->parent_reset(dev); + if (c->parent_phases.hold) { + c->parent_phases.hold(obj); + } /* Quiescent bit reset to 1 */ s->ctlr = FIELD_DP32(s->ctlr, GITS_CTLR, QUIESCENT, 1); @@ -2012,12 +2014,14 @@ static Property gicv3_its_props[] = { static void gicv3_its_class_init(ObjectClass *klass, void *data) { DeviceClass *dc = DEVICE_CLASS(klass); + ResettableClass *rc = RESETTABLE_CLASS(klass); GICv3ITSClass *ic = ARM_GICV3_ITS_CLASS(klass); GICv3ITSCommonClass *icc = ARM_GICV3_ITS_COMMON_CLASS(klass); dc->realize = gicv3_arm_its_realize; device_class_set_props(dc, gicv3_its_props); - device_class_set_parent_reset(dc, gicv3_its_reset, &ic->parent_reset); + resettable_class_set_parent_phases(rc, NULL, gicv3_its_reset_hold, NULL, + &ic->parent_phases); icc->post_load = gicv3_its_post_load; } From 227b5866c05168ea3539baa1fe60d5d5d67a6f5f Mon Sep 17 00:00:00 2001 From: Peter Maydell Date: Wed, 14 Dec 2022 14:27:13 +0000 Subject: [PATCH 25/28] hw/intc: Convert TYPE_KVM_ARM_ITS to 3-phase reset MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Convert the TYPE_KVM_ARM_ITS device to 3-phase reset. Signed-off-by: Peter Maydell Reviewed-by: Richard Henderson Reviewed-by: Philippe Mathieu-Daudé Message-id: 20221109161444.3397405-10-peter.maydell@linaro.org --- hw/intc/arm_gicv3_its_kvm.c | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/hw/intc/arm_gicv3_its_kvm.c b/hw/intc/arm_gicv3_its_kvm.c index 529c7bd494..7eda9fb86e 100644 --- a/hw/intc/arm_gicv3_its_kvm.c +++ b/hw/intc/arm_gicv3_its_kvm.c @@ -37,7 +37,7 @@ DECLARE_OBJ_CHECKERS(GICv3ITSState, KVMARMITSClass, struct KVMARMITSClass { GICv3ITSCommonClass parent_class; - void (*parent_reset)(DeviceState *dev); + ResettablePhases parent_phases; }; @@ -197,13 +197,15 @@ static void kvm_arm_its_post_load(GICv3ITSState *s) GITS_CTLR, &s->ctlr, true, &error_abort); } -static void kvm_arm_its_reset(DeviceState *dev) +static void kvm_arm_its_reset_hold(Object *obj) { - GICv3ITSState *s = ARM_GICV3_ITS_COMMON(dev); + GICv3ITSState *s = ARM_GICV3_ITS_COMMON(obj); KVMARMITSClass *c = KVM_ARM_ITS_GET_CLASS(s); int i; - c->parent_reset(dev); + if (c->parent_phases.hold) { + c->parent_phases.hold(obj); + } if (kvm_device_check_attr(s->dev_fd, KVM_DEV_ARM_VGIC_GRP_CTRL, KVM_DEV_ARM_ITS_CTRL_RESET)) { @@ -241,12 +243,14 @@ static Property kvm_arm_its_props[] = { static void kvm_arm_its_class_init(ObjectClass *klass, void *data) { DeviceClass *dc = DEVICE_CLASS(klass); + ResettableClass *rc = RESETTABLE_CLASS(klass); GICv3ITSCommonClass *icc = ARM_GICV3_ITS_COMMON_CLASS(klass); KVMARMITSClass *ic = KVM_ARM_ITS_CLASS(klass); dc->realize = kvm_arm_its_realize; device_class_set_props(dc, kvm_arm_its_props); - device_class_set_parent_reset(dc, kvm_arm_its_reset, &ic->parent_reset); + resettable_class_set_parent_phases(rc, NULL, kvm_arm_its_reset_hold, NULL, + &ic->parent_phases); icc->send_msi = kvm_its_send_msi; icc->pre_save = kvm_arm_its_pre_save; icc->post_load = kvm_arm_its_post_load; From 990f49cfd700ff72933949769276dfa5a74ce36e Mon Sep 17 00:00:00 2001 From: Schspa Shi Date: Wed, 14 Dec 2022 14:27:13 +0000 Subject: [PATCH 26/28] hw/arm/boot: set initrd with #address-cells type in fdt We use 32bit value for linux,initrd-[start/end], when we have loader_start > 4GB, there will be a wrong initrd_start passed to the kernel, and the kernel will report the following warning. [ 0.000000] ------------[ cut here ]------------ [ 0.000000] initrd not fully accessible via the linear mapping -- please check your bootloader ... [ 0.000000] WARNING: CPU: 0 PID: 0 at arch/arm64/mm/init.c:355 arm64_memblock_init+0x158/0x244 [ 0.000000] Modules linked in: [ 0.000000] CPU: 0 PID: 0 Comm: swapper Tainted: G W 6.1.0-rc3-13250-g30a0b95b1335-dirty #28 [ 0.000000] Hardware name: Horizon Sigi Virtual development board (DT) [ 0.000000] pstate: 600000c5 (nZCv daIF -PAN -UAO -TCO -DIT -SSBS BTYPE=--) [ 0.000000] pc : arm64_memblock_init+0x158/0x244 [ 0.000000] lr : arm64_memblock_init+0x158/0x244 [ 0.000000] sp : ffff800009273df0 [ 0.000000] x29: ffff800009273df0 x28: 0000001000cc0010 x27: 0000800000000000 [ 0.000000] x26: 000000000050a3e2 x25: ffff800008b46000 x24: ffff800008b46000 [ 0.000000] x23: ffff800008a53000 x22: ffff800009420000 x21: ffff800008a53000 [ 0.000000] x20: 0000000004000000 x19: 0000000004000000 x18: 00000000ffff1020 [ 0.000000] x17: 6568632065736165 x16: 6c70202d2d20676e x15: 697070616d207261 [ 0.000000] x14: 656e696c20656874 x13: 0a2e2e2e20726564 x12: 0000000000000000 [ 0.000000] x11: 0000000000000000 x10: 00000000ffffffff x9 : 0000000000000000 [ 0.000000] x8 : 0000000000000000 x7 : 796c6c756620746f x6 : 6e20647274696e69 [ 0.000000] x5 : ffff8000093c7c47 x4 : ffff800008a2102f x3 : ffff800009273a88 [ 0.000000] x2 : 80000000fffff038 x1 : 00000000000000c0 x0 : 0000000000000056 [ 0.000000] Call trace: [ 0.000000] arm64_memblock_init+0x158/0x244 [ 0.000000] setup_arch+0x164/0x1cc [ 0.000000] start_kernel+0x94/0x4ac [ 0.000000] __primary_switched+0xb4/0xbc [ 0.000000] ---[ end trace 0000000000000000 ]--- [ 0.000000] Zone ranges: [ 0.000000] DMA [mem 0x0000001000000000-0x0000001007ffffff] This doesn't affect any machine types we currently support, because for all of our machine types the RAM starts well below the 4GB mark, but it does demonstrate that we're not currently writing the device-tree properties quite as intended. To fix it, we can change it to write these values to the dtb using a type width matching #address-cells. This is the intended size for these dtb properties, and is how u-boot, for instance, writes them, although in practice the Linux kernel will cope with them being any width as long as they're big enough to fit the value. Signed-off-by: Schspa Shi Message-id: 20221129160724.75667-1-schspa@gmail.com [PMM: tweaked commit message] Reviewed-by: Peter Maydell Signed-off-by: Peter Maydell --- hw/arm/boot.c | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/hw/arm/boot.c b/hw/arm/boot.c index 15c2bf1867..3d7d11f782 100644 --- a/hw/arm/boot.c +++ b/hw/arm/boot.c @@ -656,15 +656,17 @@ int arm_load_dtb(hwaddr addr, const struct arm_boot_info *binfo, } if (binfo->initrd_size) { - rc = qemu_fdt_setprop_cell(fdt, "/chosen", "linux,initrd-start", - binfo->initrd_start); + rc = qemu_fdt_setprop_sized_cells(fdt, "/chosen", "linux,initrd-start", + acells, binfo->initrd_start); if (rc < 0) { fprintf(stderr, "couldn't set /chosen/linux,initrd-start\n"); goto fail; } - rc = qemu_fdt_setprop_cell(fdt, "/chosen", "linux,initrd-end", - binfo->initrd_start + binfo->initrd_size); + rc = qemu_fdt_setprop_sized_cells(fdt, "/chosen", "linux,initrd-end", + acells, + binfo->initrd_start + + binfo->initrd_size); if (rc < 0) { fprintf(stderr, "couldn't set /chosen/linux,initrd-end\n"); goto fail; From 3d81e8cf0c81b8b63d7d7056c450dd94bfbfd038 Mon Sep 17 00:00:00 2001 From: Thomas Huth Date: Wed, 14 Dec 2022 14:27:14 +0000 Subject: [PATCH 27/28] hw/misc: Move some arm-related files from specific_ss into softmmu_ss MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The header target/arm/kvm-consts.h checks CONFIG_KVM which is marked as poisoned in common code, so the files that include this header have to be added to specific_ss and recompiled for each, qemu-system-arm and qemu-system-aarch64. However, since the kvm headers are only optionally used in kvm-constants.h for some sanity checks, we can additionally check the NEED_CPU_H macro first to avoid the poisoned CONFIG_KVM macro, so kvm-constants.h can also be used from "common" files (without the sanity checks - which should be OK since they are still done from other target-specific files instead). This way, and by adjusting some other include statements in the related files here and there, we can move some files from specific_ss into softmmu_ss, so that they only need to be compiled once during the build process. Signed-off-by: Thomas Huth Reviewed-by: Philippe Mathieu-Daudé Message-id: 20221202154023.293614-1-thuth@redhat.com Signed-off-by: Peter Maydell --- hw/misc/imx6_src.c | 2 +- hw/misc/iotkit-sysctl.c | 1 - hw/misc/meson.build | 11 +++++------ include/hw/misc/xlnx-zynqmp-apu-ctrl.h | 2 +- target/arm/kvm-consts.h | 8 ++++---- 5 files changed, 11 insertions(+), 13 deletions(-) diff --git a/hw/misc/imx6_src.c b/hw/misc/imx6_src.c index 7b0e968804..a9c64d06eb 100644 --- a/hw/misc/imx6_src.c +++ b/hw/misc/imx6_src.c @@ -15,7 +15,7 @@ #include "qemu/log.h" #include "qemu/main-loop.h" #include "qemu/module.h" -#include "arm-powerctl.h" +#include "target/arm/arm-powerctl.h" #include "hw/core/cpu.h" #ifndef DEBUG_IMX6_SRC diff --git a/hw/misc/iotkit-sysctl.c b/hw/misc/iotkit-sysctl.c index 7147e2f84e..e664215ee6 100644 --- a/hw/misc/iotkit-sysctl.c +++ b/hw/misc/iotkit-sysctl.c @@ -30,7 +30,6 @@ #include "hw/qdev-properties.h" #include "hw/arm/armsse-version.h" #include "target/arm/arm-powerctl.h" -#include "target/arm/cpu.h" REG32(SECDBGSTAT, 0x0) REG32(SECDBGSET, 0x4) diff --git a/hw/misc/meson.build b/hw/misc/meson.build index 95268eddc0..ed0598dc9e 100644 --- a/hw/misc/meson.build +++ b/hw/misc/meson.build @@ -51,6 +51,7 @@ softmmu_ss.add(when: 'CONFIG_IMX', if_true: files( 'imx25_ccm.c', 'imx31_ccm.c', 'imx6_ccm.c', + 'imx6_src.c', 'imx6ul_ccm.c', 'imx7_ccm.c', 'imx7_gpr.c', @@ -84,8 +85,8 @@ softmmu_ss.add(when: 'CONFIG_RASPI', if_true: files( )) softmmu_ss.add(when: 'CONFIG_SLAVIO', if_true: files('slavio_misc.c')) softmmu_ss.add(when: 'CONFIG_ZYNQ', if_true: files('zynq_slcr.c')) -specific_ss.add(when: 'CONFIG_XLNX_ZYNQMP_ARM', if_true: files('xlnx-zynqmp-crf.c')) -specific_ss.add(when: 'CONFIG_XLNX_ZYNQMP_ARM', if_true: files('xlnx-zynqmp-apu-ctrl.c')) +softmmu_ss.add(when: 'CONFIG_XLNX_ZYNQMP_ARM', if_true: files('xlnx-zynqmp-crf.c')) +softmmu_ss.add(when: 'CONFIG_XLNX_ZYNQMP_ARM', if_true: files('xlnx-zynqmp-apu-ctrl.c')) specific_ss.add(when: 'CONFIG_XLNX_VERSAL', if_true: files('xlnx-versal-crl.c')) softmmu_ss.add(when: 'CONFIG_XLNX_VERSAL', if_true: files( 'xlnx-versal-xramc.c', @@ -101,6 +102,7 @@ softmmu_ss.add(when: 'CONFIG_TZ_MPC', if_true: files('tz-mpc.c')) softmmu_ss.add(when: 'CONFIG_TZ_MSC', if_true: files('tz-msc.c')) softmmu_ss.add(when: 'CONFIG_TZ_PPC', if_true: files('tz-ppc.c')) softmmu_ss.add(when: 'CONFIG_IOTKIT_SECCTL', if_true: files('iotkit-secctl.c')) +softmmu_ss.add(when: 'CONFIG_IOTKIT_SYSCTL', if_true: files('iotkit-sysctl.c')) softmmu_ss.add(when: 'CONFIG_IOTKIT_SYSINFO', if_true: files('iotkit-sysinfo.c')) softmmu_ss.add(when: 'CONFIG_ARMSSE_CPU_PWRCTRL', if_true: files('armsse-cpu-pwrctrl.c')) softmmu_ss.add(when: 'CONFIG_ARMSSE_CPUID', if_true: files('armsse-cpuid.c')) @@ -126,15 +128,12 @@ softmmu_ss.add(when: 'CONFIG_GRLIB', if_true: files('grlib_ahb_apb_pnp.c')) specific_ss.add(when: 'CONFIG_AVR_POWER', if_true: files('avr_power.c')) -specific_ss.add(when: 'CONFIG_IMX', if_true: files('imx6_src.c')) -specific_ss.add(when: 'CONFIG_IOTKIT_SYSCTL', if_true: files('iotkit-sysctl.c')) - specific_ss.add(when: 'CONFIG_MAC_VIA', if_true: files('mac_via.c')) specific_ss.add(when: 'CONFIG_MIPS_CPS', if_true: files('mips_cmgcr.c', 'mips_cpc.c')) specific_ss.add(when: 'CONFIG_MIPS_ITU', if_true: files('mips_itu.c')) -specific_ss.add(when: 'CONFIG_SBSA_REF', if_true: files('sbsa_ec.c')) +softmmu_ss.add(when: 'CONFIG_SBSA_REF', if_true: files('sbsa_ec.c')) # HPPA devices softmmu_ss.add(when: 'CONFIG_LASI', if_true: files('lasi.c')) diff --git a/include/hw/misc/xlnx-zynqmp-apu-ctrl.h b/include/hw/misc/xlnx-zynqmp-apu-ctrl.h index b8ca9434af..c3bf3c1583 100644 --- a/include/hw/misc/xlnx-zynqmp-apu-ctrl.h +++ b/include/hw/misc/xlnx-zynqmp-apu-ctrl.h @@ -13,7 +13,7 @@ #include "hw/sysbus.h" #include "hw/register.h" -#include "target/arm/cpu.h" +#include "target/arm/cpu-qom.h" #define TYPE_XLNX_ZYNQMP_APU_CTRL "xlnx.apu-ctrl" OBJECT_DECLARE_SIMPLE_TYPE(XlnxZynqMPAPUCtrl, XLNX_ZYNQMP_APU_CTRL) diff --git a/target/arm/kvm-consts.h b/target/arm/kvm-consts.h index faacf96fdc..09967ec5e6 100644 --- a/target/arm/kvm-consts.h +++ b/target/arm/kvm-consts.h @@ -14,16 +14,16 @@ #ifndef ARM_KVM_CONSTS_H #define ARM_KVM_CONSTS_H +#ifdef NEED_CPU_H #ifdef CONFIG_KVM #include #include - #define MISMATCH_CHECK(X, Y) QEMU_BUILD_BUG_ON(X != Y) +#endif +#endif -#else - +#ifndef MISMATCH_CHECK #define MISMATCH_CHECK(X, Y) QEMU_BUILD_BUG_ON(0) - #endif #define CP_REG_SIZE_SHIFT 52 From 9e406eea309bbe44c7fb17f6af112d2b756854ad Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Wed, 14 Dec 2022 14:27:14 +0000 Subject: [PATCH 28/28] target/arm: Restrict arm_cpu_exec_interrupt() to TCG accelerator MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit When building with --disable-tcg on Darwin we get: target/arm/cpu.c:725:16: error: incomplete definition of type 'struct TCGCPUOps' cc->tcg_ops->do_interrupt(cs); ~~~~~~~~~~~^ Commit 083afd18a9 ("target/arm: Restrict cpu_exec_interrupt() handler to sysemu") limited this block to system emulation, but neglected to also limit it to TCG. Signed-off-by: Philippe Mathieu-Daudé Reviewed-by: Fabiano Rosas Message-id: 20221209110823.59495-1-philmd@linaro.org Signed-off-by: Peter Maydell --- target/arm/cpu.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/target/arm/cpu.c b/target/arm/cpu.c index 38d066c294..0f55004d7e 100644 --- a/target/arm/cpu.c +++ b/target/arm/cpu.c @@ -528,7 +528,7 @@ static void arm_cpu_reset(DeviceState *dev) arm_rebuild_hflags(env); } -#ifndef CONFIG_USER_ONLY +#if defined(CONFIG_TCG) && !defined(CONFIG_USER_ONLY) static inline bool arm_excp_unmasked(CPUState *cs, unsigned int excp_idx, unsigned int target_el, @@ -725,7 +725,8 @@ static bool arm_cpu_exec_interrupt(CPUState *cs, int interrupt_request) cc->tcg_ops->do_interrupt(cs); return true; } -#endif /* !CONFIG_USER_ONLY */ + +#endif /* CONFIG_TCG && !CONFIG_USER_ONLY */ void arm_cpu_update_virq(ARMCPU *cpu) {