|
|
2fc9c1 |
From 4e5edfcdf5986d9e0801a976a3aa558b5f370099 Mon Sep 17 00:00:00 2001
|
|
|
2fc9c1 |
From: Laszlo Ersek <lersek@redhat.com>
|
|
|
2fc9c1 |
Date: Thu, 27 Aug 2020 00:21:28 +0200
|
|
|
2fc9c1 |
Subject: [PATCH 2/5] OvmfPkg/CpuHotplugSmm: fix CPU hotplug race just before
|
|
|
2fc9c1 |
SMI broadcast
|
|
|
2fc9c1 |
MIME-Version: 1.0
|
|
|
2fc9c1 |
Content-Type: text/plain; charset=UTF-8
|
|
|
2fc9c1 |
Content-Transfer-Encoding: 8bit
|
|
|
2fc9c1 |
|
|
|
2fc9c1 |
RH-Author: Laszlo Ersek (lersek)
|
|
|
2fc9c1 |
RH-MergeRequest: 1: [RHEL-8.4.0] complete the "VCPU hotplug with SMI" OVMF feature
|
|
|
2fc9c1 |
RH-Commit: [2/3] ea3ff703dfb7bd4f77b6807f06c89e754cc9d980 (lersek/edk2)
|
|
|
2fc9c1 |
RH-Bugzilla: 1849177
|
|
|
2fc9c1 |
|
|
|
2fc9c1 |
The "virsh setvcpus" (plural) command may hot-plug several VCPUs in quick
|
|
|
2fc9c1 |
succession -- it means a series of "device_add" QEMU monitor commands,
|
|
|
2fc9c1 |
back-to-back.
|
|
|
2fc9c1 |
|
|
|
2fc9c1 |
If a "device_add" occurs *just before* ACPI raises the broadcast SMI,
|
|
|
2fc9c1 |
then:
|
|
|
2fc9c1 |
|
|
|
2fc9c1 |
- OVMF processes the hot-added CPU well.
|
|
|
2fc9c1 |
|
|
|
2fc9c1 |
- However, QEMU's post-SMI ACPI loop -- which clears the pending events
|
|
|
2fc9c1 |
for the hot-added CPUs that were collected before raising the SMI -- is
|
|
|
2fc9c1 |
unaware of the stray CPU. Thus, the pending event is not cleared for it.
|
|
|
2fc9c1 |
|
|
|
2fc9c1 |
As a result of the stuck event, at the next hot-plug, OVMF tries to re-add
|
|
|
2fc9c1 |
(relocate for the 2nd time) the already-known CPU. At that time, the AP is
|
|
|
2fc9c1 |
already in the normal edk2 SMM busy-wait however, so it doesn't respond to
|
|
|
2fc9c1 |
the exchange that the BSP intends to do in SmbaseRelocate(). Thus the VM
|
|
|
2fc9c1 |
gets stuck in SMM.
|
|
|
2fc9c1 |
|
|
|
2fc9c1 |
(Because of the above symptom, this is not considered a security patch; it
|
|
|
2fc9c1 |
doesn't seem exploitable by a malicious guest OS.)
|
|
|
2fc9c1 |
|
|
|
2fc9c1 |
In CpuHotplugMmi(), skip the supposedly hot-added CPU if it's already
|
|
|
2fc9c1 |
known. The post-SMI ACPI loop will clear the pending event for it this
|
|
|
2fc9c1 |
time.
|
|
|
2fc9c1 |
|
|
|
2fc9c1 |
Cc: Ard Biesheuvel <ard.biesheuvel@arm.com>
|
|
|
2fc9c1 |
Cc: Igor Mammedov <imammedo@redhat.com>
|
|
|
2fc9c1 |
Cc: Jordan Justen <jordan.l.justen@intel.com>
|
|
|
2fc9c1 |
Cc: Philippe Mathieu-Daudé <philmd@redhat.com>
|
|
|
2fc9c1 |
Fixes: bc498ac4ca7590479cfd91ad1bb8a36286b0dc21
|
|
|
2fc9c1 |
Ref: https://bugzilla.tianocore.org/show_bug.cgi?id=2929
|
|
|
2fc9c1 |
Signed-off-by: Laszlo Ersek <lersek@redhat.com>
|
|
|
2fc9c1 |
Message-Id: <20200826222129.25798-2-lersek@redhat.com>
|
|
|
2fc9c1 |
Reviewed-by: Ard Biesheuvel <ard.biesheuvel@arm.com>
|
|
|
2fc9c1 |
(cherry picked from commit 020bb4b46d6f6708bb3358e1c738109b7908f0de)
|
|
|
2fc9c1 |
Signed-off-by: Laszlo Ersek <lersek@redhat.com>
|
|
|
2fc9c1 |
---
|
|
|
2fc9c1 |
OvmfPkg/CpuHotplugSmm/CpuHotplug.c | 19 +++++++++++++++++++
|
|
|
2fc9c1 |
1 file changed, 19 insertions(+)
|
|
|
2fc9c1 |
|
|
|
2fc9c1 |
diff --git a/OvmfPkg/CpuHotplugSmm/CpuHotplug.c b/OvmfPkg/CpuHotplugSmm/CpuHotplug.c
|
|
|
2fc9c1 |
index 20e6bec04f..cfe698ed2b 100644
|
|
|
2fc9c1 |
--- a/OvmfPkg/CpuHotplugSmm/CpuHotplug.c
|
|
|
2fc9c1 |
+++ b/OvmfPkg/CpuHotplugSmm/CpuHotplug.c
|
|
|
2fc9c1 |
@@ -193,9 +193,28 @@ CpuHotplugMmi (
|
|
|
2fc9c1 |
NewSlot = 0;
|
|
|
2fc9c1 |
while (PluggedIdx < PluggedCount) {
|
|
|
2fc9c1 |
APIC_ID NewApicId;
|
|
|
2fc9c1 |
+ UINT32 CheckSlot;
|
|
|
2fc9c1 |
UINTN NewProcessorNumberByProtocol;
|
|
|
2fc9c1 |
|
|
|
2fc9c1 |
NewApicId = mPluggedApicIds[PluggedIdx];
|
|
|
2fc9c1 |
+
|
|
|
2fc9c1 |
+ //
|
|
|
2fc9c1 |
+ // Check if the supposedly hot-added CPU is already known to us.
|
|
|
2fc9c1 |
+ //
|
|
|
2fc9c1 |
+ for (CheckSlot = 0;
|
|
|
2fc9c1 |
+ CheckSlot < mCpuHotPlugData->ArrayLength;
|
|
|
2fc9c1 |
+ CheckSlot++) {
|
|
|
2fc9c1 |
+ if (mCpuHotPlugData->ApicId[CheckSlot] == NewApicId) {
|
|
|
2fc9c1 |
+ break;
|
|
|
2fc9c1 |
+ }
|
|
|
2fc9c1 |
+ }
|
|
|
2fc9c1 |
+ if (CheckSlot < mCpuHotPlugData->ArrayLength) {
|
|
|
2fc9c1 |
+ DEBUG ((DEBUG_VERBOSE, "%a: APIC ID " FMT_APIC_ID " was hot-plugged "
|
|
|
2fc9c1 |
+ "before; ignoring it\n", __FUNCTION__, NewApicId));
|
|
|
2fc9c1 |
+ PluggedIdx++;
|
|
|
2fc9c1 |
+ continue;
|
|
|
2fc9c1 |
+ }
|
|
|
2fc9c1 |
+
|
|
|
2fc9c1 |
//
|
|
|
2fc9c1 |
// Find the first empty slot in CPU_HOT_PLUG_DATA.
|
|
|
2fc9c1 |
//
|
|
|
2fc9c1 |
--
|
|
|
2fc9c1 |
2.27.0
|
|
|
2fc9c1 |
|