X-Git-Url: https://git.proxmox.com/?a=blobdiff_plain;f=UefiCpuPkg%2FLibrary%2FMpInitLib%2FMpLib.c;h=8d1f24370a3636e6e936b5df1a4a42fddc5cdbee;hb=HEAD;hp=44a011ba75dea8362ebecc33205257a0f4098367;hpb=9c703bc0f1d6972ef44d55d9a5243f8558c564e4;p=mirror_edk2.git
diff --git a/UefiCpuPkg/Library/MpInitLib/MpLib.c b/UefiCpuPkg/Library/MpInitLib/MpLib.c
index 44a011ba75..e5dc852ed9 100644
--- a/UefiCpuPkg/Library/MpInitLib/MpLib.c
+++ b/UefiCpuPkg/Library/MpInitLib/MpLib.c
@@ -1,7 +1,7 @@
/** @file
CPU MP Initialize Library common functions.
- Copyright (c) 2016 - 2021, Intel Corporation. All rights reserved.
+ Copyright (c) 2016 - 2022, Intel Corporation. All rights reserved.
Copyright (c) 2020, AMD Inc. All rights reserved.
SPDX-License-Identifier: BSD-2-Clause-Patent
@@ -9,12 +9,35 @@
**/
#include "MpLib.h"
-#include
+#include
#include
#include
EFI_GUID mCpuInitMpLibHobGuid = CPU_INIT_MP_LIB_HOB_GUID;
+/**
+ Save the volatile registers required to be restored following INIT IPI.
+
+ @param[out] VolatileRegisters Returns buffer saved the volatile resisters
+**/
+VOID
+SaveVolatileRegisters (
+ OUT CPU_VOLATILE_REGISTERS *VolatileRegisters
+ );
+
+/**
+ Restore the volatile registers following INIT IPI.
+
+ @param[in] VolatileRegisters Pointer to volatile resisters
+ @param[in] IsRestoreDr TRUE: Restore DRx if supported
+ FALSE: Do not restore DRx
+**/
+VOID
+RestoreVolatileRegisters (
+ IN CPU_VOLATILE_REGISTERS *VolatileRegisters,
+ IN BOOLEAN IsRestoreDr
+ );
+
/**
The function will check if BSP Execute Disable is enabled.
@@ -83,7 +106,12 @@ FutureBSPProc (
CPU_MP_DATA *DataInHob;
DataInHob = (CPU_MP_DATA *)Buffer;
+ //
+ // Save and restore volatile registers when switch BSP
+ //
+ SaveVolatileRegisters (&DataInHob->APInfo.VolatileRegisters);
AsmExchangeRole (&DataInHob->APInfo, &DataInHob->BSPInfo);
+ RestoreVolatileRegisters (&DataInHob->APInfo.VolatileRegisters, FALSE);
}
/**
@@ -295,10 +323,12 @@ GetApLoopMode (
ApLoopMode = ApInHltLoop;
}
- if (ConfidentialComputingGuestHas (CCAttrAmdSevEs)) {
+ if (ConfidentialComputingGuestHas (CCAttrAmdSevEs) &&
+ !ConfidentialComputingGuestHas (CCAttrAmdSevSnp))
+ {
//
- // For SEV-ES, force AP in Hlt-loop mode in order to use the GHCB
- // protocol for starting APs
+ // For SEV-ES (SEV-SNP is also considered SEV-ES), force AP in Hlt-loop
+ // mode in order to use the GHCB protocol for starting APs
//
ApLoopMode = ApInHltLoop;
}
@@ -569,6 +599,7 @@ InitializeApData (
{
CPU_INFO_IN_HOB *CpuInfoInHob;
MSR_IA32_PLATFORM_ID_REGISTER PlatformIdMsr;
+ AP_STACK_DATA *ApStackData;
CpuInfoInHob = (CPU_INFO_IN_HOB *)(UINTN)CpuMpData->CpuInfoInHob;
CpuInfoInHob[ProcessorNumber].InitialApicId = GetInitialApicId ();
@@ -576,6 +607,12 @@ InitializeApData (
CpuInfoInHob[ProcessorNumber].Health = BistData;
CpuInfoInHob[ProcessorNumber].ApTopOfStack = ApTopOfStack;
+ //
+ // AP_STACK_DATA is stored at the top of AP Stack
+ //
+ ApStackData = (AP_STACK_DATA *)((UINTN)ApTopOfStack - sizeof (AP_STACK_DATA));
+ ApStackData->MpData = CpuMpData;
+
CpuMpData->CpuData[ProcessorNumber].Waiting = FALSE;
CpuMpData->CpuData[ProcessorNumber].CpuHealthy = (BistData == 0) ? TRUE : FALSE;
@@ -621,6 +658,7 @@ ApWakeupFunction (
CPU_INFO_IN_HOB *CpuInfoInHob;
UINT64 ApTopOfStack;
UINTN CurrentApicMode;
+ AP_STACK_DATA *ApStackData;
//
// AP finished assembly code and begin to execute C code
@@ -646,7 +684,9 @@ ApWakeupFunction (
// This is first time AP wakeup, get BIST information from AP stack
//
ApTopOfStack = CpuMpData->Buffer + (ProcessorNumber + 1) * CpuMpData->CpuApStackSize;
- BistData = *(UINT32 *)((UINTN)ApTopOfStack - sizeof (UINTN));
+ ApStackData = (AP_STACK_DATA *)((UINTN)ApTopOfStack - sizeof (AP_STACK_DATA));
+ BistData = (UINT32)ApStackData->Bist;
+
//
// CpuMpData->CpuData[0].VolatileRegisters is initialized based on BSP environment,
// to initialize AP in InitConfig path.
@@ -763,7 +803,7 @@ ApWakeupFunction (
// to allow the APs to issue an AP_RESET_HOLD before the BSP possibly
// performs another INIT-SIPI-SIPI sequence.
//
- if (!CpuMpData->SevEsIsEnabled) {
+ if (!CpuMpData->UseSevEsAPMethod) {
InterlockedDecrement ((UINT32 *)&CpuMpData->MpCpuExchangeInfo->NumApsExecuting);
}
}
@@ -777,7 +817,7 @@ ApWakeupFunction (
//
while (TRUE) {
DisableInterrupts ();
- if (CpuMpData->SevEsIsEnabled) {
+ if (CpuMpData->UseSevEsAPMethod) {
SevEsPlaceApHlt (CpuMpData);
} else {
CpuSleep ();
@@ -846,6 +886,30 @@ WaitApWakeup (
}
}
+/**
+ Calculate the size of the reset vector.
+
+ @param[in] AddressMap The pointer to Address Map structure.
+ @param[out] SizeBelow1Mb Return the size of below 1MB memory for AP reset area.
+ @param[out] SizeAbove1Mb Return the size of abvoe 1MB memory for AP reset area.
+**/
+STATIC
+VOID
+GetApResetVectorSize (
+ IN MP_ASSEMBLY_ADDRESS_MAP *AddressMap,
+ OUT UINTN *SizeBelow1Mb OPTIONAL,
+ OUT UINTN *SizeAbove1Mb OPTIONAL
+ )
+{
+ if (SizeBelow1Mb != NULL) {
+ *SizeBelow1Mb = AddressMap->ModeTransitionOffset + sizeof (MP_CPU_EXCHANGE_INFO);
+ }
+
+ if (SizeAbove1Mb != NULL) {
+ *SizeAbove1Mb = AddressMap->RendezvousFunnelSize - AddressMap->ModeTransitionOffset;
+ }
+}
+
/**
This function will fill the exchange info structure.
@@ -900,6 +964,13 @@ FillExchangeInfoData (
ExchangeInfo->SevSnpIsEnabled = CpuMpData->SevSnpIsEnabled;
ExchangeInfo->GhcbBase = (UINTN)CpuMpData->GhcbBase;
+ //
+ // Populate SEV-ES specific exchange data.
+ //
+ if (ExchangeInfo->SevSnpIsEnabled) {
+ FillExchangeInfoDataSevEs (ExchangeInfo);
+ }
+
//
// Get the BSP's data of GDT and IDT
//
@@ -922,26 +993,7 @@ FillExchangeInfoData (
Size -= sizeof (IA32_SEGMENT_DESCRIPTOR);
}
- //
- // Copy all 32-bit code and 64-bit code into memory with type of
- // EfiBootServicesCode to avoid page fault if NX memory protection is enabled.
- //
- if (CpuMpData->WakeupBufferHigh != 0) {
- Size = CpuMpData->AddressMap.RendezvousFunnelSize +
- CpuMpData->AddressMap.SwitchToRealSize -
- CpuMpData->AddressMap.ModeTransitionOffset;
- CopyMem (
- (VOID *)CpuMpData->WakeupBufferHigh,
- CpuMpData->AddressMap.RendezvousFunnelAddress +
- CpuMpData->AddressMap.ModeTransitionOffset,
- Size
- );
-
- ExchangeInfo->ModeTransitionMemory = (UINT32)CpuMpData->WakeupBufferHigh;
- } else {
- ExchangeInfo->ModeTransitionMemory = (UINT32)
- (ExchangeInfo->BufferStart + CpuMpData->AddressMap.ModeTransitionOffset);
- }
+ ExchangeInfo->ModeTransitionMemory = (UINT32)CpuMpData->WakeupBufferHigh;
ExchangeInfo->ModeHighMemory = ExchangeInfo->ModeTransitionMemory +
(UINT32)ExchangeInfo->ModeOffset -
@@ -982,8 +1034,7 @@ BackupAndPrepareWakeupBuffer (
CopyMem (
(VOID *)CpuMpData->WakeupBuffer,
(VOID *)CpuMpData->AddressMap.RendezvousFunnelAddress,
- CpuMpData->AddressMap.RendezvousFunnelSize +
- CpuMpData->AddressMap.SwitchToRealSize
+ CpuMpData->BackupBufferSize - sizeof (MP_CPU_EXCHANGE_INFO)
);
}
@@ -1004,59 +1055,39 @@ RestoreWakeupBuffer (
);
}
-/**
- Calculate the size of the reset vector.
-
- @param[in] AddressMap The pointer to Address Map structure.
-
- @return Total amount of memory required for the AP reset area
-**/
-STATIC
-UINTN
-GetApResetVectorSize (
- IN MP_ASSEMBLY_ADDRESS_MAP *AddressMap
- )
-{
- UINTN Size;
-
- Size = AddressMap->RendezvousFunnelSize +
- AddressMap->SwitchToRealSize +
- sizeof (MP_CPU_EXCHANGE_INFO);
-
- return Size;
-}
-
/**
Allocate reset vector buffer.
@param[in, out] CpuMpData The pointer to CPU MP Data structure.
**/
VOID
-AllocateResetVector (
+AllocateResetVectorBelow1Mb (
IN OUT CPU_MP_DATA *CpuMpData
)
{
- UINTN ApResetVectorSize;
UINTN ApResetStackSize;
if (CpuMpData->WakeupBuffer == (UINTN)-1) {
- ApResetVectorSize = GetApResetVectorSize (&CpuMpData->AddressMap);
-
- CpuMpData->WakeupBuffer = GetWakeupBuffer (ApResetVectorSize);
+ CpuMpData->WakeupBuffer = GetWakeupBuffer (CpuMpData->BackupBufferSize);
CpuMpData->MpCpuExchangeInfo = (MP_CPU_EXCHANGE_INFO *)(UINTN)
- (CpuMpData->WakeupBuffer +
- CpuMpData->AddressMap.RendezvousFunnelSize +
- CpuMpData->AddressMap.SwitchToRealSize);
- CpuMpData->WakeupBufferHigh = GetModeTransitionBuffer (
- CpuMpData->AddressMap.RendezvousFunnelSize +
- CpuMpData->AddressMap.SwitchToRealSize -
- CpuMpData->AddressMap.ModeTransitionOffset
- );
+ (CpuMpData->WakeupBuffer + CpuMpData->BackupBufferSize - sizeof (MP_CPU_EXCHANGE_INFO));
+ DEBUG ((
+ DEBUG_INFO,
+ "AP Vector: 16-bit = %p/%x, ExchangeInfo = %p/%x\n",
+ CpuMpData->WakeupBuffer,
+ CpuMpData->BackupBufferSize - sizeof (MP_CPU_EXCHANGE_INFO),
+ CpuMpData->MpCpuExchangeInfo,
+ sizeof (MP_CPU_EXCHANGE_INFO)
+ ));
//
// The AP reset stack is only used by SEV-ES guests. Do not allocate it
- // if SEV-ES is not enabled.
+ // if SEV-ES is not enabled. An SEV-SNP guest is also considered
+ // an SEV-ES guest, but uses a different method of AP startup, eliminating
+ // the need for the allocation.
//
- if (ConfidentialComputingGuestHas (CCAttrAmdSevEs)) {
+ if (ConfidentialComputingGuestHas (CCAttrAmdSevEs) &&
+ !ConfidentialComputingGuestHas (CCAttrAmdSevSnp))
+ {
//
// Stack location is based on ProcessorNumber, so use the total number
// of processors for calculating the total stack area.
@@ -1107,7 +1138,7 @@ FreeResetVector (
// perform the restore as this will overwrite memory which has data
// needed by SEV-ES.
//
- if (!CpuMpData->SevEsIsEnabled) {
+ if (!CpuMpData->UseSevEsAPMethod) {
RestoreWakeupBuffer (CpuMpData);
}
}
@@ -1146,7 +1177,7 @@ WakeUpAP (
(CpuMpData->InitFlag != ApInitDone))
{
ResetVectorRequired = TRUE;
- AllocateResetVector (CpuMpData);
+ AllocateResetVectorBelow1Mb (CpuMpData);
AllocateSevEsAPMemory (CpuMpData);
FillExchangeInfoData (CpuMpData);
SaveLocalApicTimerSetting (CpuMpData);
@@ -1186,7 +1217,7 @@ WakeUpAP (
if (ResetVectorRequired) {
//
- // For SEV-ES, the initial AP boot address will be defined by
+ // For SEV-ES and SEV-SNP, the initial AP boot address will be defined by
// PcdSevEsWorkAreaBase. The Segment/Rip must be the jump address
// from the original INIT-SIPI-SIPI.
//
@@ -1196,8 +1227,14 @@ WakeUpAP (
//
// Wakeup all APs
+ // Must use the INIT-SIPI-SIPI method for initial configuration in
+ // order to obtain the APIC ID.
//
- SendInitSipiSipiAllExcludingSelf ((UINT32)ExchangeInfo->BufferStart);
+ if (CpuMpData->SevSnpIsEnabled && (CpuMpData->InitFlag != ApInitConfig)) {
+ SevSnpCreateAP (CpuMpData, -1);
+ } else {
+ SendInitSipiSipiAllExcludingSelf ((UINT32)ExchangeInfo->BufferStart);
+ }
}
if (CpuMpData->InitFlag == ApInitConfig) {
@@ -1288,7 +1325,7 @@ WakeUpAP (
CpuInfoInHob = (CPU_INFO_IN_HOB *)(UINTN)CpuMpData->CpuInfoInHob;
//
- // For SEV-ES, the initial AP boot address will be defined by
+ // For SEV-ES and SEV-SNP, the initial AP boot address will be defined by
// PcdSevEsWorkAreaBase. The Segment/Rip must be the jump address
// from the original INIT-SIPI-SIPI.
//
@@ -1296,10 +1333,14 @@ WakeUpAP (
SetSevEsJumpTable (ExchangeInfo->BufferStart);
}
- SendInitSipiSipi (
- CpuInfoInHob[ProcessorNumber].ApicId,
- (UINT32)ExchangeInfo->BufferStart
- );
+ if (CpuMpData->SevSnpIsEnabled && (CpuMpData->InitFlag != ApInitConfig)) {
+ SevSnpCreateAP (CpuMpData, (INTN)ProcessorNumber);
+ } else {
+ SendInitSipiSipi (
+ CpuInfoInHob[ProcessorNumber].ApicId,
+ (UINT32)ExchangeInfo->BufferStart
+ );
+ }
}
//
@@ -1776,7 +1817,8 @@ MpInitLibInitialize (
UINT8 ApLoopMode;
UINT8 *MonitorBuffer;
UINTN Index;
- UINTN ApResetVectorSize;
+ UINTN ApResetVectorSizeBelow1Mb;
+ UINTN ApResetVectorSizeAbove1Mb;
UINTN BackupBufferAddr;
UINTN ApIdtBase;
@@ -1790,18 +1832,26 @@ MpInitLibInitialize (
ASSERT (MaxLogicalProcessorNumber != 0);
AsmGetAddressMap (&AddressMap);
- ApResetVectorSize = GetApResetVectorSize (&AddressMap);
- ApStackSize = PcdGet32 (PcdCpuApStackSize);
- ApLoopMode = GetApLoopMode (&MonitorFilterSize);
+ GetApResetVectorSize (&AddressMap, &ApResetVectorSizeBelow1Mb, &ApResetVectorSizeAbove1Mb);
+ ApStackSize = PcdGet32 (PcdCpuApStackSize);
+ //
+ // ApStackSize must be power of 2
+ //
+ ASSERT ((ApStackSize & (ApStackSize - 1)) == 0);
+ ApLoopMode = GetApLoopMode (&MonitorFilterSize);
//
// Save BSP's Control registers for APs.
//
SaveVolatileRegisters (&VolatileRegisters);
- BufferSize = ApStackSize * MaxLogicalProcessorNumber;
+ BufferSize = ApStackSize * MaxLogicalProcessorNumber;
+ //
+ // Allocate extra ApStackSize to let AP stack align on ApStackSize bounday
+ //
+ BufferSize += ApStackSize;
BufferSize += MonitorFilterSize * MaxLogicalProcessorNumber;
- BufferSize += ApResetVectorSize;
+ BufferSize += ApResetVectorSizeBelow1Mb;
BufferSize = ALIGN_VALUE (BufferSize, 8);
BufferSize += VolatileRegisters.Idtr.Limit + 1;
BufferSize += sizeof (CPU_MP_DATA);
@@ -1809,13 +1859,13 @@ MpInitLibInitialize (
MpBuffer = AllocatePages (EFI_SIZE_TO_PAGES (BufferSize));
ASSERT (MpBuffer != NULL);
ZeroMem (MpBuffer, BufferSize);
- Buffer = (UINTN)MpBuffer;
+ Buffer = ALIGN_VALUE ((UINTN)MpBuffer, ApStackSize);
//
- // The layout of the Buffer is as below:
+ // The layout of the Buffer is as below (lower address on top):
//
- // +--------------------+ <-- Buffer
- // AP Stacks (N)
+ // +--------------------+ <-- Buffer (Pointer of CpuMpData is stored in the top of each AP's stack.)
+ // AP Stacks (N) (StackTop = (RSP + ApStackSize) & ~ApStackSize))
// +--------------------+ <-- MonitorBuffer
// AP Monitor Filters (N)
// +--------------------+ <-- BackupBufferAddr (CpuMpData->BackupBuffer)
@@ -1823,7 +1873,7 @@ MpInitLibInitialize (
// +--------------------+
// Padding
// +--------------------+ <-- ApIdtBase (8-byte boundary)
- // AP IDT All APs share one separate IDT. So AP can get address of CPU_MP_DATA from IDT Base.
+ // AP IDT All APs share one separate IDT.
// +--------------------+ <-- CpuMpData
// CPU_MP_DATA
// +--------------------+ <-- CpuMpData->CpuData
@@ -1834,12 +1884,12 @@ MpInitLibInitialize (
//
MonitorBuffer = (UINT8 *)(Buffer + ApStackSize * MaxLogicalProcessorNumber);
BackupBufferAddr = (UINTN)MonitorBuffer + MonitorFilterSize * MaxLogicalProcessorNumber;
- ApIdtBase = ALIGN_VALUE (BackupBufferAddr + ApResetVectorSize, 8);
+ ApIdtBase = ALIGN_VALUE (BackupBufferAddr + ApResetVectorSizeBelow1Mb, 8);
CpuMpData = (CPU_MP_DATA *)(ApIdtBase + VolatileRegisters.Idtr.Limit + 1);
CpuMpData->Buffer = Buffer;
CpuMpData->CpuApStackSize = ApStackSize;
CpuMpData->BackupBuffer = BackupBufferAddr;
- CpuMpData->BackupBufferSize = ApResetVectorSize;
+ CpuMpData->BackupBufferSize = ApResetVectorSizeBelow1Mb;
CpuMpData->WakeupBuffer = (UINTN)-1;
CpuMpData->CpuCount = 1;
CpuMpData->BspNumber = 0;
@@ -1848,17 +1898,23 @@ MpInitLibInitialize (
CpuMpData->CpuData = (CPU_AP_DATA *)(CpuMpData + 1);
CpuMpData->CpuInfoInHob = (UINT64)(UINTN)(CpuMpData->CpuData + MaxLogicalProcessorNumber);
InitializeSpinLock (&CpuMpData->MpLock);
- CpuMpData->SevEsIsEnabled = ConfidentialComputingGuestHas (CCAttrAmdSevEs);
- CpuMpData->SevSnpIsEnabled = ConfidentialComputingGuestHas (CCAttrAmdSevSnp);
- CpuMpData->SevEsAPBuffer = (UINTN)-1;
- CpuMpData->GhcbBase = PcdGet64 (PcdGhcbBase);
+ CpuMpData->SevEsIsEnabled = ConfidentialComputingGuestHas (CCAttrAmdSevEs);
+ CpuMpData->SevSnpIsEnabled = ConfidentialComputingGuestHas (CCAttrAmdSevSnp);
+ CpuMpData->SevEsAPBuffer = (UINTN)-1;
+ CpuMpData->GhcbBase = PcdGet64 (PcdGhcbBase);
+ CpuMpData->UseSevEsAPMethod = CpuMpData->SevEsIsEnabled && !CpuMpData->SevSnpIsEnabled;
+
+ if (CpuMpData->SevSnpIsEnabled) {
+ ASSERT ((PcdGet64 (PcdGhcbHypervisorFeatures) & GHCB_HV_FEATURES_SNP_AP_CREATE) == GHCB_HV_FEATURES_SNP_AP_CREATE);
+ }
//
// Make sure no memory usage outside of the allocated buffer.
+ // (ApStackSize - (Buffer - (UINTN)MpBuffer)) is the redundant caused by alignment
//
ASSERT (
(CpuMpData->CpuInfoInHob + sizeof (CPU_INFO_IN_HOB) * MaxLogicalProcessorNumber) ==
- Buffer + BufferSize
+ (UINTN)MpBuffer + BufferSize - (ApStackSize - Buffer + (UINTN)MpBuffer)
);
//
@@ -1896,6 +1952,19 @@ MpInitLibInitialize (
(UINT32 *)(MonitorBuffer + MonitorFilterSize * Index);
}
+ //
+ // Copy all 32-bit code and 64-bit code into memory with type of
+ // EfiBootServicesCode to avoid page fault if NX memory protection is enabled.
+ //
+ CpuMpData->WakeupBufferHigh = AllocateCodeBuffer (ApResetVectorSizeAbove1Mb);
+ CopyMem (
+ (VOID *)CpuMpData->WakeupBufferHigh,
+ CpuMpData->AddressMap.RendezvousFunnelAddress +
+ CpuMpData->AddressMap.ModeTransitionOffset,
+ ApResetVectorSizeAbove1Mb
+ );
+ DEBUG ((DEBUG_INFO, "AP Vector: non-16-bit = %p/%x\n", CpuMpData->WakeupBufferHigh, ApResetVectorSizeAbove1Mb));
+
//
// Enable the local APIC for Virtual Wire Mode.
//
@@ -2211,7 +2280,12 @@ SwitchBSPWorker (
//
WakeUpAP (CpuMpData, FALSE, ProcessorNumber, FutureBSPProc, CpuMpData, TRUE);
+ //
+ // Save and restore volatile registers when switch BSP
+ //
+ SaveVolatileRegisters (&CpuMpData->BSPInfo.VolatileRegisters);
AsmExchangeRole (&CpuMpData->BSPInfo, &CpuMpData->APInfo);
+ RestoreVolatileRegisters (&CpuMpData->BSPInfo.VolatileRegisters, FALSE);
//
// Set the BSP bit of MSR_IA32_APIC_BASE on new BSP