Date   

[Patch v5 32/48] UefiCpuPkg/MpInitLib: Check APs Status and update APs status

Jeff Fan <jeff.fan@...>
 

v3:
1. Use CamelCase for CheckAndUpdateApsStatus().

Cc: Michael Kinney <michael.d.kinney@intel.com>
Cc: Feng Tian <feng.tian@intel.com>
Cc: Giri P Mudusuru <giri.p.mudusuru@intel.com>
Cc: Laszlo Ersek <lersek@redhat.com>
Contributed-under: TianoCore Contribution Agreement 1.0
Signed-off-by: Jeff Fan <jeff.fan@intel.com>
---
UefiCpuPkg/Library/MpInitLib/DxeMpLib.c | 37 ++++
UefiCpuPkg/Library/MpInitLib/MpLib.c | 326 ++++++++++++++++++++++++++++++++
UefiCpuPkg/Library/MpInitLib/MpLib.h | 42 +++-
UefiCpuPkg/Library/MpInitLib/PeiMpLib.c | 11 ++
4 files changed, 415 insertions(+), 1 deletion(-)

diff --git a/UefiCpuPkg/Library/MpInitLib/DxeMpLib.c b/UefiCpuPkg/Library/MpInitLib/DxeMpLib.c
index 988920f..bd13240 100644
--- a/UefiCpuPkg/Library/MpInitLib/DxeMpLib.c
+++ b/UefiCpuPkg/Library/MpInitLib/DxeMpLib.c
@@ -120,6 +120,43 @@ CheckAndUpdateApsStatus (
VOID
)
{
+ UINTN ProcessorNumber;
+ EFI_STATUS Status;
+ CPU_MP_DATA *CpuMpData;
+
+ CpuMpData = GetCpuMpData ();
+
+ //
+ // First, check whether pending StartupAllAPs() exists.
+ //
+ if (CpuMpData->WaitEvent != NULL) {
+
+ Status = CheckAllAPs ();
+ //
+ // If all APs finish for StartupAllAPs(), signal the WaitEvent for it.
+ //
+ if (Status != EFI_NOT_READY) {
+ Status = gBS->SignalEvent (CpuMpData->WaitEvent);
+ CpuMpData->WaitEvent = NULL;
+ }
+ }
+
+ //
+ // Second, check whether pending StartupThisAPs() callings exist.
+ //
+ for (ProcessorNumber = 0; ProcessorNumber < CpuMpData->CpuCount; ProcessorNumber++) {
+
+ if (CpuMpData->CpuData[ProcessorNumber].WaitEvent == NULL) {
+ continue;
+ }
+
+ Status = CheckThisAP (ProcessorNumber);
+
+ if (Status != EFI_NOT_READY) {
+ gBS->SignalEvent (CpuMpData->CpuData[ProcessorNumber].WaitEvent);
+ CpuMpData->CpuData[ProcessorNumber].WaitEvent = NULL;
+ }
+ }
}

/**
diff --git a/UefiCpuPkg/Library/MpInitLib/MpLib.c b/UefiCpuPkg/Library/MpInitLib/MpLib.c
index 3a266e9..2691af2 100644
--- a/UefiCpuPkg/Library/MpInitLib/MpLib.c
+++ b/UefiCpuPkg/Library/MpInitLib/MpLib.c
@@ -902,6 +902,332 @@ WakeUpAP (
}

/**
+ Calculate timeout value and return the current performance counter value.
+
+ Calculate the number of performance counter ticks required for a timeout.
+ If TimeoutInMicroseconds is 0, return value is also 0, which is recognized
+ as infinity.
+
+ @param[in] TimeoutInMicroseconds Timeout value in microseconds.
+ @param[out] CurrentTime Returns the current value of the performance counter.
+
+ @return Expected time stamp counter for timeout.
+ If TimeoutInMicroseconds is 0, return value is also 0, which is recognized
+ as infinity.
+
+**/
+UINT64
+CalculateTimeout (
+ IN UINTN TimeoutInMicroseconds,
+ OUT UINT64 *CurrentTime
+ )
+{
+ //
+ // Read the current value of the performance counter
+ //
+ *CurrentTime = GetPerformanceCounter ();
+
+ //
+ // If TimeoutInMicroseconds is 0, return value is also 0, which is recognized
+ // as infinity.
+ //
+ if (TimeoutInMicroseconds == 0) {
+ return 0;
+ }
+
+ //
+ // GetPerformanceCounterProperties () returns the timestamp counter's frequency
+ // in Hz. So multiply the return value with TimeoutInMicroseconds and then divide
+ // it by 1,000,000, to get the number of ticks for the timeout value.
+ //
+ return DivU64x32 (
+ MultU64x64 (
+ GetPerformanceCounterProperties (NULL, NULL),
+ TimeoutInMicroseconds
+ ),
+ 1000000
+ );
+}
+
+/**
+ Checks whether timeout expires.
+
+ Check whether the number of elapsed performance counter ticks required for
+ a timeout condition has been reached.
+ If Timeout is zero, which means infinity, return value is always FALSE.
+
+ @param[in, out] PreviousTime On input, the value of the performance counter
+ when it was last read.
+ On output, the current value of the performance
+ counter
+ @param[in] TotalTime The total amount of elapsed time in performance
+ counter ticks.
+ @param[in] Timeout The number of performance counter ticks required
+ to reach a timeout condition.
+
+ @retval TRUE A timeout condition has been reached.
+ @retval FALSE A timeout condition has not been reached.
+
+**/
+BOOLEAN
+CheckTimeout (
+ IN OUT UINT64 *PreviousTime,
+ IN UINT64 *TotalTime,
+ IN UINT64 Timeout
+ )
+{
+ UINT64 Start;
+ UINT64 End;
+ UINT64 CurrentTime;
+ INT64 Delta;
+ INT64 Cycle;
+
+ if (Timeout == 0) {
+ return FALSE;
+ }
+ GetPerformanceCounterProperties (&Start, &End);
+ Cycle = End - Start;
+ if (Cycle < 0) {
+ Cycle = -Cycle;
+ }
+ Cycle++;
+ CurrentTime = GetPerformanceCounter();
+ Delta = (INT64) (CurrentTime - *PreviousTime);
+ if (Start > End) {
+ Delta = -Delta;
+ }
+ if (Delta < 0) {
+ Delta += Cycle;
+ }
+ *TotalTime += Delta;
+ *PreviousTime = CurrentTime;
+ if (*TotalTime > Timeout) {
+ return TRUE;
+ }
+ return FALSE;
+}
+
+/**
+ Reset an AP to Idle state.
+
+ Any task being executed by the AP will be aborted and the AP
+ will be waiting for a new task in Wait-For-SIPI state.
+
+ @param[in] ProcessorNumber The handle number of processor.
+**/
+VOID
+ResetProcessorToIdleState (
+ IN UINTN ProcessorNumber
+ )
+{
+ CPU_MP_DATA *CpuMpData;
+
+ CpuMpData = GetCpuMpData ();
+
+ WakeUpAP (CpuMpData, FALSE, ProcessorNumber, NULL, NULL);
+
+ SetApState (&CpuMpData->CpuData[ProcessorNumber], CpuStateIdle);
+}
+
+/**
+ Searches for the next waiting AP.
+
+ Search for the next AP that is put in waiting state by single-threaded StartupAllAPs().
+
+ @param[out] NextProcessorNumber Pointer to the processor number of the next waiting AP.
+
+ @retval EFI_SUCCESS The next waiting AP has been found.
+ @retval EFI_NOT_FOUND No waiting AP exists.
+
+**/
+EFI_STATUS
+GetNextWaitingProcessorNumber (
+ OUT UINTN *NextProcessorNumber
+ )
+{
+ UINTN ProcessorNumber;
+ CPU_MP_DATA *CpuMpData;
+
+ CpuMpData = GetCpuMpData ();
+
+ for (ProcessorNumber = 0; ProcessorNumber < CpuMpData->CpuCount; ProcessorNumber++) {
+ if (CpuMpData->CpuData[ProcessorNumber].Waiting) {
+ *NextProcessorNumber = ProcessorNumber;
+ return EFI_SUCCESS;
+ }
+ }
+
+ return EFI_NOT_FOUND;
+}
+
+/** Checks status of specified AP.
+
+ This function checks whether the specified AP has finished the task assigned
+ by StartupThisAP(), and whether timeout expires.
+
+ @param[in] ProcessorNumber The handle number of processor.
+
+ @retval EFI_SUCCESS Specified AP has finished task assigned by StartupThisAPs().
+ @retval EFI_TIMEOUT The timeout expires.
+ @retval EFI_NOT_READY Specified AP has not finished task and timeout has not expired.
+**/
+EFI_STATUS
+CheckThisAP (
+ IN UINTN ProcessorNumber
+ )
+{
+ CPU_MP_DATA *CpuMpData;
+ CPU_AP_DATA *CpuData;
+
+ CpuMpData = GetCpuMpData ();
+ CpuData = &CpuMpData->CpuData[ProcessorNumber];
+
+ //
+ // Check the CPU state of AP. If it is CpuStateFinished, then the AP has finished its task.
+ // Only BSP and corresponding AP access this unit of CPU Data. This means the AP will not modify the
+ // value of state after setting the it to CpuStateFinished, so BSP can safely make use of its value.
+ //
+ //
+ // If the AP finishes for StartupThisAP(), return EFI_SUCCESS.
+ //
+ if (GetApState(CpuData) == CpuStateFinished) {
+ if (CpuData->Finished != NULL) {
+ *(CpuData->Finished) = TRUE;
+ }
+ SetApState (CpuData, CpuStateIdle);
+ return EFI_SUCCESS;
+ } else {
+ //
+ // If timeout expires for StartupThisAP(), report timeout.
+ //
+ if (CheckTimeout (&CpuData->CurrentTime, &CpuData->TotalTime, CpuData->ExpectedTime)) {
+ if (CpuData->Finished != NULL) {
+ *(CpuData->Finished) = FALSE;
+ }
+ //
+ // Reset failed AP to idle state
+ //
+ ResetProcessorToIdleState (ProcessorNumber);
+
+ return EFI_TIMEOUT;
+ }
+ }
+ return EFI_NOT_READY;
+}
+
+/**
+ Checks status of all APs.
+
+ This function checks whether all APs have finished task assigned by StartupAllAPs(),
+ and whether timeout expires.
+
+ @retval EFI_SUCCESS All APs have finished task assigned by StartupAllAPs().
+ @retval EFI_TIMEOUT The timeout expires.
+ @retval EFI_NOT_READY APs have not finished task and timeout has not expired.
+**/
+EFI_STATUS
+CheckAllAPs (
+ VOID
+ )
+{
+ UINTN ProcessorNumber;
+ UINTN NextProcessorNumber;
+ UINTN ListIndex;
+ EFI_STATUS Status;
+ CPU_MP_DATA *CpuMpData;
+ CPU_AP_DATA *CpuData;
+
+ CpuMpData = GetCpuMpData ();
+
+ NextProcessorNumber = 0;
+
+ //
+ // Go through all APs that are responsible for the StartupAllAPs().
+ //
+ for (ProcessorNumber = 0; ProcessorNumber < CpuMpData->CpuCount; ProcessorNumber++) {
+ if (!CpuMpData->CpuData[ProcessorNumber].Waiting) {
+ continue;
+ }
+
+ CpuData = &CpuMpData->CpuData[ProcessorNumber];
+ //
+ // Check the CPU state of AP. If it is CpuStateFinished, then the AP has finished its task.
+ // Only BSP and corresponding AP access this unit of CPU Data. This means the AP will not modify the
+ // value of state after setting the it to CpuStateFinished, so BSP can safely make use of its value.
+ //
+ if (GetApState(CpuData) == CpuStateFinished) {
+ CpuMpData->RunningCount ++;
+ CpuMpData->CpuData[ProcessorNumber].Waiting = FALSE;
+ SetApState(CpuData, CpuStateIdle);
+
+ //
+ // If in Single Thread mode, then search for the next waiting AP for execution.
+ //
+ if (CpuMpData->SingleThread) {
+ Status = GetNextWaitingProcessorNumber (&NextProcessorNumber);
+
+ if (!EFI_ERROR (Status)) {
+ WakeUpAP (
+ CpuMpData,
+ FALSE,
+ (UINT32) NextProcessorNumber,
+ CpuMpData->Procedure,
+ CpuMpData->ProcArguments
+ );
+ }
+ }
+ }
+ }
+
+ //
+ // If all APs finish, return EFI_SUCCESS.
+ //
+ if (CpuMpData->RunningCount == CpuMpData->StartCount) {
+ return EFI_SUCCESS;
+ }
+
+ //
+ // If timeout expires, report timeout.
+ //
+ if (CheckTimeout (
+ &CpuMpData->CurrentTime,
+ &CpuMpData->TotalTime,
+ CpuMpData->ExpectedTime)
+ ) {
+ //
+ // If FailedCpuList is not NULL, record all failed APs in it.
+ //
+ if (CpuMpData->FailedCpuList != NULL) {
+ *CpuMpData->FailedCpuList =
+ AllocatePool ((CpuMpData->StartCount - CpuMpData->FinishedCount + 1) * sizeof (UINTN));
+ ASSERT (*CpuMpData->FailedCpuList != NULL);
+ }
+ ListIndex = 0;
+
+ for (ProcessorNumber = 0; ProcessorNumber < CpuMpData->CpuCount; ProcessorNumber++) {
+ //
+ // Check whether this processor is responsible for StartupAllAPs().
+ //
+ if (CpuMpData->CpuData[ProcessorNumber].Waiting) {
+ //
+ // Reset failed APs to idle state
+ //
+ ResetProcessorToIdleState (ProcessorNumber);
+ CpuMpData->CpuData[ProcessorNumber].Waiting = FALSE;
+ if (CpuMpData->FailedCpuList != NULL) {
+ (*CpuMpData->FailedCpuList)[ListIndex++] = ProcessorNumber;
+ }
+ }
+ }
+ if (CpuMpData->FailedCpuList != NULL) {
+ (*CpuMpData->FailedCpuList)[ListIndex] = END_OF_CPU_LIST;
+ }
+ return EFI_TIMEOUT;
+ }
+ return EFI_NOT_READY;
+}
+
+/**
MP Initialize Library initialization.

This service will allocate AP reset vector and wakeup all APs to do APs
diff --git a/UefiCpuPkg/Library/MpInitLib/MpLib.h b/UefiCpuPkg/Library/MpInitLib/MpLib.h
index f8b172f..eba6713 100644
--- a/UefiCpuPkg/Library/MpInitLib/MpLib.h
+++ b/UefiCpuPkg/Library/MpInitLib/MpLib.h
@@ -394,7 +394,47 @@ CPU_MP_DATA *
GetCpuMpDataFromGuidedHob (
VOID
);
-
+
+/** Checks status of specified AP.
+
+ This function checks whether the specified AP has finished the task assigned
+ by StartupThisAP(), and whether timeout expires.
+
+ @param[in] ProcessorNumber The handle number of processor.
+
+ @retval EFI_SUCCESS Specified AP has finished task assigned by StartupThisAPs().
+ @retval EFI_TIMEOUT The timeout expires.
+ @retval EFI_NOT_READY Specified AP has not finished task and timeout has not expired.
+**/
+EFI_STATUS
+CheckThisAP (
+ IN UINTN ProcessorNumber
+ );
+
+/**
+ Checks status of all APs.
+
+ This function checks whether all APs have finished task assigned by StartupAllAPs(),
+ and whether timeout expires.
+
+ @retval EFI_SUCCESS All APs have finished task assigned by StartupAllAPs().
+ @retval EFI_TIMEOUT The timeout expires.
+ @retval EFI_NOT_READY APs have not finished task and timeout has not expired.
+**/
+EFI_STATUS
+CheckAllAPs (
+ VOID
+ );
+
+/**
+ Checks APs status and updates APs status if needed.
+
+**/
+VOID
+CheckAndUpdateApsStatus (
+ VOID
+ );
+
/**
Detect whether specified processor can find matching microcode patch and load it.

diff --git a/UefiCpuPkg/Library/MpInitLib/PeiMpLib.c b/UefiCpuPkg/Library/MpInitLib/PeiMpLib.c
index fe585bd..6445159 100644
--- a/UefiCpuPkg/Library/MpInitLib/PeiMpLib.c
+++ b/UefiCpuPkg/Library/MpInitLib/PeiMpLib.c
@@ -337,6 +337,17 @@ FreeResetVector (
}

/**
+ Checks APs status and updates APs status if needed.
+
+**/
+VOID
+CheckAndUpdateApsStatus (
+ VOID
+ )
+{
+}
+
+/**
Initialize global data for MP support.

@param[in] CpuMpData The pointer to CPU MP Data structure.
--
2.7.4.windows.1


[Patch v5 31/48] UefiCpuPkg/MpInitLib: Implementation of MpInitLibEnableDisableAP()

Jeff Fan <jeff.fan@...>
 

v4:
1. Simply the internal function MpInitLibEnableDisableAP()'s function
header due to it is duplicated with MpInitLibEnableDisableAP().
v3:
1. Use CamelCase for mCheckAllAPsEvent, mStopCheckAllApsStatus.

Cc: Michael Kinney <michael.d.kinney@intel.com>
Cc: Feng Tian <feng.tian@intel.com>
Cc: Giri P Mudusuru <giri.p.mudusuru@intel.com>
Cc: Laszlo Ersek <lersek@redhat.com>
Contributed-under: TianoCore Contribution Agreement 1.0
Signed-off-by: Jeff Fan <jeff.fan@intel.com>
---
UefiCpuPkg/Library/MpInitLib/DxeMpLib.c | 20 +++++++++++-
UefiCpuPkg/Library/MpInitLib/MpLib.c | 56 +++++++++++++++++++++++++++++++++
UefiCpuPkg/Library/MpInitLib/MpLib.h | 21 +++++++++++++
UefiCpuPkg/Library/MpInitLib/PeiMpLib.c | 2 +-
4 files changed, 97 insertions(+), 2 deletions(-)

diff --git a/UefiCpuPkg/Library/MpInitLib/DxeMpLib.c b/UefiCpuPkg/Library/MpInitLib/DxeMpLib.c
index 785653b..988920f 100644
--- a/UefiCpuPkg/Library/MpInitLib/DxeMpLib.c
+++ b/UefiCpuPkg/Library/MpInitLib/DxeMpLib.c
@@ -454,5 +454,23 @@ MpInitLibEnableDisableAP (
IN UINT32 *HealthFlag OPTIONAL
)
{
- return EFI_UNSUPPORTED;
+ EFI_STATUS Status;
+ BOOLEAN TempStopCheckState;
+
+ TempStopCheckState = FALSE;
+ //
+ // temporarily stop checkAllAPsStatus for initialize parameters.
+ //
+ if (!mStopCheckAllApsStatus) {
+ mStopCheckAllApsStatus = TRUE;
+ TempStopCheckState = TRUE;
+ }
+
+ Status = EnableDisableApWorker (ProcessorNumber, EnableAP, HealthFlag);
+
+ if (TempStopCheckState) {
+ mStopCheckAllApsStatus = FALSE;
+ }
+
+ return Status;
}
diff --git a/UefiCpuPkg/Library/MpInitLib/MpLib.c b/UefiCpuPkg/Library/MpInitLib/MpLib.c
index 8ae08f4..3a266e9 100644
--- a/UefiCpuPkg/Library/MpInitLib/MpLib.c
+++ b/UefiCpuPkg/Library/MpInitLib/MpLib.c
@@ -1239,6 +1239,62 @@ SwitchBSPWorker (
}

/**
+ Worker function to let the caller enable or disable an AP from this point onward.
+ This service may only be called from the BSP.
+
+ @param[in] ProcessorNumber The handle number of AP.
+ @param[in] EnableAP Specifies the new state for the processor for
+ enabled, FALSE for disabled.
+ @param[in] HealthFlag If not NULL, a pointer to a value that specifies
+ the new health status of the AP.
+
+ @retval EFI_SUCCESS The specified AP was enabled or disabled successfully.
+ @retval others Failed to Enable/Disable AP.
+
+**/
+EFI_STATUS
+EnableDisableApWorker (
+ IN UINTN ProcessorNumber,
+ IN BOOLEAN EnableAP,
+ IN UINT32 *HealthFlag OPTIONAL
+ )
+{
+ CPU_MP_DATA *CpuMpData;
+ UINTN CallerNumber;
+
+ CpuMpData = GetCpuMpData ();
+
+ //
+ // Check whether caller processor is BSP
+ //
+ MpInitLibWhoAmI (&CallerNumber);
+ if (CallerNumber != CpuMpData->BspNumber) {
+ return EFI_DEVICE_ERROR;
+ }
+
+ if (ProcessorNumber == CpuMpData->BspNumber) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if (ProcessorNumber >= CpuMpData->CpuCount) {
+ return EFI_NOT_FOUND;
+ }
+
+ if (!EnableAP) {
+ SetApState (&CpuMpData->CpuData[ProcessorNumber], CpuStateDisabled);
+ } else {
+ SetApState (&CpuMpData->CpuData[ProcessorNumber], CpuStateIdle);
+ }
+
+ if (HealthFlag != NULL) {
+ CpuMpData->CpuData[ProcessorNumber].CpuHealthy =
+ (BOOLEAN) ((*HealthFlag & PROCESSOR_HEALTH_STATUS_BIT) != 0);
+ }
+
+ return EFI_SUCCESS;
+}
+
+/**
This return the handle number for the calling processor. This service may be
called from the BSP and APs.

diff --git a/UefiCpuPkg/Library/MpInitLib/MpLib.h b/UefiCpuPkg/Library/MpInitLib/MpLib.h
index bfc7fb7..f8b172f 100644
--- a/UefiCpuPkg/Library/MpInitLib/MpLib.h
+++ b/UefiCpuPkg/Library/MpInitLib/MpLib.h
@@ -365,6 +365,27 @@ SwitchBSPWorker (
);

/**
+ Worker function to let the caller enable or disable an AP from this point onward.
+ This service may only be called from the BSP.
+
+ @param[in] ProcessorNumber The handle number of AP.
+ @param[in] EnableAP Specifies the new state for the processor for
+ enabled, FALSE for disabled.
+ @param[in] HealthFlag If not NULL, a pointer to a value that specifies
+ the new health status of the AP.
+
+ @retval EFI_SUCCESS The specified AP was enabled or disabled successfully.
+ @retval others Failed to Enable/Disable AP.
+
+**/
+EFI_STATUS
+EnableDisableApWorker (
+ IN UINTN ProcessorNumber,
+ IN BOOLEAN EnableAP,
+ IN UINT32 *HealthFlag OPTIONAL
+ );
+
+/**
Get pointer to CPU MP Data structure from GUIDed HOB.

@return The pointer to CPU MP Data structure.
diff --git a/UefiCpuPkg/Library/MpInitLib/PeiMpLib.c b/UefiCpuPkg/Library/MpInitLib/PeiMpLib.c
index cdec010..fe585bd 100644
--- a/UefiCpuPkg/Library/MpInitLib/PeiMpLib.c
+++ b/UefiCpuPkg/Library/MpInitLib/PeiMpLib.c
@@ -604,7 +604,7 @@ MpInitLibEnableDisableAP (
IN UINT32 *HealthFlag OPTIONAL
)
{
- return EFI_UNSUPPORTED;
+ return EnableDisableApWorker (ProcessorNumber, EnableAP, HealthFlag);
}


--
2.7.4.windows.1


[Patch v5 30/48] UefiCpuPkg/MpInitLib: Implementation of MpInitLibSwitchBSP()

Jeff Fan <jeff.fan@...>
 

v4:
1. Simply the internal function SwitchBSPWorker()'s comment header
due to it is duplicated with MpInitLibSwitchBSP().

v3:
1. Rename MpInitLibSwitchBsp to MpInitLibSwitchBSP.

Cc: Michael Kinney <michael.d.kinney@intel.com>
Cc: Feng Tian <feng.tian@intel.com>
Cc: Giri P Mudusuru <giri.p.mudusuru@intel.com>
Cc: Laszlo Ersek <lersek@redhat.com>
Contributed-under: TianoCore Contribution Agreement 1.0
Signed-off-by: Jeff Fan <jeff.fan@intel.com>
---
UefiCpuPkg/Library/MpInitLib/DxeMpLib.c | 26 +++++-
UefiCpuPkg/Library/MpInitLib/MpLib.c | 144 ++++++++++++++++++++++++++++++--
UefiCpuPkg/Library/MpInitLib/MpLib.h | 53 ++++++++++++
UefiCpuPkg/Library/MpInitLib/PeiMpLib.c | 2 +-
4 files changed, 218 insertions(+), 7 deletions(-)

diff --git a/UefiCpuPkg/Library/MpInitLib/DxeMpLib.c b/UefiCpuPkg/Library/MpInitLib/DxeMpLib.c
index 762d76d..785653b 100644
--- a/UefiCpuPkg/Library/MpInitLib/DxeMpLib.c
+++ b/UefiCpuPkg/Library/MpInitLib/DxeMpLib.c
@@ -389,7 +389,31 @@ MpInitLibSwitchBSP (
IN BOOLEAN EnableOldBSP
)
{
- return EFI_UNSUPPORTED;
+ EFI_STATUS Status;
+ BOOLEAN OldInterruptState;
+
+ //
+ // 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 corrupted, since interrupt return address will be pushed to stack
+ // by hardware.
+ //
+ OldInterruptState = SaveAndDisableInterrupts ();
+
+ //
+ // Mask LINT0 & LINT1 for the old BSP
+ //
+ DisableLvtInterrupts ();
+
+ Status = SwitchBSPWorker (ProcessorNumber, EnableOldBSP);
+
+ //
+ // Restore interrupt state.
+ //
+ SetInterruptState (OldInterruptState);
+
+ return Status;
}

/**
diff --git a/UefiCpuPkg/Library/MpInitLib/MpLib.c b/UefiCpuPkg/Library/MpInitLib/MpLib.c
index 5fbcb26..8ae08f4 100644
--- a/UefiCpuPkg/Library/MpInitLib/MpLib.c
+++ b/UefiCpuPkg/Library/MpInitLib/MpLib.c
@@ -184,6 +184,26 @@ ExtractProcessorLocation (
}

/**
+ Worker function for SwitchBSP().
+
+ Worker function for SwitchBSP(), assigned to the AP which is intended
+ to become BSP.
+
+ @param[in] Buffer Pointer to CPU MP Data
+**/
+VOID
+EFIAPI
+FutureBSPProc (
+ IN VOID *Buffer
+ )
+{
+ CPU_MP_DATA *DataInHob;
+
+ DataInHob = (CPU_MP_DATA *) Buffer;
+ AsmExchangeRole (&DataInHob->APInfo, &DataInHob->BSPInfo);
+}
+
+/**
Get the Application Processors state.

@param[in] CpuData The pointer to CPU_AP_DATA of specified AP
@@ -646,11 +666,20 @@ ApWakeupFunction (
// Invoke AP function here
//
Procedure (Parameter);
- //
- // Re-get the CPU APICID and Initial APICID
- //
- CpuMpData->CpuData[ProcessorNumber].ApicId = GetApicId ();
- CpuMpData->CpuData[ProcessorNumber].InitialApicId = GetInitialApicId ();
+ if (CpuMpData->SwitchBspFlag) {
+ //
+ // Re-get the processor number due to BSP/AP maybe exchange in AP function
+ //
+ GetProcessorNumber (CpuMpData, &ProcessorNumber);
+ CpuMpData->CpuData[ProcessorNumber].ApFunction = 0;
+ CpuMpData->CpuData[ProcessorNumber].ApFunctionArgument = 0;
+ } else {
+ //
+ // Re-get the CPU APICID and Initial APICID
+ //
+ CpuMpData->CpuData[ProcessorNumber].ApicId = GetApicId ();
+ CpuMpData->CpuData[ProcessorNumber].InitialApicId = GetInitialApicId ();
+ }
}
SetApState (&CpuMpData->CpuData[ProcessorNumber], CpuStateFinished);
}
@@ -941,6 +970,7 @@ MpInitLibInitialize (
CpuMpData->CpuCount = 1;
CpuMpData->BspNumber = 0;
CpuMpData->WaitEvent = NULL;
+ CpuMpData->SwitchBspFlag = FALSE;
CpuMpData->CpuData = (CPU_AP_DATA *) (CpuMpData + 1);
CpuMpData->CpuInfoInHob = (UINT64) (UINTN) (CpuMpData->CpuData + MaxLogicalProcessorNumber);
InitializeSpinLock(&CpuMpData->MpLock);
@@ -1103,6 +1133,110 @@ MpInitLibGetProcessorInfo (
return EFI_SUCCESS;
}

+/**
+ Worker function to switch the requested AP to be the BSP from that point onward.
+
+ @param[in] ProcessorNumber The handle number of AP that is to become the new BSP.
+ @param[in] EnableOldBSP If TRUE, then the old BSP will be listed as an
+ enabled AP. Otherwise, it will be disabled.
+
+ @retval EFI_SUCCESS BSP successfully switched.
+ @retval others Failed to switch BSP.
+
+**/
+EFI_STATUS
+SwitchBSPWorker (
+ IN UINTN ProcessorNumber,
+ IN BOOLEAN EnableOldBSP
+ )
+{
+ CPU_MP_DATA *CpuMpData;
+ UINTN CallerNumber;
+ CPU_STATE State;
+ MSR_IA32_APIC_BASE_REGISTER ApicBaseMsr;
+
+ CpuMpData = GetCpuMpData ();
+
+ //
+ // Check whether caller processor is BSP
+ //
+ MpInitLibWhoAmI (&CallerNumber);
+ if (CallerNumber != CpuMpData->BspNumber) {
+ return EFI_SUCCESS;
+ }
+
+ if (ProcessorNumber >= CpuMpData->CpuCount) {
+ return EFI_NOT_FOUND;
+ }
+
+ //
+ // Check whether specified AP is disabled
+ //
+ State = GetApState (&CpuMpData->CpuData[ProcessorNumber]);
+ if (State == CpuStateDisabled) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ //
+ // Check whether ProcessorNumber specifies the current BSP
+ //
+ if (ProcessorNumber == CpuMpData->BspNumber) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ //
+ // Check whether specified AP is busy
+ //
+ if (State == CpuStateBusy) {
+ return EFI_NOT_READY;
+ }
+
+ CpuMpData->BSPInfo.State = CPU_SWITCH_STATE_IDLE;
+ CpuMpData->APInfo.State = CPU_SWITCH_STATE_IDLE;
+ CpuMpData->SwitchBspFlag = TRUE;
+
+ //
+ // Clear the BSP bit of MSR_IA32_APIC_BASE
+ //
+ ApicBaseMsr.Uint64 = AsmReadMsr64 (MSR_IA32_APIC_BASE);
+ ApicBaseMsr.Bits.BSP = 0;
+ AsmWriteMsr64 (MSR_IA32_APIC_BASE, ApicBaseMsr.Uint64);
+
+ //
+ // Need to wakeUp AP (future BSP).
+ //
+ WakeUpAP (CpuMpData, FALSE, ProcessorNumber, FutureBSPProc, CpuMpData);
+
+ AsmExchangeRole (&CpuMpData->BSPInfo, &CpuMpData->APInfo);
+
+ //
+ // Set the BSP bit of MSR_IA32_APIC_BASE on new BSP
+ //
+ ApicBaseMsr.Uint64 = AsmReadMsr64 (MSR_IA32_APIC_BASE);
+ ApicBaseMsr.Bits.BSP = 1;
+ AsmWriteMsr64 (MSR_IA32_APIC_BASE, ApicBaseMsr.Uint64);
+
+ //
+ // Wait for old BSP finished AP task
+ //
+ while (GetApState (&CpuMpData->CpuData[CallerNumber]) != CpuStateFinished) {
+ CpuPause ();
+ }
+
+ CpuMpData->SwitchBspFlag = FALSE;
+ //
+ // Set old BSP enable state
+ //
+ if (!EnableOldBSP) {
+ SetApState (&CpuMpData->CpuData[CallerNumber], CpuStateDisabled);
+ }
+ //
+ // Save new BSP number
+ //
+ CpuMpData->BspNumber = (UINT32) ProcessorNumber;
+
+ return EFI_SUCCESS;
+}

