mirror of
https://github.com/kata-containers/kata-containers.git
synced 2025-04-29 12:14:48 +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