X-Git-Url: https://git.proxmox.com/?a=blobdiff_plain;f=UefiCpuPkg%2FCpuDxe%2FCpuMp.c;h=de6c6a5c330c97fadc23df164ad0f3af98bfa0e4;hb=a7ef158b07524f9afd0cefa3180aeac0fcb6e436;hp=f3a5a24b0f6639aa9005a74eff9a54990fe532e9;hpb=1aa6bf528926f8f012a0f2a77bdf53374551a9ec;p=mirror_edk2.git
diff --git a/UefiCpuPkg/CpuDxe/CpuMp.c b/UefiCpuPkg/CpuDxe/CpuMp.c
index f3a5a24b0f..de6c6a5c33 100644
--- a/UefiCpuPkg/CpuDxe/CpuMp.c
+++ b/UefiCpuPkg/CpuDxe/CpuMp.c
@@ -1,34 +1,16 @@
/** @file
- CPU DXE Module.
+ CPU DXE Module to produce CPU MP Protocol.
- Copyright (c) 2008 - 2015, Intel Corporation. All rights reserved.
- This program and the accompanying materials
- are licensed and made available under the terms and conditions of the BSD License
- which accompanies this distribution. The full text of the license may be found at
- http://opensource.org/licenses/bsd-license.php
-
- THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
- WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+ Copyright (c) 2008 - 2017, Intel Corporation. All rights reserved.
+ SPDX-License-Identifier: BSD-2-Clause-Patent
**/
#include "CpuDxe.h"
#include "CpuMp.h"
-UINTN gMaxLogicalProcessorNumber;
-UINTN gApStackSize;
-UINTN gPollInterval = 100; // 100 microseconds
-
-MP_SYSTEM_DATA mMpSystemData;
EFI_HANDLE mMpServiceHandle = NULL;
-EFI_EVENT mExitBootServicesEvent = (EFI_EVENT)NULL;
-
-VOID *mCommonStack = 0;
-VOID *mTopOfApCommonStack = 0;
-VOID *mApStackStart = 0;
-
-volatile BOOLEAN mAPsAlreadyInitFinished = FALSE;
-volatile BOOLEAN mStopCheckAllAPsStatus = TRUE;
+UINTN mNumberOfProcessors = 1;
EFI_MP_SERVICES_PROTOCOL mMpServicesTemplate = {
GetNumberOfProcessors,
@@ -40,370 +22,6 @@ EFI_MP_SERVICES_PROTOCOL mMpServicesTemplate = {
WhoAmI
};
-/**
- Get Mp Service Lock.
-
- @param CpuData the pointer to CPU_DATA_BLOCK of specified processor
-
-**/
-VOID
-GetMpSpinLock (
- IN CPU_DATA_BLOCK *CpuData
- )
-{
- while (!AcquireSpinLockOrFail (&CpuData->CpuDataLock)) {
- CpuPause ();
- }
- CpuData->LockSelf = GetApicId ();
-}
-
-/**
- Release Mp Service Lock.
-
- @param CpuData the pointer to CPU_DATA_BLOCK of specified processor
-
-**/
-VOID
-ReleaseMpSpinLock (
- IN CPU_DATA_BLOCK *CpuData
- )
-{
- ReleaseSpinLock (&CpuData->CpuDataLock);
-}
-
-/**
- Check whether caller processor is BSP.
-
- @retval TRUE the caller is BSP
- @retval FALSE the caller is AP
-
-**/
-BOOLEAN
-IsBSP (
- VOID
- )
-{
- UINTN CpuIndex;
- CPU_DATA_BLOCK *CpuData;
-
- CpuData = NULL;
-
- WhoAmI (&mMpServicesTemplate, &CpuIndex);
- CpuData = &mMpSystemData.CpuDatas[CpuIndex];
-
- return CpuData->Info.StatusFlag & PROCESSOR_AS_BSP_BIT ? TRUE : FALSE;
-}
-
-/**
- Get the Application Processors state.
-
- @param CpuData the pointer to CPU_DATA_BLOCK of specified AP
-
- @retval CPU_STATE the AP status
-
-**/
-CPU_STATE
-GetApState (
- IN CPU_DATA_BLOCK *CpuData
- )
-{
- CPU_STATE State;
-
- GetMpSpinLock (CpuData);
- State = CpuData->State;
- ReleaseMpSpinLock (CpuData);
-
- return State;
-}
-
-/**
- Set the Application Processors state.
-
- @param CpuData The pointer to CPU_DATA_BLOCK of specified AP
- @param State The AP status
-
-**/
-VOID
-SetApState (
- IN CPU_DATA_BLOCK *CpuData,
- IN CPU_STATE State
- )
-{
- GetMpSpinLock (CpuData);
- CpuData->State = State;
- ReleaseMpSpinLock (CpuData);
-}
-
-/**
- Set the Application Processor prepare to run a function specified
- by Params.
-
- @param CpuData the pointer to CPU_DATA_BLOCK of specified AP
- @param Procedure A pointer to the function to be run on enabled APs of the system
- @param ProcedureArgument Pointer to the optional parameter of the assigned function
-
-**/
-VOID
-SetApProcedure (
- IN CPU_DATA_BLOCK *CpuData,
- IN EFI_AP_PROCEDURE Procedure,
- IN VOID *ProcedureArgument
- )
-{
- GetMpSpinLock (CpuData);
- CpuData->Parameter = ProcedureArgument;
- CpuData->Procedure = Procedure;
- ReleaseMpSpinLock (CpuData);
-}
-
-/**
- Check the Application Processors Status whether contains the Flags.
-
- @param CpuData the pointer to CPU_DATA_BLOCK of specified AP
- @param Flags the StatusFlag describing in EFI_PROCESSOR_INFORMATION
-
- @retval TRUE the AP status includes the StatusFlag
- @retval FALSE the AP status excludes the StatusFlag
-
-**/
-BOOLEAN
-TestCpuStatusFlag (
- IN CPU_DATA_BLOCK *CpuData,
- IN UINT32 Flags
- )
-{
- UINT32 Ret;
-
- GetMpSpinLock (CpuData);
- Ret = CpuData->Info.StatusFlag & Flags;
- ReleaseMpSpinLock (CpuData);
-
- return (BOOLEAN) (Ret != 0);
-}
-
-/**
- Bitwise-Or of the Application Processors Status with the Flags.
-
- @param CpuData the pointer to CPU_DATA_BLOCK of specified AP
- @param Flags the StatusFlag describing in EFI_PROCESSOR_INFORMATION
-
-**/
-VOID
-CpuStatusFlagOr (
- IN CPU_DATA_BLOCK *CpuData,
- IN UINT32 Flags
- )
-{
- GetMpSpinLock (CpuData);
- CpuData->Info.StatusFlag |= Flags;
- ReleaseMpSpinLock (CpuData);
-}
-
-/**
- Bitwise-AndNot of the Application Processors Status with the Flags.
-
- @param CpuData the pointer to CPU_DATA_BLOCK of specified AP
- @param Flags the StatusFlag describing in EFI_PROCESSOR_INFORMATION
-
-**/
-VOID
-CpuStatusFlagAndNot (
- IN CPU_DATA_BLOCK *CpuData,
- IN UINT32 Flags
- )
-{
- GetMpSpinLock (CpuData);
- CpuData->Info.StatusFlag &= ~Flags;
- ReleaseMpSpinLock (CpuData);
-}
-
-/**
- Searches for the next blocking AP.
-
- Search for the next AP that is put in blocking state by single-threaded StartupAllAPs().
-
- @param NextNumber Pointer to the processor number of the next blocking AP.
-
- @retval EFI_SUCCESS The next blocking AP has been found.
- @retval EFI_NOT_FOUND No blocking AP exists.
-
-**/
-EFI_STATUS
-GetNextBlockedNumber (
- OUT UINTN *NextNumber
- )
-{
- UINTN Number;
- CPU_STATE CpuState;
- CPU_DATA_BLOCK *CpuData;
-
- for (Number = 0; Number < mMpSystemData.NumberOfProcessors; Number++) {
- CpuData = &mMpSystemData.CpuDatas[Number];
- if (TestCpuStatusFlag (CpuData, PROCESSOR_AS_BSP_BIT)) {
- //
- // Skip BSP
- //
- continue;
- }
-
- CpuState = GetApState (CpuData);
- if (CpuState == CpuStateBlocked) {
- *NextNumber = Number;
- return EFI_SUCCESS;
- }
- }
-
- return EFI_NOT_FOUND;
-}
-
-/**
- Check if the APs state are finished, and update them to idle state
- by StartupAllAPs().
-
-**/
-VOID
-CheckAndUpdateAllAPsToIdleState (
- VOID
- )
-{
- UINTN ProcessorNumber;
- UINTN NextNumber;
- CPU_DATA_BLOCK *CpuData;
- EFI_STATUS Status;
- CPU_STATE CpuState;
-
- for (ProcessorNumber = 0; ProcessorNumber < mMpSystemData.NumberOfProcessors; ProcessorNumber++) {
- CpuData = &mMpSystemData.CpuDatas[ProcessorNumber];
- if (TestCpuStatusFlag (CpuData, PROCESSOR_AS_BSP_BIT)) {
- //
- // Skip BSP
- //
- continue;
- }
-
- if (!TestCpuStatusFlag (CpuData, PROCESSOR_ENABLED_BIT)) {
- //
- // Skip Disabled processors
- //
- continue;
- }
-
- CpuState = GetApState (CpuData);
- if (CpuState == CpuStateFinished) {
- mMpSystemData.FinishCount++;
- if (mMpSystemData.SingleThread) {
- Status = GetNextBlockedNumber (&NextNumber);
- if (!EFI_ERROR (Status)) {
- SetApState (&mMpSystemData.CpuDatas[NextNumber], CpuStateReady);
- SetApProcedure (&mMpSystemData.CpuDatas[NextNumber],
- mMpSystemData.Procedure,
- mMpSystemData.ProcedureArgument);
- //
- // If this AP previous state is blocked, we should
- // wake up this AP by sent a SIPI. and avoid
- // re-involve the sleeping state. we must call
- // SetApProcedure() first.
- //
- ResetProcessorToIdleState (&mMpSystemData.CpuDatas[NextNumber]);
- }
- }
- SetApState (CpuData, CpuStateIdle);
- }
- }
-}
-
-/**
- Check if all APs are in state CpuStateSleeping.
-
- Return TRUE if all APs are in the CpuStateSleeping state. Do not
- check the state of the BSP or any disabled APs.
-
- @retval TRUE All APs are in CpuStateSleeping state.
- @retval FALSE One or more APs are not in CpuStateSleeping state.
-
-**/
-BOOLEAN
-CheckAllAPsSleeping (
- VOID
- )
-{
- UINTN ProcessorNumber;
- CPU_DATA_BLOCK *CpuData;
-
- for (ProcessorNumber = 0; ProcessorNumber < mMpSystemData.NumberOfProcessors; ProcessorNumber++) {
- CpuData = &mMpSystemData.CpuDatas[ProcessorNumber];
- if (TestCpuStatusFlag (CpuData, PROCESSOR_AS_BSP_BIT)) {
- //
- // Skip BSP
- //
- continue;
- }
-
- if (!TestCpuStatusFlag (CpuData, PROCESSOR_ENABLED_BIT)) {
- //
- // Skip Disabled processors
- //
- continue;
- }
-
- if (GetApState (CpuData) != CpuStateSleeping) {
- return FALSE;
- }
- }
- return TRUE;
-}
-
-/**
- If the timeout expires before all APs returns from Procedure,
- we should forcibly terminate the executing AP and fill FailedList back
- by StartupAllAPs().
-
-**/
-VOID
-ResetAllFailedAPs (
- VOID
- )
-{
- CPU_DATA_BLOCK *CpuData;
- UINTN Number;
- CPU_STATE CpuState;
-
- if (mMpSystemData.FailedList != NULL) {
- *mMpSystemData.FailedList = AllocatePool ((mMpSystemData.StartCount - mMpSystemData.FinishCount + 1) * sizeof(UINTN));
- ASSERT (*mMpSystemData.FailedList != NULL);
- }
-
- for (Number = 0; Number < mMpSystemData.NumberOfProcessors; Number++) {
- CpuData = &mMpSystemData.CpuDatas[Number];
- if (TestCpuStatusFlag (CpuData, PROCESSOR_AS_BSP_BIT)) {
- //
- // Skip BSP
- //
- continue;
- }
-
- if (!TestCpuStatusFlag (CpuData, PROCESSOR_ENABLED_BIT)) {
- //
- // Skip Disabled processors
- //
- continue;
- }
-
- CpuState = GetApState (CpuData);
- if (CpuState != CpuStateIdle &&
- CpuState != CpuStateSleeping) {
- if (mMpSystemData.FailedList != NULL) {
- (*mMpSystemData.FailedList)[mMpSystemData.FailedListIndex++] = Number;
- }
- ResetProcessorToIdleState (CpuData);
- }
- }
-
- if (mMpSystemData.FailedList != NULL) {
- (*mMpSystemData.FailedList)[mMpSystemData.FailedListIndex] = END_OF_CPU_LIST;
- }
-}
-
/**
This service retrieves the number of logical processor in the platform
and the number of those logical processors that are enabled on this boot.
@@ -452,13 +70,10 @@ GetNumberOfProcessors (
return EFI_INVALID_PARAMETER;
}
- if (!IsBSP ()) {
- return EFI_DEVICE_ERROR;
- }
-
- *NumberOfProcessors = mMpSystemData.NumberOfProcessors;
- *NumberOfEnabledProcessors = mMpSystemData.NumberOfEnabledProcessors;
- return EFI_SUCCESS;
+ return MpInitLibGetNumberOfProcessors (
+ NumberOfProcessors,
+ NumberOfEnabledProcessors
+ );
}
/**
@@ -495,20 +110,7 @@ GetProcessorInfo (
OUT EFI_PROCESSOR_INFORMATION *ProcessorInfoBuffer
)
{
- if (ProcessorInfoBuffer == NULL) {
- return EFI_INVALID_PARAMETER;
- }
-
- if (!IsBSP ()) {
- return EFI_DEVICE_ERROR;
- }
-
- if (ProcessorNumber >= mMpSystemData.NumberOfProcessors) {
- return EFI_NOT_FOUND;
- }
-
- CopyMem (ProcessorInfoBuffer, &mMpSystemData.CpuDatas[ProcessorNumber], sizeof (EFI_PROCESSOR_INFORMATION));
- return EFI_SUCCESS;
+ return MpInitLibGetProcessorInfo (ProcessorNumber, ProcessorInfoBuffer, NULL);
}
/**
@@ -659,155 +261,14 @@ StartupAllAPs (
OUT UINTN **FailedCpuList OPTIONAL
)
{
- EFI_STATUS Status;
- CPU_DATA_BLOCK *CpuData;
- UINTN Number;
- CPU_STATE APInitialState;
- CPU_STATE CpuState;
-
- CpuData = NULL;
-
- if (FailedCpuList != NULL) {
- *FailedCpuList = NULL;
- }
-
- if (!IsBSP ()) {
- return EFI_DEVICE_ERROR;
- }
-
- if (mMpSystemData.NumberOfProcessors == 1) {
- return EFI_NOT_STARTED;
- }
-
- if (Procedure == NULL) {
- return EFI_INVALID_PARAMETER;
- }
-
- //
- // temporarily stop checkAllAPsStatus for avoid resource dead-lock.
- //
- mStopCheckAllAPsStatus = TRUE;
-
- for (Number = 0; Number < mMpSystemData.NumberOfProcessors; Number++) {
- CpuData = &mMpSystemData.CpuDatas[Number];
- if (TestCpuStatusFlag (CpuData, PROCESSOR_AS_BSP_BIT)) {
- //
- // Skip BSP
- //
- continue;
- }
-
- if (!TestCpuStatusFlag (CpuData, PROCESSOR_ENABLED_BIT)) {
- //
- // Skip Disabled processors
- //
- continue;
- }
-
- CpuState = GetApState (CpuData);
- if (CpuState != CpuStateIdle &&
- CpuState != CpuStateSleeping) {
- return EFI_NOT_READY;
- }
- }
-
- mMpSystemData.Procedure = Procedure;
- mMpSystemData.ProcedureArgument = ProcedureArgument;
- mMpSystemData.WaitEvent = WaitEvent;
- mMpSystemData.Timeout = TimeoutInMicroseconds;
- mMpSystemData.TimeoutActive = (BOOLEAN) (TimeoutInMicroseconds != 0);
- mMpSystemData.FinishCount = 0;
- mMpSystemData.StartCount = 0;
- mMpSystemData.SingleThread = SingleThread;
- mMpSystemData.FailedList = FailedCpuList;
- mMpSystemData.FailedListIndex = 0;
- APInitialState = CpuStateReady;
-
- for (Number = 0; Number < mMpSystemData.NumberOfProcessors; Number++) {
- CpuData = &mMpSystemData.CpuDatas[Number];
- if (TestCpuStatusFlag (CpuData, PROCESSOR_AS_BSP_BIT)) {
- //
- // Skip BSP
- //
- continue;
- }
-
- if (!TestCpuStatusFlag (CpuData, PROCESSOR_ENABLED_BIT)) {
- //
- // Skip Disabled processors
- //
- continue;
- }
-
- //
- // Get APs prepared, and put failing APs into FailedCpuList
- // if "SingleThread", only 1 AP will put to ready state, other AP will be put to ready
- // state 1 by 1, until the previous 1 finished its task
- // if not "SingleThread", all APs are put to ready state from the beginning
- //
- CpuState = GetApState (CpuData);
- if (CpuState == CpuStateIdle ||
- CpuState == CpuStateSleeping) {
- mMpSystemData.StartCount++;
-
- SetApState (CpuData, APInitialState);
-
- if (APInitialState == CpuStateReady) {
- SetApProcedure (CpuData, Procedure, ProcedureArgument);
- //
- // If this AP previous state is Sleeping, we should
- // wake up this AP by sent a SIPI. and avoid
- // re-involve the sleeping state. we must call
- // SetApProcedure() first.
- //
- if (CpuState == CpuStateSleeping) {
- ResetProcessorToIdleState (CpuData);
- }
- }
-
- if (SingleThread) {
- APInitialState = CpuStateBlocked;
- }
- }
- }
-
- mStopCheckAllAPsStatus = FALSE;
-
- if (WaitEvent != NULL) {
- //
- // non blocking
- //
- return EFI_SUCCESS;
- }
-
- //
- // Blocking temporarily stop CheckAllAPsStatus()
- //
- mStopCheckAllAPsStatus = TRUE;
-
- while (TRUE) {
- CheckAndUpdateAllAPsToIdleState ();
- if (mMpSystemData.FinishCount == mMpSystemData.StartCount) {
- Status = EFI_SUCCESS;
- goto Done;
- }
-
- //
- // task timeout
- //
- if (mMpSystemData.TimeoutActive && mMpSystemData.Timeout < 0) {
- ResetAllFailedAPs();
- Status = EFI_TIMEOUT;
- goto Done;
- }
-
- gBS->Stall (gPollInterval);
- mMpSystemData.Timeout -= gPollInterval;
- }
-
-Done:
-
- return Status;
+ return MpInitLibStartupAllAPs (
+ Procedure,
+ SingleThread,
+ WaitEvent,
+ TimeoutInMicroseconds,
+ ProcedureArgument,
+ FailedCpuList
+ );
}
/**
@@ -832,8 +293,8 @@ Done:
@param[in] This A pointer to the EFI_MP_SERVICES_PROTOCOL
instance.
- @param[in] Procedure A pointer to the function to be run on
- enabled APs of the system. See type
+ @param[in] Procedure A pointer to the function to be run on the
+ designated AP of the system. See type
EFI_AP_PROCEDURE.
@param[in] ProcessorNumber The handle number of the AP. The range is
from 0 to the total number of logical
@@ -842,13 +303,13 @@ Done:
EFI_MP_SERVICES_PROTOCOL.GetNumberOfProcessors().
@param[in] WaitEvent The event created by the caller with CreateEvent()
service. If it is NULL, then execute in
- blocking mode. BSP waits until all APs finish
- or TimeoutInMicroseconds expires. If it's
+ blocking mode. BSP waits until this AP finish
+ or TimeoutInMicroSeconds expires. If it's
not NULL, then execute in non-blocking mode.
BSP requests the function specified by
- Procedure to be started on all the enabled
- APs, and go on executing immediately. If
- all return from Procedure or TimeoutInMicroseconds
+ Procedure to be started on this AP,
+ and go on executing immediately. If this AP
+ return from Procedure or TimeoutInMicroSeconds
expires, this event is signaled. The BSP
can use the CheckEvent() or WaitForEvent()
services to check the state of event. Type
@@ -856,20 +317,20 @@ Done:
the Unified Extensible Firmware Interface
Specification.
@param[in] TimeoutInMicroseconds Indicates the time limit in microseconds for
- APs to return from Procedure, either for
+ this AP to finish this Procedure, either for
blocking or non-blocking mode. Zero means
infinity. If the timeout expires before
- all APs return from Procedure, then Procedure
- on the failed APs is terminated. All enabled
- APs are available for next function assigned
+ this AP returns from Procedure, then Procedure
+ on the AP is terminated. The
+ AP is available for next function assigned
by EFI_MP_SERVICES_PROTOCOL.StartupAllAPs()
or EFI_MP_SERVICES_PROTOCOL.StartupThisAP().
If the timeout expires in blocking mode,
BSP returns EFI_TIMEOUT. If the timeout
expires in non-blocking mode, WaitEvent
is signaled with SignalEvent().
- @param[in] ProcedureArgument The parameter passed into Procedure for
- all APs.
+ @param[in] ProcedureArgument The parameter passed into Procedure on the
+ specified AP.
@param[out] Finished If NULL, this parameter is ignored. In
blocking mode, this parameter is ignored.
In non-blocking mode, if AP returns from
@@ -908,90 +369,14 @@ StartupThisAP (
OUT BOOLEAN *Finished OPTIONAL
)
{
- CPU_DATA_BLOCK *CpuData;
- CPU_STATE CpuState;
-
- CpuData = NULL;
-
- if (Finished != NULL) {
- *Finished = FALSE;
- }
-
- if (!IsBSP ()) {
- return EFI_DEVICE_ERROR;
- }
-
- if (Procedure == NULL) {
- return EFI_INVALID_PARAMETER;
- }
-
- if (ProcessorNumber >= mMpSystemData.NumberOfProcessors) {
- return EFI_NOT_FOUND;
- }
-
- //
- // temporarily stop checkAllAPsStatus for avoid resource dead-lock.
- //
- mStopCheckAllAPsStatus = TRUE;
-
- CpuData = &mMpSystemData.CpuDatas[ProcessorNumber];
- if (TestCpuStatusFlag (CpuData, PROCESSOR_AS_BSP_BIT) ||
- !TestCpuStatusFlag (CpuData, PROCESSOR_ENABLED_BIT)) {
- return EFI_INVALID_PARAMETER;
- }
-
- CpuState = GetApState (CpuData);
- if (CpuState != CpuStateIdle &&
- CpuState != CpuStateSleeping) {
- return EFI_NOT_READY;
- }
-
- SetApState (CpuData, CpuStateReady);
-
- SetApProcedure (CpuData, Procedure, ProcedureArgument);
- //
- // If this AP previous state is Sleeping, we should
- // wake up this AP by sent a SIPI. and avoid
- // re-involve the sleeping state. we must call
- // SetApProcedure() first.
- //
- if (CpuState == CpuStateSleeping) {
- ResetProcessorToIdleState (CpuData);
- }
-
- CpuData->Timeout = TimeoutInMicroseconds;
- CpuData->WaitEvent = WaitEvent;
- CpuData->TimeoutActive = (BOOLEAN) (TimeoutInMicroseconds != 0);
- CpuData->Finished = Finished;
-
- mStopCheckAllAPsStatus = FALSE;
-
- if (WaitEvent != NULL) {
- //
- // Non Blocking
- //
- return EFI_SUCCESS;
- }
-
- //
- // Blocking
- //
- while (TRUE) {
- if (GetApState (CpuData) == CpuStateFinished) {
- SetApState (CpuData, CpuStateIdle);
- break;
- }
-
- if (CpuData->TimeoutActive && CpuData->Timeout < 0) {
- ResetProcessorToIdleState (CpuData);
- return EFI_TIMEOUT;
- }
-
- gBS->Stall (gPollInterval);
- CpuData->Timeout -= gPollInterval;
- }
-
- return EFI_SUCCESS;
+ return MpInitLibStartupThisAP (
+ Procedure,
+ ProcessorNumber,
+ WaitEvent,
+ TimeoutInMicroseconds,
+ ProcedureArgument,
+ Finished
+ );
}
/**
@@ -1021,7 +406,7 @@ StartupThisAP (
@retval EFI_UNSUPPORTED Switching the BSP cannot be completed prior to
this service returning.
@retval EFI_UNSUPPORTED Switching the BSP is not supported.
- @retval EFI_SUCCESS The calling processor is an AP.
+ @retval EFI_DEVICE_ERROR The calling processor is an AP.
@retval EFI_NOT_FOUND The processor with the handle specified by
ProcessorNumber does not exist.
@retval EFI_INVALID_PARAMETER ProcessorNumber specifies the current BSP or
@@ -1037,10 +422,7 @@ SwitchBSP (
IN BOOLEAN EnableOldBSP
)
{
- //
- // Current always return unsupported.
- //
- return EFI_UNSUPPORTED;
+ return MpInitLibSwitchBSP (ProcessorNumber, EnableOldBSP);
}
/**
@@ -1059,8 +441,8 @@ SwitchBSP (
from this service, then EFI_UNSUPPORTED must be returned.
@param[in] This A pointer to the EFI_MP_SERVICES_PROTOCOL instance.
- @param[in] ProcessorNumber The handle number of AP that is to become the new
- BSP. The range is from 0 to the total number of
+ @param[in] ProcessorNumber The handle number of AP.
+ The range is from 0 to the total number of
logical processors minus 1. The total number of
logical processors can be retrieved by
EFI_MP_SERVICES_PROTOCOL.GetNumberOfProcessors().
@@ -1093,62 +475,7 @@ EnableDisableAP (
IN UINT32 *HealthFlag OPTIONAL
)
{
- CPU_DATA_BLOCK *CpuData;
- BOOLEAN TempStopCheckState;
- CPU_STATE CpuState;
-
- CpuData = NULL;
- TempStopCheckState = FALSE;
-
- if (!IsBSP ()) {
- return EFI_DEVICE_ERROR;
- }
-
- if (ProcessorNumber >= mMpSystemData.NumberOfProcessors) {
- return EFI_NOT_FOUND;
- }
-
- //
- // temporarily stop checkAllAPsStatus for initialize parameters.
- //
- if (!mStopCheckAllAPsStatus) {
- mStopCheckAllAPsStatus = TRUE;
- TempStopCheckState = TRUE;
- }
-
- CpuData = &mMpSystemData.CpuDatas[ProcessorNumber];
- if (TestCpuStatusFlag (CpuData, PROCESSOR_AS_BSP_BIT)) {
- return EFI_INVALID_PARAMETER;
- }
-
- CpuState = GetApState (CpuData);
- if (CpuState != CpuStateIdle &&
- CpuState != CpuStateSleeping) {
- return EFI_UNSUPPORTED;
- }
-
- if (EnableAP) {
- if (!(TestCpuStatusFlag (CpuData, PROCESSOR_ENABLED_BIT))) {
- mMpSystemData.NumberOfEnabledProcessors++;
- }
- CpuStatusFlagOr (CpuData, PROCESSOR_ENABLED_BIT);
- } else {
- if (TestCpuStatusFlag (CpuData, PROCESSOR_ENABLED_BIT)) {
- mMpSystemData.NumberOfEnabledProcessors--;
- }
- CpuStatusFlagAndNot (CpuData, PROCESSOR_ENABLED_BIT);
- }
-
- if (HealthFlag != NULL) {
- CpuStatusFlagAndNot (CpuData, (UINT32)~PROCESSOR_HEALTH_STATUS_BIT);
- CpuStatusFlagOr (CpuData, (*HealthFlag & PROCESSOR_HEALTH_STATUS_BIT));
- }
-
- if (TempStopCheckState) {
- mStopCheckAllAPsStatus = FALSE;
- }
-
- return EFI_SUCCESS;
+ return MpInitLibEnableDisableAP (ProcessorNumber, EnableAP, HealthFlag);
}
/**
@@ -1164,8 +491,8 @@ EnableDisableAP (
ProcessorNumber, and EFI_SUCCESS is returned.
@param[in] This A pointer to the EFI_MP_SERVICES_PROTOCOL instance.
- @param[out] ProcessorNumber The handle number of AP that is to become the new
- BSP. The range is from 0 to the total number of
+ @param[out] ProcessorNumber Pointer to the handle number of AP.
+ The range is from 0 to the total number of
logical processors minus 1. The total number of
logical processors can be retrieved by
EFI_MP_SERVICES_PROTOCOL.GetNumberOfProcessors().
@@ -1182,383 +509,7 @@ WhoAmI (
OUT UINTN *ProcessorNumber
)
{
- UINTN Index;
- UINT32 ProcessorId;
-
- if (ProcessorNumber == NULL) {
- return EFI_INVALID_PARAMETER;
- }
-
- ProcessorId = GetApicId ();
- for (Index = 0; Index < mMpSystemData.NumberOfProcessors; Index++) {
- if (mMpSystemData.CpuDatas[Index].Info.ProcessorId == ProcessorId) {
- break;
- }
- }
-
- *ProcessorNumber = Index;
- return EFI_SUCCESS;
-}
-
-/**
- Terminate AP's task and set it to idle state.
-
- This function terminates AP's task due to timeout by sending INIT-SIPI,
- and sends it to idle state.
-
- @param CpuData the pointer to CPU_DATA_BLOCK of specified AP
-
-**/
-VOID
-ResetProcessorToIdleState (
- IN CPU_DATA_BLOCK *CpuData
- )
-{
- ResetApStackless ((UINT32)CpuData->Info.ProcessorId);
-}
-
-/**
- Application Processors do loop routine
- after switch to its own stack.
-
- @param Context1 A pointer to the context to pass into the function.
- @param Context2 A pointer to the context to pass into the function.
-
-**/
-VOID
-ProcessorToIdleState (
- IN VOID *Context1, OPTIONAL
- IN VOID *Context2 OPTIONAL
- )
-{
- UINTN ProcessorNumber;
- CPU_DATA_BLOCK *CpuData;
- EFI_AP_PROCEDURE Procedure;
- volatile VOID *ProcedureArgument;
-
- AsmApDoneWithCommonStack ();
-
- while (!mAPsAlreadyInitFinished) {
- CpuPause ();
- }
-
- WhoAmI (&mMpServicesTemplate, &ProcessorNumber);
- CpuData = &mMpSystemData.CpuDatas[ProcessorNumber];
-
- //
- // Avoid forcibly reset AP caused the AP got lock not release.
- //
- if (CpuData->LockSelf == (INTN) GetApicId ()) {
- ReleaseSpinLock (&CpuData->CpuDataLock);
- }
-
- //
- // Avoid forcibly reset AP caused the timeout AP State is not
- // updated.
- //
- GetMpSpinLock (CpuData);
- if (CpuData->State == CpuStateBusy) {
- CpuData->Procedure = NULL;
- }
- CpuData->State = CpuStateIdle;
- ReleaseMpSpinLock (CpuData);
-
- while (TRUE) {
- GetMpSpinLock (CpuData);
- ProcedureArgument = CpuData->Parameter;
- Procedure = CpuData->Procedure;
- ReleaseMpSpinLock (CpuData);
-
- if (Procedure != NULL) {
- SetApState (CpuData, CpuStateBusy);
-
- Procedure ((VOID*) ProcedureArgument);
-
- GetMpSpinLock (CpuData);
- CpuData->Procedure = NULL;
- CpuData->State = CpuStateFinished;
- ReleaseMpSpinLock (CpuData);
- } else {
- //
- // if no procedure to execution, we simply put AP
- // into sleeping state, and waiting BSP sent SIPI.
- //
- GetMpSpinLock (CpuData);
- if (CpuData->State == CpuStateIdle) {
- CpuData->State = CpuStateSleeping;
- }
- ReleaseMpSpinLock (CpuData);
- }
-
- if (GetApState (CpuData) == CpuStateSleeping) {
- CpuSleep ();
- }
-
- CpuPause ();
- }
-
- CpuSleep ();
- CpuDeadLoop ();
-}
-
-/**
- Checks AP' status periodically.
-
- This function is triggerred by timer perodically to check the
- state of AP forStartupThisAP() executed in non-blocking mode.
-
- @param Event Event triggered.
- @param Context Parameter passed with the event.
-
-**/
-VOID
-EFIAPI
-CheckThisAPStatus (
- IN EFI_EVENT Event,
- IN VOID *Context
- )
-{
- CPU_DATA_BLOCK *CpuData;
- CPU_STATE CpuState;
-
- CpuData = (CPU_DATA_BLOCK *) Context;
- if (CpuData->TimeoutActive) {
- CpuData->Timeout -= gPollInterval;
- }
-
- CpuState = GetApState (CpuData);
-
- if (CpuState == CpuStateFinished) {
- if (CpuData->Finished) {
- *CpuData->Finished = TRUE;
- }
- SetApState (CpuData, CpuStateIdle);
- goto out;
- }
-
- if (CpuData->TimeoutActive && CpuData->Timeout < 0) {
- if (CpuState != CpuStateIdle &&
- CpuData->Finished) {
- *CpuData->Finished = FALSE;
- }
- ResetProcessorToIdleState (CpuData);
- goto out;
- }
-
- return;
-
-out:
- CpuData->TimeoutActive = FALSE;
- gBS->SignalEvent (CpuData->WaitEvent);
- CpuData->WaitEvent = NULL;
-}
-
-/**
- Checks APs' status periodically.
-
- This function is triggerred by timer perodically to check the
- state of APs for StartupAllAPs() executed in non-blocking mode.
-
- @param Event Event triggered.
- @param Context Parameter passed with the event.
-
-**/
-VOID
-EFIAPI
-CheckAllAPsStatus (
- IN EFI_EVENT Event,
- IN VOID *Context
- )
-{
- CPU_DATA_BLOCK *CpuData;
- UINTN Number;
- EFI_STATUS Status;
-
- if (mMpSystemData.TimeoutActive) {
- mMpSystemData.Timeout -= gPollInterval;
- }
-
- if (mStopCheckAllAPsStatus) {
- return;
- }
-
- //
- // avoid next timer enter.
- //
- Status = gBS->SetTimer (
- mMpSystemData.CheckAllAPsEvent,
- TimerCancel,
- 0
- );
- ASSERT_EFI_ERROR (Status);
-
- if (mMpSystemData.WaitEvent != NULL) {
- CheckAndUpdateAllAPsToIdleState ();
- //
- // task timeout
- //
- if (mMpSystemData.TimeoutActive && mMpSystemData.Timeout < 0) {
- ResetAllFailedAPs();
- //
- // force exit
- //
- mMpSystemData.FinishCount = mMpSystemData.StartCount;
- }
-
- if (mMpSystemData.FinishCount != mMpSystemData.StartCount) {
- goto EXIT;
- }
-
- mMpSystemData.TimeoutActive = FALSE;
- gBS->SignalEvent (mMpSystemData.WaitEvent);
- mMpSystemData.WaitEvent = NULL;
- mStopCheckAllAPsStatus = TRUE;
-
- goto EXIT;
- }
-
- //
- // check each AP status for StartupThisAP
- //
- for (Number = 0; Number < mMpSystemData.NumberOfProcessors; Number++) {
- CpuData = &mMpSystemData.CpuDatas[Number];
- if (CpuData->WaitEvent) {
- CheckThisAPStatus (NULL, (VOID *)CpuData);
- }
- }
-
-EXIT:
- Status = gBS->SetTimer (
- mMpSystemData.CheckAllAPsEvent,
- TimerPeriodic,
- EFI_TIMER_PERIOD_MICROSECONDS (100)
- );
- ASSERT_EFI_ERROR (Status);
-}
-
-/**
- Application Processor C code entry point.
-
-**/
-VOID
-EFIAPI
-ApEntryPointInC (
- VOID
- )
-{
- VOID* TopOfApStack;
- UINTN ProcessorNumber;
-
- if (!mAPsAlreadyInitFinished) {
- FillInProcessorInformation (FALSE, mMpSystemData.NumberOfProcessors);
- TopOfApStack = (UINT8*)mApStackStart + gApStackSize;
- mApStackStart = TopOfApStack;
-
- //
- // Store the Stack address, when reset the AP, We can found the original address.
- //
- mMpSystemData.CpuDatas[mMpSystemData.NumberOfProcessors].TopOfStack = TopOfApStack;
- mMpSystemData.NumberOfProcessors++;
- mMpSystemData.NumberOfEnabledProcessors++;
- } else {
- WhoAmI (&mMpServicesTemplate, &ProcessorNumber);
- //
- // Get the original stack address.
- //
- TopOfApStack = mMpSystemData.CpuDatas[ProcessorNumber].TopOfStack;
- }
-
- SwitchStack (
- (SWITCH_STACK_ENTRY_POINT)(UINTN)ProcessorToIdleState,
- NULL,
- NULL,
- TopOfApStack);
-}
-
-/**
- This function is called by all processors (both BSP and AP) once and collects MP related data.
-
- @param Bsp TRUE if the CPU is BSP
- @param ProcessorNumber The specific processor number
-
- @retval EFI_SUCCESS Data for the processor collected and filled in
-
-**/
-EFI_STATUS
-FillInProcessorInformation (
- IN BOOLEAN Bsp,
- IN UINTN ProcessorNumber
- )
-{
- CPU_DATA_BLOCK *CpuData;
- UINT32 ProcessorId;
-
- CpuData = &mMpSystemData.CpuDatas[ProcessorNumber];
- ProcessorId = GetApicId ();
- CpuData->Info.ProcessorId = ProcessorId;
- CpuData->Info.StatusFlag = PROCESSOR_ENABLED_BIT | PROCESSOR_HEALTH_STATUS_BIT;
- if (Bsp) {
- CpuData->Info.StatusFlag |= PROCESSOR_AS_BSP_BIT;
- }
- CpuData->Info.Location.Package = ProcessorId;
- CpuData->Info.Location.Core = 0;
- CpuData->Info.Location.Thread = 0;
- CpuData->State = Bsp ? CpuStateBusy : CpuStateIdle;
-
- CpuData->Procedure = NULL;
- CpuData->Parameter = NULL;
- InitializeSpinLock (&CpuData->CpuDataLock);
- CpuData->LockSelf = -1;
-
- return EFI_SUCCESS;
-}
-
-/**
- Prepare the System Data.
-
- @retval EFI_SUCCESS the System Data finished initilization.
-
-**/
-EFI_STATUS
-InitMpSystemData (
- VOID
- )
-{
- EFI_STATUS Status;
-
- ZeroMem (&mMpSystemData, sizeof (MP_SYSTEM_DATA));
-
- mMpSystemData.NumberOfProcessors = 1;
- mMpSystemData.NumberOfEnabledProcessors = 1;
-
- mMpSystemData.CpuDatas = AllocateZeroPool (sizeof (CPU_DATA_BLOCK) * gMaxLogicalProcessorNumber);
- ASSERT(mMpSystemData.CpuDatas != NULL);
-
- Status = gBS->CreateEvent (
- EVT_TIMER | EVT_NOTIFY_SIGNAL,
- TPL_CALLBACK,
- CheckAllAPsStatus,
- NULL,
- &mMpSystemData.CheckAllAPsEvent
- );
- ASSERT_EFI_ERROR (Status);
-
- //
- // Set timer to check all APs status.
- //
- Status = gBS->SetTimer (
- mMpSystemData.CheckAllAPsEvent,
- TimerPeriodic,
- EFI_TIMER_PERIOD_MICROSECONDS (100)
- );
- ASSERT_EFI_ERROR (Status);
-
- //
- // BSP
- //
- FillInProcessorInformation (TRUE, 0);
-
- return EFI_SUCCESS;
+ return MpInitLibWhoAmI (ProcessorNumber);;
}
/**
@@ -1580,8 +531,9 @@ CollectBistDataFromHob (
EFI_SEC_PLATFORM_INFORMATION_CPU *CpuInstance;
EFI_SEC_PLATFORM_INFORMATION_CPU BspCpuInstance;
UINTN ProcessorNumber;
- UINT32 InitialLocalApicId;
- CPU_DATA_BLOCK *CpuData;
+ EFI_PROCESSOR_INFORMATION ProcessorInfo;
+ EFI_HEALTH_FLAGS BistData;
+ UINTN CpuInstanceNumber;
SecPlatformInformation2 = NULL;
SecPlatformInformation = NULL;
@@ -1613,7 +565,7 @@ CollectBistDataFromHob (
BspCpuInstance.InfoRecord.IA32HealthFlags.Uint32 = SecPlatformInformation->IA32HealthFlags.Uint32;
CpuInstance = &BspCpuInstance;
} else {
- DEBUG ((EFI_D_INFO, "Does not find any HOB stored CPU BIST information!\n"));
+ DEBUG ((DEBUG_INFO, "Does not find any HOB stored CPU BIST information!\n"));
//
// Does not find any HOB stored BIST information
//
@@ -1621,127 +573,266 @@ CollectBistDataFromHob (
}
}
- while ((NumberOfData--) > 0) {
- for (ProcessorNumber = 0; ProcessorNumber < mMpSystemData.NumberOfProcessors; ProcessorNumber++) {
- CpuData = &mMpSystemData.CpuDatas[ProcessorNumber];
- InitialLocalApicId = (UINT32) CpuData->Info.ProcessorId;
- if (InitialLocalApicId == CpuInstance[NumberOfData].CpuLocation) {
+ for (ProcessorNumber = 0; ProcessorNumber < mNumberOfProcessors; ProcessorNumber++) {
+ MpInitLibGetProcessorInfo (ProcessorNumber, &ProcessorInfo, &BistData);
+ for (CpuInstanceNumber = 0; CpuInstanceNumber < NumberOfData; CpuInstanceNumber++) {
+ if (ProcessorInfo.ProcessorId == CpuInstance[CpuInstanceNumber].CpuLocation) {
//
// Update CPU health status for MP Services Protocol according to BIST data.
//
- if (CpuInstance[NumberOfData].InfoRecord.IA32HealthFlags.Uint32 != 0) {
- CpuData->Info.StatusFlag &= ~PROCESSOR_HEALTH_STATUS_BIT;
- //
- // Report Status Code that self test is failed
- //
- REPORT_STATUS_CODE (
- EFI_ERROR_CODE | EFI_ERROR_MAJOR,
- (EFI_COMPUTING_UNIT_HOST_PROCESSOR | EFI_CU_HP_EC_SELF_TEST)
- );
- }
+ BistData = CpuInstance[CpuInstanceNumber].InfoRecord.IA32HealthFlags;
}
}
+ if (BistData.Uint32 != 0) {
+ //
+ // Report Status Code that self test is failed
+ //
+ REPORT_STATUS_CODE (
+ EFI_ERROR_CODE | EFI_ERROR_MAJOR,
+ (EFI_COMPUTING_UNIT_HOST_PROCESSOR | EFI_CU_HP_EC_SELF_TEST)
+ );
+ }
}
}
/**
- Callback function for ExitBootServices.
+ Get GDT register value.
+
+ This function is mainly for AP purpose because AP may have different GDT
+ table than BSP.
- @param Event Event whose notification function is being invoked.
- @param Context The pointer to the notification function's context,
- which is implementation-dependent.
+ @param[in,out] Buffer The pointer to private data buffer.
**/
VOID
EFIAPI
-ExitBootServicesCallback (
- IN EFI_EVENT Event,
- IN VOID *Context
+GetGdtr (
+ IN OUT VOID *Buffer
)
{
+ AsmReadGdtr ((IA32_DESCRIPTOR *)Buffer);
+}
+
+/**
+ Initializes CPU exceptions handlers for the sake of stack switch requirement.
+
+ This function is a wrapper of InitializeCpuExceptionHandlersEx. It's mainly
+ for the sake of AP's init because of EFI_AP_PROCEDURE API requirement.
+
+ @param[in,out] Buffer The pointer to private data buffer.
+
+**/
+VOID
+EFIAPI
+InitializeExceptionStackSwitchHandlers (
+ IN OUT VOID *Buffer
+ )
+{
+ CPU_EXCEPTION_INIT_DATA *EssData;
+ IA32_DESCRIPTOR Idtr;
+ EFI_STATUS Status;
+
+ EssData = Buffer;
//
- // Avoid APs access invalid buff datas which allocated by BootServices,
- // so we send INIT IPI to APs to let them wait for SIPI state.
+ // We don't plan to replace IDT table with a new one, but we should not assume
+ // the AP's IDT is the same as BSP's IDT either.
//
- SendInitIpiAllExcludingSelf ();
+ AsmReadIdtr (&Idtr);
+ EssData->Ia32.IdtTable = (VOID *)Idtr.Base;
+ EssData->Ia32.IdtTableSize = Idtr.Limit + 1;
+ Status = InitializeCpuExceptionHandlersEx (NULL, EssData);
+ ASSERT_EFI_ERROR (Status);
}
/**
- Initialize Multi-processor support.
+ Initializes MP exceptions handlers for the sake of stack switch requirement.
+
+ This function will allocate required resources required to setup stack switch
+ and pass them through CPU_EXCEPTION_INIT_DATA to each logic processor.
**/
VOID
-InitializeMpSupport (
+InitializeMpExceptionStackSwitchHandlers (
VOID
)
{
- EFI_STATUS Status;
- UINTN Timeout;
+ UINTN Index;
+ UINTN Bsp;
+ UINTN ExceptionNumber;
+ UINTN OldGdtSize;
+ UINTN NewGdtSize;
+ UINTN NewStackSize;
+ IA32_DESCRIPTOR Gdtr;
+ CPU_EXCEPTION_INIT_DATA EssData;
+ UINT8 *GdtBuffer;
+ UINT8 *StackTop;
- gMaxLogicalProcessorNumber = (UINTN) PcdGet32 (PcdCpuMaxLogicalProcessorNumber);
- if (gMaxLogicalProcessorNumber < 1) {
- DEBUG ((DEBUG_ERROR, "Setting PcdCpuMaxLogicalProcessorNumber should be more than zero.\n"));
- return;
- }
+ ExceptionNumber = FixedPcdGetSize (PcdCpuStackSwitchExceptionList);
+ NewStackSize = FixedPcdGet32 (PcdCpuKnownGoodStackSize) * ExceptionNumber;
+ StackTop = AllocateRuntimeZeroPool (NewStackSize * mNumberOfProcessors);
+ ASSERT (StackTop != NULL);
+ StackTop += NewStackSize * mNumberOfProcessors;
+ //
+ // The default exception handlers must have been initialized. Let's just skip
+ // it in this method.
+ //
+ EssData.Ia32.Revision = CPU_EXCEPTION_INIT_DATA_REV;
+ EssData.Ia32.InitDefaultHandlers = FALSE;
- InitMpSystemData ();
+ EssData.Ia32.StackSwitchExceptions = FixedPcdGetPtr(PcdCpuStackSwitchExceptionList);
+ EssData.Ia32.StackSwitchExceptionNumber = ExceptionNumber;
+ EssData.Ia32.KnownGoodStackSize = FixedPcdGet32(PcdCpuKnownGoodStackSize);
//
- // Only perform AP detection if PcdCpuMaxLogicalProcessorNumber is greater than 1
+ // Initialize Gdtr to suppress incorrect compiler/analyzer warnings.
//
- if (gMaxLogicalProcessorNumber > 1) {
-
- gApStackSize = (UINTN) PcdGet32 (PcdCpuApStackSize);
- ASSERT ((gApStackSize & (SIZE_4KB - 1)) == 0);
+ Gdtr.Base = 0;
+ Gdtr.Limit = 0;
+ MpInitLibWhoAmI (&Bsp);
+ for (Index = 0; Index < mNumberOfProcessors; ++Index) {
+ //
+ // To support stack switch, we need to re-construct GDT but not IDT.
+ //
+ if (Index == Bsp) {
+ GetGdtr (&Gdtr);
+ } else {
+ //
+ // AP might have different size of GDT from BSP.
+ //
+ MpInitLibStartupThisAP (GetGdtr, Index, NULL, 0, (VOID *)&Gdtr, NULL);
+ }
- mApStackStart = AllocatePages (EFI_SIZE_TO_PAGES (gMaxLogicalProcessorNumber * gApStackSize));
- ASSERT (mApStackStart != NULL);
+ //
+ // X64 needs only one TSS of current task working for all exceptions
+ // because of its IST feature. IA32 needs one TSS for each exception
+ // in addition to current task. Since AP is not supposed to allocate
+ // memory, we have to do it in BSP. To simplify the code, we allocate
+ // memory for IA32 case to cover both IA32 and X64 exception stack
+ // switch.
+ //
+ // Layout of memory to allocate for each processor:
+ // --------------------------------
+ // | Alignment | (just in case)
+ // --------------------------------
+ // | |
+ // | Original GDT |
+ // | |
+ // --------------------------------
+ // | Current task descriptor |
+ // --------------------------------
+ // | |
+ // | Exception task descriptors | X ExceptionNumber
+ // | |
+ // --------------------------------
+ // | Current task-state segment |
+ // --------------------------------
+ // | |
+ // | Exception task-state segment | X ExceptionNumber
+ // | |
+ // --------------------------------
+ //
+ OldGdtSize = Gdtr.Limit + 1;
+ EssData.Ia32.ExceptionTssDescSize = sizeof (IA32_TSS_DESCRIPTOR) *
+ (ExceptionNumber + 1);
+ EssData.Ia32.ExceptionTssSize = sizeof (IA32_TASK_STATE_SEGMENT) *
+ (ExceptionNumber + 1);
+ NewGdtSize = sizeof (IA32_TSS_DESCRIPTOR) +
+ OldGdtSize +
+ EssData.Ia32.ExceptionTssDescSize +
+ EssData.Ia32.ExceptionTssSize;
+
+ GdtBuffer = AllocateRuntimeZeroPool (NewGdtSize);
+ ASSERT (GdtBuffer != NULL);
//
- // the first buffer of stack size used for common stack, when the amount of AP
- // more than 1, we should never free the common stack which maybe used for AP reset.
+ // Make sure GDT table alignment
//
- mCommonStack = mApStackStart;
- mTopOfApCommonStack = (UINT8*) mApStackStart + gApStackSize;
- mApStackStart = mTopOfApCommonStack;
+ EssData.Ia32.GdtTable = ALIGN_POINTER(GdtBuffer, sizeof (IA32_TSS_DESCRIPTOR));
+ NewGdtSize -= ((UINT8 *)EssData.Ia32.GdtTable - GdtBuffer);
+ EssData.Ia32.GdtTableSize = NewGdtSize;
+
+ EssData.Ia32.ExceptionTssDesc = ((UINT8 *)EssData.Ia32.GdtTable + OldGdtSize);
+ EssData.Ia32.ExceptionTss = ((UINT8 *)EssData.Ia32.GdtTable + OldGdtSize +
+ EssData.Ia32.ExceptionTssDescSize);
+
+ EssData.Ia32.KnownGoodStackTop = (UINTN)StackTop;
+ DEBUG ((DEBUG_INFO,
+ "Exception stack top[cpu%lu]: 0x%lX\n",
+ (UINT64)(UINTN)Index,
+ (UINT64)(UINTN)StackTop));
+
+ if (Index == Bsp) {
+ InitializeExceptionStackSwitchHandlers (&EssData);
+ } else {
+ MpInitLibStartupThisAP (
+ InitializeExceptionStackSwitchHandlers,
+ Index,
+ NULL,
+ 0,
+ (VOID *)&EssData,
+ NULL
+ );
+ }
- PrepareAPStartupCode ();
+ StackTop -= NewStackSize;
+ }
+}
- StartApsStackless ();
+/**
+ Initializes MP exceptions handlers for special features, such as Heap Guard
+ and Stack Guard.
+**/
+VOID
+InitializeMpExceptionHandlers (
+ VOID
+ )
+{
+ //
+ // Enable non-stop mode for #PF triggered by Heap Guard or NULL Pointer
+ // Detection.
+ //
+ if (HEAP_GUARD_NONSTOP_MODE || NULL_DETECTION_NONSTOP_MODE) {
+ RegisterCpuInterruptHandler (EXCEPT_IA32_DEBUG, DebugExceptionHandler);
+ RegisterCpuInterruptHandler (EXCEPT_IA32_PAGE_FAULT, PageFaultExceptionHandler);
}
- DEBUG ((DEBUG_INFO, "Detect CPU count: %d\n", mMpSystemData.NumberOfProcessors));
- if (mMpSystemData.NumberOfProcessors == 1) {
- FreeApStartupCode ();
- if (mCommonStack != NULL) {
- FreePages (mCommonStack, EFI_SIZE_TO_PAGES (gMaxLogicalProcessorNumber * gApStackSize));
- }
+ //
+ // Setup stack switch for Stack Guard feature.
+ //
+ if (PcdGetBool (PcdCpuStackGuard)) {
+ InitializeMpExceptionStackSwitchHandlers ();
}
+}
- mMpSystemData.CpuDatas = ReallocatePool (
- sizeof (CPU_DATA_BLOCK) * gMaxLogicalProcessorNumber,
- sizeof (CPU_DATA_BLOCK) * mMpSystemData.NumberOfProcessors,
- mMpSystemData.CpuDatas);
+/**
+ Initialize Multi-processor support.
+
+**/
+VOID
+InitializeMpSupport (
+ VOID
+ )
+{
+ EFI_STATUS Status;
+ UINTN NumberOfProcessors;
+ UINTN NumberOfEnabledProcessors;
//
- // Release all APs to complete initialization and enter idle loop
+ // Wakeup APs to do initialization
//
- mAPsAlreadyInitFinished = TRUE;
+ Status = MpInitLibInitialize ();
+ ASSERT_EFI_ERROR (Status);
+
+ MpInitLibGetNumberOfProcessors (&NumberOfProcessors, &NumberOfEnabledProcessors);
+ mNumberOfProcessors = NumberOfProcessors;
+ DEBUG ((DEBUG_INFO, "Detect CPU count: %d\n", mNumberOfProcessors));
//
- // Wait for all APs to enter idle loop.
+ // Initialize special exception handlers for each logic processor.
//
- Timeout = 0;
- do {
- if (CheckAllAPsSleeping ()) {
- break;
- }
- gBS->Stall (gPollInterval);
- Timeout += gPollInterval;
- } while (Timeout <= PcdGet32 (PcdCpuApInitTimeOutInMicroSeconds));
- ASSERT (Timeout <= PcdGet32 (PcdCpuApInitTimeOutInMicroSeconds));
+ InitializeMpExceptionHandlers ();
//
// Update CPU healthy information from Guided HOB
@@ -1754,21 +845,5 @@ InitializeMpSupport (
NULL
);
ASSERT_EFI_ERROR (Status);
-
- if (mMpSystemData.NumberOfProcessors > 1 && mMpSystemData.NumberOfProcessors < gMaxLogicalProcessorNumber) {
- if (mApStackStart != NULL) {
- FreePages (mApStackStart, EFI_SIZE_TO_PAGES (
- (gMaxLogicalProcessorNumber - mMpSystemData.NumberOfProcessors) *
- gApStackSize));
- }
- }
-
- Status = gBS->CreateEvent (
- EVT_SIGNAL_EXIT_BOOT_SERVICES,
- TPL_CALLBACK,
- ExitBootServicesCallback,
- NULL,
- &mExitBootServicesEvent
- );
- ASSERT_EFI_ERROR (Status);
}
+