/**
This return the handle number for the calling processor. This service may be
diff --git a/UefiCpuPkg/Library/MpInitLib/MpLib.h b/UefiCpuPkg/Library/MpInitLib/MpLib.h
index 84e0970..bfc7fb7 100644
--- a/UefiCpuPkg/Library/MpInitLib/MpLib.h
+++ b/UefiCpuPkg/Library/MpInitLib/MpLib.h
@@ -43,6 +43,23 @@
}

//
+// The MP data for switch BSP
+//
+#define CPU_SWITCH_STATE_IDLE 0
+#define CPU_SWITCH_STATE_STORED 1
+#define CPU_SWITCH_STATE_LOADED 2
+
+//
+// CPU exchange information for switch BSP
+//
+typedef struct {
+ UINT8 State; // offset 0
+ UINTN StackPointer; // offset 4 / 8
+ IA32_DESCRIPTOR Gdtr; // offset 8 / 16
+ IA32_DESCRIPTOR Idtr; // offset 14 / 26
+} CPU_EXCHANGE_ROLE_INFO;
+
+//
// AP loop state when APs are in idle state
// It's value is the same with PcdCpuApLoopMode
//
@@ -198,6 +215,9 @@ struct _CPU_MP_DATA {

AP_INIT_STATE InitFlag;
BOOLEAN X2ApicEnable;
+ BOOLEAN SwitchBspFlag;
+ CPU_EXCHANGE_ROLE_INFO BSPInfo;
+ CPU_EXCHANGE_ROLE_INFO APInfo;
MTRR_SETTINGS MtrrTable;
UINT8 ApLoopMode;
UINT8 ApTargetCState;
@@ -243,6 +263,22 @@ AsmGetAddressMap (
);

/**
+ This function is called by both the BSP and the AP which is to become the BSP to
+ Exchange execution context including stack between them. After return from this
+ function, the BSP becomes AP and the AP becomes the BSP.
+
+ @param[in] MyInfo Pointer to buffer holding the exchanging information for the executing processor.
+ @param[in] OthersInfo Pointer to buffer holding the exchanging information for the peer.
+
+**/
+VOID
+EFIAPI
+AsmExchangeRole (
+ IN CPU_EXCHANGE_ROLE_INFO *MyInfo,
+ IN CPU_EXCHANGE_ROLE_INFO *OthersInfo
+ );
+
+/**
Get the pointer to CPU MP Data structure.

@return The pointer to CPU MP Data structure.
@@ -312,6 +348,23 @@ InitMpGlobalData (
);

/**
+ Worker function to switch the requested AP to be the BSP from that point onward.
+
+ @param[in] ProcessorNumber The handle number of AP that is to become the new BSP.
+ @param[in] EnableOldBSP If TRUE, then the old BSP will be listed as an
+ enabled AP. Otherwise, it will be disabled.
+
+ @retval EFI_SUCCESS BSP successfully switched.
+ @retval others Failed to switch BSP.
+
+**/
+EFI_STATUS
+SwitchBSPWorker (
+ IN UINTN ProcessorNumber,
+ IN BOOLEAN EnableOldBSP
+ );
+
+/**
Get pointer to CPU MP Data structure from GUIDed HOB.

@return The pointer to CPU MP Data structure.
diff --git a/UefiCpuPkg/Library/MpInitLib/PeiMpLib.c b/UefiCpuPkg/Library/MpInitLib/PeiMpLib.c
index a7e1cde..cdec010 100644
--- a/UefiCpuPkg/Library/MpInitLib/PeiMpLib.c
+++ b/UefiCpuPkg/Library/MpInitLib/PeiMpLib.c
@@ -563,7 +563,7 @@ MpInitLibSwitchBSP (
IN BOOLEAN EnableOldBSP
)
{
- return EFI_UNSUPPORTED;
+ return SwitchBSPWorker (ProcessorNumber, EnableOldBSP);
}

/**
--
2.7.4.windows.1


[Patch v5 29/48] UefiCpuPkg/MpInitLib: Implementation of MpInitLibWhoAmI()

Jeff Fan <jeff.fan@...>
 

v5:
1. Move checking ProcessNumber before calling GetCpuMpData.

Cc: Michael Kinney <michael.d.kinney@intel.com>
Cc: Feng Tian <feng.tian@intel.com>
Cc: Giri P Mudusuru <giri.p.mudusuru@intel.com>
Cc: Laszlo Ersek <lersek@redhat.com>
Contributed-under: TianoCore Contribution Agreement 1.0
Signed-off-by: Jeff Fan <jeff.fan@intel.com>
---
UefiCpuPkg/Library/MpInitLib/MpLib.c | 10 +++++++++-
1 file changed, 9 insertions(+), 1 deletion(-)

diff --git a/UefiCpuPkg/Library/MpInitLib/MpLib.c b/UefiCpuPkg/Library/MpInitLib/MpLib.c
index d0473fd..5fbcb26 100644
--- a/UefiCpuPkg/Library/MpInitLib/MpLib.c
+++ b/UefiCpuPkg/Library/MpInitLib/MpLib.c
@@ -1126,7 +1126,15 @@ MpInitLibWhoAmI (
OUT UINTN *ProcessorNumber
)
{
- return EFI_UNSUPPORTED;
+ CPU_MP_DATA *CpuMpData;
+
+ if (ProcessorNumber == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ CpuMpData = GetCpuMpData ();
+
+ return GetProcessorNumber (CpuMpData, ProcessorNumber);
}

/**
--
2.7.4.windows.1


[Patch v5 28/48] UefiCpuPkg/MpInitLib: Implementation of MpInitLibGetProcessorInfo()

Jeff Fan <jeff.fan@...>
 

v5:
1. Remove (-1) and use the clean code to calculate the Location->Thread
and Location->Core.

v4:
1. Update HealthData type from UINT32 to EFI_HEALTH_FLAGS

Cc: Michael Kinney <michael.d.kinney@intel.com>
Cc: Feng Tian <feng.tian@intel.com>
Cc: Giri P Mudusuru <giri.p.mudusuru@intel.com>
Cc: Laszlo Ersek <lersek@redhat.com>
Contributed-under: TianoCore Contribution Agreement 1.0
Signed-off-by: Jeff Fan <jeff.fan@intel.com>
---
UefiCpuPkg/Library/MpInitLib/MpLib.c | 174 ++++++++++++++++++++++++++++++++++-
1 file changed, 173 insertions(+), 1 deletion(-)

diff --git a/UefiCpuPkg/Library/MpInitLib/MpLib.c b/UefiCpuPkg/Library/MpInitLib/MpLib.c
index cbaeccc..d0473fd 100644
--- a/UefiCpuPkg/Library/MpInitLib/MpLib.c
+++ b/UefiCpuPkg/Library/MpInitLib/MpLib.c
@@ -58,6 +58,132 @@ IsBspExecuteDisableEnabled (
}

/**
+ Get CPU Package/Core/Thread location information.
+
+ @param[in] InitialApicId CPU APIC ID
+ @param[out] Location Pointer to CPU location information
+**/
+VOID
+ExtractProcessorLocation (
+ IN UINT32 InitialApicId,
+ OUT EFI_CPU_PHYSICAL_LOCATION *Location
+ )
+{
+ BOOLEAN TopologyLeafSupported;
+ UINTN ThreadBits;
+ UINTN CoreBits;
+ CPUID_VERSION_INFO_EBX VersionInfoEbx;
+ CPUID_VERSION_INFO_EDX VersionInfoEdx;
+ CPUID_CACHE_PARAMS_EAX CacheParamsEax;
+ CPUID_EXTENDED_TOPOLOGY_EAX ExtendedTopologyEax;
+ CPUID_EXTENDED_TOPOLOGY_EBX ExtendedTopologyEbx;
+ CPUID_EXTENDED_TOPOLOGY_ECX ExtendedTopologyEcx;
+ UINT32 MaxCpuIdIndex;
+ UINT32 SubIndex;
+ UINTN LevelType;
+ UINT32 MaxLogicProcessorsPerPackage;
+ UINT32 MaxCoresPerPackage;
+
+ //
+ // Check if the processor is capable of supporting more than one logical processor.
+ //
+ AsmCpuid (CPUID_VERSION_INFO, NULL, NULL, NULL, &VersionInfoEdx.Uint32);
+ if (VersionInfoEdx.Bits.HTT == 0) {
+ Location->Thread = 0;
+ Location->Core = 0;
+ Location->Package = 0;
+ return;
+ }
+
+ ThreadBits = 0;
+ CoreBits = 0;
+
+ //
+ // Assume three-level mapping of APIC ID: Package:Core:SMT.
+ //
+
+ TopologyLeafSupported = FALSE;
+ //
+ // Get the max index of basic CPUID
+ //
+ AsmCpuid (CPUID_SIGNATURE, &MaxCpuIdIndex, NULL, NULL, NULL);
+
+ //
+ // If the extended topology enumeration leaf is available, it
+ // is the preferred mechanism for enumerating topology.
+ //
+ if (MaxCpuIdIndex >= CPUID_EXTENDED_TOPOLOGY) {
+ AsmCpuidEx (
+ CPUID_EXTENDED_TOPOLOGY,
+ 0,
+ &ExtendedTopologyEax.Uint32,
+ &ExtendedTopologyEbx.Uint32,
+ &ExtendedTopologyEcx.Uint32,
+ NULL
+ );
+ //
+ // If CPUID.(EAX=0BH, ECX=0H):EBX returns zero and maximum input value for
+ // basic CPUID information is greater than 0BH, then CPUID.0BH leaf is not
+ // supported on that processor.
+ //
+ if (ExtendedTopologyEbx.Uint32 != 0) {
+ TopologyLeafSupported = TRUE;
+
+ //
+ // Sub-leaf index 0 (ECX= 0 as input) provides enumeration parameters to extract
+ // the SMT sub-field of x2APIC ID.
+ //
+ LevelType = ExtendedTopologyEcx.Bits.LevelType;
+ ASSERT (LevelType == CPUID_EXTENDED_TOPOLOGY_LEVEL_TYPE_SMT);
+ ThreadBits = ExtendedTopologyEax.Bits.ApicIdShift;
+
+ //
+ // Software must not assume any "level type" encoding
+ // value to be related to any sub-leaf index, except sub-leaf 0.
+ //
+ SubIndex = 1;
+ do {
+ AsmCpuidEx (
+ CPUID_EXTENDED_TOPOLOGY,
+ SubIndex,
+ &ExtendedTopologyEax.Uint32,
+ NULL,
+ &ExtendedTopologyEcx.Uint32,
+ NULL
+ );
+ LevelType = ExtendedTopologyEcx.Bits.LevelType;
+ if (LevelType == CPUID_EXTENDED_TOPOLOGY_LEVEL_TYPE_CORE) {
+ CoreBits = ExtendedTopologyEax.Bits.ApicIdShift - ThreadBits;
+ break;
+ }
+ SubIndex++;
+ } while (LevelType != CPUID_EXTENDED_TOPOLOGY_LEVEL_TYPE_INVALID);
+ }
+ }
+
+ if (!TopologyLeafSupported) {
+ AsmCpuid (CPUID_VERSION_INFO, NULL, &VersionInfoEbx.Uint32, NULL, NULL);
+ MaxLogicProcessorsPerPackage = VersionInfoEbx.Bits.MaximumAddressableIdsForLogicalProcessors;
+ if (MaxCpuIdIndex >= CPUID_CACHE_PARAMS) {
+ AsmCpuidEx (CPUID_CACHE_PARAMS, 0, &CacheParamsEax.Uint32, NULL, NULL, NULL);
+ MaxCoresPerPackage = CacheParamsEax.Bits.MaximumAddressableIdsForLogicalProcessors + 1;
+ } else {
+ //
+ // Must be a single-core processor.
+ //
+ MaxCoresPerPackage = 1;
+ }
+
+ ThreadBits = (UINTN) (HighBitSet32 (MaxLogicProcessorsPerPackage / MaxCoresPerPackage - 1) + 1);
+ CoreBits = (UINTN) (HighBitSet32 (MaxCoresPerPackage - 1) + 1);
+ }
+
+ Location->Thread = InitialApicId & ((1 << ThreadBits) - 1);
+ Location->Core = (InitialApicId >> ThreadBits) & ((1 << CoreBits) - 1);
+ Location->Package = (InitialApicId >> (ThreadBits + CoreBits));
+}
+
+/**
Get the Application Processors state.

@param[in] CpuData The pointer to CPU_AP_DATA of specified AP
@@ -930,8 +1056,54 @@ MpInitLibGetProcessorInfo (
OUT EFI_HEALTH_FLAGS *HealthData OPTIONAL
)
{
- return EFI_UNSUPPORTED;
+ CPU_MP_DATA *CpuMpData;
+ UINTN CallerNumber;
+
+ CpuMpData = GetCpuMpData ();
+
+ //
+ // Check whether caller processor is BSP
+ //
+ MpInitLibWhoAmI (&CallerNumber);
+ if (CallerNumber != CpuMpData->BspNumber) {
+ return EFI_DEVICE_ERROR;
+ }
+
+ if (ProcessorInfoBuffer == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if (ProcessorNumber >= CpuMpData->CpuCount) {
+ return EFI_NOT_FOUND;
+ }
+
+ ProcessorInfoBuffer->ProcessorId = (UINT64) CpuMpData->CpuData[ProcessorNumber].ApicId;
+ ProcessorInfoBuffer->StatusFlag = 0;
+ if (ProcessorNumber == CpuMpData->BspNumber) {
+ ProcessorInfoBuffer->StatusFlag |= PROCESSOR_AS_BSP_BIT;
+ }
+ if (CpuMpData->CpuData[ProcessorNumber].CpuHealthy) {
+ ProcessorInfoBuffer->StatusFlag |= PROCESSOR_HEALTH_STATUS_BIT;
+ }
+ if (GetApState (&CpuMpData->CpuData[ProcessorNumber]) == CpuStateDisabled) {
+ ProcessorInfoBuffer->StatusFlag &= ~PROCESSOR_ENABLED_BIT;
+ } else {
+ ProcessorInfoBuffer->StatusFlag |= PROCESSOR_ENABLED_BIT;
+ }
+
+ //
+ // Get processor location information
+ //
+ ExtractProcessorLocation (CpuMpData->CpuData[ProcessorNumber].ApicId, &ProcessorInfoBuffer->Location);
+
+ if (HealthData != NULL) {
+ HealthData->Uint32 = CpuMpData->CpuData[ProcessorNumber].Health;
+ }
+
+ return EFI_SUCCESS;
}
+
+
/**
This return the handle number for the calling processor. This service may be
called from the BSP and APs.
--
2.7.4.windows.1


[Patch v5 27/48] UefiCpuPkg/MpInitLib: Implementation of MpInitLibGetNumberOfProcessors()

Jeff Fan <jeff.fan@...>
 

Cc: Michael Kinney <michael.d.kinney@intel.com>
Cc: Feng Tian <feng.tian@intel.com>
Cc: Giri P Mudusuru <giri.p.mudusuru@intel.com>
Cc: Laszlo Ersek <lersek@redhat.com>
Contributed-under: TianoCore Contribution Agreement 1.0
Signed-off-by: Jeff Fan <jeff.fan@intel.com>
---
UefiCpuPkg/Library/MpInitLib/MpLib.c | 39 +++++++++++++++++++++++++++++++++++-
1 file changed, 38 insertions(+), 1 deletion(-)

diff --git a/UefiCpuPkg/Library/MpInitLib/MpLib.c b/UefiCpuPkg/Library/MpInitLib/MpLib.c
index 7ae6559..cbaeccc 100644
--- a/UefiCpuPkg/Library/MpInitLib/MpLib.c
+++ b/UefiCpuPkg/Library/MpInitLib/MpLib.c
@@ -956,6 +956,7 @@ MpInitLibWhoAmI (
{
return EFI_UNSUPPORTED;
}
+
/**
Retrieves the number of logical processor in the platform and the number of
those logical processors that are enabled on this boot. This service may only
@@ -983,9 +984,45 @@ MpInitLibGetNumberOfProcessors (
OUT UINTN *NumberOfEnabledProcessors OPTIONAL
)
{
- return EFI_UNSUPPORTED;
+ CPU_MP_DATA *CpuMpData;
+ UINTN CallerNumber;
+ UINTN ProcessorNumber;
+ UINTN EnabledProcessorNumber;
+ UINTN Index;
+
+ CpuMpData = GetCpuMpData ();
+
+ if ((NumberOfProcessors == NULL) && (NumberOfEnabledProcessors == NULL)) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ //
+ // Check whether caller processor is BSP
+ //
+ MpInitLibWhoAmI (&CallerNumber);
+ if (CallerNumber != CpuMpData->BspNumber) {
+ return EFI_DEVICE_ERROR;
+ }
+
+ ProcessorNumber = CpuMpData->CpuCount;
+ EnabledProcessorNumber = 0;
+ for (Index = 0; Index < ProcessorNumber; Index++) {
+ if (GetApState (&CpuMpData->CpuData[Index]) != CpuStateDisabled) {
+ EnabledProcessorNumber ++;
+ }
+ }
+
+ if (NumberOfProcessors != NULL) {
+ *NumberOfProcessors = ProcessorNumber;
+ }
+ if (NumberOfEnabledProcessors != NULL) {
+ *NumberOfEnabledProcessors = EnabledProcessorNumber;
+ }
+
+ return EFI_SUCCESS;
}

+
/**
Get pointer to CPU MP Data structure from GUIDed HOB.

--
2.7.4.windows.1


[Patch v5 26/48] UefiCpuPkg/MpInitLib: Skip collect processor count if GUIDed HOB exist

Jeff Fan <jeff.fan@...>
 

If GUIDed HOB mCpuInitMpLibHobGuid exists, we could get the processor count and
processor APICID and Initial APICID from CPU_INFO_IN_HOB. We needn't to delay
for broadcast INIT-SIPI-SIPI results and could improve performance.

Cc: Michael Kinney <michael.d.kinney@intel.com>
Cc: Feng Tian <feng.tian@intel.com>
Cc: Giri P Mudusuru <giri.p.mudusuru@intel.com>
Cc: Laszlo Ersek <lersek@redhat.com>
Contributed-under: TianoCore Contribution Agreement 1.0
Signed-off-by: Jeff Fan <jeff.fan@intel.com>
---
UefiCpuPkg/Library/MpInitLib/MpLib.c | 60 +++++++++++++++++++++++++++++++++---
1 file changed, 55 insertions(+), 5 deletions(-)

diff --git a/UefiCpuPkg/Library/MpInitLib/MpLib.c b/UefiCpuPkg/Library/MpInitLib/MpLib.c
index d6eef13..7ae6559 100644
--- a/UefiCpuPkg/Library/MpInitLib/MpLib.c
+++ b/UefiCpuPkg/Library/MpInitLib/MpLib.c
@@ -765,6 +765,8 @@ MpInitLibInitialize (
VOID
)
{
+ CPU_MP_DATA *OldCpuMpData;
+ CPU_INFO_IN_HOB *CpuInfoInHob;
UINT32 MaxLogicalProcessorNumber;
UINT32 ApStackSize;
MP_ASSEMBLY_ADDRESS_MAP AddressMap;
@@ -778,7 +780,13 @@ MpInitLibInitialize (
UINTN Index;
UINTN ApResetVectorSize;
UINTN BackupBufferAddr;
- MaxLogicalProcessorNumber = PcdGet32(PcdCpuMaxLogicalProcessorNumber);
+
+ OldCpuMpData = GetCpuMpDataFromGuidedHob ();
+ if (OldCpuMpData == NULL) {
+ MaxLogicalProcessorNumber = PcdGet32(PcdCpuMaxLogicalProcessorNumber);
+ } else {
+ MaxLogicalProcessorNumber = OldCpuMpData->CpuCount;
+ }

AsmGetAddressMap (&AddressMap);
ApResetVectorSize = AddressMap.RendezvousFunnelSize + sizeof (MP_CPU_EXCHANGE_INFO);
@@ -843,12 +851,53 @@ MpInitLibInitialize (
//
MtrrGetAllMtrrs (&CpuMpData->MtrrTable);

+ if (OldCpuMpData == NULL) {
+ //
+ // Wakeup all APs and calculate the processor count in system
+ //
+ CollectProcessorCount (CpuMpData);
+ } else {
+ //
+ // APs have been wakeup before, just get the CPU Information
+ // from HOB
+ //
+ CpuMpData->CpuCount = OldCpuMpData->CpuCount;
+ CpuMpData->BspNumber = OldCpuMpData->BspNumber;
+ CpuMpData->InitFlag = ApInitReconfig;
+ CpuInfoInHob = (CPU_INFO_IN_HOB *) (UINTN) OldCpuMpData->CpuInfoInHob;
+ for (Index = 0; Index < CpuMpData->CpuCount; Index++) {
+ InitializeSpinLock(&CpuMpData->CpuData[Index].ApLock);
+ CpuMpData->CpuData[Index].ApicId = CpuInfoInHob[Index].ApicId;
+ CpuMpData->CpuData[Index].InitialApicId = CpuInfoInHob[Index].InitialApicId;
+ if (CpuMpData->CpuData[Index].InitialApicId >= 255) {
+ CpuMpData->X2ApicEnable = TRUE;
+ }
+ CpuMpData->CpuData[Index].Health = CpuInfoInHob[Index].Health;
+ CpuMpData->CpuData[Index].CpuHealthy = (CpuMpData->CpuData[Index].Health == 0)? TRUE:FALSE;
+ CpuMpData->CpuData[Index].ApFunction = 0;
+ CopyMem (
+ &CpuMpData->CpuData[Index].VolatileRegisters,
+ &CpuMpData->CpuData[0].VolatileRegisters,
+ sizeof (CPU_VOLATILE_REGISTERS)
+ );
+ }
+ //
+ // Wakeup APs to do some AP initialize sync
+ //
+ WakeUpAP (CpuMpData, TRUE, 0, ApInitializeSync, CpuMpData);
+ //
+ // Wait for all APs finished initialization
+ //
+ while (CpuMpData->FinishedCount < (CpuMpData->CpuCount - 1)) {
+ CpuPause ();
+ }
+ CpuMpData->InitFlag = ApInitDone;
+ for (Index = 0; Index < CpuMpData->CpuCount; Index++) {
+ SetApState (&CpuMpData->CpuData[Index], CpuStateIdle);
+ }
+ }

//
- // Wakeup all APs and calculate the processor count in system
- //
- CollectProcessorCount (CpuMpData);
- //
// Initialize global data for MP support
//
InitMpGlobalData (CpuMpData);
@@ -936,6 +985,7 @@ MpInitLibGetNumberOfProcessors (
{
return EFI_UNSUPPORTED;
}
+
/**
Get pointer to CPU MP Data structure from GUIDed HOB.

--
2.7.4.windows.1


[Patch v5 25/48] UefiCpuPkg/MpInitLib: Sort processor by ascending order of APIC ID

Jeff Fan <jeff.fan@...>
 

Cc: Michael Kinney <michael.d.kinney@intel.com>
Cc: Feng Tian <feng.tian@intel.com>
Cc: Giri P Mudusuru <giri.p.mudusuru@intel.com>
Cc: Laszlo Ersek <lersek@redhat.com>
Contributed-under: TianoCore Contribution Agreement 1.0
Signed-off-by: Jeff Fan <jeff.fan@intel.com>
---
UefiCpuPkg/Library/MpInitLib/MpLib.c | 72 ++++++++++++++++++++++++++++++++++++
1 file changed, 72 insertions(+)

diff --git a/UefiCpuPkg/Library/MpInitLib/MpLib.c b/UefiCpuPkg/Library/MpInitLib/MpLib.c
index d84dfec..d6eef13 100644
--- a/UefiCpuPkg/Library/MpInitLib/MpLib.c
+++ b/UefiCpuPkg/Library/MpInitLib/MpLib.c
@@ -217,6 +217,73 @@ GetApLoopMode (
}

/**
+ Sort the APIC ID of all processors.
+
+ This function sorts the APIC ID of all processors so that processor number is
+ assigned in the ascending order of APIC ID which eases MP debugging.
+
+ @param[in] CpuMpData Pointer to PEI CPU MP Data
+**/
+VOID
+SortApicId (
+ IN CPU_MP_DATA *CpuMpData
+ )
+{
+ UINTN Index1;
+ UINTN Index2;
+ UINTN Index3;
+ UINT32 ApicId;
+ CPU_AP_DATA CpuData;
+ UINT32 ApCount;
+ CPU_INFO_IN_HOB *CpuInfoInHob;
+
+ ApCount = CpuMpData->CpuCount - 1;
+
+ if (ApCount != 0) {
+ for (Index1 = 0; Index1 < ApCount; Index1++) {
+ Index3 = Index1;
+ //
+ // Sort key is the hardware default APIC ID
+ //
+ ApicId = CpuMpData->CpuData[Index1].ApicId;
+ for (Index2 = Index1 + 1; Index2 <= ApCount; Index2++) {
+ if (ApicId > CpuMpData->CpuData[Index2].ApicId) {
+ Index3 = Index2;
+ ApicId = CpuMpData->CpuData[Index2].ApicId;
+ }
+ }
+ if (Index3 != Index1) {
+ CopyMem (&CpuData, &CpuMpData->CpuData[Index3], sizeof (CPU_AP_DATA));
+ CopyMem (
+ &CpuMpData->CpuData[Index3],
+ &CpuMpData->CpuData[Index1],
+ sizeof (CPU_AP_DATA)
+ );
+ CopyMem (&CpuMpData->CpuData[Index1], &CpuData, sizeof (CPU_AP_DATA));
+ }
+ }
+
+ //
+ // Get the processor number for the BSP
+ //
+ ApicId = GetInitialApicId ();
+ for (Index1 = 0; Index1 < CpuMpData->CpuCount; Index1++) {
+ if (CpuMpData->CpuData[Index1].ApicId == ApicId) {
+ CpuMpData->BspNumber = (UINT32) Index1;
+ break;
+ }
+ }
+
+ CpuInfoInHob = (CPU_INFO_IN_HOB *) (UINTN) CpuMpData->CpuInfoInHob;
+ for (Index1 = 0; Index1 < CpuMpData->CpuCount; Index1++) {
+ CpuInfoInHob[Index1].InitialApicId = CpuMpData->CpuData[Index1].InitialApicId;
+ CpuInfoInHob[Index1].ApicId = CpuMpData->CpuData[Index1].ApicId;
+ CpuInfoInHob[Index1].Health = CpuMpData->CpuData[Index1].Health;
+ }
+ }
+}
+
+/**
Enable x2APIC mode on APs.

@param[in, out] Buffer Pointer to private data buffer.
@@ -331,6 +398,11 @@ CollectProcessorCount (
SetApicMode (LOCAL_APIC_MODE_X2APIC);
}
DEBUG ((DEBUG_INFO, "APIC MODE is %d\n", GetApicMode ()));
+ //
+ // Sort BSP/Aps by CPU APIC ID in ascending order
+ //
+ SortApicId (CpuMpData);
+
DEBUG ((DEBUG_INFO, "MpInitLib: Find %d processors in system.\n", CpuMpData->CpuCount));

return CpuMpData->CpuCount;
--
2.7.4.windows.1


[Patch v5 24/48] UefiCpuPkg/MpInitLib: Enable x2APIC mode on BSP/APs

Jeff Fan <jeff.fan@...>
 

If x2APIC flag is set, enable x2APIC mode on all APs and BSP. Before we wakeup
APs to enable x2APIC mode, we should wait all APs have finished initialization.

Cc: Michael Kinney <michael.d.kinney@intel.com>
Cc: Feng Tian <feng.tian@intel.com>
Cc: Giri P Mudusuru <giri.p.mudusuru@intel.com>
Cc: Laszlo Ersek <lersek@redhat.com>
Contributed-under: TianoCore Contribution Agreement 1.0
Signed-off-by: Jeff Fan <jeff.fan@intel.com>
---
UefiCpuPkg/Library/MpInitLib/MpLib.c | 32 ++++++++++++++++++++++++++++++++
1 file changed, 32 insertions(+)

diff --git a/UefiCpuPkg/Library/MpInitLib/MpLib.c b/UefiCpuPkg/Library/MpInitLib/MpLib.c
index 8f7cf43..d84dfec 100644
--- a/UefiCpuPkg/Library/MpInitLib/MpLib.c
+++ b/UefiCpuPkg/Library/MpInitLib/MpLib.c
@@ -217,6 +217,20 @@ GetApLoopMode (
}

/**
+ Enable x2APIC mode on APs.
+
+ @param[in, out] Buffer Pointer to private data buffer.
+**/
+VOID
+EFIAPI
+ApFuncEnableX2Apic (
+ IN OUT VOID *Buffer
+ )
+{
+ SetApicMode (LOCAL_APIC_MODE_X2APIC);
+}
+
+/**
Do sync on APs.

@param[in, out] Buffer Pointer to private data buffer.
@@ -299,6 +313,24 @@ CollectProcessorCount (
CpuPause ();
}

+ if (CpuMpData->X2ApicEnable) {
+ DEBUG ((DEBUG_INFO, "Force x2APIC mode!\n"));
+ //
+ // Wakeup all APs to enable x2APIC mode
+ //
+ WakeUpAP (CpuMpData, TRUE, 0, ApFuncEnableX2Apic, NULL);
+ //
+ // Wait for all known APs finished
+ //
+ while (CpuMpData->FinishedCount < (CpuMpData->CpuCount - 1)) {
+ CpuPause ();
+ }
+ //
+ // Enable x2APIC on BSP
+ //
+ SetApicMode (LOCAL_APIC_MODE_X2APIC);
+ }
+ DEBUG ((DEBUG_INFO, "APIC MODE is %d\n", GetApicMode ()));
DEBUG ((DEBUG_INFO, "MpInitLib: Find %d processors in system.\n", CpuMpData->CpuCount));

return CpuMpData->CpuCount;
--
2.7.4.windows.1


[Patch v5 23/48] UefiCpuPkg/MpInitLib: Send INIT-SIPI-SIPI to get processor count

Jeff Fan <jeff.fan@...>
 

CollectProcessorCount() will send the 1st INIT-SIPI-SIPI to get processor count
in system.

Cc: Michael Kinney <michael.d.kinney@intel.com>
Cc: Feng Tian <feng.tian@intel.com>
Cc: Giri P Mudusuru <giri.p.mudusuru@intel.com>
Cc: Laszlo Ersek <lersek@redhat.com>
Contributed-under: TianoCore Contribution Agreement 1.0
Signed-off-by: Jeff Fan <jeff.fan@intel.com>
---
UefiCpuPkg/Library/MpInitLib/MpLib.c | 40 ++++++++++++++++++++++++++++++++++++
1 file changed, 40 insertions(+)

diff --git a/UefiCpuPkg/Library/MpInitLib/MpLib.c b/UefiCpuPkg/Library/MpInitLib/MpLib.c
index de169e6..8f7cf43 100644
--- a/UefiCpuPkg/Library/MpInitLib/MpLib.c
+++ b/UefiCpuPkg/Library/MpInitLib/MpLib.c
@@ -268,6 +268,42 @@ GetProcessorNumber (
return EFI_NOT_FOUND;
}

+/**
+ This function will get CPU count in the system.
+
+ @param[in] CpuMpData Pointer to PEI CPU MP Data
+
+ @return CPU count detected
+**/
+UINTN
+CollectProcessorCount (
+ IN CPU_MP_DATA *CpuMpData
+ )
+{
+ //
+ // Send 1st broadcast IPI to APs to wakeup APs
+ //
+ CpuMpData->InitFlag = ApInitConfig;
+ CpuMpData->X2ApicEnable = FALSE;
+ WakeUpAP (CpuMpData, TRUE, 0, NULL, NULL);
+ //
+ // Wait for AP task to complete and then exit.
+ //
+ MicroSecondDelay (PcdGet32(PcdCpuApInitTimeOutInMicroSeconds));
+ CpuMpData->InitFlag = ApInitDone;
+ ASSERT (CpuMpData->CpuCount <= PcdGet32 (PcdCpuMaxLogicalProcessorNumber));
+ //
+ // Wait for all APs finished the initialization
+ //
+ while (CpuMpData->FinishedCount < (CpuMpData->CpuCount - 1)) {
+ CpuPause ();
+ }
+
+ DEBUG ((DEBUG_INFO, "MpInitLib: Find %d processors in system.\n", CpuMpData->CpuCount));
+
+ return CpuMpData->CpuCount;
+}
+
/*
Initialize CPU AP Data when AP is wakeup at the first time.

@@ -705,6 +741,10 @@ MpInitLibInitialize (


//
+ // Wakeup all APs and calculate the processor count in system
+ //
+ CollectProcessorCount (CpuMpData);
+ //
// Initialize global data for MP support
//
InitMpGlobalData (CpuMpData);
--
2.7.4.windows.1


[Patch v5 22/48] UefiCpuPkg/MpInitLib: Add WakeUpAP()

Jeff Fan <jeff.fan@...>
 

WakeUpAP() is used to wakeup APs per current ApLoopMode and make sure APs wake
up successfully.

Cc: Michael Kinney <michael.d.kinney@intel.com>
Cc: Feng Tian <feng.tian@intel.com>
Cc: Giri P Mudusuru <giri.p.mudusuru@intel.com>
Cc: Laszlo Ersek <lersek@redhat.com>
Contributed-under: TianoCore Contribution Agreement 1.0
Signed-off-by: Jeff Fan <jeff.fan@intel.com>
---
UefiCpuPkg/Library/MpInitLib/MpLib.c | 121 +++++++++++++++++++++++++++++++++++
UefiCpuPkg/Library/MpInitLib/MpLib.h | 19 ++++++
2 files changed, 140 insertions(+)

diff --git a/UefiCpuPkg/Library/MpInitLib/MpLib.c b/UefiCpuPkg/Library/MpInitLib/MpLib.c
index d081111..de169e6 100644
--- a/UefiCpuPkg/Library/MpInitLib/MpLib.c
+++ b/UefiCpuPkg/Library/MpInitLib/MpLib.c
@@ -448,6 +448,29 @@ ApWakeupFunction (
}

/**
+ Wait for AP wakeup and write AP start-up signal till AP is waken up.
+
+ @param[in] ApStartupSignalBuffer Pointer to AP wakeup signal
+**/
+VOID
+WaitApWakeup (
+ IN volatile UINT32 *ApStartupSignalBuffer
+ )
+{
+ //
+ // If AP is waken up, StartupApSignal should be cleared.
+ // Otherwise, write StartupApSignal again till AP waken up.
+ //
+ while (InterlockedCompareExchange32 (
+ (UINT32 *) ApStartupSignalBuffer,
+ WAKEUP_AP_SIGNAL,
+ WAKEUP_AP_SIGNAL
+ ) != 0) {
+ CpuPause ();
+ }
+}
+
+/**
This function will fill the exchange info structure.

@param[in] CpuMpData Pointer to CPU MP Data
@@ -486,6 +509,104 @@ FillExchangeInfoData (
}

/**
+ This function will be called by BSP to wakeup AP.
+
+ @param[in] CpuMpData Pointer to CPU MP Data
+ @param[in] Broadcast TRUE: Send broadcast IPI to all APs
+ FALSE: Send IPI to AP by ApicId
+ @param[in] ProcessorNumber The handle number of specified processor
+ @param[in] Procedure The function to be invoked by AP
+ @param[in] ProcedureArgument The argument to be passed into AP function
+**/
+VOID
+WakeUpAP (
+ IN CPU_MP_DATA *CpuMpData,
+ IN BOOLEAN Broadcast,
+ IN UINTN ProcessorNumber,
+ IN EFI_AP_PROCEDURE Procedure, OPTIONAL
+ IN VOID *ProcedureArgument OPTIONAL
+ )
+{
+ volatile MP_CPU_EXCHANGE_INFO *ExchangeInfo;
+ UINTN Index;
+ CPU_AP_DATA *CpuData;
+ BOOLEAN ResetVectorRequired;
+
+ CpuMpData->FinishedCount = 0;
+ ResetVectorRequired = FALSE;
+
+ if (CpuMpData->ApLoopMode == ApInHltLoop ||
+ CpuMpData->InitFlag != ApInitDone) {
+ ResetVectorRequired = TRUE;
+ AllocateResetVector (CpuMpData);
+ FillExchangeInfoData (CpuMpData);
+ } else if (CpuMpData->ApLoopMode == ApInMwaitLoop) {
+ //
+ // Get AP target C-state each time when waking up AP,
+ // for it maybe updated by platform again
+ //
+ CpuMpData->ApTargetCState = PcdGet8 (PcdCpuApTargetCstate);
+ }
+
+ ExchangeInfo = CpuMpData->MpCpuExchangeInfo;
+
+ if (Broadcast) {
+ for (Index = 0; Index < CpuMpData->CpuCount; Index++) {
+ if (Index != CpuMpData->BspNumber) {
+ CpuData = &CpuMpData->CpuData[Index];
+ CpuData->ApFunction = (UINTN) Procedure;
+ CpuData->ApFunctionArgument = (UINTN) ProcedureArgument;
+ SetApState (CpuData, CpuStateReady);
+ if (CpuMpData->InitFlag != ApInitConfig) {
+ *(UINT32 *) CpuData->StartupApSignal = WAKEUP_AP_SIGNAL;
+ }
+ }
+ }
+ if (ResetVectorRequired) {
+ //
+ // Wakeup all APs
+ //
+ SendInitSipiSipiAllExcludingSelf ((UINT32) ExchangeInfo->BufferStart);
+ }
+ if (CpuMpData->InitFlag != ApInitConfig) {
+ //
+ // Wait all APs waken up if this is not the 1st broadcast of SIPI
+ //
+ for (Index = 0; Index < CpuMpData->CpuCount; Index++) {
+ CpuData = &CpuMpData->CpuData[Index];
+ if (Index != CpuMpData->BspNumber) {
+ WaitApWakeup (CpuData->StartupApSignal);
+ }
+ }
+ }
+ } else {
+ CpuData = &CpuMpData->CpuData[ProcessorNumber];
+ CpuData->ApFunction = (UINTN) Procedure;
+ CpuData->ApFunctionArgument = (UINTN) ProcedureArgument;
+ SetApState (CpuData, CpuStateReady);
+ //
+ // Wakeup specified AP
+ //
+ ASSERT (CpuMpData->InitFlag != ApInitConfig);
+ *(UINT32 *) CpuData->StartupApSignal = WAKEUP_AP_SIGNAL;
+ if (ResetVectorRequired) {
+ SendInitSipiSipi (
+ CpuData->ApicId,
+ (UINT32) ExchangeInfo->BufferStart
+ );
+ }
+ //
+ // Wait specified AP waken up
+ //
+ WaitApWakeup (CpuData->StartupApSignal);
+ }
+
+ if (ResetVectorRequired) {
+ FreeResetVector (CpuMpData);
+ }
+}
+
+/**
MP Initialize Library initialization.

This service will allocate AP reset vector and wakeup all APs to do APs
diff --git a/UefiCpuPkg/Library/MpInitLib/MpLib.h b/UefiCpuPkg/Library/MpInitLib/MpLib.h
index 72a35ef..84e0970 100644
--- a/UefiCpuPkg/Library/MpInitLib/MpLib.h
+++ b/UefiCpuPkg/Library/MpInitLib/MpLib.h
@@ -283,6 +283,25 @@ FreeResetVector (
);

/**
+ This function will be called by BSP to wakeup AP.
+
+ @param[in] CpuMpData Pointer to CPU MP Data
+ @param[in] Broadcast TRUE: Send broadcast IPI to all APs
+ FALSE: Send IPI to AP by ApicId
+ @param[in] ProcessorNumber The handle number of specified processor
+ @param[in] Procedure The function to be invoked by AP
+ @param[in] ProcedureArgument The argument to be passed into AP function
+**/
+VOID
+WakeUpAP (
+ IN CPU_MP_DATA *CpuMpData,
+ IN BOOLEAN Broadcast,
+ IN UINTN ProcessorNumber,
+ IN EFI_AP_PROCEDURE Procedure, OPTIONAL
+ IN VOID *ProcedureArgument OPTIONAL
+ );
+
+/**
Initialize global data for MP support.

@param[in] CpuMpData The pointer to CPU MP Data structure.
--
2.7.4.windows.1


[Patch v5 21/48] UefiCpuPkg/MpInitLib: Fill MP_CPU_EXCHANGE_INFO fields

Jeff Fan <jeff.fan@...>
 

FillExchangeInfoData() is used to fill MP_CPU_EXCHANGE_INFO date exchanged
between C code and assembly code of AP reset vector.

v5:
1. Reference ApWakeupFunction instead of ApCFunction.

Cc: Michael Kinney <michael.d.kinney@intel.com>
Cc: Feng Tian <feng.tian@intel.com>
Cc: Giri P Mudusuru <giri.p.mudusuru@intel.com>
Cc: Laszlo Ersek <lersek@redhat.com>
Contributed-under: TianoCore Contribution Agreement 1.0
Signed-off-by: Jeff Fan <jeff.fan@intel.com>
---
UefiCpuPkg/Library/MpInitLib/MpLib.c | 79 ++++++++++++++++++++++++++++++++++++
1 file changed, 79 insertions(+)

diff --git a/UefiCpuPkg/Library/MpInitLib/MpLib.c b/UefiCpuPkg/Library/MpInitLib/MpLib.c
index a4a2c44..d081111 100644
--- a/UefiCpuPkg/Library/MpInitLib/MpLib.c
+++ b/UefiCpuPkg/Library/MpInitLib/MpLib.c
@@ -17,6 +17,47 @@
EFI_GUID mCpuInitMpLibHobGuid = CPU_INIT_MP_LIB_HOB_GUID;

/**
+ The function will check if BSP Execute Disable is enabled.
+ DxeIpl may have enabled Execute Disable for BSP,
+ APs need to get the status and sync up the settings.
+
+ @retval TRUE BSP Execute Disable is enabled.
+ @retval FALSE BSP Execute Disable is not enabled.
+**/
+BOOLEAN
+IsBspExecuteDisableEnabled (
+ VOID
+ )
+{
+ UINT32 Eax;
+ CPUID_EXTENDED_CPU_SIG_EDX Edx;
+ MSR_IA32_EFER_REGISTER EferMsr;
+ BOOLEAN Enabled;
+
+ Enabled = FALSE;
+ AsmCpuid (CPUID_EXTENDED_FUNCTION, &Eax, NULL, NULL, NULL);
+ if (Eax >= CPUID_EXTENDED_CPU_SIG) {
+ AsmCpuid (CPUID_EXTENDED_CPU_SIG, NULL, NULL, NULL, &Edx.Uint32);
+ //
+ // CPUID 0x80000001
+ // Bit 20: Execute Disable Bit available.
+ //
+ if (Edx.Bits.NX != 0) {
+ EferMsr.Uint64 = AsmReadMsr64 (MSR_IA32_EFER);
+ //
+ // MSR 0xC0000080
+ // Bit 11: Execute Disable Bit enable.
+ //
+ if (EferMsr.Bits.NXE != 0) {
+ Enabled = TRUE;
+ }
+ }
+ }
+
+ return Enabled;
+}
+
+/**
Get the Application Processors state.

@param[in] CpuData The pointer to CPU_AP_DATA of specified AP
@@ -407,6 +448,44 @@ ApWakeupFunction (
}

/**
+ This function will fill the exchange info structure.
+
+ @param[in] CpuMpData Pointer to CPU MP Data
+
+**/
+VOID
+FillExchangeInfoData (
+ IN CPU_MP_DATA *CpuMpData
+ )
+{
+ volatile MP_CPU_EXCHANGE_INFO *ExchangeInfo;
+
+ ExchangeInfo = CpuMpData->MpCpuExchangeInfo;
+ ExchangeInfo->Lock = 0;
+ ExchangeInfo->StackStart = CpuMpData->Buffer;
+ ExchangeInfo->StackSize = CpuMpData->CpuApStackSize;
+ ExchangeInfo->BufferStart = CpuMpData->WakeupBuffer;
+ ExchangeInfo->ModeOffset = CpuMpData->AddressMap.ModeEntryOffset;
+
+ ExchangeInfo->CodeSegment = AsmReadCs ();
+ ExchangeInfo->DataSegment = AsmReadDs ();
+
+ ExchangeInfo->Cr3 = AsmReadCr3 ();
+
+ ExchangeInfo->CFunction = (UINTN) ApWakeupFunction;
+ ExchangeInfo->NumApsExecuting = 0;
+ ExchangeInfo->CpuMpData = CpuMpData;
+
+ ExchangeInfo->EnableExecuteDisable = IsBspExecuteDisableEnabled ();
+
+ //
+ // Get the BSP's data of GDT and IDT
+ //
+ AsmReadGdtr ((IA32_DESCRIPTOR *) &ExchangeInfo->GdtrProfile);
+ AsmReadIdtr ((IA32_DESCRIPTOR *) &ExchangeInfo->IdtrProfile);
+}
+
+/**
MP Initialize Library initialization.

This service will allocate AP reset vector and wakeup all APs to do APs
--
2.7.4.windows.1


[Patch v5 20/48] UefiCpuPkg/MpInitLib: Add ApWakeupFunction() executed by assembly code

Jeff Fan <jeff.fan@...>
 

ApWakeupFunction() is the first C function executed from AP reset vector. When
APs waken up at the first time, it will sync BSP's MTRR setting and load
microcode on APs and collect APs' BIST information.

When AP tasked finished, it will place APs it one loop specified by ApLoopMode.

v5:
1. Rename ApCFunction to ApWakeupFunction to meet naming convention.

Cc: Michael Kinney <michael.d.kinney@intel.com>
Cc: Feng Tian <feng.tian@intel.com>
Cc: Giri P Mudusuru <giri.p.mudusuru@intel.com>
Cc: Laszlo Ersek <lersek@redhat.com>
Contributed-under: TianoCore Contribution Agreement 1.0
Signed-off-by: Jeff Fan <jeff.fan@intel.com>
---
UefiCpuPkg/Library/MpInitLib/MpLib.c | 198 +++++++++++++++++++++++++++++++++++
UefiCpuPkg/Library/MpInitLib/MpLib.h | 2 +
2 files changed, 200 insertions(+)

diff --git a/UefiCpuPkg/Library/MpInitLib/MpLib.c b/UefiCpuPkg/Library/MpInitLib/MpLib.c
index 8dfbf57..a4a2c44 100644
--- a/UefiCpuPkg/Library/MpInitLib/MpLib.c
+++ b/UefiCpuPkg/Library/MpInitLib/MpLib.c
@@ -174,6 +174,59 @@ GetApLoopMode (

return ApLoopMode;
}
+
+/**
+ Do sync on APs.
+
+ @param[in, out] Buffer Pointer to private data buffer.
+**/
+VOID
+EFIAPI
+ApInitializeSync (
+ IN OUT VOID *Buffer
+ )
+{
+ CPU_MP_DATA *CpuMpData;
+
+ CpuMpData = (CPU_MP_DATA *) Buffer;
+ //
+ // Sync BSP's MTRR table to AP
+ //
+ MtrrSetAllMtrrs (&CpuMpData->MtrrTable);
+ //
+ // Load microcode on AP
+ //
+ MicrocodeDetect (CpuMpData);
+}
+
+/**
+ Find the current Processor number by APIC ID.
+
+ @param[in] CpuMpData Pointer to PEI CPU MP Data
+ @param[in] ProcessorNumber Return the pocessor number found
+
+ @retval EFI_SUCCESS ProcessorNumber is found and returned.
+ @retval EFI_NOT_FOUND ProcessorNumber is not found.
+**/
+EFI_STATUS
+GetProcessorNumber (
+ IN CPU_MP_DATA *CpuMpData,
+ OUT UINTN *ProcessorNumber
+ )
+{
+ UINTN TotalProcessorNumber;
+ UINTN Index;
+
+ TotalProcessorNumber = CpuMpData->CpuCount;
+ for (Index = 0; Index < TotalProcessorNumber; Index ++) {
+ if (CpuMpData->CpuData[Index].ApicId == GetApicId ()) {
+ *ProcessorNumber = Index;
+ return EFI_SUCCESS;
+ }
+ }
+ return EFI_NOT_FOUND;
+}
+
/*
Initialize CPU AP Data when AP is wakeup at the first time.

@@ -209,6 +262,151 @@ InitializeApData (
}

/**
+ This function will be called from AP reset code if BSP uses WakeUpAP.
+
+ @param[in] ExchangeInfo Pointer to the MP exchange info buffer
+ @param[in] NumApsExecuting Number of current executing AP
+**/
+VOID
+EFIAPI
+ApWakeupFunction (
+ IN MP_CPU_EXCHANGE_INFO *ExchangeInfo,
+ IN UINTN NumApsExecuting
+ )
+{
+ CPU_MP_DATA *CpuMpData;
+ UINTN ProcessorNumber;
+ EFI_AP_PROCEDURE Procedure;
+ VOID *Parameter;
+ UINT32 BistData;
+ volatile UINT32 *ApStartupSignalBuffer;
+
+ //
+ // AP finished assembly code and begin to execute C code
+ //
+ CpuMpData = ExchangeInfo->CpuMpData;
+
+ ProgramVirtualWireMode ();
+
+ while (TRUE) {
+ if (CpuMpData->InitFlag == ApInitConfig) {
+ //
+ // Add CPU number
+ //
+ InterlockedIncrement ((UINT32 *) &CpuMpData->CpuCount);
+ ProcessorNumber = NumApsExecuting;
+ //
+ // This is first time AP wakeup, get BIST information from AP stack
+ //
+ BistData = *(UINT32 *) (CpuMpData->Buffer + ProcessorNumber * CpuMpData->CpuApStackSize - sizeof (UINTN));
+ //
+ // Do some AP initialize sync
+ //
+ ApInitializeSync (CpuMpData);
+ //
+ // Sync BSP's Control registers to APs
+ //
+ RestoreVolatileRegisters (&CpuMpData->CpuData[0].VolatileRegisters, FALSE);
+ InitializeApData (CpuMpData, ProcessorNumber, BistData);
+ ApStartupSignalBuffer = CpuMpData->CpuData[ProcessorNumber].StartupApSignal;
+ } else {
+ //
+ // Execute AP function if AP is ready
+ //
+ GetProcessorNumber (CpuMpData, &ProcessorNumber);
+ //
+ // Clear AP start-up signal when AP waken up
+ //
+ ApStartupSignalBuffer = CpuMpData->CpuData[ProcessorNumber].StartupApSignal;
+ InterlockedCompareExchange32 (
+ (UINT32 *) ApStartupSignalBuffer,
+ WAKEUP_AP_SIGNAL,
+ 0
+ );
+ if (CpuMpData->ApLoopMode == ApInHltLoop) {
+ //
+ // Restore AP's volatile registers saved
+ //
+ RestoreVolatileRegisters (&CpuMpData->CpuData[ProcessorNumber].VolatileRegisters, TRUE);
+ }
+
+ if (GetApState (&CpuMpData->CpuData[ProcessorNumber]) == CpuStateReady) {
+ Procedure = (EFI_AP_PROCEDURE)CpuMpData->CpuData[ProcessorNumber].ApFunction;
+ Parameter = (VOID *) CpuMpData->CpuData[ProcessorNumber].ApFunctionArgument;
+ if (Procedure != NULL) {
+ SetApState (&CpuMpData->CpuData[ProcessorNumber], CpuStateBusy);
+ //
+ // Invoke AP function here
+ //
+ Procedure (Parameter);
+ //
+ // Re-get the CPU APICID and Initial APICID
+ //
+ CpuMpData->CpuData[ProcessorNumber].ApicId = GetApicId ();
+ CpuMpData->CpuData[ProcessorNumber].InitialApicId = GetInitialApicId ();
+ }
+ SetApState (&CpuMpData->CpuData[ProcessorNumber], CpuStateFinished);
+ }
+ }
+
+ //
+ // AP finished executing C code
+ //
+ InterlockedIncrement ((UINT32 *) &CpuMpData->FinishedCount);
+
+ //
+ // Place AP is specified loop mode
+ //
+ if (CpuMpData->ApLoopMode == ApInHltLoop) {
+ //
+ // Save AP volatile registers
+ //
+ SaveVolatileRegisters (&CpuMpData->CpuData[ProcessorNumber].VolatileRegisters);
+ //
+ // Place AP in HLT-loop
+ //
+ while (TRUE) {
+ DisableInterrupts ();
+ CpuSleep ();
+ CpuPause ();
+ }
+ }
+ while (TRUE) {
+ DisableInterrupts ();
+ if (CpuMpData->ApLoopMode == ApInMwaitLoop) {
+ //
+ // Place AP in MWAIT-loop
+ //
+ AsmMonitor ((UINTN) ApStartupSignalBuffer, 0, 0);
+ if (*ApStartupSignalBuffer != WAKEUP_AP_SIGNAL) {
+ //
+ // Check AP start-up signal again.
+ // If AP start-up signal is not set, place AP into
+ // the specified C-state
+ //
+ AsmMwait (CpuMpData->ApTargetCState << 4, 0);
+ }
+ } else if (CpuMpData->ApLoopMode == ApInRunLoop) {
+ //
+ // Place AP in Run-loop
+ //
+ CpuPause ();
+ } else {
+ ASSERT (FALSE);
+ }
+
+ //
+ // If AP start-up signal is written, AP is waken up
+ // otherwise place AP in loop again
+ //
+ if (*ApStartupSignalBuffer == WAKEUP_AP_SIGNAL) {
+ break;
+ }
+ }
+ }
+}
+
+/**
MP Initialize Library initialization.

This service will allocate AP reset vector and wakeup all APs to do APs
diff --git a/UefiCpuPkg/Library/MpInitLib/MpLib.h b/UefiCpuPkg/Library/MpInitLib/MpLib.h
index 80ea0b4..72a35ef 100644
--- a/UefiCpuPkg/Library/MpInitLib/MpLib.h
+++ b/UefiCpuPkg/Library/MpInitLib/MpLib.h
@@ -35,6 +35,8 @@
#include <Library/MtrrLib.h>
#include <Library/HobLib.h>

+#define WAKEUP_AP_SIGNAL SIGNATURE_32 ('S', 'T', 'A', 'P')
+
#define CPU_INIT_MP_LIB_HOB_GUID \
{ \
0x58eb6a19, 0x3699, 0x4c68, { 0xa8, 0x36, 0xda, 0xcd, 0x8e, 0xdc, 0xad, 0x4a } \
--
2.7.4.windows.1


[Patch v5 19/48] UefiCpuPkg/MpInitLib: Allocate AP reset vector buffer under 1MB

Jeff Fan <jeff.fan@...>
 

In PeiMpInitLib, searching unallocated memory under in
EFI_HOB_TYPE_RESOURCE_DESCRIPTOR hobs to find the memory under 1MB for AP reset
vector. After End of PEI event triggered, we need to restore original the buffer
contents to avoid crash the OS on S3 boot.
In DxeMpInitLib, allocate the memory under 1MB for AP reset vector.

Add helper functions AllocateResetVector()/FreeResetVector() used by WakeupAp().

v3:
1. Move SetTimer() from Patch #17 to Patch 16.

Cc: Michael Kinney <michael.d.kinney@intel.com>
Cc: Feng Tian <feng.tian@intel.com>
Cc: Giri P Mudusuru <giri.p.mudusuru@intel.com>
Cc: Laszlo Ersek <lersek@redhat.com>
Contributed-under: TianoCore Contribution Agreement 1.0
Signed-off-by: Jeff Fan <jeff.fan@intel.com>
---
UefiCpuPkg/Library/MpInitLib/DxeMpLib.c | 60 ++++++++
UefiCpuPkg/Library/MpInitLib/MpLib.h | 20 +++
UefiCpuPkg/Library/MpInitLib/PeiMpLib.c | 245 ++++++++++++++++++++++++++++++++
3 files changed, 325 insertions(+)

diff --git a/UefiCpuPkg/Library/MpInitLib/DxeMpLib.c b/UefiCpuPkg/Library/MpInitLib/DxeMpLib.c
index 2d8bf25..762d76d 100644
--- a/UefiCpuPkg/Library/MpInitLib/DxeMpLib.c
+++ b/UefiCpuPkg/Library/MpInitLib/DxeMpLib.c
@@ -52,6 +52,65 @@ SaveCpuMpData (
}

/**
+ Allocate reset vector buffer.
+
+ @param[in, out] CpuMpData The pointer to CPU MP Data structure.
+**/
+VOID
+AllocateResetVector (
+ IN OUT CPU_MP_DATA *CpuMpData
+ )
+{
+ EFI_STATUS Status;
+ UINTN ApResetVectorSize;
+ EFI_PHYSICAL_ADDRESS StartAddress;
+
+ ApResetVectorSize = CpuMpData->AddressMap.RendezvousFunnelSize +
+ sizeof (MP_CPU_EXCHANGE_INFO);
+
+ StartAddress = BASE_1MB;
+ Status = gBS->AllocatePages (
+ AllocateMaxAddress,
+ EfiACPIMemoryNVS,
+ EFI_SIZE_TO_PAGES (ApResetVectorSize),
+ &StartAddress
+ );
+ ASSERT_EFI_ERROR (Status);
+
+ CpuMpData->WakeupBuffer = (UINTN) StartAddress;
+ CpuMpData->MpCpuExchangeInfo = (MP_CPU_EXCHANGE_INFO *) (UINTN)
+ (CpuMpData->WakeupBuffer + CpuMpData->AddressMap.RendezvousFunnelSize);
+ //
+ // copy AP reset code in it
+ //
+ CopyMem (
+ (VOID *) CpuMpData->WakeupBuffer,
+ (VOID *) CpuMpData->AddressMap.RendezvousFunnelAddress,
+ CpuMpData->AddressMap.RendezvousFunnelSize
+ );
+}
+
+/**
+ Free AP reset vector buffer.
+
+ @param[in] CpuMpData The pointer to CPU MP Data structure.
+**/
+VOID
+FreeResetVector (
+ IN CPU_MP_DATA *CpuMpData
+ )
+{
+ EFI_STATUS Status;
+ UINTN ApResetVectorSize;
+ ApResetVectorSize = CpuMpData->AddressMap.RendezvousFunnelSize +
+ sizeof (MP_CPU_EXCHANGE_INFO);
+ Status = gBS->FreePages(
+ (EFI_PHYSICAL_ADDRESS)CpuMpData->WakeupBuffer,
+ EFI_SIZE_TO_PAGES (ApResetVectorSize)
+ );
+ ASSERT_EFI_ERROR (Status);
+}
+
/**
Checks APs status and updates APs status if needed.

@@ -88,6 +147,7 @@ CheckApsStatus (
CheckAndUpdateApsStatus ();
}
}
+
/**
Initialize global data for MP support.

diff --git a/UefiCpuPkg/Library/MpInitLib/MpLib.h b/UefiCpuPkg/Library/MpInitLib/MpLib.h
index f560237..80ea0b4 100644
--- a/UefiCpuPkg/Library/MpInitLib/MpLib.h
+++ b/UefiCpuPkg/Library/MpInitLib/MpLib.h
@@ -261,6 +261,26 @@ SaveCpuMpData (
);

/**
+ Allocate reset vector buffer.
+
+ @param[in, out] CpuMpData The pointer to CPU MP Data structure.
+**/
+VOID
+AllocateResetVector (
+ IN OUT CPU_MP_DATA *CpuMpData
+ );
+
+/**
+ Free AP reset vector buffer.
+
+ @param[in] CpuMpData The pointer to CPU MP Data structure.
+**/
+VOID
+FreeResetVector (
+ IN CPU_MP_DATA *CpuMpData
+ );
+
+/**
Initialize global data for MP support.

@param[in] CpuMpData The pointer to CPU MP Data structure.
diff --git a/UefiCpuPkg/Library/MpInitLib/PeiMpLib.c b/UefiCpuPkg/Library/MpInitLib/PeiMpLib.c
index 72791b5..a7e1cde 100644
--- a/UefiCpuPkg/Library/MpInitLib/PeiMpLib.c
+++ b/UefiCpuPkg/Library/MpInitLib/PeiMpLib.c
@@ -64,8 +64,45 @@ SaveCpuMpData (
);
}

+/**
+ Get available system memory below 1MB by specified size.
+
+ @param[in] PeiCpuMpData Pointer to PEI CPU MP Data
+**/
+VOID
+BackupAndPrepareWakeupBuffer(
+ IN CPU_MP_DATA *CpuMpData
+ )
+{
+ CopyMem (
+ (VOID *) CpuMpData->BackupBuffer,
+ (VOID *) CpuMpData->WakeupBuffer,
+ CpuMpData->BackupBufferSize
+ );
+ CopyMem (
+ (VOID *) CpuMpData->WakeupBuffer,
+ (VOID *) CpuMpData->AddressMap.RendezvousFunnelAddress,
+ CpuMpData->AddressMap.RendezvousFunnelSize
+ );
+}

