summary refs log tree commit diff stats
path: root/hw/acpi/cpu_hotplug.c
diff options
context:
space:
mode:
Diffstat (limited to 'hw/acpi/cpu_hotplug.c')
-rw-r--r--hw/acpi/cpu_hotplug.c21
1 files changed, 20 insertions, 1 deletions
diff --git a/hw/acpi/cpu_hotplug.c b/hw/acpi/cpu_hotplug.c
index fe75bd9ac9..e19d902063 100644
--- a/hw/acpi/cpu_hotplug.c
+++ b/hw/acpi/cpu_hotplug.c
@@ -34,7 +34,15 @@ static uint64_t cpu_status_read(void *opaque, hwaddr addr, unsigned int size)
 static void cpu_status_write(void *opaque, hwaddr addr, uint64_t data,
                              unsigned int size)
 {
-    /* TODO: implement VCPU removal on guest signal that CPU can be removed */
+    /* firmware never used to write in CPU present bitmap so use
+       this fact as means to switch QEMU into modern CPU hotplug
+       mode by writing 0 at the beginning of legacy CPU bitmap
+     */
+    if (addr == 0 && data == 0) {
+        AcpiCpuHotplug *cpus = opaque;
+        object_property_set_bool(cpus->device, false, "cpu-hotplug-legacy",
+                                 &error_abort);
+    }
 }
 
 static const MemoryRegionOps AcpiCpuHotplug_ops = {
@@ -83,6 +91,17 @@ void legacy_acpi_cpu_hotplug_init(MemoryRegion *parent, Object *owner,
     memory_region_init_io(&gpe_cpu->io, owner, &AcpiCpuHotplug_ops,
                           gpe_cpu, "acpi-cpu-hotplug", ACPI_GPE_PROC_LEN);
     memory_region_add_subregion(parent, base, &gpe_cpu->io);
+    gpe_cpu->device = owner;
+}
+
+void acpi_switch_to_modern_cphp(AcpiCpuHotplug *gpe_cpu,
+                                CPUHotplugState *cpuhp_state,
+                                uint16_t io_port)
+{
+    MemoryRegion *parent = pci_address_space_io(PCI_DEVICE(gpe_cpu->device));
+
+    memory_region_del_subregion(parent, &gpe_cpu->io);
+    cpu_hotplug_hw_init(parent, gpe_cpu->device, cpuhp_state, io_port);
 }
 
 void build_legacy_cpu_hotplug_aml(Aml *ctx, MachineState *machine,