diff options
Diffstat (limited to 'src/VBox/Devices/EFI/Firmware/UefiCpuPkg/Library/RegisterCpuFeaturesLib/RegisterCpuFeaturesLib.c')
-rw-r--r-- | src/VBox/Devices/EFI/Firmware/UefiCpuPkg/Library/RegisterCpuFeaturesLib/RegisterCpuFeaturesLib.c | 1291 |
1 files changed, 1291 insertions, 0 deletions
diff --git a/src/VBox/Devices/EFI/Firmware/UefiCpuPkg/Library/RegisterCpuFeaturesLib/RegisterCpuFeaturesLib.c b/src/VBox/Devices/EFI/Firmware/UefiCpuPkg/Library/RegisterCpuFeaturesLib/RegisterCpuFeaturesLib.c new file mode 100644 index 00000000..2661690e --- /dev/null +++ b/src/VBox/Devices/EFI/Firmware/UefiCpuPkg/Library/RegisterCpuFeaturesLib/RegisterCpuFeaturesLib.c @@ -0,0 +1,1291 @@ +/** @file + CPU Register Table Library functions. + + Copyright (c) 2017 - 2021, Intel Corporation. All rights reserved.<BR> + SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#include "RegisterCpuFeatures.h" + +/** + Function that uses DEBUG() macros to display the contents of a a CPU feature bit mask. + + @param[in] FeatureMask A pointer to the CPU feature bit mask. + @param[in] BitMaskSize CPU feature bits mask buffer size. + +**/ +VOID +DumpCpuFeatureMask ( + IN UINT8 *FeatureMask, + IN UINT32 BitMaskSize + ) +{ + UINTN Index; + UINT8 *Data8; + + Data8 = (UINT8 *) FeatureMask; + for (Index = 0; Index < BitMaskSize; Index++) { + DEBUG ((DEBUG_INFO, " %02x ", *Data8++)); + } + DEBUG ((DEBUG_INFO, "\n")); +} + +/** + Dump CPU feature name or CPU feature bit mask. + + @param[in] CpuFeature Pointer to CPU_FEATURES_ENTRY + @param[in] BitMaskSize CPU feature bits mask buffer size. + +**/ +VOID +DumpCpuFeature ( + IN CPU_FEATURES_ENTRY *CpuFeature, + IN UINT32 BitMaskSize + ) +{ + + if (CpuFeature->FeatureName != NULL) { + DEBUG ((DEBUG_INFO, "FeatureName: %a\n", CpuFeature->FeatureName)); + } else { + DEBUG ((DEBUG_INFO, "FeatureMask = ")); + DumpCpuFeatureMask (CpuFeature->FeatureMask, BitMaskSize); + } +} + +/** + Determines if the feature bit mask is in dependent CPU feature bit mask buffer. + + @param[in] FeatureMask Pointer to CPU feature bit mask + @param[in] DependentBitMask Pointer to dependent CPU feature bit mask buffer + + @retval TRUE The feature bit mask is in dependent CPU feature bit mask buffer. + @retval FALSE The feature bit mask is not in dependent CPU feature bit mask buffer. +**/ +BOOLEAN +IsBitMaskMatchCheck ( + IN UINT8 *FeatureMask, + IN UINT8 *DependentBitMask + ) +{ + UINTN Index; + UINT8 *Data1; + UINT8 *Data2; + CPU_FEATURES_DATA *CpuFeaturesData; + + CpuFeaturesData = GetCpuFeaturesData (); + + Data1 = FeatureMask; + Data2 = DependentBitMask; + for (Index = 0; Index < CpuFeaturesData->BitMaskSize; Index++) { + if (((*(Data1++)) & (*(Data2++))) != 0) { + return TRUE; + } + } + return FALSE; +} + +/** + Try to find the specify cpu featuren in former/after feature list. + + @param[in] FeatureList Pointer to dependent CPU feature list + @param[in] CurrentEntry Pointer to current CPU feature entry. + @param[in] SearchFormer Find in former feature or after features. + @param[in] FeatureMask Pointer to CPU feature bit mask + + @retval TRUE The feature bit mask is in dependent CPU feature bit mask buffer. + @retval FALSE The feature bit mask is not in dependent CPU feature bit mask buffer. +**/ +BOOLEAN +FindSpecifyFeature ( + IN LIST_ENTRY *FeatureList, + IN LIST_ENTRY *CurrentEntry, + IN BOOLEAN SearchFormer, + IN UINT8 *FeatureMask + ) +{ + CPU_FEATURES_ENTRY *CpuFeature; + LIST_ENTRY *NextEntry; + + // + // Check whether exist the not neighborhood entry first. + // If not exist, return FALSE means not found status. + // + if (SearchFormer) { + NextEntry = CurrentEntry->BackLink; + if (IsNull (FeatureList, NextEntry)) { + return FALSE; + } + + NextEntry = NextEntry->BackLink; + if (IsNull (FeatureList, NextEntry)) { + return FALSE; + } + + NextEntry = CurrentEntry->BackLink->BackLink; + } else { + NextEntry = CurrentEntry->ForwardLink; + if (IsNull (FeatureList, NextEntry)) { + return FALSE; + } + + NextEntry = NextEntry->ForwardLink; + if (IsNull (FeatureList, NextEntry)) { + return FALSE; + } + + NextEntry = CurrentEntry->ForwardLink->ForwardLink; + } + + while (!IsNull (FeatureList, NextEntry)) { + CpuFeature = CPU_FEATURE_ENTRY_FROM_LINK (NextEntry); + + if (IsBitMaskMatchCheck (FeatureMask, CpuFeature->FeatureMask)) { + return TRUE; + } + + if (SearchFormer) { + NextEntry = NextEntry->BackLink; + } else { + NextEntry = NextEntry->ForwardLink; + } + } + + return FALSE; +} + +/** + Return feature dependence result. + + @param[in] CpuFeature Pointer to CPU feature. + @param[in] Before Check before dependence or after. + @param[in] NextCpuFeatureMask Pointer to next CPU feature Mask. + + @retval return the dependence result. +**/ +CPU_FEATURE_DEPENDENCE_TYPE +DetectFeatureScope ( + IN CPU_FEATURES_ENTRY *CpuFeature, + IN BOOLEAN Before, + IN UINT8 *NextCpuFeatureMask + ) +{ + // + // if need to check before type dependence but the feature after current feature is not + // exist, means this before type dependence not valid, just return NoneDepType. + // Just like Feature A has a dependence of feature B, but Feature B not installed, so + // Feature A maybe insert to the last entry of the list. In this case, for below code, + // Featrure A has depend of feature B, but it is the last entry of the list, so the + // NextCpuFeatureMask is NULL, so the dependence for feature A here is useless and code + // just return NoneDepType. + // + if (NextCpuFeatureMask == NULL) { + return NoneDepType; + } + + if (Before) { + if ((CpuFeature->PackageBeforeFeatureBitMask != NULL) && + IsBitMaskMatchCheck (NextCpuFeatureMask, CpuFeature->PackageBeforeFeatureBitMask)) { + return PackageDepType; + } + + if ((CpuFeature->CoreBeforeFeatureBitMask != NULL) && + IsBitMaskMatchCheck (NextCpuFeatureMask, CpuFeature->CoreBeforeFeatureBitMask)) { + return CoreDepType; + } + + if ((CpuFeature->ThreadBeforeFeatureBitMask != NULL) && + IsBitMaskMatchCheck (NextCpuFeatureMask, CpuFeature->ThreadBeforeFeatureBitMask)) { + return ThreadDepType; + } + + return NoneDepType; + } + + if ((CpuFeature->PackageAfterFeatureBitMask != NULL) && + IsBitMaskMatchCheck (NextCpuFeatureMask, CpuFeature->PackageAfterFeatureBitMask)) { + return PackageDepType; + } + + if ((CpuFeature->CoreAfterFeatureBitMask != NULL) && + IsBitMaskMatchCheck (NextCpuFeatureMask, CpuFeature->CoreAfterFeatureBitMask)) { + return CoreDepType; + } + + if ((CpuFeature->ThreadAfterFeatureBitMask != NULL) && + IsBitMaskMatchCheck (NextCpuFeatureMask, CpuFeature->ThreadAfterFeatureBitMask)) { + return ThreadDepType; + } + + return NoneDepType; +} + +/** + Return feature dependence result. + + @param[in] CpuFeature Pointer to CPU feature. + @param[in] Before Check before dependence or after. + @param[in] FeatureList Pointer to CPU feature list. + + @retval return the dependence result. +**/ +CPU_FEATURE_DEPENDENCE_TYPE +DetectNoneNeighborhoodFeatureScope ( + IN CPU_FEATURES_ENTRY *CpuFeature, + IN BOOLEAN Before, + IN LIST_ENTRY *FeatureList + ) +{ + if (Before) { + if ((CpuFeature->PackageBeforeFeatureBitMask != NULL) && + FindSpecifyFeature(FeatureList, &CpuFeature->Link, FALSE, CpuFeature->PackageBeforeFeatureBitMask)) { + return PackageDepType; + } + + if ((CpuFeature->CoreBeforeFeatureBitMask != NULL) && + FindSpecifyFeature(FeatureList, &CpuFeature->Link, FALSE, CpuFeature->CoreBeforeFeatureBitMask)) { + return CoreDepType; + } + + if ((CpuFeature->ThreadBeforeFeatureBitMask != NULL) && + FindSpecifyFeature(FeatureList, &CpuFeature->Link, FALSE, CpuFeature->ThreadBeforeFeatureBitMask)) { + return ThreadDepType; + } + + return NoneDepType; + } + + if ((CpuFeature->PackageAfterFeatureBitMask != NULL) && + FindSpecifyFeature(FeatureList, &CpuFeature->Link, TRUE, CpuFeature->PackageAfterFeatureBitMask)) { + return PackageDepType; + } + + if ((CpuFeature->CoreAfterFeatureBitMask != NULL) && + FindSpecifyFeature(FeatureList, &CpuFeature->Link, TRUE, CpuFeature->CoreAfterFeatureBitMask)) { + return CoreDepType; + } + + if ((CpuFeature->ThreadAfterFeatureBitMask != NULL) && + FindSpecifyFeature(FeatureList, &CpuFeature->Link, TRUE, CpuFeature->ThreadAfterFeatureBitMask)) { + return ThreadDepType; + } + + return NoneDepType; +} + +/** + Base on dependence relationship to asjust feature dependence. + + ONLY when the feature before(or after) the find feature also has + dependence with the find feature. In this case, driver need to base + on dependce relationship to decide how to insert current feature and + adjust the feature dependence. + + @param[in, out] PreviousFeature CPU feature current before the find one. + @param[in, out] CurrentFeature Cpu feature need to adjust. + @param[in] FindFeature Cpu feature which current feature depends. + @param[in] Before Before or after dependence relationship. + + @retval TRUE means the current feature dependence has been adjusted. + + @retval FALSE means the previous feature dependence has been adjusted. + or previous feature has no dependence with the find one. + +**/ +BOOLEAN +AdjustFeaturesDependence ( + IN OUT CPU_FEATURES_ENTRY *PreviousFeature, + IN OUT CPU_FEATURES_ENTRY *CurrentFeature, + IN CPU_FEATURES_ENTRY *FindFeature, + IN BOOLEAN Before + ) +{ + CPU_FEATURE_DEPENDENCE_TYPE PreDependType; + CPU_FEATURE_DEPENDENCE_TYPE CurrentDependType; + + PreDependType = DetectFeatureScope(PreviousFeature, Before, FindFeature->FeatureMask); + CurrentDependType = DetectFeatureScope(CurrentFeature, Before, FindFeature->FeatureMask); + + // + // If previous feature has no dependence with the find featue. + // return FALSE. + // + if (PreDependType == NoneDepType) { + return FALSE; + } + + // + // If both feature have dependence, keep the one which needs use more + // processors and clear the dependence for the other one. + // + if (PreDependType >= CurrentDependType) { + return TRUE; + } else { + return FALSE; + } +} + +/** + Base on dependence relationship to asjust feature order. + + @param[in] FeatureList Pointer to CPU feature list + @param[in, out] FindEntry The entry this feature depend on. + @param[in, out] CurrentEntry The entry for this feature. + @param[in] Before Before or after dependence relationship. + +**/ +VOID +AdjustEntry ( + IN LIST_ENTRY *FeatureList, + IN OUT LIST_ENTRY *FindEntry, + IN OUT LIST_ENTRY *CurrentEntry, + IN BOOLEAN Before + ) +{ + LIST_ENTRY *PreviousEntry; + CPU_FEATURES_ENTRY *PreviousFeature; + CPU_FEATURES_ENTRY *CurrentFeature; + CPU_FEATURES_ENTRY *FindFeature; + + // + // For CPU feature which has core or package type dependence, later code need to insert + // AcquireSpinLock/ReleaseSpinLock logic to sequency the execute order. + // So if driver finds both feature A and B need to execute before feature C, driver will + // base on dependence type of feature A and B to update the logic here. + // For example, feature A has package type dependence and feature B has core type dependence, + // because package type dependence need to wait for more processors which has strong dependence + // than core type dependence. So driver will adjust the feature order to B -> A -> C. and driver + // will remove the feature dependence in feature B. + // Driver just needs to make sure before feature C been executed, feature A has finished its task + // in all all thread. Feature A finished in all threads also means feature B have finshed in all + // threads. + // + if (Before) { + PreviousEntry = GetPreviousNode (FeatureList, FindEntry); + } else { + + PreviousEntry = GetNextNode (FeatureList, FindEntry); + } + + CurrentFeature = CPU_FEATURE_ENTRY_FROM_LINK (CurrentEntry); + RemoveEntryList (CurrentEntry); + + if (IsNull (FeatureList, PreviousEntry)) { + // + // If not exist the previous or next entry, just insert the current entry. + // + if (Before) { + InsertTailList (FindEntry, CurrentEntry); + } else { + InsertHeadList (FindEntry, CurrentEntry); + } + } else { + // + // If exist the previous or next entry, need to check it before insert curent entry. + // + PreviousFeature = CPU_FEATURE_ENTRY_FROM_LINK (PreviousEntry); + FindFeature = CPU_FEATURE_ENTRY_FROM_LINK (FindEntry); + + if (AdjustFeaturesDependence (PreviousFeature, CurrentFeature, FindFeature, Before)) { + // + // Return TRUE means current feature dependence has been cleared and the previous + // feature dependence has been kept and used. So insert current feature before (or after) + // the previous feature. + // + if (Before) { + InsertTailList (PreviousEntry, CurrentEntry); + } else { + InsertHeadList (PreviousEntry, CurrentEntry); + } + } else { + if (Before) { + InsertTailList (FindEntry, CurrentEntry); + } else { + InsertHeadList (FindEntry, CurrentEntry); + } + } + } +} + + +/** + Checks and adjusts current CPU features per dependency relationship. + + @param[in] FeatureList Pointer to CPU feature list + @param[in] CurrentEntry Pointer to current checked CPU feature + @param[in] FeatureMask The feature bit mask. + + @retval return Swapped info. +**/ +BOOLEAN +InsertToBeforeEntry ( + IN LIST_ENTRY *FeatureList, + IN LIST_ENTRY *CurrentEntry, + IN UINT8 *FeatureMask + ) +{ + LIST_ENTRY *CheckEntry; + CPU_FEATURES_ENTRY *CheckFeature; + BOOLEAN Swapped; + + Swapped = FALSE; + + // + // Check all features dispatched before this entry + // + CheckEntry = GetFirstNode (FeatureList); + while (CheckEntry != CurrentEntry) { + CheckFeature = CPU_FEATURE_ENTRY_FROM_LINK (CheckEntry); + if (IsBitMaskMatchCheck (CheckFeature->FeatureMask, FeatureMask)) { + AdjustEntry (FeatureList, CheckEntry, CurrentEntry, TRUE); + Swapped = TRUE; + break; + } + CheckEntry = CheckEntry->ForwardLink; + } + + return Swapped; +} + +/** + Checks and adjusts current CPU features per dependency relationship. + + @param[in] FeatureList Pointer to CPU feature list + @param[in] CurrentEntry Pointer to current checked CPU feature + @param[in] FeatureMask The feature bit mask. + + @retval return Swapped info. +**/ +BOOLEAN +InsertToAfterEntry ( + IN LIST_ENTRY *FeatureList, + IN LIST_ENTRY *CurrentEntry, + IN UINT8 *FeatureMask + ) +{ + LIST_ENTRY *CheckEntry; + CPU_FEATURES_ENTRY *CheckFeature; + BOOLEAN Swapped; + + Swapped = FALSE; + + // + // Check all features dispatched after this entry + // + CheckEntry = GetNextNode (FeatureList, CurrentEntry); + while (!IsNull (FeatureList, CheckEntry)) { + CheckFeature = CPU_FEATURE_ENTRY_FROM_LINK (CheckEntry); + if (IsBitMaskMatchCheck (CheckFeature->FeatureMask, FeatureMask)) { + AdjustEntry (FeatureList, CheckEntry, CurrentEntry, FALSE); + Swapped = TRUE; + break; + } + CheckEntry = CheckEntry->ForwardLink; + } + + return Swapped; +} + +/** + Checks and adjusts CPU features order per dependency relationship. + + @param[in] FeatureList Pointer to CPU feature list +**/ +VOID +CheckCpuFeaturesDependency ( + IN LIST_ENTRY *FeatureList + ) +{ + LIST_ENTRY *CurrentEntry; + CPU_FEATURES_ENTRY *CpuFeature; + LIST_ENTRY *CheckEntry; + CPU_FEATURES_ENTRY *CheckFeature; + BOOLEAN Swapped; + LIST_ENTRY *TempEntry; + LIST_ENTRY *NextEntry; + + CurrentEntry = GetFirstNode (FeatureList); + while (!IsNull (FeatureList, CurrentEntry)) { + Swapped = FALSE; + CpuFeature = CPU_FEATURE_ENTRY_FROM_LINK (CurrentEntry); + NextEntry = CurrentEntry->ForwardLink; + if (CpuFeature->BeforeAll) { + // + // Check all features dispatched before this entry + // + CheckEntry = GetFirstNode (FeatureList); + while (CheckEntry != CurrentEntry) { + CheckFeature = CPU_FEATURE_ENTRY_FROM_LINK (CheckEntry); + if (!CheckFeature->BeforeAll) { + // + // If this feature has no BeforeAll flag and is dispatched before CpuFeature, + // insert currentEntry before Checked feature + // + RemoveEntryList (CurrentEntry); + InsertTailList (CheckEntry, CurrentEntry); + Swapped = TRUE; + break; + } + CheckEntry = CheckEntry->ForwardLink; + } + if (Swapped) { + CurrentEntry = NextEntry; + continue; + } + } + + if (CpuFeature->AfterAll) { + // + // Check all features dispatched after this entry + // + CheckEntry = GetNextNode (FeatureList, CurrentEntry); + while (!IsNull (FeatureList, CheckEntry)) { + CheckFeature = CPU_FEATURE_ENTRY_FROM_LINK (CheckEntry); + if (!CheckFeature->AfterAll) { + // + // If this feature has no AfterAll flag and is dispatched after CpuFeature, + // insert currentEntry after Checked feature + // + TempEntry = GetNextNode (FeatureList, CurrentEntry); + RemoveEntryList (CurrentEntry); + InsertHeadList (CheckEntry, CurrentEntry); + CurrentEntry = TempEntry; + Swapped = TRUE; + break; + } + CheckEntry = CheckEntry->ForwardLink; + } + if (Swapped) { + CurrentEntry = NextEntry; + continue; + } + } + + if (CpuFeature->ThreadBeforeFeatureBitMask != NULL) { + Swapped = InsertToBeforeEntry (FeatureList, CurrentEntry, CpuFeature->ThreadBeforeFeatureBitMask); + if (Swapped) { + continue; + } + } + + if (CpuFeature->ThreadAfterFeatureBitMask != NULL) { + Swapped = InsertToAfterEntry (FeatureList, CurrentEntry, CpuFeature->ThreadAfterFeatureBitMask); + if (Swapped) { + continue; + } + } + + if (CpuFeature->CoreBeforeFeatureBitMask != NULL) { + Swapped = InsertToBeforeEntry (FeatureList, CurrentEntry, CpuFeature->CoreBeforeFeatureBitMask); + if (Swapped) { + continue; + } + } + + if (CpuFeature->CoreAfterFeatureBitMask != NULL) { + Swapped = InsertToAfterEntry (FeatureList, CurrentEntry, CpuFeature->CoreAfterFeatureBitMask); + if (Swapped) { + continue; + } + } + + if (CpuFeature->PackageBeforeFeatureBitMask != NULL) { + Swapped = InsertToBeforeEntry (FeatureList, CurrentEntry, CpuFeature->PackageBeforeFeatureBitMask); + if (Swapped) { + continue; + } + } + + if (CpuFeature->PackageAfterFeatureBitMask != NULL) { + Swapped = InsertToAfterEntry (FeatureList, CurrentEntry, CpuFeature->PackageAfterFeatureBitMask); + if (Swapped) { + continue; + } + } + + CurrentEntry = CurrentEntry->ForwardLink; + } +} + +/** + Worker function to register CPU Feature. + + @param[in] CpuFeaturesData Pointer to CPU feature data structure. + @param[in] CpuFeature Pointer to CPU feature entry + + @retval RETURN_SUCCESS The CPU feature was successfully registered. + @retval RETURN_OUT_OF_RESOURCES There are not enough resources to register + the CPU feature. + @retval RETURN_UNSUPPORTED Registration of the CPU feature is not + supported due to a circular dependency between + BEFORE and AFTER features. +**/ +RETURN_STATUS +RegisterCpuFeatureWorker ( + IN CPU_FEATURES_DATA *CpuFeaturesData, + IN CPU_FEATURES_ENTRY *CpuFeature + ) +{ + EFI_STATUS Status; + CPU_FEATURES_ENTRY *CpuFeatureEntry; + LIST_ENTRY *Entry; + BOOLEAN FeatureExist; + + FeatureExist = FALSE; + CpuFeatureEntry = NULL; + Entry = GetFirstNode (&CpuFeaturesData->FeatureList); + while (!IsNull (&CpuFeaturesData->FeatureList, Entry)) { + CpuFeatureEntry = CPU_FEATURE_ENTRY_FROM_LINK (Entry); + if (CompareMem (CpuFeature->FeatureMask, CpuFeatureEntry->FeatureMask, CpuFeaturesData->BitMaskSize) == 0) { + // + // If this feature already registered + // + FeatureExist = TRUE; + break; + } + Entry = Entry->ForwardLink; + } + + if (!FeatureExist) { + DEBUG ((DEBUG_INFO, "[NEW] ")); + DumpCpuFeature (CpuFeature, CpuFeaturesData->BitMaskSize); + InsertTailList (&CpuFeaturesData->FeatureList, &CpuFeature->Link); + CpuFeaturesData->FeaturesCount++; + } else { + DEBUG ((DEBUG_INFO, "[OVERRIDE] ")); + DumpCpuFeature (CpuFeature, CpuFeaturesData->BitMaskSize); + ASSERT (CpuFeatureEntry != NULL); + // + // Overwrite original parameters of CPU feature + // + if (CpuFeature->GetConfigDataFunc != NULL) { + CpuFeatureEntry->GetConfigDataFunc = CpuFeature->GetConfigDataFunc; + } + if (CpuFeature->SupportFunc != NULL) { + CpuFeatureEntry->SupportFunc = CpuFeature->SupportFunc; + } + if (CpuFeature->InitializeFunc != NULL) { + CpuFeatureEntry->InitializeFunc = CpuFeature->InitializeFunc; + } + if (CpuFeature->FeatureName != NULL) { + if (CpuFeatureEntry->FeatureName == NULL) { + CpuFeatureEntry->FeatureName = AllocatePool (CPU_FEATURE_NAME_SIZE); + ASSERT (CpuFeatureEntry->FeatureName != NULL); + } + Status = AsciiStrCpyS (CpuFeatureEntry->FeatureName, CPU_FEATURE_NAME_SIZE, CpuFeature->FeatureName); + ASSERT_EFI_ERROR (Status); + FreePool (CpuFeature->FeatureName); + } + if (CpuFeature->ThreadBeforeFeatureBitMask != NULL) { + if (CpuFeatureEntry->ThreadBeforeFeatureBitMask != NULL) { + FreePool (CpuFeatureEntry->ThreadBeforeFeatureBitMask); + } + CpuFeatureEntry->ThreadBeforeFeatureBitMask = CpuFeature->ThreadBeforeFeatureBitMask; + } + if (CpuFeature->ThreadAfterFeatureBitMask != NULL) { + if (CpuFeatureEntry->ThreadAfterFeatureBitMask != NULL) { + FreePool (CpuFeatureEntry->ThreadAfterFeatureBitMask); + } + CpuFeatureEntry->ThreadAfterFeatureBitMask = CpuFeature->ThreadAfterFeatureBitMask; + } + if (CpuFeature->CoreBeforeFeatureBitMask != NULL) { + if (CpuFeatureEntry->CoreBeforeFeatureBitMask != NULL) { + FreePool (CpuFeatureEntry->CoreBeforeFeatureBitMask); + } + CpuFeatureEntry->CoreBeforeFeatureBitMask = CpuFeature->CoreBeforeFeatureBitMask; + } + if (CpuFeature->CoreAfterFeatureBitMask != NULL) { + if (CpuFeatureEntry->CoreAfterFeatureBitMask != NULL) { + FreePool (CpuFeatureEntry->CoreAfterFeatureBitMask); + } + CpuFeatureEntry->CoreAfterFeatureBitMask = CpuFeature->CoreAfterFeatureBitMask; + } + if (CpuFeature->PackageBeforeFeatureBitMask != NULL) { + if (CpuFeatureEntry->PackageBeforeFeatureBitMask != NULL) { + FreePool (CpuFeatureEntry->PackageBeforeFeatureBitMask); + } + CpuFeatureEntry->PackageBeforeFeatureBitMask = CpuFeature->PackageBeforeFeatureBitMask; + } + if (CpuFeature->PackageAfterFeatureBitMask != NULL) { + if (CpuFeatureEntry->PackageAfterFeatureBitMask != NULL) { + FreePool (CpuFeatureEntry->PackageAfterFeatureBitMask); + } + CpuFeatureEntry->PackageAfterFeatureBitMask = CpuFeature->PackageAfterFeatureBitMask; + } + + CpuFeatureEntry->BeforeAll = CpuFeature->BeforeAll; + CpuFeatureEntry->AfterAll = CpuFeature->AfterAll; + + FreePool (CpuFeature->FeatureMask); + FreePool (CpuFeature); + } + // + // Verify CPU features dependency can change CPU feature order + // + CheckCpuFeaturesDependency (&CpuFeaturesData->FeatureList); + return RETURN_SUCCESS; +} + +/** + Sets CPU feature bit mask in CPU feature bit mask buffer. + + @param[in] FeaturesBitMask Pointer to CPU feature bit mask buffer + @param[in] Feature The bit number of the CPU feature + @param[in] BitMaskSize CPU feature bit mask buffer size +**/ +VOID +SetCpuFeaturesBitMask ( + IN UINT8 **FeaturesBitMask, + IN UINT32 Feature, + IN UINTN BitMaskSize + ) +{ + UINT8 *CpuFeaturesBitMask; + + ASSERT (FeaturesBitMask != NULL); + CpuFeaturesBitMask = *FeaturesBitMask; + if (CpuFeaturesBitMask == NULL) { + CpuFeaturesBitMask = AllocateZeroPool (BitMaskSize); + ASSERT (CpuFeaturesBitMask != NULL); + *FeaturesBitMask = CpuFeaturesBitMask; + } + + CpuFeaturesBitMask += (Feature / 8); + *CpuFeaturesBitMask |= (UINT8) (1 << (Feature % 8)); +} + +/** + Registers a CPU Feature. + + @param[in] FeatureName A Null-terminated Ascii string indicates CPU feature + name. + @param[in] GetConfigDataFunc CPU feature get configuration data function. This + is an optional parameter that may be NULL. If NULL, + then the most recently registered function for the + CPU feature is used. If no functions are registered + for a CPU feature, then the CPU configuration data + for the registered feature is NULL. + @param[in] SupportFunc CPU feature support function. This is an optional + parameter that may be NULL. If NULL, then the most + recently registered function for the CPU feature is + used. If no functions are registered for a CPU + feature, then the CPU feature is assumed to be + supported by all CPUs. + @param[in] InitializeFunc CPU feature initialize function. This is an optional + parameter that may be NULL. If NULL, then the most + recently registered function for the CPU feature is + used. If no functions are registered for a CPU + feature, then the CPU feature initialization is + skipped. + @param[in] ... Variable argument list of UINT32 CPU feature value. + Values with no modifiers are the features provided + by the registered functions. + Values with CPU_FEATURE_BEFORE modifier are features + that must be initialized after the features provided + by the registered functions are used. + Values with CPU_FEATURE_AFTER modifier are features + that must be initialized before the features provided + by the registered functions are used. + The last argument in this variable argument list must + always be CPU_FEATURE_END. + + @retval RETURN_SUCCESS The CPU feature was successfully registered. + @retval RETURN_OUT_OF_RESOURCES There are not enough resources to register + the CPU feature. + @retval RETURN_UNSUPPORTED Registration of the CPU feature is not + supported due to a circular dependency between + BEFORE and AFTER features. + @retval RETURN_NOT_READY CPU feature PCD PcdCpuFeaturesUserConfiguration + not updated by Platform driver yet. + + @note This service could be called by BSP only. +**/ +RETURN_STATUS +EFIAPI +RegisterCpuFeature ( + IN CHAR8 *FeatureName, OPTIONAL + IN CPU_FEATURE_GET_CONFIG_DATA GetConfigDataFunc, OPTIONAL + IN CPU_FEATURE_SUPPORT SupportFunc, OPTIONAL + IN CPU_FEATURE_INITIALIZE InitializeFunc, OPTIONAL + ... + ) +{ + EFI_STATUS Status; + VA_LIST Marker; + UINT32 Feature; + CPU_FEATURES_ENTRY *CpuFeature; + UINT8 *FeatureMask; + UINT8 *ThreadBeforeFeatureBitMask; + UINT8 *ThreadAfterFeatureBitMask; + UINT8 *CoreBeforeFeatureBitMask; + UINT8 *CoreAfterFeatureBitMask; + UINT8 *PackageBeforeFeatureBitMask; + UINT8 *PackageAfterFeatureBitMask; + BOOLEAN BeforeAll; + BOOLEAN AfterAll; + CPU_FEATURES_DATA *CpuFeaturesData; + + FeatureMask = NULL; + ThreadBeforeFeatureBitMask = NULL; + ThreadAfterFeatureBitMask = NULL; + CoreBeforeFeatureBitMask = NULL; + CoreAfterFeatureBitMask = NULL; + PackageBeforeFeatureBitMask = NULL; + PackageAfterFeatureBitMask = NULL; + BeforeAll = FALSE; + AfterAll = FALSE; + + CpuFeaturesData = GetCpuFeaturesData (); + if (CpuFeaturesData->FeaturesCount == 0) { + InitializeListHead (&CpuFeaturesData->FeatureList); + InitializeSpinLock (&CpuFeaturesData->CpuFlags.MemoryMappedLock); + // + // Code assumes below three PCDs have PCD same buffer size. + // + ASSERT (PcdGetSize (PcdCpuFeaturesSetting) == PcdGetSize (PcdCpuFeaturesCapability)); + ASSERT (PcdGetSize (PcdCpuFeaturesSetting) == PcdGetSize (PcdCpuFeaturesSupport)); + CpuFeaturesData->BitMaskSize = (UINT32) PcdGetSize (PcdCpuFeaturesSetting); + } + + VA_START (Marker, InitializeFunc); + Feature = VA_ARG (Marker, UINT32); + while (Feature != CPU_FEATURE_END) { + // + // It's invalid to require a feature is before AND after all other features. + // + ASSERT ((Feature & (CPU_FEATURE_BEFORE_ALL | CPU_FEATURE_AFTER_ALL)) + != (CPU_FEATURE_BEFORE_ALL | CPU_FEATURE_AFTER_ALL)); + + // + // It's invalid to require feature A is before AND after before feature B, + // either in thread level, core level or package level. + // + ASSERT ((Feature & (CPU_FEATURE_THREAD_BEFORE | CPU_FEATURE_THREAD_AFTER)) + != (CPU_FEATURE_THREAD_BEFORE | CPU_FEATURE_THREAD_AFTER)); + ASSERT ((Feature & (CPU_FEATURE_CORE_BEFORE | CPU_FEATURE_CORE_AFTER)) + != (CPU_FEATURE_CORE_BEFORE | CPU_FEATURE_CORE_AFTER)); + ASSERT ((Feature & (CPU_FEATURE_PACKAGE_BEFORE | CPU_FEATURE_PACKAGE_AFTER)) + != (CPU_FEATURE_PACKAGE_BEFORE | CPU_FEATURE_PACKAGE_AFTER)); + if (Feature < CPU_FEATURE_THREAD_BEFORE) { + BeforeAll = ((Feature & CPU_FEATURE_BEFORE_ALL) != 0) ? TRUE : FALSE; + AfterAll = ((Feature & CPU_FEATURE_AFTER_ALL) != 0) ? TRUE : FALSE; + Feature &= ~(CPU_FEATURE_BEFORE_ALL | CPU_FEATURE_AFTER_ALL); + ASSERT (FeatureMask == NULL); + SetCpuFeaturesBitMask (&FeatureMask, Feature, CpuFeaturesData->BitMaskSize); + } else if ((Feature & CPU_FEATURE_THREAD_BEFORE) != 0) { + SetCpuFeaturesBitMask (&ThreadBeforeFeatureBitMask, Feature & ~CPU_FEATURE_THREAD_BEFORE, CpuFeaturesData->BitMaskSize); + } else if ((Feature & CPU_FEATURE_THREAD_AFTER) != 0) { + SetCpuFeaturesBitMask (&ThreadAfterFeatureBitMask, Feature & ~CPU_FEATURE_THREAD_AFTER, CpuFeaturesData->BitMaskSize); + } else if ((Feature & CPU_FEATURE_CORE_BEFORE) != 0) { + SetCpuFeaturesBitMask (&CoreBeforeFeatureBitMask, Feature & ~CPU_FEATURE_CORE_BEFORE, CpuFeaturesData->BitMaskSize); + } else if ((Feature & CPU_FEATURE_CORE_AFTER) != 0) { + SetCpuFeaturesBitMask (&CoreAfterFeatureBitMask, Feature & ~CPU_FEATURE_CORE_AFTER, CpuFeaturesData->BitMaskSize); + } else if ((Feature & CPU_FEATURE_PACKAGE_BEFORE) != 0) { + SetCpuFeaturesBitMask (&PackageBeforeFeatureBitMask, Feature & ~CPU_FEATURE_PACKAGE_BEFORE, CpuFeaturesData->BitMaskSize); + } else if ((Feature & CPU_FEATURE_PACKAGE_AFTER) != 0) { + SetCpuFeaturesBitMask (&PackageAfterFeatureBitMask, Feature & ~CPU_FEATURE_PACKAGE_AFTER, CpuFeaturesData->BitMaskSize); + } + Feature = VA_ARG (Marker, UINT32); + } + VA_END (Marker); + + CpuFeature = AllocateZeroPool (sizeof (CPU_FEATURES_ENTRY)); + ASSERT (CpuFeature != NULL); + CpuFeature->Signature = CPU_FEATURE_ENTRY_SIGNATURE; + CpuFeature->FeatureMask = FeatureMask; + CpuFeature->ThreadBeforeFeatureBitMask = ThreadBeforeFeatureBitMask; + CpuFeature->ThreadAfterFeatureBitMask = ThreadAfterFeatureBitMask; + CpuFeature->CoreBeforeFeatureBitMask = CoreBeforeFeatureBitMask; + CpuFeature->CoreAfterFeatureBitMask = CoreAfterFeatureBitMask; + CpuFeature->PackageBeforeFeatureBitMask = PackageBeforeFeatureBitMask; + CpuFeature->PackageAfterFeatureBitMask = PackageAfterFeatureBitMask; + CpuFeature->BeforeAll = BeforeAll; + CpuFeature->AfterAll = AfterAll; + CpuFeature->GetConfigDataFunc = GetConfigDataFunc; + CpuFeature->SupportFunc = SupportFunc; + CpuFeature->InitializeFunc = InitializeFunc; + if (FeatureName != NULL) { + CpuFeature->FeatureName = AllocatePool (CPU_FEATURE_NAME_SIZE); + ASSERT (CpuFeature->FeatureName != NULL); + Status = AsciiStrCpyS (CpuFeature->FeatureName, CPU_FEATURE_NAME_SIZE, FeatureName); + ASSERT_EFI_ERROR (Status); + } + + Status = RegisterCpuFeatureWorker (CpuFeaturesData, CpuFeature); + ASSERT_EFI_ERROR (Status); + + return RETURN_SUCCESS; +} + +/** + Return ACPI_CPU_DATA data. + + @return Pointer to ACPI_CPU_DATA data. +**/ +ACPI_CPU_DATA * +GetAcpiCpuData ( + VOID + ) +{ + EFI_STATUS Status; + UINTN NumberOfCpus; + UINTN NumberOfEnabledProcessors; + ACPI_CPU_DATA *AcpiCpuData; + UINTN TableSize; + CPU_REGISTER_TABLE *RegisterTable; + UINTN Index; + EFI_PROCESSOR_INFORMATION ProcessorInfoBuffer; + + AcpiCpuData = (ACPI_CPU_DATA *) (UINTN) PcdGet64 (PcdCpuS3DataAddress); + if (AcpiCpuData == NULL) { + AcpiCpuData = AllocatePages (EFI_SIZE_TO_PAGES (sizeof (ACPI_CPU_DATA))); + ASSERT (AcpiCpuData != NULL); + ZeroMem (AcpiCpuData, sizeof (ACPI_CPU_DATA)); + + // + // Set PcdCpuS3DataAddress to the base address of the ACPI_CPU_DATA structure + // + Status = PcdSet64S (PcdCpuS3DataAddress, (UINT64)(UINTN)AcpiCpuData); + ASSERT_EFI_ERROR (Status); + + GetNumberOfProcessor (&NumberOfCpus, &NumberOfEnabledProcessors); + AcpiCpuData->NumberOfCpus = (UINT32)NumberOfCpus; + } + + if (AcpiCpuData->RegisterTable == 0 || + AcpiCpuData->PreSmmInitRegisterTable == 0) { + // + // Allocate buffer for empty RegisterTable and PreSmmInitRegisterTable for all CPUs + // + NumberOfCpus = AcpiCpuData->NumberOfCpus; + TableSize = 2 * NumberOfCpus * sizeof (CPU_REGISTER_TABLE); + RegisterTable = AllocatePages (EFI_SIZE_TO_PAGES (TableSize)); + ASSERT (RegisterTable != NULL); + + for (Index = 0; Index < NumberOfCpus; Index++) { + Status = GetProcessorInformation (Index, &ProcessorInfoBuffer); + ASSERT_EFI_ERROR (Status); + + RegisterTable[Index].InitialApicId = (UINT32)ProcessorInfoBuffer.ProcessorId; + RegisterTable[Index].TableLength = 0; + RegisterTable[Index].AllocatedSize = 0; + RegisterTable[Index].RegisterTableEntry = 0; + + RegisterTable[NumberOfCpus + Index].InitialApicId = (UINT32)ProcessorInfoBuffer.ProcessorId; + RegisterTable[NumberOfCpus + Index].TableLength = 0; + RegisterTable[NumberOfCpus + Index].AllocatedSize = 0; + RegisterTable[NumberOfCpus + Index].RegisterTableEntry = 0; + } + if (AcpiCpuData->RegisterTable == 0) { + AcpiCpuData->RegisterTable = (EFI_PHYSICAL_ADDRESS)(UINTN)RegisterTable; + } + if (AcpiCpuData->PreSmmInitRegisterTable == 0) { + AcpiCpuData->PreSmmInitRegisterTable = (EFI_PHYSICAL_ADDRESS)(UINTN)(RegisterTable + NumberOfCpus); + } + } + + return AcpiCpuData; +} + +/** + Enlarges CPU register table for each processor. + + @param[in, out] RegisterTable Pointer processor's CPU register table +**/ +STATIC +VOID +EnlargeRegisterTable ( + IN OUT CPU_REGISTER_TABLE *RegisterTable + ) +{ + EFI_PHYSICAL_ADDRESS Address; + UINTN UsedPages; + + UsedPages = RegisterTable->AllocatedSize / EFI_PAGE_SIZE; + Address = (UINTN)AllocatePages (UsedPages + 1); + ASSERT (Address != 0); + + // + // If there are records existing in the register table, then copy its contents + // to new region and free the old one. + // + if (RegisterTable->AllocatedSize > 0) { + CopyMem ( + (VOID *) (UINTN) Address, + (VOID *) (UINTN) RegisterTable->RegisterTableEntry, + RegisterTable->AllocatedSize + ); + + FreePages ((VOID *)(UINTN)RegisterTable->RegisterTableEntry, UsedPages); + } + + // + // Adjust the allocated size and register table base address. + // + RegisterTable->AllocatedSize += EFI_PAGE_SIZE; + RegisterTable->RegisterTableEntry = Address; +} + +/** + Add an entry in specified register table. + + This function adds an entry in specified register table, with given register type, + register index, bit section and value. + + @param[in] PreSmmFlag If TRUE, entry will be added into PreSmm register table + If FALSE, entry will be added into register table + @param[in] ProcessorNumber The index of the CPU to add a register table entry + @param[in] RegisterType Type of the register to program + @param[in] Index Index of the register to program + @param[in] ValidBitStart Start of the bit section + @param[in] ValidBitLength Length of the bit section + @param[in] Value Value to write + @param[in] TestThenWrite Whether need to test current Value before writing. + +**/ +VOID +CpuRegisterTableWriteWorker ( + IN BOOLEAN PreSmmFlag, + IN UINTN ProcessorNumber, + IN REGISTER_TYPE RegisterType, + IN UINT64 Index, + IN UINT8 ValidBitStart, + IN UINT8 ValidBitLength, + IN UINT64 Value, + IN BOOLEAN TestThenWrite + ) +{ + CPU_FEATURES_DATA *CpuFeaturesData; + ACPI_CPU_DATA *AcpiCpuData; + CPU_REGISTER_TABLE *RegisterTable; + CPU_REGISTER_TABLE_ENTRY *RegisterTableEntry; + + CpuFeaturesData = GetCpuFeaturesData (); + if (CpuFeaturesData->RegisterTable == NULL) { + AcpiCpuData = GetAcpiCpuData (); + ASSERT ((AcpiCpuData != NULL) && (AcpiCpuData->RegisterTable != 0)); + CpuFeaturesData->RegisterTable = (CPU_REGISTER_TABLE *) (UINTN) AcpiCpuData->RegisterTable; + CpuFeaturesData->PreSmmRegisterTable = (CPU_REGISTER_TABLE *) (UINTN) AcpiCpuData->PreSmmInitRegisterTable; + } + + if (PreSmmFlag) { + RegisterTable = &CpuFeaturesData->PreSmmRegisterTable[ProcessorNumber]; + } else { + RegisterTable = &CpuFeaturesData->RegisterTable[ProcessorNumber]; + } + + if (RegisterTable->TableLength == RegisterTable->AllocatedSize / sizeof (CPU_REGISTER_TABLE_ENTRY)) { + EnlargeRegisterTable (RegisterTable); + } + + // + // Append entry in the register table. + // + RegisterTableEntry = (CPU_REGISTER_TABLE_ENTRY *) (UINTN) RegisterTable->RegisterTableEntry; + RegisterTableEntry[RegisterTable->TableLength].RegisterType = RegisterType; + RegisterTableEntry[RegisterTable->TableLength].Index = (UINT32) Index; + RegisterTableEntry[RegisterTable->TableLength].HighIndex = (UINT32) RShiftU64 (Index, 32); + RegisterTableEntry[RegisterTable->TableLength].ValidBitStart = ValidBitStart; + RegisterTableEntry[RegisterTable->TableLength].ValidBitLength = ValidBitLength; + RegisterTableEntry[RegisterTable->TableLength].Value = Value; + RegisterTableEntry[RegisterTable->TableLength].TestThenWrite = TestThenWrite; + + RegisterTable->TableLength++; +} + +/** + Adds an entry in specified register table. + + This function adds an entry in specified register table, with given register type, + register index, bit section and value. + + @param[in] ProcessorNumber The index of the CPU to add a register table entry + @param[in] RegisterType Type of the register to program + @param[in] Index Index of the register to program + @param[in] ValueMask Mask of bits in register to write + @param[in] Value Value to write + + @note This service could be called by BSP only. +**/ +VOID +EFIAPI +CpuRegisterTableWrite ( + IN UINTN ProcessorNumber, + IN REGISTER_TYPE RegisterType, + IN UINT64 Index, + IN UINT64 ValueMask, + IN UINT64 Value + ) +{ + UINT8 Start; + UINT8 End; + UINT8 Length; + + Start = (UINT8)LowBitSet64 (ValueMask); + End = (UINT8)HighBitSet64 (ValueMask); + Length = End - Start + 1; + CpuRegisterTableWriteWorker (FALSE, ProcessorNumber, RegisterType, Index, Start, Length, Value, FALSE); +} + +/** + Adds an entry in specified register table. + + This function adds an entry in specified register table, with given register type, + register index, bit section and value. + + @param[in] ProcessorNumber The index of the CPU to add a register table entry + @param[in] RegisterType Type of the register to program + @param[in] Index Index of the register to program + @param[in] ValueMask Mask of bits in register to write + @param[in] Value Value to write + + @note This service could be called by BSP only. +**/ +VOID +EFIAPI +CpuRegisterTableTestThenWrite ( + IN UINTN ProcessorNumber, + IN REGISTER_TYPE RegisterType, + IN UINT64 Index, + IN UINT64 ValueMask, + IN UINT64 Value + ) +{ + UINT8 Start; + UINT8 End; + UINT8 Length; + + Start = (UINT8)LowBitSet64 (ValueMask); + End = (UINT8)HighBitSet64 (ValueMask); + Length = End - Start + 1; + CpuRegisterTableWriteWorker (FALSE, ProcessorNumber, RegisterType, Index, Start, Length, Value, TRUE); +} + +/** + Adds an entry in specified Pre-SMM register table. + + This function adds an entry in specified register table, with given register type, + register index, bit section and value. + + @param[in] ProcessorNumber The index of the CPU to add a register table entry. + @param[in] RegisterType Type of the register to program + @param[in] Index Index of the register to program + @param[in] ValueMask Mask of bits in register to write + @param[in] Value Value to write + + @note This service could be called by BSP only. +**/ +VOID +EFIAPI +PreSmmCpuRegisterTableWrite ( + IN UINTN ProcessorNumber, + IN REGISTER_TYPE RegisterType, + IN UINT64 Index, + IN UINT64 ValueMask, + IN UINT64 Value + ) +{ + UINT8 Start; + UINT8 End; + UINT8 Length; + + Start = (UINT8)LowBitSet64 (ValueMask); + End = (UINT8)HighBitSet64 (ValueMask); + Length = End - Start + 1; + CpuRegisterTableWriteWorker (TRUE, ProcessorNumber, RegisterType, Index, Start, Length, Value, FALSE); +} + +/** + Worker function to determine if a CPU feature is set in input CPU feature bit mask buffer. + + @param[in] CpuBitMask CPU feature bit mask buffer + @param[in] CpuBitMaskSize The size of CPU feature bit mask buffer + @param[in] Feature The bit number of the CPU feature + + @retval TRUE The CPU feature is set in CpuBitMask. + @retval FALSE The CPU feature is not set in CpuBitMask. + +**/ +BOOLEAN +IsCpuFeatureSetInCpuPcd ( + IN UINT8 *CpuBitMask, + IN UINTN CpuBitMaskSize, + IN UINT32 Feature + ) +{ + if ((Feature >> 3) >= CpuBitMaskSize) { + return FALSE; + } + return ((*(CpuBitMask + (Feature >> 3)) & (1 << (Feature & 0x07))) != 0); +} + +/** + Determines if a CPU feature is enabled in PcdCpuFeaturesSupport bit mask. + If a CPU feature is disabled in PcdCpuFeaturesSupport then all the code/data + associated with that feature should be optimized away if compiler + optimizations are enabled. + + @param[in] Feature The bit number of the CPU feature to check in the PCD + PcdCpuFeaturesSupport + + @retval TRUE The CPU feature is set in PcdCpuFeaturesSupport. + @retval FALSE The CPU feature is not set in PcdCpuFeaturesSupport. + + @note This service could be called by BSP only. +**/ +BOOLEAN +EFIAPI +IsCpuFeatureSupported ( + IN UINT32 Feature + ) +{ + return IsCpuFeatureSetInCpuPcd ( + (UINT8 *)PcdGetPtr (PcdCpuFeaturesSupport), + PcdGetSize (PcdCpuFeaturesSupport), + Feature + ); +} + +/** + Determines if a CPU feature is set in PcdCpuFeaturesSetting bit mask. + + @param[in] Feature The bit number of the CPU feature to check in the PCD + PcdCpuFeaturesSetting + + @retval TRUE The CPU feature is set in PcdCpuFeaturesSetting. + @retval FALSE The CPU feature is not set in PcdCpuFeaturesSetting. + + @note This service could be called by BSP only. +**/ +BOOLEAN +EFIAPI +IsCpuFeatureInSetting ( + IN UINT32 Feature + ) +{ + return IsCpuFeatureSetInCpuPcd ( + (UINT8 *)PcdGetPtr (PcdCpuFeaturesSetting), + PcdGetSize (PcdCpuFeaturesSetting), + Feature + ); +} + +/** + Switches to assigned BSP after CPU features initialization. + + @param[in] ProcessorNumber The index of the CPU executing this function. + + @note This service could be called by BSP only. +**/ +VOID +EFIAPI +SwitchBspAfterFeaturesInitialize ( + IN UINTN ProcessorNumber + ) +{ + CPU_FEATURES_DATA *CpuFeaturesData; + + CpuFeaturesData = GetCpuFeaturesData (); + CpuFeaturesData->BspNumber = ProcessorNumber; +} + |