/**
+ Restore wakeup buffer data.
+
+ @param[in] PeiCpuMpData Pointer to PEI CPU MP Data
+**/
+VOID
+RestoreWakeupBuffer(
+ IN CPU_MP_DATA *CpuMpData
+ )
+{
+ CopyMem (
+ (VOID *) CpuMpData->WakeupBuffer,
+ (VOID *) CpuMpData->BackupBuffer,
+ CpuMpData->BackupBufferSize
+ );
+}
+
/**
Notify function on End Of PEI PPI.

@@ -86,11 +123,219 @@ CpuMpEndOfPeiCallback (
IN VOID *Ppi
)
{
+ EFI_STATUS Status;
+ EFI_BOOT_MODE BootMode;
+ CPU_MP_DATA *CpuMpData;
+ EFI_PEI_HOB_POINTERS Hob;
+ EFI_HOB_MEMORY_ALLOCATION *MemoryHob;

DEBUG ((DEBUG_INFO, "PeiMpInitLib: CpuMpEndOfPeiCallback () invoked\n"));

+ Status = PeiServicesGetBootMode (&BootMode);
+ ASSERT_EFI_ERROR (Status);
+
+ CpuMpData = GetCpuMpData ();
+ if (BootMode != BOOT_ON_S3_RESUME) {
+ //
+ // Get the HOB list for processing
+ //
+ Hob.Raw = GetHobList ();
+ //
+ // Collect memory ranges
+ //
+ while (!END_OF_HOB_LIST (Hob)) {
+ if (Hob.Header->HobType == EFI_HOB_TYPE_MEMORY_ALLOCATION) {
+ MemoryHob = Hob.MemoryAllocation;
+ if (MemoryHob->AllocDescriptor.MemoryBaseAddress == CpuMpData->WakeupBuffer) {
+ //
+ // Flag this HOB type to un-used
+ //
+ GET_HOB_TYPE (Hob) = EFI_HOB_TYPE_UNUSED;
+ break;
+ }
+ }
+ Hob.Raw = GET_NEXT_HOB (Hob);
+ }
+ } else {
+ CpuMpData->EndOfPeiFlag = TRUE;
+ RestoreWakeupBuffer (CpuMpData);
+ }
return EFI_SUCCESS;
}
+
+/**
+ Check if AP wakeup buffer is overlapped with existing allocated buffer.
+
+ @param[in] WakeupBufferStart AP wakeup buffer start address.
+ @param[in] WakeupBufferEnd AP wakeup buffer end address.
+
+ @retval TRUE There is overlap.
+ @retval FALSE There is no overlap.
+**/
+BOOLEAN
+CheckOverlapWithAllocatedBuffer (
+ IN UINTN WakeupBufferStart,
+ IN UINTN WakeupBufferEnd
+ )
+{
+ EFI_PEI_HOB_POINTERS Hob;
+ EFI_HOB_MEMORY_ALLOCATION *MemoryHob;
+ BOOLEAN Overlapped;
+ UINTN MemoryStart;
+ UINTN MemoryEnd;
+
+ Overlapped = FALSE;
+ //
+ // Get the HOB list for processing
+ //
+ Hob.Raw = GetHobList ();
+ //
+ // Collect memory ranges
+ //
+ while (!END_OF_HOB_LIST (Hob)) {
+ if (Hob.Header->HobType == EFI_HOB_TYPE_MEMORY_ALLOCATION) {
+ MemoryHob = Hob.MemoryAllocation;
+ MemoryStart = (UINTN) MemoryHob->AllocDescriptor.MemoryBaseAddress;
+ MemoryEnd = (UINTN) (MemoryHob->AllocDescriptor.MemoryBaseAddress +
+ MemoryHob->AllocDescriptor.MemoryLength);
+ if (!((WakeupBufferStart >= MemoryEnd) || (WakeupBufferEnd <= MemoryStart))) {
+ Overlapped = TRUE;
+ break;
+ }
+ }
+ Hob.Raw = GET_NEXT_HOB (Hob);
+ }
+ return Overlapped;
+}
+
+/**
+ Get available system memory below 1MB by specified size.
+
+ @param[in] WakeupBufferSize Wakeup buffer size required
+
+ @retval other Return wakeup buffer address below 1MB.
+ @retval -1 Cannot find free memory below 1MB.
+**/
+UINTN
+GetWakeupBuffer (
+ IN UINTN WakeupBufferSize
+ )
+{
+ EFI_PEI_HOB_POINTERS Hob;
+ UINTN WakeupBufferStart;
+ UINTN WakeupBufferEnd;
+
+ WakeupBufferSize = (WakeupBufferSize + SIZE_4KB - 1) & ~(SIZE_4KB - 1);
+
+ //
+ // Get the HOB list for processing
+ //
+ Hob.Raw = GetHobList ();
+
+ //
+ // Collect memory ranges
+ //
+ while (!END_OF_HOB_LIST (Hob)) {
+ if (Hob.Header->HobType == EFI_HOB_TYPE_RESOURCE_DESCRIPTOR) {
+ if ((Hob.ResourceDescriptor->PhysicalStart < BASE_1MB) &&
+ (Hob.ResourceDescriptor->ResourceType == EFI_RESOURCE_SYSTEM_MEMORY) &&
+ ((Hob.ResourceDescriptor->ResourceAttribute &
+ (EFI_RESOURCE_ATTRIBUTE_READ_PROTECTED |
+ EFI_RESOURCE_ATTRIBUTE_WRITE_PROTECTED |
+ EFI_RESOURCE_ATTRIBUTE_EXECUTION_PROTECTED
+ )) == 0)
+ ) {
+ //
+ // Need memory under 1MB to be collected here
+ //
+ WakeupBufferEnd = (UINTN) (Hob.ResourceDescriptor->PhysicalStart + Hob.ResourceDescriptor->ResourceLength);
+ if (WakeupBufferEnd > BASE_1MB) {
+ //
+ // Wakeup buffer should be under 1MB
+ //
+ WakeupBufferEnd = BASE_1MB;
+ }
+ while (WakeupBufferEnd > WakeupBufferSize) {
+ //
+ // Wakeup buffer should be aligned on 4KB
+ //
+ WakeupBufferStart = (WakeupBufferEnd - WakeupBufferSize) & ~(SIZE_4KB - 1);
+ if (WakeupBufferStart < Hob.ResourceDescriptor->PhysicalStart) {
+ break;
+ }
+ if (CheckOverlapWithAllocatedBuffer (WakeupBufferStart, WakeupBufferEnd)) {
+ //
+ // If this range is overlapped with existing allocated buffer, skip it
+ // and find the next range
+ //
+ WakeupBufferEnd -= WakeupBufferSize;
+ continue;
+ }
+ DEBUG ((DEBUG_INFO, "WakeupBufferStart = %x, WakeupBufferSize = %x\n",
+ WakeupBufferStart, WakeupBufferSize));
+ //
+ // Create a memory allocation HOB.
+ //
+ BuildMemoryAllocationHob (
+ WakeupBufferStart,
+ WakeupBufferSize,
+ EfiBootServicesData
+ );
+ return WakeupBufferStart;
+ }
+ }
+ }
+ //
+ // Find the next HOB
+ //
+ Hob.Raw = GET_NEXT_HOB (Hob);
+ }
+
+ return (UINTN) -1;
+}
+
+/**
+ Allocate reset vector buffer.
+
+ @param[in, out] CpuMpData The pointer to CPU MP Data structure.
+**/
+VOID
+AllocateResetVector (
+ IN OUT CPU_MP_DATA *CpuMpData
+ )
+{
+ UINTN ApResetVectorSize;
+
+ if (CpuMpData->WakeupBuffer == (UINTN) -1) {
+ ApResetVectorSize = CpuMpData->AddressMap.RendezvousFunnelSize +
+ sizeof (MP_CPU_EXCHANGE_INFO);
+
+ CpuMpData->WakeupBuffer = GetWakeupBuffer (ApResetVectorSize);
+ CpuMpData->MpCpuExchangeInfo = (MP_CPU_EXCHANGE_INFO *) (UINTN)
+ (CpuMpData->WakeupBuffer + CpuMpData->AddressMap.RendezvousFunnelSize);
+ BackupAndPrepareWakeupBuffer (CpuMpData);
+ }
+
+ if (CpuMpData->EndOfPeiFlag) {
+ BackupAndPrepareWakeupBuffer (CpuMpData);
+ }
+}
+
+/**
+ Free AP reset vector buffer.
+
+ @param[in] CpuMpData The pointer to CPU MP Data structure.
+**/
+VOID
+FreeResetVector (
+ IN CPU_MP_DATA *CpuMpData
+ )
+{
+ if (CpuMpData->EndOfPeiFlag) {
+ RestoreWakeupBuffer (CpuMpData);
+ }
+}
+
/**
Initialize global data for MP support.

--
2.7.4.windows.1


[Patch v5 18/48] UefiCpuPkg/MpInitLib: Register one period event to check APs status

Jeff Fan <jeff.fan@...>
 

In DxeMpInitLib, register one period event callback function CheckAPsStatus()
used to check AP Status.

v5:
1. Introduce AP_CHECK_INTERVAL for adjust AP check timer interval potential.

v3:
1. Use CamelCase for mCheckAllAPsEvent, mStopCheckAllApsStatus and
CheckAndUpdateApsStatus().
2. Move SetTimer() from Patch #17 to Patch 16.

Cc: Michael Kinney <michael.d.kinney@intel.com>
Cc: Feng Tian <feng.tian@intel.com>
Cc: Giri P Mudusuru <giri.p.mudusuru@intel.com>
Cc: Laszlo Ersek <lersek@redhat.com>
Contributed-under: TianoCore Contribution Agreement 1.0
Signed-off-by: Jeff Fan <jeff.fan@intel.com>
Reviewed-by: Giri P Mudusuru <giri.p.mudusuru@intel.com>
---
UefiCpuPkg/Library/MpInitLib/DxeMpLib.c | 66 +++++++++++++++++++++++++++++++++
1 file changed, 66 insertions(+)

diff --git a/UefiCpuPkg/Library/MpInitLib/DxeMpLib.c b/UefiCpuPkg/Library/MpInitLib/DxeMpLib.c
index e294612..2d8bf25 100644
--- a/UefiCpuPkg/Library/MpInitLib/DxeMpLib.c
+++ b/UefiCpuPkg/Library/MpInitLib/DxeMpLib.c
@@ -13,7 +13,16 @@
**/

