[edk2-devel] [PATCH v11 32/32] UefiCpuPkg/MpInitLib: Use SEV-SNP AP Creation NAE event to launch APs
Brijesh Singh via groups.io
brijesh.singh=amd.com at groups.io
Sun Oct 24 23:43:04 UTC 2021
Hi Ray and Rahul,
Any comment on this patch ? If you are okay with the approach then can I
get Ack or R-b ?
-Brijesh
On 10/22/21 11:13 PM, Brijesh Singh via groups.io wrote:
> From: Tom Lendacky <thomas.lendacky at amd.com>
>
> BZ: https://bugzilla.tianocore.org/show_bug.cgi?id=3275
>
> Use the SEV-SNP AP Creation NAE event to create and launch APs under
> SEV-SNP. This capability will be advertised in the SEV Hypervisor
> Feature Support PCD (PcdSevEsHypervisorFeatures).
>
> Cc: Michael Roth <michael.roth at amd.com>
> Cc: Eric Dong <eric.dong at intel.com>
> Cc: Ray Ni <ray.ni at intel.com>
> Cc: Rahul Kumar <rahul1.kumar at intel.com>
> Cc: James Bottomley <jejb at linux.ibm.com>
> Cc: Min Xu <min.m.xu at intel.com>
> Cc: Jiewen Yao <jiewen.yao at intel.com>
> Cc: Tom Lendacky <thomas.lendacky at amd.com>
> Cc: Jordan Justen <jordan.l.justen at intel.com>
> Cc: Ard Biesheuvel <ardb+tianocore at kernel.org>
> Cc: Erdem Aktas <erdemaktas at google.com>
> Cc: Gerd Hoffmann <kraxel at redhat.com>
> Acked-by: Gerd Hoffmann <kraxel at redhat.com>
> Signed-off-by: Tom Lendacky <thomas.lendacky at amd.com>
> Signed-off-by: Brijesh Singh <brijesh.singh at amd.com>
> ---
> UefiCpuPkg/Library/MpInitLib/DxeMpInitLib.inf | 3 +
> UefiCpuPkg/Library/MpInitLib/PeiMpInitLib.inf | 3 +
> UefiCpuPkg/Library/MpInitLib/MpLib.h | 44 +++
> UefiCpuPkg/Library/MpInitLib/DxeMpLib.c | 12 +-
> UefiCpuPkg/Library/MpInitLib/Ia32/AmdSev.c | 70 +++++
> UefiCpuPkg/Library/MpInitLib/MpLib.c | 51 ++--
> UefiCpuPkg/Library/MpInitLib/X64/AmdSev.c | 261 ++++++++++++++++++
> 7 files changed, 425 insertions(+), 19 deletions(-)
> create mode 100644 UefiCpuPkg/Library/MpInitLib/Ia32/AmdSev.c
> create mode 100644 UefiCpuPkg/Library/MpInitLib/X64/AmdSev.c
>
> diff --git a/UefiCpuPkg/Library/MpInitLib/DxeMpInitLib.inf b/UefiCpuPkg/Library/MpInitLib/DxeMpInitLib.inf
> index de705bc54bb4..e1cd0b350008 100644
> --- a/UefiCpuPkg/Library/MpInitLib/DxeMpInitLib.inf
> +++ b/UefiCpuPkg/Library/MpInitLib/DxeMpInitLib.inf
> @@ -22,9 +22,11 @@ [Defines]
> #
>
> [Sources.IA32]
> + Ia32/AmdSev.c
> Ia32/MpFuncs.nasm
>
> [Sources.X64]
> + X64/AmdSev.c
> X64/MpFuncs.nasm
>
> [Sources.common]
> @@ -73,6 +75,7 @@ [Pcd]
> gUefiCpuPkgTokenSpaceGuid.PcdCpuApLoopMode ## CONSUMES
> gUefiCpuPkgTokenSpaceGuid.PcdCpuApTargetCstate ## SOMETIMES_CONSUMES
> gUefiCpuPkgTokenSpaceGuid.PcdCpuApStatusCheckIntervalInMicroSeconds ## CONSUMES
> + gUefiCpuPkgTokenSpaceGuid.PcdGhcbHypervisorFeatures ## CONSUMES
> gUefiCpuPkgTokenSpaceGuid.PcdSevEsWorkAreaBase ## SOMETIMES_CONSUMES
> gEfiMdeModulePkgTokenSpaceGuid.PcdCpuStackGuard ## CONSUMES
> gEfiMdeModulePkgTokenSpaceGuid.PcdGhcbBase ## CONSUMES
> diff --git a/UefiCpuPkg/Library/MpInitLib/PeiMpInitLib.inf b/UefiCpuPkg/Library/MpInitLib/PeiMpInitLib.inf
> index b7e15ee023f0..5facf4db9499 100644
> --- a/UefiCpuPkg/Library/MpInitLib/PeiMpInitLib.inf
> +++ b/UefiCpuPkg/Library/MpInitLib/PeiMpInitLib.inf
> @@ -22,9 +22,11 @@ [Defines]
> #
>
> [Sources.IA32]
> + Ia32/AmdSev.c
> Ia32/MpFuncs.nasm
>
> [Sources.X64]
> + X64/AmdSev.c
> X64/MpFuncs.nasm
>
> [Sources.common]
> @@ -64,6 +66,7 @@ [Pcd]
> gUefiCpuPkgTokenSpaceGuid.PcdCpuApLoopMode ## CONSUMES
> gUefiCpuPkgTokenSpaceGuid.PcdCpuApTargetCstate ## SOMETIMES_CONSUMES
> gUefiCpuPkgTokenSpaceGuid.PcdSevEsWorkAreaBase ## SOMETIMES_CONSUMES
> + gUefiCpuPkgTokenSpaceGuid.PcdGhcbHypervisorFeatures ## CONSUMES
> gEfiMdeModulePkgTokenSpaceGuid.PcdGhcbBase ## CONSUMES
> gEfiMdePkgTokenSpaceGuid.PcdConfidentialComputingGuestAttr ## CONSUMES
>
> diff --git a/UefiCpuPkg/Library/MpInitLib/MpLib.h b/UefiCpuPkg/Library/MpInitLib/MpLib.h
> index c52b6157429b..48f6e933bb36 100644
> --- a/UefiCpuPkg/Library/MpInitLib/MpLib.h
> +++ b/UefiCpuPkg/Library/MpInitLib/MpLib.h
> @@ -15,6 +15,7 @@
>
> #include <Register/Intel/Cpuid.h>
> #include <Register/Amd/Cpuid.h>
> +#include <Register/Amd/Ghcb.h>
> #include <Register/Intel/Msr.h>
> #include <Register/Intel/LocalApic.h>
> #include <Register/Intel/Microcode.h>
> @@ -150,6 +151,7 @@ typedef struct {
> UINT8 PlatformId;
> UINT64 MicrocodeEntryAddr;
> UINT32 MicrocodeRevision;
> + SEV_ES_SAVE_AREA *SevEsSaveArea;
> } CPU_AP_DATA;
>
> //
> @@ -294,6 +296,7 @@ struct _CPU_MP_DATA {
>
> BOOLEAN SevEsIsEnabled;
> BOOLEAN SevSnpIsEnabled;
> + BOOLEAN UseSevEsAPMethod;
> UINTN SevEsAPBuffer;
> UINTN SevEsAPResetStackStart;
> CPU_MP_DATA *NewCpuMpData;
> @@ -790,5 +793,46 @@ ConfidentialComputingGuestHas (
> CONFIDENTIAL_COMPUTING_GUEST_ATTR Attr
> );
>
> +/**
> + Issue RMPADJUST to adjust the VMSA attribute of an SEV-SNP page.
> +
> + @param[in] PageAddress
> + @param[in] VmsaPage
> +
> + @return RMPADJUST return value
> +**/
> +UINT32
> +SevSnpRmpAdjust (
> + IN EFI_PHYSICAL_ADDRESS PageAddress,
> + IN BOOLEAN VmsaPage
> + );
> +
> +/**
> + Create an SEV-SNP AP save area (VMSA) for use in running the vCPU.
> +
> + @param[in] CpuMpData Pointer to CPU MP Data
> + @param[in] CpuData Pointer to CPU AP Data
> + @param[in] ApicId APIC ID of the vCPU
> +**/
> +VOID
> +SevSnpCreateSaveArea (
> + IN CPU_MP_DATA *CpuMpData,
> + IN CPU_AP_DATA *CpuData,
> + UINT32 ApicId
> + );
> +
> +/**
> + Create SEV-SNP APs.
> +
> + @param[in] CpuMpData Pointer to CPU MP Data
> + @param[in] ProcessorNumber The handle number of specified processor
> + (-1 for all APs)
> +**/
> +VOID
> +SevSnpCreateAP (
> + IN CPU_MP_DATA *CpuMpData,
> + IN INTN ProcessorNumber
> + );
> +
> #endif
>
> diff --git a/UefiCpuPkg/Library/MpInitLib/DxeMpLib.c b/UefiCpuPkg/Library/MpInitLib/DxeMpLib.c
> index 657a73dca05e..7a3ef0015a31 100644
> --- a/UefiCpuPkg/Library/MpInitLib/DxeMpLib.c
> +++ b/UefiCpuPkg/Library/MpInitLib/DxeMpLib.c
> @@ -93,7 +93,13 @@ GetWakeupBuffer (
> EFI_PHYSICAL_ADDRESS StartAddress;
> EFI_MEMORY_TYPE MemoryType;
>
> - if (ConfidentialComputingGuestHas (CCAttrAmdSevEs)) {
> + if (ConfidentialComputingGuestHas (CCAttrAmdSevEs) &&
> + !ConfidentialComputingGuestHas (CCAttrAmdSevSnp)) {
> + //
> + // An SEV-ES-only guest requires the memory to be reserved. SEV-SNP, which
> + // is also considered SEV-ES, uses a different AP startup method, though,
> + // which does not have the same requirement.
> + //
> MemoryType = EfiReservedMemoryType;
> } else {
> MemoryType = EfiBootServicesData;
> @@ -373,7 +379,7 @@ RelocateApLoop (
> MpInitLibWhoAmI (&ProcessorNumber);
> CpuMpData = GetCpuMpData ();
> MwaitSupport = IsMwaitSupport ();
> - if (CpuMpData->SevEsIsEnabled) {
> + if (CpuMpData->UseSevEsAPMethod) {
> StackStart = CpuMpData->SevEsAPResetStackStart;
> } else {
> StackStart = mReservedTopOfApStack;
> @@ -422,7 +428,7 @@ MpInitChangeApLoopCallback (
> CpuPause ();
> }
>
> - if (CpuMpData->SevEsIsEnabled && (CpuMpData->WakeupBuffer != (UINTN) -1)) {
> + if (CpuMpData->UseSevEsAPMethod && (CpuMpData->WakeupBuffer != (UINTN) -1)) {
> //
> // There are APs present. Re-use reserved memory area below 1MB from
> // WakeupBuffer as the area to be used for transitioning to 16-bit mode
> diff --git a/UefiCpuPkg/Library/MpInitLib/Ia32/AmdSev.c b/UefiCpuPkg/Library/MpInitLib/Ia32/AmdSev.c
> new file mode 100644
> index 000000000000..a4702e298d98
> --- /dev/null
> +++ b/UefiCpuPkg/Library/MpInitLib/Ia32/AmdSev.c
> @@ -0,0 +1,70 @@
> +/** @file
> +
> + AMD SEV helper function.
> +
> + Copyright (c) 2021, AMD Incorporated. All rights reserved.<BR>
> +
> + SPDX-License-Identifier: BSD-2-Clause-Patent
> +
> +**/
> +
> +#include "MpLib.h"
> +
> +/**
> + Create an SEV-SNP AP save area (VMSA) for use in running the vCPU.
> +
> + @param[in] CpuMpData Pointer to CPU MP Data
> + @param[in] CpuData Pointer to CPU AP Data
> + @param[in] ApicId APIC ID of the vCPU
> +**/
> +VOID
> +SevSnpCreateSaveArea (
> + IN CPU_MP_DATA *CpuMpData,
> + IN CPU_AP_DATA *CpuData,
> + UINT32 ApicId
> + )
> +{
> + //
> + // SEV-SNP is not support on 32-bit build.
> + //
> + ASSERT (FALSE);
> +}
> +
> +/**
> + Create SEV-SNP APs.
> +
> + @param[in] CpuMpData Pointer to CPU MP Data
> + @param[in] ProcessorNumber The handle number of specified processor
> + (-1 for all APs)
> +**/
> +VOID
> +SevSnpCreateAP (
> + IN CPU_MP_DATA *CpuMpData,
> + IN INTN ProcessorNumber
> + )
> +{
> + //
> + // SEV-SNP is not support on 32-bit build.
> + //
> + ASSERT (FALSE);
> +}
> +
> +/**
> + Issue RMPADJUST to adjust the VMSA attribute of an SEV-SNP page.
> +
> + @param[in] PageAddress
> + @param[in] VmsaPage
> +
> + @return RMPADJUST return value
> +**/
> +UINT32
> +SevSnpRmpAdjust (
> + IN EFI_PHYSICAL_ADDRESS PageAddress,
> + IN BOOLEAN VmsaPage
> + )
> +{
> + //
> + // RMPADJUST is not supported in 32-bit mode
> + //
> + return RETURN_UNSUPPORTED;
> +}
> diff --git a/UefiCpuPkg/Library/MpInitLib/MpLib.c b/UefiCpuPkg/Library/MpInitLib/MpLib.c
> index d8372ffa9d5a..d134dc1326e8 100644
> --- a/UefiCpuPkg/Library/MpInitLib/MpLib.c
> +++ b/UefiCpuPkg/Library/MpInitLib/MpLib.c
> @@ -295,10 +295,11 @@ 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;
> }
> @@ -758,7 +759,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);
> }
> }
> @@ -772,7 +773,7 @@ ApWakeupFunction (
> //
> while (TRUE) {
> DisableInterrupts ();
> - if (CpuMpData->SevEsIsEnabled) {
> + if (CpuMpData->UseSevEsAPMethod) {
> SevEsPlaceApHlt (CpuMpData);
> } else {
> CpuSleep ();
> @@ -1056,9 +1057,12 @@ AllocateResetVector (
> );
> //
> // 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.
> @@ -1108,7 +1112,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);
> }
> }
> @@ -1144,7 +1148,7 @@ WakeUpAP (
> ResetVectorRequired = FALSE;
>
> if (CpuMpData->WakeUpByInitSipiSipi ||
> - CpuMpData->InitFlag != ApInitDone) {
> + CpuMpData->InitFlag != ApInitDone) {
> ResetVectorRequired = TRUE;
> AllocateResetVector (CpuMpData);
> AllocateSevEsAPMemory (CpuMpData);
> @@ -1185,7 +1189,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.
> //
> @@ -1195,8 +1199,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) {
> if (PcdGet32 (PcdCpuBootLogicalProcessorNumber) > 0) {
> @@ -1286,7 +1296,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.
> //
> @@ -1294,10 +1304,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
> + );
> + }
> }
> //
> // Wait specified AP waken up
> @@ -1832,6 +1846,11 @@ MpInitLibInitialize (
> 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.
> diff --git a/UefiCpuPkg/Library/MpInitLib/X64/AmdSev.c b/UefiCpuPkg/Library/MpInitLib/X64/AmdSev.c
> new file mode 100644
> index 000000000000..303271abdaad
> --- /dev/null
> +++ b/UefiCpuPkg/Library/MpInitLib/X64/AmdSev.c
> @@ -0,0 +1,261 @@
> +/** @file
> +
> + AMD SEV helper function.
> +
> + Copyright (c) 2021, AMD Incorporated. All rights reserved.<BR>
> +
> + SPDX-License-Identifier: BSD-2-Clause-Patent
> +
> +**/
> +
> +#include "MpLib.h"
> +#include <Library/VmgExitLib.h>
> +#include <Register/Amd/Fam17Msr.h>
> +#include <Register/Amd/Ghcb.h>
> +
> +/**
> + Create an SEV-SNP AP save area (VMSA) for use in running the vCPU.
> +
> + @param[in] CpuMpData Pointer to CPU MP Data
> + @param[in] CpuData Pointer to CPU AP Data
> + @param[in] ApicId APIC ID of the vCPU
> +**/
> +VOID
> +SevSnpCreateSaveArea (
> + IN CPU_MP_DATA *CpuMpData,
> + IN CPU_AP_DATA *CpuData,
> + UINT32 ApicId
> + )
> +{
> + SEV_ES_SAVE_AREA *SaveArea;
> + IA32_CR0 ApCr0;
> + IA32_CR0 ResetCr0;
> + IA32_CR4 ApCr4;
> + IA32_CR4 ResetCr4;
> + UINTN StartIp;
> + UINT8 SipiVector;
> + UINT32 RmpAdjustStatus;
> + UINT64 VmgExitStatus;
> + MSR_SEV_ES_GHCB_REGISTER Msr;
> + GHCB *Ghcb;
> + BOOLEAN InterruptState;
> + UINT64 ExitInfo1;
> + UINT64 ExitInfo2;
> +
> + //
> + // Allocate a single page for the SEV-ES Save Area and initialize it.
> + //
> + SaveArea = AllocateReservedPages (1);
> + if (!SaveArea) {
> + return;
> + }
> + ZeroMem (SaveArea, EFI_PAGE_SIZE);
> +
> + //
> + // Propogate the CR0.NW and CR0.CD setting to the AP
> + //
> + ResetCr0.UintN = 0x00000010;
> + ApCr0.UintN = CpuData->VolatileRegisters.Cr0;
> + if (ApCr0.Bits.NW) {
> + ResetCr0.Bits.NW = 1;
> + }
> + if (ApCr0.Bits.CD) {
> + ResetCr0.Bits.CD = 1;
> + }
> +
> + //
> + // Propagate the CR4.MCE setting to the AP
> + //
> + ResetCr4.UintN = 0;
> + ApCr4.UintN = CpuData->VolatileRegisters.Cr4;
> + if (ApCr4.Bits.MCE) {
> + ResetCr4.Bits.MCE = 1;
> + }
> +
> + //
> + // Convert the start IP into a SIPI Vector
> + //
> + StartIp = CpuMpData->MpCpuExchangeInfo->BufferStart;
> + SipiVector = (UINT8) (StartIp >> 12);
> +
> + //
> + // Set the CS:RIP value based on the start IP
> + //
> + SaveArea->Cs.Base = SipiVector << 12;
> + SaveArea->Cs.Selector = SipiVector << 8;
> + SaveArea->Cs.Limit = 0xFFFF;
> + SaveArea->Cs.Attributes.Bits.Present = 1;
> + SaveArea->Cs.Attributes.Bits.Sbit = 1;
> + SaveArea->Cs.Attributes.Bits.Type = SEV_ES_RESET_CODE_SEGMENT_TYPE;
> + SaveArea->Rip = StartIp & 0xFFF;
> +
> + //
> + // Set the remaining values as defined in APM for INIT
> + //
> + SaveArea->Ds.Limit = 0xFFFF;
> + SaveArea->Ds.Attributes.Bits.Present = 1;
> + SaveArea->Ds.Attributes.Bits.Sbit = 1;
> + SaveArea->Ds.Attributes.Bits.Type = SEV_ES_RESET_DATA_SEGMENT_TYPE;
> + SaveArea->Es = SaveArea->Ds;
> + SaveArea->Fs = SaveArea->Ds;
> + SaveArea->Gs = SaveArea->Ds;
> + SaveArea->Ss = SaveArea->Ds;
> +
> + SaveArea->Gdtr.Limit = 0xFFFF;
> + SaveArea->Ldtr.Limit = 0xFFFF;
> + SaveArea->Ldtr.Attributes.Bits.Present = 1;
> + SaveArea->Ldtr.Attributes.Bits.Type = SEV_ES_RESET_LDT_TYPE;
> + SaveArea->Idtr.Limit = 0xFFFF;
> + SaveArea->Tr.Limit = 0xFFFF;
> + SaveArea->Ldtr.Attributes.Bits.Present = 1;
> + SaveArea->Ldtr.Attributes.Bits.Type = SEV_ES_RESET_TSS_TYPE;
> +
> + SaveArea->Efer = 0x1000;
> + SaveArea->Cr4 = ResetCr4.UintN;
> + SaveArea->Cr0 = ResetCr0.UintN;
> + SaveArea->Dr7 = 0x0400;
> + SaveArea->Dr6 = 0xFFFF0FF0;
> + SaveArea->Rflags = 0x0002;
> + SaveArea->GPat = 0x0007040600070406ULL;
> + SaveArea->XCr0 = 0x0001;
> + SaveArea->Mxcsr = 0x1F80;
> + SaveArea->X87Ftw = 0x5555;
> + SaveArea->X87Fcw = 0x0040;
> +
> + //
> + // Set the SEV-SNP specific fields for the save area:
> + // VMPL - always VMPL0
> + // SEV_FEATURES - equivalent to the SEV_STATUS MSR right shifted 2 bits
> + //
> + SaveArea->Vmpl = 0;
> + SaveArea->SevFeatures = AsmReadMsr64 (MSR_SEV_STATUS) >> 2;
> +
> + //
> + // To turn the page into a recognized VMSA page, issue RMPADJUST:
> + // Target VMPL but numerically higher than current VMPL
> + // Target PermissionMask is not used
> + //
> + RmpAdjustStatus = SevSnpRmpAdjust (
> + (EFI_PHYSICAL_ADDRESS) (UINTN) SaveArea,
> + TRUE
> + );
> + ASSERT (RmpAdjustStatus == 0);
> +
> + ExitInfo1 = (UINT64) ApicId << 32;
> + ExitInfo1 |= SVM_VMGEXIT_SNP_AP_CREATE;
> + ExitInfo2 = (UINT64) (UINTN) SaveArea;
> +
> + Msr.GhcbPhysicalAddress = AsmReadMsr64 (MSR_SEV_ES_GHCB);
> + Ghcb = Msr.Ghcb;
> +
> + VmgInit (Ghcb, &InterruptState);
> + Ghcb->SaveArea.Rax = SaveArea->SevFeatures;
> + VmgSetOffsetValid (Ghcb, GhcbRax);
> + VmgExitStatus = VmgExit (
> + Ghcb,
> + SVM_EXIT_SNP_AP_CREATION,
> + ExitInfo1,
> + ExitInfo2
> + );
> + VmgDone (Ghcb, InterruptState);
> +
> + ASSERT (VmgExitStatus == 0);
> + if (VmgExitStatus != 0) {
> + RmpAdjustStatus = SevSnpRmpAdjust (
> + (EFI_PHYSICAL_ADDRESS) (UINTN) SaveArea,
> + FALSE
> + );
> + if (RmpAdjustStatus == 0) {
> + FreePages (SaveArea, 1);
> + } else {
> + DEBUG ((DEBUG_INFO, "SEV-SNP: RMPADJUST failed, leaking VMSA page\n"));
> + }
> +
> + SaveArea = NULL;
> + }
> +
> + if (CpuData->SevEsSaveArea) {
> + RmpAdjustStatus = SevSnpRmpAdjust (
> + (EFI_PHYSICAL_ADDRESS) (UINTN) CpuData->SevEsSaveArea,
> + FALSE
> + );
> + if (RmpAdjustStatus == 0) {
> + FreePages (CpuData->SevEsSaveArea, 1);
> + } else {
> + DEBUG ((DEBUG_INFO, "SEV-SNP: RMPADJUST failed, leaking VMSA page\n"));
> + }
> + }
> +
> + CpuData->SevEsSaveArea = SaveArea;
> +}
> +
> +/**
> + Create SEV-SNP APs.
> +
> + @param[in] CpuMpData Pointer to CPU MP Data
> + @param[in] ProcessorNumber The handle number of specified processor
> + (-1 for all APs)
> +**/
> +VOID
> +SevSnpCreateAP (
> + IN CPU_MP_DATA *CpuMpData,
> + IN INTN ProcessorNumber
> + )
> +{
> + CPU_INFO_IN_HOB *CpuInfoInHob;
> + CPU_AP_DATA *CpuData;
> + UINTN Index;
> + UINT32 ApicId;
> +
> + ASSERT (CpuMpData->MpCpuExchangeInfo->BufferStart < 0x100000);
> +
> + CpuInfoInHob = (CPU_INFO_IN_HOB *) (UINTN) CpuMpData->CpuInfoInHob;
> +
> + if (ProcessorNumber < 0) {
> + for (Index = 0; Index < CpuMpData->CpuCount; Index++) {
> + if (Index != CpuMpData->BspNumber) {
> + CpuData = &CpuMpData->CpuData[Index];
> + ApicId = CpuInfoInHob[Index].ApicId,
> + SevSnpCreateSaveArea (CpuMpData, CpuData, ApicId);
> + }
> + }
> + } else {
> + Index = (UINTN) ProcessorNumber;
> + CpuData = &CpuMpData->CpuData[Index];
> + ApicId = CpuInfoInHob[ProcessorNumber].ApicId,
> + SevSnpCreateSaveArea (CpuMpData, CpuData, ApicId);
> + }
> +}
> +
> +/**
> + Issue RMPADJUST to adjust the VMSA attribute of an SEV-SNP page.
> +
> + @param[in] PageAddress
> + @param[in] VmsaPage
> +
> + @return RMPADJUST return value
> +**/
> +UINT32
> +SevSnpRmpAdjust (
> + IN EFI_PHYSICAL_ADDRESS PageAddress,
> + IN BOOLEAN VmsaPage
> + )
> +{
> + UINT64 Rdx;
> +
> + //
> + // The RMPADJUST instruction is used to set or clear the VMSA bit for a
> + // page. The VMSA change is only made when running at VMPL0 and is ignored
> + // otherwise. If too low a target VMPL is specified, the instruction can
> + // succeed without changing the VMSA bit when not running at VMPL0. Using a
> + // target VMPL level of 1, RMPADJUST will return a FAIL_PERMISSION error if
> + // not running at VMPL0, thus ensuring that the VMSA bit is set appropriately
> + // when no error is returned.
> + //
> + Rdx = 1;
> + if (VmsaPage) {
> + Rdx |= RMPADJUST_VMSA_PAGE_BIT;
> + }
> +
> + return AsmRmpAdjust ((UINT64) PageAddress, 0, Rdx);
> +}
-=-=-=-=-=-=-=-=-=-=-=-
Groups.io Links: You receive all messages sent to this group.
View/Reply Online (#82609): https://edk2.groups.io/g/devel/message/82609
Mute This Topic: https://groups.io/mt/86566126/1813853
Group Owner: devel+owner at edk2.groups.io
Unsubscribe: https://edk2.groups.io/g/devel/unsub [edk2-devel-archive at redhat.com]
-=-=-=-=-=-=-=-=-=-=-=-
More information about the edk2-devel-archive
mailing list