+++ /dev/null
-/** @file\r
-Produces PI MP Services Protocol on top of Framework MP Services Protocol.\r
-\r
-Intel's Framework MP Services Protocol is replaced by EFI_MP_SERVICES_PROTOCOL in PI 1.1.\r
-This module produces PI MP Services Protocol on top of Framework MP Services Protocol.\r
-\r
-Copyright (c) 2009 - 2010, Intel Corporation. All rights reserved.<BR>\r
-This program and the accompanying materials\r
-are licensed and made available under the terms and conditions of the BSD License\r
-which accompanies this distribution. The full text of the license may be found at\r
-http://opensource.org/licenses/bsd-license.php\r
-\r
-THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
-WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
-Module Name:\r
-\r
-**/\r
-\r
-#include "MpServicesOnFrameworkMpServicesThunk.h"\r
-\r
-EFI_HANDLE mHandle = NULL;\r
-MP_SYSTEM_DATA mMPSystemData;\r
-EFI_PHYSICAL_ADDRESS mStartupVector;\r
-MP_CPU_EXCHANGE_INFO *mExchangeInfo;\r
-BOOLEAN mStopCheckAPsStatus = FALSE;\r
-UINTN mNumberOfProcessors;\r
-EFI_GENERIC_MEMORY_TEST_PROTOCOL *mGenMemoryTest;\r
-\r
-FRAMEWORK_EFI_MP_SERVICES_PROTOCOL *mFrameworkMpService;\r
-EFI_MP_SERVICES_PROTOCOL mMpService = {\r
- GetNumberOfProcessors,\r
- GetProcessorInfo,\r
- StartupAllAPs,\r
- StartupThisAP,\r
- SwitchBSP,\r
- EnableDisableAP,\r
- WhoAmI\r
-};\r
-\r
-\r
-/**\r
- Implementation of GetNumberOfProcessors() service of MP Services Protocol.\r
-\r
- This service retrieves the number of logical processor in the platform\r
- and the number of those logical processors that are enabled on this boot.\r
- This service may only be called from the BSP.\r
-\r
- @param This A pointer to the EFI_MP_SERVICES_PROTOCOL instance.\r
- @param NumberOfProcessors Pointer to the total number of logical processors in the system,\r
- including the BSP and disabled APs.\r
- @param NumberOfEnabledProcessors Pointer to the number of enabled logical processors that exist\r
- in system, including the BSP.\r
-\r
- @retval EFI_SUCCESS Number of logical processors and enabled logical processors retrieved..\r
- @retval EFI_DEVICE_ERROR Caller processor is AP.\r
- @retval EFI_INVALID_PARAMETER NumberOfProcessors is NULL\r
- @retval EFI_INVALID_PARAMETER NumberOfEnabledProcessors is NULL\r
-\r
-**/\r
-EFI_STATUS\r
-EFIAPI\r
-GetNumberOfProcessors (\r
- IN EFI_MP_SERVICES_PROTOCOL *This,\r
- OUT UINTN *NumberOfProcessors,\r
- OUT UINTN *NumberOfEnabledProcessors\r
- )\r
-{\r
- EFI_STATUS Status;\r
- UINTN CallerNumber;\r
-\r
- //\r
- // Check whether caller processor is BSP\r
- //\r
- WhoAmI (This, &CallerNumber);\r
- if (CallerNumber != GetBspNumber ()) {\r
- return EFI_DEVICE_ERROR;\r
- }\r
-\r
- //\r
- // Check parameter NumberOfProcessors\r
- //\r
- if (NumberOfProcessors == NULL) {\r
- return EFI_INVALID_PARAMETER;\r
- }\r
-\r
- //\r
- // Check parameter NumberOfEnabledProcessors\r
- //\r
- if (NumberOfEnabledProcessors == NULL) {\r
- return EFI_INVALID_PARAMETER;\r
- }\r
-\r
- Status = mFrameworkMpService->GetGeneralMPInfo (\r
- mFrameworkMpService,\r
- NumberOfProcessors,\r
- NULL,\r
- NumberOfEnabledProcessors,\r
- NULL,\r
- NULL\r
- );\r
- ASSERT_EFI_ERROR (Status);\r
-\r
- return EFI_SUCCESS;\r
-}\r
-\r
-/**\r
- Implementation of GetNumberOfProcessors() service of MP Services Protocol.\r
-\r
- Gets detailed MP-related information on the requested processor at the\r
- instant this call is made. This service may only be called from the BSP.\r
-\r
- @param This A pointer to the EFI_MP_SERVICES_PROTOCOL instance.\r
- @param ProcessorNumber The handle number of processor.\r
- @param ProcessorInfoBuffer A pointer to the buffer where information for the requested processor is deposited.\r
-\r
- @retval EFI_SUCCESS Processor information successfully returned.\r
- @retval EFI_DEVICE_ERROR Caller processor is AP.\r
- @retval EFI_INVALID_PARAMETER ProcessorInfoBuffer is NULL\r
- @retval EFI_NOT_FOUND Processor with the handle specified by ProcessorNumber does not exist.\r
-\r
-**/\r
-EFI_STATUS\r
-EFIAPI\r
-GetProcessorInfo (\r
- IN EFI_MP_SERVICES_PROTOCOL *This,\r
- IN UINTN ProcessorNumber,\r
- OUT EFI_PROCESSOR_INFORMATION *ProcessorInfoBuffer\r
- )\r
-{\r
- EFI_STATUS Status;\r
- UINTN CallerNumber;\r
- UINTN BufferSize;\r
- EFI_MP_PROC_CONTEXT ProcessorContextBuffer;\r
-\r
- //\r
- // Check whether caller processor is BSP\r
- //\r
- WhoAmI (This, &CallerNumber);\r
- if (CallerNumber != GetBspNumber ()) {\r
- return EFI_DEVICE_ERROR;\r
- }\r
-\r
- //\r
- // Check parameter ProcessorInfoBuffer\r
- //\r
- if (ProcessorInfoBuffer == NULL) {\r
- return EFI_INVALID_PARAMETER;\r
- }\r
-\r
- //\r
- // Check whether processor with the handle specified by ProcessorNumber exists\r
- //\r
- if (ProcessorNumber >= mNumberOfProcessors) {\r
- return EFI_NOT_FOUND;\r
- }\r
-\r
- BufferSize = sizeof (EFI_MP_PROC_CONTEXT);\r
- Status = mFrameworkMpService->GetProcessorContext (\r
- mFrameworkMpService,\r
- ProcessorNumber,\r
- &BufferSize,\r
- &ProcessorContextBuffer\r
- );\r
- ASSERT_EFI_ERROR (Status);\r
-\r
- ProcessorInfoBuffer->ProcessorId = (UINT64) ProcessorContextBuffer.ApicID;\r
-\r
- //\r
- // Get Status Flag of specified processor\r
- //\r
- ProcessorInfoBuffer->StatusFlag = 0;\r
-\r
- if (ProcessorContextBuffer.Enabled) {\r
- ProcessorInfoBuffer->StatusFlag |= PROCESSOR_ENABLED_BIT;\r
- }\r
-\r
- if (ProcessorContextBuffer.Designation == EfiCpuBSP) {\r
- ProcessorInfoBuffer->StatusFlag |= PROCESSOR_AS_BSP_BIT;\r
- }\r
-\r
- if (ProcessorContextBuffer.Health.Flags.Uint32 == 0) {\r
- ProcessorInfoBuffer->StatusFlag |= PROCESSOR_HEALTH_STATUS_BIT;\r
- }\r
-\r
- ProcessorInfoBuffer->Location.Package = (UINT32) ProcessorContextBuffer.PackageNumber;\r
- ProcessorInfoBuffer->Location.Core = (UINT32) ProcessorContextBuffer.NumberOfCores;\r
- ProcessorInfoBuffer->Location.Thread = (UINT32) ProcessorContextBuffer.NumberOfThreads;\r
-\r
- return EFI_SUCCESS;\r
-}\r
-\r
-/**\r
- Implementation of StartupAllAPs() service of MP Services Protocol.\r
-\r
- This service lets the caller get all enabled APs to execute a caller-provided function.\r
- This service may only be called from the BSP.\r
-\r
- @param This A pointer to the EFI_MP_SERVICES_PROTOCOL instance.\r
- @param Procedure A pointer to the function to be run on enabled APs of the system.\r
- @param SingleThread Indicates whether to execute the function simultaneously or one by one..\r
- @param WaitEvent The event created by the caller.\r
- If it is NULL, then execute in blocking mode.\r
- If it is not NULL, then execute in non-blocking mode.\r
- @param TimeoutInMicroSeconds The time limit in microseconds for this AP to finish the function.\r
- Zero means infinity.\r
- @param ProcedureArgument Pointer to the optional parameter of the assigned function.\r
- @param FailedCpuList The list of processor numbers that fail to finish the function before\r
- TimeoutInMicrosecsond expires.\r
-\r
- @retval EFI_SUCCESS In blocking mode, all APs have finished before the timeout expired.\r
- @retval EFI_SUCCESS In non-blocking mode, function has been dispatched to all enabled APs.\r
- @retval EFI_DEVICE_ERROR Caller processor is AP.\r
- @retval EFI_NOT_STARTED No enabled AP exists in the system.\r
- @retval EFI_NOT_READY Any enabled AP is busy.\r
- @retval EFI_TIMEOUT In blocking mode, The timeout expired before all enabled APs have finished.\r
- @retval EFI_INVALID_PARAMETER Procedure is NULL.\r
-\r
-**/\r
-EFI_STATUS\r
-EFIAPI\r
-StartupAllAPs (\r
- IN EFI_MP_SERVICES_PROTOCOL *This,\r
- IN EFI_AP_PROCEDURE Procedure,\r
- IN BOOLEAN SingleThread,\r
- IN EFI_EVENT WaitEvent OPTIONAL,\r
- IN UINTN TimeoutInMicroSeconds,\r
- IN VOID *ProcedureArgument OPTIONAL,\r
- OUT UINTN **FailedCpuList OPTIONAL\r
- )\r
-{\r
- EFI_STATUS Status;\r
- UINTN ProcessorNumber;\r
- CPU_DATA_BLOCK *CpuData;\r
- BOOLEAN Blocking;\r
- UINTN BspNumber;\r
-\r
- if (FailedCpuList != NULL) {\r
- *FailedCpuList = NULL;\r
- }\r
-\r
- //\r
- // Check whether caller processor is BSP\r
- //\r
- BspNumber = GetBspNumber ();\r
- WhoAmI (This, &ProcessorNumber);\r
- if (ProcessorNumber != BspNumber) {\r
- return EFI_DEVICE_ERROR;\r
- }\r
-\r
- //\r
- // Check parameter Procedure\r
- //\r
- if (Procedure == NULL) {\r
- return EFI_INVALID_PARAMETER;\r
- }\r
-\r
- //\r
- // Temporarily suppress CheckAPsStatus()\r
- //\r
- mStopCheckAPsStatus = TRUE;\r
-\r
- //\r
- // Check whether all enabled APs are idle.\r
- // If any enabled AP is not idle, return EFI_NOT_READY.\r
- //\r
- for (ProcessorNumber = 0; ProcessorNumber < mNumberOfProcessors; ProcessorNumber++) {\r
-\r
- CpuData = &mMPSystemData.CpuData[ProcessorNumber];\r
-\r
- mMPSystemData.CpuList[ProcessorNumber] = FALSE;\r
- if (ProcessorNumber != BspNumber) {\r
- if (CpuData->State != CpuStateDisabled) {\r
- if (CpuData->State != CpuStateIdle) {\r
- mStopCheckAPsStatus = FALSE;\r
- return EFI_NOT_READY;\r
- } else {\r
- //\r
- // Mark this processor as responsible for current calling.\r
- //\r
- mMPSystemData.CpuList[ProcessorNumber] = TRUE;\r
- }\r
- }\r
- }\r
- }\r
-\r
- mMPSystemData.FinishCount = 0;\r
- mMPSystemData.StartCount = 0;\r
- Blocking = FALSE;\r
- //\r
- // Go through all enabled APs to wakeup them for Procedure.\r
- // If in Single Thread mode, then only one AP is woken up, and others are waiting.\r
- //\r
- for (ProcessorNumber = 0; ProcessorNumber < mNumberOfProcessors; ProcessorNumber++) {\r
-\r
- CpuData = &mMPSystemData.CpuData[ProcessorNumber];\r
- //\r
- // Check whether this processor is responsible for current calling.\r
- //\r
- if (mMPSystemData.CpuList[ProcessorNumber]) {\r
-\r
- mMPSystemData.StartCount++;\r
-\r
- AcquireSpinLock (&CpuData->CpuDataLock);\r
- CpuData->State = CpuStateReady;\r
- ReleaseSpinLock (&CpuData->CpuDataLock);\r
-\r
- if (!Blocking) {\r
- WakeUpAp (\r
- ProcessorNumber,\r
- Procedure,\r
- ProcedureArgument\r
- );\r
- }\r
-\r
- if (SingleThread) {\r
- Blocking = TRUE;\r
- }\r
- }\r
- }\r
-\r
- //\r
- // If no enabled AP exists, return EFI_NOT_STARTED.\r
- //\r
- if (mMPSystemData.StartCount == 0) {\r
- mStopCheckAPsStatus = FALSE;\r
- return EFI_NOT_STARTED;\r
- }\r
-\r
- //\r
- // If WaitEvent is not NULL, execute in non-blocking mode.\r
- // BSP saves data for CheckAPsStatus(), and returns EFI_SUCCESS.\r
- // CheckAPsStatus() will check completion and timeout periodically.\r
- //\r
- mMPSystemData.Procedure = Procedure;\r
- mMPSystemData.ProcArguments = ProcedureArgument;\r
- mMPSystemData.SingleThread = SingleThread;\r
- mMPSystemData.FailedCpuList = FailedCpuList;\r
- mMPSystemData.ExpectedTime = CalculateTimeout (TimeoutInMicroSeconds, &mMPSystemData.CurrentTime);\r
- mMPSystemData.WaitEvent = WaitEvent;\r
-\r
- //\r
- // Allow CheckAPsStatus()\r
- //\r
- mStopCheckAPsStatus = FALSE;\r
-\r
- if (WaitEvent != NULL) {\r
- return EFI_SUCCESS;\r
- }\r
-\r
- //\r
- // If WaitEvent is NULL, execute in blocking mode.\r
- // BSP checks APs'state until all APs finish or TimeoutInMicrosecsond expires.\r
- //\r
- do {\r
- Status = CheckAllAPs ();\r
- } while (Status == EFI_NOT_READY);\r
-\r
- return Status;\r
-}\r
-\r
-/**\r
- Implementation of StartupThisAP() service of MP Services Protocol.\r
-\r
- This service lets the caller get one enabled AP to execute a caller-provided function.\r
- This service may only be called from the BSP.\r
-\r
- @param This A pointer to the EFI_MP_SERVICES_PROTOCOL instance.\r
- @param Procedure A pointer to the function to be run on the designated AP.\r
- @param ProcessorNumber The handle number of AP..\r
- @param WaitEvent The event created by the caller.\r
- If it is NULL, then execute in blocking mode.\r
- If it is not NULL, then execute in non-blocking mode.\r
- @param TimeoutInMicroseconds The time limit in microseconds for this AP to finish the function.\r
- Zero means infinity.\r
- @param ProcedureArgument Pointer to the optional parameter of the assigned function.\r
- @param Finished Indicates whether AP has finished assigned function.\r
- In blocking mode, it is ignored.\r
-\r
- @retval EFI_SUCCESS In blocking mode, specified AP has finished before the timeout expires.\r
- @retval EFI_SUCCESS In non-blocking mode, function has been dispatched to specified AP.\r
- @retval EFI_DEVICE_ERROR Caller processor is AP.\r
- @retval EFI_TIMEOUT In blocking mode, the timeout expires before specified AP has finished.\r
- @retval EFI_NOT_READY Specified AP is busy.\r
- @retval EFI_NOT_FOUND Processor with the handle specified by ProcessorNumber does not exist.\r
- @retval EFI_INVALID_PARAMETER ProcessorNumber specifies the BSP or disabled AP.\r
- @retval EFI_INVALID_PARAMETER Procedure is NULL.\r
-\r
-**/\r
-EFI_STATUS\r
-EFIAPI\r
-StartupThisAP (\r
- IN EFI_MP_SERVICES_PROTOCOL *This,\r
- IN EFI_AP_PROCEDURE Procedure,\r
- IN UINTN ProcessorNumber,\r
- IN EFI_EVENT WaitEvent OPTIONAL,\r
- IN UINTN TimeoutInMicroseconds,\r
- IN VOID *ProcedureArgument OPTIONAL,\r
- OUT BOOLEAN *Finished OPTIONAL\r
- )\r
-{\r
- CPU_DATA_BLOCK *CpuData;\r
- UINTN CallerNumber;\r
- EFI_STATUS Status;\r
- UINTN BspNumber;\r
-\r
- if (Finished != NULL) {\r
- *Finished = TRUE;\r
- }\r
-\r
- //\r
- // Check whether caller processor is BSP\r
- //\r
- BspNumber = GetBspNumber ();\r
- WhoAmI (This, &CallerNumber);\r
- if (CallerNumber != BspNumber) {\r
- return EFI_DEVICE_ERROR;\r
- }\r
-\r
- //\r
- // Check whether processor with the handle specified by ProcessorNumber exists\r
- //\r
- if (ProcessorNumber >= mNumberOfProcessors) {\r
- return EFI_NOT_FOUND;\r
- }\r
-\r
- //\r
- // Check whether specified processor is BSP\r
- //\r
- if (ProcessorNumber == BspNumber) {\r
- return EFI_INVALID_PARAMETER;\r
- }\r
-\r
- //\r
- // Check parameter Procedure\r
- //\r
- if (Procedure == NULL) {\r
- return EFI_INVALID_PARAMETER;\r
- }\r
-\r
- CpuData = &mMPSystemData.CpuData[ProcessorNumber];\r
-\r
- //\r
- // Temporarily suppress CheckAPsStatus()\r
- //\r
- mStopCheckAPsStatus = TRUE;\r
-\r
- //\r
- // Check whether specified AP is disabled\r
- //\r
- if (CpuData->State == CpuStateDisabled) {\r
- mStopCheckAPsStatus = FALSE;\r
- return EFI_INVALID_PARAMETER;\r
- }\r
-\r
- //\r
- // Check whether specified AP is busy\r
- //\r
- if (CpuData->State != CpuStateIdle) {\r
- mStopCheckAPsStatus = FALSE;\r
- return EFI_NOT_READY;\r
- }\r
-\r
- //\r
- // Wakeup specified AP for Procedure.\r
- //\r
- AcquireSpinLock (&CpuData->CpuDataLock);\r
- CpuData->State = CpuStateReady;\r
- ReleaseSpinLock (&CpuData->CpuDataLock);\r
-\r
- WakeUpAp (\r
- ProcessorNumber,\r
- Procedure,\r
- ProcedureArgument\r
- );\r
-\r
- //\r
- // If WaitEvent is not NULL, execute in non-blocking mode.\r
- // BSP saves data for CheckAPsStatus(), and returns EFI_SUCCESS.\r
- // CheckAPsStatus() will check completion and timeout periodically.\r
- //\r
- CpuData->WaitEvent = WaitEvent;\r
- CpuData->Finished = Finished;\r
- CpuData->ExpectedTime = CalculateTimeout (TimeoutInMicroseconds, &CpuData->CurrentTime);\r
-\r
- //\r
- // Allow CheckAPsStatus()\r
- //\r
- mStopCheckAPsStatus = FALSE;\r
-\r
- if (WaitEvent != NULL) {\r
- return EFI_SUCCESS;\r
- }\r
-\r
- //\r
- // If WaitEvent is NULL, execute in blocking mode.\r
- // BSP checks AP's state until it finishes or TimeoutInMicrosecsond expires.\r
- //\r
- do {\r
- Status = CheckThisAP (ProcessorNumber);\r
- } while (Status == EFI_NOT_READY);\r
-\r
- return Status;\r
-}\r
-\r
-/**\r
- Implementation of SwitchBSP() service of MP Services Protocol.\r
-\r
- This service switches the requested AP to be the BSP from that point onward.\r
- This service may only be called from the current BSP.\r
-\r
- @param This A pointer to the EFI_MP_SERVICES_PROTOCOL instance.\r
- @param ProcessorNumber The handle number of processor.\r
- @param EnableOldBSP Whether to enable or disable the original BSP.\r
-\r
- @retval EFI_SUCCESS BSP successfully switched.\r
- @retval EFI_DEVICE_ERROR Caller processor is AP.\r
- @retval EFI_NOT_FOUND Processor with the handle specified by ProcessorNumber does not exist.\r
- @retval EFI_INVALID_PARAMETER ProcessorNumber specifies the BSP or disabled AP.\r
- @retval EFI_NOT_READY Specified AP is busy.\r
-\r
-**/\r
-EFI_STATUS\r
-EFIAPI\r
-SwitchBSP (\r
- IN EFI_MP_SERVICES_PROTOCOL *This,\r
- IN UINTN ProcessorNumber,\r
- IN BOOLEAN EnableOldBSP\r
- )\r
-{\r
- EFI_STATUS Status;\r
- CPU_DATA_BLOCK *CpuData;\r
- UINTN CallerNumber;\r
- UINTN BspNumber;\r
- UINTN ApicBase;\r
- UINT32 CurrentTimerValue;\r
- UINT32 CurrentTimerRegister;\r
- UINT32 CurrentTimerDivide;\r
- UINT64 CurrentTscValue;\r
- BOOLEAN OldInterruptState;\r
-\r
- //\r
- // Check whether caller processor is BSP\r
- //\r
- BspNumber = GetBspNumber ();\r
- WhoAmI (This, &CallerNumber);\r
- if (CallerNumber != BspNumber) {\r
- return EFI_DEVICE_ERROR;\r
- }\r
-\r
- //\r
- // Check whether processor with the handle specified by ProcessorNumber exists\r
- //\r
- if (ProcessorNumber >= mNumberOfProcessors) {\r
- return EFI_NOT_FOUND;\r
- }\r
-\r
- //\r
- // Check whether specified processor is BSP\r
- //\r
- if (ProcessorNumber == BspNumber) {\r
- return EFI_INVALID_PARAMETER;\r
- }\r
-\r
- CpuData = &mMPSystemData.CpuData[ProcessorNumber];\r
-\r
- //\r
- // Check whether specified AP is disabled\r
- //\r
- if (CpuData->State == CpuStateDisabled) {\r
- return EFI_INVALID_PARAMETER;\r
- }\r
-\r
- //\r
- // Check whether specified AP is busy\r
- //\r
- if (CpuData->State != CpuStateIdle) {\r
- return EFI_NOT_READY;\r
- }\r
-\r
- //\r
- // Save and disable interrupt.\r
- //\r
- OldInterruptState = SaveAndDisableInterrupts ();\r
- \r
- //\r
- // Record the current local APIC timer setting of BSP\r
- //\r
- ApicBase = (UINTN)AsmMsrBitFieldRead64 (MSR_IA32_APIC_BASE, 12, 35) << 12;\r
- CurrentTimerValue = MmioRead32 (ApicBase + APIC_REGISTER_TIMER_COUNT);\r
- CurrentTimerRegister = MmioRead32 (ApicBase + APIC_REGISTER_LVT_TIMER);\r
- CurrentTimerDivide = MmioRead32 (ApicBase + APIC_REGISTER_TIMER_DIVIDE);\r
- //\r
- // Set mask bit (BIT 16) of LVT Timer Register to disable its interrupt\r
- //\r
- MmioBitFieldWrite32 (ApicBase + APIC_REGISTER_LVT_TIMER, 16, 16, 1);\r
-\r
- //\r
- // Record the current TSC value\r
- //\r
- CurrentTscValue = AsmReadTsc ();\r
- \r
- Status = mFrameworkMpService->SwitchBSP (\r
- mFrameworkMpService,\r
- ProcessorNumber,\r
- EnableOldBSP\r
- );\r
- ASSERT_EFI_ERROR (Status);\r
-\r
- //\r
- // Restore TSC value\r
- //\r
- AsmWriteMsr64 (MSR_IA32_TIME_STAMP_COUNTER, CurrentTscValue);\r
-\r
- //\r
- // Restore local APIC timer setting to new BSP\r
- //\r
- MmioWrite32 (ApicBase + APIC_REGISTER_TIMER_DIVIDE, CurrentTimerDivide);\r
- MmioWrite32 (ApicBase + APIC_REGISTER_TIMER_INIT_COUNT, CurrentTimerValue);\r
- MmioWrite32 (ApicBase + APIC_REGISTER_LVT_TIMER, CurrentTimerRegister);\r
-\r
- //\r
- // Restore interrupt state.\r
- //\r
- SetInterruptState (OldInterruptState);\r
- \r
- ChangeCpuState (BspNumber, EnableOldBSP);\r
-\r
- return EFI_SUCCESS;\r
-}\r
-\r
-/**\r
- Implementation of EnableDisableAP() service of MP Services Protocol.\r
-\r
- This service lets the caller enable or disable an AP.\r
- This service may only be called from the BSP.\r
-\r
- @param This A pointer to the EFI_MP_SERVICES_PROTOCOL instance.\r
- @param ProcessorNumber The handle number of processor.\r
- @param EnableAP Indicates whether the newstate of the AP is enabled or disabled.\r
- @param HealthFlag Indicates new health state of the AP..\r
-\r
- @retval EFI_SUCCESS AP successfully enabled or disabled.\r
- @retval EFI_DEVICE_ERROR Caller processor is AP.\r
- @retval EFI_NOT_FOUND Processor with the handle specified by ProcessorNumber does not exist.\r
- @retval EFI_INVALID_PARAMETERS ProcessorNumber specifies the BSP.\r
-\r
-**/\r
-EFI_STATUS\r
-EFIAPI\r
-EnableDisableAP (\r
- IN EFI_MP_SERVICES_PROTOCOL *This,\r
- IN UINTN ProcessorNumber,\r
- IN BOOLEAN EnableAP,\r
- IN UINT32 *HealthFlag OPTIONAL\r
- )\r
-{\r
- EFI_STATUS Status;\r
- UINTN CallerNumber;\r
- EFI_MP_HEALTH HealthState;\r
- EFI_MP_HEALTH *HealthStatePointer;\r
- UINTN BspNumber;\r
-\r
- //\r
- // Check whether caller processor is BSP\r
- //\r
- BspNumber = GetBspNumber ();\r
- WhoAmI (This, &CallerNumber);\r
- if (CallerNumber != BspNumber) {\r
- return EFI_DEVICE_ERROR;\r
- }\r
-\r
- //\r
- // Check whether processor with the handle specified by ProcessorNumber exists\r
- //\r
- if (ProcessorNumber >= mNumberOfProcessors) {\r
- return EFI_NOT_FOUND;\r
- }\r
-\r
- //\r
- // Check whether specified processor is BSP\r
- //\r
- if (ProcessorNumber == BspNumber) {\r
- return EFI_INVALID_PARAMETER;\r
- }\r
-\r
- if (HealthFlag == NULL) {\r
- HealthStatePointer = NULL;\r
- } else {\r
- if ((*HealthFlag & PROCESSOR_HEALTH_STATUS_BIT) == 0) {\r
- HealthState.Flags.Uint32 = 1;\r
- } else {\r
- HealthState.Flags.Uint32 = 0;\r
- }\r
- HealthState.TestStatus = 0;\r
-\r
- HealthStatePointer = &HealthState;\r
- }\r
-\r
- Status = mFrameworkMpService->EnableDisableAP (\r
- mFrameworkMpService,\r
- ProcessorNumber,\r
- EnableAP,\r
- HealthStatePointer\r
- );\r
- ASSERT_EFI_ERROR (Status);\r
-\r
- ChangeCpuState (ProcessorNumber, EnableAP);\r
-\r
- return EFI_SUCCESS;\r
-}\r
-\r
-/**\r
- Implementation of WhoAmI() service of MP Services Protocol.\r
-\r
- This service lets the caller processor get its handle number.\r
- This service may be called from the BSP and APs.\r
-\r
- @param This A pointer to the EFI_MP_SERVICES_PROTOCOL instance.\r
- @param ProcessorNumber Pointer to the handle number of AP.\r
-\r
- @retval EFI_SUCCESS Processor number successfully returned.\r
- @retval EFI_INVALID_PARAMETER ProcessorNumber is NULL\r
-\r
-**/\r
-EFI_STATUS\r
-EFIAPI\r
-WhoAmI (\r
- IN EFI_MP_SERVICES_PROTOCOL *This,\r
- OUT UINTN *ProcessorNumber\r
- )\r
-{\r
- EFI_STATUS Status;\r
-\r
- if (ProcessorNumber == NULL) {\r
- return EFI_INVALID_PARAMETER;\r
- }\r
-\r
- Status = mFrameworkMpService->WhoAmI (\r
- mFrameworkMpService,\r
- ProcessorNumber\r
- );\r
- ASSERT_EFI_ERROR (Status);\r
-\r
- return EFI_SUCCESS;\r
-}\r
-\r
-/**\r
- Checks APs' status periodically.\r
-\r
- This function is triggered by timer periodically to check the\r
- state of APs for StartupAllAPs() and StartupThisAP() executed\r
- in non-blocking mode.\r
-\r
- @param Event Event triggered.\r
- @param Context Parameter passed with the event.\r
-\r
-**/\r
-VOID\r
-EFIAPI\r
-CheckAPsStatus (\r
- IN EFI_EVENT Event,\r
- IN VOID *Context\r
- )\r
-{\r
- UINTN ProcessorNumber;\r
- CPU_DATA_BLOCK *CpuData;\r
- EFI_STATUS Status;\r
-\r
- //\r
- // If CheckAPsStatus() is stopped, then return immediately.\r
- //\r
- if (mStopCheckAPsStatus) {\r
- return;\r
- }\r
-\r
- //\r
- // First, check whether pending StartupAllAPs() exists.\r
- //\r
- if (mMPSystemData.WaitEvent != NULL) {\r
-\r
- Status = CheckAllAPs ();\r
- //\r
- // If all APs finish for StartupAllAPs(), signal the WaitEvent for it..\r
- //\r
- if (Status != EFI_NOT_READY) {\r
- Status = gBS->SignalEvent (mMPSystemData.WaitEvent);\r
- mMPSystemData.WaitEvent = NULL;\r
- }\r
- }\r
-\r
- //\r
- // Second, check whether pending StartupThisAPs() callings exist.\r
- //\r
- for (ProcessorNumber = 0; ProcessorNumber < mNumberOfProcessors; ProcessorNumber++) {\r
-\r
- CpuData = &mMPSystemData.CpuData[ProcessorNumber];\r
-\r
- if (CpuData->WaitEvent == NULL) {\r
- continue;\r
- }\r
-\r
- Status = CheckThisAP (ProcessorNumber);\r
-\r
- if (Status != EFI_NOT_READY) {\r
- gBS->SignalEvent (CpuData->WaitEvent);\r
- CpuData->WaitEvent = NULL;\r
- }\r
- }\r
- return ;\r
-}\r
-\r
-/**\r
- Checks status of all APs.\r
-\r
- This function checks whether all APs have finished task assigned by StartupAllAPs(),\r
- and whether timeout expires.\r
-\r
- @retval EFI_SUCCESS All APs have finished task assigned by StartupAllAPs().\r
- @retval EFI_TIMEOUT The timeout expires.\r
- @retval EFI_NOT_READY APs have not finished task and timeout has not expired.\r
-\r
-**/\r
-EFI_STATUS\r
-CheckAllAPs (\r
- VOID\r
- )\r
-{\r
- UINTN ProcessorNumber;\r
- UINTN NextProcessorNumber;\r
- UINTN ListIndex;\r
- EFI_STATUS Status;\r
- CPU_STATE CpuState;\r
- CPU_DATA_BLOCK *CpuData;\r
-\r
- NextProcessorNumber = 0;\r
-\r
- //\r
- // Go through all APs that are responsible for the StartupAllAPs().\r
- //\r
- for (ProcessorNumber = 0; ProcessorNumber < mNumberOfProcessors; ProcessorNumber++) {\r
- if (!mMPSystemData.CpuList[ProcessorNumber]) {\r
- continue;\r
- }\r
-\r
- CpuData = &mMPSystemData.CpuData[ProcessorNumber];\r
-\r
- //\r
- // Check the CPU state of AP. If it is CpuStateFinished, then the AP has finished its task.\r
- // Only BSP and corresponding AP access this unit of CPU Data. This means the AP will not modify the\r
- // value of state after setting the it to CpuStateFinished, so BSP can safely make use of its value.\r
- //\r
- AcquireSpinLock (&CpuData->CpuDataLock);\r
- CpuState = CpuData->State;\r
- ReleaseSpinLock (&CpuData->CpuDataLock);\r
-\r
- if (CpuState == CpuStateFinished) {\r
- mMPSystemData.FinishCount++;\r
- mMPSystemData.CpuList[ProcessorNumber] = FALSE;\r
-\r
- AcquireSpinLock (&CpuData->CpuDataLock);\r
- CpuData->State = CpuStateIdle;\r
- ReleaseSpinLock (&CpuData->CpuDataLock);\r
-\r
- //\r
- // If in Single Thread mode, then search for the next waiting AP for execution.\r
- //\r
- if (mMPSystemData.SingleThread) {\r
- Status = GetNextWaitingProcessorNumber (&NextProcessorNumber);\r
-\r
- if (!EFI_ERROR (Status)) {\r
- WakeUpAp (\r
- NextProcessorNumber,\r
- mMPSystemData.Procedure,\r
- mMPSystemData.ProcArguments\r
- );\r
- }\r
- }\r
- }\r
- }\r
-\r
- //\r
- // If all APs finish, return EFI_SUCCESS.\r
- //\r
- if (mMPSystemData.FinishCount == mMPSystemData.StartCount) {\r
- return EFI_SUCCESS;\r
- }\r
-\r
- //\r
- // If timeout expires, report timeout.\r
- //\r
- if (CheckTimeout (&mMPSystemData.CurrentTime, &mMPSystemData.TotalTime, mMPSystemData.ExpectedTime)) {\r
- //\r
- // If FailedCpuList is not NULL, record all failed APs in it.\r
- //\r
- if (mMPSystemData.FailedCpuList != NULL) {\r
- *mMPSystemData.FailedCpuList = AllocatePool ((mMPSystemData.StartCount - mMPSystemData.FinishCount + 1) * sizeof(UINTN));\r
- ASSERT (*mMPSystemData.FailedCpuList != NULL);\r
- }\r
- ListIndex = 0;\r
-\r
- for (ProcessorNumber = 0; ProcessorNumber < mNumberOfProcessors; ProcessorNumber++) {\r
- //\r
- // Check whether this processor is responsible for StartupAllAPs().\r
- //\r
- if (mMPSystemData.CpuList[ProcessorNumber]) {\r
- //\r
- // Reset failed APs to idle state\r
- //\r
- ResetProcessorToIdleState (ProcessorNumber);\r
- mMPSystemData.CpuList[ProcessorNumber] = FALSE;\r
- if (mMPSystemData.FailedCpuList != NULL) {\r
- (*mMPSystemData.FailedCpuList)[ListIndex++] = ProcessorNumber;\r
- }\r
- }\r
- }\r
- if (mMPSystemData.FailedCpuList != NULL) {\r
- (*mMPSystemData.FailedCpuList)[ListIndex] = END_OF_CPU_LIST;\r
- }\r
- return EFI_TIMEOUT;\r
- }\r
- return EFI_NOT_READY;\r
-}\r
-\r
-/**\r
- Checks status of specified AP.\r
-\r
- This function checks whether specified AP has finished task assigned by StartupThisAP(),\r
- and whether timeout expires.\r
-\r
- @param ProcessorNumber The handle number of processor.\r
-\r
- @retval EFI_SUCCESS Specified AP has finished task assigned by StartupThisAPs().\r
- @retval EFI_TIMEOUT The timeout expires.\r
- @retval EFI_NOT_READY Specified AP has not finished task and timeout has not expired.\r
-\r
-**/\r
-EFI_STATUS\r
-CheckThisAP (\r
- UINTN ProcessorNumber\r
- )\r
-{\r
- CPU_DATA_BLOCK *CpuData;\r
- CPU_STATE CpuState;\r
-\r
- ASSERT (ProcessorNumber < mNumberOfProcessors);\r
- ASSERT (ProcessorNumber < MAX_CPU_NUMBER);\r
-\r
- CpuData = &mMPSystemData.CpuData[ProcessorNumber];\r
-\r
- //\r
- // Check the CPU state of AP. If it is CpuStateFinished, then the AP has finished its task.\r
- // Only BSP and corresponding AP access this unit of CPU Data. This means the AP will not modify the\r
- // value of state after setting the it to CpuStateFinished, so BSP can safely make use of its value.\r
- //\r
- AcquireSpinLock (&CpuData->CpuDataLock);\r
- CpuState = CpuData->State;\r
- ReleaseSpinLock (&CpuData->CpuDataLock);\r
-\r
- //\r
- // If the APs finishes for StartupThisAP(), return EFI_SUCCESS.\r
- //\r
- if (CpuState == CpuStateFinished) {\r
-\r
- AcquireSpinLock (&CpuData->CpuDataLock);\r
- CpuData->State = CpuStateIdle;\r
- ReleaseSpinLock (&CpuData->CpuDataLock);\r
-\r
- if (CpuData->Finished != NULL) {\r
- *(CpuData->Finished) = TRUE;\r
- }\r
- return EFI_SUCCESS;\r
- } else {\r
- //\r
- // If timeout expires for StartupThisAP(), report timeout.\r
- //\r
- if (CheckTimeout (&CpuData->CurrentTime, &CpuData->TotalTime, CpuData->ExpectedTime)) {\r
-\r
- if (CpuData->Finished != NULL) {\r
- *(CpuData->Finished) = FALSE;\r
- }\r
- //\r
- // Reset failed AP to idle state\r
- //\r
- ResetProcessorToIdleState (ProcessorNumber);\r
-\r
- return EFI_TIMEOUT;\r
- }\r
- }\r
- return EFI_NOT_READY;\r
-}\r
-\r
-/**\r
- Calculate timeout value and return the current performance counter value.\r
-\r
- Calculate the number of performance counter ticks required for a timeout.\r
- If TimeoutInMicroseconds is 0, return value is also 0, which is recognized\r
- as infinity.\r
-\r
- @param TimeoutInMicroseconds Timeout value in microseconds.\r
- @param CurrentTime Returns the current value of the performance counter.\r
-\r
- @return Expected timestamp counter for timeout.\r
- If TimeoutInMicroseconds is 0, return value is also 0, which is recognized\r
- as infinity.\r
-\r
-**/\r
-UINT64\r
-CalculateTimeout (\r
- IN UINTN TimeoutInMicroseconds,\r
- OUT UINT64 *CurrentTime\r
- )\r
-{\r
- //\r
- // Read the current value of the performance counter\r
- //\r
- *CurrentTime = GetPerformanceCounter ();\r
-\r
- //\r
- // If TimeoutInMicroseconds is 0, return value is also 0, which is recognized\r
- // as infinity.\r
- //\r
- if (TimeoutInMicroseconds == 0) {\r
- return 0;\r
- }\r
-\r
- //\r
- // GetPerformanceCounterProperties () returns the timestamp counter's frequency\r
- // in Hz. So multiply the return value with TimeoutInMicroseconds and then divide\r
- // it by 1,000,000, to get the number of ticks for the timeout value.\r
- //\r
- return DivU64x32 (\r
- MultU64x64 (\r
- GetPerformanceCounterProperties (NULL, NULL),\r
- TimeoutInMicroseconds\r
- ),\r
- 1000000\r
- );\r
-}\r
-\r
-/**\r
- Checks whether timeout expires.\r
-\r
- Check whether the number of ellapsed performance counter ticks required for a timeout condition\r
- has been reached. If Timeout is zero, which means infinity, return value is always FALSE.\r
-\r
- @param PreviousTime On input, the value of the performance counter when it was last read.\r
- On output, the current value of the performance counter\r
- @param TotalTime The total amount of ellapsed time in performance counter ticks.\r
- @param Timeout The number of performance counter ticks required to reach a timeout condition.\r
-\r
- @retval TRUE A timeout condition has been reached.\r
- @retval FALSE A timeout condition has not been reached.\r
-\r
-**/\r
-BOOLEAN\r
-CheckTimeout (\r
- IN OUT UINT64 *PreviousTime,\r
- IN UINT64 *TotalTime,\r
- IN UINT64 Timeout\r
- )\r
-{\r
- UINT64 Start;\r
- UINT64 End;\r
- UINT64 CurrentTime;\r
- INT64 Delta;\r
- INT64 Cycle;\r
-\r
- if (Timeout == 0) {\r
- return FALSE;\r
- }\r
- GetPerformanceCounterProperties (&Start, &End);\r
- Cycle = End - Start;\r
- if (Cycle < 0) {\r
- Cycle = -Cycle;\r
- }\r
- Cycle++;\r
- CurrentTime = GetPerformanceCounter();\r
- Delta = (INT64) (CurrentTime - *PreviousTime);\r
- if (Start > End) {\r
- Delta = -Delta;\r
- }\r
- if (Delta < 0) {\r
- Delta += Cycle;\r
- }\r
- *TotalTime += Delta;\r
- *PreviousTime = CurrentTime;\r
- if (*TotalTime > Timeout) {\r
- return TRUE;\r
- }\r
- return FALSE;\r
-}\r
-\r
-/**\r
- Searches for the next waiting AP.\r
-\r
- Search for the next AP that is put in waiting state by single-threaded StartupAllAPs().\r
-\r
- @param NextProcessorNumber Pointer to the processor number of the next waiting AP.\r
-\r
- @retval EFI_SUCCESS The next waiting AP has been found.\r
- @retval EFI_NOT_FOUND No waiting AP exists.\r
-\r
-**/\r
-EFI_STATUS\r
-GetNextWaitingProcessorNumber (\r
- OUT UINTN *NextProcessorNumber\r
- )\r
-{\r
- UINTN ProcessorNumber;\r
-\r
- for (ProcessorNumber = 0; ProcessorNumber < mNumberOfProcessors; ProcessorNumber++) {\r
-\r
- if (mMPSystemData.CpuList[ProcessorNumber]) {\r
- *NextProcessorNumber = ProcessorNumber;\r
- return EFI_SUCCESS;\r
- }\r
- }\r
-\r
- return EFI_NOT_FOUND;\r
-}\r
-\r
-\r
-/**\r
- Wrapper function for all procedures assigned to AP.\r
-\r
- Wrapper function for all procedures assigned to AP via MP service protocol.\r
- It controls states of AP and invokes assigned precedure.\r
-\r
-**/\r
-VOID\r
-ApProcWrapper (\r
- VOID\r
- )\r
-{\r
- EFI_AP_PROCEDURE Procedure;\r
- VOID *Parameter;\r
- UINTN ProcessorNumber;\r
- CPU_DATA_BLOCK *CpuData;\r
-\r
- //\r
- // Program virtual wire mode for AP, since it will be lost after AP wake up\r
- //\r
- ProgramVirtualWireMode ();\r
- DisableLvtInterrupts ();\r
-\r
- //\r
- // Initialize Debug Agent to support source level debug on AP code.\r
- //\r
- InitializeDebugAgent (DEBUG_AGENT_INIT_DXE_AP, NULL, NULL);\r
-\r
- WhoAmI (&mMpService, &ProcessorNumber);\r
- CpuData = &mMPSystemData.CpuData[ProcessorNumber];\r
-\r
- AcquireSpinLock (&CpuData->CpuDataLock);\r
- CpuData->State = CpuStateBusy;\r
- ReleaseSpinLock (&CpuData->CpuDataLock);\r
-\r
- //\r
- // Now let us check it out.\r
- //\r
- AcquireSpinLock (&CpuData->CpuDataLock);\r
- Procedure = CpuData->Procedure;\r
- Parameter = CpuData->Parameter;\r
- ReleaseSpinLock (&CpuData->CpuDataLock);\r
-\r
- if (Procedure != NULL) {\r
-\r
- Procedure (Parameter);\r
-\r
- //\r
- // if BSP is switched to AP, it continue execute from here, but it carries register state\r
- // of the old AP, so need to reload CpuData (might be stored in a register after compiler\r
- // optimization) to make sure it points to the right data\r
- //\r
- WhoAmI (&mMpService, &ProcessorNumber);\r
- CpuData = &mMPSystemData.CpuData[ProcessorNumber];\r
-\r
- AcquireSpinLock (&CpuData->CpuDataLock);\r
- CpuData->Procedure = NULL;\r
- ReleaseSpinLock (&CpuData->CpuDataLock);\r
- }\r
-\r
- AcquireSpinLock (&CpuData->CpuDataLock);\r
- CpuData->State = CpuStateFinished;\r
- ReleaseSpinLock (&CpuData->CpuDataLock);\r
-}\r
-\r
-/**\r
- Function to wake up a specified AP and assign procedure to it.\r
-\r
- @param ProcessorNumber Handle number of the specified processor.\r
- @param Procedure Procedure to assign.\r
- @param ProcArguments Argument for Procedure.\r
-\r
-**/\r
-VOID\r
-WakeUpAp (\r
- IN UINTN ProcessorNumber,\r
- IN EFI_AP_PROCEDURE Procedure,\r
- IN VOID *ProcArguments\r
- )\r
-{\r
- EFI_STATUS Status;\r
- CPU_DATA_BLOCK *CpuData;\r
- EFI_PROCESSOR_INFORMATION ProcessorInfoBuffer;\r
-\r
- ASSERT (ProcessorNumber < mNumberOfProcessors);\r
- ASSERT (ProcessorNumber < MAX_CPU_NUMBER);\r
-\r
- CpuData = &mMPSystemData.CpuData[ProcessorNumber];\r
-\r
- AcquireSpinLock (&CpuData->CpuDataLock);\r
- CpuData->Parameter = ProcArguments;\r
- CpuData->Procedure = Procedure;\r
- ReleaseSpinLock (&CpuData->CpuDataLock);\r
-\r
- Status = GetProcessorInfo (\r
- &mMpService,\r
- ProcessorNumber,\r
- &ProcessorInfoBuffer\r
- );\r
- ASSERT_EFI_ERROR (Status);\r
-\r
- mExchangeInfo->ApFunction = (VOID *) (UINTN) ApProcWrapper;\r
- mExchangeInfo->ProcessorNumber[ProcessorInfoBuffer.ProcessorId] = (UINT32) ProcessorNumber;\r
- SendInitSipiSipi (\r
- (UINT32) ProcessorInfoBuffer.ProcessorId,\r
- (UINT32) (UINTN) mStartupVector\r
- );\r
-}\r
-\r
-/**\r
- Terminate AP's task and set it to idle state.\r
-\r
- This function terminates AP's task due to timeout by sending INIT-SIPI,\r
- and sends it to idle state.\r
-\r
- @param ProcessorNumber Handle number of the specified processor.\r
-\r
-**/\r
-VOID\r
-ResetProcessorToIdleState (\r
- UINTN ProcessorNumber\r
- )\r
-{\r
- EFI_STATUS Status;\r
- CPU_DATA_BLOCK *CpuData;\r
- EFI_PROCESSOR_INFORMATION ProcessorInfoBuffer;\r
-\r
- Status = GetProcessorInfo (\r
- &mMpService,\r
- ProcessorNumber,\r
- &ProcessorInfoBuffer\r
- );\r
- ASSERT_EFI_ERROR (Status);\r
-\r
- mExchangeInfo->ApFunction = NULL;\r
- mExchangeInfo->ProcessorNumber[ProcessorInfoBuffer.ProcessorId] = (UINT32) ProcessorNumber;\r
- SendInitSipiSipi (\r
- (UINT32) ProcessorInfoBuffer.ProcessorId,\r
- (UINT32) (UINTN) mStartupVector\r
- );\r
-\r
- CpuData = &mMPSystemData.CpuData[ProcessorNumber];\r
-\r
- AcquireSpinLock (&CpuData->CpuDataLock);\r
- CpuData->State = CpuStateIdle;\r
- ReleaseSpinLock (&CpuData->CpuDataLock);\r
-}\r
-\r
-/**\r
- Worker function of EnableDisableAP ()\r
-\r
- Worker function of EnableDisableAP (). Changes state of specified processor.\r
-\r
- @param ProcessorNumber Processor number of specified AP.\r
- @param NewState Desired state of the specified AP.\r
-\r
- @retval EFI_SUCCESS AP's state successfully changed.\r
-\r
-**/\r
-EFI_STATUS\r
-ChangeCpuState (\r
- IN UINTN ProcessorNumber,\r
- IN BOOLEAN NewState\r
- )\r
-{\r
- CPU_DATA_BLOCK *CpuData;\r
-\r
- ASSERT (ProcessorNumber < mNumberOfProcessors);\r
- ASSERT (ProcessorNumber < MAX_CPU_NUMBER);\r
-\r
- CpuData = &mMPSystemData.CpuData[ProcessorNumber];\r
-\r
- if (!NewState) {\r
- AcquireSpinLock (&CpuData->CpuDataLock);\r
- CpuData->State = CpuStateDisabled;\r
- ReleaseSpinLock (&CpuData->CpuDataLock);\r
- } else {\r
- AcquireSpinLock (&CpuData->CpuDataLock);\r
- CpuData->State = CpuStateIdle;\r
- ReleaseSpinLock (&CpuData->CpuDataLock);\r
- }\r
-\r
- return EFI_SUCCESS;\r
-}\r
-\r
-/**\r
- Test memory region of EfiGcdMemoryTypeReserved.\r
-\r
- @param Length The length of memory region to test.\r
-\r
- @retval EFI_SUCCESS The memory region passes test.\r
- @retval EFI_NOT_FOUND The memory region is not reserved memory.\r
- @retval EFI_DEVICE_ERROR The memory fails on test.\r
-\r
-**/\r
-EFI_STATUS\r
-TestReservedMemory (\r
- UINTN Length\r
- )\r
-{\r
- EFI_STATUS Status;\r
- EFI_GCD_MEMORY_SPACE_DESCRIPTOR Descriptor;\r
- EFI_PHYSICAL_ADDRESS Address;\r
- UINTN LengthCovered;\r
- UINTN RemainingLength;\r
-\r
- //\r
- // Walk through the memory descriptors covering the memory range.\r
- //\r
- Address = mStartupVector;\r
- RemainingLength = Length;\r
- while (Address < mStartupVector + Length) {\r
- Status = gDS->GetMemorySpaceDescriptor(\r
- Address,\r
- &Descriptor\r
- );\r
- if (EFI_ERROR (Status)) {\r
- return EFI_NOT_FOUND;\r
- }\r
-\r
- if (Descriptor.GcdMemoryType != EfiGcdMemoryTypeReserved) {\r
- return EFI_NOT_FOUND;\r
- }\r
- //\r
- // Calculated the length of the intersected range.\r
- //\r
- LengthCovered = (UINTN) (Descriptor.BaseAddress + Descriptor.Length - Address);\r
- if (LengthCovered > RemainingLength) {\r
- LengthCovered = RemainingLength;\r
- }\r
-\r
- Status = mGenMemoryTest->CompatibleRangeTest (\r
- mGenMemoryTest,\r
- Address,\r
- LengthCovered\r
- );\r
- if (EFI_ERROR (Status)) {\r
- return EFI_DEVICE_ERROR;\r
- }\r
-\r
- Address += LengthCovered;\r
- RemainingLength -= LengthCovered;\r
- }\r
-\r
- return EFI_SUCCESS;\r
-}\r
-\r
-/**\r
- Allocates startup vector for APs.\r
-\r
- This function allocates Startup vector for APs.\r
-\r
- @param Size The size of startup vector.\r
-\r
-**/\r
-VOID\r
-AllocateStartupVector (\r
- UINTN Size\r
- )\r
-{\r
- EFI_STATUS Status;\r
-\r
- Status = gBS->LocateProtocol (\r
- &gEfiGenericMemTestProtocolGuid,\r
- NULL,\r
- (VOID **) &mGenMemoryTest\r
- );\r
- if (EFI_ERROR (Status)) {\r
- mGenMemoryTest = NULL;\r
- }\r
-\r
- for (mStartupVector = 0x7F000; mStartupVector >= 0x2000; mStartupVector -= EFI_PAGE_SIZE) {\r
- if (mGenMemoryTest != NULL) {\r
- //\r
- // Test memory if it is EfiGcdMemoryTypeReserved.\r
- //\r
- Status = TestReservedMemory (EFI_SIZE_TO_PAGES (Size) * EFI_PAGE_SIZE);\r
- if (Status == EFI_DEVICE_ERROR) {\r
- continue;\r
- }\r
- }\r
-\r
- Status = gBS->AllocatePages (\r
- AllocateAddress,\r
- EfiBootServicesCode,\r
- EFI_SIZE_TO_PAGES (Size),\r
- &mStartupVector\r
- );\r
-\r
- if (!EFI_ERROR (Status)) {\r
- break;\r
- }\r
- }\r
-\r
- ASSERT_EFI_ERROR (Status);\r
-}\r
-\r
-/**\r
- Prepares Startup Vector for APs.\r
-\r
- This function prepares Startup Vector for APs.\r
-\r
-**/\r
-VOID\r
-PrepareAPStartupVector (\r
- VOID\r
- )\r
-{\r
- MP_ASSEMBLY_ADDRESS_MAP AddressMap;\r
- IA32_DESCRIPTOR GdtrForBSP;\r
- IA32_DESCRIPTOR IdtrForBSP;\r
- EFI_PHYSICAL_ADDRESS GdtForAP;\r
- EFI_PHYSICAL_ADDRESS IdtForAP;\r
- EFI_STATUS Status;\r
-\r
- //\r
- // Get the address map of startup code for AP,\r
- // including code size, and offset of long jump instructions to redirect.\r
- //\r
- AsmGetAddressMap (&AddressMap);\r
-\r
- //\r
- // Allocate a 4K-aligned region under 1M for startup vector for AP.\r
- // The region contains AP startup code and exchange data between BSP and AP.\r
- //\r
- AllocateStartupVector (AddressMap.Size + sizeof (MP_CPU_EXCHANGE_INFO));\r
-\r
- //\r
- // Copy AP startup code to startup vector, and then redirect the long jump\r
- // instructions for mode switching.\r
- //\r
- CopyMem ((VOID *) (UINTN) mStartupVector, AddressMap.RendezvousFunnelAddress, AddressMap.Size);\r
- *(UINT32 *) (UINTN) (mStartupVector + AddressMap.FlatJumpOffset + 3) = (UINT32) (mStartupVector + AddressMap.PModeEntryOffset);\r
- //\r
- // For IA32 mode, LongJumpOffset is filled with zero. If non-zero, then we are in X64 mode, so further redirect for long mode switch.\r
- //\r
- if (AddressMap.LongJumpOffset != 0) {\r
- *(UINT32 *) (UINTN) (mStartupVector + AddressMap.LongJumpOffset + 2) = (UINT32) (mStartupVector + AddressMap.LModeEntryOffset);\r
- }\r
-\r
- //\r
- // Get the start address of exchange data between BSP and AP.\r
- //\r
- mExchangeInfo = (MP_CPU_EXCHANGE_INFO *) (UINTN) (mStartupVector + AddressMap.Size);\r
-\r
- ZeroMem ((VOID *) mExchangeInfo, sizeof (MP_CPU_EXCHANGE_INFO));\r
-\r
- mExchangeInfo->StackStart = AllocatePages (EFI_SIZE_TO_PAGES (mNumberOfProcessors * AP_STACK_SIZE));\r
- mExchangeInfo->StackSize = AP_STACK_SIZE;\r
-\r
- AsmReadGdtr (&GdtrForBSP);\r
- AsmReadIdtr (&IdtrForBSP);\r
-\r
- //\r
- // Allocate memory under 4G to hold GDT for APs\r
- //\r
- GdtForAP = 0xffffffff;\r
- Status = gBS->AllocatePages (\r
- AllocateMaxAddress,\r
- EfiBootServicesData,\r
- EFI_SIZE_TO_PAGES ((GdtrForBSP.Limit + 1) + (IdtrForBSP.Limit + 1)),\r
- &GdtForAP\r
- );\r
- ASSERT_EFI_ERROR (Status);\r
-\r
- IdtForAP = (UINTN) GdtForAP + GdtrForBSP.Limit + 1;\r
-\r
- CopyMem ((VOID *) (UINTN) GdtForAP, (VOID *) GdtrForBSP.Base, GdtrForBSP.Limit + 1);\r
- CopyMem ((VOID *) (UINTN) IdtForAP, (VOID *) IdtrForBSP.Base, IdtrForBSP.Limit + 1);\r
-\r
- mExchangeInfo->GdtrProfile.Base = (UINTN) GdtForAP;\r
- mExchangeInfo->GdtrProfile.Limit = GdtrForBSP.Limit;\r
- mExchangeInfo->IdtrProfile.Base = (UINTN) IdtForAP;\r
- mExchangeInfo->IdtrProfile.Limit = IdtrForBSP.Limit;\r
-\r
- mExchangeInfo->BufferStart = (UINT32) mStartupVector;\r
- mExchangeInfo->Cr3 = (UINT32) (AsmReadCr3 ());\r
-}\r
-\r
-/**\r
- Prepares memory region for processor configuration.\r
-\r
- This function prepares memory region for processor configuration.\r
-\r
-**/\r
-VOID\r
-PrepareMemoryForConfiguration (\r
- VOID\r
- )\r
-{\r
- UINTN Index;\r
-\r
- //\r
- // Initialize Spin Locks for system\r
- //\r
- InitializeSpinLock (&mMPSystemData.APSerializeLock);\r
- for (Index = 0; Index < MAX_CPU_NUMBER; Index++) {\r
- InitializeSpinLock (&mMPSystemData.CpuData[Index].CpuDataLock);\r
- }\r
-\r
- PrepareAPStartupVector ();\r
-}\r
-\r
-/**\r
- Gets the processor number of BSP.\r
-\r
- @return The processor number of BSP.\r
-\r
-**/\r
-UINTN\r
-GetBspNumber (\r
- VOID\r
- )\r
-{\r
- UINTN ProcessorNumber;\r
- EFI_MP_PROC_CONTEXT ProcessorContextBuffer;\r
- EFI_STATUS Status;\r
- UINTN BufferSize;\r
-\r
- BufferSize = sizeof (EFI_MP_PROC_CONTEXT);\r
-\r
- for (ProcessorNumber = 0; ProcessorNumber < mNumberOfProcessors; ProcessorNumber++) {\r
- Status = mFrameworkMpService->GetProcessorContext (\r
- mFrameworkMpService,\r
- ProcessorNumber,\r
- &BufferSize,\r
- &ProcessorContextBuffer\r
- );\r
- ASSERT_EFI_ERROR (Status);\r
-\r
- if (ProcessorContextBuffer.Designation == EfiCpuBSP) {\r
- break;\r
- }\r
- }\r
- ASSERT (ProcessorNumber < mNumberOfProcessors);\r
-\r
- return ProcessorNumber;\r
-}\r
-\r
-/**\r
- Entrypoint of MP Services Protocol thunk driver.\r
-\r
- @param[in] ImageHandle The firmware allocated handle for the EFI image.\r
- @param[in] SystemTable A pointer to the EFI System Table.\r
-\r
- @retval EFI_SUCCESS The entry point is executed successfully.\r
-\r
-**/\r
-EFI_STATUS\r
-EFIAPI\r
-InitializeMpServicesProtocol (\r
- IN EFI_HANDLE ImageHandle,\r
- IN EFI_SYSTEM_TABLE *SystemTable\r
- )\r
-{\r
- EFI_STATUS Status;\r
-\r
- //\r
- // Locates Framework version MP Services Protocol\r
- //\r
- Status = gBS->LocateProtocol (\r
- &gFrameworkEfiMpServiceProtocolGuid,\r
- NULL,\r
- (VOID **) &mFrameworkMpService\r
- );\r
- ASSERT_EFI_ERROR (Status);\r
-\r
- Status = mFrameworkMpService->GetGeneralMPInfo (\r
- mFrameworkMpService,\r
- &mNumberOfProcessors,\r
- NULL,\r
- NULL,\r
- NULL,\r
- NULL\r
- );\r
- ASSERT_EFI_ERROR (Status);\r
- ASSERT (mNumberOfProcessors < MAX_CPU_NUMBER);\r
-\r
- PrepareMemoryForConfiguration ();\r
-\r
- //\r
- // Create timer event to check AP state for non-blocking execution.\r
- //\r
- Status = gBS->CreateEvent (\r
- EVT_TIMER | EVT_NOTIFY_SIGNAL,\r
- TPL_CALLBACK,\r
- CheckAPsStatus,\r
- NULL,\r
- &mMPSystemData.CheckAPsEvent\r
- );\r
- ASSERT_EFI_ERROR (Status);\r
-\r
- //\r
- // Now install the MP services protocol.\r
- //\r
- Status = gBS->InstallProtocolInterface (\r
- &mHandle,\r
- &gEfiMpServiceProtocolGuid,\r
- EFI_NATIVE_INTERFACE,\r
- &mMpService\r
- );\r
- ASSERT_EFI_ERROR (Status);\r
-\r
- //\r
- // Launch the timer event to check AP state.\r
- //\r
- Status = gBS->SetTimer (\r
- mMPSystemData.CheckAPsEvent,\r
- TimerPeriodic,\r
- 100000\r
- );\r
- ASSERT_EFI_ERROR (Status);\r
-\r
- return EFI_SUCCESS;\r
-}\r