#include "MpLib.h"
+
+#include <Library/UefiLib.h>
+#include <Library/UefiBootServicesTableLib.h>
+
+#define AP_CHECK_INTERVAL (EFI_TIMER_PERIOD_MILLISECONDS (100))
+
CPU_MP_DATA *mCpuMpData = NULL;
+EFI_EVENT mCheckAllApsEvent = NULL;
+volatile BOOLEAN mStopCheckAllApsStatus = TRUE;
+

/**
Get the pointer to CPU MP Data structure.
@@ -43,6 +52,43 @@ SaveCpuMpData (
}

/**
+/**
+ Checks APs status and updates APs status if needed.
+
+**/
+VOID
+CheckAndUpdateApsStatus (
+ VOID
+ )
+{
+}
+
+/**
+ Checks APs' status periodically.
+
+ This function is triggerred by timer perodically to check the
+ state of APs for StartupAllAPs() and StartupThisAP() executed
+ in non-blocking mode.
+
+ @param[in] Event Event triggered.
+ @param[in] Context Parameter passed with the event.
+
+**/
+VOID
+EFIAPI
+CheckApsStatus (
+ IN EFI_EVENT Event,
+ IN VOID *Context
+ )
+{
+ //
+ // If CheckApsStatus() is not stopped, otherwise return immediately.
+ //
+ if (!mStopCheckAllApsStatus) {
+ CheckAndUpdateApsStatus ();
+ }
+}
+/**
Initialize global data for MP support.

@param[in] CpuMpData The pointer to CPU MP Data structure.
@@ -52,8 +98,28 @@ InitMpGlobalData (
IN CPU_MP_DATA *CpuMpData
)
{
+ EFI_STATUS Status;
+
SaveCpuMpData (CpuMpData);

+ Status = gBS->CreateEvent (
+ EVT_TIMER | EVT_NOTIFY_SIGNAL,
+ TPL_NOTIFY,
+ CheckApsStatus,
+ NULL,
+ &mCheckAllApsEvent
+ );
+ ASSERT_EFI_ERROR (Status);
+
+ //
+ // Set timer to check all APs status.
+ //
+ Status = gBS->SetTimer (
+ mCheckAllApsEvent,
+ TimerPeriodic,
+ AP_CHECK_INTERVAL
+ );
+ ASSERT_EFI_ERROR (Status);
}

/**
--
2.7.4.windows.1


[Patch v5 17/48] UefiCpuPkg/MpInitLib: Register one End of PEI callback function

Jeff Fan <jeff.fan@...>
 

In PeiMpInitLib, register End of PEI callback function CpuMpEndOfPeiCallback().

v5:
1. Add comment block for mMpInitLibNotifyList.

Cc: Michael Kinney <michael.d.kinney@intel.com>
Cc: Feng Tian <feng.tian@intel.com>
Cc: Giri P Mudusuru <giri.p.mudusuru@intel.com>
Cc: Laszlo Ersek <lersek@redhat.com>
Contributed-under: TianoCore Contribution Agreement 1.0
Signed-off-by: Jeff Fan <jeff.fan@intel.com>
---
UefiCpuPkg/Library/MpInitLib/MpLib.h | 20 +++++++++++++++
UefiCpuPkg/Library/MpInitLib/PeiMpLib.c | 43 +++++++++++++++++++++++++++++++++
2 files changed, 63 insertions(+)

diff --git a/UefiCpuPkg/Library/MpInitLib/MpLib.h b/UefiCpuPkg/Library/MpInitLib/MpLib.h
index d3ccac8..f560237 100644
--- a/UefiCpuPkg/Library/MpInitLib/MpLib.h
+++ b/UefiCpuPkg/Library/MpInitLib/MpLib.h
@@ -290,5 +290,25 @@ MicrocodeDetect (
IN CPU_MP_DATA *CpuMpData
);

+/**
+ Notify function on End Of PEI PPI.
+
+ On S3 boot, this function will restore wakeup buffer data.
+ On normal boot, this function will flag wakeup buffer to be un-used type.
+
+ @param[in] PeiServices The pointer to the PEI Services Table.
+ @param[in] NotifyDescriptor Address of the notification descriptor data structure.
+ @param[in] Ppi Address of the PPI that was installed.
+
+ @retval EFI_SUCCESS When everything is OK.
+**/
+EFI_STATUS
+EFIAPI
+CpuMpEndOfPeiCallback (
+ IN EFI_PEI_SERVICES **PeiServices,
+ IN EFI_PEI_NOTIFY_DESCRIPTOR *NotifyDescriptor,
+ IN VOID *Ppi
+ );
+
#endif

