qemu/target-arm-Add-support-of-unrealize-ARMCPU-during-vC.patch

295 lines
9.1 KiB
Diff
Raw Permalink Normal View History

QEMU update to version 8.2.0-6: - coro: support live patch for libcare - tests/acpi: Update expected ACPI tables for vcpu hotplug(update BinDir) - arm/virt: Require mc->has_hotpluggable_cpus for cold-plugged vcpu - arm/virt: Consider has_ged when set mc->has_hotpluggable_cpus - arm/virt-acpi: Require possible_cpu_arch_ids for build_cpus_aml() - acpi/ged: Remove cpuhp field of ged - acpi/ged: Init cpu hotplug only when machine support it - intc/gicv3: Fixes for vcpu hotplug - arm/kvm: Set psci smccc filter only with vcpu hotplug - accel/kvm: Use correct id for parked vcpu - arm/virt: Fix adjudgement of core_id for vcpu hotplugged - arm/virt.c: Convey local_err when set psci-conduit - system/cpus: Fix resume_all_vcpus() under vCPU hotplug condition - system/cpus: Fix pause_all_vcpus() under concurrent environment - acpi/cpu: Fix cpu_hotplug_hw_init() - arm/cpu: Some fixes for arm_cpu_unrealizefn() - system/physmem: Fix possible double free when destroy cpu as - hw/arm/virt: Expose cold-booted CPUs as MADT GICC Enabled - tcg/mttcg: enable threads to unregister in tcg_ctxs[] - hw/arm: Support hotplug capability check using _OSC method - target/arm/kvm,tcg: Register/Handle SMCCC hypercall exits to VMM/Qemu - target/arm/kvm: Write CPU state back to KVM on reset - target/arm: Add support of *unrealize* ARMCPU during vCPU Hot-unplug - physmem,gdbstub: Common helping funcs/changes to *unrealize* vCPU - hw/arm: Changes required for reset and to support next boot - arm/virt: Update the guest(via GED) about CPU hot-(un)plug events - hw/intc/arm-gicv3*: Changes required to (re)init the vCPU register info - hw/arm,gicv3: Changes to update GIC with vCPU hot-plug notification - arm/virt: Changes to (un)wire GICC<->vCPU IRQs during hot-(un)plug - arm/virt: Add/update basic hot-(un)plug framework - hw/acpi: Update ACPI GED framework to support vCPU Hotplug - arm/virt: Release objects for *disabled* possible vCPUs after init - hw/acpi: Make _MAT method optional - hw/arm: MADT Tbl change to size the guest with possible vCPUs - hw/acpi: Update GED _EVT method AML with cpu scan - hw/acpi: ACPI/AML Changes to reflect the correct _STA.{PRES,ENA} Bits to Guest - arm/virt: Make ARM vCPU *present* status ACPI *persistent* - arm/virt/acpi: Build CPUs AML with CPU Hotplug support - tests/acpi/bios-tables-test: Allow changes to virt/DSDT file - acpi/cpu: Add cpu_cppc building support - arm/virt/acpi: Factor out CPPC building from DSDT CPU aml - hw/acpi: Update CPUs AML with cpu-(ctrl)dev change - arm/virt: Create GED dev before *disabled* CPU Objs are destroyed - arm/virt: Add cpu hotplug events to GED during creation - hw/acpi: Init GED framework with cpu hotplug events - hw/acpi: Use qemu_present_cpu() API in ACPI CPU hotplug init - hw/acpi: Add ACPI CPU hotplug init stub - arm/acpi: Enable ACPI support for vcpu hotplug - hw/acpi: Move CPU ctrl-dev MMIO region len macro to common header file - arm/virt: Init PMU at host for all possible vcpus - arm/virt,gicv3: Changes to pre-size GIC with possible vcpus @machine init - arm/virt,kvm: Pre-create disabled possible vCPUs @machine init - accel/kvm: Extract common KVM vCPU {creation,parking} code - arm/virt,target/arm: Machine init time change common to vCPU {cold|hot}-plug - hw/arm/virt: Move setting of common CPU properties in a function - cpus-common: Add common CPU utility for possible vCPUs - arm/virt,target/arm: Add new ARMCPU {socket,cluster,core,thread}-id property Signed-off-by: Jiabo Feng <fengjiabo1@huawei.com>
2024-04-10 20:59:57 +08:00
From b311feda2078e7ee8f060531d4d061beccbc2f77 Mon Sep 17 00:00:00 2001
From: Salil Mehta <salil.mehta@huawei.com>
Date: Sat, 9 May 2020 20:13:10 +0100
Subject: [PATCH] target/arm: Add support of *unrealize* ARMCPU during vCPU
Hot-unplug
vCPU Hot-unplug will result in QOM CPU object unrealization which will do away
with all the vCPU thread creations, allocations, registrations that happened
as part of the realization process. This change introduces the ARM CPU unrealize
function taking care of exactly that.
Note, initialized KVM vCPUs are not destroyed in host KVM but their Qemu context
is parked at the QEMU KVM layer.
Co-developed-by: Salil Mehta <salil.mehta@huawei.com>
Signed-off-by: Salil Mehta <salil.mehta@huawei.com>
Co-developed-by: Keqian Zhu <zhukeqian1@huawei.com>
Signed-off-by: Keqian Zhu <zhukeqian1@huawei.com>
Reported-by: Vishnu Pajjuri <vishnu@os.amperecomputing.com>
[VP: Identified CPU stall issue & suggested probable fix]
Signed-off-by: Salil Mehta <salil.mehta@huawei.com>
---
target/arm/cpu.c | 101 +++++++++++++++++++++++++++++++++++++++++
target/arm/cpu.h | 14 ++++++
target/arm/gdbstub.c | 6 +++
target/arm/helper.c | 25 ++++++++++
target/arm/internals.h | 3 ++
target/arm/kvm64.c | 4 ++
6 files changed, 153 insertions(+)
diff --git a/target/arm/cpu.c b/target/arm/cpu.c
index 18b8a79c8f..501f88eb2f 100644
--- a/target/arm/cpu.c
+++ b/target/arm/cpu.c
@@ -142,6 +142,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)
{
@@ -153,6 +163,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 */
@@ -2390,6 +2410,85 @@ static void arm_cpu_realizefn(DeviceState *dev, Error **errp)
acc->parent_realize(dev, errp);
}
+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);
+ bool has_secure;
+
+ has_secure = cpu->has_el3 || arm_feature(env, ARM_FEATURE_M_SECURITY);
+
+ /* rock 'n' un-roll, whatever happened in the arm_cpu_realizefn cleanly */
+ cpu_address_space_destroy(cs, ARMASIdx_NS);
+
+ if (cpu->tag_memory != NULL) {
+ cpu_address_space_destroy(cs, ARMASIdx_TagNS);
+ if (has_secure) {
+ cpu_address_space_destroy(cs, ARMASIdx_TagS);
+ }
+ }
+
+ if (has_secure) {
+ cpu_address_space_destroy(cs, ARMASIdx_S);
+ }
+
+ 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 (cpu->pmsav8r_hdregion) {
+ g_free(env->pmsav8.hprbar);
+ g_free(env->pmsav8.hprlar);
+ }
+ }
+
+ 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 ObjectClass *arm_cpu_class_by_name(const char *cpu_model)
{
ObjectClass *oc;
@@ -2492,6 +2591,8 @@ static void arm_cpu_class_init(ObjectClass *oc, void *data)
device_class_set_parent_realize(dc, arm_cpu_realizefn,
&acc->parent_realize);
+ device_class_set_parent_unrealize(dc, arm_cpu_unrealizefn,
+ &acc->parent_unrealize);
device_class_set_props(dc, arm_cpu_properties);
diff --git a/target/arm/cpu.h b/target/arm/cpu.h
index 145d3dbf13..c51a0e3467 100644
--- a/target/arm/cpu.h
+++ b/target/arm/cpu.h
@@ -1138,6 +1138,7 @@ struct ARMCPUClass {
const ARMCPUInfo *info;
DeviceRealize parent_realize;
+ DeviceUnrealize parent_unrealize;
ResettablePhases parent_phases;
};
@@ -3359,6 +3360,13 @@ static inline AddressSpace *arm_addressspace(CPUState *cs, MemTxAttrs attrs)
*/
void arm_register_pre_el_change_hook(ARMCPU *cpu, ARMELChangeHookFn *hook,
void *opaque);
+/**
+ * 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);
+
/**
* arm_register_el_change_hook:
* Register a hook function which will be called immediately after this
@@ -3371,6 +3379,12 @@ 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:
diff --git a/target/arm/gdbstub.c b/target/arm/gdbstub.c
index 28f546a5ff..5ba1e28e34 100644
--- a/target/arm/gdbstub.c
+++ b/target/arm/gdbstub.c
@@ -553,3 +553,9 @@ void arm_cpu_register_gdb_regs_for_features(ARMCPU *cpu)
}
#endif /* CONFIG_TCG */
}
+
+void arm_cpu_unregister_gdb_regs(ARMCPU *cpu)
+{
+ CPUState *cs = CPU(cpu);
+ gdb_unregister_coprocessor_all(cs);
+}
diff --git a/target/arm/helper.c b/target/arm/helper.c
index 2746d3fdac..e47498828c 100644
--- a/target/arm/helper.c
+++ b/target/arm/helper.c
@@ -263,6 +263,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.
*/
@@ -9438,6 +9451,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);
+}
+
/* 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 143d57c0fe..c3a7682f05 100644
--- a/target/arm/internals.h
+++ b/target/arm/internals.h
@@ -187,9 +187,12 @@ void arm_cpu_register(const ARMCPUInfo *info);
void aarch64_cpu_register(const ARMCPUInfo *info);
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);
void arm_cpu_register_gdb_regs_for_features(ARMCPU *cpu);
+void arm_cpu_unregister_gdb_regs(ARMCPU *cpu);
void arm_translate_init(void);
void arm_restore_state_to_opc(CPUState *cs,
diff --git a/target/arm/kvm64.c b/target/arm/kvm64.c
index 03ce1e7525..9c3a35d63a 100644
--- a/target/arm/kvm64.c
+++ b/target/arm/kvm64.c
@@ -647,6 +647,10 @@ int kvm_arch_init_vcpu(CPUState *cs)
int kvm_arch_destroy_vcpu(CPUState *cs)
{
+ if (cs->thread_id) {
+ qemu_del_vm_change_state_handler(cs->vmcse);
+ }
+
return 0;
}
--
2.27.0