[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