From mboxrd@z Thu Jan 1 00:00:00 1970 Received: from mail-wm1-f44.google.com (mail-wm1-f44.google.com [209.85.128.44]) by mx.groups.io with SMTP id smtpd.web11.14435.1583157799774326419 for ; Mon, 02 Mar 2020 06:03:20 -0800 Authentication-Results: mx.groups.io; dkim=pass header.i=@linaro.org header.s=google header.b=rm7Ns1AD; spf=pass (domain: linaro.org, ip: 209.85.128.44, mailfrom: ard.biesheuvel@linaro.org) Received: by mail-wm1-f44.google.com with SMTP id m3so10780360wmi.0 for ; Mon, 02 Mar 2020 06:03:19 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=linaro.org; s=google; h=mime-version:references:in-reply-to:from:date:message-id:subject:to :cc:content-transfer-encoding; bh=sVl2VSn2tuXiuUkUdOtKliZTTyfTwN3pO97enP2KSDw=; b=rm7Ns1ADTRq14QKHTvjurOfiiYiaS40dHLZ+yWCCgKcRGooKgeiCyX6Vag1Evnnsqn 26F9d1j+1GDrcUHJtvNXeQsliUptzpbHGOuijjd11swI1gr2CDhQMIILWkvIsV1xSuwr 25MS5726DXawJ7oNzvUoZPSdGa9Hye2Nm7PliZXdwVrvwm2ilOxTXTGFAZclKEYXXGhh fb5FGiU7XBXf12HMOXFLGPKS/WbK+o0Ul1WlU6V4HTJKAaNJc+usks5g4Leyd3GGCOH6 wWR6XYtyMoxQpeyszkRVOrwHvPo25gCaFzvTuFY6aMSG919maJMwcf/zvHVpph9NqvMm bHNw== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:mime-version:references:in-reply-to:from:date :message-id:subject:to:cc:content-transfer-encoding; bh=sVl2VSn2tuXiuUkUdOtKliZTTyfTwN3pO97enP2KSDw=; b=hhYb+x5+af70qd5485oa5WsZz7AzpUGvWtlzykd+MxssUUHsCjvPnjrLSj+nfcTNuW D8DB6MyJwdjwHHtb8oaY1jAvMhAgPtExHReYBevpWQ3owp/GjzV7hzs7kIUHMxdOrIKx ZA4rhS2IWD+sqN0eynQP4N4WR/kV5TTydPmfD68QJHxxWh8c0gCnnuvIxzrTI2kLasOx EQrpLMuJ7WxS05XUq7E36WiiU8WkyWrehY6DUTiVyJazf85KkoWxe2o3x613qJJ86UAg yzbZHsO1oct3Xg+BKVSoiIbpYrbjvGnr5WPRLJTDPfB+WHWJmXb2RvvqCn21OXacS9r/ 0elA== X-Gm-Message-State: APjAAAWg0amahgkhETbaCuC0nSjVBOzzV3BQfHVL9eD/q9Jgle/v1mRq H+Flt/z84hMLXEXJPGL7GiqKatD28UxAt3ojdYmB9A== X-Google-Smtp-Source: APXvYqwSTuqr5Ex33zrmrULgLVwXuT0FBLuAeIzyMXIHhKYdg3xQo5Z7my365yDk8GTfzLtri4Gv7f19AVoe30CpF0Q= X-Received: by 2002:a7b:cb93:: with SMTP id m19mr20947547wmi.133.1583157798221; Mon, 02 Mar 2020 06:03:18 -0800 (PST) MIME-Version: 1.0 References: <20200226221156.29589-1-lersek@redhat.com> <20200226221156.29589-13-lersek@redhat.com> In-Reply-To: <20200226221156.29589-13-lersek@redhat.com> From: "Ard Biesheuvel" Date: Mon, 2 Mar 2020 15:03:07 +0100 Message-ID: Subject: Re: [PATCH v2 12/16] OvmfPkg/CpuHotplugSmm: introduce First SMI Handler for hot-added CPUs To: Laszlo Ersek Cc: edk2-devel-groups-io , Igor Mammedov , Jiewen Yao , Jordan Justen , Michael Kinney , =?UTF-8?Q?Philippe_Mathieu=2DDaud=C3=A9?= Content-Type: text/plain; charset="UTF-8" Content-Transfer-Encoding: quoted-printable On Wed, 26 Feb 2020 at 23:12, Laszlo Ersek wrote: > > Implement the First SMI Handler for hot-added CPUs, in NASM. > > Add the interfacing C-language function that the SMM Monarch calls. This > function launches and coordinates SMBASE relocation for a hot-added CPU. > > Cc: Ard Biesheuvel > Cc: Igor Mammedov > Cc: Jiewen Yao > Cc: Jordan Justen > Cc: Michael Kinney > Cc: Philippe Mathieu-Daud=C3=A9 > Ref: https://bugzilla.tianocore.org/show_bug.cgi?id=3D1512 > Signed-off-by: Laszlo Ersek Acked-by: Ard Biesheuvel > --- > > Notes: > v2: > > - implement the combined approach described here: > > http://mid.mail-archive.com/111145fc-be3d-2a9a-a126-c14345a8a8a4@re= dhat.com > https://edk2.groups.io/g/devel/message/54754 > > by introducing "FIRST_SMI_HANDLER_CONTEXT.AboutToLeaveSmm". > > OvmfPkg/CpuHotplugSmm/CpuHotplugSmm.inf | 4 + > OvmfPkg/CpuHotplugSmm/FirstSmiHandlerContext.h | 47 ++++++ > OvmfPkg/CpuHotplugSmm/Smbase.h | 14 ++ > OvmfPkg/CpuHotplugSmm/FirstSmiHandler.nasm | 154 +++++++++++++++++++ > OvmfPkg/CpuHotplugSmm/Smbase.c | 157 +++++++++++++++++++= + > 5 files changed, 376 insertions(+) > > diff --git a/OvmfPkg/CpuHotplugSmm/CpuHotplugSmm.inf b/OvmfPkg/CpuHotplug= Smm/CpuHotplugSmm.inf > index bf4162299c7c..04322b0d7855 100644 > --- a/OvmfPkg/CpuHotplugSmm/CpuHotplugSmm.inf > +++ b/OvmfPkg/CpuHotplugSmm/CpuHotplugSmm.inf > @@ -5,56 +5,60 @@ > # > # SPDX-License-Identifier: BSD-2-Clause-Patent > ## > > [Defines] > INF_VERSION =3D 1.29 > PI_SPECIFICATION_VERSION =3D 0x00010046 #= PI-1.7.0 > BASE_NAME =3D CpuHotplugSmm > FILE_GUID =3D 84EEA114-C6BE-4445-8F90-51D97863E363 > MODULE_TYPE =3D DXE_SMM_DRIVER > ENTRY_POINT =3D CpuHotplugEntry > > # > # The following information is for reference only and not required by th= e build > # tools. > # > # VALID_ARCHITECTURES =3D IA32 X64 > # > > [Sources] > ApicId.h > CpuHotplug.c > + FirstSmiHandler.nasm > + FirstSmiHandlerContext.h > PostSmmPen.nasm > QemuCpuhp.c > QemuCpuhp.h > Smbase.c > Smbase.h > > [Packages] > MdePkg/MdePkg.dec > OvmfPkg/OvmfPkg.dec > UefiCpuPkg/UefiCpuPkg.dec > > [LibraryClasses] > BaseLib > BaseMemoryLib > DebugLib > + LocalApicLib > MmServicesTableLib > PcdLib > SafeIntLib > + SynchronizationLib > UefiDriverEntryPoint > > [Protocols] > gEfiMmCpuIoProtocolGuid ## C= ONSUMES > gEfiSmmCpuServiceProtocolGuid ## C= ONSUMES > > [Pcd] > gUefiCpuPkgTokenSpaceGuid.PcdCpuHotPlugDataAddress ## C= ONSUMES > gUefiOvmfPkgTokenSpaceGuid.PcdQ35SmramAtDefaultSmbase ## C= ONSUMES > > [FeaturePcd] > gUefiOvmfPkgTokenSpaceGuid.PcdSmmSmramRequire ## C= ONSUMES > > [Depex] > gEfiMmCpuIoProtocolGuid AND > gEfiSmmCpuServiceProtocolGuid > diff --git a/OvmfPkg/CpuHotplugSmm/FirstSmiHandlerContext.h b/OvmfPkg/Cpu= HotplugSmm/FirstSmiHandlerContext.h > new file mode 100644 > index 000000000000..029de4cdea35 > --- /dev/null > +++ b/OvmfPkg/CpuHotplugSmm/FirstSmiHandlerContext.h > @@ -0,0 +1,47 @@ > +/** @file > + Define the FIRST_SMI_HANDLER_CONTEXT structure, which is an exchange a= rea > + between the SMM Monarch and the hot-added CPU, for relocating the SMBA= SE of > + the hot-added CPU. > + > + Copyright (c) 2020, Red Hat, Inc. > + > + SPDX-License-Identifier: BSD-2-Clause-Patent > +**/ > + > +#ifndef FIRST_SMI_HANDLER_CONTEXT_H_ > +#define FIRST_SMI_HANDLER_CONTEXT_H_ > + > +// > +// The following structure is used to communicate between the SMM Monarc= h > +// (running the root MMI handler) and the hot-added CPU (handling its fi= rst > +// SMI). It is placed at SMM_DEFAULT_SMBASE, which is in SMRAM under QEM= U's > +// "SMRAM at default SMBASE" feature. > +// > +#pragma pack (1) > +typedef struct { > + // > + // When ApicIdGate is MAX_UINT64, then no hot-added CPU may proceed wi= th > + // SMBASE relocation. > + // > + // Otherwise, the hot-added CPU whose APIC ID equals ApicIdGate may pr= oceed > + // with SMBASE relocation. > + // > + // This field is intentionally wider than APIC_ID (UINT32) because we = need a > + // "gate locked" value that is different from all possible APIC_IDs. > + // > + UINT64 ApicIdGate; > + // > + // The new SMBASE value for the hot-added CPU to set in the SMRAM Save= State > + // Map, before leaving SMM with the RSM instruction. > + // > + UINT32 NewSmbase; > + // > + // The hot-added CPU sets this field to 1 right before executing the R= SM > + // instruction. This tells the SMM Monarch to proceed to polling the l= ast > + // byte of the normal RAM reserved page (Post-SMM Pen). > + // > + UINT8 AboutToLeaveSmm; > +} FIRST_SMI_HANDLER_CONTEXT; > +#pragma pack () > + > +#endif // FIRST_SMI_HANDLER_CONTEXT_H_ > diff --git a/OvmfPkg/CpuHotplugSmm/Smbase.h b/OvmfPkg/CpuHotplugSmm/Smbas= e.h > index cb5aed98cdd3..e73730d19926 100644 > --- a/OvmfPkg/CpuHotplugSmm/Smbase.h > +++ b/OvmfPkg/CpuHotplugSmm/Smbase.h > @@ -1,32 +1,46 @@ > /** @file > SMBASE relocation for hot-plugged CPUs. > > Copyright (c) 2020, Red Hat, Inc. > > SPDX-License-Identifier: BSD-2-Clause-Patent > **/ > > #ifndef SMBASE_H_ > #define SMBASE_H_ > > #include // EFI_STATUS > #include // EFI_BOOT_SERVICES > > +#include "ApicId.h" // APIC_ID > + > EFI_STATUS > SmbaseAllocatePostSmmPen ( > OUT UINT32 *PenAddress, > IN CONST EFI_BOOT_SERVICES *BootServices > ); > > VOID > SmbaseReinstallPostSmmPen ( > IN UINT32 PenAddress > ); > > VOID > SmbaseReleasePostSmmPen ( > IN UINT32 PenAddress, > IN CONST EFI_BOOT_SERVICES *BootServices > ); > > +VOID > +SmbaseInstallFirstSmiHandler ( > + VOID > + ); > + > +EFI_STATUS > +SmbaseRelocate ( > + IN APIC_ID ApicId, > + IN UINTN Smbase, > + IN UINT32 PenAddress > + ); > + > #endif // SMBASE_H_ > diff --git a/OvmfPkg/CpuHotplugSmm/FirstSmiHandler.nasm b/OvmfPkg/CpuHotp= lugSmm/FirstSmiHandler.nasm > new file mode 100644 > index 000000000000..5399b5fa4387 > --- /dev/null > +++ b/OvmfPkg/CpuHotplugSmm/FirstSmiHandler.nasm > @@ -0,0 +1,154 @@ > +;-----------------------------------------------------------------------= ------- > +; @file > +; Relocate the SMBASE on a hot-added CPU when it services its first SMI. > +; > +; Copyright (c) 2020, Red Hat, Inc. > +; > +; SPDX-License-Identifier: BSD-2-Clause-Patent > +; > +; The routine runs on the hot-added CPU in the following "big real mode"= , > +; 16-bit environment; per "SMI HANDLER EXECUTION ENVIRONMENT" in the Int= el SDM > +; (table "Processor Register Initialization in SMM"): > +; > +; - CS selector: 0x3000 (most significant 16 bits of SMM_DEFAULT_SMBASE= ). > +; > +; - CS limit: 0xFFFF_FFFF. > +; > +; - CS base: SMM_DEFAULT_SMBASE (0x3_0000). > +; > +; - IP: SMM_HANDLER_OFFSET (0x8000). > +; > +; - ES, SS, DS, FS, GS selectors: 0. > +; > +; - ES, SS, DS, FS, GS limits: 0xFFFF_FFFF. > +; > +; - ES, SS, DS, FS, GS bases: 0. > +; > +; - Operand-size and address-size override prefixes can be used to acce= ss the > +; address space beyond 1MB. > +;-----------------------------------------------------------------------= ------- > + > +SECTION .data > +BITS 16 > + > +; > +; Bring in SMM_DEFAULT_SMBASE from > +; "MdePkg/Include/Register/Intel/SmramSaveStateMap.h". > +; > +SMM_DEFAULT_SMBASE: equ 0x3_0000 > + > +; > +; Field offsets in FIRST_SMI_HANDLER_CONTEXT, which resides at > +; SMM_DEFAULT_SMBASE. > +; > +ApicIdGate: equ 0 ; UINT64 > +NewSmbase: equ 8 ; UINT32 > +AboutToLeaveSmm: equ 12 ; UINT8 > + > +; > +; SMRAM Save State Map field offsets, per the AMD (not Intel) layout tha= t QEMU > +; implements. Relative to SMM_DEFAULT_SMBASE. > +; > +SaveStateRevId: equ 0xFEFC ; UINT32 > +SaveStateSmbase: equ 0xFEF8 ; UINT32 > +SaveStateSmbase64: equ 0xFF00 ; UINT32 > + > +; > +; CPUID constants, from "MdePkg/Include/Register/Intel/Cpuid.h". > +; > +CPUID_SIGNATURE: equ 0x00 > +CPUID_EXTENDED_TOPOLOGY: equ 0x0B > +CPUID_VERSION_INFO: equ 0x01 > + > +GLOBAL ASM_PFX (mFirstSmiHandler) ; UINT8[] > +GLOBAL ASM_PFX (mFirstSmiHandlerSize) ; UINT16 > + > +ASM_PFX (mFirstSmiHandler): > + ; > + ; Get our own APIC ID first, so we can contend for ApicIdGate. > + ; > + ; This basically reimplements GetInitialApicId() from > + ; "UefiCpuPkg/Library/BaseXApicLib/BaseXApicLib.c". > + ; > + mov eax, CPUID_SIGNATURE > + cpuid > + cmp eax, CPUID_EXTENDED_TOPOLOGY > + jb GetApicIdFromVersionInfo > + > + mov eax, CPUID_EXTENDED_TOPOLOGY > + mov ecx, 0 > + cpuid > + test ebx, 0xFFFF > + jz GetApicIdFromVersionInfo > + > + ; > + ; EDX has the APIC ID, save it to ESI. > + ; > + mov esi, edx > + jmp KnockOnGate > + > +GetApicIdFromVersionInfo: > + mov eax, CPUID_VERSION_INFO > + cpuid > + shr ebx, 24 > + ; > + ; EBX has the APIC ID, save it to ESI. > + ; > + mov esi, ebx > + > +KnockOnGate: > + ; > + ; See if ApicIdGate shows our own APIC ID. If so, swap it to MAX_UINT6= 4 > + ; (close the gate), and advance. Otherwise, keep knocking. > + ; > + ; InterlockedCompareExchange64(): > + ; - Value :=3D &FIRST_SMI_HANDLER_CONTEXT.ApicIdGate > + ; - CompareValue (EDX:EAX) :=3D APIC ID (from ESI) > + ; - ExchangeValue (ECX:EBX) :=3D MAX_UINT64 > + ; > + mov edx, 0 > + mov eax, esi > + mov ecx, 0xFFFF_FFFF > + mov ebx, 0xFFFF_FFFF > + lock cmpxchg8b [ds : dword (SMM_DEFAULT_SMBASE + ApicIdGate)] > + jz ApicIdMatch > + pause > + jmp KnockOnGate > + > +ApicIdMatch: > + ; > + ; Update the SMBASE field in the SMRAM Save State Map. > + ; > + ; First, calculate the address of the SMBASE field, based on the SMM R= evision > + ; ID; store the result in EBX. > + ; > + mov eax, dword [ds : dword (SMM_DEFAULT_SMBASE + SaveStateRevId)] > + test eax, 0xFFFF > + jz LegacySaveStateMap > + > + mov ebx, SMM_DEFAULT_SMBASE + SaveStateSmbase64 > + jmp UpdateSmbase > + > +LegacySaveStateMap: > + mov ebx, SMM_DEFAULT_SMBASE + SaveStateSmbase > + > +UpdateSmbase: > + ; > + ; Load the new SMBASE value into EAX. > + ; > + mov eax, dword [ds : dword (SMM_DEFAULT_SMBASE + NewSmbase)] > + ; > + ; Save it to the SMBASE field whose address we calculated in EBX. > + ; > + mov dword [ds : dword ebx], eax > + ; > + ; Set AboutToLeaveSmm. > + ; > + mov byte [ds : dword (SMM_DEFAULT_SMBASE + AboutToLeaveSmm)], 1 > + ; > + ; We're done; leave SMM and continue to the pen. > + ; > + rsm > + > +ASM_PFX (mFirstSmiHandlerSize): > + dw $ - ASM_PFX (mFirstSmiHandler) > diff --git a/OvmfPkg/CpuHotplugSmm/Smbase.c b/OvmfPkg/CpuHotplugSmm/Smbas= e.c > index ea21153d9145..170571221d84 100644 > --- a/OvmfPkg/CpuHotplugSmm/Smbase.c > +++ b/OvmfPkg/CpuHotplugSmm/Smbase.c > @@ -1,38 +1,46 @@ > /** @file > SMBASE relocation for hot-plugged CPUs. > > Copyright (c) 2020, Red Hat, Inc. > > SPDX-License-Identifier: BSD-2-Clause-Patent > **/ > > #include // BASE_1MB > +#include // CpuPause() > #include // CopyMem() > #include // DEBUG() > +#include // SendInitSipiSipi() > +#include // InterlockedCompareExcha= nge64() > +#include // SMM_DEFAULT_SMBASE > + > +#include "FirstSmiHandlerContext.h" // FIRST_SMI_HANDLER_CONTE= XT > > #include "Smbase.h" > > extern CONST UINT8 mPostSmmPen[]; > extern CONST UINT16 mPostSmmPenSize; > +extern CONST UINT8 mFirstSmiHandler[]; > +extern CONST UINT16 mFirstSmiHandlerSize; > > /** > Allocate a non-SMRAM reserved memory page for the Post-SMM Pen for hot= -added > CPUs. > > This function may only be called from the entry point function of the = driver. > > @param[out] PenAddress The address of the allocated (normal RAM) res= erved > page. > > @param[in] BootServices Pointer to the UEFI boot services table. Used= for > allocating the normal RAM (not SMRAM) reserve= d page. > > @retval EFI_SUCCESS Allocation successful. > > @retval EFI_BAD_BUFFER_SIZE The Post-SMM Pen template is not smaller = than > EFI_PAGE_SIZE. > > @return Error codes propagated from underlying se= rvices. > DEBUG_ERROR messages have been logged. No > resources have been allocated. > **/ > @@ -89,22 +97,171 @@ SmbaseReinstallPostSmmPen ( > } > > /** > Release the reserved page allocated with SmbaseAllocatePostSmmPen(). > > This function may only be called from the entry point function of the = driver, > on the error path. > > @param[in] PenAddress The allocation address returned by > SmbaseAllocatePostSmmPen(). > > @param[in] BootServices Pointer to the UEFI boot services table. Used= for > releasing the normal RAM (not SMRAM) reserved= page. > **/ > VOID > SmbaseReleasePostSmmPen ( > IN UINT32 PenAddress, > IN CONST EFI_BOOT_SERVICES *BootServices > ) > { > BootServices->FreePages (PenAddress, 1); > } > + > +/** > + Place the handler routine for the first SMIs of hot-added CPUs at > + (SMM_DEFAULT_SMBASE + SMM_HANDLER_OFFSET). > + > + Note that this effects an "SMRAM to SMRAM" copy. > + > + Additionally, shut the APIC ID gate in FIRST_SMI_HANDLER_CONTEXT. > + > + This function may only be called from the entry point function of the = driver, > + and only after PcdQ35SmramAtDefaultSmbase has been determined to be TR= UE. > +**/ > +VOID > +SmbaseInstallFirstSmiHandler ( > + VOID > + ) > +{ > + FIRST_SMI_HANDLER_CONTEXT *Context; > + > + CopyMem ((VOID *)(UINTN)(SMM_DEFAULT_SMBASE + SMM_HANDLER_OFFSET), > + mFirstSmiHandler, mFirstSmiHandlerSize); > + > + Context =3D (VOID *)(UINTN)SMM_DEFAULT_SMBASE; > + Context->ApicIdGate =3D MAX_UINT64; > +} > + > +/** > + Relocate the SMBASE on a hot-added CPU. Then pen the hot-added CPU in = the > + normal RAM reserved memory page, set up earlier with > + SmbaseAllocatePostSmmPen() and SmbaseReinstallPostSmmPen(). > + > + The SMM Monarch is supposed to call this function from the root MMI ha= ndler. > + > + The SMM Monarch is responsible for calling SmbaseInstallFirstSmiHandle= r(), > + SmbaseAllocatePostSmmPen(), and SmbaseReinstallPostSmmPen() before cal= ling > + this function. > + > + If the OS maliciously boots the hot-added CPU ahead of letting the ACP= I CPU > + hotplug event handler broadcast the CPU hotplug MMI, then the hot-adde= d CPU > + returns to the OS rather than to the pen, upon RSM. In that case, this > + function will hang forever (unless the OS happens to signal back throu= gh the > + last byte of the pen page). > + > + @param[in] ApicId The APIC ID of the hot-added CPU whose SMBASE s= hould > + be relocated. > + > + @param[in] Smbase The new SMBASE address. The root MMI handler is > + responsible for passing in a free ("unoccupied"= ) > + SMBASE address that was pre-configured by > + PiSmmCpuDxeSmm in CPU_HOT_PLUG_DATA. > + > + @param[in] PenAddress The address of the Post-SMM Pen for hot-added C= PUs, as > + returned by SmbaseAllocatePostSmmPen(), and ins= talled > + by SmbaseReinstallPostSmmPen(). > + > + @retval EFI_SUCCESS The SMBASE of the hot-added CPU with AP= IC ID > + ApicId has been relocated to Smbase. Th= e > + hot-added CPU has reported back about l= eaving > + SMM. > + > + @retval EFI_PROTOCOL_ERROR Synchronization bug encountered around > + FIRST_SMI_HANDLER_CONTEXT.ApicIdGate. > + > + @retval EFI_INVALID_PARAMETER Smbase does not fit in 32 bits. No relo= cation > + has been attempted. > +**/ > +EFI_STATUS > +SmbaseRelocate ( > + IN APIC_ID ApicId, > + IN UINTN Smbase, > + IN UINT32 PenAddress > + ) > +{ > + EFI_STATUS Status; > + volatile UINT8 *SmmVacated; > + volatile FIRST_SMI_HANDLER_CONTEXT *Context; > + UINT64 ExchangeResult; > + > + if (Smbase > MAX_UINT32) { > + Status =3D EFI_INVALID_PARAMETER; > + DEBUG ((DEBUG_ERROR, "%a: ApicId=3D" FMT_APIC_ID " Smbase=3D0x%Lx: %= r\n", > + __FUNCTION__, ApicId, (UINT64)Smbase, Status)); > + return Status; > + } > + > + SmmVacated =3D (UINT8 *)(UINTN)PenAddress + (EFI_PAGE_SIZE - 1); > + Context =3D (VOID *)(UINTN)SMM_DEFAULT_SMBASE; > + > + // > + // Clear AboutToLeaveSmm, so we notice when the hot-added CPU is just = about > + // to reach RSM, and we can proceed to polling the last byte of the re= served > + // page (which could be attacked by the OS). > + // > + Context->AboutToLeaveSmm =3D 0; > + > + // > + // Clear the last byte of the reserved page, so we notice when the hot= -added > + // CPU checks back in from the pen. > + // > + *SmmVacated =3D 0; > + > + // > + // Boot the hot-added CPU. > + // > + // If the OS is benign, and so the hot-added CPU is still in RESET sta= te, > + // then the broadcast SMI is still pending for it; it will now launch > + // directly into SMM. > + // > + // If the OS is malicious, the hot-added CPU has been booted already, = and so > + // it is already spinning on the APIC ID gate. In that case, the > + // INIT-SIPI-SIPI below will be ignored. > + // > + SendInitSipiSipi (ApicId, PenAddress); > + > + // > + // Expose the desired new SMBASE value to the hot-added CPU. > + // > + Context->NewSmbase =3D (UINT32)Smbase; > + > + // > + // Un-gate SMBASE relocation for the hot-added CPU whose APIC ID is Ap= icId. > + // > + ExchangeResult =3D InterlockedCompareExchange64 (&Context->ApicIdGate, > + MAX_UINT64, ApicId); > + if (ExchangeResult !=3D MAX_UINT64) { > + Status =3D EFI_PROTOCOL_ERROR; > + DEBUG ((DEBUG_ERROR, "%a: ApicId=3D" FMT_APIC_ID " ApicIdGate=3D0x%L= x: %r\n", > + __FUNCTION__, ApicId, ExchangeResult, Status)); > + return Status; > + } > + > + // > + // Wait until the hot-added CPU is just about to execute RSM. > + // > + while (Context->AboutToLeaveSmm =3D=3D 0) { > + CpuPause (); > + } > + > + // > + // Now wait until the hot-added CPU reports back from the pen (or the = OS > + // attacks the last byte of the reserved page). > + // > + while (*SmmVacated =3D=3D 0) { > + CpuPause (); > + } > + > + Status =3D EFI_SUCCESS; > + return Status; > +} > -- > 2.19.1.3.g30247aa5d201 > >