UefiCpuPkg/MpInitLib: Place APs in safe loop before hand-off to OS

Register Exit Boot Service callback function MpInitExitBootServicesCallback() to
place AP one safe loop before hand-off to OS.

Allocated one reserved memory and copy the AsmRellocateApLoop() code into it. It
could avoid the CPU Dxe driver (located in Boot Service data range) crashed
after Exit Boot Service event.
Place AP into the target Cx-State (specified by PcdCpuApTargetCstate) could save
power if Monitor-mwait feature supported.
In long mode, switch AP into protected mode could let AP not require page table
when executing this safe loop. Page Table (located in Boot Service data range)
may crashed after Exit Boot Service event.

v3:
  1. Rename *RellocateAp* to *RelocateAp*

Cc: Michael Kinney <michael.d.kinney@intel.com>
Cc: Feng Tian <feng.tian@intel.com>
Cc: Giri P Mudusuru <giri.p.mudusuru@intel.com>
Cc: Laszlo Ersek <lersek@redhat.com>
Contributed-under: TianoCore Contribution Agreement 1.0
Signed-off-by: Jeff Fan <jeff.fan@intel.com>
Reviewed-by: Michael Kinney <michael.d.kinney@intel.com>
Tested-by: Laszlo Ersek <lersek@redhat.com>
Tested-by: Michael Kinney <michael.d.kinney@intel.com>
This commit is contained in:
Jeff Fan 2016-07-24 23:03:12 +08:00
parent 86efe97693
commit 4d3314f694
2 changed files with 108 additions and 0 deletions

View File

@ -21,6 +21,7 @@
CPU_MP_DATA *mCpuMpData = NULL;
EFI_EVENT mCheckAllApsEvent = NULL;
EFI_EVENT mMpInitExitBootServicesEvent = NULL;
volatile BOOLEAN mStopCheckAllApsStatus = TRUE;
@ -185,6 +186,94 @@ CheckApsStatus (
}
}
/**
Get Protected mode code segment from current GDT table.
@returen Protected mode code segment value.
**/
UINT16
GetProtectedModeCS (
VOID
)
{
IA32_DESCRIPTOR GdtrDesc;
IA32_SEGMENT_DESCRIPTOR *GdtEntry;
UINTN GdtEntryCount;
UINT16 Index;
Index = (UINT16) -1;
AsmReadGdtr (&GdtrDesc);
GdtEntryCount = (GdtrDesc.Limit + 1) / sizeof (IA32_SEGMENT_DESCRIPTOR);
GdtEntry = (IA32_SEGMENT_DESCRIPTOR *) GdtrDesc.Base;
for (Index = 0; Index < GdtEntryCount; Index++) {
if (GdtEntry->Bits.L == 0) {
if (GdtEntry->Bits.Type > 8 && GdtEntry->Bits.L == 0) {
break;
}
}
GdtEntry++;
}
ASSERT (Index != -1);
return Index * 8;
}
/**
Do sync on APs.
@param[in, out] Buffer Pointer to private data buffer.
**/
VOID
EFIAPI
RelocateApLoop (
IN OUT VOID *Buffer
)
{
CPU_MP_DATA *CpuMpData;
BOOLEAN MwaitSupport;
ASM_RELOCATE_AP_LOOP AsmRelocateApLoopFunc;
CpuMpData = GetCpuMpData ();
MwaitSupport = IsMwaitSupport ();
AsmRelocateApLoopFunc = (ASM_RELOCATE_AP_LOOP) (UINTN) Buffer;
AsmRelocateApLoopFunc (MwaitSupport, CpuMpData->ApTargetCState, CpuMpData->PmCodeSegment);
//
// It should never reach here
//
ASSERT (FALSE);
}
/**
Callback function for ExitBootServices.
@param[in] Event Event whose notification function is being invoked.
@param[in] Context The pointer to the notification function's context,
which is implementation-dependent.
**/
VOID
EFIAPI
MpInitExitBootServicesCallback (
IN EFI_EVENT Event,
IN VOID *Context
)
{
CPU_MP_DATA *CpuMpData;
VOID *ReservedApLoopFunc;
//
// Avoid APs access invalid buff data which allocated by BootServices,
// so we will allocate reserved data for AP loop code.
//
CpuMpData = GetCpuMpData ();
CpuMpData->PmCodeSegment = GetProtectedModeCS ();
CpuMpData->ApLoopMode = PcdGet8 (PcdCpuApLoopMode);
ReservedApLoopFunc = AllocateReservedCopyPool (
CpuMpData->AddressMap.RelocateApLoopFuncSize,
CpuMpData->AddressMap.RelocateApLoopFuncAddress
);
WakeUpAP (CpuMpData, TRUE, 0, RelocateApLoop, ReservedApLoopFunc);
DEBUG ((DEBUG_INFO, "MpInitExitBootServicesCallback() done!\n"));
}
/**
Initialize global data for MP support.
@ -217,6 +306,14 @@ InitMpGlobalData (
AP_CHECK_INTERVAL
);
ASSERT_EFI_ERROR (Status);
Status = gBS->CreateEvent (
EVT_SIGNAL_EXIT_BOOT_SERVICES,
TPL_CALLBACK,
MpInitExitBootServicesCallback,
NULL,
&mMpInitExitBootServicesEvent
);
ASSERT_EFI_ERROR (Status);
}
/**

View File

@ -519,6 +519,17 @@ MicrocodeDetect (
IN CPU_MP_DATA *CpuMpData
);
/**
Detect whether Mwait-monitor feature is supported.
@retval TRUE Mwait-monitor feature is supported.
@retval FALSE Mwait-monitor feature is not supported.
**/
BOOLEAN
IsMwaitSupport (
VOID
);
/**
Notify function on End Of PEI PPI.