diff --git a/UefiCpuPkg/Library/MpInitLib/PeiMpLib.c b/UefiCpuPkg/Library/MpInitLib/PeiMpLib.c
index 6211e71..72791b5 100644
--- a/UefiCpuPkg/Library/MpInitLib/PeiMpLib.c
+++ b/UefiCpuPkg/Library/MpInitLib/PeiMpLib.c
@@ -13,6 +13,17 @@
**/

#include "MpLib.h"
+#include <Ppi/EndOfPeiPhase.h>
+#include <Library/PeiServicesLib.h>
+
+//
+// Global PEI notify function descriptor on EndofPei event
+//
+GLOBAL_REMOVE_IF_UNREFERENCED EFI_PEI_NOTIFY_DESCRIPTOR mMpInitLibNotifyList = {
+ (EFI_PEI_PPI_DESCRIPTOR_NOTIFY_CALLBACK | EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST),
+ &gEfiEndOfPeiSignalPpiGuid,
+ CpuMpEndOfPeiCallback
+};

/**
Get pointer to CPU MP Data structure.
@@ -55,6 +66,32 @@ SaveCpuMpData (


/**
+/**
+ Notify function on End Of PEI PPI.
+
+ On S3 boot, this function will restore wakeup buffer data.
+ On normal boot, this function will flag wakeup buffer to be un-used type.
+
+ @param[in] PeiServices The pointer to the PEI Services Table.
+ @param[in] NotifyDescriptor Address of the notification descriptor data structure.
+ @param[in] Ppi Address of the PPI that was installed.
+
+ @retval EFI_SUCCESS When everything is OK.
+**/
+EFI_STATUS
+EFIAPI
+CpuMpEndOfPeiCallback (
+ IN EFI_PEI_SERVICES **PeiServices,
+ IN EFI_PEI_NOTIFY_DESCRIPTOR *NotifyDescriptor,
+ IN VOID *Ppi
+ )
+{
+
+ DEBUG ((DEBUG_INFO, "PeiMpInitLib: CpuMpEndOfPeiCallback () invoked\n"));
+
+ return EFI_SUCCESS;
+}
+/**
Initialize global data for MP support.

@param[in] CpuMpData The pointer to CPU MP Data structure.
@@ -64,8 +101,14 @@ InitMpGlobalData (
IN CPU_MP_DATA *CpuMpData
)
{
+ EFI_STATUS Status;

SaveCpuMpData (CpuMpData);
+ //
+ // Register an event for EndOfPei
+ //
+ Status = PeiServicesNotifyPpi (&mMpInitLibNotifyList);
+ ASSERT_EFI_ERROR (Status);
}

/**
--
2.7.4.windows.1


[Patch v5 16/48] UefiCpuPkg/MpInitLib: Save CPU MP Data pointer

Jeff Fan <jeff.fan@...>
 

In PeiMpInitLib, save CPU MP Data pointer into one local Guided HOB.
In DxeMpInitLib, save CPU MP Data pointer into one global variable.

Add helper functions GetCpuMpData()/SaveCpuMpData().

v5:
1. Move CPU_INIT_MP_LIB_HOB_GUID from MpLib.c to MpLib.h to make
all C files visible.

Cc: Michael Kinney <michael.d.kinney@intel.com>
Cc: Feng Tian <feng.tian@intel.com>
Cc: Giri P Mudusuru <giri.p.mudusuru@intel.com>
Cc: Laszlo Ersek <lersek@redhat.com>
Contributed-under: TianoCore Contribution Agreement 1.0
Signed-off-by: Jeff Fan <jeff.fan@intel.com>
---
UefiCpuPkg/Library/MpInitLib/DxeMpLib.c | 42 +++++++++++++++++++++++++
UefiCpuPkg/Library/MpInitLib/MpLib.c | 30 ++++++++++++++++++
UefiCpuPkg/Library/MpInitLib/MpLib.h | 48 +++++++++++++++++++++++++++++
UefiCpuPkg/Library/MpInitLib/PeiMpLib.c | 54 +++++++++++++++++++++++++++++++++
4 files changed, 174 insertions(+)

diff --git a/UefiCpuPkg/Library/MpInitLib/DxeMpLib.c b/UefiCpuPkg/Library/MpInitLib/DxeMpLib.c
index 46a48a4..e294612 100644
--- a/UefiCpuPkg/Library/MpInitLib/DxeMpLib.c
+++ b/UefiCpuPkg/Library/MpInitLib/DxeMpLib.c
@@ -13,6 +13,48 @@
**/

