summaryrefslogtreecommitdiff
path: root/ReferenceCode/Haswell/CpuInit/Dxe/MpService.c
diff options
context:
space:
mode:
Diffstat (limited to 'ReferenceCode/Haswell/CpuInit/Dxe/MpService.c')
-rw-r--r--ReferenceCode/Haswell/CpuInit/Dxe/MpService.c2194
1 files changed, 2194 insertions, 0 deletions
diff --git a/ReferenceCode/Haswell/CpuInit/Dxe/MpService.c b/ReferenceCode/Haswell/CpuInit/Dxe/MpService.c
new file mode 100644
index 0000000..7979618
--- /dev/null
+++ b/ReferenceCode/Haswell/CpuInit/Dxe/MpService.c
@@ -0,0 +1,2194 @@
+/** @file
+ Code which support multi-processor
+
+@copyright
+ Copyright (c) 1999 - 2013 Intel Corporation. All rights reserved
+ This software and associated documentation (if any) is furnished
+ under a license and may only be used or copied in accordance
+ with the terms of the license. Except as permitted by such
+ license, no part of this software or documentation may be
+ reproduced, stored in a retrieval system, or transmitted in any
+ form or by any means without the express written consent of
+ Intel Corporation.
+
+ This file contains an 'Intel Peripheral Driver' and is
+ licensed for Intel CPUs and chipsets under the terms of your
+ license agreement with Intel or your vendor. This file may
+ be modified by the user, subject to additional terms of the
+ license agreement
+
+**/
+#if !defined(EDK_RELEASE_VERSION) || (EDK_RELEASE_VERSION < 0x00020000)
+#include "EdkIIGlueDxe.h"
+#include "MpService.h"
+#include "PiMpService.h"
+#include "CpuInitDxe.h"
+#include "MachineCheck.h"
+#include "Features.h"
+#include "BootGuardLibrary.h"
+#endif
+
+#include EFI_PROTOCOL_DEFINITION (GenericMemoryTest)
+#include EFI_GUID_DEFINITION (GlobalVariable)
+#include EFI_PROTOCOL_DEFINITION (ExitPmAuth)
+
+extern DXE_CPU_PLATFORM_POLICY_PROTOCOL *mPlatformCpu;
+extern EFI_METRONOME_ARCH_PROTOCOL *mMetronome;
+extern MP_SYSTEM_DATA *mMPSystemData;
+extern UINTN mCommonFeatures;
+extern volatile UINTN mSwitchToLegacyRegionCount;
+extern EFI_CPU_MICROCODE_HEADER **mMicrocodePointerBuffer;
+extern EFI_DATA_HUB_PROTOCOL *mDataHub;
+
+static EFI_HANDLE mHandle = NULL;
+static UINT32 mFinishedCount = 0;
+extern UINT32 mMcuLoadCount;
+STATIC UINT64 mCpuPerfCtrlValue;
+EFI_MP_SERVICES_PROTOCOL mMpService = {
+ GetGeneralMPInfo,
+ GetProcessorContext,
+ StartupAllAPs,
+ StartupThisAP,
+ SwitchBSP,
+ SendIPI,
+ EnableDisableAP,
+ WhoAmI
+};
+
+EFI_PHYSICAL_ADDRESS mOriginalBuffer;
+EFI_PHYSICAL_ADDRESS mBackupBuffer;
+DXE_CPU_INFO_PROTOCOL mCpuInfo;
+
+/**
+ Initialize MP services by MP Service Protocol
+**/
+VOID
+EFIAPI
+InitializeMpServices (
+ VOID
+ )
+{
+ EFI_STATUS Status;
+ EFI_EVENT LegacyBootEvent;
+ EFI_EVENT ExitBootServicesEvent;
+ VOID *Registration;
+
+ LegacyBootEvent = NULL;
+ ExitBootServicesEvent = NULL;
+
+ ///
+ /// Save Mtrr Registers in global data areas
+ ///
+ ReadMtrrRegisters ();
+
+ ///
+ /// Initialize and collect MP related data
+ ///
+ Status = InitializeMpSystemData ();
+ if (EFI_ERROR (Status)) {
+ goto Done;
+ }
+
+ ///
+ /// Register protocol notifacation function for ExitPmAuth protocol
+ ///
+ EfiCreateProtocolNotifyEvent (
+ &gExitPmAuthProtocolGuid,
+ TPL_NOTIFY,
+ ReAllocateMemoryForAP,
+ NULL,
+ &Registration
+ );
+
+ ///
+ /// Register protocol notifaction function to allocate memory in EBDA as early as possible
+ ///
+ EfiCreateProtocolNotifyEvent (
+ &gEfiLegacyBiosProtocolGuid,
+ TPL_NOTIFY,
+ ReAllocateEbdaMemoryForAP,
+ NULL,
+ &Registration
+ );
+
+ ///
+ /// Create legacy boot and EFI boot events to reset APs before OS handoff
+ ///
+ Status = EfiCreateEventLegacyBootEx (
+ EFI_TPL_CALLBACK,
+ ResetAPs,
+ mMPSystemData,
+ &LegacyBootEvent
+ );
+ if (EFI_ERROR (Status)) {
+ goto Done;
+ }
+
+ Status = gBS->CreateEvent (
+ EVENT_SIGNAL_EXIT_BOOT_SERVICES,
+ TPL_CALLBACK,
+ ResetAPs,
+ mMPSystemData,
+ &ExitBootServicesEvent
+ );
+ if (EFI_ERROR (Status)) {
+ goto Done;
+ }
+
+ ///
+ /// Create timer event to check AP state for non-blocking execution.
+ ///
+ Status = gBS->CreateEvent (
+ EFI_EVENT_TIMER | EFI_EVENT_NOTIFY_SIGNAL,
+ EFI_TPL_CALLBACK,
+ CheckAPsStatus,
+ NULL,
+ &mMPSystemData->CheckAPsEvent
+ );
+ ASSERT_EFI_ERROR (Status);
+
+ ///
+ /// Now install the Frameowrk & PI MP services protocol.
+ ///
+ Status = gBS->InstallMultipleProtocolInterfaces (
+ &mHandle,
+ &gEfiMpServiceProtocolGuid,
+ &mMpService,
+ &gEfiPiMpServiceProtocolGuid,
+ &mPiMpService,
+ NULL
+ );
+ ASSERT_EFI_ERROR (Status);
+
+ Status = gBS->SetTimer (
+ mMPSystemData->CheckAPsEvent,
+ TimerPeriodic,
+ 10000 * MICROSECOND
+ );
+ ASSERT_EFI_ERROR (Status);
+
+ if (EFI_ERROR (Status)) {
+
+Done:
+ if (LegacyBootEvent != NULL) {
+ gBS->CloseEvent (LegacyBootEvent);
+ }
+
+ if (ExitBootServicesEvent != NULL) {
+ gBS->CloseEvent (ExitBootServicesEvent);
+ }
+
+ FreePool (mMPSystemData);
+ }
+}
+
+/**
+ Get general MP information
+
+ @param[in] This - EFI_MP_SERVICE_PROTOCOL
+ @param[in] NumberOfCPUs - Number of processors
+ @param[in] MaximumNumberOfCPUs - Max supported number of processors
+ @param[in] NumberOfEnabledCPUs - Number of processors enabled
+ @param[in] RendezvousIntNumber - number of Rendezvous procedure
+ @param[in] RendezvousProcLength - length of Rendezvous procedure
+
+ @retval EFI_SUCCESS - always return success
+**/
+EFI_STATUS
+EFIAPI
+GetGeneralMPInfo (
+ IN EFI_MP_SERVICES_PROTOCOL *This,
+ OUT UINTN *NumberOfCPUs,
+ OUT UINTN *MaximumNumberOfCPUs,
+ OUT UINTN *NumberOfEnabledCPUs,
+ OUT UINTN *RendezvousIntNumber,
+ OUT UINTN *RendezvousProcLength
+ )
+{
+ UINTN Index;
+ CPU_DATA_BLOCK *CpuData;
+
+ if (NumberOfCPUs) {
+ *NumberOfCPUs = mMPSystemData->NumberOfCpus;
+ }
+
+ if (MaximumNumberOfCPUs) {
+ *MaximumNumberOfCPUs = mMPSystemData->MaximumCpusForThisSystem;
+ }
+
+ if (RendezvousProcLength) {
+ *RendezvousProcLength = RENDEZVOUS_PROC_LENGTH;
+ }
+
+ if (RendezvousIntNumber) {
+ *RendezvousIntNumber = 0;
+ }
+
+ if (NumberOfEnabledCPUs) {
+ *NumberOfEnabledCPUs = 0;
+ for (Index = 0; Index < mMPSystemData->NumberOfCpus; Index++) {
+ CpuData = &mMPSystemData->CpuData[Index];
+ if (mMPSystemData->EnableSecondaryCpu) {
+ if (CpuData->State != CPU_STATE_DISABLED) {
+ (*NumberOfEnabledCPUs)++;
+ }
+ } else {
+ if (CpuData->State != CPU_STATE_DISABLED && !mMPSystemData->CpuData[Index].SecondaryCpu) {
+ (*NumberOfEnabledCPUs)++;
+ }
+ }
+ }
+ }
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Get processor context
+
+ @param[in] This - EFI_MP_SERVICE_PROTOCOL
+ @param[in] CpuNumber - Cpu number
+ @param[in] BufferLength - buffer length
+ @param[in] ProcessorContextBuffer - pointer to the buffer that will be updated
+
+ @retval EFI_INVALID_PARAMETER - buffer is NULL or CpuNumber our of range
+ @retval EFI_BUFFER_TOO_SMALL - buffer too small
+ @retval EFI_SUCCESS - got processor context successfully
+**/
+EFI_STATUS
+EFIAPI
+GetProcessorContext (
+ IN EFI_MP_SERVICES_PROTOCOL *This,
+ IN UINTN CpuNumber,
+ IN OUT UINTN *BufferLength,
+ IN OUT EFI_MP_PROC_CONTEXT *ProcessorContextBuffer
+ )
+{
+ EFI_MP_PROC_CONTEXT *ProcessorBuffer;
+ CPU_DATA_BLOCK *CpuData;
+
+ if (BufferLength == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if (*BufferLength < sizeof (EFI_MP_PROC_CONTEXT)) {
+ *BufferLength = sizeof (EFI_MP_PROC_CONTEXT);
+ return EFI_BUFFER_TOO_SMALL;
+ }
+
+ if ((mMPSystemData->NumberOfCpus <= CpuNumber) || (ProcessorContextBuffer == NULL)) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ CpuData = &mMPSystemData->CpuData[CpuNumber];
+
+ *BufferLength = sizeof (EFI_MP_PROC_CONTEXT);
+ ProcessorBuffer = ProcessorContextBuffer;
+
+ ProcessorBuffer->ApicID = CpuData->ApicID;
+
+ ProcessorBuffer->Enabled = TRUE;
+ if (!mMPSystemData->EnableSecondaryCpu) {
+ if (CpuData->SecondaryCpu) {
+ ProcessorBuffer->Enabled = FALSE;
+ }
+ }
+
+ if (CpuData->State == CPU_STATE_DISABLED) {
+ ProcessorBuffer->Enabled = FALSE;
+ }
+
+ if (CpuNumber == mMPSystemData->BSP) {
+ ProcessorBuffer->Designation = EfiCpuBSP;
+ } else {
+ ProcessorBuffer->Designation = EfiCpuAP;
+ }
+
+ ProcessorBuffer->Health.Flags = CpuData->Health;
+ ProcessorBuffer->Health.TestStatus = 0;
+
+ ProcessorBuffer->PackageNumber = CpuData->CpuDataforDatahub.Location.Package;
+ ProcessorBuffer->NumberOfCores = CpuData->CpuDataforDatahub.Location.Core;
+ ProcessorBuffer->NumberOfThreads = CpuData->CpuDataforDatahub.Location.Thread;
+ ProcessorBuffer->ProcessorTestMask = 0;
+
+ return EFI_SUCCESS;
+}
+
+/**
+ MP Service to get specified application processor (AP)
+ to execute a caller-provided code stream.
+
+ @param[in] This - Pointer to MP Service Protocol
+ @param[in] Procedure - The procedure to be assigned to AP.
+ @param[in] CpuNumber - Number of the specified processor.
+ @param[in] WaitEvent - If timeout, the event to be triggered after this AP finishes.
+ @param[in] TimeoutInMicroSecs - The timeout value in microsecond. Zero means infinity.
+ @param[in] ProcArguments - Argument for Procedure.
+
+ @retval EFI_INVALID_PARAMETER - Procudure is NULL.
+ @retval EFI_INVALID_PARAMETER - Number of CPU out of range, or it belongs to BSP.
+ @retval EFI_INVALID_PARAMETER - Specified CPU is not idle.
+ @retval EFI_SUCCESS - The AP has finished.
+ @retval EFI_TIMEOUT - Time goes out before the AP has finished.
+**/
+EFI_STATUS
+EFIAPI
+StartupThisAP (
+ IN EFI_MP_SERVICES_PROTOCOL *This,
+ IN EFI_AP_PROCEDURE Procedure,
+ IN UINTN CpuNumber,
+ IN EFI_EVENT WaitEvent OPTIONAL,
+ IN UINTN TimeoutInMicroSecs OPTIONAL,
+ IN OUT VOID *ProcArguments OPTIONAL
+ )
+{
+ EFI_STATUS Status;
+ CPU_DATA_BLOCK *CpuData;
+ UINT64 ExpectedTime;
+
+ ///
+ /// Check for invalid CPU number
+ ///
+ if ((CpuNumber >= mMPSystemData->NumberOfCpus) || CpuNumber == mMPSystemData->BSP) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if (Procedure == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ CpuData = &mMPSystemData->CpuData[CpuNumber];
+
+ ///
+ /// As a first step, check if processor is OK to start up code stream.
+ ///
+ if (CpuData->State != CPU_STATE_IDLE) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ ExpectedTime = CalculateTimeout (TimeoutInMicroSecs);
+
+ mMPSystemData->StartCount = 1;
+ mMPSystemData->FinishCount = 0;
+
+ WakeUpAp (
+ CpuData,
+ Procedure,
+ ProcArguments
+ );
+
+ while (TRUE) {
+ AsmAcquireMPLock (&CpuData->StateLock);
+ if (CpuData->State == CPU_STATE_FINISHED) {
+ CpuData->State = CPU_STATE_IDLE;
+ AsmReleaseMPLock (&CpuData->StateLock);
+ break;
+ }
+
+ AsmReleaseMPLock (&CpuData->StateLock);
+
+ if (CheckTimeout (ExpectedTime)) {
+ ///
+ /// Save data into private data structure, and create timer to poll AP state before exiting
+ ///
+ mMPSystemData->WaitEvent = WaitEvent;
+ Status = gBS->SetTimer (
+ CpuData->CheckThisAPEvent,
+ TimerPeriodic,
+ CPU_CHECK_AP_INTERVAL * MICROSECOND
+ );
+ return EFI_TIMEOUT;
+ }
+
+ gBS->Stall (CPU_CHECK_AP_INTERVAL);
+ }
+
+ if (WaitEvent) gBS->SignalEvent (WaitEvent); //(AMI_CHG)
+ return EFI_SUCCESS;
+}
+
+/**
+ MP Service to get all the available application processors (APs)
+ to execute a caller-provided code stream.
+
+ @param[in] This - Pointer to MP Service Protocol
+ @param[in] Procedure - The procedure to be assigned to APs.
+ @param[in] SingleThread - If true, all APs execute in block mode.
+ Otherwise, all APs exceute in non-block mode.
+ @param[in] WaitEvent - If timeout, the event to be triggered after all APs finish.
+ @param[in] TimeoutInMicroSecs - The timeout value in microsecond. Zero means infinity.
+ @param[in] ProcArguments - Argument for Procedure.
+ @param[in] FailedCPUList - If not NULL, all APs that fail to start will be recorded in the list.
+
+ @retval EFI_INVALID_PARAMETER - Procudure is NULL.
+ @retval EFI_SUCCESS - Only 1 logical processor exists.
+ @retval EFI_SUCCESS - All APs have finished.
+ @retval EFI_TIMEOUT - Time goes out before all APs have finished.
+**/
+EFI_STATUS
+EFIAPI
+StartupAllAPs (
+ IN EFI_MP_SERVICES_PROTOCOL *This,
+ IN EFI_AP_PROCEDURE Procedure,
+ IN BOOLEAN SingleThread,
+ IN EFI_EVENT WaitEvent OPTIONAL,
+ IN UINTN TimeoutInMicroSecs OPTIONAL,
+ IN OUT VOID *ProcArguments OPTIONAL,
+ OUT UINTN *FailedCPUList OPTIONAL
+ )
+{
+ EFI_STATUS Status;
+ CPU_DATA_BLOCK *CpuData;
+ CPU_DATA_BLOCK *NextCpuData;
+ UINTN ListIndex;
+ UINTN CpuNumber;
+ UINTN NextCpuNumber;
+ UINT64 ExpectedTime;
+ CPU_STATE APInitialState;
+ CPU_STATE CpuState;
+
+ ///
+ /// Check for valid procedure for APs
+ ///
+ if (Procedure == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if (mMPSystemData->NumberOfCpus == 1) {
+ if (WaitEvent) gBS->SignalEvent (WaitEvent); //(AMI_CHG)
+ return EFI_SUCCESS;
+ }
+
+// AMI Override: Add
+ //
+ // Check whether all enabled APs are idle.
+ // If any enabled AP is not idle, return EFI_NOT_READY.
+ //
+ for (CpuNumber = 0; CpuNumber < mMPSystemData->NumberOfCpus; CpuNumber++) {
+
+ CpuData = &mMPSystemData->CpuData[CpuNumber];
+
+ //
+ // Skip BSP and disabled APs.
+ //
+ if (CpuNumber == mMPSystemData->BSP ||
+ CpuData->State == CPU_STATE_DISABLED) {
+ continue;
+ }
+
+ //
+ // If any enabled APs are busy, return EFI_NOT_FOUND.
+ //
+ if (CpuData->State != CPU_STATE_IDLE) {
+ return EFI_NOT_READY;
+ }
+ }
+ //
+ // All enabled APs are idle, we can safely initiate a new session
+ //
+// AMI Override: End
+ ExpectedTime = CalculateTimeout (TimeoutInMicroSecs);
+
+ ListIndex = 0;
+ CpuData = NULL;
+
+ mMPSystemData->FinishCount = 0;
+ mMPSystemData->StartCount = 0;
+ APInitialState = CPU_STATE_READY;
+
+ for (CpuNumber = 0; CpuNumber < mMPSystemData->NumberOfCpus; CpuNumber++) {
+ CpuData = &mMPSystemData->CpuData[CpuNumber];
+
+ ///
+ /// Get APs prepared, and put failing APs into FailedCPUList
+ /// If "SingleThread", one AP will be put to ready state.
+ /// Once this AP finishes its task, the next AP is put to Ready state.
+ /// This process continues until all APs are put into Ready State
+ /// if not "SingleThread", all APs are put to ready state at the same time
+ ///
+ if (CpuNumber != mMPSystemData->BSP) {
+ if (CpuData->State == CPU_STATE_IDLE) {
+ mMPSystemData->StartCount++;
+
+ AsmAcquireMPLock (&CpuData->StateLock);
+ CpuData->State = APInitialState;
+ AsmReleaseMPLock (&CpuData->StateLock);
+
+ if (SingleThread) {
+ APInitialState = CPU_STATE_BLOCKED;
+ }
+
+ } else if (FailedCPUList != NULL) {
+ FailedCPUList[ListIndex] = CpuNumber;
+ ListIndex++;
+ }
+ }
+ }
+
+ while (TRUE) {
+ for (CpuNumber = 0; CpuNumber < mMPSystemData->NumberOfCpus; CpuNumber++) {
+ CpuData = &mMPSystemData->CpuData[CpuNumber];
+ if (CpuNumber == mMPSystemData->BSP) {
+ continue;
+ }
+ CpuState = CpuData->State;
+ switch (CpuState) {
+ case CPU_STATE_READY:
+ WakeUpAp (
+ CpuData,
+ Procedure,
+ ProcArguments
+ );
+ break;
+
+ case CPU_STATE_FINISHED:
+ mMPSystemData->FinishCount++;
+ if (SingleThread) {
+ Status = GetNextBlockedCpuNumber (&NextCpuNumber);
+ if (!EFI_ERROR (Status)) {
+ NextCpuData = &mMPSystemData->CpuData[NextCpuNumber];
+ AsmAcquireMPLock (&NextCpuData->StateLock);
+ NextCpuData->State = CPU_STATE_READY;
+ AsmReleaseMPLock (&NextCpuData->StateLock);
+ }
+ }
+ AsmAcquireMPLock (&CpuData->StateLock);
+ CpuData->State = CPU_STATE_IDLE;
+ AsmReleaseMPLock (&CpuData->StateLock);
+ break;
+
+ default:
+ break;
+ }
+ }
+
+ if (mMPSystemData->FinishCount == mMPSystemData->StartCount) {
+ if (WaitEvent) gBS->SignalEvent (WaitEvent); //(AMI_CHG)
+ return EFI_SUCCESS;
+ }
+
+ if (CheckTimeout (ExpectedTime)) {
+ ///
+ /// Save data into private data structure, and create timer to poll AP state before exiting
+ ///
+ mMPSystemData->Procedure = Procedure;
+ mMPSystemData->ProcArguments = ProcArguments;
+ mMPSystemData->SingleThread = SingleThread;
+ mMPSystemData->WaitEvent = WaitEvent;
+
+ Status = gBS->SetTimer (
+ mMPSystemData->CheckAllAPsEvent,
+ TimerPeriodic,
+ CPU_CHECK_AP_INTERVAL * MICROSECOND
+ );
+ return EFI_TIMEOUT;
+ }
+
+ gBS->Stall (CPU_CHECK_AP_INTERVAL);
+ }
+
+ if (WaitEvent) gBS->SignalEvent (WaitEvent); //(AMI_CHG)
+ return EFI_SUCCESS;
+}
+
+/**
+ MP Service to makes the current BSP into an AP and then switches the
+ designated AP into the AP. This procedure is usually called after a CPU
+ test that has found that BSP is not healthy to continue it's responsbilities.
+
+ @param[in] This - Pointer to MP Service Protocol.
+ @param[in] CpuNumber - The number of the specified AP.
+ @param[in] EnableOldBSP - Whether to enable or disable the original BSP.
+
+ @retval EFI_INVALID_PARAMETER - Number for Specified AP out of range.
+ @retval EFI_INVALID_PARAMETER - Number of specified CPU belongs to BSP.
+ @retval EFI_NOT_READY - Specified AP is not idle.
+ @retval EFI_SUCCESS - BSP successfully switched.
+**/
+EFI_STATUS
+EFIAPI
+SwitchBSP (
+ IN EFI_MP_SERVICES_PROTOCOL *This,
+ IN UINTN CpuNumber,
+ IN BOOLEAN EnableOldBSP
+ )
+{
+ EFI_STATUS Status;
+ EFI_CPU_ARCH_PROTOCOL *CpuArch;
+ BOOLEAN OldInterruptState;
+ CPU_DATA_BLOCK *CpuData;
+ CPU_STATE CpuState;
+
+ ///
+ /// Check if the specified CPU number is valid
+ ///
+ if (CpuNumber >= mMPSystemData->NumberOfCpus) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ ///
+ /// Check if the specified CPU is already BSP
+ ///
+ if (CpuNumber == mMPSystemData->BSP) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ CpuData = &mMPSystemData->CpuData[CpuNumber];
+ if (CpuData->State != CPU_STATE_IDLE) {
+ return EFI_NOT_READY;
+ }
+ ///
+ /// Before send both BSP and AP to a procedure to exchange their roles,
+ /// interrupt must be disabled. This is because during the exchange role
+ /// process, 2 CPU may use 1 stack. If interrupt happens, the stack will
+ /// be corrputed, since interrupt return address will be pushed to stack
+ /// by hardware.
+ ///
+ CpuArch = mMPSystemData->CpuArch;
+ (CpuArch->GetInterruptState)(CpuArch, &OldInterruptState);
+ if (OldInterruptState) {
+ Status = CpuArch->DisableInterrupt (CpuArch);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+ }
+
+ ///
+ /// Unprogram virtual wire mode for the old BSP
+ ///
+ ProgramXApic (FALSE);
+ SetApicBSPBit (FALSE);
+
+ mMPSystemData->BSPInfo.State = CPU_SWITCH_STATE_IDLE;
+ mMPSystemData->BSPInfo.Lock = VacantFlag;
+ mMPSystemData->APInfo.State = CPU_SWITCH_STATE_IDLE;
+ mMPSystemData->APInfo.Lock = VacantFlag;
+
+ ///
+ /// Need to wakeUp AP (future BSP)
+ ///
+ WakeUpAp (
+ CpuData,
+ FutureBSPProc,
+ mMPSystemData
+ );
+
+ AsmExchangeRole (&mMPSystemData->BSPInfo, &mMPSystemData->APInfo);
+
+ ///
+ /// The new BSP has come out. Since it carries the register value of the AP, need
+ /// to pay attention to variable which are stored in registers (due to optimization)
+ ///
+ SetApicBSPBit (TRUE);
+ ProgramXApic (TRUE);
+
+ if (OldInterruptState) {
+ Status = CpuArch->EnableInterrupt (CpuArch);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+ }
+
+ CpuData = &mMPSystemData->CpuData[mMPSystemData->BSP];
+ while (TRUE) {
+ AsmAcquireMPLock (&CpuData->StateLock);
+ CpuState = CpuData->State;
+ AsmReleaseMPLock (&CpuData->StateLock);
+
+ if (CpuState == CPU_STATE_FINISHED) {
+ break;
+ }
+ }
+
+ Status = ChangeCpuState (mMPSystemData->BSP, EnableOldBSP, CPU_CAUSE_NOT_DISABLED);
+ mMPSystemData->BSP = CpuNumber;
+
+ return EFI_SUCCESS;
+}
+
+/**
+ This procedure sends an IPI to the designated processor in
+ the requested delivery mode with the requested vector.
+
+ @param[in] This - Pointer to MP Service Protocol.
+ @param[in] CpuNumber - The number of the specified AP.
+ @param[in] VectorNumber - Vector number.
+ @param[in] DeliveryMode - I/O APIC Interrupt Deliver Modes
+
+ @retval EFI_INVALID_PARAMETER - Input paramters were not correct.
+ @retval Other status - Status returned by SendInterrupt ()
+**/
+EFI_STATUS
+EFIAPI
+SendIPI (
+ IN EFI_MP_SERVICES_PROTOCOL *This,
+ IN UINTN CpuNumber,
+ IN UINTN VectorNumber,
+ IN UINTN DeliveryMode
+ )
+{
+ UINT32 TriggerMode;
+ EFI_STATUS Status;
+ CPU_DATA_BLOCK *CpuData;
+ MP_CPU_EXCHANGE_INFO *ExchangeInfo;
+ MONITOR_MWAIT_DATA *MonitorAddr;
+
+ ///
+ /// Check for valid input parameters.
+ ///
+ if (CpuNumber >= mMPSystemData->NumberOfCpus || CpuNumber == mMPSystemData->BSP) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if (VectorNumber >= INTERRUPT_VECTOR_NUMBER) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if (DeliveryMode >= DELIVERY_MODE_MAX) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ CpuData = &mMPSystemData->CpuData[CpuNumber];
+ TriggerMode = TRIGGER_MODE_EDGE;
+
+ ///
+ /// Fix the vector number for special interrupts like SMI and INIT.
+ ///
+ if (DeliveryMode == DELIVERY_MODE_SMI || DeliveryMode == DELIVERY_MODE_INIT) {
+ VectorNumber = 0x0;
+ }
+
+ ///
+ /// If current waking manner is not HLT loop and some other DXE driver
+ /// like as TXT needs to send INIT command per this MpService routine,
+ /// then we need to set vector change flag for the specific AP to back
+ /// to MWAIT or RUN loop procedure, so additional INIT-SIPI command
+ /// will be sent in WakeUpAp routine for AP tasks to work later.
+ ///
+ ExchangeInfo = (MP_CPU_EXCHANGE_INFO *) (UINTN) (mAcpiCpuData->WakeUpBuffer + MP_CPU_EXCHANGE_INFO_OFFSET);
+ if (ExchangeInfo->WakeUpApManner != WakeUpApPerHltLoop && DeliveryMode == DELIVERY_MODE_INIT) {
+ MonitorAddr = (MONITOR_MWAIT_DATA *)
+ (
+ (UINT8 *) ExchangeInfo->StackStart +
+ (ExchangeInfo->BistBuffer[CpuData->ApicID].Number + 1) *
+ ExchangeInfo->StackSize -
+ MONITOR_FILTER_SIZE
+ );
+ MonitorAddr->WakeUpApVectorChangeFlag = TRUE;
+ }
+
+ Status = SendInterrupt (
+ BROADCAST_MODE_SPECIFY_CPU,
+ CpuData->ApicID,
+ (UINT32) VectorNumber,
+ (UINT32) DeliveryMode,
+ TriggerMode,
+ TRUE
+ );
+
+ return Status;
+}
+
+/**
+ This procedure enables Or disables APs.
+
+ @param[in] This - Pointer to MP Service Protocol.
+ @param[in] CpuNumber - The number of the specified AP.
+ @param[in] NewAPState - Indicate new desired AP state
+ @param[in] HealthState - If not NULL, it points to the value that specifies
+ the new health status of the AP. If it is NULL,
+ this parameter is ignored.
+
+ @retval EFI_INVALID_PARAMETER - Input paramters were not correct.
+ @retval EFI_SUCCESS - Function completed successfully
+**/
+EFI_STATUS
+EFIAPI
+EnableDisableAP (
+ IN EFI_MP_SERVICES_PROTOCOL *This,
+ IN UINTN CpuNumber,
+ IN BOOLEAN NewAPState,
+ IN EFI_MP_HEALTH *HealthState OPTIONAL
+ )
+{
+ EFI_STATUS Status;
+ CPU_DATA_BLOCK *CpuData;
+
+ ///
+ /// Check for valid input parameters.
+ ///
+ if (CpuNumber >= mMPSystemData->NumberOfCpus || CpuNumber == mMPSystemData->BSP) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ CpuData = &mMPSystemData->CpuData[CpuNumber];
+ Status = ChangeCpuState (CpuNumber, NewAPState, CPU_CAUSE_USER_SELECTION);
+
+ if (HealthState != NULL) {
+ CopyMem (&CpuData->Health, HealthState, sizeof (EFI_MP_HEALTH));
+ }
+
+ return EFI_SUCCESS;
+}
+
+/**
+ This procedure returns the calling CPU handle.
+
+ @param[in] This - Pointer to MP Service Protocol.
+ @param[in] CpuNumber - The number of the specified AP.
+
+ @retval EFI_SUCCESS - Function completed successfully
+**/
+EFI_STATUS
+EFIAPI
+WhoAmI (
+ IN EFI_MP_SERVICES_PROTOCOL *This,
+ OUT UINTN *CpuNumber
+ )
+{
+ UINTN ApicID;
+ UINTN NumOfCpus;
+ UINTN Index;
+
+ ApicID = GetApicID (NULL, NULL);
+
+ NumOfCpus = mMPSystemData->NumberOfCpus;
+
+ for (Index = 0; Index < NumOfCpus; Index++) {
+ if (ApicID == mMPSystemData->CpuData[Index].ApicID) {
+ break;
+ }
+ }
+
+ *CpuNumber = Index;
+ return EFI_SUCCESS;
+}
+
+/**
+ Searches the HOB list provided by the core to find
+ if a MP guided HOB list exists or not. If it does, it copies it to the driver
+ data area, else returns 0
+
+ @param[in] MPSystemData - Pointer to an MP_SYSTEM_DATA structure
+
+ @retval EFI_SUCCESS - Success
+ @retval EFI_NOT_FOUND - HOB not found or else
+**/
+EFI_STATUS
+GetMpBistStatus (
+ IN MP_SYSTEM_DATA *MPSystemData
+ )
+{
+ VOID *HobList;
+ VOID *DataInHob;
+ EFI_PEI_HOB_POINTERS Hob;
+ UINTN DataSize;
+
+ ///
+ /// Check for MP Data Hob.
+ ///
+ HobList = GetFirstGuidHob (&gEfiHtBistHobGuid);
+
+ if (HobList == NULL) {
+ DEBUG ((EFI_D_ERROR, "No HOBs found\n"));
+ return EFI_NOT_FOUND;
+ }
+
+ DataInHob = (VOID *) ((UINTN) HobList + sizeof (EFI_HOB_GUID_TYPE));
+
+ Hob.Header = HobList;
+ DataSize = Hob.Header->HobLength - sizeof (EFI_HOB_GUID_TYPE);
+
+ ///
+ /// This is the MP HOB. So, copy all the data
+ ///
+ if (HobList != NULL) {
+ if (NULL == MPSystemData->BistHobData) {
+ (gBS->AllocatePool)(EfiReservedMemoryType, DataSize, (VOID **) &MPSystemData->BistHobData);
+ }
+
+ CopyMem (MPSystemData->BistHobData, DataInHob, DataSize);
+ MPSystemData->BistHobSize = DataSize;
+ }
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Check if CPUID support large than 3
+
+ @retval TRUE if CPUID support large than 3
+ @retval FALSE if not
+**/
+BOOLEAN
+IsCpuidSupportOver3 (
+ VOID
+ )
+{
+ BOOLEAN RetVal;
+ EFI_CPUID_REGISTER CpuidRegisters;
+ RetVal = FALSE;
+ AsmCpuid (
+ CPUID_SIGNATURE,
+ &CpuidRegisters.RegEax,
+ &CpuidRegisters.RegEbx,
+ &CpuidRegisters.RegEcx,
+ &CpuidRegisters.RegEdx
+ );
+ if (CpuidRegisters.RegEax > 3) {
+ RetVal = TRUE;
+ }
+
+ return RetVal;
+}
+
+/**
+ Allocate data pool for MP information and fill data in it.
+
+ @param[in] WakeUpBuffer - The address of wakeup buffer.
+ @param[in] StackAddressStart - The start address of APs's stacks.
+ @param[in] MaximumCPUsForThisSystem - Maximum CPUs in this system.
+
+ @retval EFI_SUCCESS - Function successfully executed.
+ @retval Other - Error occurred while allocating memory.
+**/
+EFI_STATUS
+FillMPData (
+ OUT EFI_PHYSICAL_ADDRESS WakeUpBuffer,
+ OUT VOID *StackAddressStart,
+ IN UINTN MaximumCPUsForThisSystem
+ )
+{
+ EFI_STATUS Status;
+
+ ///
+ /// First check if the MP data structures and AP rendezvous routine have been
+ /// supplied by the PEIMs that executed in early boot stage.
+ ///
+ ///
+ /// Clear the data structure area first.
+ ///
+ ZeroMem (mMPSystemData, sizeof (MP_SYSTEM_DATA));
+
+ Status = GetMpBistStatus (mMPSystemData);
+
+ mAcpiCpuData->CpuPrivateData = (EFI_PHYSICAL_ADDRESS) (UINTN) (&(mMPSystemData->S3DataPointer));
+ mAcpiCpuData->APState = mPlatformCpu->CpuConfig->HtState;
+ mAcpiCpuData->WakeUpBuffer = WakeUpBuffer;
+ mAcpiCpuData->StackAddress = (EFI_PHYSICAL_ADDRESS) StackAddressStart;
+
+ Status = PrepareGdtIdtForAP (
+ (PSEUDO_DESCRIPTOR *) (UINTN) mAcpiCpuData->GdtrProfile,
+ (PSEUDO_DESCRIPTOR *) (UINTN) mAcpiCpuData->IdtrProfile
+ );
+
+ ///
+ /// First BSP fills and inits all known values, including it's own records.
+ ///
+ mMPSystemData->APSerializeLock = VacantFlag;
+ mMPSystemData->NumberOfCpus = 1;
+ mMPSystemData->EnableSecondaryCpu = mPlatformCpu->CpuConfig->HtState;
+
+ ///
+ /// Record these CPU configuration data (both for normal boot and for S3 use)
+ ///
+ if (IsCpuidSupportOver3 ()) {
+ mMPSystemData->LimitCpuidMaximumValue = mPlatformCpu->CpuConfig->LimitCpuidMaximumValue;
+ } else {
+ mMPSystemData->LimitCpuidMaximumValue = FALSE;
+ }
+
+ mMPSystemData->ExecuteDisableBit = mPlatformCpu->CpuConfig->ExecuteDisableBit;
+ mMPSystemData->VmxEnable = mPlatformCpu->CpuConfig->VmxEnable;
+ mMPSystemData->TxtEnable = mPlatformCpu->CpuConfig->SmxEnable;
+ mMPSystemData->MonitorMwaitEnable = mPlatformCpu->CpuConfig->MonitorMwaitEnable;
+ mMPSystemData->MachineCheckEnable = mPlatformCpu->CpuConfig->MachineCheckEnable;
+ mMPSystemData->XapicEnable = mPlatformCpu->CpuConfig->XapicEnable;
+ mMPSystemData->AesEnable = mPlatformCpu->CpuConfig->AesEnable;
+ mMPSystemData->DebugInterfaceEnable = 0;
+ mMPSystemData->DebugInterfaceLockEnable = 1;
+ if (mPlatformCpu->Revision >= DXE_PLATFORM_CPU_POLICY_PROTOCOL_REVISION_2) {
+ mMPSystemData->DebugInterfaceEnable = mPlatformCpu->CpuConfig->DebugInterfaceEnable;
+ mMPSystemData->DebugInterfaceLockEnable = mPlatformCpu->CpuConfig->DebugInterfaceLockEnable;
+ }
+
+ mMPSystemData->S3DataPointer.S3BootScriptTable = (UINT32) (UINTN) mMPSystemData->S3BootScriptTable;
+ mMPSystemData->S3DataPointer.S3BspMtrrTable = (UINT32) (UINTN) mMPSystemData->S3BspMtrrTable;
+
+ mMPSystemData->CpuArch = NULL;
+ gBS->LocateProtocol (&gEfiCpuArchProtocolGuid, NULL, (VOID **) &mMPSystemData->CpuArch);
+
+ mMPSystemData->MaximumCpusForThisSystem = MaximumCPUsForThisSystem;
+
+ mMPSystemData->BSP = 0;
+
+ ///
+ /// Save Mtrr Register for S3 resume
+ ///
+ SaveBspMtrrForS3 ();
+
+ FillInProcessorInformation (mMPSystemData, TRUE, 0);
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Wake up APs for the first time to count their number and collect BIST data.
+
+ @param[in] WakeUpBuffer - Address of the wakeup buffer.
+
+ @retval EFI_SUCCESS - Function successfully finishes.
+**/
+EFI_STATUS
+CountApNumberAndCollectBist (
+ IN EFI_PHYSICAL_ADDRESS WakeUpBuffer
+ )
+{
+ MP_CPU_EXCHANGE_INFO *ExchangeInfo;
+ UINTN Index;
+ UINT64 MsrValue;
+ UINT64 ProcessorThreadCount;
+ UINT32 ResponseProcessorCount;
+ UINTN TimeoutTime;
+
+ ///
+ /// Send INIT IPI - SIPI to all APs
+ ///
+ SendInterrupt (
+ BROADCAST_MODE_ALL_EXCLUDING_SELF,
+ 0,
+ 0,
+ DELIVERY_MODE_INIT,
+ TRIGGER_MODE_EDGE,
+ TRUE
+ );
+ gBS->Stall (10 * STALL_ONE_MILLI_SECOND);
+ SendInterrupt (
+ BROADCAST_MODE_ALL_EXCLUDING_SELF,
+ 0,
+ (UINT32) RShiftU64 (WakeUpBuffer,
+ 12),
+ DELIVERY_MODE_SIPI,
+ TRIGGER_MODE_EDGE,
+ TRUE
+ );
+ gBS->Stall (200 * STALL_ONE_MICRO_SECOND);
+ SendInterrupt (
+ BROADCAST_MODE_ALL_EXCLUDING_SELF,
+ 0,
+ (UINT32) RShiftU64 (WakeUpBuffer,
+ 12),
+ DELIVERY_MODE_SIPI,
+ TRIGGER_MODE_EDGE,
+ TRUE
+ );
+ gBS->Stall (200 * STALL_ONE_MICRO_SECOND);
+ ExchangeInfo = (MP_CPU_EXCHANGE_INFO *) (UINTN) (WakeUpBuffer + MP_CPU_EXCHANGE_INFO_OFFSET);
+
+ ///
+ /// Get thread count
+ ///
+ MsrValue = AsmReadMsr64 (MSR_CORE_THREAD_COUNT);
+ ProcessorThreadCount = MsrValue & 0xffff;
+
+ ///
+ /// Only support MAXIMUM_CPU_NUMBER threads so far
+ ///
+ ASSERT (ProcessorThreadCount <= MAXIMUM_CPU_NUMBER);
+ if (ProcessorThreadCount > MAXIMUM_CPU_NUMBER) {
+ ProcessorThreadCount = MAXIMUM_CPU_NUMBER;
+ }
+
+ for (TimeoutTime = 0; TimeoutTime <= CPU_WAIT_FOR_TASK_TO_BE_COMPLETED; TimeoutTime += CPU_CHECK_AP_INTERVAL) {
+ ///
+ /// Wait for task to complete and then exit.
+ ///
+ gBS->Stall (CPU_CHECK_AP_INTERVAL);
+ for (Index = 1, ResponseProcessorCount = 1; Index < MAXIMUM_CPU_NUMBER; Index++) {
+ if (ExchangeInfo->BistBuffer[Index].Number == 1) {
+ ResponseProcessorCount++;
+ }
+ }
+
+ if (ResponseProcessorCount == ProcessorThreadCount) {
+ break;
+ }
+ }
+
+ for (Index = 0; Index < MAXIMUM_CPU_NUMBER; Index++) {
+ if (ExchangeInfo->BistBuffer[Index].Number == 1) {
+ ExchangeInfo->BistBuffer[Index].Number = (UINT32) mMPSystemData->NumberOfCpus++;
+ }
+ }
+
+ mAcpiCpuData->NumberOfCpus = (UINT32) mMPSystemData->NumberOfCpus;
+
+ ExchangeInfo->InitFlag = 0;
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Wake up APs for the second time to collect detailed information.
+
+ @param[in] WakeUpBuffer - Address of the wakeup buffer.
+
+ @retval EFI_SUCCESS - Function successfully finishes.
+**/
+EFI_STATUS
+PollForInitialization (
+ IN EFI_PHYSICAL_ADDRESS WakeUpBuffer
+ )
+{
+ MP_CPU_EXCHANGE_INFO *ExchangeInfo;
+ UINT32 FailedRevision;
+ EFI_STATUS Status;
+
+ ExchangeInfo = (MP_CPU_EXCHANGE_INFO *) (UINTN) (WakeUpBuffer + MP_CPU_EXCHANGE_INFO_OFFSET);
+
+ ExchangeInfo->ApFunction = (VOID *) (UINTN) DetailedMpInitialization;
+
+ CpuInitFloatPointUnit ();
+
+ ///
+ /// Update microcode for BSP
+ ///
+ mMcuLoadCount = 0;
+ Status = InitializeMicrocode (mMicrocodePointerBuffer, &FailedRevision);
+ if (Status == EFI_LOAD_ERROR) {
+ DEBUG((EFI_D_INFO,"Failed to load microcode patch\n"));
+ }
+
+ ///
+ /// Wait until all APs finish
+ ///
+ while (mFinishedCount < mAcpiCpuData->NumberOfCpus - 1) {
+ CpuPause ();
+ }
+
+ McuFirstLoadDone ();
+ return EFI_SUCCESS;
+}
+
+/**
+ Callback function to initialize MP data hub
+
+ @param[in] Event - Event whose notification function is being invoked.
+ @param[in] Context - Pointer to the notification functions context, which is implementation dependent.
+**/
+VOID
+EFIAPI
+MpDataHubCallback (
+ IN EFI_EVENT Event,
+ IN VOID *Context
+ )
+{
+ CPU_DATA_FOR_DATAHUB *CpuDataforDatahub;
+ UINTN Index;
+ EFI_STATUS Status;
+
+ Status = InitializeDataHubPtr (&mDataHub);
+ if (EFI_ERROR (Status)) {
+ return;
+ }
+
+ for (Index = 0; Index < mMPSystemData->NumberOfCpus; Index++) {
+ CpuDataforDatahub = &mMPSystemData->CpuData[Index].CpuDataforDatahub;
+ UpdateDataforDatahub (Index, CpuDataforDatahub);
+ }
+
+}
+
+/**
+ Initialize multiple processors and collect MP related data
+
+ @retval EFI_SUCCESS - Multiple processors get initialized and data collected successfully
+ @retval Other - The operation failed and appropriate error status will be returned
+**/
+EFI_STATUS
+InitializeMpSystemData (
+ VOID
+ )
+{
+ EFI_STATUS Status;
+ UINT32 MaxThreadsPerCore;
+ UINT32 MaxCoresPerDie;
+ UINT32 MaxDiesPerPackage;
+ UINT32 MaxPackages;
+
+ VOID *StackAddressStart;
+ EFI_PHYSICAL_ADDRESS WakeUpBuffer;
+ MP_CPU_EXCHANGE_INFO *ExchangeInfo;
+ UINTN Index;
+
+ EFI_CPU_ARCH_PROTOCOL *CpuArch;
+ BOOLEAN mInterruptState;
+ CPU_DATA_BLOCK *CpuData;
+ UINTN MaximumCPUsForThisSystem;
+ VOID *Registration;
+ EFI_HANDLE Handle;
+
+ Handle = NULL;
+
+ ///
+ /// Program Local APIC registers
+ ///
+ ProgramXApic (TRUE);
+
+ ///
+ /// Get information on threads, cores, dies and package for the CPU(s) on this platform
+ ///
+ Status = mPlatformCpu->CpuConfig->GetMaxCount (
+ mPlatformCpu,
+ &MaxThreadsPerCore,
+ &MaxCoresPerDie,
+ &MaxDiesPerPackage,
+ &MaxPackages
+ );
+ ///
+ /// Get the total CPU count
+ ///
+ if (!EFI_ERROR (Status)) {
+ MaximumCPUsForThisSystem = MaxThreadsPerCore * MaxCoresPerDie * MaxDiesPerPackage * MaxPackages;
+ } else {
+ MaximumCPUsForThisSystem = MAXIMUM_CPU_NUMBER;
+ }
+
+ ///
+ /// Prepare Wakeup Buffer and Stack for APs
+ ///
+ Status = PrepareMemoryForAPs (
+ &WakeUpBuffer,
+ &StackAddressStart,
+ MaximumCPUsForThisSystem
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ mOriginalBuffer = WakeUpBuffer;
+ Status = (gBS->AllocatePages)(AllocateAnyPages, EfiBootServicesData, 1, &mBackupBuffer);
+
+ ///
+ /// Fill MP Data
+ ///
+ FillMPData (
+ WakeUpBuffer,
+ StackAddressStart,
+ MaximumCPUsForThisSystem
+ );
+
+ ///
+ /// Prepare exchange information for APs
+ ///
+ ExchangeInfo = (MP_CPU_EXCHANGE_INFO *) (UINTN) (WakeUpBuffer + MP_CPU_EXCHANGE_INFO_OFFSET);
+ PrepareExchangeInfo (
+ ExchangeInfo,
+ StackAddressStart,
+ NULL,
+ WakeUpBuffer
+ );
+
+ ReportStatusCode (
+ EFI_PROGRESS_CODE,
+ EFI_COMPUTING_UNIT_HOST_PROCESSOR | EFI_CU_HP_PC_AP_INIT
+ );
+
+ CpuArch = mMPSystemData->CpuArch;
+ (CpuArch->GetInterruptState)(CpuArch, &mInterruptState);
+ CpuArch->DisableInterrupt (CpuArch);
+
+ ///
+ /// Get BSP Performance Control setting
+ ///
+ mCpuPerfCtrlValue = AsmReadMsr64 (MSR_IA32_PERF_CTRL);
+
+#ifdef BOOT_GUARD_SUPPORT_FLAG
+ //
+ // Disable PBET before send IPI to APs
+ //
+ StopPbeTimer ();
+#endif
+
+ ///
+ /// First INIT-SIPI-SIPI and reset AP waking counters
+ ///
+ CountApNumberAndCollectBist (WakeUpBuffer);
+ ExchangeInfo->WakeUpApManner = WakeUpApCounterInit;
+
+ ///
+ /// Assign AP function to initialize FPU MCU MTRR and get detail info
+ ///
+ PollForInitialization (WakeUpBuffer);
+ ///
+ /// Assign WakeUpApManner (WakeUpApPerHltLoop/WakeUpApPerMwaitLoop/WakeUpApPerRunLoop)
+ ///
+ ExchangeInfo->WakeUpApManner = mPlatformCpu->CpuConfig->ApIdleManner;
+ ///
+ /// Assign AP function to ApProcWrapper for StartAllAps/StartThisAp calling
+ ///
+ ExchangeInfo->ApFunction = (VOID *) (UINTN) ApProcWrapper;
+
+ if (mInterruptState) {
+ CpuArch->EnableInterrupt (CpuArch);
+ }
+
+ for (Index = 1; Index < mMPSystemData->NumberOfCpus; Index++) {
+ CpuData = &mMPSystemData->CpuData[Index];
+ if (CpuData->Health.Uint32 != 0) {
+ ReportStatusCode (
+ EFI_ERROR_MAJOR | EFI_ERROR_CODE,
+ EFI_COMPUTING_UNIT_HOST_PROCESSOR | EFI_CU_HP_EC_SELF_TEST
+ );
+ }
+
+ Status = CheckMicrocodeUpdate (Index, CpuData->MicrocodeStatus, CpuData->FailedRevision);
+ if (Status == EFI_LOAD_ERROR) {
+ DEBUG((EFI_D_INFO,"Failed to load microcode patch\n"));
+ }
+ }
+
+ Status = gBS->CreateEvent (
+ EFI_EVENT_TIMER | EFI_EVENT_NOTIFY_SIGNAL,
+ EFI_TPL_CALLBACK,
+ CheckAllAPsStatus,
+ NULL,
+ &mMPSystemData->CheckAllAPsEvent
+ );
+ for (Index = 0; Index < mMPSystemData->NumberOfCpus; Index++) {
+ CpuData = &mMPSystemData->CpuData[Index];
+ if (Index == mMPSystemData->BSP) {
+ continue;
+ }
+ Status = gBS->CreateEvent (
+ EFI_EVENT_TIMER | EFI_EVENT_NOTIFY_SIGNAL,
+ EFI_TPL_CALLBACK,
+ CheckThisAPStatus,
+ (VOID *) CpuData,
+ &CpuData->CheckThisAPEvent
+ );
+ }
+ ///
+ /// Switch BSP to Lowest Feature Processor (LFP)
+ ///
+ if (mPlatformCpu->CpuConfig->BspSelection == 16) {
+ Status = SwitchToLowestFeatureProcess (&mMpService);
+ }
+
+ ///
+ /// Initialize feature control structure
+ ///
+ InitializeFeaturePerSetup (mMPSystemData);
+
+ ///
+ /// Detect and log all processor supported features
+ ///
+ CollectProcessorFeature (&mMpService);
+ Status = mMpService.StartupAllAPs (
+ &mMpService,
+ CollectProcessorFeature,
+ FALSE,
+ NULL,
+ 0,
+ (VOID *) &mMpService,
+ NULL
+ );
+
+ ProgramProcessorFeature (&mMpService);
+ Status = mMpService.StartupAllAPs (
+ &mMpService,
+ ProgramProcessorFeature,
+ FALSE,
+ NULL,
+ 0,
+ (VOID *) &mMpService,
+ NULL
+ );
+
+ ///
+ /// Install CPU info protocol
+ ///
+ mCpuInfo.Revision = DXE_CPU_INFO_REVISION_1;
+ mCpuInfo.RcVersion = CPU_RC_VERSION;
+ mCpuInfo.CpuCommonFeatures = mCommonFeatures;
+
+ gBS->InstallMultipleProtocolInterfaces (
+ &Handle,
+ &gDxeCpuInfoProtocolGuid,
+ &mCpuInfo,
+ NULL
+ );
+ DEBUG ((EFI_D_INFO, "mCommonFeatures = %x\n", mCommonFeatures));
+
+ EfiCreateProtocolNotifyEvent (
+ &gEfiDataHubProtocolGuid,
+ EFI_TPL_CALLBACK,
+ MpDataHubCallback,
+ NULL,
+ &Registration
+ );
+
+ CopyMem ((VOID *) (UINTN) mBackupBuffer, (VOID *) (UINTN) mOriginalBuffer, EFI_PAGE_SIZE);
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Wrapper function for all procedures assigned to AP via MP service protocol.
+ It controls states of AP and invokes assigned precedure.
+**/
+VOID
+ApProcWrapper (
+ VOID
+ )
+{
+ EFI_AP_PROCEDURE Procedure;
+ VOID *Parameter;
+ UINTN CpuNumber;
+ CPU_DATA_BLOCK *CpuData;
+ MP_CPU_EXCHANGE_INFO *ExchangeInfo;
+ MONITOR_MWAIT_DATA *MonitorAddr;
+
+ ///
+ /// Initialize MCE for CR4.
+ ///
+ InitializeMce (mMPSystemData->MachineCheckEnable);
+
+ WhoAmI (&mMpService, &CpuNumber);
+ CpuData = &mMPSystemData->CpuData[CpuNumber];
+
+ ///
+ /// Now let us check it out.
+ ///
+ Procedure = CpuData->Procedure;
+ Parameter = CpuData->Parameter;
+
+ if (Procedure != NULL) {
+ AsmAcquireMPLock (&CpuData->StateLock);
+ CpuData->State = CPU_STATE_BUSY;
+ AsmReleaseMPLock (&CpuData->StateLock);
+ Procedure (Parameter);
+
+ ///
+ /// if BSP is switched to AP, it continue execute from here, but it carries register state
+ /// of the old AP, so need to reload CpuData (might be stored in a register after compiler
+ /// optimization) to make sure it points to the right data
+ ///
+ WhoAmI (&mMpService, &CpuNumber);
+ CpuData = &mMPSystemData->CpuData[CpuNumber];
+
+ AsmAcquireMPLock (&CpuData->ProcedureLock);
+ CpuData->Procedure = NULL;
+ AsmReleaseMPLock (&CpuData->ProcedureLock);
+
+ AsmAcquireMPLock (&CpuData->StateLock);
+ CpuData->State = CPU_STATE_FINISHED;
+ AsmReleaseMPLock (&CpuData->StateLock);
+
+ ///
+ /// Check AP wakeup manner, update signal and relating counter once finishing AP task
+ ///
+ ExchangeInfo = (MP_CPU_EXCHANGE_INFO *) (UINTN) (mAcpiCpuData->WakeUpBuffer + MP_CPU_EXCHANGE_INFO_OFFSET);
+ MonitorAddr = (MONITOR_MWAIT_DATA *)
+ (
+ (UINT8 *) ExchangeInfo->StackStart +
+ (ExchangeInfo->BistBuffer[CpuData->ApicID].Number + 1) *
+ ExchangeInfo->StackSize -
+ MONITOR_FILTER_SIZE
+ );
+
+ switch (ExchangeInfo->WakeUpApManner) {
+ case WakeUpApPerHltLoop:
+ MonitorAddr->HltLoopBreakCounter += 1;
+ break;
+
+ case WakeUpApPerMwaitLoop:
+ MonitorAddr->MwaitLoopBreakCounter += 1;
+ break;
+
+ case WakeUpApPerRunLoop:
+ MonitorAddr->RunLoopBreakCounter += 1;
+ break;
+
+ case WakeUpApPerMwaitLoop32:
+ MonitorAddr->MwaitLoopBreakCounter32 += 1;
+ break;
+
+ case WakeUpApPerRunLoop32:
+ MonitorAddr->RunLoopBreakCounter32 += 1;
+ break;
+
+ default:
+ break;
+ }
+
+ MonitorAddr->BreakToRunApSignal = 0;
+ }
+}
+
+/**
+ Procedure for detailed initialization of APs. It will be assigned to all APs
+ after first INIT-SIPI-SIPI finishing CPU number counting and BIST collection.
+**/
+VOID
+DetailedMpInitialization (
+ VOID
+ )
+{
+ EFI_STATUS Status;
+ UINT32 FailedRevision;
+
+ ///
+ /// Program APs CPU Performance Control setting
+ ///
+ AsmWriteMsr64 (MSR_IA32_PERF_CTRL, mCpuPerfCtrlValue);
+
+ CpuInitFloatPointUnit ();
+
+ Status = InitializeMicrocode (
+ (EFI_CPU_MICROCODE_HEADER **) (UINTN) mAcpiCpuData->MicrocodePointerBuffer,
+ &FailedRevision
+ );
+
+ ///
+ /// Init MLC Streamer Prefetcher and MLC Spatial Prefetcher
+ ///
+ InitializeProcessorsPrefetcher (
+ mPlatformCpu->CpuConfig->MlcStreamerPrefetcher,
+ mPlatformCpu->CpuConfig->MlcSpatialPrefetcher
+ );
+
+ ///
+ /// Init Cache after all MCU is loaded
+ ///
+ while (mMcuLoadCount < mAcpiCpuData->NumberOfCpus) {
+ CpuPause ();
+ }
+
+ ///
+ /// Save Mtrr Registers in global data areas
+ ///
+ MpMtrrSynchUp (NULL);
+ ProgramXApic (FALSE);
+ FillInProcessorInformation (mMPSystemData, FALSE, 0);
+ InterlockedIncrement (&mFinishedCount);
+}
+
+/**
+ Switch current BSP processor to AP
+
+ @param[in] MPSystemData - Pointer to the data structure containing MP related data
+**/
+VOID
+FutureBSPProc (
+ IN MP_SYSTEM_DATA *MPSystemData
+ )
+{
+ AsmExchangeRole (&MPSystemData->APInfo, &MPSystemData->BSPInfo);
+ return;
+}
+
+/**
+ This function is called by all processors (both BSP and AP) once and collects MP related data
+
+ @param[in] MPSystemData - Pointer to the data structure containing MP related data
+ @param[in] BSP - TRUE if the CPU is BSP
+ @param[in] BistParam - BIST (build-in self test) data for the processor. This data
+ is only valid for processors that are waked up for the 1ast
+ time in this CPU DXE driver.
+
+ @retval EFI_SUCCESS - Data for the processor collected and filled in
+**/
+EFI_STATUS
+FillInProcessorInformation (
+ IN MP_SYSTEM_DATA *MPSystemData,
+ IN BOOLEAN BSP,
+ IN UINT32 BistParam
+ )
+{
+ UINT32 Health;
+ UINT32 ApicID;
+ CPU_DATA_BLOCK *CpuData;
+ UINT32 BIST;
+ UINTN CpuNumber;
+ UINTN Index;
+ UINTN Count;
+ MP_CPU_EXCHANGE_INFO *ExchangeInfo;
+
+ ApicID = GetApicID (NULL, NULL);
+ BIST = 0;
+
+ if (BSP) {
+ CpuNumber = 0;
+ BIST = BistParam;
+ } else {
+ ExchangeInfo = (MP_CPU_EXCHANGE_INFO *) (UINTN) (mAcpiCpuData->WakeUpBuffer + MP_CPU_EXCHANGE_INFO_OFFSET);
+ CpuNumber = ExchangeInfo->BistBuffer[ApicID].Number;
+ BIST = ExchangeInfo->BistBuffer[ApicID].BIST;
+ }
+
+ CpuData = &MPSystemData->CpuData[CpuNumber];
+ CpuData->SecondaryCpu = IsSecondaryThread ();
+ CpuData->ApicID = ApicID;
+ CpuData->Procedure = NULL;
+ CpuData->Parameter = NULL;
+ CpuData->StateLock = VacantFlag;
+ CpuData->ProcedureLock = VacantFlag;
+ CpuData->State = CPU_STATE_IDLE;
+
+ Health = BIST;
+ Count = MPSystemData->BistHobSize / sizeof (BIST_HOB_DATA);
+ for (Index = 0; Index < Count; Index++) {
+ if (ApicID == MPSystemData->BistHobData[Index].ApicId) {
+ Health = MPSystemData->BistHobData[Index].Health.Uint32;
+ }
+ }
+
+ if (Health > 0) {
+ CpuData->State = CPU_STATE_DISABLED;
+ MPSystemData->DisableCause[CpuNumber] = CPU_CAUSE_SELFTEST_FAILURE;
+
+ } else {
+ MPSystemData->DisableCause[CpuNumber] = CPU_CAUSE_NOT_DISABLED;
+ }
+
+ FillinDataforDataHub (CpuNumber, &CpuData->CpuDataforDatahub);
+ CpuData->CpuDataforDatahub.Health.Uint32 = Health;
+
+ CopyMem (&CpuData->PhysicalLocation, &CpuData->CpuDataforDatahub.Location, sizeof (PHYSICAL_LOCATION));
+ return EFI_SUCCESS;
+}
+
+/**
+ Set APIC BSP bit
+
+ @param[in] Enable - enable as BSP or not
+
+ @retval EFI_SUCCESS - always return success
+**/
+EFI_STATUS
+SetApicBSPBit (
+ IN BOOLEAN Enable
+ )
+{
+ UINT64 ApicBaseReg;
+
+ ApicBaseReg = AsmReadMsr64 (MSR_IA32_APIC_BASE);
+
+ if (Enable) {
+ ApicBaseReg |= 0x100;
+ } else {
+ ApicBaseReg &= 0xfffffffffffffe00;
+ }
+
+ AsmWriteMsr64 (MSR_IA32_APIC_BASE, ApicBaseReg);
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Change CPU state
+
+ @param[in] CpuNumber - CPU number
+ @param[in] NewState - the new state that will be changed to
+ @param[in] Cause - Cause
+
+ @retval EFI_SUCCESS - always return success
+**/
+EFI_STATUS
+ChangeCpuState (
+ IN UINTN CpuNumber,
+ IN BOOLEAN NewState,
+ IN CPU_STATE_CHANGE_CAUSE Cause
+ )
+{
+ CPU_DATA_BLOCK *CpuData;
+ EFI_COMPUTING_UNIT_CPU_DISABLED_ERROR_DATA ErrorData;
+
+ CpuData = &mMPSystemData->CpuData[CpuNumber];
+
+ mMPSystemData->DisableCause[CpuNumber] = Cause;
+
+ if (!NewState) {
+ AsmAcquireMPLock (&CpuData->StateLock);
+ CpuData->State = CPU_STATE_DISABLED;
+ AsmReleaseMPLock (&CpuData->StateLock);
+
+ ErrorData.DataHeader.HeaderSize = sizeof (EFI_STATUS_CODE_DATA);
+ ErrorData.DataHeader.Size = sizeof (EFI_COMPUTING_UNIT_CPU_DISABLED_ERROR_DATA) - sizeof (EFI_STATUS_CODE_DATA);
+ CopyMem (
+ &ErrorData.DataHeader.Type,
+ &gEfiStatusCodeSpecificDataGuid,
+ sizeof (EFI_GUID)
+ );
+ ErrorData.Cause = Cause;
+ ErrorData.SoftwareDisabled = TRUE;
+//(AMI_CHG)>
+/* ReportStatusCode (
+ EFI_ERROR_MINOR | EFI_ERROR_CODE,
+ EFI_COMPUTING_UNIT_HOST_PROCESSOR | EFI_CU_EC_DISABLED
+ );*/
+//<(AMI_CHG)
+ } else {
+ AsmAcquireMPLock (&CpuData->StateLock);
+ CpuData->State = CPU_STATE_IDLE;
+ AsmReleaseMPLock (&CpuData->StateLock);
+ }
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Check if this is non-core processor - HT AP thread
+
+ @retval TRUE if this is HT AP thread
+ @retval FALSE if this is core thread
+**/
+BOOLEAN
+IsSecondaryThread (
+ VOID
+ )
+{
+ UINT32 ApicID;
+ EFI_CPUID_REGISTER CpuidRegisters;
+ UINT8 CpuCount;
+ UINT8 CoreCount;
+ UINT8 CpuPerCore;
+ UINT32 Mask;
+
+ ApicID = GetApicID (NULL, NULL);
+
+ AsmCpuid (
+ CPUID_VERSION_INFO,
+ &CpuidRegisters.RegEax,
+ &CpuidRegisters.RegEbx,
+ &CpuidRegisters.RegEcx,
+ &CpuidRegisters.RegEdx
+ );
+ if ((CpuidRegisters.RegEdx & 0x10000000) == 0) {
+ return FALSE;
+ }
+
+ CpuCount = (UINT8) ((CpuidRegisters.RegEbx >> 16) & 0xff);
+ if (CpuCount == 1) {
+ return FALSE;
+ }
+
+ AsmCpuid (
+ CPUID_SIGNATURE,
+ &CpuidRegisters.RegEax,
+ &CpuidRegisters.RegEbx,
+ &CpuidRegisters.RegEcx,
+ &CpuidRegisters.RegEdx
+ );
+ if (CpuidRegisters.RegEax > 3) {
+
+ CoreCount = GetCoreNumber ();
+ } else {
+ CoreCount = 1;
+ }
+
+ ///
+ /// Assumes there is symmetry across core boundary, i.e. each core within a package has the same number of logical processors
+ ///
+ if (CpuCount == CoreCount) {
+ return FALSE;
+ }
+
+ CpuPerCore = CpuCount / CoreCount;
+
+ ///
+ /// Assume 1 Core has no more than 8 threads
+ ///
+ if (CpuPerCore == 2) {
+ Mask = 0x1;
+ } else if (CpuPerCore <= 4) {
+ Mask = 0x3;
+ } else {
+ Mask = 0x7;
+ }
+
+ if ((ApicID & Mask) == 0) {
+ return FALSE;
+ } else {
+ return TRUE;
+ }
+}
+
+/**
+ If timeout occurs in StartupAllAps(), a timer is set, which invokes this
+ procedure periodically to check whether all APs have finished.
+
+ @param[in] Event - Event triggered.
+ @param[in] Context - Parameter passed with the event.
+**/
+VOID
+CheckAllAPsStatus (
+ IN EFI_EVENT Event,
+ IN VOID *Context
+ )
+{
+ UINTN CpuNumber;
+ UINTN NextCpuNumber;
+ CPU_DATA_BLOCK *CpuData;
+ CPU_DATA_BLOCK *NextCpuData;
+ EFI_STATUS Status;
+ CPU_STATE CpuState;
+
+ for (CpuNumber = 0; CpuNumber < mMPSystemData->NumberOfCpus; CpuNumber++) {
+ CpuData = &mMPSystemData->CpuData[CpuNumber];
+ if (CpuNumber == mMPSystemData->BSP) {
+ continue;
+ }
+
+ AsmAcquireMPLock (&CpuData->StateLock);
+ CpuState = CpuData->State;
+ AsmReleaseMPLock (&CpuData->StateLock);
+
+ switch (CpuState) {
+ case CPU_STATE_READY:
+ WakeUpAp (
+ CpuData,
+ mMPSystemData->Procedure,
+ mMPSystemData->ProcArguments
+ );
+ break;
+
+ case CPU_STATE_FINISHED:
+ if (mMPSystemData->SingleThread) {
+ Status = GetNextBlockedCpuNumber (&NextCpuNumber);
+ if (!EFI_ERROR (Status)) {
+ NextCpuData = &mMPSystemData->CpuData[NextCpuNumber];
+
+ AsmAcquireMPLock (&NextCpuData->StateLock);
+ NextCpuData->State = CPU_STATE_READY;
+ AsmReleaseMPLock (&NextCpuData->StateLock);
+
+ WakeUpAp (
+ NextCpuData,
+ mMPSystemData->Procedure,
+ mMPSystemData->ProcArguments
+ );
+ }
+ }
+
+ AsmAcquireMPLock (&CpuData->StateLock);
+ CpuData->State = CPU_STATE_IDLE;
+ AsmReleaseMPLock (&CpuData->StateLock);
+
+ mMPSystemData->FinishCount++;
+ break;
+
+ default:
+ break;
+ }
+ }
+
+ if (mMPSystemData->FinishCount == mMPSystemData->StartCount) {
+ gBS->SetTimer (
+ mMPSystemData->CheckAllAPsEvent,
+ TimerCancel,
+ 0
+ );
+ Status = gBS->SignalEvent (mMPSystemData->WaitEvent);
+ }
+
+ return;
+}
+
+/**
+ Check if this AP has finished task
+
+ @param[in] Event - Event triggered.
+ @param[in] Context - Parameter passed with the event.
+**/
+VOID
+CheckThisAPStatus (
+ IN EFI_EVENT Event,
+ IN VOID *Context
+ )
+{
+ CPU_DATA_BLOCK *CpuData;
+ EFI_STATUS Status;
+ CPU_STATE CpuState;
+
+ CpuData = (CPU_DATA_BLOCK *) Context;
+
+ AsmAcquireMPLock (&CpuData->StateLock);
+ CpuState = CpuData->State;
+ AsmReleaseMPLock (&CpuData->StateLock);
+
+ if (CpuState == CPU_STATE_FINISHED) {
+ gBS->SetTimer (
+ CpuData->CheckThisAPEvent,
+ TimerCancel,
+ 0
+ );
+ Status = gBS->SignalEvent (mMPSystemData->WaitEvent);
+ AsmAcquireMPLock (&CpuData->StateLock);
+ CpuData->State = CPU_STATE_IDLE;
+ AsmReleaseMPLock (&CpuData->StateLock);
+ }
+
+ return;
+}
+
+/**
+ Convert the timeout value to TSC value
+
+ @param[in] TimeoutInMicroSecs - how many microseconds the timeout is
+
+ @retval expected TSC value for timeout
+**/
+UINT64
+CalculateTimeout (
+ IN UINTN TimeoutInMicroSecs
+ )
+{
+ UINT64 CurrentTsc;
+ UINT64 ExpectedTsc;
+ UINT64 Frequency;
+ EFI_STATUS Status;
+
+ if (TimeoutInMicroSecs == 0) {
+ return 0xffffffffffff;
+ }
+
+ CurrentTsc = EfiReadTsc ();
+
+ Status = GetActualFrequency (mMetronome, &Frequency);
+
+ ExpectedTsc = CurrentTsc + MultU64x32 (Frequency, (UINT32) TimeoutInMicroSecs);
+
+ return ExpectedTsc;
+}
+
+/**
+ Check if timeout happened
+
+ @param[in] ExpectedTsc - the TSC value for timeout
+
+ @retval TRUE if timeout happened
+ @retval FALSE if timeout not yet happened
+**/
+BOOLEAN
+CheckTimeout (
+ IN UINT64 ExpectedTsc
+ )
+{
+ UINT64 CurrentTsc;
+
+ CurrentTsc = EfiReadTsc ();
+ if (CurrentTsc >= ExpectedTsc) {
+ return TRUE;
+ }
+
+ return FALSE;
+}
+
+/**
+ Get the next blocked processor
+
+ @param[in] NextCpuNumber - that will be updated for next blocked CPU number
+
+ @retval EFI_SUCCESS - The next blocked CPU found
+ @retval EFI_NOT_FOUND - cannot find blocked CPU
+**/
+EFI_STATUS
+GetNextBlockedCpuNumber (
+ OUT UINTN *NextCpuNumber
+ )
+{
+ UINTN CpuNumber;
+ CPU_STATE CpuState;
+ CPU_DATA_BLOCK *CpuData;
+
+ for (CpuNumber = 0; CpuNumber < mMPSystemData->NumberOfCpus; CpuNumber++) {
+ if (CpuNumber == mMPSystemData->BSP) {
+ continue;
+ }
+
+ CpuData = &mMPSystemData->CpuData[CpuNumber];
+
+ AsmAcquireMPLock (&CpuData->StateLock);
+ CpuState = CpuData->State;
+ AsmReleaseMPLock (&CpuData->StateLock);
+
+ if (CpuState == CPU_STATE_BLOCKED) {
+ *NextCpuNumber = CpuNumber;
+ return EFI_SUCCESS;
+ }
+ }
+
+ return EFI_NOT_FOUND;
+}
+
+/**
+ Update data hub for processor status
+
+ @param[in] CpuNumber - CPU number
+ @param[in] CpuDataforDatahub - the data hub that will be updated
+**/
+VOID
+UpdateDataforDatahub (
+ IN UINTN CpuNumber,
+ OUT CPU_DATA_FOR_DATAHUB *CpuDataforDatahub
+ )
+{
+ CpuDataforDatahub->Status = GetProcessorStatus (CpuNumber);
+ InitializeProcessorData (CpuNumber, CpuDataforDatahub);
+ InitializeCacheData (CpuNumber, CpuDataforDatahub->CacheInformation);
+
+ return;
+}
+
+/**
+ Function to wake up a specified AP and assign procedure to it.
+
+ @param[in] CpuData - CPU data block for the specified AP.
+ @param[in] Procedure - Procedure to assign.
+ @param[in] ProcArguments - Argument for Procedure.
+**/
+VOID
+WakeUpAp (
+ IN CPU_DATA_BLOCK *CpuData,
+ IN EFI_AP_PROCEDURE Procedure,
+ IN VOID *ProcArguments
+ )
+{
+ MP_CPU_EXCHANGE_INFO *ExchangeInfo;
+ MONITOR_MWAIT_DATA *MonitorAddr;
+
+ AsmAcquireMPLock (&CpuData->ProcedureLock);
+ CpuData->Parameter = ProcArguments;
+ CpuData->Procedure = Procedure;
+ AsmReleaseMPLock (&CpuData->ProcedureLock);
+
+ ExchangeInfo = (MP_CPU_EXCHANGE_INFO *) (UINTN) (mAcpiCpuData->WakeUpBuffer + MP_CPU_EXCHANGE_INFO_OFFSET);
+ MonitorAddr = (MONITOR_MWAIT_DATA *)
+ (
+ (UINT8 *) ExchangeInfo->StackStart +
+ (ExchangeInfo->BistBuffer[CpuData->ApicID].Number + 1) *
+ ExchangeInfo->StackSize -
+ MONITOR_FILTER_SIZE
+ );
+
+ if (MonitorAddr->WakeUpApVectorChangeFlag == TRUE || ExchangeInfo->WakeUpApManner == WakeUpApPerHltLoop) {
+ SendInterrupt (
+ BROADCAST_MODE_SPECIFY_CPU,
+ CpuData->ApicID,
+ 0,
+ DELIVERY_MODE_INIT,
+ TRIGGER_MODE_EDGE,
+ TRUE
+ );
+ SendInterrupt (
+ BROADCAST_MODE_SPECIFY_CPU,
+ CpuData->ApicID,
+ (UINT32) RShiftU64 (mAcpiCpuData->WakeUpBuffer,
+ 12),
+ DELIVERY_MODE_SIPI,
+ TRIGGER_MODE_EDGE,
+ TRUE
+ );
+ MonitorAddr->WakeUpApVectorChangeFlag = FALSE;
+
+ //
+ // Clear StateLock to 0 to avoid AP locking it then entering SMM and getting INIT-SIPI here could cause dead-lock
+ //
+ CpuData->StateLock = 0;
+ }
+
+ MonitorAddr->BreakToRunApSignal = (UINTN) (BREAK_TO_RUN_AP_SIGNAL | CpuData->ApicID);
+}
+
+/**
+ Check whether any AP is running for assigned task.
+
+ @retval TRUE - Some APs are running.
+ @retval FALSE - No AP is running.
+**/
+BOOLEAN
+ApRunning (
+ VOID
+ )
+{
+ CPU_DATA_BLOCK *CpuData;
+ UINTN CpuNumber;
+
+ for (CpuNumber = 0; CpuNumber < mMPSystemData->NumberOfCpus; CpuNumber++) {
+ CpuData = &mMPSystemData->CpuData[CpuNumber];
+
+ if (CpuNumber != mMPSystemData->BSP) {
+ if (CpuData->State == CPU_STATE_READY || CpuData->State == CPU_STATE_BUSY) {
+ return TRUE;
+ }
+ }
+ }
+
+ return FALSE;
+}
+
+/**
+ Re-load microcode patch before boot.
+
+ @param[in] MpServices - point to EFI_MP_SERVICES_PROTOCOL
+
+ @retval EFI_SUCCESS - one processor re-loads microcode patch
+**/
+EFI_STATUS
+ReLoadMicrocodePatch (
+ IN EFI_MP_SERVICES_PROTOCOL *MpServices
+ )
+{
+ UINT32 FailedRevision;
+ UINTN CpuNumber;
+ EFI_STATUS Status;
+
+ Status = InitializeMicrocode (
+ mMicrocodePointerBuffer,
+ &FailedRevision
+ );
+ WhoAmI (
+ &mMpService,
+ &CpuNumber
+ );
+ Status = CheckMicrocodeUpdate (
+ CpuNumber,
+ Status,
+ FailedRevision
+ );
+ return Status;
+}
+
+/**
+ Re-load microcode patch before boot.
+
+ @retval EFI_SUCCESS - Multiple processors re-load microcode patch
+**/
+EFI_STATUS
+ReLoadMicrocodeBeforeBoot (
+ VOID
+ )
+{
+ EFI_STATUS Status;
+
+ ///
+ /// Added code to handle microcode patch reload here!!!
+ ///
+ mMcuLoadCount = 0;
+ Status = ReLoadMicrocodePatch (&mMpService);
+ if (!EFI_ERROR (Status)) {
+ Status = mMpService.StartupAllAPs (
+ &mMpService,
+ ReLoadMicrocodePatch,
+ FALSE,
+ NULL,
+ 0,
+ (VOID *) &mMpService,
+ NULL
+ );
+ }
+ return Status;
+}