- 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>
295 lines
9.1 KiB
Diff
295 lines
9.1 KiB
Diff
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
|
|
|