#include <Register/Amd/Fam17Msr.h>\r
#include <Register/Amd/Ghcb.h>\r
\r
+/**\r
+ Perform the requested AP Creation action.\r
+\r
+ @param[in] SaveArea Pointer to VM save area (VMSA)\r
+ @param[in] ApicId APIC ID of the vCPU\r
+ @param[in] Action AP action to perform\r
+\r
+ @retval TRUE Action completed successfully\r
+ @retval FALSE Action did not complete successfully\r
+**/\r
+STATIC\r
+BOOLEAN\r
+SevSnpPerformApAction (\r
+ IN SEV_ES_SAVE_AREA *SaveArea,\r
+ IN UINT32 ApicId,\r
+ IN UINTN Action\r
+ )\r
+{\r
+ MSR_SEV_ES_GHCB_REGISTER Msr;\r
+ GHCB *Ghcb;\r
+ BOOLEAN InterruptState;\r
+ UINT64 ExitInfo1;\r
+ UINT64 ExitInfo2;\r
+ UINT32 RmpAdjustStatus;\r
+ UINT64 VmgExitStatus;\r
+\r
+ if (Action == SVM_VMGEXIT_SNP_AP_CREATE) {\r
+ //\r
+ // To turn the page into a recognized VMSA page, issue RMPADJUST:\r
+ // Target VMPL but numerically higher than current VMPL\r
+ // Target PermissionMask is not used\r
+ //\r
+ RmpAdjustStatus = SevSnpRmpAdjust (\r
+ (EFI_PHYSICAL_ADDRESS)(UINTN)SaveArea,\r
+ TRUE\r
+ );\r
+ if (RmpAdjustStatus != 0) {\r
+ DEBUG ((DEBUG_INFO, "SEV-SNP: RMPADJUST failed for VMSA creation\n"));\r
+ ASSERT (FALSE);\r
+\r
+ return FALSE;\r
+ }\r
+ }\r
+\r
+ ExitInfo1 = (UINT64)ApicId << 32;\r
+ ExitInfo1 |= Action;\r
+ ExitInfo2 = (UINT64)(UINTN)SaveArea;\r
+\r
+ Msr.GhcbPhysicalAddress = AsmReadMsr64 (MSR_SEV_ES_GHCB);\r
+ Ghcb = Msr.Ghcb;\r
+\r
+ CcExitVmgInit (Ghcb, &InterruptState);\r
+\r
+ if (Action == SVM_VMGEXIT_SNP_AP_CREATE) {\r
+ Ghcb->SaveArea.Rax = SaveArea->SevFeatures;\r
+ CcExitVmgSetOffsetValid (Ghcb, GhcbRax);\r
+ }\r
+\r
+ VmgExitStatus = CcExitVmgExit (\r
+ Ghcb,\r
+ SVM_EXIT_SNP_AP_CREATION,\r
+ ExitInfo1,\r
+ ExitInfo2\r
+ );\r
+\r
+ CcExitVmgDone (Ghcb, InterruptState);\r
+\r
+ if (VmgExitStatus != 0) {\r
+ DEBUG ((DEBUG_INFO, "SEV-SNP: AP Destroy failed\n"));\r
+ ASSERT (FALSE);\r
+\r
+ return FALSE;\r
+ }\r
+\r
+ if (Action == SVM_VMGEXIT_SNP_AP_DESTROY) {\r
+ //\r
+ // Make the current VMSA not runnable and accessible to be\r
+ // reprogrammed.\r
+ //\r
+ RmpAdjustStatus = SevSnpRmpAdjust (\r
+ (EFI_PHYSICAL_ADDRESS)(UINTN)SaveArea,\r
+ FALSE\r
+ );\r
+ if (RmpAdjustStatus != 0) {\r
+ DEBUG ((DEBUG_INFO, "SEV-SNP: RMPADJUST failed for VMSA reset\n"));\r
+ ASSERT (FALSE);\r
+\r
+ return FALSE;\r
+ }\r
+ }\r
+\r
+ return TRUE;\r
+}\r
+\r
/**\r
Create an SEV-SNP AP save area (VMSA) for use in running the vCPU.\r
\r
UINT32 ApicId\r
)\r
{\r
- SEV_ES_SAVE_AREA *SaveArea;\r
- IA32_CR0 ApCr0;\r
- IA32_CR0 ResetCr0;\r
- IA32_CR4 ApCr4;\r
- IA32_CR4 ResetCr4;\r
- UINTN StartIp;\r
- UINT8 SipiVector;\r
- UINT32 RmpAdjustStatus;\r
- UINT64 VmgExitStatus;\r
- MSR_SEV_ES_GHCB_REGISTER Msr;\r
- GHCB *Ghcb;\r
- BOOLEAN InterruptState;\r
- UINT64 ExitInfo1;\r
- UINT64 ExitInfo2;\r
+ SEV_ES_SAVE_AREA *SaveArea;\r
+ IA32_CR0 ApCr0;\r
+ IA32_CR0 ResetCr0;\r
+ IA32_CR4 ApCr4;\r
+ IA32_CR4 ResetCr4;\r
+ UINTN StartIp;\r
+ UINT8 SipiVector;\r
+\r
+ if (CpuData->SevEsSaveArea == NULL) {\r
+ //\r
+ // Allocate a single page for the SEV-ES Save Area and initialize it.\r
+ //\r
+ SaveArea = AllocateReservedPages (1);\r
+ if (!SaveArea) {\r
+ return;\r
+ }\r
\r
- //\r
- // Allocate a single page for the SEV-ES Save Area and initialize it.\r
- //\r
- SaveArea = AllocateReservedPages (1);\r
- if (!SaveArea) {\r
- return;\r
+ CpuData->SevEsSaveArea = SaveArea;\r
+ } else {\r
+ SaveArea = CpuData->SevEsSaveArea;\r
+\r
+ //\r
+ // Tell the hypervisor to not use the current VMSA\r
+ //\r
+ if (!SevSnpPerformApAction (SaveArea, ApicId, SVM_VMGEXIT_SNP_AP_DESTROY)) {\r
+ return;\r
+ }\r
}\r
\r
ZeroMem (SaveArea, EFI_PAGE_SIZE);\r
SaveArea->Vmpl = 0;\r
SaveArea->SevFeatures = AsmReadMsr64 (MSR_SEV_STATUS) >> 2;\r
\r
- //\r
- // To turn the page into a recognized VMSA page, issue RMPADJUST:\r
- // Target VMPL but numerically higher than current VMPL\r
- // Target PermissionMask is not used\r
- //\r
- RmpAdjustStatus = SevSnpRmpAdjust (\r
- (EFI_PHYSICAL_ADDRESS)(UINTN)SaveArea,\r
- TRUE\r
- );\r
- ASSERT (RmpAdjustStatus == 0);\r
-\r
- ExitInfo1 = (UINT64)ApicId << 32;\r
- ExitInfo1 |= SVM_VMGEXIT_SNP_AP_CREATE;\r
- ExitInfo2 = (UINT64)(UINTN)SaveArea;\r
-\r
- Msr.GhcbPhysicalAddress = AsmReadMsr64 (MSR_SEV_ES_GHCB);\r
- Ghcb = Msr.Ghcb;\r
-\r
- CcExitVmgInit (Ghcb, &InterruptState);\r
- Ghcb->SaveArea.Rax = SaveArea->SevFeatures;\r
- CcExitVmgSetOffsetValid (Ghcb, GhcbRax);\r
- VmgExitStatus = CcExitVmgExit (\r
- Ghcb,\r
- SVM_EXIT_SNP_AP_CREATION,\r
- ExitInfo1,\r
- ExitInfo2\r
- );\r
- CcExitVmgDone (Ghcb, InterruptState);\r
-\r
- ASSERT (VmgExitStatus == 0);\r
- if (VmgExitStatus != 0) {\r
- RmpAdjustStatus = SevSnpRmpAdjust (\r
- (EFI_PHYSICAL_ADDRESS)(UINTN)SaveArea,\r
- FALSE\r
- );\r
- if (RmpAdjustStatus == 0) {\r
- FreePages (SaveArea, 1);\r
- } else {\r
- DEBUG ((DEBUG_INFO, "SEV-SNP: RMPADJUST failed, leaking VMSA page\n"));\r
- }\r
-\r
- SaveArea = NULL;\r
- }\r
-\r
- if (CpuData->SevEsSaveArea) {\r
- RmpAdjustStatus = SevSnpRmpAdjust (\r
- (EFI_PHYSICAL_ADDRESS)(UINTN)CpuData->SevEsSaveArea,\r
- FALSE\r
- );\r
- if (RmpAdjustStatus == 0) {\r
- FreePages (CpuData->SevEsSaveArea, 1);\r
- } else {\r
- DEBUG ((DEBUG_INFO, "SEV-SNP: RMPADJUST failed, leaking VMSA page\n"));\r
- }\r
- }\r
-\r
- CpuData->SevEsSaveArea = SaveArea;\r
+ SevSnpPerformApAction (SaveArea, ApicId, SVM_VMGEXIT_SNP_AP_CREATE);\r
}\r
\r
/**\r