#include "MpLib.h"
+CPU_MP_DATA *mCpuMpData = NULL;
+
+/**
+ Get the pointer to CPU MP Data structure.
+
+ @return The pointer to CPU MP Data structure.
+**/
+CPU_MP_DATA *
+GetCpuMpData (
+ VOID
+ )
+{
+ ASSERT (mCpuMpData != NULL);
+ return mCpuMpData;
+}
+
+/**
+ Save the pointer to CPU MP Data structure.
+
+ @param[in] CpuMpData The pointer to CPU MP Data structure will be saved.
+**/
+VOID
+SaveCpuMpData (
+ IN CPU_MP_DATA *CpuMpData
+ )
+{
+ mCpuMpData = CpuMpData;
+}
+
+/**
+ Initialize global data for MP support.
+
+ @param[in] CpuMpData The pointer to CPU MP Data structure.
+**/
+VOID
+InitMpGlobalData (
+ IN CPU_MP_DATA *CpuMpData
+ )
+{
+ SaveCpuMpData (CpuMpData);
+
+}

/**
This service executes a caller provided function on all enabled APs.
diff --git a/UefiCpuPkg/Library/MpInitLib/MpLib.c b/UefiCpuPkg/Library/MpInitLib/MpLib.c
index 7384f5d..8dfbf57 100644
--- a/UefiCpuPkg/Library/MpInitLib/MpLib.c
+++ b/UefiCpuPkg/Library/MpInitLib/MpLib.c
@@ -14,6 +14,8 @@

#include "MpLib.h"

+EFI_GUID mCpuInitMpLibHobGuid = CPU_INIT_MP_LIB_HOB_GUID;
+
/**
Get the Application Processors state.

@@ -303,6 +305,12 @@ MpInitLibInitialize (
//
MtrrGetAllMtrrs (&CpuMpData->MtrrTable);

+
+ //
+ // Initialize global data for MP support
+ //
+ InitMpGlobalData (CpuMpData);
+
return EFI_SUCCESS;
}

@@ -386,3 +394,25 @@ MpInitLibGetNumberOfProcessors (
{
return EFI_UNSUPPORTED;
}
+/**
+ Get pointer to CPU MP Data structure from GUIDed HOB.
+
+ @return The pointer to CPU MP Data structure.
+**/
+CPU_MP_DATA *
+GetCpuMpDataFromGuidedHob (
+ VOID
+ )
+{
+ EFI_HOB_GUID_TYPE *GuidHob;
+ VOID *DataInHob;
+ CPU_MP_DATA *CpuMpData;
+
+ CpuMpData = NULL;
+ GuidHob = GetFirstGuidHob (&mCpuInitMpLibHobGuid);
+ if (GuidHob != NULL) {
+ DataInHob = GET_GUID_HOB_DATA (GuidHob);
+ CpuMpData = (CPU_MP_DATA *) (*(UINTN *) DataInHob);
+ }
+ return CpuMpData;
+}
diff --git a/UefiCpuPkg/Library/MpInitLib/MpLib.h b/UefiCpuPkg/Library/MpInitLib/MpLib.h
index 625d061..d3ccac8 100644
--- a/UefiCpuPkg/Library/MpInitLib/MpLib.h
+++ b/UefiCpuPkg/Library/MpInitLib/MpLib.h
@@ -35,6 +35,11 @@
#include <Library/MtrrLib.h>
#include <Library/HobLib.h>

