render / rpms / edk2

Forked from rpms/edk2 2 months ago
Clone

Blame SOURCES/edk2-OvmfPkg-CpuHotplugSmm-fix-CPU-hotplug-race-just-befo.patch

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