#include <Register/Amd/Fam17Msr.h>\r
#include <Register/Amd/Ghcb.h>\r
\r
+#define _IS_ALIGNED(x, y) (ALIGN_POINTER((x), (y)) == (x))\r
+\r
/**\r
Perform the requested AP Creation action.\r
\r
UINT32 ApicId\r
)\r
{\r
+ UINT8 *Pages;\r
SEV_ES_SAVE_AREA *SaveArea;\r
IA32_CR0 ApCr0;\r
IA32_CR0 ResetCr0;\r
\r
if (CpuData->SevEsSaveArea == NULL) {\r
//\r
- // Allocate a single page for the SEV-ES Save Area and initialize it.\r
+ // Allocate a page for the SEV-ES Save Area and initialize it. Due to AMD\r
+ // erratum #1467 (VMSA cannot be on a 2MB boundary), allocate an extra page\r
+ // to choose from to work around the issue.\r
//\r
- SaveArea = AllocateReservedPages (1);\r
- if (!SaveArea) {\r
+ Pages = AllocateReservedPages (2);\r
+ if (!Pages) {\r
return;\r
}\r
\r
+ //\r
+ // Since page allocation works by allocating downward in the address space,\r
+ // try to always free the first (lower address) page to limit possible holes\r
+ // in the memory map. So, if the address of the second page is 2MB aligned,\r
+ // then use the first page and free the second page. Otherwise, free the\r
+ // first page and use the second page.\r
+ //\r
+ if (_IS_ALIGNED (Pages + EFI_PAGE_SIZE, SIZE_2MB)) {\r
+ SaveArea = (SEV_ES_SAVE_AREA *)Pages;\r
+ FreePages (Pages + EFI_PAGE_SIZE, 1);\r
+ } else {\r
+ SaveArea = (SEV_ES_SAVE_AREA *)(Pages + EFI_PAGE_SIZE);\r
+ FreePages (Pages, 1);\r
+ }\r
+\r
CpuData->SevEsSaveArea = SaveArea;\r
} else {\r
SaveArea = CpuData->SevEsSaveArea;\r