123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989 |
- /** @file
- MP initialize support functions for DXE phase.
- Copyright (c) 2016 - 2020, Intel Corporation. All rights reserved.<BR>
- SPDX-License-Identifier: BSD-2-Clause-Patent
- **/
- #include "MpLib.h"
- #include <Library/UefiLib.h>
- #include <Library/UefiBootServicesTableLib.h>
- #include <Library/DebugAgentLib.h>
- #include <Library/DxeServicesTableLib.h>
- #include <Library/VmgExitLib.h>
- #include <Register/Amd/Fam17Msr.h>
- #include <Register/Amd/Ghcb.h>
- #include <Protocol/Timer.h>
- #define AP_SAFE_STACK_SIZE 128
- CPU_MP_DATA *mCpuMpData = NULL;
- EFI_EVENT mCheckAllApsEvent = NULL;
- EFI_EVENT mMpInitExitBootServicesEvent = NULL;
- EFI_EVENT mLegacyBootEvent = NULL;
- volatile BOOLEAN mStopCheckAllApsStatus = TRUE;
- VOID *mReservedApLoopFunc = NULL;
- UINTN mReservedTopOfApStack;
- volatile UINT32 mNumberToFinish = 0;
- //
- // Begin wakeup buffer allocation below 0x88000
- //
- STATIC EFI_PHYSICAL_ADDRESS mSevEsDxeWakeupBuffer = 0x88000;
- /**
- Enable Debug Agent to support source debugging on AP function.
- **/
- VOID
- EnableDebugAgent (
- VOID
- )
- {
- //
- // Initialize Debug Agent to support source level debug in DXE phase
- //
- InitializeDebugAgent (DEBUG_AGENT_INIT_DXE_AP, NULL, NULL);
- }
- /**
- Get the pointer to CPU MP Data structure.
- @return The pointer to CPU MP Data structure.
- **/
- CPU_MP_DATA *
- GetCpuMpData (
- VOID
- )
- {
- ASSERT (mCpuMpData != NULL);
- return mCpuMpData;
- }
- /**
- Save the pointer to CPU MP Data structure.
- @param[in] CpuMpData The pointer to CPU MP Data structure will be saved.
- **/
- VOID
- SaveCpuMpData (
- IN CPU_MP_DATA *CpuMpData
- )
- {
- mCpuMpData = CpuMpData;
- }
- /**
- Get available system memory below 0x88000 by specified size.
- @param[in] WakeupBufferSize Wakeup buffer size required
- @retval other Return wakeup buffer address below 1MB.
- @retval -1 Cannot find free memory below 1MB.
- **/
- UINTN
- GetWakeupBuffer (
- IN UINTN WakeupBufferSize
- )
- {
- EFI_STATUS Status;
- EFI_PHYSICAL_ADDRESS StartAddress;
- EFI_MEMORY_TYPE MemoryType;
- if (PcdGetBool (PcdSevEsIsEnabled)) {
- MemoryType = EfiReservedMemoryType;
- } else {
- MemoryType = EfiBootServicesData;
- }
- //
- // Try to allocate buffer below 1M for waking vector.
- // LegacyBios driver only reports warning when page allocation in range
- // [0x60000, 0x88000) fails.
- // This library is consumed by CpuDxe driver to produce CPU Arch protocol.
- // LagacyBios driver depends on CPU Arch protocol which guarantees below
- // allocation runs earlier than LegacyBios driver.
- //
- if (PcdGetBool (PcdSevEsIsEnabled)) {
- //
- // SEV-ES Wakeup buffer should be under 0x88000 and under any previous one
- //
- StartAddress = mSevEsDxeWakeupBuffer;
- } else {
- StartAddress = 0x88000;
- }
- Status = gBS->AllocatePages (
- AllocateMaxAddress,
- MemoryType,
- EFI_SIZE_TO_PAGES (WakeupBufferSize),
- &StartAddress
- );
- ASSERT_EFI_ERROR (Status);
- if (EFI_ERROR (Status)) {
- StartAddress = (EFI_PHYSICAL_ADDRESS)-1;
- } else if (PcdGetBool (PcdSevEsIsEnabled)) {
- //
- // Next SEV-ES wakeup buffer allocation must be below this allocation
- //
- mSevEsDxeWakeupBuffer = StartAddress;
- }
- DEBUG ((
- DEBUG_INFO,
- "WakeupBufferStart = %x, WakeupBufferSize = %x\n",
- (UINTN)StartAddress,
- WakeupBufferSize
- ));
- return (UINTN)StartAddress;
- }
- /**
- Get available EfiBootServicesCode memory below 4GB by specified size.
- This buffer is required to safely transfer AP from real address mode to
- protected mode or long mode, due to the fact that the buffer returned by
- GetWakeupBuffer() may be marked as non-executable.
- @param[in] BufferSize Wakeup transition buffer size.
- @retval other Return wakeup transition buffer address below 4GB.
- @retval 0 Cannot find free memory below 4GB.
- **/
- UINTN
- GetModeTransitionBuffer (
- IN UINTN BufferSize
- )
- {
- EFI_STATUS Status;
- EFI_PHYSICAL_ADDRESS StartAddress;
- StartAddress = BASE_4GB - 1;
- Status = gBS->AllocatePages (
- AllocateMaxAddress,
- EfiBootServicesCode,
- EFI_SIZE_TO_PAGES (BufferSize),
- &StartAddress
- );
- if (EFI_ERROR (Status)) {
- StartAddress = 0;
- }
- return (UINTN)StartAddress;
- }
- /**
- Return the address of the SEV-ES AP jump table.
- This buffer is required in order for an SEV-ES guest to transition from
- UEFI into an OS.
- @return Return SEV-ES AP jump table buffer
- **/
- UINTN
- GetSevEsAPMemory (
- VOID
- )
- {
- EFI_STATUS Status;
- EFI_PHYSICAL_ADDRESS StartAddress;
- MSR_SEV_ES_GHCB_REGISTER Msr;
- GHCB *Ghcb;
- BOOLEAN InterruptState;
- //
- // Allocate 1 page for AP jump table page
- //
- StartAddress = BASE_4GB - 1;
- Status = gBS->AllocatePages (
- AllocateMaxAddress,
- EfiReservedMemoryType,
- 1,
- &StartAddress
- );
- ASSERT_EFI_ERROR (Status);
- DEBUG ((DEBUG_INFO, "Dxe: SevEsAPMemory = %lx\n", (UINTN)StartAddress));
- //
- // Save the SevEsAPMemory as the AP jump table.
- //
- Msr.GhcbPhysicalAddress = AsmReadMsr64 (MSR_SEV_ES_GHCB);
- Ghcb = Msr.Ghcb;
- VmgInit (Ghcb, &InterruptState);
- VmgExit (Ghcb, SVM_EXIT_AP_JUMP_TABLE, 0, (UINT64)(UINTN)StartAddress);
- VmgDone (Ghcb, InterruptState);
- return (UINTN)StartAddress;
- }
- /**
- Checks APs status and updates APs status if needed.
- **/
- VOID
- CheckAndUpdateApsStatus (
- VOID
- )
- {
- UINTN ProcessorNumber;
- EFI_STATUS Status;
- CPU_MP_DATA *CpuMpData;
- CpuMpData = GetCpuMpData ();
- //
- // First, check whether pending StartupAllAPs() exists.
- //
- if (CpuMpData->WaitEvent != NULL) {
- Status = CheckAllAPs ();
- //
- // If all APs finish for StartupAllAPs(), signal the WaitEvent for it.
- //
- if (Status != EFI_NOT_READY) {
- Status = gBS->SignalEvent (CpuMpData->WaitEvent);
- CpuMpData->WaitEvent = NULL;
- }
- }
- //
- // Second, check whether pending StartupThisAPs() callings exist.
- //
- for (ProcessorNumber = 0; ProcessorNumber < CpuMpData->CpuCount; ProcessorNumber++) {
- if (CpuMpData->CpuData[ProcessorNumber].WaitEvent == NULL) {
- continue;
- }
- Status = CheckThisAP (ProcessorNumber);
- if (Status != EFI_NOT_READY) {
- gBS->SignalEvent (CpuMpData->CpuData[ProcessorNumber].WaitEvent);
- CpuMpData->CpuData[ProcessorNumber].WaitEvent = NULL;
- }
- }
- }
- /**
- Checks APs' status periodically.
- This function is triggered by timer periodically to check the
- state of APs for StartupAllAPs() and StartupThisAP() executed
- in non-blocking mode.
- @param[in] Event Event triggered.
- @param[in] Context Parameter passed with the event.
- **/
- VOID
- EFIAPI
- CheckApsStatus (
- IN EFI_EVENT Event,
- IN VOID *Context
- )
- {
- //
- // If CheckApsStatus() is not stopped, otherwise return immediately.
- //
- if (!mStopCheckAllApsStatus) {
- CheckAndUpdateApsStatus ();
- }
- }
- /**
- Get Protected mode code segment with 16-bit default addressing
- from current GDT table.
- @return Protected mode 16-bit code segment value.
- **/
- UINT16
- GetProtectedMode16CS (
- 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.DB == 0)) {
- break;
- }
- }
- GdtEntry++;
- }
- ASSERT (Index != GdtEntryCount);
- return Index * 8;
- }
- /**
- Get Protected mode code segment from current GDT table.
- @return Protected mode code segment value.
- **/
- UINT16
- GetProtectedModeCS (
- VOID
- )
- {
- IA32_DESCRIPTOR GdtrDesc;
- IA32_SEGMENT_DESCRIPTOR *GdtEntry;
- UINTN GdtEntryCount;
- UINT16 Index;
- 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.DB == 1)) {
- break;
- }
- }
- GdtEntry++;
- }
- ASSERT (Index != GdtEntryCount);
- 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;
- UINTN ProcessorNumber;
- UINTN StackStart;
- MpInitLibWhoAmI (&ProcessorNumber);
- CpuMpData = GetCpuMpData ();
- MwaitSupport = IsMwaitSupport ();
- if (CpuMpData->SevEsIsEnabled) {
- StackStart = CpuMpData->SevEsAPResetStackStart;
- } else {
- StackStart = mReservedTopOfApStack;
- }
- AsmRelocateApLoopFunc = (ASM_RELOCATE_AP_LOOP)(UINTN)mReservedApLoopFunc;
- AsmRelocateApLoopFunc (
- MwaitSupport,
- CpuMpData->ApTargetCState,
- CpuMpData->PmCodeSegment,
- StackStart - ProcessorNumber * AP_SAFE_STACK_SIZE,
- (UINTN)&mNumberToFinish,
- CpuMpData->Pm16CodeSegment,
- CpuMpData->SevEsAPBuffer,
- CpuMpData->WakeupBuffer
- );
- //
- // 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
- MpInitChangeApLoopCallback (
- IN EFI_EVENT Event,
- IN VOID *Context
- )
- {
- CPU_MP_DATA *CpuMpData;
- CpuMpData = GetCpuMpData ();
- CpuMpData->PmCodeSegment = GetProtectedModeCS ();
- CpuMpData->Pm16CodeSegment = GetProtectedMode16CS ();
- CpuMpData->ApLoopMode = PcdGet8 (PcdCpuApLoopMode);
- mNumberToFinish = CpuMpData->CpuCount - 1;
- WakeUpAP (CpuMpData, TRUE, 0, RelocateApLoop, NULL, TRUE);
- while (mNumberToFinish > 0) {
- CpuPause ();
- }
- if (CpuMpData->SevEsIsEnabled && (CpuMpData->WakeupBuffer != (UINTN)-1)) {
- //
- // There are APs present. Re-use reserved memory area below 1MB from
- // WakeupBuffer as the area to be used for transitioning to 16-bit mode
- // in support of booting of the AP by an OS.
- //
- CopyMem (
- (VOID *)CpuMpData->WakeupBuffer,
- (VOID *)(CpuMpData->AddressMap.RendezvousFunnelAddress +
- CpuMpData->AddressMap.SwitchToRealPM16ModeOffset),
- CpuMpData->AddressMap.SwitchToRealPM16ModeSize
- );
- }
- DEBUG ((DEBUG_INFO, "%a() done!\n", __FUNCTION__));
- }
- /**
- Initialize global data for MP support.
- @param[in] CpuMpData The pointer to CPU MP Data structure.
- **/
- VOID
- InitMpGlobalData (
- IN CPU_MP_DATA *CpuMpData
- )
- {
- EFI_STATUS Status;
- EFI_PHYSICAL_ADDRESS Address;
- UINTN ApSafeBufferSize;
- UINTN Index;
- EFI_GCD_MEMORY_SPACE_DESCRIPTOR MemDesc;
- UINTN StackBase;
- CPU_INFO_IN_HOB *CpuInfoInHob;
- SaveCpuMpData (CpuMpData);
- if (CpuMpData->CpuCount == 1) {
- //
- // If only BSP exists, return
- //
- return;
- }
- if (PcdGetBool (PcdCpuStackGuard)) {
- //
- // One extra page at the bottom of the stack is needed for Guard page.
- //
- if (CpuMpData->CpuApStackSize <= EFI_PAGE_SIZE) {
- DEBUG ((DEBUG_ERROR, "PcdCpuApStackSize is not big enough for Stack Guard!\n"));
- ASSERT (FALSE);
- }
- //
- // DXE will reuse stack allocated for APs at PEI phase if it's available.
- // Let's check it here.
- //
- // Note: BSP's stack guard is set at DxeIpl phase. But for the sake of
- // BSP/AP exchange, stack guard for ApTopOfStack of cpu 0 will still be
- // set here.
- //
- CpuInfoInHob = (CPU_INFO_IN_HOB *)(UINTN)CpuMpData->CpuInfoInHob;
- for (Index = 0; Index < CpuMpData->CpuCount; ++Index) {
- if ((CpuInfoInHob != NULL) && (CpuInfoInHob[Index].ApTopOfStack != 0)) {
- StackBase = (UINTN)CpuInfoInHob[Index].ApTopOfStack - CpuMpData->CpuApStackSize;
- } else {
- StackBase = CpuMpData->Buffer + Index * CpuMpData->CpuApStackSize;
- }
- Status = gDS->GetMemorySpaceDescriptor (StackBase, &MemDesc);
- ASSERT_EFI_ERROR (Status);
- Status = gDS->SetMemorySpaceAttributes (
- StackBase,
- EFI_PAGES_TO_SIZE (1),
- MemDesc.Attributes | EFI_MEMORY_RP
- );
- ASSERT_EFI_ERROR (Status);
- DEBUG ((
- DEBUG_INFO,
- "Stack Guard set at %lx [cpu%lu]!\n",
- (UINT64)StackBase,
- (UINT64)Index
- ));
- }
- }
- //
- // Avoid APs access invalid buffer data which allocated by BootServices,
- // so we will allocate reserved data for AP loop code. We also need to
- // allocate this buffer below 4GB due to APs may be transferred to 32bit
- // protected mode on long mode DXE.
- // Allocating it in advance since memory services are not available in
- // Exit Boot Services callback function.
- //
- ApSafeBufferSize = EFI_PAGES_TO_SIZE (
- EFI_SIZE_TO_PAGES (
- CpuMpData->AddressMap.RelocateApLoopFuncSize
- )
- );
- Address = BASE_4GB - 1;
- Status = gBS->AllocatePages (
- AllocateMaxAddress,
- EfiReservedMemoryType,
- EFI_SIZE_TO_PAGES (ApSafeBufferSize),
- &Address
- );
- ASSERT_EFI_ERROR (Status);
- mReservedApLoopFunc = (VOID *)(UINTN)Address;
- ASSERT (mReservedApLoopFunc != NULL);
- //
- // Make sure that the buffer memory is executable if NX protection is enabled
- // for EfiReservedMemoryType.
- //
- // TODO: Check EFI_MEMORY_XP bit set or not once it's available in DXE GCD
- // service.
- //
- Status = gDS->GetMemorySpaceDescriptor (Address, &MemDesc);
- if (!EFI_ERROR (Status)) {
- gDS->SetMemorySpaceAttributes (
- Address,
- ApSafeBufferSize,
- MemDesc.Attributes & (~EFI_MEMORY_XP)
- );
- }
- ApSafeBufferSize = EFI_PAGES_TO_SIZE (
- EFI_SIZE_TO_PAGES (
- CpuMpData->CpuCount * AP_SAFE_STACK_SIZE
- )
- );
- Address = BASE_4GB - 1;
- Status = gBS->AllocatePages (
- AllocateMaxAddress,
- EfiReservedMemoryType,
- EFI_SIZE_TO_PAGES (ApSafeBufferSize),
- &Address
- );
- ASSERT_EFI_ERROR (Status);
- mReservedTopOfApStack = (UINTN)Address + ApSafeBufferSize;
- ASSERT ((mReservedTopOfApStack & (UINTN)(CPU_STACK_ALIGNMENT - 1)) == 0);
- CopyMem (
- mReservedApLoopFunc,
- CpuMpData->AddressMap.RelocateApLoopFuncAddress,
- CpuMpData->AddressMap.RelocateApLoopFuncSize
- );
- Status = gBS->CreateEvent (
- EVT_TIMER | EVT_NOTIFY_SIGNAL,
- TPL_NOTIFY,
- CheckApsStatus,
- NULL,
- &mCheckAllApsEvent
- );
- ASSERT_EFI_ERROR (Status);
- //
- // Set timer to check all APs status.
- //
- Status = gBS->SetTimer (
- mCheckAllApsEvent,
- TimerPeriodic,
- EFI_TIMER_PERIOD_MICROSECONDS (
- PcdGet32 (PcdCpuApStatusCheckIntervalInMicroSeconds)
- )
- );
- ASSERT_EFI_ERROR (Status);
- Status = gBS->CreateEvent (
- EVT_SIGNAL_EXIT_BOOT_SERVICES,
- TPL_CALLBACK,
- MpInitChangeApLoopCallback,
- NULL,
- &mMpInitExitBootServicesEvent
- );
- ASSERT_EFI_ERROR (Status);
- Status = gBS->CreateEventEx (
- EVT_NOTIFY_SIGNAL,
- TPL_CALLBACK,
- MpInitChangeApLoopCallback,
- NULL,
- &gEfiEventLegacyBootGuid,
- &mLegacyBootEvent
- );
- ASSERT_EFI_ERROR (Status);
- }
- /**
- This service executes a caller provided function on all enabled APs.
- @param[in] Procedure A pointer to the function to be run on
- enabled APs of the system. See type
- EFI_AP_PROCEDURE.
- @param[in] SingleThread If TRUE, then all the enabled APs execute
- the function specified by Procedure one by
- one, in ascending order of processor handle
- number. If FALSE, then all the enabled APs
- execute the function specified by Procedure
- simultaneously.
- @param[in] WaitEvent The event created by the caller with CreateEvent()
- service. If it is NULL, then execute in
- blocking mode. BSP waits until all APs finish
- or TimeoutInMicroSeconds expires. If it's
- not NULL, then execute in non-blocking mode.
- BSP requests the function specified by
- Procedure to be started on all the enabled
- APs, and go on executing immediately. If
- all return from Procedure, or TimeoutInMicroSeconds
- expires, this event is signaled. The BSP
- can use the CheckEvent() or WaitForEvent()
- services to check the state of event. Type
- EFI_EVENT is defined in CreateEvent() in
- the Unified Extensible Firmware Interface
- Specification.
- @param[in] TimeoutInMicroseconds Indicates the time limit in microseconds for
- APs to return from Procedure, either for
- blocking or non-blocking mode. Zero means
- infinity. If the timeout expires before
- all APs return from Procedure, then Procedure
- on the failed APs is terminated. All enabled
- APs are available for next function assigned
- by MpInitLibStartupAllAPs() or
- MPInitLibStartupThisAP().
- If the timeout expires in blocking mode,
- BSP returns EFI_TIMEOUT. If the timeout
- expires in non-blocking mode, WaitEvent
- is signaled with SignalEvent().
- @param[in] ProcedureArgument The parameter passed into Procedure for
- all APs.
- @param[out] FailedCpuList If NULL, this parameter is ignored. Otherwise,
- if all APs finish successfully, then its
- content is set to NULL. If not all APs
- finish before timeout expires, then its
- content is set to address of the buffer
- holding handle numbers of the failed APs.
- The buffer is allocated by MP Initialization
- library, and it's the caller's responsibility to
- free the buffer with FreePool() service.
- In blocking mode, it is ready for consumption
- when the call returns. In non-blocking mode,
- it is ready when WaitEvent is signaled. The
- list of failed CPU is terminated by
- END_OF_CPU_LIST.
- @retval EFI_SUCCESS In blocking mode, all APs have finished before
- the timeout expired.
- @retval EFI_SUCCESS In non-blocking mode, function has been dispatched
- to all enabled APs.
- @retval EFI_UNSUPPORTED A non-blocking mode request was made after the
- UEFI event EFI_EVENT_GROUP_READY_TO_BOOT was
- signaled.
- @retval EFI_UNSUPPORTED WaitEvent is not NULL if non-blocking mode is not
- supported.
- @retval EFI_DEVICE_ERROR Caller processor is AP.
- @retval EFI_NOT_STARTED No enabled APs exist in the system.
- @retval EFI_NOT_READY Any enabled APs are busy.
- @retval EFI_NOT_READY MP Initialize Library is not initialized.
- @retval EFI_TIMEOUT In blocking mode, the timeout expired before
- all enabled APs have finished.
- @retval EFI_INVALID_PARAMETER Procedure is NULL.
- **/
- EFI_STATUS
- EFIAPI
- MpInitLibStartupAllAPs (
- IN EFI_AP_PROCEDURE Procedure,
- IN BOOLEAN SingleThread,
- IN EFI_EVENT WaitEvent OPTIONAL,
- IN UINTN TimeoutInMicroseconds,
- IN VOID *ProcedureArgument OPTIONAL,
- OUT UINTN **FailedCpuList OPTIONAL
- )
- {
- EFI_STATUS Status;
- //
- // Temporarily stop checkAllApsStatus for avoid resource dead-lock.
- //
- mStopCheckAllApsStatus = TRUE;
- Status = StartupAllCPUsWorker (
- Procedure,
- SingleThread,
- TRUE,
- WaitEvent,
- TimeoutInMicroseconds,
- ProcedureArgument,
- FailedCpuList
- );
- //
- // Start checkAllApsStatus
- //
- mStopCheckAllApsStatus = FALSE;
- return Status;
- }
- /**
- This service lets the caller get one enabled AP to execute a caller-provided
- function.
- @param[in] Procedure A pointer to the function to be run on the
- designated AP of the system. See type
- EFI_AP_PROCEDURE.
- @param[in] ProcessorNumber The handle number of the AP. The range is
- from 0 to the total number of logical
- processors minus 1. The total number of
- logical processors can be retrieved by
- MpInitLibGetNumberOfProcessors().
- @param[in] WaitEvent The event created by the caller with CreateEvent()
- service. If it is NULL, then execute in
- blocking mode. BSP waits until this AP finish
- or TimeoutInMicroSeconds expires. If it's
- not NULL, then execute in non-blocking mode.
- BSP requests the function specified by
- Procedure to be started on this AP,
- and go on executing immediately. If this AP
- return from Procedure or TimeoutInMicroSeconds
- expires, this event is signaled. The BSP
- can use the CheckEvent() or WaitForEvent()
- services to check the state of event. Type
- EFI_EVENT is defined in CreateEvent() in
- the Unified Extensible Firmware Interface
- Specification.
- @param[in] TimeoutInMicroseconds Indicates the time limit in microseconds for
- this AP to finish this Procedure, either for
- blocking or non-blocking mode. Zero means
- infinity. If the timeout expires before
- this AP returns from Procedure, then Procedure
- on the AP is terminated. The
- AP is available for next function assigned
- by MpInitLibStartupAllAPs() or
- MpInitLibStartupThisAP().
- If the timeout expires in blocking mode,
- BSP returns EFI_TIMEOUT. If the timeout
- expires in non-blocking mode, WaitEvent
- is signaled with SignalEvent().
- @param[in] ProcedureArgument The parameter passed into Procedure on the
- specified AP.
- @param[out] Finished If NULL, this parameter is ignored. In
- blocking mode, this parameter is ignored.
- In non-blocking mode, if AP returns from
- Procedure before the timeout expires, its
- content is set to TRUE. Otherwise, the
- value is set to FALSE. The caller can
- determine if the AP returned from Procedure
- by evaluating this value.
- @retval EFI_SUCCESS In blocking mode, specified AP finished before
- the timeout expires.
- @retval EFI_SUCCESS In non-blocking mode, the function has been
- dispatched to specified AP.
- @retval EFI_UNSUPPORTED A non-blocking mode request was made after the
- UEFI event EFI_EVENT_GROUP_READY_TO_BOOT was
- signaled.
- @retval EFI_UNSUPPORTED WaitEvent is not NULL if non-blocking mode is not
- supported.
- @retval EFI_DEVICE_ERROR The calling processor is an AP.
- @retval EFI_TIMEOUT In blocking mode, the timeout expired before
- the specified AP has finished.
- @retval EFI_NOT_READY The specified AP is busy.
- @retval EFI_NOT_READY MP Initialize Library is not initialized.
- @retval EFI_NOT_FOUND The processor with the handle specified by
- ProcessorNumber does not exist.
- @retval EFI_INVALID_PARAMETER ProcessorNumber specifies the BSP or disabled AP.
- @retval EFI_INVALID_PARAMETER Procedure is NULL.
- **/
- EFI_STATUS
- EFIAPI
- MpInitLibStartupThisAP (
- IN EFI_AP_PROCEDURE Procedure,
- IN UINTN ProcessorNumber,
- IN EFI_EVENT WaitEvent OPTIONAL,
- IN UINTN TimeoutInMicroseconds,
- IN VOID *ProcedureArgument OPTIONAL,
- OUT BOOLEAN *Finished OPTIONAL
- )
- {
- EFI_STATUS Status;
- //
- // temporarily stop checkAllApsStatus for avoid resource dead-lock.
- //
- mStopCheckAllApsStatus = TRUE;
- Status = StartupThisAPWorker (
- Procedure,
- ProcessorNumber,
- WaitEvent,
- TimeoutInMicroseconds,
- ProcedureArgument,
- Finished
- );
- mStopCheckAllApsStatus = FALSE;
- return Status;
- }
- /**
- This service switches the requested AP to be the BSP from that point onward.
- This service changes the BSP for all purposes. This call can only be performed
- by the current BSP.
- @param[in] ProcessorNumber The handle number of AP that is to become the new
- BSP. The range is from 0 to the total number of
- logical processors minus 1. The total number of
- logical processors can be retrieved by
- MpInitLibGetNumberOfProcessors().
- @param[in] EnableOldBSP If TRUE, then the old BSP will be listed as an
- enabled AP. Otherwise, it will be disabled.
- @retval EFI_SUCCESS BSP successfully switched.
- @retval EFI_UNSUPPORTED Switching the BSP cannot be completed prior to
- this service returning.
- @retval EFI_UNSUPPORTED Switching the BSP is not supported.
- @retval EFI_DEVICE_ERROR The calling processor is an AP.
- @retval EFI_NOT_FOUND The processor with the handle specified by
- ProcessorNumber does not exist.
- @retval EFI_INVALID_PARAMETER ProcessorNumber specifies the current BSP or
- a disabled AP.
- @retval EFI_NOT_READY The specified AP is busy.
- @retval EFI_NOT_READY MP Initialize Library is not initialized.
- **/
- EFI_STATUS
- EFIAPI
- MpInitLibSwitchBSP (
- IN UINTN ProcessorNumber,
- IN BOOLEAN EnableOldBSP
- )
- {
- EFI_STATUS Status;
- EFI_TIMER_ARCH_PROTOCOL *Timer;
- UINT64 TimerPeriod;
- TimerPeriod = 0;
- //
- // Locate Timer Arch Protocol
- //
- Status = gBS->LocateProtocol (&gEfiTimerArchProtocolGuid, NULL, (VOID **)&Timer);
- if (EFI_ERROR (Status)) {
- Timer = NULL;
- }
- if (Timer != NULL) {
- //
- // Save current rate of DXE Timer
- //
- Timer->GetTimerPeriod (Timer, &TimerPeriod);
- //
- // Disable DXE Timer and drain pending interrupts
- //
- Timer->SetTimerPeriod (Timer, 0);
- }
- Status = SwitchBSPWorker (ProcessorNumber, EnableOldBSP);
- if (Timer != NULL) {
- //
- // Enable and restore rate of DXE Timer
- //
- Timer->SetTimerPeriod (Timer, TimerPeriod);
- }
- return Status;
- }
- /**
- This service lets the caller enable or disable an AP from this point onward.
- This service may only be called from the BSP.
- @param[in] ProcessorNumber The handle number of AP.
- The range is from 0 to the total number of
- logical processors minus 1. The total number of
- logical processors can be retrieved by
- MpInitLibGetNumberOfProcessors().
- @param[in] EnableAP Specifies the new state for the processor for
- enabled, FALSE for disabled.
- @param[in] HealthFlag If not NULL, a pointer to a value that specifies
- the new health status of the AP. This flag
- corresponds to StatusFlag defined in
- EFI_MP_SERVICES_PROTOCOL.GetProcessorInfo(). Only
- the PROCESSOR_HEALTH_STATUS_BIT is used. All other
- bits are ignored. If it is NULL, this parameter
- is ignored.
- @retval EFI_SUCCESS The specified AP was enabled or disabled successfully.
- @retval EFI_UNSUPPORTED Enabling or disabling an AP cannot be completed
- prior to this service returning.
- @retval EFI_UNSUPPORTED Enabling or disabling an AP is not supported.
- @retval EFI_DEVICE_ERROR The calling processor is an AP.
- @retval EFI_NOT_FOUND Processor with the handle specified by ProcessorNumber
- does not exist.
- @retval EFI_INVALID_PARAMETER ProcessorNumber specifies the BSP.
- @retval EFI_NOT_READY MP Initialize Library is not initialized.
- **/
- EFI_STATUS
- EFIAPI
- MpInitLibEnableDisableAP (
- IN UINTN ProcessorNumber,
- IN BOOLEAN EnableAP,
- IN UINT32 *HealthFlag OPTIONAL
- )
- {
- EFI_STATUS Status;
- BOOLEAN TempStopCheckState;
- TempStopCheckState = FALSE;
- //
- // temporarily stop checkAllAPsStatus for initialize parameters.
- //
- if (!mStopCheckAllApsStatus) {
- mStopCheckAllApsStatus = TRUE;
- TempStopCheckState = TRUE;
- }
- Status = EnableDisableApWorker (ProcessorNumber, EnableAP, HealthFlag);
- if (TempStopCheckState) {
- mStopCheckAllApsStatus = FALSE;
- }
- return Status;
- }
- /**
- This funtion will try to invoke platform specific microcode shadow logic to
- relocate microcode update patches into memory.
- @param[in, out] CpuMpData The pointer to CPU MP Data structure.
- @retval EFI_SUCCESS Shadow microcode success.
- @retval EFI_OUT_OF_RESOURCES No enough resource to complete the operation.
- @retval EFI_UNSUPPORTED Can't find platform specific microcode shadow
- PPI/Protocol.
- **/
- EFI_STATUS
- PlatformShadowMicrocode (
- IN OUT CPU_MP_DATA *CpuMpData
- )
- {
- //
- // There is no DXE version of platform shadow microcode protocol so far.
- // A platform which only uses DxeMpInitLib instance could only supports
- // the PCD based microcode shadowing.
- //
- return EFI_UNSUPPORTED;
- }
|