On 03/12/21 07:26, Ankur Arora wrote:
> Add logic in EjectCpu() to do the actual the CPU ejection.
>
> On the BSP, ejection happens by first selecting the CPU via
> its QemuSelector and then sending the QEMU "eject" command.
> QEMU in-turn signals the remote VCPU thread which context-switches
> the CPU out of the SMI handler.
>
> Meanwhile the CPU being ejected, waits around in its holding
> area until it is context-switched out. Note that it is possible
> that a slow CPU gets ejected before it reaches the wait loop.
> However, this would never happen before it has executed the
> "AllCpusInSync" loop in SmiRendezvous().
> It can mean that an ejected CPU does not execute code after
> that point but given that the CPU state will be destroyed by
> QEMU, the missed cleanup is no great loss.
>
> Cc: Laszlo Ersek
> Cc: Jordan Justen
> Cc: Ard Biesheuvel
> Cc: Igor Mammedov
> Cc: Boris Ostrovsky
> Cc: Aaron Young
> Ref: https://bugzilla.tianocore.org/show_bug.cgi?id=3132
> Signed-off-by: Ankur Arora
> ---
>
> Notes:
> Addresses the following comments from v8:
>
> (1a,1b) CheckIfBsp(): get rid of ProcessorNum, document retval.
> (2) Line up IsBsp and ApicBaseMsr
> (3) s/ongoing SMI iteration/ongoing SMI/
> (4) Get rid of the allusions to alignment in the comment in EjectCpu().
> () Also reduce some of the repetitive detail in this comment.
> (5) EjectCpu(): reorder logic to cleanly separate the AP and the BSP
> portions.
> (6) Get rid of unnecessary MemoryFence() between QemuCpuhpWrite
> and clearing of the eject status.
> (7) Change type of QemuSelector to %Lu in DEBUG statement
> (8) Get rid of the repetitive comment in SmmCpuFeaturesRendezvousExit().
> The necessary parts of this got moved to patch-7.
>
> OvmfPkg/Include/IndustryStandard/QemuCpuHotplug.h | 1 +
> OvmfPkg/CpuHotplugSmm/CpuHotplug.c| 113
> --
> 2 files changed, 108 insertions(+), 6 deletions(-)
Reviewed-by: Laszlo Ersek
Thanks
Laszlo
>
> diff --git a/OvmfPkg/Include/IndustryStandard/QemuCpuHotplug.h
> b/OvmfPkg/Include/IndustryStandard/QemuCpuHotplug.h
> index 2ec7a107a64d..d0e83102c13f 100644
> --- a/OvmfPkg/Include/IndustryStandard/QemuCpuHotplug.h
> +++ b/OvmfPkg/Include/IndustryStandard/QemuCpuHotplug.h
> @@ -34,6 +34,7 @@
> #define QEMU_CPUHP_STAT_ENABLEDBIT0
> #define QEMU_CPUHP_STAT_INSERT BIT1
> #define QEMU_CPUHP_STAT_REMOVE BIT2
> +#define QEMU_CPUHP_STAT_EJECT BIT3
> #define QEMU_CPUHP_STAT_FW_REMOVE BIT4
>
> #define QEMU_CPUHP_RW_CMD_DATA 0x8
> diff --git a/OvmfPkg/CpuHotplugSmm/CpuHotplug.c
> b/OvmfPkg/CpuHotplugSmm/CpuHotplug.c
> index 2eeb4567a262..ae3abd525900 100644
> --- a/OvmfPkg/CpuHotplugSmm/CpuHotplug.c
> +++ b/OvmfPkg/CpuHotplugSmm/CpuHotplug.c
> @@ -18,6 +18,7 @@
> #include // CPU_HOT_EJECT_DATA
> #include // EFI_MM_CPU_IO_PROTOCOL
> #include // EFI_SMM_CPU_SERVICE_PROTOCOL
> +#include // MSR_IA32_APIC_BASE_REGISTER
> #include// EFI_STATUS
>
> #include "ApicId.h" // APIC_ID
> @@ -193,12 +194,40 @@ RevokeNewSlot:
> }
>
> /**
> + EjectCpu needs to know the BSP at SMI exit at a point when
> + some of the EFI_SMM_CPU_SERVICE_PROTOCOL state has been torn
> + down.
> + Reuse the logic from OvmfPkg::PlatformSmmBspElection() to
> + do that.
> +
> + @retval TRUE If the CPU executing this function is the BSP.
> +
> + @retval FALSE If the CPU executing this function is an AP.
> +**/
> +STATIC
> +BOOLEAN
> +CheckIfBsp (
> + VOID
> + )
> +{
> + MSR_IA32_APIC_BASE_REGISTER ApicBaseMsr;
> + BOOLEAN IsBsp;
> +
> + ApicBaseMsr.Uint64 = AsmReadMsr64 (MSR_IA32_APIC_BASE);
> + IsBsp = (BOOLEAN)(ApicBaseMsr.Bits.BSP == 1);
> + return IsBsp;
> +}
> +
> +/**
>CPU Hot-eject handler, called from SmmCpuFeaturesRendezvousExit()
>on each CPU at exit from SMM.
>
> - If, the executing CPU is not being ejected, nothing to be done.
> + If, the executing CPU is neither the BSP, nor being ejected, nothing
> + to be done.
>If, the executing CPU is being ejected, wait in a halted loop
>until ejected.
> + If, the executing CPU is the BSP, set QEMU CPU status to eject
> + for CPUs being ejected.
>
>@param[in] ProcessorNum ProcessorNum denotes the CPU exiting SMM,
> and will be used as an index into
> @@ -214,6 +243,83 @@ EjectCpu (
> {
>UINT64 QemuSelector;
>
> + if (CheckIfBsp ()) {
> +UINT32 Idx;
> +
> +for (Idx = 0; Idx < mCpuHotEjectData->ArrayLength; Idx++) {
> + UINT64 QemuSelector;
> +
> + QemuSelector = mCpuHotEjectData->QemuSelectorMap[Idx];
> +
> + if (QemuSelector != CPU_EJECT_QEMU_SELECTOR_INVALID) {
> +//
> +// This to-be-ejected-CPU has already received the BSP's SMI exit
> +// signal and