mirror of
https://github.com/kata-containers/kata-containers.git
synced 2025-04-28 03:42:09 +00:00
Qemu: Enable the vcpu-hotplug for arm
Initially enable vcpu hotplug in qemu for arm base on Salli's work[1]. Fixes:#3280 Signed-off-by: Huang Shijie <shijie8@gmail.com> [1] https://github.com/salil-mehta/qemu/tree/virt-cpuhp-armv8/rfc-v1
This commit is contained in:
parent
97e18cf2d0
commit
2d0ec00aff
@ -0,0 +1,79 @@
|
||||
From cbc35b3747ff8c50e64e3b8aeecf1b782ee27cad Mon Sep 17 00:00:00 2001
|
||||
From: Huang Shijie <shijie8@gmail.com>
|
||||
Date: Mon, 22 Nov 2021 17:51:11 +0800
|
||||
Subject: [PATCH 01/28] arm/cpuhp: Add QMP vcpu params validation support
|
||||
|
||||
From Salil Mehta <salil.mehta@huawei.com>
|
||||
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 <zhukeqian1@huawei.com>
|
||||
Signed-off-by: Salil Mehta <salil.mehta@huawei.com>
|
||||
Signed-off-by: Huang Shijie <shijie8@gmail.com>
|
||||
---
|
||||
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
|
||||
|
@ -0,0 +1,101 @@
|
||||
From a24ce04b7c2e958a0730f19e6f54e6570a075b20 Mon Sep 17 00:00:00 2001
|
||||
From: Salil Mehta <salil.mehta@huawei.com>
|
||||
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 <zhukeqian1@huawei.com>
|
||||
Signed-off-by: Salil Mehta <salil.mehta@huawei.com>
|
||||
Signed-off-by: Huang Shijie <shijie8@gmail.com>
|
||||
---
|
||||
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
|
||||
|
@ -0,0 +1,97 @@
|
||||
From cf832166791bddea562ba9372795db04ea41a581 Mon Sep 17 00:00:00 2001
|
||||
From: Salil Mehta <salil.mehta@huawei.com>
|
||||
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 <zhukeqian1@huawei.com>
|
||||
Signed-off-by: Salil Mehta <salil.mehta@huawei.com>
|
||||
---
|
||||
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
|
||||
|
@ -0,0 +1,447 @@
|
||||
From 0de9776b56a8848f28bdd21332dff50fac12bca4 Mon Sep 17 00:00:00 2001
|
||||
From: Salil Mehta <salil.mehta@huawei.com>
|
||||
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 <zhukeqian1@huawei.com>
|
||||
Signed-off-by: Salil Mehta <salil.mehta@huawei.com>
|
||||
Signed-off-by: Huang Shijie <shijie8@gmail.com>
|
||||
---
|
||||
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
|
||||
|
@ -0,0 +1,243 @@
|
||||
From 1d9605a449833e464bd0388bb658d31a84ad4c7d Mon Sep 17 00:00:00 2001
|
||||
From: Salil Mehta <salil.mehta@huawei.com>
|
||||
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 <zhukeqian1@huawei.com>
|
||||
Signed-off-by: Salil Mehta <salil.mehta@huawei.com>
|
||||
Signed-off-by: Huang Shijie <shijie8@gmail.com>
|
||||
---
|
||||
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
|
||||
|
@ -0,0 +1,220 @@
|
||||
From b588545bf1bb168eb0853ae36525d5407657eb7b Mon Sep 17 00:00:00 2001
|
||||
From: Salil Mehta <salil.mehta@huawei.com>
|
||||
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 <zhukeqian1@huawei.com>
|
||||
Signed-off-by: Salil Mehta <salil.mehta@huawei.com>
|
||||
Signed-off-by: Huang Shijie <shijie8@gmail.com>
|
||||
---
|
||||
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
|
||||
|
@ -0,0 +1,95 @@
|
||||
From b885e6d6e6a1199a6db17fb5753df2ca63c611b5 Mon Sep 17 00:00:00 2001
|
||||
From: Salil Mehta <salil.mehta@huawei.com>
|
||||
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 <zhukeqian1@huawei.com>
|
||||
Signed-off-by: Salil Mehta <salil.mehta@huawei.com>
|
||||
Signed-off-by: Huang Shijie <shijie8@gmail.com>
|
||||
---
|
||||
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
|
||||
|
@ -0,0 +1,115 @@
|
||||
From 8cdfd18d515aa5be1c54061e42f1c8a69997667b Mon Sep 17 00:00:00 2001
|
||||
From: Salil Mehta <salil.mehta@huawei.com>
|
||||
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 <zhukeqian1@huawei.com>
|
||||
Signed-off-by: Salil Mehta <salil.mehta@huawei.com>
|
||||
Signed-off-by: Huang Shijie <shijie8@gmail.com>
|
||||
---
|
||||
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
|
||||
|
@ -0,0 +1,101 @@
|
||||
From d184f34dbfc972b0a27be189ce8c1a75e400c920 Mon Sep 17 00:00:00 2001
|
||||
From: Salil Mehta <salil.mehta@huawei.com>
|
||||
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 <zhukeqian1@huawei.com>
|
||||
Signed-off-by: Salil Mehta <salil.mehta@huawei.com>
|
||||
Signed-off-by: Huang Shijie <shijie8@gmail.com>
|
||||
---
|
||||
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
|
||||
|
@ -0,0 +1,139 @@
|
||||
From f7b9c727b0da0bec444d85bd1bf7bd5bfb9d3e4f Mon Sep 17 00:00:00 2001
|
||||
From: Salil Mehta <salil.mehta@huawei.com>
|
||||
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 <zhukeqian1@huawei.com>
|
||||
Signed-off-by: Salil Mehta <salil.mehta@huawei.com>
|
||||
Signed-off-by: Huang Shijie <shijie8@gmail.com>
|
||||
---
|
||||
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
|
||||
|
@ -0,0 +1,51 @@
|
||||
From e9a06ca70bbb956ec96f69e2e7bebc2a7b9044a8 Mon Sep 17 00:00:00 2001
|
||||
From: Salil Mehta <salil.mehta@huawei.com>
|
||||
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 <zhukeqian1@huawei.com>
|
||||
Signed-off-by: Salil Mehta <salil.mehta@huawei.com>
|
||||
Signed-off-by: Huang Shijie <shijie8@gmail.com>
|
||||
---
|
||||
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
|
||||
|
@ -0,0 +1,67 @@
|
||||
From 323ce9267470a6e0bf22c9b19399f12804524d78 Mon Sep 17 00:00:00 2001
|
||||
From: Salil Mehta <salil.mehta@huawei.com>
|
||||
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 <zhukeqian1@huawei.com>
|
||||
Signed-off-by: Salil Mehta <salil.mehta@huawei.com>
|
||||
Signed-off-by: Huang Shijie <shijie8@gmail.com>
|
||||
---
|
||||
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
|
||||
|
@ -0,0 +1,95 @@
|
||||
From 22e597ca7364c7787bd9abd3da27b7aaa92f3337 Mon Sep 17 00:00:00 2001
|
||||
From: Salil Mehta <salil.mehta@huawei.com>
|
||||
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 <zhukeqian1@huawei.com>
|
||||
Signed-off-by: Salil Mehta <salil.mehta@huawei.com>
|
||||
Signed-off-by: Huang Shijie <shijie8@gmail.com>
|
||||
---
|
||||
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
|
||||
|
@ -0,0 +1,86 @@
|
||||
From 435c926d8739b1ad4ffbfeabe83aabbda2d3ec22 Mon Sep 17 00:00:00 2001
|
||||
From: Salil Mehta <salil.mehta@huawei.com>
|
||||
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 <zhukeqian1@huawei.com>
|
||||
Signed-off-by: Salil Mehta <salil.mehta@huawei.com>
|
||||
Signed-off-by: Huang Shijie <shijie8@gmail.com>
|
||||
---
|
||||
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
|
||||
|
@ -0,0 +1,97 @@
|
||||
From 6a8a86ca3b4b66ab3489911bd0ad4da594531882 Mon Sep 17 00:00:00 2001
|
||||
From: Salil Mehta <salil.mehta@huawei.com>
|
||||
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 <zhukeqian1@huawei.com>
|
||||
Signed-off-by: Salil Mehta <salil.mehta@huawei.com>
|
||||
Signed-off-by: Huang Shijie <shijie8@gmail.com>
|
||||
---
|
||||
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
|
||||
|
@ -0,0 +1,171 @@
|
||||
From 2010227bc3f326b0755ec3878476c2f0616ea407 Mon Sep 17 00:00:00 2001
|
||||
From: Salil Mehta <salil.mehta@huawei.com>
|
||||
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 <zhukeqian1@huawei.com>
|
||||
Signed-off-by: Salil Mehta <salil.mehta@huawei.com>
|
||||
Signed-off-by: Huang Shijie <shijie8@gmail.com>
|
||||
---
|
||||
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
|
||||
|
@ -0,0 +1,232 @@
|
||||
From 8ee7755e469b3e8d1a4edb0fd703d33a163092f5 Mon Sep 17 00:00:00 2001
|
||||
From: Salil Mehta <salil.mehta@huawei.com>
|
||||
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 <zhukeqian1@huawei.com>
|
||||
Signed-off-by: Salil Mehta <salil.mehta@huawei.com>
|
||||
Signed-off-by: Huang Shijie <shijie8@gmail.com>
|
||||
---
|
||||
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
|
||||
|
@ -0,0 +1,211 @@
|
||||
From f2ce0fea29008de9c95800044e0e508ba682554d Mon Sep 17 00:00:00 2001
|
||||
From: Salil Mehta <salil.mehta@huawei.com>
|
||||
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 <zhukeqian1@huawei.com>
|
||||
Signed-off-by: Salil Mehta <salil.mehta@huawei.com>
|
||||
Signed-off-by: Huang Shijie <shijie8@gmail.com>
|
||||
---
|
||||
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
|
||||
|
@ -0,0 +1,268 @@
|
||||
From 44cdfa821bf310d3adab8885127ff30a2c23157f Mon Sep 17 00:00:00 2001
|
||||
From: Salil Mehta <salil.mehta@huawei.com>
|
||||
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 <zhukeqian1@huawei.com>
|
||||
Signed-off-by: Salil Mehta <salil.mehta@huawei.com>
|
||||
Signed-off-by: Huang Shijie <shijie8@gmail.com>
|
||||
---
|
||||
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
|
||||
|
@ -0,0 +1,115 @@
|
||||
From 740d5e7968376d6007fcc71008f277b8ea94a2fb Mon Sep 17 00:00:00 2001
|
||||
From: Salil Mehta <salil.mehta@huawei.com>
|
||||
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 <zhukeqian1@huawei.com>
|
||||
Signed-off-by: Salil Mehta <salil.mehta@huawei.com>
|
||||
Signed-off-by: Huang Shijie <shijie8@gmail.com>
|
||||
---
|
||||
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
|
||||
|
@ -0,0 +1,109 @@
|
||||
From e9301ff546d27cf5f6acc677d19e7c89c693d6ea Mon Sep 17 00:00:00 2001
|
||||
From: Salil Mehta <salil.mehta@huawei.com>
|
||||
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 <zhukeqian1@huawei.com>
|
||||
Signed-off-by: Salil Mehta <salil.mehta@huawei.com>
|
||||
Signed-off-by: Huang Shijie <shijie8@gmail.com>
|
||||
---
|
||||
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
|
||||
|
@ -0,0 +1,415 @@
|
||||
From 71102726bd7434d8fd635be0f1c067fdb795efe3 Mon Sep 17 00:00:00 2001
|
||||
From: Salil Mehta <salil.mehta@huawei.com>
|
||||
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 <zhukeqian1@huawei.com>
|
||||
Signed-off-by: Salil Mehta <salil.mehta@huawei.com>
|
||||
Signed-off-by: Huang Shijie <shijie8@gmail.com>
|
||||
---
|
||||
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
|
||||
|
@ -0,0 +1,38 @@
|
||||
From 5864b2046f2481772bb1f28aa4e4bbc5258ad1f1 Mon Sep 17 00:00:00 2001
|
||||
From: Huang Shijie <shijie8@gmail.com>
|
||||
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 <shijie8@gmail.com>
|
||||
Signed-off-by: Huang Shijie <shijie8@gmail.com>
|
||||
---
|
||||
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
|
||||
|
@ -0,0 +1,47 @@
|
||||
From b165fbe697c6f029973fffea151e384247639829 Mon Sep 17 00:00:00 2001
|
||||
From: Huang Shijie <shijie8@gmail.com>
|
||||
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 <shijie8@gmail.com>
|
||||
Signed-off-by: Huang Shijie <shijie8@gmail.com>
|
||||
---
|
||||
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
|
||||
|
@ -0,0 +1,180 @@
|
||||
From ee68b08a7194ea9fefdf00ee57fa9edcb56b4359 Mon Sep 17 00:00:00 2001
|
||||
From: Huang Shijie <shijie8@gmail.com>
|
||||
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 <shijie8@gmail.com>
|
||||
Signed-off-by: Huang Shijie <shijie8@gmail.com>
|
||||
---
|
||||
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
|
||||
|
@ -0,0 +1,65 @@
|
||||
From 0e3ad502669659822083fd9fde80220e5a9af0ed Mon Sep 17 00:00:00 2001
|
||||
From: Huang Shijie <shijie8@gmail.com>
|
||||
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 <shijie8@gmail.com>
|
||||
Signed-off-by: Huang Shijie <shijie8@gmail.com>
|
||||
---
|
||||
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
|
||||
|
@ -0,0 +1,63 @@
|
||||
From e9376db8e4113e2222543a9a4cdc68a40b78b69c Mon Sep 17 00:00:00 2001
|
||||
From: Huang Shijie <shijie8@gmail.com>
|
||||
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 <shijie8@gmail.com>
|
||||
Signed-off-by: Huang Shijie <shijie8@gmail.com>
|
||||
---
|
||||
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
|
||||
|
@ -0,0 +1,230 @@
|
||||
From e9ec5f6617c1811f244618e3a23c29ea2fb27c6a Mon Sep 17 00:00:00 2001
|
||||
From: Huang Shijie <shijie8@gmail.com>
|
||||
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 <shijie8@gmail.com>
|
||||
Signed-off-by: Huang Shijie <shijie8@gmail.com>
|
||||
---
|
||||
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
|
||||
|
Loading…
Reference in New Issue
Block a user