+/**\r
+ Check if AP wakeup buffer is overlapped with existing allocated buffer.\r
+\r
+ @param[in] WakeupBufferStart AP wakeup buffer start address.\r
+ @param[in] WakeupBufferEnd AP wakeup buffer end address.\r
+\r
+ @retval TRUE There is overlap.\r
+ @retval FALSE There is no overlap.\r
+**/\r
+BOOLEAN\r
+CheckOverlapWithAllocatedBuffer (\r
+ IN UINT64 WakeupBufferStart,\r
+ IN UINT64 WakeupBufferEnd\r
+ )\r
+{\r
+ EFI_PEI_HOB_POINTERS Hob;\r
+ EFI_HOB_MEMORY_ALLOCATION *MemoryHob;\r
+ BOOLEAN Overlapped;\r
+ UINT64 MemoryStart;\r
+ UINT64 MemoryEnd;\r
+\r
+ Overlapped = FALSE;\r
+ //\r
+ // Get the HOB list for processing\r
+ //\r
+ Hob.Raw = GetHobList ();\r
+ //\r
+ // Collect memory ranges\r
+ //\r
+ while (!END_OF_HOB_LIST (Hob)) {\r
+ if (Hob.Header->HobType == EFI_HOB_TYPE_MEMORY_ALLOCATION) {\r
+ MemoryHob = Hob.MemoryAllocation;\r
+ MemoryStart = MemoryHob->AllocDescriptor.MemoryBaseAddress;\r
+ MemoryEnd = MemoryHob->AllocDescriptor.MemoryBaseAddress + MemoryHob->AllocDescriptor.MemoryLength;\r
+ if (!((WakeupBufferStart >= MemoryEnd) || (WakeupBufferEnd <= MemoryStart))) {\r
+ Overlapped = TRUE;\r
+ break;\r
+ }\r
+ }\r
+\r
+ Hob.Raw = GET_NEXT_HOB (Hob);\r
+ }\r
+\r
+ return Overlapped;\r
+}\r
+\r
+/**\r
+ Get available system memory below 1MB by specified size.\r
+\r
+ @param[in] WakeupBufferSize Wakeup buffer size required\r
+\r
+ @retval other Return wakeup buffer address below 1MB.\r
+ @retval -1 Cannot find free memory below 1MB.\r
+**/\r
+UINTN\r
+GetWakeupBuffer (\r
+ IN UINTN WakeupBufferSize\r
+ )\r
+{\r
+ EFI_PEI_HOB_POINTERS Hob;\r
+ UINT64 WakeupBufferStart;\r
+ UINT64 WakeupBufferEnd;\r
+\r
+ WakeupBufferSize = (WakeupBufferSize + SIZE_4KB - 1) & ~(SIZE_4KB - 1);\r
+\r
+ //\r
+ // Get the HOB list for processing\r
+ //\r
+ Hob.Raw = GetHobList ();\r
+\r
+ //\r
+ // Collect memory ranges\r
+ //\r
+ while (!END_OF_HOB_LIST (Hob)) {\r
+ if (Hob.Header->HobType == EFI_HOB_TYPE_RESOURCE_DESCRIPTOR) {\r
+ if ((Hob.ResourceDescriptor->PhysicalStart < BASE_1MB) &&\r
+ (Hob.ResourceDescriptor->ResourceType == EFI_RESOURCE_SYSTEM_MEMORY) &&\r
+ ((Hob.ResourceDescriptor->ResourceAttribute &\r
+ (EFI_RESOURCE_ATTRIBUTE_READ_PROTECTED |\r
+ EFI_RESOURCE_ATTRIBUTE_WRITE_PROTECTED |\r
+ EFI_RESOURCE_ATTRIBUTE_EXECUTION_PROTECTED\r
+ )) == 0)\r
+ )\r
+ {\r
+ //\r
+ // Need memory under 1MB to be collected here\r
+ //\r
+ WakeupBufferEnd = Hob.ResourceDescriptor->PhysicalStart + Hob.ResourceDescriptor->ResourceLength;\r
+ if (ConfidentialComputingGuestHas (CCAttrAmdSevEs) &&\r
+ (WakeupBufferEnd > mSevEsPeiWakeupBuffer))\r
+ {\r
+ //\r
+ // SEV-ES Wakeup buffer should be under 1MB and under any previous one\r
+ //\r
+ WakeupBufferEnd = mSevEsPeiWakeupBuffer;\r
+ } else if (WakeupBufferEnd > BASE_1MB) {\r
+ //\r
+ // Wakeup buffer should be under 1MB\r
+ //\r
+ WakeupBufferEnd = BASE_1MB;\r
+ }\r
+\r
+ while (WakeupBufferEnd > WakeupBufferSize) {\r
+ //\r
+ // Wakeup buffer should be aligned on 4KB\r
+ //\r
+ WakeupBufferStart = (WakeupBufferEnd - WakeupBufferSize) & ~(SIZE_4KB - 1);\r
+ if (WakeupBufferStart < Hob.ResourceDescriptor->PhysicalStart) {\r
+ break;\r
+ }\r
+\r
+ if (CheckOverlapWithAllocatedBuffer (WakeupBufferStart, WakeupBufferEnd)) {\r
+ //\r
+ // If this range is overlapped with existing allocated buffer, skip it\r
+ // and find the next range\r
+ //\r
+ WakeupBufferEnd -= WakeupBufferSize;\r
+ continue;\r
+ }\r
+\r
+ DEBUG ((\r
+ DEBUG_INFO,\r
+ "WakeupBufferStart = %x, WakeupBufferSize = %x\n",\r
+ WakeupBufferStart,\r
+ WakeupBufferSize\r
+ ));\r
+\r
+ if (ConfidentialComputingGuestHas (CCAttrAmdSevEs)) {\r
+ //\r
+ // Next SEV-ES wakeup buffer allocation must be below this\r
+ // allocation\r
+ //\r
+ mSevEsPeiWakeupBuffer = WakeupBufferStart;\r
+ }\r
+\r
+ return (UINTN)WakeupBufferStart;\r
+ }\r
+ }\r
+ }\r
+\r
+ //\r
+ // Find the next HOB\r
+ //\r
+ Hob.Raw = GET_NEXT_HOB (Hob);\r
+ }\r
+\r
+ return (UINTN)-1;\r
+}\r
+\r
+/**\r
+ Get available EfiBootServicesCode memory below 4GB by specified size.\r
+\r
+ This buffer is required to safely transfer AP from real address mode to\r
+ protected mode or long mode, due to the fact that the buffer returned by\r
+ GetWakeupBuffer() may be marked as non-executable.\r
+\r
+ @param[in] BufferSize Wakeup transition buffer size.\r
+\r
+ @retval other Return wakeup transition buffer address below 4GB.\r
+ @retval 0 Cannot find free memory below 4GB.\r
+**/\r
+UINTN\r
+AllocateCodeBuffer (\r
+ IN UINTN BufferSize\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ EFI_PHYSICAL_ADDRESS Address;\r
+\r
+ Status = PeiServicesAllocatePages (EfiBootServicesCode, EFI_SIZE_TO_PAGES (BufferSize), &Address);\r
+ if (EFI_ERROR (Status)) {\r
+ Address = 0;\r
+ }\r
+\r
+ return (UINTN)Address;\r
+}\r