On most architectures, during vCPU hot-plug and hot-unplug actions, firmware or the VMM/QEMU can convey vCPU status to the OS by toggling the ACPI method `_STA.Present` Bit. However, certain CPU architecture specifications prohibit [1] modifications to CPU's `presence` after the kernel has booted.
This limitation [2][3] arises because many per-CPU components, such as interrupt controllers that are closely integrated with CPUs, or other per-CPU features, may not support reconfiguration once the kernel is initialized. These components often cannot be powered down as they might belong to an `always-on` power domain. Consequently, specifications require all CPUs to remain `_STA.Present` after system initialization. To address this issue from an ACPI perspective, an `is_enabled` state has been introduced in the `AcpiCpuStatus`. This state reflects whether a vCPU has been hot-plugged or hot-unplugged in QEMU, thus indicating its availability to the guest kernel. The guest can evaluate this status by calling the ACPI `_STA` method and checking the `_STA.Enabled` bit after QEMU signals the hot-plug event via GED. References: [1] Check comment 5 in the bugzilla entry Link: https://bugzilla.tianocore.org/show_bug.cgi?id=4481#c5 [2] KVMForum 2023 Presentation: Challenges Revisited in Supporting Virt CPU Hotplug on architectures that don’t Support CPU Hotplug (like ARM64) a. Kernel Link: https://kvm-forum.qemu.org/2023/KVM-forum-cpu-hotplug_7OJ1YyJ.pdf b. Qemu Link: https://kvm-forum.qemu.org/2023/Challenges_Revisited_in_Supporting_Virt_CPU_Hotplug_-__ii0iNb3.pdf [3] KVMForum 2020 Presentation: Challenges in Supporting Virtual CPU Hotplug on SoC Based Systems (like ARM64) Link: https://kvmforum2020.sched.com/event/eE4m Signed-off-by: Salil Mehta <salil.me...@huawei.com> Reviewed-by: Gustavo Romero <gustavo.rom...@linaro.org> --- hw/acpi/cpu.c | 9 ++++++++- include/hw/acpi/cpu.h | 2 +- 2 files changed, 9 insertions(+), 2 deletions(-) diff --git a/hw/acpi/cpu.c b/hw/acpi/cpu.c index 5cb60ca8bc..238a0edbc1 100644 --- a/hw/acpi/cpu.c +++ b/hw/acpi/cpu.c @@ -225,7 +225,14 @@ 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); + + state->devs[i].cpu = cpu; + if (cpu && DEVICE(cpu)->realized) { + state->devs[i].is_enabled = true; + } else { + state->devs[i].is_enabled = false; + } 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/include/hw/acpi/cpu.h b/include/hw/acpi/cpu.h index 32654dc274..ff49caa501 100644 --- a/include/hw/acpi/cpu.h +++ b/include/hw/acpi/cpu.h @@ -26,6 +26,7 @@ typedef struct AcpiCpuStatus { uint64_t arch_id; bool is_inserting; bool is_removing; + bool is_enabled; bool fw_remove; uint32_t ost_event; uint32_t ost_status; @@ -74,5 +75,4 @@ extern const VMStateDescription vmstate_cpu_hotplug; #define VMSTATE_CPU_HOTPLUG(cpuhp, state) \ VMSTATE_STRUCT(cpuhp, state, 1, \ vmstate_cpu_hotplug, CPUHotplugState) - #endif -- 2.34.1