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