+/**\r
+ Get available system memory below 1MB by specified size.\r
+\r
+ @param[in] CpuMpData The pointer to CPU MP Data structure.\r
+**/\r
+VOID\r
+BackupAndPrepareWakeupBuffer (\r
+ IN CPU_MP_DATA *CpuMpData\r
+ )\r
+{\r
+ CopyMem (\r
+ (VOID *)CpuMpData->BackupBuffer,\r
+ (VOID *)CpuMpData->WakeupBuffer,\r
+ CpuMpData->BackupBufferSize\r
+ );\r
+ CopyMem (\r
+ (VOID *)CpuMpData->WakeupBuffer,\r
+ (VOID *)CpuMpData->AddressMap.RendezvousFunnelAddress,\r
+ CpuMpData->BackupBufferSize - sizeof (MP_CPU_EXCHANGE_INFO)\r
+ );\r
+}\r
+\r
+/**\r
+ Restore wakeup buffer data.\r
+\r
+ @param[in] CpuMpData The pointer to CPU MP Data structure.\r
+**/\r
+VOID\r
+RestoreWakeupBuffer (\r
+ IN CPU_MP_DATA *CpuMpData\r
+ )\r
+{\r
+ CopyMem (\r
+ (VOID *)CpuMpData->WakeupBuffer,\r
+ (VOID *)CpuMpData->BackupBuffer,\r
+ CpuMpData->BackupBufferSize\r
+ );\r
+}\r
+\r
+/**\r
+ Allocate reset vector buffer.\r
+\r
+ @param[in, out] CpuMpData The pointer to CPU MP Data structure.\r
+**/\r
+VOID\r
+AllocateResetVectorBelow1Mb (\r
+ IN OUT CPU_MP_DATA *CpuMpData\r
+ )\r
+{\r
+ UINTN ApResetStackSize;\r
+\r
+ if (CpuMpData->WakeupBuffer == (UINTN)-1) {\r
+ CpuMpData->WakeupBuffer = GetWakeupBuffer (CpuMpData->BackupBufferSize);\r
+ CpuMpData->MpCpuExchangeInfo = (MP_CPU_EXCHANGE_INFO *)(UINTN)\r
+ (CpuMpData->WakeupBuffer + CpuMpData->BackupBufferSize - sizeof (MP_CPU_EXCHANGE_INFO));\r
+ DEBUG ((\r
+ DEBUG_INFO,\r
+ "AP Vector: 16-bit = %p/%x, ExchangeInfo = %p/%x\n",\r
+ CpuMpData->WakeupBuffer,\r
+ CpuMpData->BackupBufferSize - sizeof (MP_CPU_EXCHANGE_INFO),\r
+ CpuMpData->MpCpuExchangeInfo,\r
+ sizeof (MP_CPU_EXCHANGE_INFO)\r
+ ));\r
+ //\r
+ // The AP reset stack is only used by SEV-ES guests. Do not allocate it\r
+ // if SEV-ES is not enabled. An SEV-SNP guest is also considered\r
+ // an SEV-ES guest, but uses a different method of AP startup, eliminating\r
+ // the need for the allocation.\r
+ //\r
+ if (ConfidentialComputingGuestHas (CCAttrAmdSevEs) &&\r
+ !ConfidentialComputingGuestHas (CCAttrAmdSevSnp))\r
+ {\r
+ //\r
+ // Stack location is based on ProcessorNumber, so use the total number\r
+ // of processors for calculating the total stack area.\r
+ //\r
+ ApResetStackSize = (AP_RESET_STACK_SIZE *\r
+ PcdGet32 (PcdCpuMaxLogicalProcessorNumber));\r
+\r
+ //\r
+ // Invoke GetWakeupBuffer a second time to allocate the stack area\r
+ // below 1MB. The returned buffer will be page aligned and sized and\r
+ // below the previously allocated buffer.\r
+ //\r
+ CpuMpData->SevEsAPResetStackStart = GetWakeupBuffer (ApResetStackSize);\r
+\r
+ //\r
+ // Check to be sure that the "allocate below" behavior hasn't changed.\r
+ // This will also catch a failed allocation, as "-1" is returned on\r
+ // failure.\r
+ //\r
+ if (CpuMpData->SevEsAPResetStackStart >= CpuMpData->WakeupBuffer) {\r
+ DEBUG ((\r
+ DEBUG_ERROR,\r
+ "SEV-ES AP reset stack is not below wakeup buffer\n"\r
+ ));\r
+\r
+ ASSERT (FALSE);\r
+ CpuDeadLoop ();\r
+ }\r
+ }\r
+ }\r
+\r
+ BackupAndPrepareWakeupBuffer (CpuMpData);\r
+}\r
+\r
+/**\r
+ Free AP reset vector buffer.\r
+\r
+ @param[in] CpuMpData The pointer to CPU MP Data structure.\r
+**/\r
+VOID\r
+FreeResetVector (\r
+ IN CPU_MP_DATA *CpuMpData\r
+ )\r
+{\r
+ //\r
+ // If SEV-ES is enabled, the reset area is needed for AP parking and\r
+ // and AP startup in the OS, so the reset area is reserved. Do not\r
+ // perform the restore as this will overwrite memory which has data\r
+ // needed by SEV-ES.\r
+ //\r
+ if (!CpuMpData->UseSevEsAPMethod) {\r
+ RestoreWakeupBuffer (CpuMpData);\r
+ }\r
+}\r
+\r