UefiCpuPkg/MpInitLib: Use SEV-SNP AP Creation NAE event to launch APs
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@amd.com> Cc: Eric Dong <eric.dong@intel.com> Cc: Ray Ni <ray.ni@intel.com> Cc: Rahul Kumar <rahul1.kumar@intel.com> Cc: James Bottomley <jejb@linux.ibm.com> Cc: Min Xu <min.m.xu@intel.com> Cc: Jiewen Yao <jiewen.yao@intel.com> Cc: Tom Lendacky <thomas.lendacky@amd.com> Cc: Jordan Justen <jordan.l.justen@intel.com> Cc: Ard Biesheuvel <ardb+tianocore@kernel.org> Cc: Erdem Aktas <erdemaktas@google.com> Cc: Gerd Hoffmann <kraxel@redhat.com> Acked-by: Ray Ni <ray.ni@intel.com> Acked-by: Gerd Hoffmann <kraxel@redhat.com> Signed-off-by: Tom Lendacky <thomas.lendacky@amd.com> Signed-off-by: Brijesh Singh <brijesh.singh@amd.com>
This commit is contained in:
		
				
					committed by
					
						![mergify[bot]](/avatar/e3df20cd7a67969c41a65f03bea54961?size=40) mergify[bot]
						mergify[bot]
					
				
			
			
				
	
			
			
			
						parent
						
							67484aed69
						
					
				
				
					commit
					06544455d0
				
			| @@ -22,9 +22,11 @@ | |||||||
