+/**\r
+ Get Protected mode code segment with 16-bit default addressing\r
+ from current GDT table.\r
+\r
+ @return Protected mode 16-bit code segment value.\r
+**/\r
+UINT16\r
+GetProtectedMode16CS (\r
+ VOID\r
+ )\r
+{\r
+ IA32_DESCRIPTOR GdtrDesc;\r
+ IA32_SEGMENT_DESCRIPTOR *GdtEntry;\r
+ UINTN GdtEntryCount;\r
+ UINT16 Index;\r
+\r
+ Index = (UINT16)-1;\r
+ AsmReadGdtr (&GdtrDesc);\r
+ GdtEntryCount = (GdtrDesc.Limit + 1) / sizeof (IA32_SEGMENT_DESCRIPTOR);\r
+ GdtEntry = (IA32_SEGMENT_DESCRIPTOR *)GdtrDesc.Base;\r
+ for (Index = 0; Index < GdtEntryCount; Index++) {\r
+ if (GdtEntry->Bits.L == 0) {\r
+ if ((GdtEntry->Bits.Type > 8) && (GdtEntry->Bits.DB == 0)) {\r
+ break;\r
+ }\r
+ }\r
+\r
+ GdtEntry++;\r
+ }\r
+\r
+ ASSERT (Index != GdtEntryCount);\r
+ return Index * 8;\r
+}\r
+\r
+/**\r
+ Get Protected mode code segment from current GDT table.\r
+\r
+ @return Protected mode code segment value.\r
+**/\r
+UINT16\r
+GetProtectedModeCS (\r
+ VOID\r
+ )\r
+{\r
+ IA32_DESCRIPTOR GdtrDesc;\r
+ IA32_SEGMENT_DESCRIPTOR *GdtEntry;\r
+ UINTN GdtEntryCount;\r
+ UINT16 Index;\r
+\r
+ AsmReadGdtr (&GdtrDesc);\r
+ GdtEntryCount = (GdtrDesc.Limit + 1) / sizeof (IA32_SEGMENT_DESCRIPTOR);\r
+ GdtEntry = (IA32_SEGMENT_DESCRIPTOR *)GdtrDesc.Base;\r
+ for (Index = 0; Index < GdtEntryCount; Index++) {\r
+ if (GdtEntry->Bits.L == 0) {\r
+ if ((GdtEntry->Bits.Type > 8) && (GdtEntry->Bits.DB == 1)) {\r
+ break;\r
+ }\r
+ }\r
+\r
+ GdtEntry++;\r
+ }\r
+\r
+ ASSERT (Index != GdtEntryCount);\r
+ return Index * 8;\r
+}\r
+\r
+/**\r
+ Do sync on APs.\r
+\r
+ @param[in, out] Buffer Pointer to private data buffer.\r
+**/\r
+VOID\r
+EFIAPI\r
+RelocateApLoop (\r
+ IN OUT VOID *Buffer\r
+ )\r
+{\r
+ CPU_MP_DATA *CpuMpData;\r
+ BOOLEAN MwaitSupport;\r
+ UINTN ProcessorNumber;\r
+ UINTN StackStart;\r
+\r
+ MpInitLibWhoAmI (&ProcessorNumber);\r
+ CpuMpData = GetCpuMpData ();\r
+ MwaitSupport = IsMwaitSupport ();\r
+ if (CpuMpData->UseSevEsAPMethod) {\r
+ //\r
+ // 64-bit AMD processors with SEV-ES\r
+ //\r
+ StackStart = CpuMpData->SevEsAPResetStackStart;\r
+ mReservedApLoop.AmdSevEntry (\r
+ MwaitSupport,\r
+ CpuMpData->ApTargetCState,\r
+ CpuMpData->PmCodeSegment,\r
+ StackStart - ProcessorNumber * AP_SAFE_STACK_SIZE,\r
+ (UINTN)&mNumberToFinish,\r
+ CpuMpData->Pm16CodeSegment,\r
+ CpuMpData->SevEsAPBuffer,\r
+ CpuMpData->WakeupBuffer\r
+ );\r
+ } else {\r
+ //\r
+ // Intel processors (32-bit or 64-bit), 32-bit AMD processors, or 64-bit AMD processors without SEV-ES\r
+ //\r
+ StackStart = mReservedTopOfApStack;\r
+ mReservedApLoop.GenericEntry (\r
+ MwaitSupport,\r
+ CpuMpData->ApTargetCState,\r
+ StackStart - ProcessorNumber * AP_SAFE_STACK_SIZE,\r
+ (UINTN)&mNumberToFinish,\r
+ mApPageTable\r
+ );\r
+ }\r
+\r
+ //\r
+ // It should never reach here\r
+ //\r
+ ASSERT (FALSE);\r
+}\r
+\r
+/**\r
+ Callback function for ExitBootServices.\r
+\r
+ @param[in] Event Event whose notification function is being invoked.\r
+ @param[in] Context The pointer to the notification function's context,\r
+ which is implementation-dependent.\r
+\r
+**/\r
+VOID\r
+EFIAPI\r
+MpInitChangeApLoopCallback (\r
+ IN EFI_EVENT Event,\r
+ IN VOID *Context\r
+ )\r
+{\r
+ CPU_MP_DATA *CpuMpData;\r
+\r
+ CpuMpData = GetCpuMpData ();\r
+ CpuMpData->PmCodeSegment = GetProtectedModeCS ();\r
+ CpuMpData->Pm16CodeSegment = GetProtectedMode16CS ();\r
+ CpuMpData->ApLoopMode = PcdGet8 (PcdCpuApLoopMode);\r
+ mNumberToFinish = CpuMpData->CpuCount - 1;\r
+ WakeUpAP (CpuMpData, TRUE, 0, RelocateApLoop, NULL, TRUE);\r
+ while (mNumberToFinish > 0) {\r
+ CpuPause ();\r
+ }\r
+\r
+ if (CpuMpData->UseSevEsAPMethod && (CpuMpData->WakeupBuffer != (UINTN)-1)) {\r
+ //\r
+ // There are APs present. Re-use reserved memory area below 1MB from\r
+ // WakeupBuffer as the area to be used for transitioning to 16-bit mode\r
+ // in support of booting of the AP by an OS.\r
+ //\r
+ CopyMem (\r
+ (VOID *)CpuMpData->WakeupBuffer,\r
+ (VOID *)(CpuMpData->AddressMap.RendezvousFunnelAddress +\r
+ CpuMpData->AddressMap.SwitchToRealPM16ModeOffset),\r
+ CpuMpData->AddressMap.SwitchToRealPM16ModeSize\r
+ );\r
+ }\r
+\r
+ DEBUG ((DEBUG_INFO, "%a() done!\n", __FUNCTION__));\r
+}\r
+\r