| /** @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->CpuFeatureInitData.RegisterTable == 0) || | |
| (AcpiCpuData->CpuFeatureInitData.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->CpuFeatureInitData.RegisterTable == 0) { | |
| AcpiCpuData->CpuFeatureInitData.RegisterTable = (EFI_PHYSICAL_ADDRESS)(UINTN)RegisterTable; | |
| } | |
| if (AcpiCpuData->CpuFeatureInitData.PreSmmInitRegisterTable == 0) { | |
| AcpiCpuData->CpuFeatureInitData.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->CpuFeatureInitData.RegisterTable != 0)); | |
| CpuFeaturesData->RegisterTable = (CPU_REGISTER_TABLE *)(UINTN)AcpiCpuData->CpuFeatureInitData.RegisterTable; | |
| CpuFeaturesData->PreSmmRegisterTable = (CPU_REGISTER_TABLE *)(UINTN)AcpiCpuData->CpuFeatureInitData.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; | |
| } |