+#define CPU_INIT_MP_LIB_HOB_GUID \
+ { \
+ 0x58eb6a19, 0x3699, 0x4c68, { 0xa8, 0x36, 0xda, 0xcd, 0x8e, 0xdc, 0xad, 0x4a } \
+ }
+
//
// AP loop state when APs are in idle state
// It's value is the same with PcdCpuApLoopMode
@@ -198,6 +203,9 @@ struct _CPU_MP_DATA {
CPU_AP_DATA *CpuData;
volatile MP_CPU_EXCHANGE_INFO *MpCpuExchangeInfo;
};
+
+extern EFI_GUID mCpuInitMpLibHobGuid;
+
/**
Assembly code to place AP into safe loop mode.

@@ -233,6 +241,46 @@ AsmGetAddressMap (
);

/**
+ Get the pointer to CPU MP Data structure.
+
+ @return The pointer to CPU MP Data structure.
+**/
+CPU_MP_DATA *
+GetCpuMpData (
+ VOID
+ );
+
+/**
+ Save the pointer to CPU MP Data structure.
+
+ @param[in] CpuMpData The pointer to CPU MP Data structure will be saved.
+**/
+VOID
+SaveCpuMpData (
+ IN CPU_MP_DATA *CpuMpData
+ );
+
+/**
+ Initialize global data for MP support.
+
+ @param[in] CpuMpData The pointer to CPU MP Data structure.
+**/
+VOID
+InitMpGlobalData (
+ IN CPU_MP_DATA *CpuMpData
+ );
+
+/**
+ Get pointer to CPU MP Data structure from GUIDed HOB.
+
+ @return The pointer to CPU MP Data structure.
+**/
+CPU_MP_DATA *
+GetCpuMpDataFromGuidedHob (
+ VOID
+ );
+
+/**
Detect whether specified processor can find matching microcode patch and load it.

@param[in] PeiCpuMpData Pointer to PEI CPU MP Data
diff --git a/UefiCpuPkg/Library/MpInitLib/PeiMpLib.c b/UefiCpuPkg/Library/MpInitLib/PeiMpLib.c
index a7e9fb8..6211e71 100644
--- a/UefiCpuPkg/Library/MpInitLib/PeiMpLib.c
+++ b/UefiCpuPkg/Library/MpInitLib/PeiMpLib.c
@@ -15,6 +15,60 @@
#include "MpLib.h"

/**
+ Get pointer to CPU MP Data structure.
+
+ @return The pointer to CPU MP Data structure.
+**/
+CPU_MP_DATA *
+GetCpuMpData (
+ VOID
+ )
+{
+ CPU_MP_DATA *CpuMpData;
+
+ CpuMpData = GetCpuMpDataFromGuidedHob ();
+ ASSERT (CpuMpData != NULL);
+ return CpuMpData;
+}
+
+/**
+ Save the pointer to CPU MP Data structure.
+
+ @param[in] CpuMpData The pointer to CPU MP Data structure will be saved.
+**/
+VOID
+SaveCpuMpData (
+ IN CPU_MP_DATA *CpuMpData
+ )
+{
+ UINT64 Data64;
+ //
+ // Build location of CPU MP DATA buffer in HOB
+ //
+ Data64 = (UINT64) (UINTN) CpuMpData;
+ BuildGuidDataHob (
+ &mCpuInitMpLibHobGuid,
+ (VOID *) &Data64,
+ sizeof (UINT64)
+ );
+}
+
+
+/**
+ Initialize global data for MP support.
+
+ @param[in] CpuMpData The pointer to CPU MP Data structure.
+**/
+VOID
+InitMpGlobalData (
+ IN CPU_MP_DATA *CpuMpData
+ )
+{
+
+ SaveCpuMpData (CpuMpData);
+}
+
+/**
This service executes a caller provided function on all enabled APs.

@param[in] Procedure A pointer to the function to be run on
--
2.7.4.windows.1


[Patch v5 15/48] UefiCpuPkg/MpInitLib: Add MicrocodeDetect() and load microcode on BSP

Jeff Fan <jeff.fan@...>
 

v4:
1. ProcessorSignature is updated to CPU_MICROCODE_PROCESSOR_SIGNATURE
instead of UINT32.

Cc: Michael Kinney <michael.d.kinney@intel.com>
Cc: Feng Tian <feng.tian@intel.com>
Cc: Giri P Mudusuru <giri.p.mudusuru@intel.com>
Cc: Laszlo Ersek <lersek@redhat.com>
Contributed-under: TianoCore Contribution Agreement 1.0
Signed-off-by: Jeff Fan <jeff.fan@intel.com>
---
UefiCpuPkg/Library/MpInitLib/DxeMpInitLib.inf | 1 +
.../{CpuMpPei => Library/MpInitLib}/Microcode.c | 77 +++++++++++-----------
UefiCpuPkg/Library/MpInitLib/MpLib.c | 5 ++
UefiCpuPkg/Library/MpInitLib/MpLib.h | 10 +++
UefiCpuPkg/Library/MpInitLib/PeiMpInitLib.inf | 1 +
5 files changed, 57 insertions(+), 37 deletions(-)
copy UefiCpuPkg/{CpuMpPei => Library/MpInitLib}/Microcode.c (68%)

diff --git a/UefiCpuPkg/Library/MpInitLib/DxeMpInitLib.inf b/UefiCpuPkg/Library/MpInitLib/DxeMpInitLib.inf
index e9a2725..03a8994 100644
--- a/UefiCpuPkg/Library/MpInitLib/DxeMpInitLib.inf
+++ b/UefiCpuPkg/Library/MpInitLib/DxeMpInitLib.inf
@@ -39,6 +39,7 @@ [Sources.common]
DxeMpLib.c
MpLib.c
MpLib.h
+ Microcode.c

[Packages]
MdePkg/MdePkg.dec
diff --git a/UefiCpuPkg/CpuMpPei/Microcode.c b/UefiCpuPkg/Library/MpInitLib/Microcode.c
similarity index 68%
copy from UefiCpuPkg/CpuMpPei/Microcode.c
copy to UefiCpuPkg/Library/MpInitLib/Microcode.c
index 4fe6f2d..0fd8e8c 100644
--- a/UefiCpuPkg/CpuMpPei/Microcode.c
+++ b/UefiCpuPkg/Library/MpInitLib/Microcode.c
@@ -12,56 +12,55 @@

**/

-#include "CpuMpPei.h"
+#include "MpLib.h"

/**
Get microcode update signature of currently loaded microcode update.

@return Microcode signature.
-
**/
UINT32
GetCurrentMicrocodeSignature (
VOID
)
{
- UINT64 Signature;
+ MSR_IA32_BIOS_SIGN_ID_REGISTER BiosSignIdMsr;

- AsmWriteMsr64 (EFI_MSR_IA32_BIOS_SIGN_ID, 0);
+ AsmWriteMsr64 (MSR_IA32_BIOS_SIGN_ID, 0);
AsmCpuid (CPUID_VERSION_INFO, NULL, NULL, NULL, NULL);
- Signature = AsmReadMsr64 (EFI_MSR_IA32_BIOS_SIGN_ID);
- return (UINT32) RShiftU64 (Signature, 32);
+ BiosSignIdMsr.Uint64 = AsmReadMsr64 (MSR_IA32_BIOS_SIGN_ID);
+ return BiosSignIdMsr.Bits.MicrocodeUpdateSignature;
}