| # | # | ||||||
|  |  | ||||||
| [Sources.IA32] | [Sources.IA32] | ||||||
|  |   Ia32/AmdSev.c | ||||||
|   Ia32/MpFuncs.nasm |   Ia32/MpFuncs.nasm | ||||||
|  |  | ||||||
| [Sources.X64] | [Sources.X64] | ||||||
|  |   X64/AmdSev.c | ||||||
|   X64/MpFuncs.nasm |   X64/MpFuncs.nasm | ||||||
|  |  | ||||||
| [Sources.common] | [Sources.common] | ||||||
| @@ -73,6 +75,7 @@ | |||||||
|   gUefiCpuPkgTokenSpaceGuid.PcdCpuApLoopMode                           ## CONSUMES |   gUefiCpuPkgTokenSpaceGuid.PcdCpuApLoopMode                           ## CONSUMES | ||||||
|   gUefiCpuPkgTokenSpaceGuid.PcdCpuApTargetCstate                       ## SOMETIMES_CONSUMES |   gUefiCpuPkgTokenSpaceGuid.PcdCpuApTargetCstate                       ## SOMETIMES_CONSUMES | ||||||
|   gUefiCpuPkgTokenSpaceGuid.PcdCpuApStatusCheckIntervalInMicroSeconds  ## CONSUMES |   gUefiCpuPkgTokenSpaceGuid.PcdCpuApStatusCheckIntervalInMicroSeconds  ## CONSUMES | ||||||
|  |   gUefiCpuPkgTokenSpaceGuid.PcdGhcbHypervisorFeatures                  ## CONSUMES | ||||||
|   gUefiCpuPkgTokenSpaceGuid.PcdSevEsWorkAreaBase                       ## SOMETIMES_CONSUMES |   gUefiCpuPkgTokenSpaceGuid.PcdSevEsWorkAreaBase                       ## SOMETIMES_CONSUMES | ||||||
|   gEfiMdeModulePkgTokenSpaceGuid.PcdCpuStackGuard                      ## CONSUMES |   gEfiMdeModulePkgTokenSpaceGuid.PcdCpuStackGuard                      ## CONSUMES | ||||||
|   gEfiMdeModulePkgTokenSpaceGuid.PcdGhcbBase                           ## CONSUMES |   gEfiMdeModulePkgTokenSpaceGuid.PcdGhcbBase                           ## CONSUMES | ||||||
|   | |||||||
| @@ -93,7 +93,14 @@ GetWakeupBuffer ( | |||||||
|   EFI_PHYSICAL_ADDRESS  StartAddress; |   EFI_PHYSICAL_ADDRESS  StartAddress; | ||||||
|   EFI_MEMORY_TYPE       MemoryType; |   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; |     MemoryType = EfiReservedMemoryType; | ||||||
|   } else { |   } else { | ||||||
|     MemoryType = EfiBootServicesData; |     MemoryType = EfiBootServicesData; | ||||||
| @@ -380,7 +387,7 @@ RelocateApLoop ( | |||||||
|   MpInitLibWhoAmI (&ProcessorNumber); |   MpInitLibWhoAmI (&ProcessorNumber); | ||||||
|   CpuMpData    = GetCpuMpData (); |   CpuMpData    = GetCpuMpData (); | ||||||
|   MwaitSupport = IsMwaitSupport (); |   MwaitSupport = IsMwaitSupport (); | ||||||
|   if (CpuMpData->SevEsIsEnabled) { |   if (CpuMpData->UseSevEsAPMethod) { | ||||||
|     StackStart = CpuMpData->SevEsAPResetStackStart; |     StackStart = CpuMpData->SevEsAPResetStackStart; | ||||||
|   } else { |   } else { | ||||||
|     StackStart = mReservedTopOfApStack; |     StackStart = mReservedTopOfApStack; | ||||||
| @@ -430,7 +437,7 @@ MpInitChangeApLoopCallback ( | |||||||
|     CpuPause (); |     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 |     // 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 |     // WakeupBuffer as the area to be used for transitioning to 16-bit mode | ||||||
|   | |||||||
							
								
								
									
										70
									
								
								UefiCpuPkg/Library/MpInitLib/Ia32/AmdSev.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										70
									
								
								UefiCpuPkg/Library/MpInitLib/Ia32/AmdSev.c
									
									
									
									
									
										Normal file
									
								
							| @@ -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; | ||||||
|  | } | ||||||
| @@ -295,10 +295,12 @@ GetApLoopMode ( | |||||||
|       ApLoopMode = ApInHltLoop; |       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 |       // For SEV-ES (SEV-SNP is also considered SEV-ES), force AP in Hlt-loop | ||||||
|       // protocol for starting APs |       // mode in order to use the GHCB protocol for starting APs | ||||||
|       // |       // | ||||||
|       ApLoopMode = ApInHltLoop; |       ApLoopMode = ApInHltLoop; | ||||||
|     } |     } | ||||||
| @@ -763,7 +765,7 @@ ApWakeupFunction ( | |||||||
|       // to allow the APs to issue an AP_RESET_HOLD before the BSP possibly |       // to allow the APs to issue an AP_RESET_HOLD before the BSP possibly | ||||||
|       // performs another INIT-SIPI-SIPI sequence. |       // performs another INIT-SIPI-SIPI sequence. | ||||||
|       // |       // | ||||||
|       if (!CpuMpData->SevEsIsEnabled) { |       if (!CpuMpData->UseSevEsAPMethod) { | ||||||
|         InterlockedDecrement ((UINT32 *)&CpuMpData->MpCpuExchangeInfo->NumApsExecuting); |         InterlockedDecrement ((UINT32 *)&CpuMpData->MpCpuExchangeInfo->NumApsExecuting); | ||||||
|       } |       } | ||||||
|     } |     } | ||||||
| @@ -777,7 +779,7 @@ ApWakeupFunction ( | |||||||
|       // |       // | ||||||
|       while (TRUE) { |       while (TRUE) { | ||||||
|         DisableInterrupts (); |         DisableInterrupts (); | ||||||
|         if (CpuMpData->SevEsIsEnabled) { |         if (CpuMpData->UseSevEsAPMethod) { | ||||||
|           SevEsPlaceApHlt (CpuMpData); |           SevEsPlaceApHlt (CpuMpData); | ||||||
|         } else { |         } else { | ||||||
|           CpuSleep (); |           CpuSleep (); | ||||||
| @@ -1061,9 +1063,13 @@ AllocateResetVector ( | |||||||
|                                     ); |                                     ); | ||||||
|     // |     // | ||||||
|     // The AP reset stack is only used by SEV-ES guests. Do not allocate it |     // 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 |       // Stack location is based on ProcessorNumber, so use the total number | ||||||
|       // of processors for calculating the total stack area. |       // of processors for calculating the total stack area. | ||||||
| @@ -1114,7 +1120,7 @@ FreeResetVector ( | |||||||
|   // perform the restore as this will overwrite memory which has data |   // perform the restore as this will overwrite memory which has data | ||||||
|   // needed by SEV-ES. |   // needed by SEV-ES. | ||||||
|   // |   // | ||||||
|   if (!CpuMpData->SevEsIsEnabled) { |   if (!CpuMpData->UseSevEsAPMethod) { | ||||||
|     RestoreWakeupBuffer (CpuMpData); |     RestoreWakeupBuffer (CpuMpData); | ||||||
|   } |   } | ||||||
| } | } | ||||||
| @@ -1193,7 +1199,7 @@ WakeUpAP ( | |||||||
|  |  | ||||||
|     if (ResetVectorRequired) { |     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 |       // PcdSevEsWorkAreaBase. The Segment/Rip must be the jump address | ||||||
|       // from the original INIT-SIPI-SIPI. |       // from the original INIT-SIPI-SIPI. | ||||||
|       // |       // | ||||||
| @@ -1203,9 +1209,15 @@ WakeUpAP ( | |||||||
|  |  | ||||||
|       // |       // | ||||||
|       // Wakeup all APs |       // Wakeup all APs | ||||||
|  |       //   Must use the INIT-SIPI-SIPI method for initial configuration in | ||||||
|  |       //   order to obtain the APIC ID. | ||||||
|       // |       // | ||||||
|  |       if (CpuMpData->SevSnpIsEnabled && (CpuMpData->InitFlag != ApInitConfig)) { | ||||||
|  |         SevSnpCreateAP (CpuMpData, -1); | ||||||
|  |       } else { | ||||||
|         SendInitSipiSipiAllExcludingSelf ((UINT32)ExchangeInfo->BufferStart); |         SendInitSipiSipiAllExcludingSelf ((UINT32)ExchangeInfo->BufferStart); | ||||||
|       } |       } | ||||||
|  |     } | ||||||
|  |  | ||||||
|     if (CpuMpData->InitFlag == ApInitConfig) { |     if (CpuMpData->InitFlag == ApInitConfig) { | ||||||
|       if (PcdGet32 (PcdCpuBootLogicalProcessorNumber) > 0) { |       if (PcdGet32 (PcdCpuBootLogicalProcessorNumber) > 0) { | ||||||
| @@ -1295,7 +1307,7 @@ WakeUpAP ( | |||||||
|       CpuInfoInHob = (CPU_INFO_IN_HOB *)(UINTN)CpuMpData->CpuInfoInHob; |       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 |       // PcdSevEsWorkAreaBase. The Segment/Rip must be the jump address | ||||||
|       // from the original INIT-SIPI-SIPI. |       // from the original INIT-SIPI-SIPI. | ||||||
|       // |       // | ||||||
| @@ -1303,11 +1315,15 @@ WakeUpAP ( | |||||||
|         SetSevEsJumpTable (ExchangeInfo->BufferStart); |         SetSevEsJumpTable (ExchangeInfo->BufferStart); | ||||||
|       } |       } | ||||||
|  |  | ||||||
|  |       if (CpuMpData->SevSnpIsEnabled && (CpuMpData->InitFlag != ApInitConfig)) { | ||||||
|  |         SevSnpCreateAP (CpuMpData, (INTN)ProcessorNumber); | ||||||
|  |       } else { | ||||||
|         SendInitSipiSipi ( |         SendInitSipiSipi ( | ||||||
|           CpuInfoInHob[ProcessorNumber].ApicId, |           CpuInfoInHob[ProcessorNumber].ApicId, | ||||||
|           (UINT32)ExchangeInfo->BufferStart |           (UINT32)ExchangeInfo->BufferStart | ||||||
|           ); |           ); | ||||||
|       } |       } | ||||||
|  |     } | ||||||
|  |  | ||||||
|     // |     // | ||||||
|     // Wait specified AP waken up |     // Wait specified AP waken up | ||||||
| @@ -1859,6 +1875,11 @@ MpInitLibInitialize ( | |||||||
|   CpuMpData->SevSnpIsEnabled  = ConfidentialComputingGuestHas (CCAttrAmdSevSnp); |   CpuMpData->SevSnpIsEnabled  = ConfidentialComputingGuestHas (CCAttrAmdSevSnp); | ||||||
|   CpuMpData->SevEsAPBuffer    = (UINTN)-1; |   CpuMpData->SevEsAPBuffer    = (UINTN)-1; | ||||||
|   CpuMpData->GhcbBase         = PcdGet64 (PcdGhcbBase); |   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. |   // Make sure no memory usage outside of the allocated buffer. | ||||||
|   | |||||||
| @@ -15,6 +15,7 @@ | |||||||
|  |  | ||||||
| #include <Register/Intel/Cpuid.h> | #include <Register/Intel/Cpuid.h> | ||||||
| #include <Register/Amd/Cpuid.h> | #include <Register/Amd/Cpuid.h> | ||||||
|  | #include <Register/Amd/Ghcb.h> | ||||||
| #include <Register/Intel/Msr.h> | #include <Register/Intel/Msr.h> | ||||||
| #include <Register/Intel/LocalApic.h> | #include <Register/Intel/LocalApic.h> | ||||||
| #include <Register/Intel/Microcode.h> | #include <Register/Intel/Microcode.h> | ||||||
| @@ -150,6 +151,7 @@ typedef struct { | |||||||
|   UINT8                     PlatformId; |   UINT8                     PlatformId; | ||||||
|   UINT64                    MicrocodeEntryAddr; |   UINT64                    MicrocodeEntryAddr; | ||||||
|   UINT32                    MicrocodeRevision; |   UINT32                    MicrocodeRevision; | ||||||
|  |   SEV_ES_SAVE_AREA          *SevEsSaveArea; | ||||||
| } CPU_AP_DATA; | } CPU_AP_DATA; | ||||||
|  |  | ||||||
| // | // | ||||||
| @@ -294,6 +296,7 @@ struct _CPU_MP_DATA { | |||||||
|  |  | ||||||
|   BOOLEAN        SevEsIsEnabled; |   BOOLEAN        SevEsIsEnabled; | ||||||
|   BOOLEAN        SevSnpIsEnabled; |   BOOLEAN        SevSnpIsEnabled; | ||||||
|  |   BOOLEAN        UseSevEsAPMethod; | ||||||
|   UINTN          SevEsAPBuffer; |   UINTN          SevEsAPBuffer; | ||||||
|   UINTN          SevEsAPResetStackStart; |   UINTN          SevEsAPResetStackStart; | ||||||
|   CPU_MP_DATA    *NewCpuMpData; |   CPU_MP_DATA    *NewCpuMpData; | ||||||
| @@ -799,4 +802,45 @@ FillExchangeInfoDataSevEs ( | |||||||
|   IN volatile MP_CPU_EXCHANGE_INFO  *ExchangeInfo |   IN volatile MP_CPU_EXCHANGE_INFO  *ExchangeInfo | ||||||
|   ); |   ); | ||||||
|  |  | ||||||
|  | /** | ||||||
|  |   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 | #endif | ||||||
|   | |||||||
| @@ -22,9 +22,11 @@ | |||||||
| # | # | ||||||
|  |  | ||||||
| [Sources.IA32] | [Sources.IA32] | ||||||
|  |   Ia32/AmdSev.c | ||||||
|   Ia32/MpFuncs.nasm |   Ia32/MpFuncs.nasm | ||||||
|  |  | ||||||
| [Sources.X64] | [Sources.X64] | ||||||
|  |   X64/AmdSev.c | ||||||
|   X64/MpFuncs.nasm |   X64/MpFuncs.nasm | ||||||
|  |  | ||||||
| [Sources.common] | [Sources.common] | ||||||
| @@ -64,6 +66,7 @@ | |||||||
|   gUefiCpuPkgTokenSpaceGuid.PcdCpuApLoopMode                       ## CONSUMES |   gUefiCpuPkgTokenSpaceGuid.PcdCpuApLoopMode                       ## CONSUMES | ||||||
|   gUefiCpuPkgTokenSpaceGuid.PcdCpuApTargetCstate                   ## SOMETIMES_CONSUMES |   gUefiCpuPkgTokenSpaceGuid.PcdCpuApTargetCstate                   ## SOMETIMES_CONSUMES | ||||||
|   gUefiCpuPkgTokenSpaceGuid.PcdSevEsWorkAreaBase                   ## SOMETIMES_CONSUMES |   gUefiCpuPkgTokenSpaceGuid.PcdSevEsWorkAreaBase                   ## SOMETIMES_CONSUMES | ||||||
|  |   gUefiCpuPkgTokenSpaceGuid.PcdGhcbHypervisorFeatures              ## CONSUMES | ||||||
|   gEfiMdeModulePkgTokenSpaceGuid.PcdGhcbBase                       ## CONSUMES |   gEfiMdeModulePkgTokenSpaceGuid.PcdGhcbBase                       ## CONSUMES | ||||||
|   gEfiMdePkgTokenSpaceGuid.PcdConfidentialComputingGuestAttr       ## CONSUMES |   gEfiMdePkgTokenSpaceGuid.PcdConfidentialComputingGuestAttr       ## CONSUMES | ||||||
|  |  | ||||||
|   | |||||||
							
								
								
									
										263
									
								
								UefiCpuPkg/Library/MpInitLib/X64/AmdSev.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										263
									
								
								UefiCpuPkg/Library/MpInitLib/X64/AmdSev.c
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,263 @@ | |||||||
|  | /** @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); | ||||||
|  | } | ||||||
		Reference in New Issue
	
	Block a user