diff --git a/tools/packaging/qemu/patches/6.1.x/0001-arm-cpuhp-Add-QMP-vcpu-params-validation-support.patch b/tools/packaging/qemu/patches/6.1.x/0001-arm-cpuhp-Add-QMP-vcpu-params-validation-support.patch new file mode 100644 index 0000000000..3625d7bb20 --- /dev/null +++ b/tools/packaging/qemu/patches/6.1.x/0001-arm-cpuhp-Add-QMP-vcpu-params-validation-support.patch @@ -0,0 +1,79 @@ +From cbc35b3747ff8c50e64e3b8aeecf1b782ee27cad Mon Sep 17 00:00:00 2001 +From: Huang Shijie +Date: Mon, 22 Nov 2021 17:51:11 +0800 +Subject: [PATCH 01/28] arm/cpuhp: Add QMP vcpu params validation support + +From Salil Mehta +For now, vcpu hotplug is only supported with single socket single thread, +single die. NUMA is not supported either and everthing falls into single +node. Work to properly support these could be taken later once community +agrees with the base framework changes being presented to support ARM vcpu +hotplug in QEMU. Hence, these checks. + +Co-developed-by: Keqian Zhu +Signed-off-by: Salil Mehta +Signed-off-by: Huang Shijie +--- + hw/arm/virt.c | 39 +++++++++++++++++++++++++++++++++++++++ + 1 file changed, 39 insertions(+) + +diff --git a/hw/arm/virt.c b/hw/arm/virt.c +index 81eda46b0b..99d59fada2 100644 +--- a/hw/arm/virt.c ++++ b/hw/arm/virt.c +@@ -2564,6 +2564,44 @@ static HotplugHandler *virt_machine_get_hotplug_handler(MachineState *machine, + return NULL; + } + ++static void virt_smp_parse(MachineState *ms, SMPConfiguration *config, Error **errp) ++{ ++ unsigned cpus = config->has_cpus ? config->cpus : 1; ++ unsigned sockets = config->has_sockets ? config->sockets: 1; ++ unsigned cores = config->has_cores ? config->cores : cpus; ++ unsigned threads = config->has_threads ? config->threads: 1; ++ unsigned int max_cpus; ++ ++ if (sockets > 1 || threads > 1) { ++ error_report("does not support more than one socket or thread"); ++ exit(1); ++ } ++ ++ if (cores != cpus) { ++ error_report("cpu topology: " ++ "sockets (%u) * cores (%u) * threads (%u) < " ++ "smp_cpus (%u)", ++ sockets, cores, threads, cpus); ++ exit(1); ++ } ++ ++ max_cpus = config->has_maxcpus ? config->maxcpus : cpus; ++ if (sockets * cores * threads > max_cpus) { ++ error_report("cpu topology: " ++ "sockets (%u) * cores (%u) * threads (%u) > " ++ "maxcpus (%u)", ++ sockets, cores, threads, ++ max_cpus); ++ exit(1); ++ } ++ ++ ms->smp.max_cpus = max_cpus; ++ ms->smp.sockets = sockets; ++ ms->smp.cpus = cpus; ++ ms->smp.cores = cores; ++ ms->smp.threads = threads; ++} ++ + /* + * for arm64 kvm_type [7-0] encodes the requested number of bits + * in the IPA address space +@@ -2641,6 +2679,7 @@ static void virt_machine_class_init(ObjectClass *oc, void *data) + mc->auto_enable_numa_with_memhp = true; + mc->auto_enable_numa_with_memdev = true; + mc->default_ram_id = "mach-virt.ram"; ++ mc->smp_parse = virt_smp_parse; + + object_class_property_add(oc, "acpi", "OnOffAuto", + virt_get_acpi, virt_set_acpi, +-- +2.30.2 + diff --git a/tools/packaging/qemu/patches/6.1.x/0002-arm-cpuhp-Add-new-ARMCPU-core-id-property.patch b/tools/packaging/qemu/patches/6.1.x/0002-arm-cpuhp-Add-new-ARMCPU-core-id-property.patch new file mode 100644 index 0000000000..48e62b9934 --- /dev/null +++ b/tools/packaging/qemu/patches/6.1.x/0002-arm-cpuhp-Add-new-ARMCPU-core-id-property.patch @@ -0,0 +1,101 @@ +From a24ce04b7c2e958a0730f19e6f54e6570a075b20 Mon Sep 17 00:00:00 2001 +From: Salil Mehta +Date: Tue, 23 Nov 2021 15:08:45 +0800 +Subject: [PATCH 02/28] arm/cpuhp: Add new ARMCPU core-id property + +This shall be used to store user specified core index and shall be directly +used as slot-index during hot{plug|unplug} of vcpu. + +For now, we are not taking into account of other topology info like thread-id, +socket-id to derive mp-affinity. Host KVM uses vcpu-id to derive the mpidr for +the vcpu of the guest. This is not in exact corroboration with the ARM spec +view of the MPIDR. Hence, the concept of threads or SMT bit present as part of +the MPIDR_EL1 also gets lost. + +Also, we need ACPI PPTT Table support in QEMU to be able to export this +topology info to the guest VM and the info should be consistent with what host +cpu supports if accel=kvm is being used. + +Perhaps some comments on this will help? @Andrew/drjones@redhat.com + +Co-developed-by: Keqian Zhu +Signed-off-by: Salil Mehta +Signed-off-by: Huang Shijie +--- + hw/arm/virt.c | 5 +++++ + target/arm/cpu.c | 5 +++++ + target/arm/cpu.h | 1 + + 3 files changed, 11 insertions(+) + +diff --git a/hw/arm/virt.c b/hw/arm/virt.c +index 99d59fada2..86e1470925 100644 +--- a/hw/arm/virt.c ++++ b/hw/arm/virt.c +@@ -1944,6 +1944,7 @@ static void machvirt_init(MachineState *machine) + &error_fatal); + + aarch64 &= object_property_get_bool(cpuobj, "aarch64", NULL); ++ object_property_set_int(cpuobj, "core-id", n, NULL); + + if (!vms->secure) { + object_property_set_bool(cpuobj, "has_el3", false, NULL); +@@ -2357,6 +2358,7 @@ static const CPUArchIdList *virt_possible_cpu_arch_ids(MachineState *ms) + { + int n; + unsigned int max_cpus = ms->smp.max_cpus; ++ unsigned int smp_threads = ms->smp.threads; + VirtMachineState *vms = VIRT_MACHINE(ms); + + if (ms->possible_cpus) { +@@ -2369,10 +2371,13 @@ static const CPUArchIdList *virt_possible_cpu_arch_ids(MachineState *ms) + ms->possible_cpus->len = max_cpus; + for (n = 0; n < ms->possible_cpus->len; n++) { + ms->possible_cpus->cpus[n].type = ms->cpu_type; ++ ms->possible_cpus->cpus[n].vcpus_count = smp_threads; + ms->possible_cpus->cpus[n].arch_id = + virt_cpu_mp_affinity(vms, n); + ms->possible_cpus->cpus[n].props.has_thread_id = true; + ms->possible_cpus->cpus[n].props.thread_id = n; ++ ms->possible_cpus->cpus[n].props.has_core_id = true; ++ ms->possible_cpus->cpus[n].props.core_id = n; + } + return ms->possible_cpus; + } +diff --git a/target/arm/cpu.c b/target/arm/cpu.c +index 2866dd7658..5dc3fa6c3a 100644 +--- a/target/arm/cpu.c ++++ b/target/arm/cpu.c +@@ -1130,6 +1130,9 @@ static Property arm_cpu_has_dsp_property = + static Property arm_cpu_has_mpu_property = + DEFINE_PROP_BOOL("has-mpu", ARMCPU, has_mpu, true); + ++static Property arm_cpu_coreid_property = ++ DEFINE_PROP_INT32("core-id", ARMCPU, core_id, -1); ++ + /* This is like DEFINE_PROP_UINT32 but it doesn't set the default value, + * because the CPU initfn will have already set cpu->pmsav7_dregion to + * the right value for that particular CPU type, and we don't want +@@ -1303,6 +1306,8 @@ void arm_cpu_post_init(Object *obj) + kvm_arm_add_vcpu_properties(obj); + } + ++ qdev_property_add_static(DEVICE(obj), &arm_cpu_coreid_property); ++ + #ifndef CONFIG_USER_ONLY + if (arm_feature(&cpu->env, ARM_FEATURE_AARCH64) && + cpu_isar_feature(aa64_mte, cpu)) { +diff --git a/target/arm/cpu.h b/target/arm/cpu.h +index 9f0a5f84d5..ba11468ab5 100644 +--- a/target/arm/cpu.h ++++ b/target/arm/cpu.h +@@ -999,6 +999,7 @@ struct ARMCPU { + QLIST_HEAD(, ARMELChangeHook) el_change_hooks; + + int32_t node_id; /* NUMA node this CPU belongs to */ ++ int32_t core_id; /* core-id of this ARM VCPU */ + + /* Used to synchronize KVM and QEMU in-kernel device levels */ + uint8_t device_irq_level; +-- +2.30.2 + diff --git a/tools/packaging/qemu/patches/6.1.x/0003-arm-cpuhp-Add-common-cpu-utility-for-possible-vcpus.patch b/tools/packaging/qemu/patches/6.1.x/0003-arm-cpuhp-Add-common-cpu-utility-for-possible-vcpus.patch new file mode 100644 index 0000000000..c01c4454dd --- /dev/null +++ b/tools/packaging/qemu/patches/6.1.x/0003-arm-cpuhp-Add-common-cpu-utility-for-possible-vcpus.patch @@ -0,0 +1,97 @@ +From cf832166791bddea562ba9372795db04ea41a581 Mon Sep 17 00:00:00 2001 +From: Salil Mehta +Date: Tue, 23 Nov 2021 15:22:27 +0800 +Subject: [PATCH 03/28] arm/cpuhp: Add common cpu utility for possible vcpus + +Adds various utility functions which might be required to fetch or check the +state of the possible vcpus. This also introduces concept of *disabled* vcpus, +which are part of the *possible* vcpus but are not part of the *present* vcpu. +This state shall be used during machine init time to check the presence of +vcpus. + +Co-developed-by: Keqian Zhu +Signed-off-by: Salil Mehta +--- + cpus-common.c | 19 +++++++++++++++++++ + include/hw/core/cpu.h | 21 +++++++++++++++++++++ + 2 files changed, 40 insertions(+) + +diff --git a/cpus-common.c b/cpus-common.c +index 6e73d3e58d..4f0fa42a2e 100644 +--- a/cpus-common.c ++++ b/cpus-common.c +@@ -23,6 +23,7 @@ + #include "hw/core/cpu.h" + #include "sysemu/cpus.h" + #include "qemu/lockable.h" ++#include "hw/boards.h" + + static QemuMutex qemu_cpu_list_lock; + static QemuCond exclusive_cond; +@@ -86,6 +87,24 @@ void cpu_list_add(CPUState *cpu) + QTAILQ_INSERT_TAIL_RCU(&cpus, cpu, node); + } + ++CPUState *qemu_get_possible_cpu(int index) ++{ ++ MachineState *ms = MACHINE(qdev_get_machine()); ++ const CPUArchIdList *possible_cpus = ms->possible_cpus; ++ CPUState *cpu; ++ ++ assert((index >= 0) && (index < possible_cpus->len)); ++ ++ cpu = CPU(possible_cpus->cpus[index].cpu); ++ ++ return cpu; ++} ++ ++bool qemu_present_cpu(CPUState *cpu) ++{ ++ return (cpu && !cpu->disabled); ++} ++ + void cpu_list_remove(CPUState *cpu) + { + QEMU_LOCK_GUARD(&qemu_cpu_list_lock); +diff --git a/include/hw/core/cpu.h b/include/hw/core/cpu.h +index bc864564ce..5a2571af3e 100644 +--- a/include/hw/core/cpu.h ++++ b/include/hw/core/cpu.h +@@ -391,6 +391,7 @@ struct CPUState { + SavedIOTLB saved_iotlb; + #endif + ++ bool disabled; + /* TODO Move common fields from CPUArchState here. */ + int cpu_index; + int cluster_index; +@@ -749,6 +750,26 @@ static inline bool cpu_in_exclusive_context(const CPUState *cpu) + */ + CPUState *qemu_get_cpu(int index); + ++/** ++ * qemu_get_possible_cpu: ++ * @index: The CPUState@cpu_index value of the CPU to obtain. ++ * ++ * Gets a CPU matching @index. ++ * ++ * Returns: The possible CPU or %NULL if there is no matching CPU. ++ */ ++CPUState *qemu_get_possible_cpu(int index); ++ ++/** ++ * qemu_present_cpu: ++ * @cpu: The vCPU to check ++ * ++ * Checks if the vcpu is amongst the present possible vcpus. ++ * ++ * Returns: True if it is present possible vcpu else false ++ */ ++bool qemu_present_cpu(CPUState *cpu); ++ + /** + * cpu_exists: + * @id: Guest-exposed CPU ID to lookup. +-- +2.30.2 + diff --git a/tools/packaging/qemu/patches/6.1.x/0004-arm-cpuhp-Machine-init-time-change-common-to-vcpu-co.patch b/tools/packaging/qemu/patches/6.1.x/0004-arm-cpuhp-Machine-init-time-change-common-to-vcpu-co.patch new file mode 100644 index 0000000000..8350ea7b94 --- /dev/null +++ b/tools/packaging/qemu/patches/6.1.x/0004-arm-cpuhp-Machine-init-time-change-common-to-vcpu-co.patch @@ -0,0 +1,447 @@ +From 0de9776b56a8848f28bdd21332dff50fac12bca4 Mon Sep 17 00:00:00 2001 +From: Salil Mehta +Date: Tue, 23 Nov 2021 16:30:39 +0800 +Subject: [PATCH 04/28] arm/cpuhp: Machine init time change common to vcpu + {cold|hot}-plug + +This refactors (+) introduces the common logic required during the +initialization of both cold and hot plugged vcpus. This also initializes the +*disabled* state of the vcpus which shall be used further during init phases +of various other components like GIC, PMU, ACPI etc as part of the virt machine +initialization. + +Co-developed-by: Keqian Zhu +Signed-off-by: Salil Mehta +Signed-off-by: Huang Shijie +--- + hw/arm/virt.c | 226 +++++++++++++++++++++++++++++++++++++++--- + include/hw/arm/virt.h | 2 + + target/arm/cpu.c | 7 ++ + target/arm/cpu64.c | 8 ++ + 4 files changed, 228 insertions(+), 15 deletions(-) + +diff --git a/hw/arm/virt.c b/hw/arm/virt.c +index 86e1470925..81219d1d5a 100644 +--- a/hw/arm/virt.c ++++ b/hw/arm/virt.c +@@ -204,6 +204,8 @@ static const char *valid_cpus[] = { + ARM_CPU_TYPE_NAME("max"), + }; + ++static CPUArchId *virt_find_cpu_slot(MachineState *ms, int vcpuid); ++ + static bool cpu_type_valid(const char *cpu) + { + int i; +@@ -1750,6 +1752,62 @@ static void finalize_gic_version(VirtMachineState *vms) + } + } + ++static void virt_cpu_set_properties(Object *cpuobj, const CPUArchId *cpu_slot) ++{ ++ MachineState *ms = MACHINE(qdev_get_machine()); ++ MemoryRegion *sysmem = get_system_memory(); ++ VirtMachineState *vms = VIRT_MACHINE(ms); ++ uint64_t mp_affinity = cpu_slot->arch_id; ++ CPUState *cs = CPU(cpuobj); ++ VirtMachineClass *vmc; ++ ++ vmc = VIRT_MACHINE_GET_CLASS(ms); ++ ++ /* now, set the cpu object property values */ ++ object_property_set_int(cpuobj, "mp-affinity", mp_affinity, NULL); ++ ++ numa_cpu_pre_plug(cpu_slot, DEVICE(cpuobj), &error_fatal); ++ ++ if (!vms->secure) { ++ object_property_set_bool(cpuobj, "has_el3", false, NULL); ++ } ++ ++ if (!vms->virt && object_property_find(cpuobj, "has_el2")) { ++ object_property_set_bool(cpuobj, "has_el2", false, NULL); ++ } ++ ++ if (vms->psci_conduit != QEMU_PSCI_CONDUIT_DISABLED) { ++ object_property_set_int(cpuobj, "psci-conduit", vms->psci_conduit, ++ NULL); ++ /* Secondary CPUs start in PSCI powered-down state */ ++ if (cs->cpu_index > 0) ++ object_property_set_bool(cpuobj, "start-powered-off", true, ++ NULL); ++ } ++ ++ if (vmc->kvm_no_adjvtime && ++ object_property_find(cpuobj, "kvm-no-adjvtime")) { ++ object_property_set_bool(cpuobj, "kvm-no-adjvtime", true, NULL); ++ } ++ ++ if (vmc->no_pmu && object_property_find(cpuobj, "pmu")) { ++ object_property_set_bool(cpuobj, "pmu", false, NULL); ++ } ++ ++ if (object_property_find(cpuobj, "reset-cbar")) { ++ object_property_set_int(cpuobj, "reset-cbar", vms->memmap[VIRT_CPUPERIPHS].base, ++ &error_abort); ++ } ++ ++ object_property_set_link(cpuobj, "memory", OBJECT(sysmem), ++ &error_abort); ++ ++ if (vms->secure) { ++ object_property_set_link(cpuobj, "secure-memory", OBJECT(vms->secure_sysmem), ++ &error_abort); ++ } ++} ++ + /* + * virt_cpu_post_init() must be called after the CPUs have + * been realized and the GIC has been created. +@@ -1867,6 +1925,7 @@ static void machvirt_init(MachineState *machine) + memory_region_init(secure_sysmem, OBJECT(machine), "secure-memory", + UINT64_MAX); + memory_region_add_subregion_overlap(secure_sysmem, 0, sysmem, -1); ++ vms->secure_sysmem = secure_sysmem; + } + + firmware_loaded = virt_firmware_init(vms, sysmem, +@@ -1909,6 +1968,15 @@ static void machvirt_init(MachineState *machine) + exit(1); + } + ++ vms->max_cpus = max_cpus; ++ if (vms->gic_version < VIRT_GIC_VERSION_3) { ++ warn_report("For GICv%d max-cpus must be equal to smp-cpus", ++ vms->gic_version); ++ warn_report("Overriding specified max-cpus(%d) with smp-cpus(%d)", ++ max_cpus, smp_cpus); ++ vms->max_cpus = smp_cpus; ++ } ++ + if (vms->virt && kvm_enabled()) { + error_report("mach-virt: KVM does not support providing " + "Virtualization extensions to the guest CPU"); +@@ -1927,14 +1995,14 @@ static void machvirt_init(MachineState *machine) + assert(possible_cpus->len == max_cpus); + for (n = 0; n < possible_cpus->len; n++) { + Object *cpuobj; +- CPUState *cs; ++/* CPUState *cs; + + if (n >= smp_cpus) { + break; + } +- ++*/ + cpuobj = object_new(possible_cpus->cpus[n].type); +- object_property_set_int(cpuobj, "mp-affinity", ++/* object_property_set_int(cpuobj, "mp-affinity", + possible_cpus->cpus[n].arch_id, NULL); + + cs = CPU(cpuobj); +@@ -1942,11 +2010,11 @@ static void machvirt_init(MachineState *machine) + + numa_cpu_pre_plug(&possible_cpus->cpus[cs->cpu_index], DEVICE(cpuobj), + &error_fatal); +- ++*/ + aarch64 &= object_property_get_bool(cpuobj, "aarch64", NULL); + object_property_set_int(cpuobj, "core-id", n, NULL); + +- if (!vms->secure) { ++/* if (!vms->secure) { + object_property_set_bool(cpuobj, "has_el3", false, NULL); + } + +@@ -1957,9 +2025,9 @@ static void machvirt_init(MachineState *machine) + if (vms->psci_conduit != QEMU_PSCI_CONDUIT_DISABLED) { + object_property_set_int(cpuobj, "psci-conduit", vms->psci_conduit, + NULL); +- ++*/ + /* Secondary CPUs start in PSCI powered-down state */ +- if (n > 0) { ++/* if (n > 0) { + object_property_set_bool(cpuobj, "start-powered-off", true, + NULL); + } +@@ -1991,15 +2059,15 @@ static void machvirt_init(MachineState *machine) + object_property_set_link(cpuobj, "secure-memory", + OBJECT(secure_sysmem), &error_abort); + } +- +- if (vms->mte) { ++*/ ++// if (vms->mte) { + /* Create the memory region only once, but link to all cpus. */ +- if (!tag_sysmem) { ++// if (!tag_sysmem) { + /* + * The property exists only if MemTag is supported. + * If it is, we must allocate the ram to back that up. + */ +- if (!object_property_find(cpuobj, "tag-memory")) { ++/* if (!object_property_find(cpuobj, "tag-memory")) { + error_report("MTE requested, but not supported " + "by the guest CPU"); + exit(1); +@@ -2013,9 +2081,9 @@ static void machvirt_init(MachineState *machine) + secure_tag_sysmem = g_new(MemoryRegion, 1); + memory_region_init(secure_tag_sysmem, OBJECT(machine), + "secure-tag-memory", UINT64_MAX / 32); +- ++*/ + /* As with ram, secure-tag takes precedence over tag. */ +- memory_region_add_subregion_overlap(secure_tag_sysmem, 0, ++/* memory_region_add_subregion_overlap(secure_tag_sysmem, 0, + tag_sysmem, -1); + } + } +@@ -2028,7 +2096,7 @@ static void machvirt_init(MachineState *machine) + &error_abort); + } + } +- ++*/ + qdev_realize(DEVICE(cpuobj), NULL, &error_fatal); + object_unref(cpuobj); + } +@@ -2382,6 +2450,71 @@ static const CPUArchIdList *virt_possible_cpu_arch_ids(MachineState *ms) + return ms->possible_cpus; + } + ++static int virt_archid_cmp(const void *a, const void *b) ++{ ++ CPUArchId *archid_a = (CPUArchId *)a; ++ CPUArchId *archid_b = (CPUArchId *)b; ++ ++ return archid_a->arch_id - archid_b->arch_id; ++} ++ ++static CPUArchId *virt_find_cpu_slot(MachineState *ms, int vcpuid) ++{ ++ VirtMachineState *vms = VIRT_MACHINE(ms); ++ CPUArchId arch_id, *found_cpu; ++ uint64_t mp_affinity; ++ ++ mp_affinity = virt_cpu_mp_affinity(vms, vcpuid); ++ arch_id.arch_id = mp_affinity; ++ found_cpu = bsearch(&arch_id, ms->possible_cpus->cpus, ++ ms->possible_cpus->len, ++ sizeof(*ms->possible_cpus->cpus), virt_archid_cmp); ++ ++ assert (found_cpu); ++ ++ /* ++ * RFC: Question: ++ * For KVM/TCG, MPIDR for vcpu is derived using vcpu-id. ++ * In fact, as of now there is a linear relation between ++ * vcpu-id and mpidr(see below fig.) as derived in host ++ * kvm. Slot-id is the index where vcpu with certain ++ * arch-id(=mpidr/ap-affinity) is plugged. ++ * ++ * Therefore, for now we could use the vcpu-id as slot ++ * index for getting CPUArchId of the vcpu coresponding ++ * to this slot(this view is not perfectly consistent ++ * with the ARM specification view of MPIDR_EL1). ++ * QEMU/KVM view of cpu topology makes it bit difficult ++ * to use topo-info(pkg-id, core-id, thread-id) with ++ * device_add/-device interface which might not match ++ * with what actual underlying host cpu supports. ++ * therefore question is do we care about this? and ++ * is it okay to have view of thread-id inconsistent ++ * with the host cpu? How should QEMU create PPTT ++ * for the Guest? ++ * ++ * +----+----+----+----+----+----+----+----+ ++ * MASK | F F | F F | F F | 0 F | ++ * +----+----+----+----+----+----+----+----+ ++ * ++ * | | cluster | cluster | |core| ++ * |<---------Package-id-------->| |core| ++ * ++ * +----+----+----+----+----+----+----+----+ ++ * MPIDR ||| Res | Aff2 | Aff1 | Aff0 | ++ * +----+----+----+----+----+----+----+----+ ++ * \ \ \ | | ++ * \ 8bit \ 8bit \ |4bit| ++ * \<------->\<------->\ |<-->| ++ * \ \ \| | ++ * +----+----+----+----+----+----+----+----+ ++ * VCPU-ID | Byte4 | Byte2 | Byte1 | Byte0 | ++ * +----+----+----+----+----+----+----+----+ ++ */ ++ ++ return found_cpu; ++} ++ + static void virt_memory_pre_plug(HotplugHandler *hotplug_dev, DeviceState *dev, + Error **errp) + { +@@ -2425,6 +2558,64 @@ static void virt_memory_plug(HotplugHandler *hotplug_dev, + dev, &error_abort); + } + ++static void virt_cpu_pre_plug(HotplugHandler *hotplug_dev, DeviceState *dev, ++ Error **errp) ++{ ++ MachineState *ms = MACHINE(hotplug_dev); ++ ARMCPU *cpu = ARM_CPU(dev); ++ CPUState *cs = CPU(dev); ++ CPUArchId *cpu_slot; ++ ++ /* sanity check the cpu */ ++ if (!object_dynamic_cast(OBJECT(cpu), ms->cpu_type)) { ++ error_setg(errp, "Invalid CPU type, expected cpu type: '%s'", ++ ms->cpu_type); ++ return; ++ } ++ ++ if ((cpu->core_id < 0) || (cpu->core_id >= ms->possible_cpus->len)) { ++ error_setg(errp, "Invalid core-id %u specified, must be in range 1:%u", ++ cpu->core_id, ms->possible_cpus->len - 1); ++ return; ++ } ++ ++ /* ++ * RFC: Question: ++ * For now we are not taking into account of other topo info like ++ * thread-id, socket-id to generate arch-id/mp-affinity. ++ * The way KVM/Host generates mpidr value and the way ARM spec ++ * identifies uniquely cpu within the heirarchy is bit inconsistent. ++ * Perhaps needs more discussion on this? Hence, directly using ++ * core_id as cpu_index for now. Ideally, slot-index found out using ++ * the topo info should have been the cpu-index. ++ */ ++ cs->cpu_index = cpu->core_id; ++ ++ cpu_slot = virt_find_cpu_slot(ms, cpu->core_id); ++ if (qemu_present_cpu(CPU(cpu_slot->cpu))) { ++ error_setg(errp, "cpu %d with arch-id %" PRIu64 " exists", ++ cpu->core_id, cpu_slot->arch_id); ++ return; ++ } ++ virt_cpu_set_properties(OBJECT(cs), cpu_slot); ++} ++ ++static void virt_cpu_plug(HotplugHandler *hotplug_dev, DeviceState *dev, ++ Error **errp) ++{ ++ MachineState *ms = MACHINE(hotplug_dev); ++ ARMCPU *cpu = ARM_CPU(dev); ++ CPUState *cs = CPU(dev); ++ CPUArchId *cpu_slot; ++ ++ /* insert the cold/hot-plugged vcpu in the slot */ ++ cpu_slot = virt_find_cpu_slot(ms, cpu->core_id); ++ cpu_slot->cpu = OBJECT(dev); ++ ++ cs->disabled = false; ++ return; ++} ++ + static void virt_machine_device_pre_plug_cb(HotplugHandler *hotplug_dev, + DeviceState *dev, Error **errp) + { +@@ -2432,6 +2623,8 @@ static void virt_machine_device_pre_plug_cb(HotplugHandler *hotplug_dev, + + if (object_dynamic_cast(OBJECT(dev), TYPE_PC_DIMM)) { + virt_memory_pre_plug(hotplug_dev, dev, errp); ++ } else if (object_dynamic_cast(OBJECT(dev), TYPE_CPU)) { ++ virt_cpu_pre_plug(hotplug_dev, dev, errp); + } else if (object_dynamic_cast(OBJECT(dev), TYPE_VIRTIO_IOMMU_PCI)) { + hwaddr db_start = 0, db_end = 0; + char *resv_prop_str; +@@ -2476,6 +2669,8 @@ static void virt_machine_device_plug_cb(HotplugHandler *hotplug_dev, + } + if (object_dynamic_cast(OBJECT(dev), TYPE_PC_DIMM)) { + virt_memory_plug(hotplug_dev, dev, errp); ++ } else if (object_dynamic_cast(OBJECT(dev), TYPE_CPU)) { ++ virt_cpu_plug(hotplug_dev, dev, errp); + } + if (object_dynamic_cast(OBJECT(dev), TYPE_VIRTIO_IOMMU_PCI)) { + PCIDevice *pdev = PCI_DEVICE(dev); +@@ -2556,7 +2751,8 @@ static HotplugHandler *virt_machine_get_hotplug_handler(MachineState *machine, + MachineClass *mc = MACHINE_GET_CLASS(machine); + + if (device_is_dynamic_sysbus(mc, dev) || +- (object_dynamic_cast(OBJECT(dev), TYPE_PC_DIMM))) { ++ (object_dynamic_cast(OBJECT(dev), TYPE_PC_DIMM)) || ++ (object_dynamic_cast(OBJECT(dev), TYPE_CPU))) { + return HOTPLUG_HANDLER(machine); + } + if (object_dynamic_cast(OBJECT(dev), TYPE_VIRTIO_IOMMU_PCI)) { +diff --git a/include/hw/arm/virt.h b/include/hw/arm/virt.h +index 9661c46699..960812c66e 100644 +--- a/include/hw/arm/virt.h ++++ b/include/hw/arm/virt.h +@@ -137,6 +137,7 @@ struct VirtMachineState { + DeviceState *platform_bus_dev; + FWCfgState *fw_cfg; + PFlashCFI01 *flash[2]; ++ MemoryRegion *secure_sysmem; + bool secure; + bool highmem; + bool highmem_ecam; +@@ -155,6 +156,7 @@ struct VirtMachineState { + char *pciehb_nodename; + const int *irqmap; + int fdt_size; ++ int max_cpus; + uint32_t clock_phandle; + uint32_t gic_phandle; + uint32_t msi_phandle; +diff --git a/target/arm/cpu.c b/target/arm/cpu.c +index 5dc3fa6c3a..ff827d56b7 100644 +--- a/target/arm/cpu.c ++++ b/target/arm/cpu.c +@@ -2004,6 +2004,12 @@ static const struct TCGCPUOps arm_tcg_ops = { + }; + #endif /* CONFIG_TCG */ + ++static int64_t arm_cpu_get_arch_id(CPUState *cs) ++{ ++ ARMCPU *cpu = ARM_CPU(cs); ++ return cpu->mp_affinity; ++} ++ + static void arm_cpu_class_init(ObjectClass *oc, void *data) + { + ARMCPUClass *acc = ARM_CPU_CLASS(oc); +@@ -2019,6 +2025,7 @@ static void arm_cpu_class_init(ObjectClass *oc, void *data) + cc->class_by_name = arm_cpu_class_by_name; + cc->has_work = arm_cpu_has_work; + cc->dump_state = arm_cpu_dump_state; ++ cc->get_arch_id = arm_cpu_get_arch_id; + cc->set_pc = arm_cpu_set_pc; + cc->gdb_read_register = arm_cpu_gdb_read_register; + cc->gdb_write_register = arm_cpu_gdb_write_register; +diff --git a/target/arm/cpu64.c b/target/arm/cpu64.c +index c690318a9b..2134be0b67 100644 +--- a/target/arm/cpu64.c ++++ b/target/arm/cpu64.c +@@ -894,7 +894,10 @@ static gchar *aarch64_gdb_arch_name(CPUState *cs) + static void aarch64_cpu_class_init(ObjectClass *oc, void *data) + { + CPUClass *cc = CPU_CLASS(oc); ++ DeviceClass *dc = DEVICE_CLASS(oc); ++ CPUState *cs = CPU(oc); + ++ dc->user_creatable = true; + cc->gdb_read_register = aarch64_cpu_gdb_read_register; + cc->gdb_write_register = aarch64_cpu_gdb_write_register; + cc->gdb_num_core_regs = 34; +@@ -906,6 +909,11 @@ static void aarch64_cpu_class_init(ObjectClass *oc, void *data) + object_class_property_set_description(oc, "aarch64", + "Set on/off to enable/disable aarch64 " + "execution state "); ++ /* ++ * we start every ARM64 vcpu as disabled possible vcpu. It needs to be ++ * enabled explicitly ++ */ ++ cs->disabled = true; + } + + static void aarch64_cpu_instance_init(Object *obj) +-- +2.30.2 + diff --git a/tools/packaging/qemu/patches/6.1.x/0005-arm-cpuhp-Pre-create-disabled-possible-vcpus-machine.patch b/tools/packaging/qemu/patches/6.1.x/0005-arm-cpuhp-Pre-create-disabled-possible-vcpus-machine.patch new file mode 100644 index 0000000000..408bde0f26 --- /dev/null +++ b/tools/packaging/qemu/patches/6.1.x/0005-arm-cpuhp-Pre-create-disabled-possible-vcpus-machine.patch @@ -0,0 +1,243 @@ +From 1d9605a449833e464bd0388bb658d31a84ad4c7d Mon Sep 17 00:00:00 2001 +From: Salil Mehta +Date: Wed, 24 Nov 2021 15:30:20 +0800 +Subject: [PATCH 05/28] arm/cpuhp: Pre-create disabled possible vcpus @machine + init + +In ARMv8 architecture, GIC needs all the vcpus to be created and present when +it is initialized. This is because: +1. GICC and MPIDR association must be fixed at the VM initialization time. + This is represented by register GIC_TYPER(mp_afffinity, proc_num) +2. GICC(cpu interfaces), GICR(redistributors) etc all must be initialized + at the boot time as well. +3. Memory regions associated with GICR etc. cannot be changed(add/del/mod) + after VM has inited. + +This patch adds the support to pre-create all such possible vcpus within the +host using the KVM interface as part of the virt machine initialization. These +vcpus could later be attached to QOM/ACPI while they are actually hot plugged +and made present. + +NOTE: There is some refactoring related to the kvm_destroy_vcpu/kvm_get_vcpu + (to make use of the common code) has been intentionaly left out in RFC + version to avoid obscuring the framework change of the cpu hotplug. The + existing code being presented in this patch could further be optimized + later. + +Co-developed-by: Keqian Zhu +Signed-off-by: Salil Mehta +Signed-off-by: Huang Shijie +--- + accel/kvm/kvm-all.c | 31 +++++++++++++++++++++++++++ + accel/kvm/kvm-cpus.h | 2 ++ + hw/arm/virt.c | 50 +++++++++++++++++++++++++++++++++++++++++--- + target/arm/kvm.c | 33 +++++++++++++++++++++++++++++ + target/arm/kvm_arm.h | 11 ++++++++++ + 5 files changed, 124 insertions(+), 3 deletions(-) + +diff --git a/accel/kvm/kvm-all.c b/accel/kvm/kvm-all.c +index 0125c17edb..46717dad14 100644 +--- a/accel/kvm/kvm-all.c ++++ b/accel/kvm/kvm-all.c +@@ -425,6 +425,37 @@ err: + return ret; + } + ++void kvm_park_vcpu(CPUState *cs) ++{ ++ unsigned long vcpu_id = cs->cpu_index; ++ struct KVMParkedVcpu *vcpu; ++ ++ vcpu = g_malloc0(sizeof(*vcpu)); ++ vcpu->vcpu_id = vcpu_id; ++ vcpu->kvm_fd = cs->kvm_fd; ++ QLIST_INSERT_HEAD(&kvm_state->kvm_parked_vcpus, vcpu, node); ++} ++ ++int kvm_create_vcpu(CPUState *cpu) ++{ ++ unsigned long vcpu_id = cpu->cpu_index; ++ KVMState *s = kvm_state; ++ int ret = 0; ++ ++ DPRINTF("kvm_create_vcpu\n"); ++ ++ ret = kvm_vm_ioctl(s, KVM_CREATE_VCPU, (void *)vcpu_id); ++ if (ret < 0) { ++ goto err; ++ } ++ cpu->kvm_fd = ret; ++ cpu->kvm_state = s; ++ cpu->vcpu_dirty = true; ++ ++err: ++ return ret; ++} ++ + void kvm_destroy_vcpu(CPUState *cpu) + { + if (do_kvm_destroy_vcpu(cpu) < 0) { +diff --git a/accel/kvm/kvm-cpus.h b/accel/kvm/kvm-cpus.h +index bf0bd1bee4..54a4fd19cf 100644 +--- a/accel/kvm/kvm-cpus.h ++++ b/accel/kvm/kvm-cpus.h +@@ -14,6 +14,8 @@ + + int kvm_init_vcpu(CPUState *cpu, Error **errp); + int kvm_cpu_exec(CPUState *cpu); ++int kvm_create_vcpu(CPUState *cpu); ++void kvm_park_vcpu(CPUState *cs); + void kvm_destroy_vcpu(CPUState *cpu); + void kvm_cpu_synchronize_post_reset(CPUState *cpu); + void kvm_cpu_synchronize_post_init(CPUState *cpu); +diff --git a/hw/arm/virt.c b/hw/arm/virt.c +index 81219d1d5a..853288b34a 100644 +--- a/hw/arm/virt.c ++++ b/hw/arm/virt.c +@@ -1995,13 +1995,14 @@ static void machvirt_init(MachineState *machine) + assert(possible_cpus->len == max_cpus); + for (n = 0; n < possible_cpus->len; n++) { + Object *cpuobj; +-/* CPUState *cs; ++ CPUState *cs; + +- if (n >= smp_cpus) { ++/* if (n >= smp_cpus) { + break; + } + */ + cpuobj = object_new(possible_cpus->cpus[n].type); ++ cs = CPU(cpuobj); + /* object_property_set_int(cpuobj, "mp-affinity", + possible_cpus->cpus[n].arch_id, NULL); + +@@ -2096,9 +2097,52 @@ static void machvirt_init(MachineState *machine) + &error_abort); + } + } +-*/ ++ + qdev_realize(DEVICE(cpuobj), NULL, &error_fatal); + object_unref(cpuobj); ++*/ ++ if (n < smp_cpus) { ++ char *core_id = g_strdup_printf("core%d", n); ++ qdev_set_id(DEVICE(cpuobj),core_id); ++ object_property_set_bool(cpuobj, "realized", true, &error_fatal); ++ g_free(core_id); ++ object_unref(OBJECT(cs)); ++ } else { ++ CPUArchId *cpu_slot; ++ /* handling for vcpus which are yet to be hot-plugged */ ++ cs->cpu_index = n; cs->disabled=true; ++ /* ARM host vcpu features need to be fixed at the boot time */ ++ virt_cpu_set_properties(cpuobj, &possible_cpus->cpus[n]); ++ /* ++ * For KVM, we shall be pre-creating the now disabled/un-plugged ++ * possbile host vcpus and park them till the time they are ++ * actually hot plugged. This is required to pre-size the host ++ * GICC and GICR with the all possible vcpus for this VM. ++ */ ++ if (kvm_enabled()) { ++ kvm_arm_create_host_vcpu(ARM_CPU(cs)); ++ } ++ /* ++ * Add disabled vcpu to cpu slot during the init phase of the virt machine. ++ * 1. We need this ARMCPU object during the GIC init. This object ++ * will facilitate in pre-realizing the gic. Any info like ++ * mp-affinity(required to derive gicr_type) etc could still be ++ * fetched while preserving QOM abstraction akin to realized ++ * vcpus. ++ * 2. Now, after initialization of the virt machine is complete we could use ++ * two approaches to deal with this ARMCPU object: ++ * (i) re-use this ARMCPU object during hotplug of this vcpu. ++ * OR ++ * (ii) defer release this ARMCPU object after gic has been ++ * initialized or during pre-plug phase when a vcpu is ++ * hotplugged. ++ * ++ * We will use the (ii) approach and release the ARMCPU objects after GIC ++ * and machine has been initialized in machine_init_done() phase ++ */ ++ cpu_slot = virt_find_cpu_slot(machine, cs->cpu_index); ++ cpu_slot->cpu = OBJECT(cs); ++ } + } + fdt_add_timer_nodes(vms); + fdt_add_cpu_nodes(vms); +diff --git a/target/arm/kvm.c b/target/arm/kvm.c +index d8381ba224..bb75beec9d 100644 +--- a/target/arm/kvm.c ++++ b/target/arm/kvm.c +@@ -32,6 +32,7 @@ + #include "hw/boards.h" + #include "hw/irq.h" + #include "qemu/log.h" ++#include "accel/kvm/kvm-cpus.h" + + const KVMCapabilityInfo kvm_arch_required_capabilities[] = { + KVM_CAP_LAST_INFO +@@ -627,6 +628,38 @@ void kvm_arm_reset_vcpu(ARMCPU *cpu) + write_list_to_cpustate(cpu); + } + ++void kvm_arm_create_host_vcpu(ARMCPU *cpu) ++{ ++ CPUState *cs = CPU(cpu); ++ unsigned long vcpu_id = cs->cpu_index; ++ int ret; ++ ++ ret = kvm_create_vcpu(cs); ++ if (ret < 0) { ++ error_report("Failed to create host vcpu %ld", vcpu_id); ++ abort(); ++ } ++ ++ /* ++ * Initialize the vcpu in the host. This will reset the sys regs ++ * for this vcpu and related registers like MPIDR_EL1 etc. also ++ * gets programmed during this call to host. These are referred ++ * later while setting device attributes of the GICR during GICv3 ++ * reset ++ */ ++ ret = kvm_arch_init_vcpu(cs); ++ if (ret < 0) { ++ error_report("Failed to initialize host vcpu %ld", vcpu_id); ++ abort(); ++ } ++ ++ /* ++ * park the created vcpu. shall be used during kvm_get_vcpu() when ++ * threads are created during realization of ARM vcpus ++ */ ++ kvm_park_vcpu(cs); ++} ++ + /* + * Update KVM's MP_STATE based on what QEMU thinks it is + */ +diff --git a/target/arm/kvm_arm.h b/target/arm/kvm_arm.h +index 34f8daa377..e0490c97b5 100644 +--- a/target/arm/kvm_arm.h ++++ b/target/arm/kvm_arm.h +@@ -155,6 +155,17 @@ void kvm_arm_cpu_post_load(ARMCPU *cpu); + */ + void kvm_arm_reset_vcpu(ARMCPU *cpu); + ++/** ++ * kvm_arm_create_host_vcpu: ++ * @cpu: ARMCPU ++ * ++ * Called at to pre create all possible kvm vcpus within the the host at the ++ * virt machine init time. This will also init this pre-created vcpu and ++ * hence result in vcpu reset at host. These pre created and inited vcpus ++ * shall be parked for use when ARM vcpus are actually realized. ++ */ ++void kvm_arm_create_host_vcpu(ARMCPU *cpu); ++ + /** + * kvm_arm_init_serror_injection: + * @cs: CPUState +-- +2.30.2 + diff --git a/tools/packaging/qemu/patches/6.1.x/0006-arm-cpuhp-Changes-to-pre-size-GIC-with-possible-vcpu.patch b/tools/packaging/qemu/patches/6.1.x/0006-arm-cpuhp-Changes-to-pre-size-GIC-with-possible-vcpu.patch new file mode 100644 index 0000000000..2cf86805f4 --- /dev/null +++ b/tools/packaging/qemu/patches/6.1.x/0006-arm-cpuhp-Changes-to-pre-size-GIC-with-possible-vcpu.patch @@ -0,0 +1,220 @@ +From b588545bf1bb168eb0853ae36525d5407657eb7b Mon Sep 17 00:00:00 2001 +From: Salil Mehta +Date: Wed, 24 Nov 2021 16:09:08 +0800 +Subject: [PATCH 06/28] arm/cpuhp: Changes to pre-size GIC with possible vcpus + @machine init + +GIC needs to be pre-sized with possible vcpus at the initialization time. This +is necessary because Memory regions and resources associated with GICC/GICR +etc cannot be changed (add/del/modified) after VM has inited. Also, GIC_TYPER +needs to be initialized with mp_affinity and cpu interface number association. +This cannot be changed after GIC has initialized. + +Once all the cpu interfaces of the GIC has been inited it needs to be ensured +that any updations to the GICC during reset only takes place for the present +vcpus and not the disabled ones. Therefore, proper checks are required at +various places. + +Co-developed-by: Keqian Zhu +Signed-off-by: Salil Mehta +Signed-off-by: Huang Shijie +--- + hw/arm/virt.c | 15 ++++++++------- + hw/intc/arm_gicv3_common.c | 8 ++++++-- + hw/intc/arm_gicv3_cpuif.c | 6 ++++++ + hw/intc/arm_gicv3_kvm.c | 31 ++++++++++++++++++++++++++++--- + include/hw/arm/virt.h | 2 +- + 5 files changed, 49 insertions(+), 13 deletions(-) + +diff --git a/hw/arm/virt.c b/hw/arm/virt.c +index 853288b34a..1b28687883 100644 +--- a/hw/arm/virt.c ++++ b/hw/arm/virt.c +@@ -630,13 +630,14 @@ static void create_gic(VirtMachineState *vms) + const char *gictype; + int type = vms->gic_version, i; + unsigned int smp_cpus = ms->smp.cpus; ++ unsigned int max_cpus = vms->max_cpus; + uint32_t nb_redist_regions = 0; + + gictype = (type == 3) ? gicv3_class_name() : gic_class_name(); + + vms->gic = qdev_new(gictype); + qdev_prop_set_uint32(vms->gic, "revision", type); +- qdev_prop_set_uint32(vms->gic, "num-cpu", smp_cpus); ++ qdev_prop_set_uint32(vms->gic, "num-cpu", max_cpus); + /* Note that the num-irq property counts both internal and external + * interrupts; there are always 32 of the former (mandated by GIC spec). + */ +@@ -648,7 +649,7 @@ static void create_gic(VirtMachineState *vms) + if (type == 3) { + uint32_t redist0_capacity = + vms->memmap[VIRT_GIC_REDIST].size / GICV3_REDIST_SIZE; +- uint32_t redist0_count = MIN(smp_cpus, redist0_capacity); ++ uint32_t redist0_count = MIN(max_cpus, redist0_capacity); + + nb_redist_regions = virt_gicv3_redist_region_count(vms); + +@@ -661,7 +662,7 @@ static void create_gic(VirtMachineState *vms) + vms->memmap[VIRT_HIGH_GIC_REDIST2].size / GICV3_REDIST_SIZE; + + qdev_prop_set_uint32(vms->gic, "redist-region-count[1]", +- MIN(smp_cpus - redist0_count, redist1_capacity)); ++ MIN(max_cpus - redist0_count, redist1_capacity)); + } + } else { + if (!kvm_irqchip_in_kernel()) { +@@ -718,7 +719,7 @@ static void create_gic(VirtMachineState *vms) + } else if (vms->virt) { + qemu_irq irq = qdev_get_gpio_in(vms->gic, + ppibase + ARCH_GIC_MAINT_IRQ); +- sysbus_connect_irq(gicbusdev, i + 4 * smp_cpus, irq); ++ sysbus_connect_irq(gicbusdev, i + 4 * max_cpus, irq); + } + + qdev_connect_gpio_out_named(cpudev, "pmu-interrupt", 0, +@@ -726,11 +727,11 @@ static void create_gic(VirtMachineState *vms) + + VIRTUAL_PMU_IRQ)); + + sysbus_connect_irq(gicbusdev, i, qdev_get_gpio_in(cpudev, ARM_CPU_IRQ)); +- sysbus_connect_irq(gicbusdev, i + smp_cpus, ++ sysbus_connect_irq(gicbusdev, i + max_cpus, + qdev_get_gpio_in(cpudev, ARM_CPU_FIQ)); +- sysbus_connect_irq(gicbusdev, i + 2 * smp_cpus, ++ sysbus_connect_irq(gicbusdev, i + 2 * max_cpus, + qdev_get_gpio_in(cpudev, ARM_CPU_VIRQ)); +- sysbus_connect_irq(gicbusdev, i + 3 * smp_cpus, ++ sysbus_connect_irq(gicbusdev, i + 3 * max_cpus, + qdev_get_gpio_in(cpudev, ARM_CPU_VFIQ)); + } + +diff --git a/hw/intc/arm_gicv3_common.c b/hw/intc/arm_gicv3_common.c +index 58ef65f589..cfc112e43e 100644 +--- a/hw/intc/arm_gicv3_common.c ++++ b/hw/intc/arm_gicv3_common.c +@@ -348,11 +348,15 @@ static void arm_gicv3_common_realize(DeviceState *dev, Error **errp) + s->cpu = g_new0(GICv3CPUState, s->num_cpu); + + for (i = 0; i < s->num_cpu; i++) { +- CPUState *cpu = qemu_get_cpu(i); ++ CPUState *cpu = qemu_get_possible_cpu(i); + uint64_t cpu_affid; + int last; + +- s->cpu[i].cpu = cpu; ++ if (qemu_present_cpu(cpu)) ++ s->cpu[i].cpu = cpu; ++ else ++ s->cpu[i].cpu = NULL; ++ + s->cpu[i].gic = s; + /* Store GICv3CPUState in CPUARMState gicv3state pointer */ + gicv3_set_gicv3state(cpu, &s->cpu[i]); +diff --git a/hw/intc/arm_gicv3_cpuif.c b/hw/intc/arm_gicv3_cpuif.c +index a032d505f5..819c032ec5 100644 +--- a/hw/intc/arm_gicv3_cpuif.c ++++ b/hw/intc/arm_gicv3_cpuif.c +@@ -781,6 +781,9 @@ void gicv3_cpuif_update(GICv3CPUState *cs) + ARMCPU *cpu = ARM_CPU(cs->cpu); + CPUARMState *env = &cpu->env; + ++ if (!qemu_present_cpu(cs->cpu)) ++ return; ++ + g_assert(qemu_mutex_iothread_locked()); + + trace_gicv3_cpuif_update(gicv3_redist_affid(cs), cs->hppi.irq, +@@ -1674,6 +1677,9 @@ static void icc_generate_sgi(CPUARMState *env, GICv3CPUState *cs, + for (i = 0; i < s->num_cpu; i++) { + GICv3CPUState *ocs = &s->cpu[i]; + ++ if (!qemu_present_cpu(ocs->cpu)) ++ continue; ++ + if (irm) { + /* IRM == 1 : route to all CPUs except self */ + if (cs == ocs) { +diff --git a/hw/intc/arm_gicv3_kvm.c b/hw/intc/arm_gicv3_kvm.c +index 5c09f00dec..4e7bb4ac1f 100644 +--- a/hw/intc/arm_gicv3_kvm.c ++++ b/hw/intc/arm_gicv3_kvm.c +@@ -24,6 +24,7 @@ + #include "hw/intc/arm_gicv3_common.h" + #include "qemu/error-report.h" + #include "qemu/module.h" ++#include "sysemu/cpus.h" + #include "sysemu/kvm.h" + #include "sysemu/runstate.h" + #include "kvm_arm.h" +@@ -456,6 +457,17 @@ static void kvm_arm_gicv3_put(GICv3State *s) + GICv3CPUState *c = &s->cpu[ncpu]; + int num_pri_bits; + ++ /* ++ * To support hotplug of vcpus we need to make sure all gic cpuif/GICC ++ * are initialized at machvirt init time. Once the init is done we ++ * release the ARMCPU object for disabled vcpus but this leg could hit ++ * during reset of GICC later as well i.e. after init has happened and ++ * all of the cases we want to make sure we dont acess the GICC for ++ * the disabled VCPUs. ++ */ ++ if (!qemu_present_cpu(c->cpu)) ++ continue; ++ + kvm_gicc_access(s, ICC_SRE_EL1, ncpu, &c->icc_sre_el1, true); + kvm_gicc_access(s, ICC_CTLR_EL1, ncpu, + &c->icc_ctlr_el1[GICV3_NS], true); +@@ -683,11 +695,24 @@ static void arm_gicv3_icc_reset(CPUARMState *env, const ARMCPRegInfo *ri) + return; + } + ++ /* ++ * This shall be called even when vcpu is being hotplugged and other vcpus ++ * might be running. Host kernel KVM code to handle device access of IOCTLs ++ * KVM_{GET|SET}_DEVICE_ATTR might fail due to inability to grab vcpu locks ++ * for all the vcpus. Hence, we need to pause all vcpus to facilitate ++ * locking within host. ++ */ ++ if (!qemu_present_cpu(c->cpu)) ++ pause_all_vcpus(); ++ + /* Initialize to actual HW supported configuration */ + kvm_device_access(s->dev_fd, KVM_DEV_ARM_VGIC_GRP_CPU_SYSREGS, + KVM_VGIC_ATTR(ICC_CTLR_EL1, c->gicr_typer), + &c->icc_ctlr_el1[GICV3_NS], false, &error_abort); + ++ if (!qemu_present_cpu(c->cpu)) ++ resume_all_vcpus(); ++ + c->icc_ctlr_el1[GICV3_S] = c->icc_ctlr_el1[GICV3_NS]; + } + +@@ -794,9 +819,9 @@ static void kvm_arm_gicv3_realize(DeviceState *dev, Error **errp) + } + + for (i = 0; i < s->num_cpu; i++) { +- ARMCPU *cpu = ARM_CPU(qemu_get_cpu(i)); +- +- define_arm_cp_regs(cpu, gicv3_cpuif_reginfo); ++ CPUState *cs = qemu_get_cpu(i); ++ if (qemu_present_cpu(cs)) ++ define_arm_cp_regs(ARM_CPU(cs), gicv3_cpuif_reginfo); + } + + /* Try to create the device via the device control API */ +diff --git a/include/hw/arm/virt.h b/include/hw/arm/virt.h +index 960812c66e..6233be9590 100644 +--- a/include/hw/arm/virt.h ++++ b/include/hw/arm/virt.h +@@ -187,7 +187,7 @@ static inline int virt_gicv3_redist_region_count(VirtMachineState *vms) + + assert(vms->gic_version == VIRT_GIC_VERSION_3); + +- return MACHINE(vms)->smp.cpus > redist0_capacity ? 2 : 1; ++ return vms->max_cpus > redist0_capacity ? 2 : 1; + } + + #endif /* QEMU_ARM_VIRT_H */ +-- +2.30.2 + diff --git a/tools/packaging/qemu/patches/6.1.x/0007-arm-cpuhp-Init-PMU-at-host-for-all-possible-vcpus.patch b/tools/packaging/qemu/patches/6.1.x/0007-arm-cpuhp-Init-PMU-at-host-for-all-possible-vcpus.patch new file mode 100644 index 0000000000..dac93f3a81 --- /dev/null +++ b/tools/packaging/qemu/patches/6.1.x/0007-arm-cpuhp-Init-PMU-at-host-for-all-possible-vcpus.patch @@ -0,0 +1,95 @@ +From b885e6d6e6a1199a6db17fb5753df2ca63c611b5 Mon Sep 17 00:00:00 2001 +From: Salil Mehta +Date: Wed, 24 Nov 2021 16:21:39 +0800 +Subject: [PATCH 07/28] arm/cpuhp: Init PMU at host for all possible vcpus + +PMU for all possible vcpus must be initialized at the virt machine +initialization time. This patch refactors existing code to accomodate possible +vcpus. This also assumes that all processor being used are identical at least +for now but does not affect the normal scanarios where they might not be in +future. This assumption only affects the future hotplug scenarios if ever there +exists any hetergenous processors. In such a case PMU might not be enabled on +some vcpus. Is it acceptable and doable tradeoff for now? + +This perhaps needs more discussion. please check below link, +Link: https://lists.gnu.org/archive/html/qemu-devel/2020-06/msg00131.html + +Co-developed-by: Keqian Zhu +Signed-off-by: Salil Mehta +Signed-off-by: Huang Shijie +--- + hw/arm/virt.c | 38 ++++++++++++++++++++++++++++++++++++-- + include/hw/arm/virt.h | 1 + + 2 files changed, 37 insertions(+), 2 deletions(-) + +diff --git a/hw/arm/virt.c b/hw/arm/virt.c +index 1b28687883..61fc431d20 100644 +--- a/hw/arm/virt.c ++++ b/hw/arm/virt.c +@@ -1502,6 +1502,38 @@ static void create_secure_ram(VirtMachineState *vms, + g_free(nodename); + } + ++/*static bool virt_pmu_init(VirtMachineState *vms) ++{ ++ CPUArchIdList *possible_cpus = vms->parent.possible_cpus; ++ ARMCPU *armcpu; ++ int n; */ ++ ++ /* ++ * As of now KVM ensures that within the host all the vcpus have same ++ * features configured. This cannot be changed later and cannot be diferent ++ * for new vcpus being plugged in. Also, -cpu option/virt machine cpu-type ++ * ensures all the vcpus are identical. ++ */ ++/* for (n = 0; n < possible_cpus->len; n++) { ++ CPUState *cpu = qemu_get_possible_cpu(n); ++ armcpu = ARM_CPU(cpu); ++ ++ if (!arm_feature(&armcpu->env, ARM_FEATURE_PMU)) { ++ warn_report("Not all vcpus might have PMU initialized"); ++ return false; ++ } ++ ++ if (kvm_enabled()) { ++ if (kvm_irqchip_in_kernel()) { ++ kvm_arm_pmu_set_irq(cpu, PPI(VIRTUAL_PMU_IRQ)); ++ } ++ kvm_arm_pmu_init(cpu); ++ } ++ } ++ ++ return true; ++}*/ ++ + static void *machvirt_dtb(const struct arm_boot_info *binfo, int *fdt_size) + { + const VirtMachineState *board = container_of(binfo, VirtMachineState, +@@ -2161,8 +2193,10 @@ static void machvirt_init(MachineState *machine) + + virt_cpu_post_init(vms, sysmem); + +- fdt_add_pmu_nodes(vms); +- ++// if (!vmc->no_pmu && virt_pmu_init(vms)) { ++// vms->pmu = true; ++ fdt_add_pmu_nodes(vms); ++// } + create_uart(vms, VIRT_UART, sysmem, serial_hd(0)); + + if (vms->secure) { +diff --git a/include/hw/arm/virt.h b/include/hw/arm/virt.h +index 6233be9590..a568420303 100644 +--- a/include/hw/arm/virt.h ++++ b/include/hw/arm/virt.h +@@ -144,6 +144,7 @@ struct VirtMachineState { + bool its; + bool virt; + bool ras; ++ bool pmu; + bool mte; + OnOffAuto acpi; + VirtGICType gic_version; +-- +2.30.2 + diff --git a/tools/packaging/qemu/patches/6.1.x/0008-arm-cpuhp-Enable-ACPI-support-for-vcpu-hotplug.patch b/tools/packaging/qemu/patches/6.1.x/0008-arm-cpuhp-Enable-ACPI-support-for-vcpu-hotplug.patch new file mode 100644 index 0000000000..366914870e --- /dev/null +++ b/tools/packaging/qemu/patches/6.1.x/0008-arm-cpuhp-Enable-ACPI-support-for-vcpu-hotplug.patch @@ -0,0 +1,115 @@ +From 8cdfd18d515aa5be1c54061e42f1c8a69997667b Mon Sep 17 00:00:00 2001 +From: Salil Mehta +Date: Thu, 25 Nov 2021 13:58:25 +0800 +Subject: [PATCH 08/28] arm/cpuhp: Enable ACPI support for vcpu hotplug + +ACPI is required to interface QEMU with the guest. Roughly falls into below +cases, + +1. Convey the possible vcpus config at the machine init time to the guest + using various DSDT tables like MADT etc. +2. Convey vcpu hotplug events to guest(using GED) +3. Assist in evaluation of various ACPI methods(like _EVT, _STA, _OST, _EJ0, + _MAT etc.) +4. Provides ACPI cpu hotplug state and 12 Byte memory mapped cpu hotplug + control register interface to the OSPM/guest corresponding to each possible + vcpu. The register interface consists of various R/W fields and their + handling operations. These are called when ever register fields or memory + regions are accessed(i.e. read or written) by OSPM when ever it evaluates + various ACPI methods. + +Note: lot of this framework code is inherited from the changes already done for + x86 but still some minor changes are required to make it compatible with + ARM64.) + +This patch enables the ACPI support for virtual cpu hotplug in kconfig and +during initialization. + +Co-developed-by: Keqian Zhu +Signed-off-by: Salil Mehta +Signed-off-by: Huang Shijie +--- + hw/acpi/cpu.c | 6 +++++- + hw/arm/Kconfig | 1 + + hw/arm/virt.c | 2 ++ + include/hw/acpi/cpu_hotplug.h | 2 ++ + include/hw/arm/virt.h | 1 + + 5 files changed, 11 insertions(+), 1 deletion(-) + +diff --git a/hw/acpi/cpu.c b/hw/acpi/cpu.c +index f82e9512fd..cf07a6c30c 100644 +--- a/hw/acpi/cpu.c ++++ b/hw/acpi/cpu.c +@@ -226,7 +226,11 @@ void cpu_hotplug_hw_init(MemoryRegion *as, Object *owner, + state->dev_count = id_list->len; + state->devs = g_new0(typeof(*state->devs), state->dev_count); + for (i = 0; i < id_list->len; i++) { +- state->devs[i].cpu = CPU(id_list->cpus[i].cpu); ++ struct CPUState *cpu = CPU(id_list->cpus[i].cpu); ++ if (qemu_present_cpu(cpu)) ++ state->devs[i].cpu = cpu; ++ else ++ state->devs[i].cpu = NULL; + state->devs[i].arch_id = id_list->cpus[i].arch_id; + } + memory_region_init_io(&state->ctrl_reg, owner, &cpu_hotplug_ops, state, +diff --git a/hw/arm/Kconfig b/hw/arm/Kconfig +index 4ba0aca067..32b150676a 100644 +--- a/hw/arm/Kconfig ++++ b/hw/arm/Kconfig +@@ -29,6 +29,7 @@ config ARM_VIRT + select ACPI_HW_REDUCED + select ACPI_NVDIMM + select ACPI_APEI ++ select ACPI_CPU_HOTPLUG + + config CHEETAH + bool +diff --git a/hw/arm/virt.c b/hw/arm/virt.c +index 61fc431d20..4265c0e2e8 100644 +--- a/hw/arm/virt.c ++++ b/hw/arm/virt.c +@@ -77,6 +77,7 @@ + #include "hw/virtio/virtio-iommu.h" + #include "hw/char/pl011.h" + #include "qemu/guest-random.h" ++#include "hw/acpi/cpu_hotplug.h" + + #define DEFINE_VIRT_MACHINE_LATEST(major, minor, latest) \ + static void virt_##major##_##minor##_class_init(ObjectClass *oc, \ +@@ -152,6 +153,7 @@ static const MemMapEntry base_memmap[] = { + [VIRT_NVDIMM_ACPI] = { 0x09090000, NVDIMM_ACPI_IO_LEN}, + [VIRT_PVTIME] = { 0x090a0000, 0x00010000 }, + [VIRT_SECURE_GPIO] = { 0x090b0000, 0x00001000 }, ++ [VIRT_CPUHP_ACPI] = { 0x090c0000, ACPI_CPU_HOTPLUG_REG_LEN}, + [VIRT_MMIO] = { 0x0a000000, 0x00000200 }, + /* ...repeating for a total of NUM_VIRTIO_TRANSPORTS, each of that size */ + [VIRT_PLATFORM_BUS] = { 0x0c000000, 0x02000000 }, +diff --git a/include/hw/acpi/cpu_hotplug.h b/include/hw/acpi/cpu_hotplug.h +index 3b932abbbb..48b291e45e 100644 +--- a/include/hw/acpi/cpu_hotplug.h ++++ b/include/hw/acpi/cpu_hotplug.h +@@ -19,6 +19,8 @@ + #include "hw/hotplug.h" + #include "hw/acpi/cpu.h" + ++#define ACPI_CPU_HOTPLUG_REG_LEN 12 ++ + typedef struct AcpiCpuHotplug { + Object *device; + MemoryRegion io; +diff --git a/include/hw/arm/virt.h b/include/hw/arm/virt.h +index a568420303..8954b78c27 100644 +--- a/include/hw/arm/virt.h ++++ b/include/hw/arm/virt.h +@@ -85,6 +85,7 @@ enum { + VIRT_PCDIMM_ACPI, + VIRT_ACPI_GED, + VIRT_NVDIMM_ACPI, ++ VIRT_CPUHP_ACPI, + VIRT_PVTIME, + VIRT_LOWMEMMAP_LAST, + }; +-- +2.30.2 + diff --git a/tools/packaging/qemu/patches/6.1.x/0009-arm-cpuhp-Init-GED-framework-with-cpu-hotplug-events.patch b/tools/packaging/qemu/patches/6.1.x/0009-arm-cpuhp-Init-GED-framework-with-cpu-hotplug-events.patch new file mode 100644 index 0000000000..e06b29bcc3 --- /dev/null +++ b/tools/packaging/qemu/patches/6.1.x/0009-arm-cpuhp-Init-GED-framework-with-cpu-hotplug-events.patch @@ -0,0 +1,101 @@ +From d184f34dbfc972b0a27be189ce8c1a75e400c920 Mon Sep 17 00:00:00 2001 +From: Salil Mehta +Date: Thu, 25 Nov 2021 16:31:07 +0800 +Subject: [PATCH 09/28] arm/cpuhp: Init GED framework with cpu hotplug events + +ACPI GED(as described in the ACPI 6.2 spec) can be used to generate ACPI events +when OSPM/guest receives an interrupt listed in the _CRS object of GED. OSPM +then maps or demultiplexes the event by evaluating _EVT method. + +This change adds the support of cpu hotplug event initialization in the +existing GED framework. + +Co-developed-by: Keqian Zhu +Signed-off-by: Salil Mehta +Signed-off-by: Huang Shijie +--- + hw/acpi/generic_event_device.c | 8 ++++++++ + hw/arm/virt.c | 3 ++- + include/hw/acpi/generic_event_device.h | 5 +++++ + 3 files changed, 15 insertions(+), 1 deletion(-) + +diff --git a/hw/acpi/generic_event_device.c b/hw/acpi/generic_event_device.c +index e28457a7d1..1ed7623907 100644 +--- a/hw/acpi/generic_event_device.c ++++ b/hw/acpi/generic_event_device.c +@@ -25,6 +25,7 @@ static const uint32_t ged_supported_events[] = { + ACPI_GED_MEM_HOTPLUG_EVT, + ACPI_GED_PWR_DOWN_EVT, + ACPI_GED_NVDIMM_HOTPLUG_EVT, ++ ACPI_GED_CPU_HOTPLUG_EVT, + }; + + /* +@@ -390,6 +391,13 @@ static void acpi_ged_initfn(Object *obj) + acpi_memory_hotplug_init(&s->container_memhp, OBJECT(dev), + &s->memhp_state, 0); + ++ s->cpuhp.device = OBJECT(s); ++ memory_region_init(&s->container_cpuhp, OBJECT(dev), "cpuhp container", ++ ACPI_CPU_HOTPLUG_REG_LEN); ++ sysbus_init_mmio(SYS_BUS_DEVICE(dev), &s->container_cpuhp); ++ cpu_hotplug_hw_init(&s->container_cpuhp, OBJECT(dev), ++ &s->cpuhp_state, 0); ++ + memory_region_init_io(&ged_st->regs, obj, &ged_regs_ops, ged_st, + TYPE_ACPI_GED "-regs", ACPI_GED_REG_COUNT); + sysbus_init_mmio(sbd, &ged_st->regs); +diff --git a/hw/arm/virt.c b/hw/arm/virt.c +index 4265c0e2e8..47db084183 100644 +--- a/hw/arm/virt.c ++++ b/hw/arm/virt.c +@@ -560,7 +560,7 @@ static inline DeviceState *create_acpi_ged(VirtMachineState *vms) + DeviceState *dev; + MachineState *ms = MACHINE(vms); + int irq = vms->irqmap[VIRT_ACPI_GED]; +- uint32_t event = ACPI_GED_PWR_DOWN_EVT; ++ uint32_t event = ACPI_GED_PWR_DOWN_EVT | ACPI_GED_CPU_HOTPLUG_EVT; + + if (ms->ram_slots) { + event |= ACPI_GED_MEM_HOTPLUG_EVT; +@@ -575,6 +575,7 @@ static inline DeviceState *create_acpi_ged(VirtMachineState *vms) + + sysbus_mmio_map(SYS_BUS_DEVICE(dev), 0, vms->memmap[VIRT_ACPI_GED].base); + sysbus_mmio_map(SYS_BUS_DEVICE(dev), 1, vms->memmap[VIRT_PCDIMM_ACPI].base); ++ sysbus_mmio_map(SYS_BUS_DEVICE(dev), 2, vms->memmap[VIRT_CPUHP_ACPI].base); + sysbus_connect_irq(SYS_BUS_DEVICE(dev), 0, qdev_get_gpio_in(vms->gic, irq)); + + sysbus_realize_and_unref(SYS_BUS_DEVICE(dev), &error_fatal); +diff --git a/include/hw/acpi/generic_event_device.h b/include/hw/acpi/generic_event_device.h +index 6bed92e8fc..454bf08da2 100644 +--- a/include/hw/acpi/generic_event_device.h ++++ b/include/hw/acpi/generic_event_device.h +@@ -63,6 +63,7 @@ + #include "hw/acpi/memory_hotplug.h" + #include "hw/acpi/ghes.h" + #include "qom/object.h" ++#include "hw/acpi/cpu_hotplug.h" + + #define ACPI_POWER_BUTTON_DEVICE "PWRB" + +@@ -75,6 +76,7 @@ OBJECT_DECLARE_SIMPLE_TYPE(AcpiGedState, ACPI_GED) + + #define ACPI_GED_EVT_SEL_OFFSET 0x0 + #define ACPI_GED_EVT_SEL_LEN 0x4 ++#define ACPI_GED_CPU_HOTPLUG_EVT 0x8 + + #define ACPI_GED_REG_SLEEP_CTL 0x00 + #define ACPI_GED_REG_SLEEP_STS 0x01 +@@ -110,6 +112,9 @@ struct AcpiGedState { + SysBusDevice parent_obj; + MemHotplugState memhp_state; + MemoryRegion container_memhp; ++ CPUHotplugState cpuhp_state; ++ MemoryRegion container_cpuhp; ++ AcpiCpuHotplug cpuhp; + GEDState ged_state; + uint32_t ged_event_bitmap; + qemu_irq irq; +-- +2.30.2 + diff --git a/tools/packaging/qemu/patches/6.1.x/0010-arm-cpuhp-Update-CPUs-AML-with-cpu-ctrl-dev-change.patch b/tools/packaging/qemu/patches/6.1.x/0010-arm-cpuhp-Update-CPUs-AML-with-cpu-ctrl-dev-change.patch new file mode 100644 index 0000000000..3b9413b541 --- /dev/null +++ b/tools/packaging/qemu/patches/6.1.x/0010-arm-cpuhp-Update-CPUs-AML-with-cpu-ctrl-dev-change.patch @@ -0,0 +1,139 @@ +From f7b9c727b0da0bec444d85bd1bf7bd5bfb9d3e4f Mon Sep 17 00:00:00 2001 +From: Salil Mehta +Date: Thu, 25 Nov 2021 16:54:49 +0800 +Subject: [PATCH 10/28] arm/cpuhp: Update CPUs AML with cpu-(ctrl)dev change + +CPUs Control device(\\_SB.PCI0) register interface for the x86 arch is based on +PCI and is IO port based and hence existing cpus AML code assumes _CRS objects +would evaluate to a system resource which describes IO Port address. But on ARM +arch CPUs control device(\\_SB.PRES) register interface is memory-mapped hence +_CRS object should evaluate to system resource which describes memory-mapped +base address. + +This cpus AML code change updates the existing inerface of the build cpus AML +function to accept both IO/MEMORY type regions and update the _CRS object +correspondingly. + +NOTE: Beside above CPU scan shall be triggered when OSPM evaluates _EVT method + part of the GED framework which is covered in subsequent patch. + +Co-developed-by: Keqian Zhu +Signed-off-by: Salil Mehta +Signed-off-by: Huang Shijie +--- + hw/acpi/cpu.c | 23 +++++++++++++++-------- + hw/arm/virt-acpi-build.c | 13 ++++++++++++- + hw/i386/acpi-build.c | 2 +- + include/hw/acpi/cpu.h | 5 +++-- + 4 files changed, 31 insertions(+), 12 deletions(-) + +diff --git a/hw/acpi/cpu.c b/hw/acpi/cpu.c +index cf07a6c30c..98657ad28b 100644 +--- a/hw/acpi/cpu.c ++++ b/hw/acpi/cpu.c +@@ -345,9 +345,10 @@ const VMStateDescription vmstate_cpu_hotplug = { + #define CPU_FW_EJECT_EVENT "CEJF" + + void build_cpus_aml(Aml *table, MachineState *machine, CPUHotplugFeatures opts, +- hwaddr io_base, ++ hwaddr mmap_io_base, + const char *res_root, +- const char *event_handler_method) ++ const char *event_handler_method, ++ AmlRegionSpace rs) + { + Aml *ifctx; + Aml *field; +@@ -375,13 +376,18 @@ void build_cpus_aml(Aml *table, MachineState *machine, CPUHotplugFeatures opts, + aml_append(cpu_ctrl_dev, aml_mutex(CPU_LOCK, 0)); + + crs = aml_resource_template(); +- aml_append(crs, aml_io(AML_DECODE16, io_base, io_base, 1, ++ if (rs == AML_SYSTEM_IO) { ++ aml_append(crs, aml_io(AML_DECODE16, mmap_io_base, mmap_io_base, 1, + ACPI_CPU_HOTPLUG_REG_LEN)); ++ } else { ++ aml_append(crs, aml_memory32_fixed(mmap_io_base, ++ ACPI_CPU_HOTPLUG_REG_LEN, AML_READ_WRITE)); ++ } + aml_append(cpu_ctrl_dev, aml_name_decl("_CRS", crs)); + + /* declare CPU hotplug MMIO region with related access fields */ + aml_append(cpu_ctrl_dev, +- aml_operation_region("PRST", AML_SYSTEM_IO, aml_int(io_base), ++ aml_operation_region("PRST", rs, aml_int(mmap_io_base), + ACPI_CPU_HOTPLUG_REG_LEN)); + + field = aml_field("PRST", AML_BYTE_ACC, AML_NOLOCK, +@@ -720,9 +726,10 @@ void build_cpus_aml(Aml *table, MachineState *machine, CPUHotplugFeatures opts, + aml_append(sb_scope, cpus_dev); + aml_append(table, sb_scope); + +- method = aml_method(event_handler_method, 0, AML_NOTSERIALIZED); +- aml_append(method, aml_call0("\\_SB.CPUS." CPU_SCAN_METHOD)); +- aml_append(table, method); +- ++ if (event_handler_method) { ++ method = aml_method(event_handler_method, 0, AML_NOTSERIALIZED); ++ aml_append(method, aml_call0("\\_SB.CPUS." CPU_SCAN_METHOD)); ++ aml_append(table, method); ++ } + g_free(cphp_res_path); + } +diff --git a/hw/arm/virt-acpi-build.c b/hw/arm/virt-acpi-build.c +index 037cc1fd82..95a3c3b31b 100644 +--- a/hw/arm/virt-acpi-build.c ++++ b/hw/arm/virt-acpi-build.c +@@ -703,7 +703,18 @@ build_dsdt(GArray *table_data, BIOSLinker *linker, VirtMachineState *vms) + * the RTC ACPI device at all when using UEFI. + */ + scope = aml_scope("\\_SB"); +- acpi_dsdt_add_cpus(scope, vms); ++ /* if GED is enabled then cpus AML shall be added as part build_cpus_aml */ ++ if (vms->acpi_dev) { ++ CPUHotplugFeatures opts = { ++ .acpi_1_compatible = false, ++ .has_legacy_cphp = false ++ }; ++ ++ build_cpus_aml(scope, ms, opts, memmap[VIRT_CPUHP_ACPI].base, ++ "\\_SB", NULL, AML_SYSTEM_MEMORY); ++ } else { ++ acpi_dsdt_add_cpus(scope, vms); ++ } + acpi_dsdt_add_uart(scope, &memmap[VIRT_UART], + (irqmap[VIRT_UART] + ARM_SPI_BASE)); + if (vmc->acpi_expose_flash) { +diff --git a/hw/i386/acpi-build.c b/hw/i386/acpi-build.c +index a33ac8b91e..fa7a5ed79d 100644 +--- a/hw/i386/acpi-build.c ++++ b/hw/i386/acpi-build.c +@@ -1503,7 +1503,7 @@ build_dsdt(GArray *table_data, BIOSLinker *linker, + .fw_unplugs_cpu = pm->smi_on_cpu_unplug, + }; + build_cpus_aml(dsdt, machine, opts, pm->cpu_hp_io_base, +- "\\_SB.PCI0", "\\_GPE._E02"); ++ "\\_SB.PCI0", "\\_GPE._E02", AML_SYSTEM_IO); + } + + if (pcms->memhp_io_base && nr_mem) { +diff --git a/include/hw/acpi/cpu.h b/include/hw/acpi/cpu.h +index 999caaf510..ead8f1d1cc 100644 +--- a/include/hw/acpi/cpu.h ++++ b/include/hw/acpi/cpu.h +@@ -56,9 +56,10 @@ typedef struct CPUHotplugFeatures { + } CPUHotplugFeatures; + + void build_cpus_aml(Aml *table, MachineState *machine, CPUHotplugFeatures opts, +- hwaddr io_base, ++ hwaddr mmap_io_base, + const char *res_root, +- const char *event_handler_method); ++ const char *event_handler_method, ++ AmlRegionSpace rs); + + void acpi_cpu_ospm_status(CPUHotplugState *cpu_st, ACPIOSTInfoList ***list); + +-- +2.30.2 + diff --git a/tools/packaging/qemu/patches/6.1.x/0011-arm-cpuhp-Update-GED-_EVT-method-AML-with-cpu-scan.patch b/tools/packaging/qemu/patches/6.1.x/0011-arm-cpuhp-Update-GED-_EVT-method-AML-with-cpu-scan.patch new file mode 100644 index 0000000000..050a268098 --- /dev/null +++ b/tools/packaging/qemu/patches/6.1.x/0011-arm-cpuhp-Update-GED-_EVT-method-AML-with-cpu-scan.patch @@ -0,0 +1,51 @@ +From e9a06ca70bbb956ec96f69e2e7bebc2a7b9044a8 Mon Sep 17 00:00:00 2001 +From: Salil Mehta +Date: Thu, 25 Nov 2021 17:38:19 +0800 +Subject: [PATCH 11/28] arm/cpuhp: Update GED _EVT method AML with cpu scan + +OSPM evaluates _EVT method to map the event. The cpu hotplug event eventually +results in start of the cpu scan. Scan figures out the cpu and the kind of +event(plug/unplug) and notifies it back to the guest. + +The change in this patch updates the GED AML _EVT method with the call to +\\_SB.CPUS.CSCN which will do above. + +Co-developed-by: Keqian Zhu +Signed-off-by: Salil Mehta +Signed-off-by: Huang Shijie +--- + hw/acpi/generic_event_device.c | 4 ++++ + include/hw/acpi/cpu_hotplug.h | 2 ++ + 2 files changed, 6 insertions(+) + +diff --git a/hw/acpi/generic_event_device.c b/hw/acpi/generic_event_device.c +index 1ed7623907..7278b89c6a 100644 +--- a/hw/acpi/generic_event_device.c ++++ b/hw/acpi/generic_event_device.c +@@ -108,6 +108,10 @@ void build_ged_aml(Aml *table, const char *name, HotplugHandler *hotplug_dev, + aml_append(if_ctx, aml_call0(MEMORY_DEVICES_CONTAINER "." + MEMORY_SLOT_SCAN_METHOD)); + break; ++ case ACPI_GED_CPU_HOTPLUG_EVT: ++ aml_append(if_ctx, aml_call0(ACPI_CPU_CONTAINER "." ++ ACPI_CPU_SCAN_METHOD)); ++ break; + case ACPI_GED_PWR_DOWN_EVT: + aml_append(if_ctx, + aml_notify(aml_name(ACPI_POWER_BUTTON_DEVICE), +diff --git a/include/hw/acpi/cpu_hotplug.h b/include/hw/acpi/cpu_hotplug.h +index 48b291e45e..ef631750b4 100644 +--- a/include/hw/acpi/cpu_hotplug.h ++++ b/include/hw/acpi/cpu_hotplug.h +@@ -20,6 +20,8 @@ + #include "hw/acpi/cpu.h" + + #define ACPI_CPU_HOTPLUG_REG_LEN 12 ++#define ACPI_CPU_SCAN_METHOD "CSCN" ++#define ACPI_CPU_CONTAINER "\\_SB.CPUS" + + typedef struct AcpiCpuHotplug { + Object *device; +-- +2.30.2 + diff --git a/tools/packaging/qemu/patches/6.1.x/0012-arm-cpuhp-MADT-Tbl-change-to-size-the-guest-with-pos.patch b/tools/packaging/qemu/patches/6.1.x/0012-arm-cpuhp-MADT-Tbl-change-to-size-the-guest-with-pos.patch new file mode 100644 index 0000000000..03cbf720f8 --- /dev/null +++ b/tools/packaging/qemu/patches/6.1.x/0012-arm-cpuhp-MADT-Tbl-change-to-size-the-guest-with-pos.patch @@ -0,0 +1,67 @@ +From 323ce9267470a6e0bf22c9b19399f12804524d78 Mon Sep 17 00:00:00 2001 +From: Salil Mehta +Date: Thu, 25 Nov 2021 17:52:12 +0800 +Subject: [PATCH 12/28] arm/cpuhp: MADT Tbl change to size the guest with + possible vcpus + +Changes required during building of MADT Table by QEMU to accomodate disabled +possible vcpus. This info shall be used by the guest kernel to size up its +resources during boot time. This pre-sizing of the guest kernel done on +possible vcpus will facilitate hotplug of the disabled vcpus. + +Co-developed-by: Keqian Zhu +Signed-off-by: Salil Mehta +Signed-off-by: Huang Shijie +--- + hw/arm/virt-acpi-build.c | 18 +++++++++++------- + 1 file changed, 11 insertions(+), 7 deletions(-) + +diff --git a/hw/arm/virt-acpi-build.c b/hw/arm/virt-acpi-build.c +index 95a3c3b31b..416b43c9f8 100644 +--- a/hw/arm/virt-acpi-build.c ++++ b/hw/arm/virt-acpi-build.c +@@ -573,6 +573,8 @@ build_madt(GArray *table_data, BIOSLinker *linker, VirtMachineState *vms) + const int *irqmap = vms->irqmap; + AcpiMadtGenericDistributor *gicd; + AcpiMadtGenericMsiFrame *gic_msi; ++ MachineState *ms = &vms->parent; ++ CPUArchIdList *possible_cpus = ms->possible_cpus; + int i; + + acpi_data_push(table_data, sizeof(AcpiMultipleApicTable)); +@@ -583,11 +585,10 @@ build_madt(GArray *table_data, BIOSLinker *linker, VirtMachineState *vms) + gicd->base_address = cpu_to_le64(memmap[VIRT_GIC_DIST].base); + gicd->version = vms->gic_version; + +- for (i = 0; i < MACHINE(vms)->smp.cpus; i++) { ++ for (i = 0; i < MACHINE(vms)->smp.max_cpus; i++) { + AcpiMadtGenericCpuInterface *gicc = acpi_data_push(table_data, + sizeof(*gicc)); +- ARMCPU *armcpu = ARM_CPU(qemu_get_cpu(i)); +- ++ ARMCPU *cpu = ARM_CPU(qemu_get_possible_cpu(i)); + gicc->type = ACPI_APIC_GENERIC_CPU_INTERFACE; + gicc->length = sizeof(*gicc); + if (vms->gic_version == 2) { +@@ -596,11 +597,14 @@ build_madt(GArray *table_data, BIOSLinker *linker, VirtMachineState *vms) + gicc->gicv_base_address = cpu_to_le64(memmap[VIRT_GIC_VCPU].base); + } + gicc->cpu_interface_number = cpu_to_le32(i); +- gicc->arm_mpidr = cpu_to_le64(armcpu->mp_affinity); ++ gicc->arm_mpidr = possible_cpus->cpus[i].arch_id; + gicc->uid = cpu_to_le32(i); +- gicc->flags = cpu_to_le32(ACPI_MADT_GICC_ENABLED); +- +- if (arm_feature(&armcpu->env, ARM_FEATURE_PMU)) { ++ if ( i < MACHINE(vms)->smp.cpus ) { ++ gicc->flags = cpu_to_le32(ACPI_MADT_GICC_ENABLED); ++ } else { ++ gicc->flags = cpu_to_le32(0); ++ } ++ if ((cpu && arm_feature(&cpu->env, ARM_FEATURE_PMU)) || vms->pmu) { + gicc->performance_interrupt = cpu_to_le32(PPI(VIRTUAL_PMU_IRQ)); + } + if (vms->virt) { +-- +2.30.2 + diff --git a/tools/packaging/qemu/patches/6.1.x/0013-arm-cpuhp-Add-ACPI-_MAT-entry-for-Processor-object.patch b/tools/packaging/qemu/patches/6.1.x/0013-arm-cpuhp-Add-ACPI-_MAT-entry-for-Processor-object.patch new file mode 100644 index 0000000000..d8eeac6090 --- /dev/null +++ b/tools/packaging/qemu/patches/6.1.x/0013-arm-cpuhp-Add-ACPI-_MAT-entry-for-Processor-object.patch @@ -0,0 +1,95 @@ +From 22e597ca7364c7787bd9abd3da27b7aaa92f3337 Mon Sep 17 00:00:00 2001 +From: Salil Mehta +Date: Thu, 25 Nov 2021 17:59:22 +0800 +Subject: [PATCH 13/28] arm/cpuhp: Add ACPI _MAT entry for Processor object + +Adds a function which builds the ACPI _MAT entry for processor objects. This +shall be called from the cpus AML for all possible vcpus. + +The entry is passed to the guest kernel with ACPI_MADT_GICC_ENABLED flag when +it evaluates _MAT object. OSPM evaluates _MAT object in context to the cpu +hotplug event. + +Co-developed-by: Keqian Zhu +Signed-off-by: Salil Mehta +Signed-off-by: Huang Shijie +--- + hw/acpi/cpu.c | 5 +++++ + hw/arm/virt-acpi-build.c | 25 +++++++++++++++++++++++-- + include/hw/arm/virt.h | 1 + + 3 files changed, 29 insertions(+), 2 deletions(-) + +diff --git a/hw/acpi/cpu.c b/hw/acpi/cpu.c +index 98657ad28b..7b6765d5dd 100644 +--- a/hw/acpi/cpu.c ++++ b/hw/acpi/cpu.c +@@ -691,6 +691,11 @@ void build_cpus_aml(Aml *table, MachineState *machine, CPUHotplugFeatures opts, + apic->flags = cpu_to_le32(1); + break; + } ++ case ACPI_APIC_GENERIC_CPU_INTERFACE: { ++ AcpiMadtGenericCpuInterface *gicc = (void *)madt_buf->data; ++ gicc->flags = cpu_to_le32(1); ++ break; ++ } + default: + assert(0); + } +diff --git a/hw/arm/virt-acpi-build.c b/hw/arm/virt-acpi-build.c +index 416b43c9f8..48b34d50a2 100644 +--- a/hw/arm/virt-acpi-build.c ++++ b/hw/arm/virt-acpi-build.c +@@ -563,6 +563,22 @@ build_gtdt(GArray *table_data, BIOSLinker *linker, VirtMachineState *vms) + vms->oem_table_id); + } + ++static void ++build_mat_entry(AcpiDeviceIf *adev, int uid, const CPUArchIdList *arch_ids, ++ GArray *entry) ++{ ++ AcpiMadtGenericCpuInterface *gicc = acpi_data_push(entry,sizeof(*gicc)); ++ MachineState *ms = MACHINE(qdev_get_machine()); ++ CPUArchIdList *possible_cpus = ms->possible_cpus; ++ ++ /* fill the relevant fields of _MAT entry for GICC */ ++ gicc->type = ACPI_APIC_GENERIC_CPU_INTERFACE; ++ gicc->length = sizeof(*gicc); ++ gicc->cpu_interface_number = cpu_to_le32(uid); ++ gicc->arm_mpidr = possible_cpus->cpus[uid].arch_id; ++ gicc->uid = cpu_to_le32(uid); ++} ++ + /* MADT */ + static void + build_madt(GArray *table_data, BIOSLinker *linker, VirtMachineState *vms) +@@ -713,8 +729,13 @@ build_dsdt(GArray *table_data, BIOSLinker *linker, VirtMachineState *vms) + .acpi_1_compatible = false, + .has_legacy_cphp = false + }; +- +- build_cpus_aml(scope, ms, opts, memmap[VIRT_CPUHP_ACPI].base, ++ ++ AcpiDeviceIfClass *adevc; ++ /* _MAT entry shall be used within cpus aml */ ++ adevc = ACPI_DEVICE_IF_CLASS(DEVICE_GET_CLASS(vms->acpi_dev)); ++ adevc->madt_cpu = build_mat_entry; ++ ++ build_cpus_aml(scope, ms, opts, memmap[VIRT_CPUHP_ACPI].base, + "\\_SB", NULL, AML_SYSTEM_MEMORY); + } else { + acpi_dsdt_add_cpus(scope, vms); +diff --git a/include/hw/arm/virt.h b/include/hw/arm/virt.h +index 8954b78c27..491eeddca4 100644 +--- a/include/hw/arm/virt.h ++++ b/include/hw/arm/virt.h +@@ -37,6 +37,7 @@ + #include "hw/block/flash.h" + #include "sysemu/kvm.h" + #include "hw/intc/arm_gicv3_common.h" ++#include "hw/acpi/acpi_dev_interface.h" + #include "qom/object.h" + + #define NUM_GICV2M_SPIS 64 +-- +2.30.2 + diff --git a/tools/packaging/qemu/patches/6.1.x/0014-arm-cpuhp-Release-objects-for-disabled-possible-vcpu.patch b/tools/packaging/qemu/patches/6.1.x/0014-arm-cpuhp-Release-objects-for-disabled-possible-vcpu.patch new file mode 100644 index 0000000000..a5df954ba4 --- /dev/null +++ b/tools/packaging/qemu/patches/6.1.x/0014-arm-cpuhp-Release-objects-for-disabled-possible-vcpu.patch @@ -0,0 +1,86 @@ +From 435c926d8739b1ad4ffbfeabe83aabbda2d3ec22 Mon Sep 17 00:00:00 2001 +From: Salil Mehta +Date: Wed, 1 Dec 2021 12:38:03 +0800 +Subject: [PATCH 14/28] arm/cpuhp: Release objects for *disabled* possible + vcpus after init + +During machvirt_init(), ARMCPU objects are pre-created along with the +corresponding KVM vcpus in the host. Disabled possible KVM vcpus are then +parked at the per-virt-machine list "kvm_parked_vcpus". + +Prime purpose to pre-create ARMCPU objects for the disabled vcpus is to +facilitate the GIC initialization (pre-sized with possible vcpus). GIC +requires all vcpus corresponding to its GICC(GIC CPU Interface) to be +initialized and present during its own initialization. + +After initialization of the machine is complete we release the ARMCPU objects +for the disabled vcpus(which shall be re-created at the time when vcpu is hot +plugged again. This newly created ARMCPU object is then attached with +corresponding parked KVM VCPU). + +We have few options after the machine init where the disabled ARMCPU object +could be released: +1. Release in context to the virt_machine_done() notifier.(This is also our + current approach) +2. Defer the release till a new vcpu object is hot plugged. Then release the + object in context to the pre_plug() phase. +3. Never release and keep on reusing them and release once at VM exit. This + will require some modifications within the interface of qdevice_add() to + get old ARMCPU object instead of creating a new one for the hotplug request. + +Each of the above approaches come with their own pros and cons. This prototype +uses the 1st approach.(suggestions are welcome!) + +Co-developed-by: Keqian Zhu +Signed-off-by: Salil Mehta +Signed-off-by: Huang Shijie +--- + hw/arm/virt.c | 25 +++++++++++++++++++++++++ + 1 file changed, 25 insertions(+) + +diff --git a/hw/arm/virt.c b/hw/arm/virt.c +index 47db084183..a0b6393f76 100644 +--- a/hw/arm/virt.c ++++ b/hw/arm/virt.c +@@ -1505,6 +1505,28 @@ static void create_secure_ram(VirtMachineState *vms, + g_free(nodename); + } + ++static void virt_remove_disabled_cpus(VirtMachineState *vms) ++{ ++ MachineState *ms = MACHINE(vms); ++ int n; ++ ++ /* ++ * RFC: Question: Other approach could have been to keep them forever ++ * and release it only once when qemu exits as part o finalize or when ++ * new vcpu is hotplugged. In the later old could be released for the ++ * newly created object for the same vcpu? ++ */ ++ for (n = MACHINE(vms)->smp.cpus; n < MACHINE(vms)->smp.max_cpus; n++) { ++ CPUState *cs = qemu_get_possible_cpu(n); ++ if (!qemu_present_cpu(cs)) { ++ CPUArchId *cpu_slot; ++ cpu_slot = virt_find_cpu_slot(ms, cs->cpu_index); ++ cpu_slot->cpu = NULL; ++ object_unref(OBJECT(cs)); ++ } ++ } ++} ++ + /*static bool virt_pmu_init(VirtMachineState *vms) + { + CPUArchIdList *possible_cpus = vms->parent.possible_cpus; +@@ -1608,6 +1630,9 @@ void virt_machine_done(Notifier *notifier, void *data) + + virt_acpi_setup(vms); + virt_build_smbios(vms); ++ ++ /* release the disabled ARMCPU objects used during init for pre-sizing */ ++ virt_remove_disabled_cpus(vms); + } + + static uint64_t virt_cpu_mp_affinity(VirtMachineState *vms, int idx) +-- +2.30.2 + diff --git a/tools/packaging/qemu/patches/6.1.x/0015-arm-cpuhp-Update-ACPI-GED-framework-to-support-vcpu-.patch b/tools/packaging/qemu/patches/6.1.x/0015-arm-cpuhp-Update-ACPI-GED-framework-to-support-vcpu-.patch new file mode 100644 index 0000000000..a6be7f41a8 --- /dev/null +++ b/tools/packaging/qemu/patches/6.1.x/0015-arm-cpuhp-Update-ACPI-GED-framework-to-support-vcpu-.patch @@ -0,0 +1,97 @@ +From 6a8a86ca3b4b66ab3489911bd0ad4da594531882 Mon Sep 17 00:00:00 2001 +From: Salil Mehta +Date: Thu, 25 Nov 2021 18:15:46 +0800 +Subject: [PATCH 15/28] arm/cpuhp: Update ACPI GED framework to support vcpu + hotplug + +ACPI GED shall be used to convey to the guest kernel about any cpu hot-(un)plug +events. Therefore, existing ACPI GED framework inside QEMU needs to be enhanced +to support CPU hotplug state and events. + +Co-developed-by: Keqian Zhu +Signed-off-by: Salil Mehta +Signed-off-by: Huang Shijie +--- + hw/acpi/generic_event_device.c | 42 +++++++++++++++++++++++++++++++++- + 1 file changed, 41 insertions(+), 1 deletion(-) + +diff --git a/hw/acpi/generic_event_device.c b/hw/acpi/generic_event_device.c +index 7278b89c6a..815f4a91ce 100644 +--- a/hw/acpi/generic_event_device.c ++++ b/hw/acpi/generic_event_device.c +@@ -238,13 +238,48 @@ static void acpi_ged_device_plug_cb(HotplugHandler *hotplug_dev, + nvdimm_acpi_plug_cb(hotplug_dev, dev); + } else { + acpi_memory_plug_cb(hotplug_dev, &s->memhp_state, dev, errp); +- } ++ } ++ } else if (object_dynamic_cast(OBJECT(dev), TYPE_CPU)) { ++ acpi_cpu_plug_cb(hotplug_dev, &s->cpuhp_state, dev, errp); + } else { + error_setg(errp, "virt: device plug request for unsupported device" + " type: %s", object_get_typename(OBJECT(dev))); + } + } + ++static void acpi_ged_device_unplug_request_cb(HotplugHandler *hotplug_dev, ++ DeviceState *dev, Error **errp) ++{ ++ AcpiGedState *s = ACPI_GED(hotplug_dev); ++ ++ if (object_dynamic_cast(OBJECT(dev), TYPE_CPU)) { ++ acpi_cpu_unplug_request_cb(hotplug_dev, &s->cpuhp_state, dev, errp); ++ } else { ++ error_setg(errp, "virt: device unplug request for the unsupported device" ++ " type: %s", object_get_typename(OBJECT(dev))); ++ } ++} ++ ++static void acpi_ged_device_unplug_cb(HotplugHandler *hotplug_dev, ++ DeviceState *dev, Error **errp) ++{ ++ AcpiGedState *s = ACPI_GED(hotplug_dev); ++ ++ if (object_dynamic_cast(OBJECT(dev), TYPE_CPU)) { ++ acpi_cpu_unplug_cb(&s->cpuhp_state, dev, errp); ++ } else { ++ error_setg(errp, "virt: device plug request for unsupported device" ++ " type: %s", object_get_typename(OBJECT(dev))); ++ } ++} ++ ++static void acpi_ged_ospm_status(AcpiDeviceIf *adev, ACPIOSTInfoList ***list) ++{ ++ AcpiGedState *s = ACPI_GED(adev); ++ ++ acpi_cpu_ospm_status(&s->cpuhp_state, list); ++} ++ + static void acpi_ged_unplug_request_cb(HotplugHandler *hotplug_dev, + DeviceState *dev, Error **errp) + { +@@ -284,6 +319,8 @@ static void acpi_ged_send_event(AcpiDeviceIf *adev, AcpiEventStatusBits ev) + sel = ACPI_GED_PWR_DOWN_EVT; + } else if (ev & ACPI_NVDIMM_HOTPLUG_STATUS) { + sel = ACPI_GED_NVDIMM_HOTPLUG_EVT; ++ } else if (ev & ACPI_CPU_HOTPLUG_STATUS) { ++ sel = ACPI_GED_CPU_HOTPLUG_EVT; + } else { + /* Unknown event. Return without generating interrupt. */ + warn_report("GED: Unsupported event %d. No irq injected", ev); +@@ -418,10 +455,13 @@ static void acpi_ged_class_init(ObjectClass *class, void *data) + dc->vmsd = &vmstate_acpi_ged; + + hc->plug = acpi_ged_device_plug_cb; ++ hc->unplug_request = acpi_ged_device_unplug_request_cb; ++ hc->unplug = acpi_ged_device_unplug_cb; + hc->unplug_request = acpi_ged_unplug_request_cb; + hc->unplug = acpi_ged_unplug_cb; + + adevc->send_event = acpi_ged_send_event; ++ adevc->ospm_status = acpi_ged_ospm_status; + } + + static const TypeInfo acpi_ged_info = { +-- +2.30.2 + diff --git a/tools/packaging/qemu/patches/6.1.x/0016-arm-cpuhp-Add-update-basic-hot-un-plug-framework.patch b/tools/packaging/qemu/patches/6.1.x/0016-arm-cpuhp-Add-update-basic-hot-un-plug-framework.patch new file mode 100644 index 0000000000..18bf4cf4e3 --- /dev/null +++ b/tools/packaging/qemu/patches/6.1.x/0016-arm-cpuhp-Add-update-basic-hot-un-plug-framework.patch @@ -0,0 +1,171 @@ +From 2010227bc3f326b0755ec3878476c2f0616ea407 Mon Sep 17 00:00:00 2001 +From: Salil Mehta +Date: Sat, 27 Nov 2021 15:03:17 +0800 +Subject: [PATCH 16/28] arm/cpuhp: Add/update basic hot-(un)plug framework + +Adds the new cpu hot-unplug hooks and updates the existing hotplug hooks with +sanity checks. + +Note, Functional contents of the hooks(now left with TODO comment) shall be +gradually filled in the subsequent patches in an incremental approach to patch +and logic building which would be roughly as follows: +1. (Un-)wiring of interrupts between vcpu<->gic +2. Sending events to Guest for hot-(un)plug so that guest can take appropriate + actions. +3. Notifying GIC about hot-(un)plug action so that vcpu could be (un-)stitched + to the GIC CPU interface. +4. Updating the Guest with Next boot info for this vcpu in the firmware. + +Co-developed-by: Keqian Zhu +Signed-off-by: Salil Mehta +Signed-off-by: Huang Shijie +--- + hw/arm/virt.c | 87 +++++++++++++++++++++++++++++++++++++++++++++++++-- + 1 file changed, 85 insertions(+), 2 deletions(-) + +diff --git a/hw/arm/virt.c b/hw/arm/virt.c +index a0b6393f76..ce34fb019a 100644 +--- a/hw/arm/virt.c ++++ b/hw/arm/virt.c +@@ -2668,11 +2668,22 @@ static void virt_memory_plug(HotplugHandler *hotplug_dev, + static void virt_cpu_pre_plug(HotplugHandler *hotplug_dev, DeviceState *dev, + Error **errp) + { ++ VirtMachineState *vms = VIRT_MACHINE(hotplug_dev); + MachineState *ms = MACHINE(hotplug_dev); + ARMCPU *cpu = ARM_CPU(dev); + CPUState *cs = CPU(dev); + CPUArchId *cpu_slot; + ++ if (dev->hotplugged && !vms->acpi_dev) { ++ error_setg(errp, "GED acpi device does not exists"); ++ return; ++ } ++ ++ if (dev->hotplugged && (vms->gic_version < VIRT_GIC_VERSION_3)) { ++ error_setg(errp, "CPU hotplug not supported with GICv%d, use GICv3 or " ++ "later", vms->gic_version); ++ return; ++ } + /* sanity check the cpu */ + if (!object_dynamic_cast(OBJECT(cpu), ms->cpu_type)) { + error_setg(errp, "Invalid CPU type, expected cpu type: '%s'", +@@ -2705,6 +2716,9 @@ static void virt_cpu_pre_plug(HotplugHandler *hotplug_dev, DeviceState *dev, + return; + } + virt_cpu_set_properties(OBJECT(cs), cpu_slot); ++ if (dev->hotplugged) { ++ /* TODO: update GIC about this hotplug change here */ ++ } + } + + static void virt_cpu_plug(HotplugHandler *hotplug_dev, DeviceState *dev, +@@ -2719,10 +2733,74 @@ static void virt_cpu_plug(HotplugHandler *hotplug_dev, DeviceState *dev, + cpu_slot = virt_find_cpu_slot(ms, cpu->core_id); + cpu_slot->cpu = OBJECT(dev); + ++ if (dev->hotplugged) { ++ /* TODO: wire the gic-cpu irqs */ ++ /* TODO: update acpi hotplug state and send cpu hotplug event to guest */ ++ /* TODO: register this cpu for reset & update F/W info for the next boot */ ++ } + cs->disabled = false; + return; + } + ++static void virt_cpu_unplug_request(HotplugHandler *hotplug_dev, ++ DeviceState *dev, Error **errp) ++{ ++ VirtMachineState *vms = VIRT_MACHINE(hotplug_dev); ++ CPUState *cs = CPU(dev); ++ ++ if (!vms->acpi_dev || !dev->realized) { ++ error_setg(errp, "GED does not exists or device is not realized!"); ++ return; ++ } ++ ++ if (vms->gic_version < VIRT_GIC_VERSION_3) { ++ error_setg(errp, "CPU hot-unplug not supported with GICv%d", ++ vms->gic_version); ++ return; ++ } ++ ++ if (cs->cpu_index == first_cpu->cpu_index) ++ { ++ error_setg(errp, "hot-unplug of ARM boot vcpu %d not supported", ++ first_cpu->cpu_index); ++ return; ++ } ++ ++ /* TODO: request cpu hotplug from guest */ ++ ++ return; ++} ++ ++static void virt_cpu_unplug(HotplugHandler *hotplug_dev, DeviceState *dev, ++ Error **errp) ++{ ++ VirtMachineState *vms = VIRT_MACHINE(hotplug_dev); ++ MachineState *ms = MACHINE(hotplug_dev); ++ CPUState *cs = CPU(dev); ++ CPUArchId *cpu_slot; ++ ++ if (!vms->acpi_dev || !dev->realized) { ++ error_setg(errp, "GED does not exists or device is not realized!"); ++ return; ++ } ++ ++ cpu_slot = virt_find_cpu_slot(ms, ARM_CPU(cs)->core_id); ++ ++ /* TODO: update the acpi cpu hotplug state for cpu hot-unplug */ ++ ++ /* TODO: unwire the gic-cpu irqs here */ ++ /* TODO: update the GIC about this hot unplug change */ ++ ++ /* TODO: unregister this cpu for reset & update F/W info for the next boot */ ++ ++ qemu_opts_del(dev->opts); ++ dev->opts = NULL; ++ ++ cpu_slot->cpu = NULL; ++ cs->disabled = true; ++ return; ++} ++ + static void virt_machine_device_pre_plug_cb(HotplugHandler *hotplug_dev, + DeviceState *dev, Error **errp) + { +@@ -2835,9 +2913,11 @@ static void virt_machine_device_unplug_request_cb(HotplugHandler *hotplug_dev, + { + if (object_dynamic_cast(OBJECT(dev), TYPE_PC_DIMM)) { + virt_dimm_unplug_request(hotplug_dev, dev, errp); ++ } else if (object_dynamic_cast(OBJECT(dev), TYPE_CPU)) { ++ virt_cpu_unplug_request(hotplug_dev, dev, errp); + } else { +- error_setg(errp, "device unplug request for unsupported device" +- " type: %s", object_get_typename(OBJECT(dev))); ++ error_setg(errp, "device unplug request for unsupported type: %s", ++ object_get_typename(OBJECT(dev))); + } + } + +@@ -2846,6 +2926,8 @@ static void virt_machine_device_unplug_cb(HotplugHandler *hotplug_dev, + { + if (object_dynamic_cast(OBJECT(dev), TYPE_PC_DIMM)) { + virt_dimm_unplug(hotplug_dev, dev, errp); ++ } else if (object_dynamic_cast(OBJECT(dev), TYPE_CPU)) { ++ virt_cpu_unplug(hotplug_dev, dev, errp); + } else { + error_setg(errp, "virt: device unplug for unsupported device" + " type: %s", object_get_typename(OBJECT(dev))); +@@ -2977,6 +3059,7 @@ static void virt_machine_class_init(ObjectClass *oc, void *data) + mc->default_cpu_type = ARM_CPU_TYPE_NAME("cortex-a15"); + mc->get_default_cpu_node_id = virt_get_default_cpu_node_id; + mc->kvm_type = virt_kvm_type; ++ mc->has_hotpluggable_cpus = true; + assert(!mc->get_hotplug_handler); + mc->get_hotplug_handler = virt_machine_get_hotplug_handler; + hc->pre_plug = virt_machine_device_pre_plug_cb; +-- +2.30.2 + diff --git a/tools/packaging/qemu/patches/6.1.x/0017-arm-cpuhp-Changes-to-un-wire-GICC-VCPU-IRQs-during-h.patch b/tools/packaging/qemu/patches/6.1.x/0017-arm-cpuhp-Changes-to-un-wire-GICC-VCPU-IRQs-during-h.patch new file mode 100644 index 0000000000..c48da0b40c --- /dev/null +++ b/tools/packaging/qemu/patches/6.1.x/0017-arm-cpuhp-Changes-to-un-wire-GICC-VCPU-IRQs-during-h.patch @@ -0,0 +1,232 @@ +From 8ee7755e469b3e8d1a4edb0fd703d33a163092f5 Mon Sep 17 00:00:00 2001 +From: Salil Mehta +Date: Sat, 27 Nov 2021 15:19:39 +0800 +Subject: [PATCH 17/28] arm/cpuhp: Changes to (un)wire GICC<->VCPU IRQs during + hot-(un)plug + +Refactors the existing gic create code to extract common code to wire the +vcpu<->gic interrupts. This function could be used with cold-plug case and also +used when vcpu is hot-plugged. It also introduces a new function to unwire the +vcpu>->gic interrupts for the vcpu hot-unplug cases. + +Co-developed-by: Keqian Zhu +Signed-off-by: Salil Mehta +Signed-off-by: Huang Shijie +--- + hw/arm/virt.c | 144 +++++++++++++++++++++++++++++------------ + hw/core/qdev.c | 2 +- + include/hw/qdev-core.h | 2 + + 3 files changed, 104 insertions(+), 44 deletions(-) + +diff --git a/hw/arm/virt.c b/hw/arm/virt.c +index ce34fb019a..b0429cdf8c 100644 +--- a/hw/arm/virt.c ++++ b/hw/arm/virt.c +@@ -625,6 +625,103 @@ static void create_v2m(VirtMachineState *vms) + vms->msi_controller = VIRT_MSI_CTRL_GICV2M; + } + ++static void unwire_gic_cpu_irqs(VirtMachineState *vms, CPUState *cs) ++{ ++ unsigned int max_cpus = vms->max_cpus; ++ DeviceState *cpudev = DEVICE(cs); ++ DeviceState *gicdev = vms->gic; ++ int cpu = CPU(cs)->cpu_index; ++ int type = vms->gic_version; ++ int irq; ++ ++ /* Mapping from the output timer irq lines from the CPU to the ++ * GIC PPI inputs we use for the virt board. ++ */ ++ const int timer_irq[] = { ++ [GTIMER_PHYS] = ARCH_TIMER_NS_EL1_IRQ, ++ [GTIMER_VIRT] = ARCH_TIMER_VIRT_IRQ, ++ [GTIMER_HYP] = ARCH_TIMER_NS_EL2_IRQ, ++ [GTIMER_SEC] = ARCH_TIMER_S_EL1_IRQ, ++ }; ++ ++ for (irq = 0; irq < ARRAY_SIZE(timer_irq); irq++) { ++ qdev_disconnect_gpio_out_named(cpudev, NULL, irq); ++ } ++ ++ if (type == 3) { ++ qdev_disconnect_gpio_out_named(cpudev, "gicv3-maintenance-interrupt", 0); ++ } else if (vms->virt) { ++ qdev_disconnect_gpio_out_named(gicdev, SYSBUS_DEVICE_GPIO_IRQ, cpu + 4 * max_cpus); ++ } ++ ++ /* ++ * RFC: Question: This currently does not takes care of intimating the devices ++ * which might be sitting on system bus. Do we need a sysbus_disconnect_irq() ++ * which also does the job of notification beside disconnection? ++ */ ++ qdev_disconnect_gpio_out_named(cpudev, "pmu-interrupt", 0); ++ qdev_disconnect_gpio_out_named(gicdev, SYSBUS_DEVICE_GPIO_IRQ, cpu); ++ qdev_disconnect_gpio_out_named(gicdev, ++ SYSBUS_DEVICE_GPIO_IRQ, cpu + max_cpus); ++ qdev_disconnect_gpio_out_named(gicdev, SYSBUS_DEVICE_GPIO_IRQ, ++ cpu + 2 * max_cpus); ++ qdev_disconnect_gpio_out_named(gicdev, SYSBUS_DEVICE_GPIO_IRQ, ++ cpu + 3 * max_cpus); ++} ++ ++static void wire_gic_cpu_irqs(VirtMachineState *vms, CPUState *cs) ++{ ++ unsigned int max_cpus = vms->max_cpus; ++ DeviceState *cpudev = DEVICE(cs); ++ DeviceState *gicdev = vms->gic; ++ int cpu = CPU(cs)->cpu_index; ++ int type = vms->gic_version; ++ SysBusDevice *gicbusdev; ++ int ppibase; ++ int irq; ++ ++ ppibase = NUM_IRQS + cpu * GIC_INTERNAL + GIC_NR_SGIS; ++ ++ /* Mapping from the output timer irq lines from the CPU to the ++ * GIC PPI inputs we use for the virt board. ++ */ ++ const int timer_irq[] = { ++ [GTIMER_PHYS] = ARCH_TIMER_NS_EL1_IRQ, ++ [GTIMER_VIRT] = ARCH_TIMER_VIRT_IRQ, ++ [GTIMER_HYP] = ARCH_TIMER_NS_EL2_IRQ, ++ [GTIMER_SEC] = ARCH_TIMER_S_EL1_IRQ, ++ }; ++ ++ for (irq = 0; irq < ARRAY_SIZE(timer_irq); irq++) { ++ qdev_connect_gpio_out(cpudev, irq, ++ qdev_get_gpio_in(gicdev, ++ ppibase + timer_irq[irq])); ++ } ++ ++ gicbusdev = SYS_BUS_DEVICE(gicdev); ++ if (type == 3) { ++ qemu_irq irq = qdev_get_gpio_in(gicdev, ++ ppibase + ARCH_GIC_MAINT_IRQ); ++ qdev_connect_gpio_out_named(cpudev, "gicv3-maintenance-interrupt", ++ 0, irq); ++ } else if (vms->virt) { ++ qemu_irq irq = qdev_get_gpio_in(gicdev, ++ ppibase + ARCH_GIC_MAINT_IRQ); ++ sysbus_connect_irq(gicbusdev, cpu + 4 * max_cpus, irq); ++ } ++ ++ qdev_connect_gpio_out_named(cpudev, "pmu-interrupt", 0, ++ qdev_get_gpio_in(gicdev, ++ ppibase + VIRTUAL_PMU_IRQ)); ++ sysbus_connect_irq(gicbusdev, cpu, qdev_get_gpio_in(cpudev, ARM_CPU_IRQ)); ++ sysbus_connect_irq(gicbusdev, cpu + max_cpus, ++ qdev_get_gpio_in(cpudev, ARM_CPU_FIQ)); ++ sysbus_connect_irq(gicbusdev, cpu + 2 * max_cpus, ++ qdev_get_gpio_in(cpudev, ARM_CPU_VIRQ)); ++ sysbus_connect_irq(gicbusdev, cpu + 3 * max_cpus, ++ qdev_get_gpio_in(cpudev, ARM_CPU_VFIQ)); ++} ++ + static void create_gic(VirtMachineState *vms) + { + MachineState *ms = MACHINE(vms); +@@ -695,47 +792,7 @@ static void create_gic(VirtMachineState *vms) + * and the GIC's IRQ/FIQ/VIRQ/VFIQ interrupt outputs to the CPU's inputs. + */ + for (i = 0; i < smp_cpus; i++) { +- DeviceState *cpudev = DEVICE(qemu_get_cpu(i)); +- int ppibase = NUM_IRQS + i * GIC_INTERNAL + GIC_NR_SGIS; +- int irq; +- /* Mapping from the output timer irq lines from the CPU to the +- * GIC PPI inputs we use for the virt board. +- */ +- const int timer_irq[] = { +- [GTIMER_PHYS] = ARCH_TIMER_NS_EL1_IRQ, +- [GTIMER_VIRT] = ARCH_TIMER_VIRT_IRQ, +- [GTIMER_HYP] = ARCH_TIMER_NS_EL2_IRQ, +- [GTIMER_SEC] = ARCH_TIMER_S_EL1_IRQ, +- }; +- +- for (irq = 0; irq < ARRAY_SIZE(timer_irq); irq++) { +- qdev_connect_gpio_out(cpudev, irq, +- qdev_get_gpio_in(vms->gic, +- ppibase + timer_irq[irq])); +- } +- +- if (type == 3) { +- qemu_irq irq = qdev_get_gpio_in(vms->gic, +- ppibase + ARCH_GIC_MAINT_IRQ); +- qdev_connect_gpio_out_named(cpudev, "gicv3-maintenance-interrupt", +- 0, irq); +- } else if (vms->virt) { +- qemu_irq irq = qdev_get_gpio_in(vms->gic, +- ppibase + ARCH_GIC_MAINT_IRQ); +- sysbus_connect_irq(gicbusdev, i + 4 * max_cpus, irq); +- } +- +- qdev_connect_gpio_out_named(cpudev, "pmu-interrupt", 0, +- qdev_get_gpio_in(vms->gic, ppibase +- + VIRTUAL_PMU_IRQ)); +- +- sysbus_connect_irq(gicbusdev, i, qdev_get_gpio_in(cpudev, ARM_CPU_IRQ)); +- sysbus_connect_irq(gicbusdev, i + max_cpus, +- qdev_get_gpio_in(cpudev, ARM_CPU_FIQ)); +- sysbus_connect_irq(gicbusdev, i + 2 * max_cpus, +- qdev_get_gpio_in(cpudev, ARM_CPU_VIRQ)); +- sysbus_connect_irq(gicbusdev, i + 3 * max_cpus, +- qdev_get_gpio_in(cpudev, ARM_CPU_VFIQ)); ++ wire_gic_cpu_irqs(vms, qemu_get_cpu(i)); + } + + fdt_add_gic_node(vms); +@@ -2724,6 +2781,7 @@ static void virt_cpu_pre_plug(HotplugHandler *hotplug_dev, DeviceState *dev, + static void virt_cpu_plug(HotplugHandler *hotplug_dev, DeviceState *dev, + Error **errp) + { ++ VirtMachineState *vms = VIRT_MACHINE(hotplug_dev); + MachineState *ms = MACHINE(hotplug_dev); + ARMCPU *cpu = ARM_CPU(dev); + CPUState *cs = CPU(dev); +@@ -2734,7 +2792,7 @@ static void virt_cpu_plug(HotplugHandler *hotplug_dev, DeviceState *dev, + cpu_slot->cpu = OBJECT(dev); + + if (dev->hotplugged) { +- /* TODO: wire the gic-cpu irqs */ ++ wire_gic_cpu_irqs(vms, cs); + /* TODO: update acpi hotplug state and send cpu hotplug event to guest */ + /* TODO: register this cpu for reset & update F/W info for the next boot */ + } +@@ -2788,7 +2846,7 @@ static void virt_cpu_unplug(HotplugHandler *hotplug_dev, DeviceState *dev, + + /* TODO: update the acpi cpu hotplug state for cpu hot-unplug */ + +- /* TODO: unwire the gic-cpu irqs here */ ++ unwire_gic_cpu_irqs(vms, cs); + /* TODO: update the GIC about this hot unplug change */ + + /* TODO: unregister this cpu for reset & update F/W info for the next boot */ +diff --git a/hw/core/qdev.c b/hw/core/qdev.c +index cefc5eaa0a..bb3dfc06da 100644 +--- a/hw/core/qdev.c ++++ b/hw/core/qdev.c +@@ -552,7 +552,7 @@ qemu_irq qdev_get_gpio_out_connector(DeviceState *dev, const char *name, int n) + + /* disconnect a GPIO output, returning the disconnected input (if any) */ + +-static qemu_irq qdev_disconnect_gpio_out_named(DeviceState *dev, ++qemu_irq qdev_disconnect_gpio_out_named(DeviceState *dev, + const char *name, int n) + { + char *propname = g_strdup_printf("%s[%d]", +diff --git a/include/hw/qdev-core.h b/include/hw/qdev-core.h +index bafc311bfa..ea29e7a7af 100644 +--- a/include/hw/qdev-core.h ++++ b/include/hw/qdev-core.h +@@ -553,6 +553,8 @@ qemu_irq qdev_get_gpio_out_connector(DeviceState *dev, const char *name, int n); + qemu_irq qdev_intercept_gpio_out(DeviceState *dev, qemu_irq icpt, + const char *name, int n); + ++qemu_irq qdev_disconnect_gpio_out_named(DeviceState *dev, ++ const char *name, int n); + BusState *qdev_get_child_bus(DeviceState *dev, const char *name); + + /*** Device API. ***/ +-- +2.30.2 + diff --git a/tools/packaging/qemu/patches/6.1.x/0018-arm-cpuhp-Changes-to-update-GIC-with-vcpu-hot-plug-n.patch b/tools/packaging/qemu/patches/6.1.x/0018-arm-cpuhp-Changes-to-update-GIC-with-vcpu-hot-plug-n.patch new file mode 100644 index 0000000000..0233907c20 --- /dev/null +++ b/tools/packaging/qemu/patches/6.1.x/0018-arm-cpuhp-Changes-to-update-GIC-with-vcpu-hot-plug-n.patch @@ -0,0 +1,211 @@ +From f2ce0fea29008de9c95800044e0e508ba682554d Mon Sep 17 00:00:00 2001 +From: Salil Mehta +Date: Sat, 27 Nov 2021 16:06:48 +0800 +Subject: [PATCH 18/28] arm/cpuhp: Changes to update GIC with vcpu hot-plug + notification + +Adds the notification support about vcpu hot-(un)plug required to update the +GIC so that it can update its vcpu to GIC cpu interface association. + +NOTE: This is using 'struct VirtMachineState' inside the notifier function. + Question: Not sure if it is right to use machine related data structure + inside GIC related files? Its design looks to be pretty much abstracted + from any machine related stuff. @Peter Maydell + +Co-developed-by: Keqian Zhu +Signed-off-by: Salil Mehta +Signed-off-by: Huang Shijie +--- + hw/arm/virt.c | 12 +++++-- + hw/intc/arm_gicv3_common.c | 54 +++++++++++++++++++++++++++++- + hw/intc/arm_gicv3_cpuif.c | 5 +++ + hw/intc/gicv3_internal.h | 1 + + include/hw/arm/virt.h | 1 + + include/hw/intc/arm_gicv3_common.h | 1 + + 6 files changed, 71 insertions(+), 3 deletions(-) + +diff --git a/hw/arm/virt.c b/hw/arm/virt.c +index b0429cdf8c..15595611a3 100644 +--- a/hw/arm/virt.c ++++ b/hw/arm/virt.c +@@ -2109,6 +2109,8 @@ static void machvirt_init(MachineState *machine) + + create_fdt(vms); + ++ notifier_list_init(&vms->cpuhp_notifiers); ++ + possible_cpus = mc->possible_cpu_arch_ids(machine); + assert(possible_cpus->len == max_cpus); + for (n = 0; n < possible_cpus->len; n++) { +@@ -2722,6 +2724,12 @@ static void virt_memory_plug(HotplugHandler *hotplug_dev, + dev, &error_abort); + } + ++static void virt_update_gic(VirtMachineState *vms, CPUState *cs) ++{ ++ /* notify gic to stitch GICC to this new cpu */ ++ notifier_list_notify(&vms->cpuhp_notifiers, cs); ++} ++ + static void virt_cpu_pre_plug(HotplugHandler *hotplug_dev, DeviceState *dev, + Error **errp) + { +@@ -2774,7 +2782,7 @@ static void virt_cpu_pre_plug(HotplugHandler *hotplug_dev, DeviceState *dev, + } + virt_cpu_set_properties(OBJECT(cs), cpu_slot); + if (dev->hotplugged) { +- /* TODO: update GIC about this hotplug change here */ ++ virt_update_gic(vms, cs); + } + } + +@@ -2847,7 +2855,7 @@ static void virt_cpu_unplug(HotplugHandler *hotplug_dev, DeviceState *dev, + /* TODO: update the acpi cpu hotplug state for cpu hot-unplug */ + + unwire_gic_cpu_irqs(vms, cs); +- /* TODO: update the GIC about this hot unplug change */ ++ virt_update_gic(vms, cs); + + /* TODO: unregister this cpu for reset & update F/W info for the next boot */ + +diff --git a/hw/intc/arm_gicv3_common.c b/hw/intc/arm_gicv3_common.c +index cfc112e43e..aed9906ace 100644 +--- a/hw/intc/arm_gicv3_common.c ++++ b/hw/intc/arm_gicv3_common.c +@@ -31,7 +31,7 @@ + #include "gicv3_internal.h" + #include "hw/arm/linux-boot-if.h" + #include "sysemu/kvm.h" +- ++#include "hw/arm/virt.h" + + static void gicv3_gicd_no_migration_shift_bug_post_load(GICv3State *cs) + { +@@ -305,8 +305,57 @@ void gicv3_init_irqs_and_mmio(GICv3State *s, qemu_irq_handler handler, + } + } + ++static int arm_gicv3_get_proc_num(GICv3State *s, CPUState *cpu) ++{ ++ uint64_t mp_affinity; ++ uint64_t gicr_typer; ++ uint64_t cpu_affid; ++ int i; ++ ++ mp_affinity = object_property_get_uint(OBJECT(cpu), "mp-affinity", NULL); ++ /* match the cpu mp-affinity to get the gic cpuif number */ ++ for (i = 0; i < s->num_cpu; i++) { ++ gicr_typer = s->cpu[i].gicr_typer; ++ cpu_affid = (gicr_typer >> 32) & 0xFFFFFF; ++ if (cpu_affid == mp_affinity) { ++ return i; ++ } ++ } ++ ++ return -1; ++} ++ ++static void arm_gicv3_cpu_update_notifier(Notifier * notifier, void * data) ++{ ++ VirtMachineState *vms = VIRT_MACHINE(qdev_get_machine()); ++ GICv3State *s = ARM_GICV3_COMMON(vms->gic); ++ CPUState *cpu = (CPUState *)data; ++ int gic_cpuif_num; ++ ++ /* this shall get us mapped gicv3 cpuif corresponding to mpidr */ ++ gic_cpuif_num = arm_gicv3_get_proc_num(s, cpu); ++ if (gic_cpuif_num < 0) { ++ error_report("Failed to associate cpu %d with any GIC cpuif", ++ cpu->cpu_index); ++ abort(); ++ } ++ ++ /* check if update is for vcpu hot-unplug */ ++ if (qemu_present_cpu(cpu)) { ++ s->cpu[gic_cpuif_num].cpu = NULL; ++ return; ++ } ++ ++ /* re-stitch the gic cpuif to this new cpu */ ++ gicv3_set_gicv3state(cpu, &s->cpu[gic_cpuif_num]); ++ gicv3_set_cpustate(&s->cpu[gic_cpuif_num], cpu); ++ ++ /* TODO: initialize the registers info for this newly added cpu */ ++} ++ + static void arm_gicv3_common_realize(DeviceState *dev, Error **errp) + { ++ VirtMachineState *vms = VIRT_MACHINE(qdev_get_machine()); + GICv3State *s = ARM_GICV3_COMMON(dev); + int i; + +@@ -386,12 +435,15 @@ static void arm_gicv3_common_realize(DeviceState *dev, Error **errp) + (i << 8) | + (last << 4); + } ++ s->cpu_update_notifier.notify = arm_gicv3_cpu_update_notifier; ++ notifier_list_add(&vms->cpuhp_notifiers, &s->cpu_update_notifier); + } + + static void arm_gicv3_finalize(Object *obj) + { + GICv3State *s = ARM_GICV3_COMMON(obj); + ++ notifier_remove(&s->cpu_update_notifier); + g_free(s->redist_region_count); + } + +diff --git a/hw/intc/arm_gicv3_cpuif.c b/hw/intc/arm_gicv3_cpuif.c +index 819c032ec5..f4a0a1c2ab 100644 +--- a/hw/intc/arm_gicv3_cpuif.c ++++ b/hw/intc/arm_gicv3_cpuif.c +@@ -21,6 +21,11 @@ + #include "hw/irq.h" + #include "cpu.h" + ++void gicv3_set_cpustate(GICv3CPUState *s, CPUState *cpu) ++{ ++ s->cpu = cpu; ++} ++ + void gicv3_set_gicv3state(CPUState *cpu, GICv3CPUState *s) + { + ARMCPU *arm_cpu = ARM_CPU(cpu); +diff --git a/hw/intc/gicv3_internal.h b/hw/intc/gicv3_internal.h +index 05303a55c8..6e14a7a6cd 100644 +--- a/hw/intc/gicv3_internal.h ++++ b/hw/intc/gicv3_internal.h +@@ -409,5 +409,6 @@ static inline void gicv3_cache_all_target_cpustates(GICv3State *s) + } + + void gicv3_set_gicv3state(CPUState *cpu, GICv3CPUState *s); ++void gicv3_set_cpustate(GICv3CPUState *s, CPUState *cpu); + + #endif /* QEMU_ARM_GICV3_INTERNAL_H */ +diff --git a/include/hw/arm/virt.h b/include/hw/arm/virt.h +index 491eeddca4..b91249201a 100644 +--- a/include/hw/arm/virt.h ++++ b/include/hw/arm/virt.h +@@ -169,6 +169,7 @@ struct VirtMachineState { + DeviceState *gic; + DeviceState *acpi_dev; + Notifier powerdown_notifier; ++ NotifierList cpuhp_notifiers; + PCIBus *bus; + char *oem_id; + char *oem_table_id; +diff --git a/include/hw/intc/arm_gicv3_common.h b/include/hw/intc/arm_gicv3_common.h +index 91491a2f66..b36f98a413 100644 +--- a/include/hw/intc/arm_gicv3_common.h ++++ b/include/hw/intc/arm_gicv3_common.h +@@ -248,6 +248,7 @@ struct GICv3State { + GICv3CPUState *gicd_irouter_target[GICV3_MAXIRQ]; + uint32_t gicd_nsacr[DIV_ROUND_UP(GICV3_MAXIRQ, 16)]; + ++ Notifier cpu_update_notifier; + GICv3CPUState *cpu; + }; + +-- +2.30.2 + diff --git a/tools/packaging/qemu/patches/6.1.x/0019-arm-cpuhp-Changes-required-to-re-init-the-vcpu-regis.patch b/tools/packaging/qemu/patches/6.1.x/0019-arm-cpuhp-Changes-required-to-re-init-the-vcpu-regis.patch new file mode 100644 index 0000000000..0c23c44657 --- /dev/null +++ b/tools/packaging/qemu/patches/6.1.x/0019-arm-cpuhp-Changes-required-to-re-init-the-vcpu-regis.patch @@ -0,0 +1,268 @@ +From 44cdfa821bf310d3adab8885127ff30a2c23157f Mon Sep 17 00:00:00 2001 +From: Salil Mehta +Date: Sat, 27 Nov 2021 17:00:11 +0800 +Subject: [PATCH 19/28] arm/cpuhp: Changes required to (re)init the vcpu + register info + +VCPU register info needs to be re-initialized each time vcpu is hot-plugged. +This has to be done both for emulation/TCG and KVM case. This is done in +context to the GIC update notification for any vcpu hot-(un)plug events. This +change adds that support and re-factors existing to maximize the code re-use. + +Co-developed-by: Keqian Zhu +Signed-off-by: Salil Mehta +Signed-off-by: Huang Shijie +--- + hw/intc/arm_gicv3.c | 1 + + hw/intc/arm_gicv3_common.c | 7 +- + hw/intc/arm_gicv3_cpuif.c | 131 +++++++++++++++-------------- + hw/intc/arm_gicv3_kvm.c | 7 +- + hw/intc/gicv3_internal.h | 1 + + include/hw/intc/arm_gicv3_common.h | 1 + + 6 files changed, 84 insertions(+), 64 deletions(-) + +diff --git a/hw/intc/arm_gicv3.c b/hw/intc/arm_gicv3.c +index d63f8af604..21a50161df 100644 +--- a/hw/intc/arm_gicv3.c ++++ b/hw/intc/arm_gicv3.c +@@ -395,6 +395,7 @@ static void arm_gicv3_class_init(ObjectClass *klass, void *data) + ARMGICv3Class *agc = ARM_GICV3_CLASS(klass); + + agcc->post_load = arm_gicv3_post_load; ++ agcc->init_cpu_reginfo = gicv3_init_cpu_reginfo; + device_class_set_parent_realize(dc, arm_gic_realize, &agc->parent_realize); + } + +diff --git a/hw/intc/arm_gicv3_common.c b/hw/intc/arm_gicv3_common.c +index aed9906ace..c1307895c8 100644 +--- a/hw/intc/arm_gicv3_common.c ++++ b/hw/intc/arm_gicv3_common.c +@@ -330,6 +330,7 @@ static void arm_gicv3_cpu_update_notifier(Notifier * notifier, void * data) + VirtMachineState *vms = VIRT_MACHINE(qdev_get_machine()); + GICv3State *s = ARM_GICV3_COMMON(vms->gic); + CPUState *cpu = (CPUState *)data; ++ ARMGICv3CommonClass *c = ARM_GICV3_COMMON_GET_CLASS(s); + int gic_cpuif_num; + + /* this shall get us mapped gicv3 cpuif corresponding to mpidr */ +@@ -349,8 +350,10 @@ static void arm_gicv3_cpu_update_notifier(Notifier * notifier, void * data) + /* re-stitch the gic cpuif to this new cpu */ + gicv3_set_gicv3state(cpu, &s->cpu[gic_cpuif_num]); + gicv3_set_cpustate(&s->cpu[gic_cpuif_num], cpu); +- +- /* TODO: initialize the registers info for this newly added cpu */ ++ /* initialize the registers info for this newly added cpu */ ++ if (c->init_cpu_reginfo) { ++ c->init_cpu_reginfo(cpu); ++ } + } + + static void arm_gicv3_common_realize(DeviceState *dev, Error **errp) +diff --git a/hw/intc/arm_gicv3_cpuif.c b/hw/intc/arm_gicv3_cpuif.c +index f4a0a1c2ab..96f1637f83 100644 +--- a/hw/intc/arm_gicv3_cpuif.c ++++ b/hw/intc/arm_gicv3_cpuif.c +@@ -2625,6 +2625,72 @@ static const ARMCPRegInfo gicv3_cpuif_ich_apxr23_reginfo[] = { + REGINFO_SENTINEL + }; + ++void gicv3_init_cpu_reginfo(CPUState *cs) ++{ ++ ARMCPU *cpu = ARM_CPU(cs); ++ GICv3CPUState *gcs = icc_cs_from_env(&cpu->env); ++ ++ /* Note that we can't just use the GICv3CPUState as an opaque pointer ++ * in define_arm_cp_regs_with_opaque(), because when we're called back ++ * it might be with code translated by CPU 0 but run by CPU 1, in ++ * which case we'd get the wrong value. ++ * So instead we define the regs with no ri->opaque info, and ++ * get back to the GICv3CPUState from the CPUARMState. ++ */ ++ define_arm_cp_regs(cpu, gicv3_cpuif_reginfo); ++ if (arm_feature(&cpu->env, ARM_FEATURE_EL2) ++ && cpu->gic_num_lrs) { ++ int j; ++ ++ gcs->num_list_regs = cpu->gic_num_lrs; ++ gcs->vpribits = cpu->gic_vpribits; ++ gcs->vprebits = cpu->gic_vprebits; ++ ++ /* Check against architectural constraints: getting these ++ * wrong would be a bug in the CPU code defining these, ++ * and the implementation relies on them holding. ++ */ ++ g_assert(gcs->vprebits <= gcs->vpribits); ++ g_assert(gcs->vprebits >= 5 && gcs->vprebits <= 7); ++ g_assert(gcs->vpribits >= 5 && gcs->vpribits <= 8); ++ ++ define_arm_cp_regs(cpu, gicv3_cpuif_hcr_reginfo); ++ ++ for (j = 0; j < gcs->num_list_regs; j++) { ++ /* Note that the AArch64 LRs are 64-bit; the AArch32 LRs ++ * are split into two cp15 regs, LR (the low part, with the ++ * same encoding as the AArch64 LR) and LRC (the high part). ++ */ ++ ARMCPRegInfo lr_regset[] = { ++ { .name = "ICH_LRn_EL2", .state = ARM_CP_STATE_BOTH, ++ .opc0 = 3, .opc1 = 4, .crn = 12, ++ .crm = 12 + (j >> 3), .opc2 = j & 7, ++ .type = ARM_CP_IO | ARM_CP_NO_RAW, ++ .access = PL2_RW, ++ .readfn = ich_lr_read, ++ .writefn = ich_lr_write, ++ }, ++ { .name = "ICH_LRCn_EL2", .state = ARM_CP_STATE_AA32, ++ .cp = 15, .opc1 = 4, .crn = 12, ++ .crm = 14 + (j >> 3), .opc2 = j & 7, ++ .type = ARM_CP_IO | ARM_CP_NO_RAW, ++ .access = PL2_RW, ++ .readfn = ich_lr_read, ++ .writefn = ich_lr_write, ++ }, ++ REGINFO_SENTINEL ++ }; ++ define_arm_cp_regs(cpu, lr_regset); ++ } ++ if (gcs->vprebits >= 6) { ++ define_arm_cp_regs(cpu, gicv3_cpuif_ich_apxr1_reginfo); ++ } ++ if (gcs->vprebits == 7) { ++ define_arm_cp_regs(cpu, gicv3_cpuif_ich_apxr23_reginfo); ++ } ++ } ++} ++ + static void gicv3_cpuif_el_change_hook(ARMCPU *cpu, void *opaque) + { + GICv3CPUState *cs = opaque; +@@ -2641,67 +2707,10 @@ void gicv3_init_cpuif(GICv3State *s) + + for (i = 0; i < s->num_cpu; i++) { + ARMCPU *cpu = ARM_CPU(qemu_get_cpu(i)); +- GICv3CPUState *cs = &s->cpu[i]; +- +- /* Note that we can't just use the GICv3CPUState as an opaque pointer +- * in define_arm_cp_regs_with_opaque(), because when we're called back +- * it might be with code translated by CPU 0 but run by CPU 1, in +- * which case we'd get the wrong value. +- * So instead we define the regs with no ri->opaque info, and +- * get back to the GICv3CPUState from the CPUARMState. +- */ +- define_arm_cp_regs(cpu, gicv3_cpuif_reginfo); +- if (arm_feature(&cpu->env, ARM_FEATURE_EL2) +- && cpu->gic_num_lrs) { +- int j; +- +- cs->num_list_regs = cpu->gic_num_lrs; +- cs->vpribits = cpu->gic_vpribits; +- cs->vprebits = cpu->gic_vprebits; +- +- /* Check against architectural constraints: getting these +- * wrong would be a bug in the CPU code defining these, +- * and the implementation relies on them holding. +- */ +- g_assert(cs->vprebits <= cs->vpribits); +- g_assert(cs->vprebits >= 5 && cs->vprebits <= 7); +- g_assert(cs->vpribits >= 5 && cs->vpribits <= 8); +- +- define_arm_cp_regs(cpu, gicv3_cpuif_hcr_reginfo); +- +- for (j = 0; j < cs->num_list_regs; j++) { +- /* Note that the AArch64 LRs are 64-bit; the AArch32 LRs +- * are split into two cp15 regs, LR (the low part, with the +- * same encoding as the AArch64 LR) and LRC (the high part). +- */ +- ARMCPRegInfo lr_regset[] = { +- { .name = "ICH_LRn_EL2", .state = ARM_CP_STATE_BOTH, +- .opc0 = 3, .opc1 = 4, .crn = 12, +- .crm = 12 + (j >> 3), .opc2 = j & 7, +- .type = ARM_CP_IO | ARM_CP_NO_RAW, +- .access = PL2_RW, +- .readfn = ich_lr_read, +- .writefn = ich_lr_write, +- }, +- { .name = "ICH_LRCn_EL2", .state = ARM_CP_STATE_AA32, +- .cp = 15, .opc1 = 4, .crn = 12, +- .crm = 14 + (j >> 3), .opc2 = j & 7, +- .type = ARM_CP_IO | ARM_CP_NO_RAW, +- .access = PL2_RW, +- .readfn = ich_lr_read, +- .writefn = ich_lr_write, +- }, +- REGINFO_SENTINEL +- }; +- define_arm_cp_regs(cpu, lr_regset); +- } +- if (cs->vprebits >= 6) { +- define_arm_cp_regs(cpu, gicv3_cpuif_ich_apxr1_reginfo); +- } +- if (cs->vprebits == 7) { +- define_arm_cp_regs(cpu, gicv3_cpuif_ich_apxr23_reginfo); +- } ++ if (qemu_present_cpu(CPU(cpu))) { ++ GICv3CPUState *cs = icc_cs_from_env(&cpu->env); ++ gicv3_init_cpu_reginfo(CPU(cpu)); ++ arm_register_el_change_hook(cpu, gicv3_cpuif_el_change_hook, cs); + } +- arm_register_el_change_hook(cpu, gicv3_cpuif_el_change_hook, cs); + } + } +diff --git a/hw/intc/arm_gicv3_kvm.c b/hw/intc/arm_gicv3_kvm.c +index 4e7bb4ac1f..65ac3d5a88 100644 +--- a/hw/intc/arm_gicv3_kvm.c ++++ b/hw/intc/arm_gicv3_kvm.c +@@ -789,6 +789,10 @@ static void vm_change_state_handler(void *opaque, bool running, + } + } + ++static void kvm_gicv3_init_cpu_reginfo(CPUState *cs) ++{ ++ define_arm_cp_regs(ARM_CPU(cs), gicv3_cpuif_reginfo); ++} + + static void kvm_arm_gicv3_realize(DeviceState *dev, Error **errp) + { +@@ -821,7 +825,7 @@ static void kvm_arm_gicv3_realize(DeviceState *dev, Error **errp) + for (i = 0; i < s->num_cpu; i++) { + CPUState *cs = qemu_get_cpu(i); + if (qemu_present_cpu(cs)) +- define_arm_cp_regs(ARM_CPU(cs), gicv3_cpuif_reginfo); ++ kvm_gicv3_init_cpu_reginfo(cs); + } + + /* Try to create the device via the device control API */ +@@ -908,6 +912,7 @@ static void kvm_arm_gicv3_class_init(ObjectClass *klass, void *data) + + agcc->pre_save = kvm_arm_gicv3_get; + agcc->post_load = kvm_arm_gicv3_put; ++ agcc->init_cpu_reginfo = kvm_gicv3_init_cpu_reginfo; + 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); +diff --git a/hw/intc/gicv3_internal.h b/hw/intc/gicv3_internal.h +index 6e14a7a6cd..66eec3c3fc 100644 +--- a/hw/intc/gicv3_internal.h ++++ b/hw/intc/gicv3_internal.h +@@ -298,6 +298,7 @@ void gicv3_dist_set_irq(GICv3State *s, int irq, int level); + void gicv3_redist_set_irq(GICv3CPUState *cs, int irq, int level); + void gicv3_redist_send_sgi(GICv3CPUState *cs, int grp, int irq, bool ns); + void gicv3_init_cpuif(GICv3State *s); ++void gicv3_init_cpu_reginfo(CPUState *cs); + + /** + * gicv3_cpuif_update: +diff --git a/include/hw/intc/arm_gicv3_common.h b/include/hw/intc/arm_gicv3_common.h +index b36f98a413..b2457cbcb8 100644 +--- a/include/hw/intc/arm_gicv3_common.h ++++ b/include/hw/intc/arm_gicv3_common.h +@@ -291,6 +291,7 @@ struct ARMGICv3CommonClass { + + void (*pre_save)(GICv3State *s); + void (*post_load)(GICv3State *s); ++ void (*init_cpu_reginfo)(CPUState *cs); + }; + + void gicv3_init_irqs_and_mmio(GICv3State *s, qemu_irq_handler handler, +-- +2.30.2 + diff --git a/tools/packaging/qemu/patches/6.1.x/0020-arm-cpuhp-Update-the-guest-via-GED-about-cpu-hot-un-.patch b/tools/packaging/qemu/patches/6.1.x/0020-arm-cpuhp-Update-the-guest-via-GED-about-cpu-hot-un-.patch new file mode 100644 index 0000000000..ab368a4392 --- /dev/null +++ b/tools/packaging/qemu/patches/6.1.x/0020-arm-cpuhp-Update-the-guest-via-GED-about-cpu-hot-un-.patch @@ -0,0 +1,115 @@ +From 740d5e7968376d6007fcc71008f277b8ea94a2fb Mon Sep 17 00:00:00 2001 +From: Salil Mehta +Date: Sat, 27 Nov 2021 17:07:55 +0800 +Subject: [PATCH 20/28] arm/cpuhp: Update the guest(via GED) about cpu + hot-(un)plug events + +During any vcpu hot-(un)plug, running guest VM needs to be intimated about the +new vcpu being added or request the deletion of the vcpu which is already part +of the guest VM. This is done using the ACPI GED event which eventually gets +demultiplexed to a CPU hotplug event and further to specific hot-(un)plug event +of a particular vcpu. + +This change adds the ACPI calls to the existing hot-(un)plug hooks to trigger +ACPI GED events from QEMU to guest VM. + +Co-developed-by: Keqian Zhu +Signed-off-by: Salil Mehta +Signed-off-by: Huang Shijie +--- + hw/arm/virt.c | 31 +++++++++++++++++++++++++++---- + 1 file changed, 27 insertions(+), 4 deletions(-) + +diff --git a/hw/arm/virt.c b/hw/arm/virt.c +index 15595611a3..c3073d6755 100644 +--- a/hw/arm/virt.c ++++ b/hw/arm/virt.c +@@ -2794,17 +2794,25 @@ static void virt_cpu_plug(HotplugHandler *hotplug_dev, DeviceState *dev, + ARMCPU *cpu = ARM_CPU(dev); + CPUState *cs = CPU(dev); + CPUArchId *cpu_slot; ++ Error *local_err = NULL; + + /* insert the cold/hot-plugged vcpu in the slot */ + cpu_slot = virt_find_cpu_slot(ms, cpu->core_id); + cpu_slot->cpu = OBJECT(dev); + + if (dev->hotplugged) { ++ HotplugHandlerClass *hhc; + wire_gic_cpu_irqs(vms, cs); +- /* TODO: update acpi hotplug state and send cpu hotplug event to guest */ ++ /* update acpi hotplug state and send cpu hotplug event to guest */ ++ hhc = HOTPLUG_HANDLER_GET_CLASS(vms->acpi_dev); ++ hhc->plug(HOTPLUG_HANDLER(vms->acpi_dev), dev, &local_err); ++ if (local_err) ++ goto fail; + /* TODO: register this cpu for reset & update F/W info for the next boot */ + } + cs->disabled = false; ++fail: ++ error_propagate(errp, local_err); + return; + } + +@@ -2812,7 +2820,9 @@ static void virt_cpu_unplug_request(HotplugHandler *hotplug_dev, + DeviceState *dev, Error **errp) + { + VirtMachineState *vms = VIRT_MACHINE(hotplug_dev); ++ HotplugHandlerClass *hhc; + CPUState *cs = CPU(dev); ++ Error *local_err = NULL; + + if (!vms->acpi_dev || !dev->realized) { + error_setg(errp, "GED does not exists or device is not realized!"); +@@ -2832,8 +2842,13 @@ static void virt_cpu_unplug_request(HotplugHandler *hotplug_dev, + return; + } + +- /* TODO: request cpu hotplug from guest */ +- ++ /* request cpu hotplug from guest */ ++ hhc = HOTPLUG_HANDLER_GET_CLASS(vms->acpi_dev); ++ hhc->unplug_request(HOTPLUG_HANDLER(vms->acpi_dev), dev, &local_err); ++ if (local_err) ++ goto fail; ++fail: ++ error_propagate(errp, local_err); + return; + } + +@@ -2842,8 +2857,10 @@ static void virt_cpu_unplug(HotplugHandler *hotplug_dev, DeviceState *dev, + { + VirtMachineState *vms = VIRT_MACHINE(hotplug_dev); + MachineState *ms = MACHINE(hotplug_dev); ++ HotplugHandlerClass *hhc; + CPUState *cs = CPU(dev); + CPUArchId *cpu_slot; ++ Error *local_err = NULL; + + if (!vms->acpi_dev || !dev->realized) { + error_setg(errp, "GED does not exists or device is not realized!"); +@@ -2852,7 +2869,11 @@ static void virt_cpu_unplug(HotplugHandler *hotplug_dev, DeviceState *dev, + + cpu_slot = virt_find_cpu_slot(ms, ARM_CPU(cs)->core_id); + +- /* TODO: update the acpi cpu hotplug state for cpu hot-unplug */ ++ /* update the acpi cpu hotplug state for cpu hot-unplug */ ++ hhc = HOTPLUG_HANDLER_GET_CLASS(vms->acpi_dev); ++ hhc->unplug(HOTPLUG_HANDLER(vms->acpi_dev), dev, &local_err); ++ if (local_err) ++ goto fail; + + unwire_gic_cpu_irqs(vms, cs); + virt_update_gic(vms, cs); +@@ -2865,6 +2886,8 @@ static void virt_cpu_unplug(HotplugHandler *hotplug_dev, DeviceState *dev, + cpu_slot->cpu = NULL; + cs->disabled = true; + return; ++fail: ++ error_propagate(errp, local_err); + } + + static void virt_machine_device_pre_plug_cb(HotplugHandler *hotplug_dev, +-- +2.30.2 + diff --git a/tools/packaging/qemu/patches/6.1.x/0021-arm-cpuhp-Changes-required-for-reset-and-to-support-.patch b/tools/packaging/qemu/patches/6.1.x/0021-arm-cpuhp-Changes-required-for-reset-and-to-support-.patch new file mode 100644 index 0000000000..9a7264f1db --- /dev/null +++ b/tools/packaging/qemu/patches/6.1.x/0021-arm-cpuhp-Changes-required-for-reset-and-to-support-.patch @@ -0,0 +1,109 @@ +From e9301ff546d27cf5f6acc677d19e7c89c693d6ea Mon Sep 17 00:00:00 2001 +From: Salil Mehta +Date: Sat, 27 Nov 2021 17:14:45 +0800 +Subject: [PATCH 21/28] arm/cpuhp: Changes required for reset and to support + next boot + +Updates the firmware config with the next boot cpus information and also +registers the reset callback to be called when guest reboots to reset the cpu. + +Co-developed-by: Keqian Zhu +Signed-off-by: Salil Mehta +Signed-off-by: Huang Shijie +--- + hw/arm/boot.c | 2 +- + hw/arm/virt.c | 17 +++++++++++++---- + include/hw/arm/boot.h | 2 ++ + include/hw/arm/virt.h | 1 + + 4 files changed, 17 insertions(+), 5 deletions(-) + +diff --git a/hw/arm/boot.c b/hw/arm/boot.c +index 57efb61ee4..e966d8e032 100644 +--- a/hw/arm/boot.c ++++ b/hw/arm/boot.c +@@ -675,7 +675,7 @@ fail: + return -1; + } + +-static void do_cpu_reset(void *opaque) ++void do_cpu_reset(void *opaque) + { + ARMCPU *cpu = opaque; + CPUState *cs = CPU(cpu); +diff --git a/hw/arm/virt.c b/hw/arm/virt.c +index c3073d6755..ab35bd51af 100644 +--- a/hw/arm/virt.c ++++ b/hw/arm/virt.c +@@ -48,6 +48,7 @@ + #include "sysemu/numa.h" + #include "sysemu/runstate.h" + #include "sysemu/tpm.h" ++#include "sysemu/reset.h" + #include "sysemu/kvm.h" + #include "hw/loader.h" + #include "qapi/error.h" +@@ -1236,7 +1237,7 @@ static FWCfgState *create_fw_cfg(const VirtMachineState *vms, AddressSpace *as) + char *nodename; + + fw_cfg = fw_cfg_init_mem_wide(base + 8, base, 8, base + 16, as); +- fw_cfg_add_i16(fw_cfg, FW_CFG_NB_CPUS, (uint16_t)ms->smp.cpus); ++ fw_cfg_add_i16(fw_cfg, FW_CFG_NB_CPUS, vms->boot_cpus); + + nodename = g_strdup_printf("/fw-cfg@%" PRIx64, base); + qemu_fdt_add_subnode(ms->fdt, nodename); +@@ -2808,7 +2809,12 @@ static void virt_cpu_plug(HotplugHandler *hotplug_dev, DeviceState *dev, + hhc->plug(HOTPLUG_HANDLER(vms->acpi_dev), dev, &local_err); + if (local_err) + goto fail; +- /* TODO: register this cpu for reset & update F/W info for the next boot */ ++ /* register this cpu for reset & update F/W info for the next boot */ ++ qemu_register_reset(do_cpu_reset, ARM_CPU(cs)); ++ vms->boot_cpus++; ++ if (vms->fw_cfg) { ++ fw_cfg_modify_i16(vms->fw_cfg, FW_CFG_NB_CPUS, vms->boot_cpus); ++ } + } + cs->disabled = false; + fail: +@@ -2878,8 +2884,11 @@ static void virt_cpu_unplug(HotplugHandler *hotplug_dev, DeviceState *dev, + unwire_gic_cpu_irqs(vms, cs); + virt_update_gic(vms, cs); + +- /* TODO: unregister this cpu for reset & update F/W info for the next boot */ +- ++ qemu_unregister_reset(do_cpu_reset, ARM_CPU(cs)); ++ vms->boot_cpus--; ++ if (vms->fw_cfg) { ++ fw_cfg_modify_i16(vms->fw_cfg, FW_CFG_NB_CPUS, vms->boot_cpus); ++ } + qemu_opts_del(dev->opts); + dev->opts = NULL; + +diff --git a/include/hw/arm/boot.h b/include/hw/arm/boot.h +index ce2b48b88b..aa156967af 100644 +--- a/include/hw/arm/boot.h ++++ b/include/hw/arm/boot.h +@@ -163,6 +163,8 @@ AddressSpace *arm_boot_address_space(ARMCPU *cpu, + int arm_load_dtb(hwaddr addr, const struct arm_boot_info *binfo, + hwaddr addr_limit, AddressSpace *as, MachineState *ms); + ++void do_cpu_reset(void *opaque); ++ + /* Write a secure board setup routine with a dummy handler for SMCs */ + void arm_write_secure_board_setup_dummy_smc(ARMCPU *cpu, + const struct arm_boot_info *info, +diff --git a/include/hw/arm/virt.h b/include/hw/arm/virt.h +index b91249201a..f18d797245 100644 +--- a/include/hw/arm/virt.h ++++ b/include/hw/arm/virt.h +@@ -160,6 +160,7 @@ struct VirtMachineState { + const int *irqmap; + int fdt_size; + int max_cpus; ++ uint16_t boot_cpus; + uint32_t clock_phandle; + uint32_t gic_phandle; + uint32_t msi_phandle; +-- +2.30.2 + diff --git a/tools/packaging/qemu/patches/6.1.x/0022-arm-cpuhp-Add-support-of-unrealize-ARMCPU-during-vcp.patch b/tools/packaging/qemu/patches/6.1.x/0022-arm-cpuhp-Add-support-of-unrealize-ARMCPU-during-vcp.patch new file mode 100644 index 0000000000..f8f287af31 --- /dev/null +++ b/tools/packaging/qemu/patches/6.1.x/0022-arm-cpuhp-Add-support-of-unrealize-ARMCPU-during-vcp.patch @@ -0,0 +1,415 @@ +From 71102726bd7434d8fd635be0f1c067fdb795efe3 Mon Sep 17 00:00:00 2001 +From: Salil Mehta +Date: Sat, 27 Nov 2021 17:37:22 +0800 +Subject: [PATCH 22/28] arm/cpuhp: Add support of *unrealize* ARMCPU during + vcpu hot-unplug + +During vcpu hot-unplug ARM cpu unrealization shall happen which should do away +with all the vcpu thread creations, allocations, registrations which happened +as part of the realization process of the ARM cpu. This change introduces the +ARM cpu unrealize function taking care of exactly that. + +Note, initialized vcpus are not destroyed at host KVM but are rather parked in +the QEMU/KVM layer. These are later reused once vcpu is hotplugged again. + +Co-developed-by: Keqian Zhu +Signed-off-by: Salil Mehta +Signed-off-by: Huang Shijie +--- + gdbstub.c | 13 +++++++ + include/exec/exec-all.h | 8 ++++ + include/exec/gdbstub.h | 1 + + include/hw/core/cpu.h | 2 + + softmmu/physmem.c | 24 ++++++++++++ + target/arm/cpu-qom.h | 3 ++ + target/arm/cpu.c | 86 +++++++++++++++++++++++++++++++++++++++++ + target/arm/cpu.h | 14 +++++++ + target/arm/helper.c | 31 +++++++++++++++ + target/arm/internals.h | 1 + + target/arm/kvm64.c | 6 ++- + 11 files changed, 188 insertions(+), 1 deletion(-) + +diff --git a/gdbstub.c b/gdbstub.c +index 52bde5bdc9..d5fb3cb9ae 100644 +--- a/gdbstub.c ++++ b/gdbstub.c +@@ -1005,6 +1005,19 @@ void gdb_register_coprocessor(CPUState *cpu, + } + } + ++void gdb_unregister_coprocessor_all(CPUState *cpu) ++{ ++ GDBRegisterState *s, *p; ++ ++ p = cpu->gdb_regs; ++ while (p) { ++ s = p; ++ p = p->next; ++ g_free(s); ++ } ++ cpu->gdb_regs = NULL; ++} ++ + #ifndef CONFIG_USER_ONLY + /* Translate GDB watchpoint type to a flags value for cpu_watchpoint_* */ + static inline int xlat_gdb_type(CPUState *cpu, int gdbtype) +diff --git a/include/exec/exec-all.h b/include/exec/exec-all.h +index 5d1b6d80fb..1fbe9aee0c 100644 +--- a/include/exec/exec-all.h ++++ b/include/exec/exec-all.h +@@ -106,6 +106,14 @@ void cpu_reloading_memory_map(void); + */ + void cpu_address_space_init(CPUState *cpu, int asidx, + const char *prefix, MemoryRegion *mr); ++/** ++ * cpu_address_space_destroy: ++ * @cpu: CPU for which address space needs to be destroyed ++ * @asidx: integer index of this address space ++ * ++ * Note that with KVM only one address space is supported. ++ */ ++void cpu_address_space_destroy(CPUState *cpu, int asidx); + #endif + + #if !defined(CONFIG_USER_ONLY) && defined(CONFIG_TCG) +diff --git a/include/exec/gdbstub.h b/include/exec/gdbstub.h +index a024a0350d..1a2100d014 100644 +--- a/include/exec/gdbstub.h ++++ b/include/exec/gdbstub.h +@@ -84,6 +84,7 @@ void gdb_register_coprocessor(CPUState *cpu, + gdb_get_reg_cb get_reg, gdb_set_reg_cb set_reg, + int num_regs, const char *xml, int g_pos); + ++void gdb_unregister_coprocessor_all(CPUState *cpu); + /* + * The GDB remote protocol transfers values in target byte order. As + * the gdbstub may be batching up several register values we always +diff --git a/include/hw/core/cpu.h b/include/hw/core/cpu.h +index 5a2571af3e..e50c13f889 100644 +--- a/include/hw/core/cpu.h ++++ b/include/hw/core/cpu.h +@@ -344,6 +344,7 @@ struct CPUState { + QSIMPLEQ_HEAD(, qemu_work_item) work_list; + + CPUAddressSpace *cpu_ases; ++ int cpu_ases_ref_count; + int num_ases; + AddressSpace *as; + MemoryRegion *memory; +@@ -376,6 +377,7 @@ struct CPUState { + int kvm_fd; + struct KVMState *kvm_state; + struct kvm_run *kvm_run; ++ VMChangeStateEntry *vmcse; + struct kvm_dirty_gfn *kvm_dirty_gfns; + uint32_t kvm_fetch_index; + +diff --git a/softmmu/physmem.c b/softmmu/physmem.c +index 2e18947598..75a50fa1b7 100644 +--- a/softmmu/physmem.c ++++ b/softmmu/physmem.c +@@ -748,6 +748,7 @@ void cpu_address_space_init(CPUState *cpu, int asidx, + + if (!cpu->cpu_ases) { + cpu->cpu_ases = g_new0(CPUAddressSpace, cpu->num_ases); ++ cpu->cpu_ases_ref_count = cpu->num_ases; + } + + newas = &cpu->cpu_ases[asidx]; +@@ -760,6 +761,29 @@ void cpu_address_space_init(CPUState *cpu, int asidx, + } + } + ++void cpu_address_space_destroy(CPUState *cpu, int asidx) ++{ ++ CPUAddressSpace *cpuas; ++ ++ assert(asidx < cpu->num_ases); ++ assert(asidx == 0 || !kvm_enabled()); ++ assert(cpu->cpu_ases); ++ ++ cpuas = &cpu->cpu_ases[asidx]; ++ if (tcg_enabled()) { ++ memory_listener_unregister(&cpuas->tcg_as_listener); ++ } ++ ++ address_space_destroy(cpuas->as); ++ ++ if(cpu->cpu_ases_ref_count == 1) { ++ g_free(cpu->cpu_ases); ++ cpu->cpu_ases = NULL; ++ } ++ ++ cpu->cpu_ases_ref_count--; ++} ++ + AddressSpace *cpu_get_address_space(CPUState *cpu, int asidx) + { + /* Return the AddressSpace corresponding to the specified index */ +diff --git a/target/arm/cpu-qom.h b/target/arm/cpu-qom.h +index a22bd506d0..ef83507121 100644 +--- a/target/arm/cpu-qom.h ++++ b/target/arm/cpu-qom.h +@@ -55,6 +55,7 @@ struct ARMCPUClass { + + const ARMCPUInfo *info; + DeviceRealize parent_realize; ++ DeviceUnrealize parent_unrealize; + DeviceReset parent_reset; + }; + +@@ -71,7 +72,9 @@ struct AArch64CPUClass { + }; + + void register_cp_regs_for_features(ARMCPU *cpu); ++void unregister_cp_regs_for_features(ARMCPU *cpu); + void init_cpreg_list(ARMCPU *cpu); ++void destroy_cpreg_list(ARMCPU *cpu); + + /* Callback functions for the generic timer's timers. */ + void arm_gt_ptimer_cb(void *opaque); +diff --git a/target/arm/cpu.c b/target/arm/cpu.c +index ff827d56b7..455ad5aa9e 100644 +--- a/target/arm/cpu.c ++++ b/target/arm/cpu.c +@@ -97,6 +97,16 @@ void arm_register_pre_el_change_hook(ARMCPU *cpu, ARMELChangeHookFn *hook, + QLIST_INSERT_HEAD(&cpu->pre_el_change_hooks, entry, node); + } + ++void arm_unregister_pre_el_change_hooks(ARMCPU *cpu) ++{ ++ ARMELChangeHook *entry, *next; ++ ++ QLIST_FOREACH_SAFE(entry, &cpu->pre_el_change_hooks, node, next) { ++ QLIST_REMOVE(entry, node); ++ g_free(entry); ++ } ++} ++ + void arm_register_el_change_hook(ARMCPU *cpu, ARMELChangeHookFn *hook, + void *opaque) + { +@@ -108,6 +118,16 @@ void arm_register_el_change_hook(ARMCPU *cpu, ARMELChangeHookFn *hook, + QLIST_INSERT_HEAD(&cpu->el_change_hooks, entry, node); + } + ++void arm_unregister_el_change_hooks(ARMCPU *cpu) ++{ ++ ARMELChangeHook *entry, *next; ++ ++ QLIST_FOREACH_SAFE(entry, &cpu->el_change_hooks, node, next) { ++ QLIST_REMOVE(entry, node); ++ g_free(entry); ++ } ++} ++ + static void cp_reg_reset(gpointer key, gpointer value, gpointer opaque) + { + /* Reset a single ARMCPRegInfo register */ +@@ -139,6 +159,70 @@ static void cp_reg_reset(gpointer key, gpointer value, gpointer opaque) + } + } + ++static void arm_cpu_unrealizefn(DeviceState *dev) ++{ ++ ARMCPUClass *acc = ARM_CPU_GET_CLASS(dev); ++ ARMCPU *cpu = ARM_CPU(dev); ++ CPUARMState *env = &cpu->env; ++ CPUState *cs = CPU(dev); ++ ++ /* rock 'n' un-roll, whatever happened in the arm_cpu_realizefn cleanly */ ++ if (cpu->has_el3 || arm_feature(env, ARM_FEATURE_M_SECURITY)) { ++ cpu_address_space_destroy(cs, ARMASIdx_S); ++ } ++ cpu_address_space_destroy(cs, ARMASIdx_NS); ++ ++ destroy_cpreg_list(cpu); ++ arm_cpu_unregister_gdb_regs(cpu); ++ unregister_cp_regs_for_features(cpu); ++ ++ if (cpu->sau_sregion && arm_feature(env, ARM_FEATURE_M_SECURITY)) { ++ g_free(env->sau.rbar); ++ g_free(env->sau.rlar); ++ } ++ ++ if (arm_feature(env, ARM_FEATURE_PMSA) && ++ arm_feature(env, ARM_FEATURE_V7) && ++ cpu->pmsav7_dregion) { ++ if (arm_feature(env, ARM_FEATURE_V8)) { ++ g_free(env->pmsav8.rbar[M_REG_NS]); ++ g_free(env->pmsav8.rlar[M_REG_NS]); ++ if (arm_feature(env, ARM_FEATURE_M_SECURITY)) { ++ g_free(env->pmsav8.rbar[M_REG_S]); ++ g_free(env->pmsav8.rlar[M_REG_S]); ++ } ++ } else { ++ g_free(env->pmsav7.drbar); ++ g_free(env->pmsav7.drsr); ++ g_free(env->pmsav7.dracr); ++ } ++ } ++ ++ if (arm_feature(env, ARM_FEATURE_PMU)) { ++ if (!kvm_enabled()) { ++ arm_unregister_pre_el_change_hooks(cpu); ++ arm_unregister_el_change_hooks(cpu); ++ } ++ ++#ifndef CONFIG_USER_ONLY ++ if (cpu->pmu_timer) { ++ timer_del(cpu->pmu_timer); ++ } ++#endif ++ } ++ ++ cpu_remove_sync(CPU(dev)); ++ acc->parent_unrealize(dev); ++ ++#ifndef CONFIG_USER_ONLY ++ timer_del(cpu->gt_timer[GTIMER_PHYS]); ++ timer_del(cpu->gt_timer[GTIMER_VIRT]); ++ timer_del(cpu->gt_timer[GTIMER_HYP]); ++ timer_del(cpu->gt_timer[GTIMER_SEC]); ++ timer_del(cpu->gt_timer[GTIMER_HYPVIRT]); ++#endif ++} ++ + static void cp_reg_check_reset(gpointer key, gpointer value, gpointer opaque) + { + /* Purely an assertion check: we've already done reset once, +@@ -2021,6 +2105,8 @@ static void arm_cpu_class_init(ObjectClass *oc, void *data) + + device_class_set_props(dc, arm_cpu_properties); + device_class_set_parent_reset(dc, arm_cpu_reset, &acc->parent_reset); ++ device_class_set_parent_unrealize(dc, arm_cpu_unrealizefn, ++ &acc->parent_unrealize); + + cc->class_by_name = arm_cpu_class_by_name; + cc->has_work = arm_cpu_has_work; +diff --git a/target/arm/cpu.h b/target/arm/cpu.h +index ba11468ab5..f7f3308c42 100644 +--- a/target/arm/cpu.h ++++ b/target/arm/cpu.h +@@ -1144,6 +1144,13 @@ void arm_pmu_timer_cb(void *opaque); + * Functions to register as EL change hooks for PMU mode filtering + */ + void pmu_pre_el_change(ARMCPU *cpu, void *ignored); ++ ++/** ++ * arm_unregister_pre_el_change_hook: ++ * unregister all pre EL change hook functions. Generally called during ++ * unrealize'ing leg ++ */ ++void arm_unregister_pre_el_change_hooks(ARMCPU *cpu); + void pmu_post_el_change(ARMCPU *cpu, void *ignored); + + /* +@@ -3616,6 +3623,13 @@ void arm_register_pre_el_change_hook(ARMCPU *cpu, ARMELChangeHookFn *hook, + void arm_register_el_change_hook(ARMCPU *cpu, ARMELChangeHookFn *hook, void + *opaque); + ++/** ++ * arm_unregister_el_change_hook: ++ * unregister all EL change hook functions. Generally called during ++ * unrealize'ing leg ++ */ ++void arm_unregister_el_change_hooks(ARMCPU *cpu); ++ + /** + * arm_rebuild_hflags: + * Rebuild the cached TBFLAGS for arbitrary changed processor state. +diff --git a/target/arm/helper.c b/target/arm/helper.c +index 155d8bf239..3c61b16b56 100644 +--- a/target/arm/helper.c ++++ b/target/arm/helper.c +@@ -507,6 +507,19 @@ void init_cpreg_list(ARMCPU *cpu) + g_list_free(keys); + } + ++void destroy_cpreg_list(ARMCPU *cpu) ++{ ++ assert(cpu->cpreg_indexes); ++ assert(cpu->cpreg_values); ++ assert(cpu->cpreg_vmstate_indexes); ++ assert(cpu->cpreg_vmstate_values); ++ ++ g_free(cpu->cpreg_indexes); ++ g_free(cpu->cpreg_values); ++ g_free(cpu->cpreg_vmstate_indexes); ++ g_free(cpu->cpreg_vmstate_values); ++} ++ + /* + * Some registers are not accessible from AArch32 EL3 if SCR.NS == 0. + */ +@@ -8671,6 +8684,18 @@ void register_cp_regs_for_features(ARMCPU *cpu) + #endif + } + ++void unregister_cp_regs_for_features(ARMCPU *cpu) ++{ ++ CPUARMState *env = &cpu->env; ++ if (arm_feature(env, ARM_FEATURE_M)) { ++ /* M profile has no coprocessor registers */ ++ return; ++ } ++ ++ /* empty it all. unregister all the coprocessor registers */ ++ g_hash_table_remove_all(cpu->cp_regs); ++} ++ + void arm_cpu_register_gdb_regs_for_features(ARMCPU *cpu) + { + CPUState *cs = CPU(cpu); +@@ -8709,6 +8734,12 @@ void arm_cpu_register_gdb_regs_for_features(ARMCPU *cpu) + + } + ++void arm_cpu_unregister_gdb_regs(ARMCPU *cpu) ++{ ++ CPUState *cs = CPU(cpu); ++ gdb_unregister_coprocessor_all(cs); ++} ++ + /* Sort alphabetically by type name, except for "any". */ + static gint arm_cpu_list_compare(gconstpointer a, gconstpointer b) + { +diff --git a/target/arm/internals.h b/target/arm/internals.h +index cd2ea8a388..fbdc3f2eab 100644 +--- a/target/arm/internals.h ++++ b/target/arm/internals.h +@@ -173,6 +173,7 @@ static inline int r14_bank_number(int mode) + void arm_cpu_register_gdb_regs_for_features(ARMCPU *cpu); + void arm_translate_init(void); + ++void arm_cpu_unregister_gdb_regs(ARMCPU *cpu); + #ifdef CONFIG_TCG + void arm_cpu_synchronize_from_tb(CPUState *cs, const TranslationBlock *tb); + #endif /* CONFIG_TCG */ +diff --git a/target/arm/kvm64.c b/target/arm/kvm64.c +index 59982d470d..19d3eac253 100644 +--- a/target/arm/kvm64.c ++++ b/target/arm/kvm64.c +@@ -839,7 +839,9 @@ int kvm_arch_init_vcpu(CPUState *cs) + return -EINVAL; + } + +- qemu_add_vm_change_state_handler(kvm_arm_vm_state_change, cs); ++ if (qemu_present_cpu(cs)) ++ cs->vmcse = qemu_add_vm_change_state_handler(kvm_arm_vm_state_change, ++ cs); + + /* Determine init features for this CPU */ + memset(cpu->kvm_init_features, 0, sizeof(cpu->kvm_init_features)); +@@ -904,6 +906,8 @@ int kvm_arch_init_vcpu(CPUState *cs) + + int kvm_arch_destroy_vcpu(CPUState *cs) + { ++ if (qemu_present_cpu(cs)) ++ qemu_del_vm_change_state_handler(cs->vmcse); + return 0; + } + +-- +2.30.2 + diff --git a/tools/packaging/qemu/patches/6.1.x/0023-armcpuhp-initial-pvtime-and-pmu-for-all-possible-cpu.patch b/tools/packaging/qemu/patches/6.1.x/0023-armcpuhp-initial-pvtime-and-pmu-for-all-possible-cpu.patch new file mode 100644 index 0000000000..80c29cd30c --- /dev/null +++ b/tools/packaging/qemu/patches/6.1.x/0023-armcpuhp-initial-pvtime-and-pmu-for-all-possible-cpu.patch @@ -0,0 +1,38 @@ +From 5864b2046f2481772bb1f28aa4e4bbc5258ad1f1 Mon Sep 17 00:00:00 2001 +From: Huang Shijie +Date: Wed, 8 Dec 2021 13:35:28 +0800 +Subject: [PATCH 23/28] armcpuhp: initial pvtime and pmu for all possible cpu + +initial pvtime and pmu for all possible cpus when machvirt init. + +Signed-off-by: Huang Shijie +Signed-off-by: Huang Shijie +--- + hw/arm/virt.c | 4 +++- + 1 file changed, 3 insertions(+), 1 deletion(-) + +diff --git a/hw/arm/virt.c b/hw/arm/virt.c +index ab35bd51af..3f4763367a 100644 +--- a/hw/arm/virt.c ++++ b/hw/arm/virt.c +@@ -1933,6 +1933,7 @@ static void virt_cpu_set_properties(Object *cpuobj, const CPUArchId *cpu_slot) + */ + static void virt_cpu_post_init(VirtMachineState *vms, MemoryRegion *sysmem) + { ++ CPUArchIdList *possible_cpus = vms->parent.possible_cpus; + int max_cpus = MACHINE(vms)->smp.max_cpus; + bool aarch64, pmu, steal_time; + CPUState *cpu; +@@ -1965,7 +1966,8 @@ static void virt_cpu_post_init(VirtMachineState *vms, MemoryRegion *sysmem) + memory_region_add_subregion(sysmem, pvtime_reg_base, pvtime); + } + +- CPU_FOREACH(cpu) { ++ for (int n = 0; n < possible_cpus->len; n++) { ++ cpu = qemu_get_possible_cpu(n); + if (pmu) { + assert(arm_feature(&ARM_CPU(cpu)->env, ARM_FEATURE_PMU)); + if (kvm_irqchip_in_kernel()) { +-- +2.30.2 + diff --git a/tools/packaging/qemu/patches/6.1.x/0024-armcpuhp-add-cpu-hotunplug-frame-work-in-acpi-device.patch b/tools/packaging/qemu/patches/6.1.x/0024-armcpuhp-add-cpu-hotunplug-frame-work-in-acpi-device.patch new file mode 100644 index 0000000000..0768d03afd --- /dev/null +++ b/tools/packaging/qemu/patches/6.1.x/0024-armcpuhp-add-cpu-hotunplug-frame-work-in-acpi-device.patch @@ -0,0 +1,47 @@ +From b165fbe697c6f029973fffea151e384247639829 Mon Sep 17 00:00:00 2001 +From: Huang Shijie +Date: Wed, 8 Dec 2021 16:15:33 +0800 +Subject: [PATCH 24/28] armcpuhp: add cpu hotunplug frame work in acpi device + handle + +Signed-off-by: Huang Shijie +Signed-off-by: Huang Shijie +--- + hw/acpi/generic_event_device.c | 6 ++++++ + 1 file changed, 6 insertions(+) + +diff --git a/hw/acpi/generic_event_device.c b/hw/acpi/generic_event_device.c +index 815f4a91ce..22a3fb348b 100644 +--- a/hw/acpi/generic_event_device.c ++++ b/hw/acpi/generic_event_device.c +@@ -12,7 +12,9 @@ + #include "qemu/osdep.h" + #include "qapi/error.h" + #include "hw/acpi/acpi.h" ++#include "hw/acpi/cpu.h" + #include "hw/acpi/generic_event_device.h" ++#include "hw/arm/virt.h" + #include "hw/irq.h" + #include "hw/mem/pc-dimm.h" + #include "hw/mem/nvdimm.h" +@@ -288,6 +290,8 @@ static void acpi_ged_unplug_request_cb(HotplugHandler *hotplug_dev, + if ((object_dynamic_cast(OBJECT(dev), TYPE_PC_DIMM) && + !(object_dynamic_cast(OBJECT(dev), TYPE_NVDIMM)))) { + acpi_memory_unplug_request_cb(hotplug_dev, &s->memhp_state, dev, errp); ++ } else if (object_dynamic_cast(OBJECT(dev), TYPE_CPU)) { ++ acpi_cpu_unplug_request_cb(hotplug_dev, &s->cpuhp_state, dev, errp); + } else { + error_setg(errp, "acpi: device unplug request for unsupported device" + " type: %s", object_get_typename(OBJECT(dev))); +@@ -301,6 +305,8 @@ static void acpi_ged_unplug_cb(HotplugHandler *hotplug_dev, + + if (object_dynamic_cast(OBJECT(dev), TYPE_PC_DIMM)) { + acpi_memory_unplug_cb(&s->memhp_state, dev, errp); ++ } else if (object_dynamic_cast(OBJECT(dev), TYPE_CPU)) { ++ acpi_cpu_unplug_cb(&s->cpuhp_state, dev, errp); + } else { + error_setg(errp, "acpi: device unplug for unsupported device" + " type: %s", object_get_typename(OBJECT(dev))); +-- +2.30.2 + diff --git a/tools/packaging/qemu/patches/6.1.x/0025-cleanup-code-of-arm-cpu-hotplug-support.patch b/tools/packaging/qemu/patches/6.1.x/0025-cleanup-code-of-arm-cpu-hotplug-support.patch new file mode 100644 index 0000000000..6f0daf780b --- /dev/null +++ b/tools/packaging/qemu/patches/6.1.x/0025-cleanup-code-of-arm-cpu-hotplug-support.patch @@ -0,0 +1,180 @@ +From ee68b08a7194ea9fefdf00ee57fa9edcb56b4359 Mon Sep 17 00:00:00 2001 +From: Huang Shijie +Date: Wed, 8 Dec 2021 17:08:07 +0800 +Subject: [PATCH 25/28] cleanup code of arm cpu hotplug support + +Signed-off-by: Huang Shijie +Signed-off-by: Huang Shijie +--- + hw/arm/virt.c | 136 +------------------------------------------------- + 1 file changed, 1 insertion(+), 135 deletions(-) + +diff --git a/hw/arm/virt.c b/hw/arm/virt.c +index 3f4763367a..5c04abb352 100644 +--- a/hw/arm/virt.c ++++ b/hw/arm/virt.c +@@ -1585,38 +1585,6 @@ static void virt_remove_disabled_cpus(VirtMachineState *vms) + } + } + +-/*static bool virt_pmu_init(VirtMachineState *vms) +-{ +- CPUArchIdList *possible_cpus = vms->parent.possible_cpus; +- ARMCPU *armcpu; +- int n; */ +- +- /* +- * As of now KVM ensures that within the host all the vcpus have same +- * features configured. This cannot be changed later and cannot be diferent +- * for new vcpus being plugged in. Also, -cpu option/virt machine cpu-type +- * ensures all the vcpus are identical. +- */ +-/* for (n = 0; n < possible_cpus->len; n++) { +- CPUState *cpu = qemu_get_possible_cpu(n); +- armcpu = ARM_CPU(cpu); +- +- if (!arm_feature(&armcpu->env, ARM_FEATURE_PMU)) { +- warn_report("Not all vcpus might have PMU initialized"); +- return false; +- } +- +- if (kvm_enabled()) { +- if (kvm_irqchip_in_kernel()) { +- kvm_arm_pmu_set_irq(cpu, PPI(VIRTUAL_PMU_IRQ)); +- } +- kvm_arm_pmu_init(cpu); +- } +- } +- +- return true; +-}*/ +- + static void *machvirt_dtb(const struct arm_boot_info *binfo, int *fdt_size) + { + const VirtMachineState *board = container_of(binfo, VirtMachineState, +@@ -2120,110 +2088,11 @@ static void machvirt_init(MachineState *machine) + Object *cpuobj; + CPUState *cs; + +-/* if (n >= smp_cpus) { +- break; +- } +-*/ + cpuobj = object_new(possible_cpus->cpus[n].type); + cs = CPU(cpuobj); +-/* object_property_set_int(cpuobj, "mp-affinity", +- possible_cpus->cpus[n].arch_id, NULL); +- +- cs = CPU(cpuobj); +- cs->cpu_index = n; +- +- numa_cpu_pre_plug(&possible_cpus->cpus[cs->cpu_index], DEVICE(cpuobj), +- &error_fatal); +-*/ + aarch64 &= object_property_get_bool(cpuobj, "aarch64", NULL); + object_property_set_int(cpuobj, "core-id", n, NULL); + +-/* if (!vms->secure) { +- object_property_set_bool(cpuobj, "has_el3", false, NULL); +- } +- +- if (!vms->virt && object_property_find(cpuobj, "has_el2")) { +- object_property_set_bool(cpuobj, "has_el2", false, NULL); +- } +- +- if (vms->psci_conduit != QEMU_PSCI_CONDUIT_DISABLED) { +- object_property_set_int(cpuobj, "psci-conduit", vms->psci_conduit, +- NULL); +-*/ +- /* Secondary CPUs start in PSCI powered-down state */ +-/* if (n > 0) { +- object_property_set_bool(cpuobj, "start-powered-off", true, +- NULL); +- } +- } +- +- if (vmc->kvm_no_adjvtime && +- object_property_find(cpuobj, "kvm-no-adjvtime")) { +- object_property_set_bool(cpuobj, "kvm-no-adjvtime", true, NULL); +- } +- +- if (vmc->no_kvm_steal_time && +- object_property_find(cpuobj, "kvm-steal-time")) { +- object_property_set_bool(cpuobj, "kvm-steal-time", false, NULL); +- } +- +- if (vmc->no_pmu && object_property_find(cpuobj, "pmu")) { +- object_property_set_bool(cpuobj, "pmu", false, NULL); +- } +- +- if (object_property_find(cpuobj, "reset-cbar")) { +- object_property_set_int(cpuobj, "reset-cbar", +- vms->memmap[VIRT_CPUPERIPHS].base, +- &error_abort); +- } +- +- object_property_set_link(cpuobj, "memory", OBJECT(sysmem), +- &error_abort); +- if (vms->secure) { +- object_property_set_link(cpuobj, "secure-memory", +- OBJECT(secure_sysmem), &error_abort); +- } +-*/ +-// if (vms->mte) { +- /* Create the memory region only once, but link to all cpus. */ +-// if (!tag_sysmem) { +- /* +- * The property exists only if MemTag is supported. +- * If it is, we must allocate the ram to back that up. +- */ +-/* if (!object_property_find(cpuobj, "tag-memory")) { +- error_report("MTE requested, but not supported " +- "by the guest CPU"); +- exit(1); +- } +- +- tag_sysmem = g_new(MemoryRegion, 1); +- memory_region_init(tag_sysmem, OBJECT(machine), +- "tag-memory", UINT64_MAX / 32); +- +- if (vms->secure) { +- secure_tag_sysmem = g_new(MemoryRegion, 1); +- memory_region_init(secure_tag_sysmem, OBJECT(machine), +- "secure-tag-memory", UINT64_MAX / 32); +-*/ +- /* As with ram, secure-tag takes precedence over tag. */ +-/* memory_region_add_subregion_overlap(secure_tag_sysmem, 0, +- tag_sysmem, -1); +- } +- } +- +- object_property_set_link(cpuobj, "tag-memory", OBJECT(tag_sysmem), +- &error_abort); +- if (vms->secure) { +- object_property_set_link(cpuobj, "secure-tag-memory", +- OBJECT(secure_tag_sysmem), +- &error_abort); +- } +- } +- +- qdev_realize(DEVICE(cpuobj), NULL, &error_fatal); +- object_unref(cpuobj); +-*/ + if (n < smp_cpus) { + char *core_id = g_strdup_printf("core%d", n); + qdev_set_id(DEVICE(cpuobj),core_id); +@@ -2283,10 +2152,7 @@ static void machvirt_init(MachineState *machine) + + virt_cpu_post_init(vms, sysmem); + +-// if (!vmc->no_pmu && virt_pmu_init(vms)) { +-// vms->pmu = true; +- fdt_add_pmu_nodes(vms); +-// } ++ fdt_add_pmu_nodes(vms); + create_uart(vms, VIRT_UART, sysmem, serial_hd(0)); + + if (vms->secure) { +-- +2.30.2 + diff --git a/tools/packaging/qemu/patches/6.1.x/0026-armcpuhp-set-cpu-disabled-to-true-when-initialize-cp.patch b/tools/packaging/qemu/patches/6.1.x/0026-armcpuhp-set-cpu-disabled-to-true-when-initialize-cp.patch new file mode 100644 index 0000000000..659f797fb7 --- /dev/null +++ b/tools/packaging/qemu/patches/6.1.x/0026-armcpuhp-set-cpu-disabled-to-true-when-initialize-cp.patch @@ -0,0 +1,65 @@ +From 0e3ad502669659822083fd9fde80220e5a9af0ed Mon Sep 17 00:00:00 2001 +From: Huang Shijie +Date: Fri, 10 Dec 2021 15:49:06 +0800 +Subject: [PATCH 26/28] armcpuhp: set cpu->disabled to true when initialize cpu + +The new qemu edition remove the instance init fn of arm cpu. revert is +back and set cpu->disabled to true in it. + +Signed-off-by: Huang Shijie +Signed-off-by: Huang Shijie +--- + target/arm/cpu64.c | 16 ++++++++++------ + 1 file changed, 10 insertions(+), 6 deletions(-) + +diff --git a/target/arm/cpu64.c b/target/arm/cpu64.c +index 2134be0b67..249dc24849 100644 +--- a/target/arm/cpu64.c ++++ b/target/arm/cpu64.c +@@ -895,7 +895,6 @@ static void aarch64_cpu_class_init(ObjectClass *oc, void *data) + { + CPUClass *cc = CPU_CLASS(oc); + DeviceClass *dc = DEVICE_CLASS(oc); +- CPUState *cs = CPU(oc); + + dc->user_creatable = true; + cc->gdb_read_register = aarch64_cpu_gdb_read_register; +@@ -909,11 +908,6 @@ static void aarch64_cpu_class_init(ObjectClass *oc, void *data) + object_class_property_set_description(oc, "aarch64", + "Set on/off to enable/disable aarch64 " + "execution state "); +- /* +- * we start every ARM64 vcpu as disabled possible vcpu. It needs to be +- * enabled explicitly +- */ +- cs->disabled = true; + } + + static void aarch64_cpu_instance_init(Object *obj) +@@ -924,6 +918,15 @@ static void aarch64_cpu_instance_init(Object *obj) + arm_cpu_post_init(obj); + } + ++static void aarch64_cpu_initfn(Object *obj) ++{ ++ CPUState *cs = CPU(obj); ++ /* ++ * we start every ARM64 vcpu as disabled possible vcpu. It needs to be ++ * enabled explicitly ++ */ ++ cs->disabled = true; ++} + static void cpu_register_class_init(ObjectClass *oc, void *data) + { + ARMCPUClass *acc = ARM_CPU_CLASS(oc); +@@ -952,6 +955,7 @@ static const TypeInfo aarch64_cpu_type_info = { + .parent = TYPE_ARM_CPU, + .instance_size = sizeof(ARMCPU), + .instance_finalize = aarch64_cpu_finalizefn, ++ .instance_init = aarch64_cpu_initfn, + .abstract = true, + .class_size = sizeof(AArch64CPUClass), + .class_init = aarch64_cpu_class_init, +-- +2.30.2 + diff --git a/tools/packaging/qemu/patches/6.1.x/0027-armcpuhp-clean-acpi-ged-call-back.patch b/tools/packaging/qemu/patches/6.1.x/0027-armcpuhp-clean-acpi-ged-call-back.patch new file mode 100644 index 0000000000..943d48bff3 --- /dev/null +++ b/tools/packaging/qemu/patches/6.1.x/0027-armcpuhp-clean-acpi-ged-call-back.patch @@ -0,0 +1,63 @@ +From e9376db8e4113e2222543a9a4cdc68a40b78b69c Mon Sep 17 00:00:00 2001 +From: Huang Shijie +Date: Fri, 10 Dec 2021 15:51:51 +0800 +Subject: [PATCH 27/28] armcpuhp: clean acpi ged call back + +The new qemu edition has add acpi ged call back and should clean the +related patch before. + +Signed-off-by: Huang Shijie +Signed-off-by: Huang Shijie +--- + hw/acpi/generic_event_device.c | 28 ---------------------------- + 1 file changed, 28 deletions(-) + +diff --git a/hw/acpi/generic_event_device.c b/hw/acpi/generic_event_device.c +index 22a3fb348b..928593ab2c 100644 +--- a/hw/acpi/generic_event_device.c ++++ b/hw/acpi/generic_event_device.c +@@ -249,32 +249,6 @@ static void acpi_ged_device_plug_cb(HotplugHandler *hotplug_dev, + } + } + +-static void acpi_ged_device_unplug_request_cb(HotplugHandler *hotplug_dev, +- DeviceState *dev, Error **errp) +-{ +- AcpiGedState *s = ACPI_GED(hotplug_dev); +- +- if (object_dynamic_cast(OBJECT(dev), TYPE_CPU)) { +- acpi_cpu_unplug_request_cb(hotplug_dev, &s->cpuhp_state, dev, errp); +- } else { +- error_setg(errp, "virt: device unplug request for the unsupported device" +- " type: %s", object_get_typename(OBJECT(dev))); +- } +-} +- +-static void acpi_ged_device_unplug_cb(HotplugHandler *hotplug_dev, +- DeviceState *dev, Error **errp) +-{ +- AcpiGedState *s = ACPI_GED(hotplug_dev); +- +- if (object_dynamic_cast(OBJECT(dev), TYPE_CPU)) { +- acpi_cpu_unplug_cb(&s->cpuhp_state, dev, errp); +- } else { +- error_setg(errp, "virt: device plug request for unsupported device" +- " type: %s", object_get_typename(OBJECT(dev))); +- } +-} +- + static void acpi_ged_ospm_status(AcpiDeviceIf *adev, ACPIOSTInfoList ***list) + { + AcpiGedState *s = ACPI_GED(adev); +@@ -461,8 +435,6 @@ static void acpi_ged_class_init(ObjectClass *class, void *data) + dc->vmsd = &vmstate_acpi_ged; + + hc->plug = acpi_ged_device_plug_cb; +- hc->unplug_request = acpi_ged_device_unplug_request_cb; +- hc->unplug = acpi_ged_device_unplug_cb; + hc->unplug_request = acpi_ged_unplug_request_cb; + hc->unplug = acpi_ged_unplug_cb; + +-- +2.30.2 + diff --git a/tools/packaging/qemu/patches/6.1.x/0028-armcpuhp-fix-bug-when-maxvcpu-number-larger-than-8.patch b/tools/packaging/qemu/patches/6.1.x/0028-armcpuhp-fix-bug-when-maxvcpu-number-larger-than-8.patch new file mode 100644 index 0000000000..b5680ce525 --- /dev/null +++ b/tools/packaging/qemu/patches/6.1.x/0028-armcpuhp-fix-bug-when-maxvcpu-number-larger-than-8.patch @@ -0,0 +1,230 @@ +From e9ec5f6617c1811f244618e3a23c29ea2fb27c6a Mon Sep 17 00:00:00 2001 +From: Huang Shijie +Date: Thu, 16 Dec 2021 11:36:25 +0800 +Subject: [PATCH 28/28] armcpuhp: fix bug when maxvcpu number larger than 8 + +The gic version finalized after the use the gic version in +virt_cpu_mp_affinity. But VIRT_GICVERSION_HOST must be determined before +used it. So, must call finalize_gic_version before used gic_version. + +For now cpu socket and thread is not supported, thus we need set thread +and socket to 1 if they are larger than 1. + +Signed-off-by: Huang Shijie +Signed-off-by: Huang Shijie +--- + hw/arm/virt.c | 183 ++++++++++++++++++++++++++++---------------------- + 1 file changed, 102 insertions(+), 81 deletions(-) + +diff --git a/hw/arm/virt.c b/hw/arm/virt.c +index 5c04abb352..23dd2337f6 100644 +--- a/hw/arm/virt.c ++++ b/hw/arm/virt.c +@@ -1661,85 +1661,6 @@ void virt_machine_done(Notifier *notifier, void *data) + virt_remove_disabled_cpus(vms); + } + +-static uint64_t virt_cpu_mp_affinity(VirtMachineState *vms, int idx) +-{ +- uint8_t clustersz = ARM_DEFAULT_CPUS_PER_CLUSTER; +- VirtMachineClass *vmc = VIRT_MACHINE_GET_CLASS(vms); +- +- if (!vmc->disallow_affinity_adjustment) { +- /* Adjust MPIDR like 64-bit KVM hosts, which incorporate the +- * GIC's target-list limitations. 32-bit KVM hosts currently +- * always create clusters of 4 CPUs, but that is expected to +- * change when they gain support for gicv3. When KVM is enabled +- * it will override the changes we make here, therefore our +- * purposes are to make TCG consistent (with 64-bit KVM hosts) +- * and to improve SGI efficiency. +- */ +- if (vms->gic_version == VIRT_GIC_VERSION_3) { +- clustersz = GICV3_TARGETLIST_BITS; +- } else { +- clustersz = GIC_TARGETLIST_BITS; +- } +- } +- return arm_cpu_mp_affinity(idx, clustersz); +-} +- +-static void virt_set_memmap(VirtMachineState *vms) +-{ +- MachineState *ms = MACHINE(vms); +- hwaddr base, device_memory_base, device_memory_size; +- int i; +- +- vms->memmap = extended_memmap; +- +- for (i = 0; i < ARRAY_SIZE(base_memmap); i++) { +- vms->memmap[i] = base_memmap[i]; +- } +- +- if (ms->ram_slots > ACPI_MAX_RAM_SLOTS) { +- error_report("unsupported number of memory slots: %"PRIu64, +- ms->ram_slots); +- exit(EXIT_FAILURE); +- } +- +- /* +- * We compute the base of the high IO region depending on the +- * amount of initial and device memory. The device memory start/size +- * is aligned on 1GiB. We never put the high IO region below 256GiB +- * so that if maxram_size is < 255GiB we keep the legacy memory map. +- * The device region size assumes 1GiB page max alignment per slot. +- */ +- device_memory_base = +- ROUND_UP(vms->memmap[VIRT_MEM].base + ms->ram_size, GiB); +- device_memory_size = ms->maxram_size - ms->ram_size + ms->ram_slots * GiB; +- +- /* Base address of the high IO region */ +- base = device_memory_base + ROUND_UP(device_memory_size, GiB); +- if (base < device_memory_base) { +- error_report("maxmem/slots too huge"); +- exit(EXIT_FAILURE); +- } +- if (base < vms->memmap[VIRT_MEM].base + LEGACY_RAMLIMIT_BYTES) { +- base = vms->memmap[VIRT_MEM].base + LEGACY_RAMLIMIT_BYTES; +- } +- +- for (i = VIRT_LOWMEMMAP_LAST; i < ARRAY_SIZE(extended_memmap); i++) { +- hwaddr size = extended_memmap[i].size; +- +- base = ROUND_UP(base, size); +- vms->memmap[i].base = base; +- vms->memmap[i].size = size; +- base += size; +- } +- vms->highest_gpa = base - 1; +- if (device_memory_size > 0) { +- ms->device_memory = g_malloc0(sizeof(*ms->device_memory)); +- ms->device_memory->base = device_memory_base; +- memory_region_init(&ms->device_memory->mr, OBJECT(vms), +- "device-memory", device_memory_size); +- } +-} +- + /* + * finalize_gic_version - Determines the final gic_version + * according to the gic-version property +@@ -1839,6 +1760,88 @@ static void finalize_gic_version(VirtMachineState *vms) + } + } + ++static uint64_t virt_cpu_mp_affinity(VirtMachineState *vms, int idx) ++{ ++ uint8_t clustersz = ARM_DEFAULT_CPUS_PER_CLUSTER; ++ VirtMachineClass *vmc = VIRT_MACHINE_GET_CLASS(vms); ++ ++ if(vms->gic_version == VIRT_GIC_VERSION_HOST) ++ finalize_gic_version(vms); ++ ++ if (!vmc->disallow_affinity_adjustment) { ++ /* Adjust MPIDR like 64-bit KVM hosts, which incorporate the ++ * GIC's target-list limitations. 32-bit KVM hosts currently ++ * always create clusters of 4 CPUs, but that is expected to ++ * change when they gain support for gicv3. When KVM is enabled ++ * it will override the changes we make here, therefore our ++ * purposes are to make TCG consistent (with 64-bit KVM hosts) ++ * and to improve SGI efficiency. ++ */ ++ if (vms->gic_version == VIRT_GIC_VERSION_3) { ++ clustersz = GICV3_TARGETLIST_BITS; ++ } else { ++ clustersz = GIC_TARGETLIST_BITS; ++ } ++ } ++ return arm_cpu_mp_affinity(idx, clustersz); ++} ++ ++static void virt_set_memmap(VirtMachineState *vms) ++{ ++ MachineState *ms = MACHINE(vms); ++ hwaddr base, device_memory_base, device_memory_size; ++ int i; ++ ++ vms->memmap = extended_memmap; ++ ++ for (i = 0; i < ARRAY_SIZE(base_memmap); i++) { ++ vms->memmap[i] = base_memmap[i]; ++ } ++ ++ if (ms->ram_slots > ACPI_MAX_RAM_SLOTS) { ++ error_report("unsupported number of memory slots: %"PRIu64, ++ ms->ram_slots); ++ exit(EXIT_FAILURE); ++ } ++ ++ /* ++ * We compute the base of the high IO region depending on the ++ * amount of initial and device memory. The device memory start/size ++ * is aligned on 1GiB. We never put the high IO region below 256GiB ++ * so that if maxram_size is < 255GiB we keep the legacy memory map. ++ * The device region size assumes 1GiB page max alignment per slot. ++ */ ++ device_memory_base = ++ ROUND_UP(vms->memmap[VIRT_MEM].base + ms->ram_size, GiB); ++ device_memory_size = ms->maxram_size - ms->ram_size + ms->ram_slots * GiB; ++ ++ /* Base address of the high IO region */ ++ base = device_memory_base + ROUND_UP(device_memory_size, GiB); ++ if (base < device_memory_base) { ++ error_report("maxmem/slots too huge"); ++ exit(EXIT_FAILURE); ++ } ++ if (base < vms->memmap[VIRT_MEM].base + LEGACY_RAMLIMIT_BYTES) { ++ base = vms->memmap[VIRT_MEM].base + LEGACY_RAMLIMIT_BYTES; ++ } ++ ++ for (i = VIRT_LOWMEMMAP_LAST; i < ARRAY_SIZE(extended_memmap); i++) { ++ hwaddr size = extended_memmap[i].size; ++ ++ base = ROUND_UP(base, size); ++ vms->memmap[i].base = base; ++ vms->memmap[i].size = size; ++ base += size; ++ } ++ vms->highest_gpa = base - 1; ++ if (device_memory_size > 0) { ++ ms->device_memory = g_malloc0(sizeof(*ms->device_memory)); ++ ms->device_memory->base = device_memory_base; ++ memory_region_init(&ms->device_memory->mr, OBJECT(vms), ++ "device-memory", device_memory_size); ++ } ++} ++ + static void virt_cpu_set_properties(Object *cpuobj, const CPUArchId *cpu_slot) + { + MachineState *ms = MACHINE(qdev_get_machine()); +@@ -2928,9 +2931,27 @@ static void virt_smp_parse(MachineState *ms, SMPConfiguration *config, Error **e + unsigned threads = config->has_threads ? config->threads: 1; + unsigned int max_cpus; + ++ if(config->has_cores) { ++ config->cores = cpus; ++ cores = cpus; ++ } + if (sockets > 1 || threads > 1) { +- error_report("does not support more than one socket or thread"); +- exit(1); ++ printf("does not support more than one socket or thread, will put sockets and threads to cores"); ++ if(config->has_cores) { ++ if(config->has_sockets && config->has_threads) { ++ threads = 1; ++ sockets = 1; ++ config->sockets = 1; ++ config->threads = 1; ++ } else if (config->has_sockets) { ++ sockets = 1; ++ config->sockets = 1; ++ } else { ++ config->threads = 1; ++ threads = 1; ++ } ++ } else ++ exit(1); + } + + if (cores != cpus) { +-- +2.30.2 + diff --git a/tools/packaging/qemu/patches/6.1.x/no_patches.txt b/tools/packaging/qemu/patches/6.1.x/no_patches.txt deleted file mode 100644 index e69de29bb2..0000000000