From mboxrd@z Thu Jan 1 00:00:00 1970 Received: from mga12.intel.com (mga12.intel.com [192.55.52.136]) by mx.groups.io with SMTP id smtpd.web11.11788.1687942151408549511 for ; Wed, 28 Jun 2023 01:49:12 -0700 Authentication-Results: mx.groups.io; dkim=fail reason="unable to parse pub key" header.i=@intel.com header.s=intel header.b=I/8sDcGt; spf=pass (domain: intel.com, ip: 192.55.52.136, mailfrom: yuanhao.xie@intel.com) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=intel.com; i=@intel.com; q=dns/txt; s=Intel; t=1687942152; x=1719478152; h=from:to:cc:subject:date:message-id:in-reply-to: references:mime-version:content-transfer-encoding; bh=EX3eTG3jLTrbyy7tvbq3KsiCy+Rj5GTvVNSevRJ5fLA=; b=I/8sDcGtQOFECZ+iPWlRYxpY9jGhpLJ/nD6iG+cJTbQklsspicp2Dy9v RMWiFpmixFSnfO5wa9XPIHxpPR+rg6RgEes8xRsZGbBMTTQvS8JSfzFuD UoDPlwzaBFSBp5Mzs+eQ01n21jSpDGHYqptA3YnirLnGESk9iivI/paxv Fq7I+wgY21CSx01GwE8DvuIQGKb37e//rN/Iqt58zCWwqUXRqU2aJP9Qa UOV0Cm1yuFBOGzMuk/vtB6y2zKKVWLmSCJiO95reiEWINWKWk5OcTyRWK Qm/mIaHH3W7amo6kw5efplL6gSa8SzpyhT7/9I3gSXe0v1CgQ+wXlAIfF g==; X-IronPort-AV: E=McAfee;i="6600,9927,10754"; a="341373551" X-IronPort-AV: E=Sophos;i="6.01,165,1684825200"; d="scan'208";a="341373551" Received: from orsmga005.jf.intel.com ([10.7.209.41]) by fmsmga106.fm.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 28 Jun 2023 01:48:02 -0700 X-ExtLoop1: 1 X-IronPort-AV: E=McAfee;i="6600,9927,10754"; a="890964594" X-IronPort-AV: E=Sophos;i="6.01,165,1684825200"; d="scan'208";a="890964594" Received: from shwdeopenlab705.ccr.corp.intel.com ([10.239.55.55]) by orsmga005-auth.jf.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 28 Jun 2023 01:47:58 -0700 From: "Yuanhao Xie" To: devel@edk2.groups.io Cc: Gerd Hoffmann , Eric Dong , Ray Ni , Rahul Kumar , Tom Lendacky , Yuanhao Xie Subject: [Patch V4 3/5] UefiCpuPkg: Create MpHandOff. Date: Wed, 28 Jun 2023 16:47:22 +0800 Message-Id: <20230628084724.57574-4-yuanhao.xie@intel.com> X-Mailer: git-send-email 2.36.1.windows.1 In-Reply-To: <20230628084724.57574-1-yuanhao.xie@intel.com> References: <20230628084724.57574-1-yuanhao.xie@intel.com> MIME-Version: 1.0 Content-Transfer-Encoding: 8bit Initially, the purpose of the Hob was twofold: it served as a way to transfer information from PEI to DXE. However, during the DXE phase, only a few fields from the CPU_MP_DATA which collected in PEI phase were needed. A new Hob was specifically created to transfer information to the DXE phase. This new Hob contained only the essential fields required for reuse in DXE. For instance, instead of directly including the BspNumber in MpHandOff, the DXE phase introduced the use of GetBspNumber() to collect the BspNumber from ApicID and CpuCount. The SaveCpuMpData() function was updated to construct the MP_HAND_OFF Hob. Additionally, the function introduced the MP_HAND_OFF_SIGNAL, which solely served the purpose of awakening the APs and transitioning their context from PEI to DXE. The WaitLoopExecutionMode field indicated whether the bit mode of PEI matched that of DXE. Both of them were filled only if the ApLoopMode was not ApInHltLoop. In the case of ApInHltLoop, it remained necessary to wake up the APs using the init-sipi-sipi sequence. This improvement still allow INIT-SIPI-SIPI even APs are wait in Run/Mwait loop mode. The function GetMpHandOffHob() was added to facilitate access to the collected MpHandOff in the DXE phase. The CpuMpData in the DXE phase was updated by gathering information from MpHandOff. Since MpHandOff replaced the usage of OldCpuMpData and contained essential information from the PEI phase to the DXE phase. AmdSevUpdateCpuMpData was included to maintain the original implementation of AmdSev, ensuring that OldCpuMpData->NewCpuMpData pointed to CpuMpData. Cc: Gerd Hoffmann Cc: Eric Dong Cc: Ray Ni Cc: Rahul Kumar Cc: Tom Lendacky Signed-off-by: Yuanhao Xie --- UefiCpuPkg/Library/MpInitLib/AmdSev.c | 17 +++++++++++++++++ UefiCpuPkg/Library/MpInitLib/DxeMpInitLib.inf | 1 + UefiCpuPkg/Library/MpInitLib/MpHandOff.h | 47 +++++++++++++++++++++++++++++++++++++++++++++++ UefiCpuPkg/Library/MpInitLib/MpLib.c | 83 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++------------- UefiCpuPkg/Library/MpInitLib/MpLib.h | 19 +++++++++++++++++++ UefiCpuPkg/Library/MpInitLib/PeiMpInitLib.inf | 2 +- UefiCpuPkg/Library/MpInitLib/PeiMpLib.c | 32 +++++++++++++++++++++++++++++++- 7 files changed, 186 insertions(+), 15 deletions(-) diff --git a/UefiCpuPkg/Library/MpInitLib/AmdSev.c b/UefiCpuPkg/Library/MpInitLib/AmdSev.c index ca9bfed7f3..bda4960f6f 100644 --- a/UefiCpuPkg/Library/MpInitLib/AmdSev.c +++ b/UefiCpuPkg/Library/MpInitLib/AmdSev.c @@ -260,3 +260,20 @@ FillExchangeInfoDataSevEs ( ExchangeInfo->ExtTopoAvail = !!ExtTopoEbx.Bits.LogicalProcessors; } } + +/** + Get pointer to CPU MP Data structure from GUIDed HOB. + + @param[in] CpuMpData The pointer to CPU MP Data structure. +**/ +VOID +AmdSevUpdateCpuMpData ( + IN CPU_MP_DATA *CpuMpData + ) +{ + CPU_MP_DATA *OldCpuMpData; + + OldCpuMpData = GetCpuMpDataFromGuidedHob (); + + OldCpuMpData->NewCpuMpData = CpuMpData; +} diff --git a/UefiCpuPkg/Library/MpInitLib/DxeMpInitLib.inf b/UefiCpuPkg/Library/MpInitLib/DxeMpInitLib.inf index 67ebf7254c..7d45d3ad4d 100644 --- a/UefiCpuPkg/Library/MpInitLib/DxeMpInitLib.inf +++ b/UefiCpuPkg/Library/MpInitLib/DxeMpInitLib.inf @@ -38,6 +38,7 @@ MpLib.c MpLib.h Microcode.c + MpHandOff.h [Packages] MdePkg/MdePkg.dec diff --git a/UefiCpuPkg/Library/MpInitLib/MpHandOff.h b/UefiCpuPkg/Library/MpInitLib/MpHandOff.h new file mode 100644 index 0000000000..83e4055ec9 --- /dev/null +++ b/UefiCpuPkg/Library/MpInitLib/MpHandOff.h @@ -0,0 +1,47 @@ +/** @file + Defines the HOB GUID used to describe the MSEG memory region allocated in PEI. + Copyright (c) 2015 - 2023, Intel Corporation. All rights reserved.
+ SPDX-License-Identifier: BSD-2-Clause-Patent +**/ + +#ifndef MP_HANDOFF_H_ +#define MP_HANDOFF_H_ + +#define MP_HANDOFF_GUID \ + { \ + 0x11e2bd88, 0xed38, 0x4abd, {0xa3, 0x99, 0x21, 0xf2, 0x5f, 0xd0, 0x7a, 0x60 } \ + } + +extern EFI_GUID mMpHandOffGuid; + +// +// The information required to transfer from the PEI phase to the +// DXE phase is contained within the MP_HAND_OFF and PROCESSOR_HAND_OFF. +// If the SizeOfPointer (WaitLoopExecutionMode) of both phases are equal, +// and the APs is not in halt mode, +// then the APs can be awakened by triggering the start-up +// signal, rather than using INIT-SIPI-SIPI. +// To trigger the start-up signal, BSP writes the specified +// StartupSignalValue to the StartupSignalAddress of each processor. +// This address is monitored by the APs. +// +typedef struct { + UINT32 ApicId; + UINT32 Health; + UINT64 StartupSignalAddress; + UINT64 StartupProcedureAddress; +} PROCESSOR_HAND_OFF; + +typedef struct { + // + // The ProcessorIndex indicates the range of processors. If it is set to 0, it signifies + // processors from 0 to CpuCount - 1. Multiple instances in the HOB list describe + // processors from ProcessorIndex to ProcessorIndex + CpuCount - 1. + // + UINT32 ProcessorIndex; + UINT32 CpuCount; + UINT32 WaitLoopExecutionMode; + UINT32 StartupSignalValue; + PROCESSOR_HAND_OFF Info[]; +} MP_HAND_OFF; +#endif diff --git a/UefiCpuPkg/Library/MpInitLib/MpLib.c b/UefiCpuPkg/Library/MpInitLib/MpLib.c index e8dd640f9b..ccc01859f0 100644 --- a/UefiCpuPkg/Library/MpInitLib/MpLib.c +++ b/UefiCpuPkg/Library/MpInitLib/MpLib.c @@ -14,6 +14,7 @@ #include EFI_GUID mCpuInitMpLibHobGuid = CPU_INIT_MP_LIB_HOB_GUID; +EFI_GUID mMpHandOffGuid = MP_HANDOFF_GUID; /** Save the volatile registers required to be restored following INIT IPI. @@ -1814,6 +1815,59 @@ CheckAllAPs ( return EFI_NOT_READY; } +/** + This function Get BspNumber. + + @param[in] MpHandOff Pointer to MpHandOff + @return BspNumber +**/ +UINT32 +GetBspNumber ( + IN CONST MP_HAND_OFF *MpHandOff + ) +{ + UINT32 ApicId; + UINT32 BspNumber; + UINT32 Index; + + // + // Get the processor number for the BSP + // + BspNumber = MAX_UINT32; + ApicId = GetInitialApicId (); + for (Index = 0; Index < MpHandOff->CpuCount; Index++) { + if (MpHandOff->Info[Index].ApicId == ApicId) { + BspNumber = Index; + } + } + + ASSERT (BspNumber != MAX_UINT32); + + return BspNumber; +} + +/** + Get pointer to MP_HAND_OFF GUIDed HOB. + + @return The pointer to MP_HAND_OFF structure. +**/ +MP_HAND_OFF * +GetMpHandOffHob ( + VOID + ) +{ + EFI_HOB_GUID_TYPE *GuidHob; + MP_HAND_OFF *MpHandOff; + + MpHandOff = NULL; + GuidHob = GetFirstGuidHob (&mMpHandOffGuid); + if (GuidHob != NULL) { + MpHandOff = (MP_HAND_OFF *)GET_GUID_HOB_DATA (GuidHob); + } + + return MpHandOff; +} + /** MP Initialize Library initialization. @@ -1833,7 +1887,7 @@ MpInitLibInitialize ( VOID ) { - CPU_MP_DATA *OldCpuMpData; + MP_HAND_OFF *MpHandOff; CPU_INFO_IN_HOB *CpuInfoInHob; UINT32 MaxLogicalProcessorNumber; UINT32 ApStackSize; @@ -1852,11 +1906,11 @@ MpInitLibInitialize ( UINTN BackupBufferAddr; UINTN ApIdtBase; - OldCpuMpData = GetCpuMpDataFromGuidedHob (); - if (OldCpuMpData == NULL) { + MpHandOff = GetMpHandOffHob (); + if (MpHandOff == NULL) { MaxLogicalProcessorNumber = PcdGet32 (PcdCpuMaxLogicalProcessorNumber); } else { - MaxLogicalProcessorNumber = OldCpuMpData->CpuCount; + MaxLogicalProcessorNumber = MpHandOff->CpuCount; } ASSERT (MaxLogicalProcessorNumber != 0); @@ -2000,7 +2054,7 @@ MpInitLibInitialize ( // ProgramVirtualWireMode (); - if (OldCpuMpData == NULL) { + if (MpHandOff == NULL) { if (MaxLogicalProcessorNumber > 1) { // // Wakeup all APs and calculate the processor count in system @@ -2012,15 +2066,18 @@ MpInitLibInitialize ( // APs have been wakeup before, just get the CPU Information // from HOB // - OldCpuMpData->NewCpuMpData = CpuMpData; - CpuMpData->CpuCount = OldCpuMpData->CpuCount; - CpuMpData->BspNumber = OldCpuMpData->BspNumber; - CpuMpData->CpuInfoInHob = OldCpuMpData->CpuInfoInHob; - CpuInfoInHob = (CPU_INFO_IN_HOB *)(UINTN)CpuMpData->CpuInfoInHob; + AmdSevUpdateCpuMpData (CpuMpData); + CpuMpData->CpuCount = MpHandOff->CpuCount; + CpuMpData->BspNumber = GetBspNumber (MpHandOff); + CpuInfoInHob = (CPU_INFO_IN_HOB *)(UINTN)CpuMpData->CpuInfoInHob; for (Index = 0; Index < CpuMpData->CpuCount; Index++) { InitializeSpinLock (&CpuMpData->CpuData[Index].ApLock); - CpuMpData->CpuData[Index].CpuHealthy = (CpuInfoInHob[Index].Health == 0) ? TRUE : FALSE; + CpuMpData->CpuData[Index].CpuHealthy = (MpHandOff->Info[Index].Health == 0) ? TRUE : FALSE; CpuMpData->CpuData[Index].ApFunction = 0; + CpuInfoInHob[Index].InitialApicId = MpHandOff->Info[Index].ApicId; + CpuInfoInHob[Index].ApTopOfStack = CpuMpData->Buffer + (Index + 1) * CpuMpData->CpuApStackSize; + CpuInfoInHob[Index].ApicId = MpHandOff->Info[Index].ApicId; + CpuInfoInHob[Index].Health = MpHandOff->Info[Index].Health; } } @@ -2049,7 +2106,7 @@ MpInitLibInitialize ( // Wakeup APs to do some AP initialize sync (Microcode & MTRR) // if (CpuMpData->CpuCount > 1) { - if (OldCpuMpData != NULL) { + if (MpHandOff != NULL) { // // Only needs to use this flag for DXE phase to update the wake up // buffer. Wakeup buffer allocated in PEI phase is no longer valid @@ -2066,7 +2123,7 @@ MpInitLibInitialize ( CpuPause (); } - if (OldCpuMpData != NULL) { + if (MpHandOff != NULL) { CpuMpData->InitFlag = ApInitDone; } diff --git a/UefiCpuPkg/Library/MpInitLib/MpLib.h b/UefiCpuPkg/Library/MpInitLib/MpLib.h index b694c7b40f..a7f36d323b 100644 --- a/UefiCpuPkg/Library/MpInitLib/MpLib.h +++ b/UefiCpuPkg/Library/MpInitLib/MpLib.h @@ -39,8 +39,17 @@ #include #include +#include "MpHandOff.h" #define WAKEUP_AP_SIGNAL SIGNATURE_32 ('S', 'T', 'A', 'P') +// +// To trigger the start-up signal, BSP writes the specified +// StartupSignalValue to the StartupSignalAddress of each processor. +// This address is monitored by the APs, and as soon as they receive +// the value that matches the MP_HAND_OFF_SIGNAL, they will wake up +// and switch the context from PEI to DXE phase. +// +#define MP_HAND_OFF_SIGNAL SIGNATURE_32 ('M', 'P', 'H', 'O') #define CPU_INIT_MP_LIB_HOB_GUID \ { \ @@ -891,4 +900,14 @@ SevSnpCreateAP ( IN INTN ProcessorNumber ); +/** + Get pointer to CPU MP Data structure from GUIDed HOB. + + @param[in] CpuMpData The pointer to CPU MP Data structure. +**/ +VOID +AmdSevUpdateCpuMpData ( + IN CPU_MP_DATA *CpuMpData + ); + #endif diff --git a/UefiCpuPkg/Library/MpInitLib/PeiMpInitLib.inf b/UefiCpuPkg/Library/MpInitLib/PeiMpInitLib.inf index 78eded96bf..83e9028d0f 100644 --- a/UefiCpuPkg/Library/MpInitLib/PeiMpInitLib.inf +++ b/UefiCpuPkg/Library/MpInitLib/PeiMpInitLib.inf @@ -36,7 +36,7 @@ MpLib.c MpLib.h Microcode.c - + MpHandOff.h [Packages] MdePkg/MdePkg.dec UefiCpuPkg/UefiCpuPkg.dec diff --git a/UefiCpuPkg/Library/MpInitLib/PeiMpLib.c b/UefiCpuPkg/Library/MpInitLib/PeiMpLib.c index 013f89b197..f80e00edcf 100644 --- a/UefiCpuPkg/Library/MpInitLib/PeiMpLib.c +++ b/UefiCpuPkg/Library/MpInitLib/PeiMpLib.c @@ -126,7 +126,37 @@ SaveCpuMpData ( IN CPU_MP_DATA *CpuMpData ) { - UINT64 Data64; + UINT64 Data64; + UINTN Index; + CPU_INFO_IN_HOB *CpuInfoInHob; + MP_HAND_OFF *MpHandOff; + UINTN MpHandOffSize; + + // + // When APs are in a state that can be waken up by a store operation to a memory address, + // report the MP_HAND_OFF data for DXE to use. + // + CpuInfoInHob = (CPU_INFO_IN_HOB *)(UINTN)CpuMpData->CpuInfoInHob; + MpHandOffSize = sizeof (MP_HAND_OFF) + sizeof (PROCESSOR_HAND_OFF) * CpuMpData->CpuCount; + MpHandOff = (MP_HAND_OFF *)BuildGuidHob (&mMpHandOffGuid, MpHandOffSize); + ASSERT (MpHandOff != NULL); + ZeroMem (MpHandOff, MpHandOffSize); + MpHandOff->ProcessorIndex = 0; + + MpHandOff->CpuCount = CpuMpData->CpuCount; + if (CpuMpData->ApLoopMode != ApInHltLoop) { + MpHandOff->StartupSignalValue = MP_HAND_OFF_SIGNAL; + MpHandOff->WaitLoopExecutionMode = sizeof (VOID *); + } + + for (Index = 0; Index < MpHandOff->CpuCount; Index++) { + MpHandOff->Info[Index].ApicId = CpuInfoInHob[Index].ApicId; + MpHandOff->Info[Index].Health = CpuInfoInHob[Index].Health; + if (CpuMpData->ApLoopMode != ApInHltLoop) { + MpHandOff->Info[Index].StartupSignalAddress = (UINT64)(UINTN)CpuMpData->CpuData[Index].StartupApSignal; + MpHandOff->Info[Index].StartupProcedureAddress = (UINT64)(UINTN)&CpuMpData->CpuData[Index].ApFunction; + } + } // // Build location of CPU MP DATA buffer in HOB -- 2.36.1.windows.1