From nobody Sat Feb 7 06:49:17 2026 Delivered-To: importer@patchew.org Received-SPF: pass (zohomail.com: domain of groups.io designates 66.175.222.12 as permitted sender) client-ip=66.175.222.12; envelope-from=bounce+27952+54955+1787277+3901457@groups.io; helo=web01.groups.io; Authentication-Results: mx.zohomail.com; dkim=pass; spf=pass (zohomail.com: domain of groups.io designates 66.175.222.12 as permitted sender) smtp.mailfrom=bounce+27952+54955+1787277+3901457@groups.io; dmarc=fail(p=none dis=none) header.from=redhat.com ARC-Seal: i=1; a=rsa-sha256; t=1582755157; cv=none; d=zohomail.com; s=zohoarc; b=Fo6+pXG9RmHhkCLbkMk3m9gvyfFD8YkjkqxlGBnR3we+cY10XvA63wR/Z1JMDroA9wdYCOlljFIj42vZF/DUMsoZnJyHaSUpdhO9B7xNT150/2fXqCSDGGvyphz7T2u+yq3K6cF6bQJx8As0C4q1LPmQ2PA7fzDf6WbYkpdAGB0= ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=zohomail.com; s=zohoarc; t=1582755157; h=Content-Type:Content-Transfer-Encoding:Cc:Date:From:In-Reply-To:List-Id:List-Unsubscribe:MIME-Version:Message-ID:Reply-To:References:Sender:Subject:To; bh=iDa0e4cF+z4fKyMQdVghzHYMneLaeHjYitNAXe77SuA=; b=mZptpABGUGiHKcQTywqvvSkmC1rs245G68W+t1+wKNw2QUq+KjEvg4QMvwDPk5BMMo2NFdMKrioRA8MjOvL5kESrOpOCfDUvhQoB/+P945IFg4G2LtTJ6l8gs6TC9hIAg8ePh6EA1IJrKmrH8T5vKKcFXuk6MBuXvu25Gv4ST5Y= ARC-Authentication-Results: i=1; mx.zohomail.com; dkim=pass; spf=pass (zohomail.com: domain of groups.io designates 66.175.222.12 as permitted sender) smtp.mailfrom=bounce+27952+54955+1787277+3901457@groups.io; dmarc=fail header.from= (p=none dis=none) header.from= Received: from web01.groups.io (web01.groups.io [66.175.222.12]) by mx.zohomail.com with SMTPS id 1582755157145936.4821703043253; Wed, 26 Feb 2020 14:12:37 -0800 (PST) Return-Path: X-Received: by 127.0.0.2 with SMTP id 31m4YY1788612xD18iLK66hP; Wed, 26 Feb 2020 14:12:36 -0800 X-Received: from us-smtp-1.mimecast.com (us-smtp-1.mimecast.com [207.211.31.120]) by mx.groups.io with SMTP id smtpd.web11.242.1582755155439029114 for ; Wed, 26 Feb 2020 14:12:35 -0800 X-Received: from mimecast-mx01.redhat.com (mimecast-mx01.redhat.com [209.132.183.4]) (Using TLS) by relay.mimecast.com with ESMTP id us-mta-13-R6XzJysgOBOketJvp6rxBQ-1; Wed, 26 Feb 2020 17:12:30 -0500 X-MC-Unique: R6XzJysgOBOketJvp6rxBQ-1 X-Received: from smtp.corp.redhat.com (int-mx03.intmail.prod.int.phx2.redhat.com [10.5.11.13]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by mimecast-mx01.redhat.com (Postfix) with ESMTPS id 9926FDB61; Wed, 26 Feb 2020 22:12:29 +0000 (UTC) X-Received: from lacos-laptop-7.usersys.redhat.com (ovpn-116-185.ams2.redhat.com [10.36.116.185]) by smtp.corp.redhat.com (Postfix) with ESMTP id E1F5560BEF; Wed, 26 Feb 2020 22:12:27 +0000 (UTC) From: "Laszlo Ersek" To: edk2-devel-groups-io Cc: Ard Biesheuvel , Igor Mammedov , Jiewen Yao , Jordan Justen , Michael Kinney , =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Subject: [edk2-devel] [PATCH v2 12/16] OvmfPkg/CpuHotplugSmm: introduce First SMI Handler for hot-added CPUs Date: Wed, 26 Feb 2020 23:11:52 +0100 Message-Id: <20200226221156.29589-13-lersek@redhat.com> In-Reply-To: <20200226221156.29589-1-lersek@redhat.com> References: <20200226221156.29589-1-lersek@redhat.com> MIME-Version: 1.0 X-Scanned-By: MIMEDefang 2.79 on 10.5.11.13 X-Mimecast-Spam-Score: 0 X-Mimecast-Originator: redhat.com Precedence: Bulk List-Unsubscribe: Sender: devel@edk2.groups.io List-Id: Mailing-List: list devel@edk2.groups.io; contact devel+owner@edk2.groups.io Reply-To: devel@edk2.groups.io,lersek@redhat.com X-Gm-Message-State: 48t6QHNIN0R2DT1kDmqkU2fax1787277AA= Content-Transfer-Encoding: quoted-printable DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=groups.io; q=dns/txt; s=20140610; t=1582755156; bh=iDa0e4cF+z4fKyMQdVghzHYMneLaeHjYitNAXe77SuA=; h=Cc:Content-Type:Date:From:Reply-To:Subject:To; b=l+3oHjNk3lc9mJ/7UO+XVHHkneL4yYK+m1Qql2O/0Mqsc9yuea8ULHWVx7kjN8o8wTY pRQ0sOUZjwpRd7cXgFEMC4/+bjkV+jXnJHzuWFftTS47UN4SBDqZfmAe9ywnYbT6/EXxB /+PsCRqj9Qxl4+CPMOXvAfuc1Bh/cVjZ5FU= X-ZohoMail-DKIM: pass (identity @groups.io) Content-Type: text/plain; charset="utf-8" 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: =20 - implement the combined approach described here: =20 http://mid.mail-archive.com/111145fc-be3d-2a9a-a126-c14345a8a8a4@redh= at.com https://edk2.groups.io/g/devel/message/54754 =20 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/CpuHotplugSm= m/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 ## =20 [Defines] INF_VERSION =3D 1.29 PI_SPECIFICATION_VERSION =3D 0x00010046 # P= I-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 =20 # # The following information is for reference only and not required by the = build # tools. # # VALID_ARCHITECTURES =3D IA32 X64 # =20 [Sources] ApicId.h CpuHotplug.c + FirstSmiHandler.nasm + FirstSmiHandlerContext.h PostSmmPen.nasm QemuCpuhp.c QemuCpuhp.h Smbase.c Smbase.h =20 [Packages] MdePkg/MdePkg.dec OvmfPkg/OvmfPkg.dec UefiCpuPkg/UefiCpuPkg.dec =20 [LibraryClasses] BaseLib BaseMemoryLib DebugLib + LocalApicLib MmServicesTableLib PcdLib SafeIntLib + SynchronizationLib UefiDriverEntryPoint =20 [Protocols] gEfiMmCpuIoProtocolGuid ## CON= SUMES gEfiSmmCpuServiceProtocolGuid ## CON= SUMES =20 [Pcd] gUefiCpuPkgTokenSpaceGuid.PcdCpuHotPlugDataAddress ## CON= SUMES gUefiOvmfPkgTokenSpaceGuid.PcdQ35SmramAtDefaultSmbase ## CON= SUMES =20 [FeaturePcd] gUefiOvmfPkgTokenSpaceGuid.PcdSmmSmramRequire ## CON= SUMES =20 [Depex] gEfiMmCpuIoProtocolGuid AND gEfiSmmCpuServiceProtocolGuid diff --git a/OvmfPkg/CpuHotplugSmm/FirstSmiHandlerContext.h b/OvmfPkg/CpuHo= tplugSmm/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 area + between the SMM Monarch and the hot-added CPU, for relocating the SMBASE= 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 Monarch +// (running the root MMI handler) and the hot-added CPU (handling its first +// SMI). It is placed at SMM_DEFAULT_SMBASE, which is in SMRAM under QEMU's +// "SMRAM at default SMBASE" feature. +// +#pragma pack (1) +typedef struct { + // + // When ApicIdGate is MAX_UINT64, then no hot-added CPU may proceed with + // SMBASE relocation. + // + // Otherwise, the hot-added CPU whose APIC ID equals ApicIdGate may proc= eed + // with SMBASE relocation. + // + // This field is intentionally wider than APIC_ID (UINT32) because we ne= ed 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 S= tate + // Map, before leaving SMM with the RSM instruction. + // + UINT32 NewSmbase; + // + // The hot-added CPU sets this field to 1 right before executing the RSM + // instruction. This tells the SMM Monarch to proceed to polling the last + // 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/Smbase.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. =20 Copyright (c) 2020, Red Hat, Inc. =20 SPDX-License-Identifier: BSD-2-Clause-Patent **/ =20 #ifndef SMBASE_H_ #define SMBASE_H_ =20 #include // EFI_STATUS #include // EFI_BOOT_SERVICES =20 +#include "ApicId.h" // APIC_ID + EFI_STATUS SmbaseAllocatePostSmmPen ( OUT UINT32 *PenAddress, IN CONST EFI_BOOT_SERVICES *BootServices ); =20 VOID SmbaseReinstallPostSmmPen ( IN UINT32 PenAddress ); =20 VOID SmbaseReleasePostSmmPen ( IN UINT32 PenAddress, IN CONST EFI_BOOT_SERVICES *BootServices ); =20 +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/CpuHotplu= gSmm/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 Intel= 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 access= 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 that = 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_UINT64 + ; (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 Rev= ision + ; 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/Smbase.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. =20 Copyright (c) 2020, Red Hat, Inc. =20 SPDX-License-Identifier: BSD-2-Clause-Patent **/ =20 #include // BASE_1MB +#include // CpuPause() #include // CopyMem() #include // DEBUG() +#include // SendInitSipiSipi() +#include // InterlockedCompareExchang= e64() +#include // SMM_DEFAULT_SMBASE + +#include "FirstSmiHandlerContext.h" // FIRST_SMI_HANDLER_CONTEXT =20 #include "Smbase.h" =20 extern CONST UINT8 mPostSmmPen[]; extern CONST UINT16 mPostSmmPenSize; +extern CONST UINT8 mFirstSmiHandler[]; +extern CONST UINT16 mFirstSmiHandlerSize; =20 /** Allocate a non-SMRAM reserved memory page for the Post-SMM Pen for hot-a= dded CPUs. =20 This function may only be called from the entry point function of the dr= iver. =20 @param[out] PenAddress The address of the allocated (normal RAM) reser= ved page. =20 @param[in] BootServices Pointer to the UEFI boot services table. Used f= or allocating the normal RAM (not SMRAM) reserved = page. =20 @retval EFI_SUCCESS Allocation successful. =20 @retval EFI_BAD_BUFFER_SIZE The Post-SMM Pen template is not smaller th= an EFI_PAGE_SIZE. =20 @return Error codes propagated from underlying serv= ices. DEBUG_ERROR messages have been logged. No resources have been allocated. **/ @@ -89,22 +97,171 @@ SmbaseReinstallPostSmmPen ( } =20 /** Release the reserved page allocated with SmbaseAllocatePostSmmPen(). =20 This function may only be called from the entry point function of the dr= iver, on the error path. =20 @param[in] PenAddress The allocation address returned by SmbaseAllocatePostSmmPen(). =20 @param[in] BootServices Pointer to the UEFI boot services table. Used f= or releasing the normal RAM (not SMRAM) reserved p= age. **/ 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 dr= iver, + and only after PcdQ35SmramAtDefaultSmbase has been determined to be TRUE. +**/ +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 hand= ler. + + The SMM Monarch is responsible for calling SmbaseInstallFirstSmiHandler(= ), + SmbaseAllocatePostSmmPen(), and SmbaseReinstallPostSmmPen() before calli= ng + this function. + + If the OS maliciously boots the hot-added CPU ahead of letting the ACPI = CPU + hotplug event handler broadcast the CPU hotplug MMI, then the hot-added = 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 through= the + last byte of the pen page). + + @param[in] ApicId The APIC ID of the hot-added CPU whose SMBASE sho= uld + 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 CPU= s, as + returned by SmbaseAllocatePostSmmPen(), and insta= lled + by SmbaseReinstallPostSmmPen(). + + @retval EFI_SUCCESS The SMBASE of the hot-added CPU with APIC= ID + ApicId has been relocated to Smbase. The + hot-added CPU has reported back about lea= ving + 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 reloca= tion + 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 ab= out + // to reach RSM, and we can proceed to polling the last byte of the rese= rved + // 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-a= dded + // 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 state, + // 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, an= d 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 Apic= Id. + // + 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%Lx:= %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; +} --=20 2.19.1.3.g30247aa5d201 -=3D-=3D-=3D-=3D-=3D-=3D-=3D-=3D-=3D-=3D-=3D- Groups.io Links: You receive all messages sent to this group. View/Reply Online (#54955): https://edk2.groups.io/g/devel/message/54955 Mute This Topic: https://groups.io/mt/71575188/1787277 Group Owner: devel+owner@edk2.groups.io Unsubscribe: https://edk2.groups.io/g/devel/unsub [importer@patchew.org] -=3D-=3D-=3D-=3D-=3D-=3D-=3D-=3D-=3D-=3D-=3D-