/**
Detect whether specified processor can find matching microcode patch and load it.

- @param PeiCpuMpData Pointer to PEI CPU MP Data
+ @param[in] PeiCpuMpData Pointer to PEI CPU MP Data
**/
VOID
MicrocodeDetect (
- IN PEI_CPU_MP_DATA *PeiCpuMpData
+ IN CPU_MP_DATA *CpuMpData
)
{
UINT64 MicrocodePatchAddress;
UINT64 MicrocodePatchRegionSize;
UINT32 ExtendedTableLength;
UINT32 ExtendedTableCount;
- EFI_CPU_MICROCODE_EXTENDED_TABLE *ExtendedTable;
- EFI_CPU_MICROCODE_EXTENDED_TABLE_HEADER *ExtendedTableHeader;
- EFI_CPU_MICROCODE_HEADER *MicrocodeEntryPoint;
+ CPU_MICROCODE_EXTENDED_TABLE *ExtendedTable;
+ CPU_MICROCODE_EXTENDED_TABLE_HEADER *ExtendedTableHeader;
+ CPU_MICROCODE_HEADER *MicrocodeEntryPoint;
UINTN MicrocodeEnd;
UINTN Index;
UINT8 PlatformId;
- UINT32 RegEax;
+ CPUID_VERSION_INFO_EAX Eax;
UINT32 CurrentRevision;
UINT32 LatestRevision;
UINTN TotalSize;
UINT32 CheckSum32;
BOOLEAN CorrectMicrocode;
- MICROCODE_INFO MicrocodeInfo;
+ VOID *MicrocodeData;
+ MSR_IA32_PLATFORM_ID_REGISTER PlatformIdMsr;

- ZeroMem (&MicrocodeInfo, sizeof (MICROCODE_INFO));
MicrocodePatchAddress = PcdGet64 (PcdCpuMicrocodePatchAddress);
MicrocodePatchRegionSize = PcdGet64 (PcdCpuMicrocodePatchRegionSize);
if (MicrocodePatchRegionSize == 0) {
@@ -82,18 +81,19 @@ MicrocodeDetect (
ExtendedTableLength = 0;
//
// Here data of CPUID leafs have not been collected into context buffer, so
- // GetProcessorCpuid() cannot be used here to retrieve CPUID data.
+ // GetProcessorCpuid() cannot be used here to retrieve sCPUID data.
//
- AsmCpuid (CPUID_VERSION_INFO, &RegEax, NULL, NULL, NULL);
+ AsmCpuid (CPUID_VERSION_INFO, &Eax.Uint32, NULL, NULL, NULL);

//
// The index of platform information resides in bits 50:52 of MSR IA32_PLATFORM_ID
//
- PlatformId = (UINT8) AsmMsrBitFieldRead64 (EFI_MSR_IA32_PLATFORM_ID, 50, 52);
+ PlatformIdMsr.Uint64 = AsmReadMsr64 (MSR_IA32_PLATFORM_ID);
+ PlatformId = (UINT8) PlatformIdMsr.Bits.PlatformId;

LatestRevision = 0;
MicrocodeEnd = (UINTN) (MicrocodePatchAddress + MicrocodePatchRegionSize);
- MicrocodeEntryPoint = (EFI_CPU_MICROCODE_HEADER *) (UINTN) MicrocodePatchAddress;
+ MicrocodeEntryPoint = (CPU_MICROCODE_HEADER *) (UINTN) MicrocodePatchAddress;
do {
//
// Check if the microcode is for the Cpu and the version is newer
@@ -106,44 +106,49 @@ MicrocodeDetect (
// because the padding data should not include 0x00000001 and it should be the repeated
// byte format (like 0xXYXYXYXY....).
//
- if (MicrocodeEntryPoint->ProcessorId == RegEax &&
+ if (MicrocodeEntryPoint->ProcessorSignature.Uint32 == Eax.Uint32 &&
MicrocodeEntryPoint->UpdateRevision > LatestRevision &&
(MicrocodeEntryPoint->ProcessorFlags & (1 << PlatformId))
) {
if (MicrocodeEntryPoint->DataSize == 0) {
- CheckSum32 = CalculateSum32 ((UINT32 *)MicrocodeEntryPoint, 2048);
+ CheckSum32 = CalculateSum32 ((UINT32 *) MicrocodeEntryPoint, 2048);
} else {
- CheckSum32 = CalculateSum32 ((UINT32 *)MicrocodeEntryPoint, MicrocodeEntryPoint->DataSize + sizeof(EFI_CPU_MICROCODE_HEADER));
+ CheckSum32 = CalculateSum32 (
+ (UINT32 *) MicrocodeEntryPoint,
+ MicrocodeEntryPoint->DataSize + sizeof (CPU_MICROCODE_HEADER)
+ );
}
if (CheckSum32 == 0) {
CorrectMicrocode = TRUE;
}
} else if ((MicrocodeEntryPoint->DataSize != 0) &&
(MicrocodeEntryPoint->UpdateRevision > LatestRevision)) {
- ExtendedTableLength = MicrocodeEntryPoint->TotalSize - (MicrocodeEntryPoint->DataSize + sizeof (EFI_CPU_MICROCODE_HEADER));
+ ExtendedTableLength = MicrocodeEntryPoint->TotalSize - (MicrocodeEntryPoint->DataSize +
+ sizeof (CPU_MICROCODE_HEADER));
if (ExtendedTableLength != 0) {
//
// Extended Table exist, check if the CPU in support list
//
- ExtendedTableHeader = (EFI_CPU_MICROCODE_EXTENDED_TABLE_HEADER *)((UINT8 *)(MicrocodeEntryPoint) + MicrocodeEntryPoint->DataSize + sizeof (EFI_CPU_MICROCODE_HEADER));
+ ExtendedTableHeader = (CPU_MICROCODE_EXTENDED_TABLE_HEADER *) ((UINT8 *) (MicrocodeEntryPoint)
+ + MicrocodeEntryPoint->DataSize + sizeof (CPU_MICROCODE_HEADER));
//
// Calculate Extended Checksum
//
if ((ExtendedTableLength % 4) == 0) {
- CheckSum32 = CalculateSum32 ((UINT32 *)ExtendedTableHeader, ExtendedTableLength);
+ CheckSum32 = CalculateSum32 ((UINT32 *) ExtendedTableHeader, ExtendedTableLength);
if (CheckSum32 == 0) {
//
// Checksum correct
//
ExtendedTableCount = ExtendedTableHeader->ExtendedSignatureCount;
- ExtendedTable = (EFI_CPU_MICROCODE_EXTENDED_TABLE *)(ExtendedTableHeader + 1);
+ ExtendedTable = (CPU_MICROCODE_EXTENDED_TABLE *) (ExtendedTableHeader + 1);
for (Index = 0; Index < ExtendedTableCount; Index ++) {
- CheckSum32 = CalculateSum32 ((UINT32 *)ExtendedTable, sizeof(EFI_CPU_MICROCODE_EXTENDED_TABLE));
+ CheckSum32 = CalculateSum32 ((UINT32 *) ExtendedTable, sizeof(CPU_MICROCODE_EXTENDED_TABLE));
if (CheckSum32 == 0) {
//
// Verify Header
//
- if ((ExtendedTable->ProcessorSignature == RegEax) &&
+ if ((ExtendedTable->ProcessorSignature.Uint32 == Eax.Uint32) &&
(ExtendedTable->ProcessorFlag & (1 << PlatformId)) ) {
//
// Find one
@@ -166,7 +171,7 @@ MicrocodeDetect (
// alignment value should be larger than 1-KByte. We could skip SIZE_1KB padding data to
// find the next possible microcode patch header.
//
- MicrocodeEntryPoint = (EFI_CPU_MICROCODE_HEADER *) (((UINTN) MicrocodeEntryPoint) + SIZE_1KB);
+ MicrocodeEntryPoint = (CPU_MICROCODE_HEADER *) (((UINTN) MicrocodeEntryPoint) + SIZE_1KB);
continue;
}
//
@@ -180,12 +185,10 @@ MicrocodeDetect (

if (CorrectMicrocode) {
LatestRevision = MicrocodeEntryPoint->UpdateRevision;
- MicrocodeInfo.MicrocodeData = (VOID *)((UINTN)MicrocodeEntryPoint + sizeof (EFI_CPU_MICROCODE_HEADER));
- MicrocodeInfo.MicrocodeSize = TotalSize;
- MicrocodeInfo.ProcessorId = RegEax;
+ MicrocodeData = (VOID *) ((UINTN) MicrocodeEntryPoint + sizeof (CPU_MICROCODE_HEADER));
}

- MicrocodeEntryPoint = (EFI_CPU_MICROCODE_HEADER *) (((UINTN) MicrocodeEntryPoint) + TotalSize);
+ MicrocodeEntryPoint = (CPU_MICROCODE_HEADER *) (((UINTN) MicrocodeEntryPoint) + TotalSize);
} while (((UINTN) MicrocodeEntryPoint < MicrocodeEnd));

if (LatestRevision > CurrentRevision) {
@@ -196,18 +199,18 @@ MicrocodeDetect (
// revision equal to zero.
//
AsmWriteMsr64 (
- EFI_MSR_IA32_BIOS_UPDT_TRIG,
- (UINT64) (UINTN) MicrocodeInfo.MicrocodeData
- );
+ MSR_IA32_BIOS_UPDT_TRIG,
+ (UINT64) (UINTN) MicrocodeData
+ );
//
// Get and check new microcode signature
//
CurrentRevision = GetCurrentMicrocodeSignature ();
if (CurrentRevision != LatestRevision) {
- AcquireSpinLock(&PeiCpuMpData->MpLock);
+ AcquireSpinLock(&CpuMpData->MpLock);
DEBUG ((EFI_D_ERROR, "Updated microcode signature [0x%08x] does not match \
loaded microcode signature [0x%08x]\n", CurrentRevision, LatestRevision));
- ReleaseSpinLock(&PeiCpuMpData->MpLock);
+ ReleaseSpinLock(&CpuMpData->MpLock);
}
}
}
diff --git a/UefiCpuPkg/Library/MpInitLib/MpLib.c b/UefiCpuPkg/Library/MpInitLib/MpLib.c
index 0832228..7384f5d 100644
--- a/UefiCpuPkg/Library/MpInitLib/MpLib.c
+++ b/UefiCpuPkg/Library/MpInitLib/MpLib.c
@@ -294,6 +294,11 @@ MpInitLibInitialize (
CpuMpData->CpuData[Index].StartupApSignal =
(UINT32 *)(MonitorBuffer + MonitorFilterSize * Index);
}
+ //
+ // Load Microcode on BSP
+ //
+ MicrocodeDetect (CpuMpData);
+ //
// Store BSP's MTRR setting
//
MtrrGetAllMtrrs (&CpuMpData->MtrrTable);
diff --git a/UefiCpuPkg/Library/MpInitLib/MpLib.h b/UefiCpuPkg/Library/MpInitLib/MpLib.h
index ca8bd44..625d061 100644
--- a/UefiCpuPkg/Library/MpInitLib/MpLib.h
+++ b/UefiCpuPkg/Library/MpInitLib/MpLib.h
@@ -232,5 +232,15 @@ AsmGetAddressMap (
OUT MP_ASSEMBLY_ADDRESS_MAP *AddressMap
);

+/**
+ Detect whether specified processor can find matching microcode patch and load it.
+
+ @param[in] PeiCpuMpData Pointer to PEI CPU MP Data
+**/
+VOID
+MicrocodeDetect (
+ IN CPU_MP_DATA *CpuMpData
+ );
+
#endif

diff --git a/UefiCpuPkg/Library/MpInitLib/PeiMpInitLib.inf b/UefiCpuPkg/Library/MpInitLib/PeiMpInitLib.inf
index c195a38..0c6873d 100644
--- a/UefiCpuPkg/Library/MpInitLib/PeiMpInitLib.inf
+++ b/UefiCpuPkg/Library/MpInitLib/PeiMpInitLib.inf
@@ -39,6 +39,7 @@ [Sources.common]
PeiMpLib.c
MpLib.c
MpLib.h
+ Microcode.c

[Packages]
MdePkg/MdePkg.dec
--
2.7.4.windows.1


[Patch v5 14/48] UefiCpuPkg/MpInitLib: Add CPU_VOLATILE_REGISTERS & worker functions

Jeff Fan <jeff.fan@...>
 

Add CPU_VOLATILE_REGISTERS definitions for CRx and DRx required to be restored
after APs received INIT IPI.

Add worker functions SaveVolatileRegisters()/RestoreVolatileRegisters() used to
save/restore CRx and DRx. It also check if Debugging Extensions supported or
not.

v5:
1. Add comment block for structure CPU_VOLATILE_REGISTERS.

Cc: Michael Kinney <michael.d.kinney@intel.com>
Cc: Feng Tian <feng.tian@intel.com>
Cc: Giri P Mudusuru <giri.p.mudusuru@intel.com>
Cc: Laszlo Ersek <lersek@redhat.com>
Contributed-under: TianoCore Contribution Agreement 1.0
Signed-off-by: Jeff Fan <jeff.fan@intel.com>
---
UefiCpuPkg/Library/MpInitLib/MpLib.c | 71 ++++++++++++++++++++++++++++++++++++
UefiCpuPkg/Library/MpInitLib/MpLib.h | 16 ++++++++
2 files changed, 87 insertions(+)

diff --git a/UefiCpuPkg/Library/MpInitLib/MpLib.c b/UefiCpuPkg/Library/MpInitLib/MpLib.c
index 70e5eb1..0832228 100644
--- a/UefiCpuPkg/Library/MpInitLib/MpLib.c
+++ b/UefiCpuPkg/Library/MpInitLib/MpLib.c
@@ -47,6 +47,73 @@ SetApState (
}

/**
+ Save the volatile registers required to be restored following INIT IPI.
+
+ @param[out] VolatileRegisters Returns buffer saved the volatile resisters
+**/
+VOID
+SaveVolatileRegisters (
+ OUT CPU_VOLATILE_REGISTERS *VolatileRegisters
+ )
+{
+ CPUID_VERSION_INFO_EDX VersionInfoEdx;
+
+ VolatileRegisters->Cr0 = AsmReadCr0 ();
+ VolatileRegisters->Cr3 = AsmReadCr3 ();
+ VolatileRegisters->Cr4 = AsmReadCr4 ();
+
+ AsmCpuid (CPUID_VERSION_INFO, NULL, NULL, NULL, &VersionInfoEdx.Uint32);
+ if (VersionInfoEdx.Bits.DE != 0) {
+ //
+ // If processor supports Debugging Extensions feature
+ // by CPUID.[EAX=01H]:EDX.BIT2
+ //
+ VolatileRegisters->Dr0 = AsmReadDr0 ();
+ VolatileRegisters->Dr1 = AsmReadDr1 ();
+ VolatileRegisters->Dr2 = AsmReadDr2 ();
+ VolatileRegisters->Dr3 = AsmReadDr3 ();
+ VolatileRegisters->Dr6 = AsmReadDr6 ();
+ VolatileRegisters->Dr7 = AsmReadDr7 ();
+ }
+}
+
+/**
+ Restore the volatile registers following INIT IPI.
+
+ @param[in] VolatileRegisters Pointer to volatile resisters
+ @param[in] IsRestoreDr TRUE: Restore DRx if supported
+ FALSE: Do not restore DRx
+**/
+VOID
+RestoreVolatileRegisters (
+ IN CPU_VOLATILE_REGISTERS *VolatileRegisters,
+ IN BOOLEAN IsRestoreDr
+ )
+{
+ CPUID_VERSION_INFO_EDX VersionInfoEdx;
+
+ AsmWriteCr0 (VolatileRegisters->Cr0);
+ AsmWriteCr3 (VolatileRegisters->Cr3);
+ AsmWriteCr4 (VolatileRegisters->Cr4);
+
+ if (IsRestoreDr) {
+ AsmCpuid (CPUID_VERSION_INFO, NULL, NULL, NULL, &VersionInfoEdx.Uint32);
+ if (VersionInfoEdx.Bits.DE != 0) {
+ //
+ // If processor supports Debugging Extensions feature
+ // by CPUID.[EAX=01H]:EDX.BIT2
+ //
+ AsmWriteDr0 (VolatileRegisters->Dr0);
+ AsmWriteDr1 (VolatileRegisters->Dr1);
+ AsmWriteDr2 (VolatileRegisters->Dr2);
+ AsmWriteDr3 (VolatileRegisters->Dr3);
+ AsmWriteDr6 (VolatileRegisters->Dr6);
+ AsmWriteDr7 (VolatileRegisters->Dr7);
+ }
+ }
+}
+
+/**
Detect whether Mwait-monitor feature is supported.

@retval TRUE Mwait-monitor feature is supported.
@@ -204,6 +271,10 @@ MpInitLibInitialize (
CpuMpData->CpuInfoInHob = (UINT64) (UINTN) (CpuMpData->CpuData + MaxLogicalProcessorNumber);
InitializeSpinLock(&CpuMpData->MpLock);
//
+ // Save BSP's Control registers to APs
+ //
+ SaveVolatileRegisters (&CpuMpData->CpuData[0].VolatileRegisters);
+ //
// Set BSP basic information
//
InitializeApData (CpuMpData, 0, 0);
diff --git a/UefiCpuPkg/Library/MpInitLib/MpLib.h b/UefiCpuPkg/Library/MpInitLib/MpLib.h
index 84bd872..ca8bd44 100644
--- a/UefiCpuPkg/Library/MpInitLib/MpLib.h
+++ b/UefiCpuPkg/Library/MpInitLib/MpLib.h
@@ -66,6 +66,21 @@ typedef enum {
} CPU_STATE;

//
+// CPU volatile registers around INIT-SIPI-SIPI
+//
+typedef struct {
+ UINTN Cr0;
+ UINTN Cr3;
+ UINTN Cr4;
+ UINTN Dr0;
+ UINTN Dr1;
+ UINTN Dr2;
+ UINTN Dr3;
+ UINTN Dr6;
+ UINTN Dr7;
+} CPU_VOLATILE_REGISTERS;
+
+//
// AP related data
//
typedef struct {
@@ -78,6 +93,7 @@ typedef struct {
UINT32 Health;
BOOLEAN CpuHealthy;
volatile CPU_STATE State;
+ CPU_VOLATILE_REGISTERS VolatileRegisters;
BOOLEAN Waiting;
BOOLEAN *Finished;
UINT64 ExpectedTime;
--
2.7.4.windows.1


[Patch v5 13/48] UefiCpuPkg/MpInitLib: Initialize CPU_AP_DATA for CPU APs

Jeff Fan <jeff.fan@...>
 

Initialize CPU_AP_DATA for CPU APs and add GetApState()/SetApState() helper
functions to get/set AP state.

Cc: Michael Kinney <michael.d.kinney@intel.com>
Cc: Feng Tian <feng.tian@intel.com>
Cc: Giri P Mudusuru <giri.p.mudusuru@intel.com>
Cc: Laszlo Ersek <lersek@redhat.com>
Contributed-under: TianoCore Contribution Agreement 1.0
Signed-off-by: Jeff Fan <jeff.fan@intel.com>
---
UefiCpuPkg/Library/MpInitLib/MpLib.c | 76 ++++++++++++++++++++++++++++++++++++
UefiCpuPkg/Library/MpInitLib/MpLib.h | 12 ++++++
2 files changed, 88 insertions(+)

diff --git a/UefiCpuPkg/Library/MpInitLib/MpLib.c b/UefiCpuPkg/Library/MpInitLib/MpLib.c
index f05db7c..70e5eb1 100644
--- a/UefiCpuPkg/Library/MpInitLib/MpLib.c
+++ b/UefiCpuPkg/Library/MpInitLib/MpLib.c
@@ -14,6 +14,37 @@

#include "MpLib.h"

+/**
+ Get the Application Processors state.
+
+ @param[in] CpuData The pointer to CPU_AP_DATA of specified AP
+
+ @return The AP status
+**/
+CPU_STATE
+GetApState (
+ IN CPU_AP_DATA *CpuData
+ )
+{
+ return CpuData->State;
+}
+
+/**
+ Set the Application Processors state.
+
+ @param[in] CpuData The pointer to CPU_AP_DATA of specified AP
+ @param[in] State The AP status
+**/
+VOID
+SetApState (
+ IN CPU_AP_DATA *CpuData,
+ IN CPU_STATE State
+ )
+{
+ AcquireSpinLock (&CpuData->ApLock);
+ CpuData->State = State;
+ ReleaseSpinLock (&CpuData->ApLock);
+}

/**
Detect whether Mwait-monitor feature is supported.
@@ -74,6 +105,40 @@ GetApLoopMode (

return ApLoopMode;
}
+/*
+ Initialize CPU AP Data when AP is wakeup at the first time.
+
+ @param[in, out] CpuMpData Pointer to PEI CPU MP Data
+ @param[in] ProcessorNumber The handle number of processor
+ @param[in] BistData Processor BIST data
+
+**/
+VOID
+InitializeApData (
+ IN OUT CPU_MP_DATA *CpuMpData,
+ IN UINTN ProcessorNumber,
+ IN UINT32 BistData
+ )
+{
+ CpuMpData->CpuData[ProcessorNumber].Waiting = FALSE;
+ CpuMpData->CpuData[ProcessorNumber].Health = BistData;
+ CpuMpData->CpuData[ProcessorNumber].CpuHealthy = (BistData == 0) ? TRUE : FALSE;
+ CpuMpData->CpuData[ProcessorNumber].ApicId = GetApicId ();
+ CpuMpData->CpuData[ProcessorNumber].InitialApicId = GetInitialApicId ();
+ if (CpuMpData->CpuData[ProcessorNumber].InitialApicId >= 0xFF) {
+ //
+ // Set x2APIC mode if there are any logical processor reporting
+ // an Initial APIC ID of 255 or greater.
+ //
+ AcquireSpinLock(&CpuMpData->MpLock);
+ CpuMpData->X2ApicEnable = TRUE;
+ ReleaseSpinLock(&CpuMpData->MpLock);
+ }
+
+ InitializeSpinLock(&CpuMpData->CpuData[ProcessorNumber].ApLock);
+ SetApState (&CpuMpData->CpuData[ProcessorNumber], CpuStateIdle);
+}
+
/**
MP Initialize Library initialization.

@@ -103,6 +168,7 @@ MpInitLibInitialize (
CPU_MP_DATA *CpuMpData;
UINT8 ApLoopMode;
UINT8 *MonitorBuffer;
+ UINTN Index;
UINTN ApResetVectorSize;
UINTN BackupBufferAddr;
MaxLogicalProcessorNumber = PcdGet32(PcdCpuMaxLogicalProcessorNumber);
@@ -138,6 +204,10 @@ MpInitLibInitialize (
CpuMpData->CpuInfoInHob = (UINT64) (UINTN) (CpuMpData->CpuData + MaxLogicalProcessorNumber);
InitializeSpinLock(&CpuMpData->MpLock);
//
+ // Set BSP basic information
+ //
+ InitializeApData (CpuMpData, 0, 0);
+ //
// Save assembly code information
//
CopyMem (&CpuMpData->AddressMap, &AddressMap, sizeof (MP_ASSEMBLY_ADDRESS_MAP));
@@ -147,6 +217,12 @@ MpInitLibInitialize (
CpuMpData->ApLoopMode = ApLoopMode;
DEBUG ((DEBUG_INFO, "AP Loop Mode is %d\n", CpuMpData->ApLoopMode));
//
+ // Set up APs wakeup signal buffer
+ //
+ for (Index = 0; Index < MaxLogicalProcessorNumber; Index++) {
+ CpuMpData->CpuData[Index].StartupApSignal =
+ (UINT32 *)(MonitorBuffer + MonitorFilterSize * Index);
+ }
// Store BSP's MTRR setting
//
MtrrGetAllMtrrs (&CpuMpData->MtrrTable);
diff --git a/UefiCpuPkg/Library/MpInitLib/MpLib.h b/UefiCpuPkg/Library/MpInitLib/MpLib.h
index e605f8d..84bd872 100644
--- a/UefiCpuPkg/Library/MpInitLib/MpLib.h
+++ b/UefiCpuPkg/Library/MpInitLib/MpLib.h
@@ -55,6 +55,17 @@ typedef enum {
} AP_INIT_STATE;

//
+// AP state
+//
+typedef enum {
+ CpuStateIdle,
+ CpuStateReady,
+ CpuStateBusy,
+ CpuStateFinished,
+ CpuStateDisabled
+} CPU_STATE;
+
+//
// AP related data
//
typedef struct {
@@ -66,6 +77,7 @@ typedef struct {
UINT32 ApicId;
UINT32 Health;
BOOLEAN CpuHealthy;
+ volatile CPU_STATE State;
BOOLEAN Waiting;
BOOLEAN *Finished;
UINT64 ExpectedTime;
--
2.7.4.windows.1