+/**\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->AddressMap.RendezvousFunnelSize +\r
+ CpuMpData->AddressMap.SwitchToRealSize\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
+ Calculate the size of the reset vector.\r
+\r
+ @param[in] AddressMap The pointer to Address Map structure.\r
+\r
+ @return Total amount of memory required for the AP reset area\r
+**/\r
+STATIC\r
+UINTN\r
+GetApResetVectorSize (\r
+ IN MP_ASSEMBLY_ADDRESS_MAP *AddressMap\r
+ )\r
+{\r
+ UINTN Size;\r
+\r
+ Size = AddressMap->RendezvousFunnelSize +\r
+ AddressMap->SwitchToRealSize +\r
+ sizeof (MP_CPU_EXCHANGE_INFO);\r
+\r
+ return Size;\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
+AllocateResetVector (\r
+ IN OUT CPU_MP_DATA *CpuMpData\r
+ )\r
+{\r
+ UINTN ApResetVectorSize;\r
+ UINTN ApResetStackSize;\r
+\r
+ if (CpuMpData->WakeupBuffer == (UINTN)-1) {\r
+ ApResetVectorSize = GetApResetVectorSize (&CpuMpData->AddressMap);\r
+\r
+ CpuMpData->WakeupBuffer = GetWakeupBuffer (ApResetVectorSize);\r
+ CpuMpData->MpCpuExchangeInfo = (MP_CPU_EXCHANGE_INFO *)(UINTN)\r
+ (CpuMpData->WakeupBuffer +\r
+ CpuMpData->AddressMap.RendezvousFunnelSize +\r
+ CpuMpData->AddressMap.SwitchToRealSize);\r
+ CpuMpData->WakeupBufferHigh = GetModeTransitionBuffer (\r
+ CpuMpData->AddressMap.RendezvousFunnelSize +\r
+ CpuMpData->AddressMap.SwitchToRealSize -\r
+ CpuMpData->AddressMap.ModeTransitionOffset\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.\r
+ //\r
+ if (ConfidentialComputingGuestHas (CCAttrAmdSevEs)) {\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->SevEsIsEnabled) {\r
+ RestoreWakeupBuffer (CpuMpData);\r
+ }\r
+}\r
+\r