From nobody Sat Nov 2 14:36:54 2024 Delivered-To: importer@patchew.org Received-SPF: none (zoho.com: 198.145.21.10 is neither permitted nor denied by domain of lists.01.org) client-ip=198.145.21.10; envelope-from=edk2-devel-bounces@lists.01.org; helo=ml01.01.org; Authentication-Results: mx.zoho.com; spf=none (zoho.com: 198.145.21.10 is neither permitted nor denied by domain of lists.01.org) smtp.mailfrom=edk2-devel-bounces@lists.01.org; Return-Path: Received: from ml01.01.org (ml01.01.org [198.145.21.10]) by mx.zohomail.com with SMTPS id 1489545931627388.44719133349133; Tue, 14 Mar 2017 19:45:31 -0700 (PDT) Received: from [127.0.0.1] (localhost [IPv6:::1]) by ml01.01.org (Postfix) with ESMTP id 63359803F3; Tue, 14 Mar 2017 19:45:30 -0700 (PDT) Received: from mga03.intel.com (mga03.intel.com [134.134.136.65]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by ml01.01.org (Postfix) with ESMTPS id 34CB3803EF for ; Tue, 14 Mar 2017 19:45:29 -0700 (PDT) Received: from orsmga002.jf.intel.com ([10.7.209.21]) by orsmga103.jf.intel.com with ESMTP/TLS/DHE-RSA-AES256-GCM-SHA384; 14 Mar 2017 19:45:29 -0700 Received: from jfan12-desk.ccr.corp.intel.com ([10.239.158.57]) by orsmga002.jf.intel.com with ESMTP; 14 Mar 2017 19:45:27 -0700 X-Original-To: edk2-devel@lists.01.org DKIM-Signature: v=1; a=rsa-sha256; c=simple/simple; d=intel.com; i=@intel.com; q=dns/txt; s=intel; t=1489545929; x=1521081929; h=from:to:cc:subject:date:message-id:in-reply-to: references; bh=jQ/LsLWQK2UxcS7STs858Q5HKPfbAlNLW56vE/VZuWE=; b=gF+LXNogJrAC1GO24ibXCSaxG/k4pPykeIMu6TNw+sY+geiMOmut+Mwp ekL/tvs1a5mE4Pr6aoiVSZCTePjboQ==; X-ExtLoop1: 1 X-IronPort-AV: E=Sophos;i="5.36,167,1486454400"; d="scan'208";a="60473975" From: Jeff Fan To: edk2-devel@lists.01.org Date: Wed, 15 Mar 2017 10:45:16 +0800 Message-Id: <20170315024517.9776-2-jeff.fan@intel.com> X-Mailer: git-send-email 2.9.3.windows.2 In-Reply-To: <20170315024517.9776-1-jeff.fan@intel.com> References: <20170315024517.9776-1-jeff.fan@intel.com> Subject: [edk2] [PATCH v2 09/11] UefiCpuPkg: Add PEI/DXE Register CPU Features Library instances X-BeenThere: edk2-devel@lists.01.org X-Mailman-Version: 2.1.21 Precedence: list List-Id: EDK II Development List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: Michael Kinney , Feng Tian MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Errors-To: edk2-devel-bounces@lists.01.org Sender: "edk2-devel" X-ZohoMail: RSF_4 Z_629925259 SPT_0 Content-Type: text/plain; charset="utf-8" PEI Register CPU Features Library instance is used to register/manager/prog= ram CPU features on PEI phase. DXE Register CPU Features Library instance is used to register/manager/prog= ram CPU features on DXE phase. v2: Format debug messages. Cc: Feng Tian Cc: Michael Kinney Contributed-under: TianoCore Contribution Agreement 1.0 Signed-off-by: Jeff Fan --- .../RegisterCpuFeaturesLib/CpuFeaturesInitialize.c | 747 +++++++++++++++++= +++ .../DxeRegisterCpuFeaturesLib.c | 266 +++++++ .../DxeRegisterCpuFeaturesLib.inf | 62 ++ .../PeiRegisterCpuFeaturesLib.c | 390 +++++++++++ .../PeiRegisterCpuFeaturesLib.inf | 64 ++ .../RegisterCpuFeaturesLib/RegisterCpuFeatures.h | 193 ++++++ .../RegisterCpuFeaturesDxe.uni | 22 + .../RegisterCpuFeaturesLib.c | 770 +++++++++++++++++= ++++ UefiCpuPkg/UefiCpuPkg.dsc | 6 +- 9 files changed, 2519 insertions(+), 1 deletion(-) create mode 100644 UefiCpuPkg/Library/RegisterCpuFeaturesLib/CpuFeaturesIn= itialize.c create mode 100644 UefiCpuPkg/Library/RegisterCpuFeaturesLib/DxeRegisterCp= uFeaturesLib.c create mode 100644 UefiCpuPkg/Library/RegisterCpuFeaturesLib/DxeRegisterCp= uFeaturesLib.inf create mode 100644 UefiCpuPkg/Library/RegisterCpuFeaturesLib/PeiRegisterCp= uFeaturesLib.c create mode 100644 UefiCpuPkg/Library/RegisterCpuFeaturesLib/PeiRegisterCp= uFeaturesLib.inf create mode 100644 UefiCpuPkg/Library/RegisterCpuFeaturesLib/RegisterCpuFe= atures.h create mode 100644 UefiCpuPkg/Library/RegisterCpuFeaturesLib/RegisterCpuFe= aturesDxe.uni create mode 100644 UefiCpuPkg/Library/RegisterCpuFeaturesLib/RegisterCpuFe= aturesLib.c diff --git a/UefiCpuPkg/Library/RegisterCpuFeaturesLib/CpuFeaturesInitializ= e.c b/UefiCpuPkg/Library/RegisterCpuFeaturesLib/CpuFeaturesInitialize.c new file mode 100644 index 0000000..d201239 --- /dev/null +++ b/UefiCpuPkg/Library/RegisterCpuFeaturesLib/CpuFeaturesInitialize.c @@ -0,0 +1,747 @@ +/** @file + CPU Features Initialize functions. + + Copyright (c) 2017, Intel Corporation. All rights reserved.
+ This program and the accompanying materials + are licensed and made available under the terms and conditions of the BS= D License + which accompanies this distribution. The full text of the license may b= e 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 IMP= LIED. + +**/ + +#include "RegisterCpuFeatures.h" + +/** + Worker function to save PcdCpuFeaturesCapability.=20 + =20 + @param[in] SupportedFeatureMask The pointer to CPU feature bits mask b= uffer +*/ +VOID +SetCapabilityPcd ( + IN UINT8 *SupportedFeatureMask + ) +{=20 + EFI_STATUS Status; + UINTN BitMaskSize; + =20 + BitMaskSize =3D PcdGetSize (PcdCpuFeaturesCapability); + Status =3D PcdSetPtrS (PcdCpuFeaturesCapability, &BitMaskSize, Supported= FeatureMask); + ASSERT_EFI_ERROR (Status); +} + +/** + Worker function to save PcdCpuFeaturesSetting.=20 + =20 + @param[in] SupportedFeatureMask The pointer to CPU feature bits mask b= uffer +**/ +VOID +SetSettingPcd ( + IN UINT8 *SupportedFeatureMask + ) +{=20 + EFI_STATUS Status; + UINTN BitMaskSize; + =20 + BitMaskSize =3D PcdGetSize (PcdCpuFeaturesSetting); + Status =3D PcdSetPtrS (PcdCpuFeaturesSetting, &BitMaskSize, SupportedFea= tureMask); + ASSERT_EFI_ERROR (Status); +} + +/** + Worker function to get PcdCpuFeaturesSupport.=20 + =20 + @return The pointer to CPU feature bits mask buffer. +**/ +UINT8 * +GetSupportPcds ( + VOID + ) +{ + UINTN BitMaskSize; + UINT8 *SupportBitMask; + =20 + BitMaskSize =3D PcdGetSize (PcdCpuFeaturesSupport); + SupportBitMask =3D AllocateZeroPool (BitMaskSize); + SupportBitMask =3D (UINT8 *) PcdGetPtr (PcdCpuFeaturesSupport); + + return SupportBitMask; +} + +/** + Worker function to get PcdCpuFeaturesUserConfiguration.=20 + =20 + @return The pointer to CPU feature bits mask buffer. +**/ +UINT8 * +GetConfigurationPcds ( + VOID + ) +{ + UINTN BitMaskSize; + UINT8 *SupportBitMask; + =20 + BitMaskSize =3D PcdGetSize (PcdCpuFeaturesUserConfiguration); + SupportBitMask =3D AllocateZeroPool (BitMaskSize); + SupportBitMask =3D (UINT8 *) PcdGetPtr (PcdCpuFeaturesUserConfiguration); + + return SupportBitMask; +} + +/** + Collects CPU type and feature information. + + @param[in, out] CpuInfo The pointer to CPU feature information +**/ +VOID +FillProcessorInfo ( + IN OUT REGISTER_CPU_FEATURE_INFORMATION *CpuInfo + ) +{ + CPUID_VERSION_INFO_EAX Eax; + CPUID_VERSION_INFO_ECX Ecx; + CPUID_VERSION_INFO_EDX Edx; + UINT32 DisplayedFamily; + UINT32 DisplayedModel; + + AsmCpuid (CPUID_VERSION_INFO, &Eax.Uint32, NULL, &Ecx.Uint32, &Edx.Uint3= 2); + + DisplayedFamily =3D Eax.Bits.FamilyId; + if (Eax.Bits.FamilyId =3D=3D 0x0F) { + DisplayedFamily |=3D (Eax.Bits.ExtendedFamilyId << 4); + } + + DisplayedModel =3D Eax.Bits.Model; + if (Eax.Bits.FamilyId =3D=3D 0x06 || Eax.Bits.FamilyId =3D=3D 0x0f) { + DisplayedModel |=3D (Eax.Bits.ExtendedModelId << 4); + } + + CpuInfo->DisplayFamily =3D DisplayedFamily; + CpuInfo->DisplayModel =3D DisplayedModel; + CpuInfo->SteppingId =3D Eax.Bits.SteppingId; + CpuInfo->ProcessorType =3D Eax.Bits.ProcessorType; + CpuInfo->CpuIdVersionInfoEcx.Uint32 =3D Ecx.Uint32; + CpuInfo->CpuIdVersionInfoEdx.Uint32 =3D Edx.Uint32; +} + +/** + Prepares for private data used for CPU features. + + @param[in] NumberOfCpus Number of processor in system +**/ +VOID +CpuInitDataInitialize ( + IN UINTN NumberOfCpus + ) +{ + EFI_STATUS Status; + UINTN ProcessorNumber; + EFI_PROCESSOR_INFORMATION ProcessorInfoBuffer; + UINTN Index; + CPU_FEATURES_ENTRY *CpuFeature; + CPU_FEATURES_INIT_ORDER *InitOrder; + CPU_FEATURES_DATA *CpuFeaturesData; + LIST_ENTRY *Entry; + + CpuFeaturesData =3D GetCpuFeaturesData (); + CpuFeaturesData->InitOrder =3D AllocateZeroPool (sizeof (CPU_FEATURES_IN= IT_ORDER) * NumberOfCpus); + ASSERT (CpuFeaturesData->InitOrder !=3D NULL); + CpuFeaturesData->BitMaskSize =3D PcdGetSize (PcdCpuFeaturesSupport); + + // + // Collect CPU Features information + // + Entry =3D GetFirstNode (&CpuFeaturesData->FeatureList); + Index =3D 0; + while (!IsNull (&CpuFeaturesData->FeatureList, Entry)) { + CpuFeature =3D CPU_FEATURE_ENTRY_FROM_LINK (Entry); + ASSERT (CpuFeature->InitializeFunc !=3D NULL); + if (CpuFeature->GetConfigDataFunc !=3D NULL) { + CpuFeature->ConfigData =3D CpuFeature->GetConfigDataFunc (NumberOfCp= us); + } + Entry =3D Entry->ForwardLink; + } + + for (ProcessorNumber =3D 0; ProcessorNumber < NumberOfCpus; ProcessorNum= ber++) { + InitOrder =3D &CpuFeaturesData->InitOrder[ProcessorNumber]; + InitOrder->FeaturesSupportedMask =3D AllocateZeroPool (CpuFeaturesData= ->BitMaskSize); + InitializeListHead (&InitOrder->OrderList); + Status =3D GetProcessorInformation (ProcessorNumber, &ProcessorInfoBuf= fer); + ASSERT_EFI_ERROR (Status); + CopyMem ( + &InitOrder->CpuInfo.ProcessorInfo, + &ProcessorInfoBuffer, + sizeof (EFI_PROCESSOR_INFORMATION) + ); + } + // + // Get support and configuration PCDs + // + CpuFeaturesData->SupportPcds =3D GetSupportPcds (); + CpuFeaturesData->ConfigurationPcds =3D GetConfigurationPcds (); +} + +/** + Worker function to do OR operation on CPU feature supported bits mask bu= ffer. + =20 + @param[in] SupportedFeatureMask The pointer to CPU feature bits mask b= uffer + @param[in] OrFeatureBitMask The feature bit mask to do OR operation +**/ +VOID +SupportedMaskOr ( + IN UINT8 *SupportedFeatureMask, + IN UINT8 *OrFeatureBitMask + ) +{ + UINTN Index; + UINTN BitMaskSize; + UINT8 *Data1; + UINT8 *Data2; + =20 + BitMaskSize =3D PcdGetSize (PcdCpuFeaturesSupport); + Data1 =3D SupportedFeatureMask; + Data2 =3D OrFeatureBitMask; + for (Index =3D 0; Index < BitMaskSize; Index++) { + *(Data1++) |=3D *(Data2++); + } +} + +/** + Worker function to do AND operation on CPU feature supported bits mask b= uffer. + =20 + @param[in] SupportedFeatureMask The pointer to CPU feature bits mask b= uffer + @param[in] AndFeatureBitMask The feature bit mask to do AND operati= on +**/ +VOID +SupportedMaskAnd ( + IN UINT8 *SupportedFeatureMask, + IN UINT8 *AndFeatureBitMask + ) +{ + UINTN Index; + UINTN BitMaskSize; + UINT8 *Data1; + UINT8 *Data2; + =20 + BitMaskSize =3D PcdGetSize (PcdCpuFeaturesSupport); + Data1 =3D SupportedFeatureMask; + Data2 =3D AndFeatureBitMask; + for (Index =3D 0; Index < BitMaskSize; Index++) { + *(Data1++) &=3D *(Data2++); + } +} + +/** + Worker function to check if the compared CPU feature set in the CPU feat= ure + supported bits mask buffer. + =20 + @param[in] SupportedFeatureMask The pointer to CPU feature bits mask = buffer + @param[in] ComparedFeatureBitMask The feature bit mask to be compared + + @retval TRUE The ComparedFeatureBitMask is set in CPU feature supporte= d bits + mask buffer. + @retval FALSE The ComparedFeatureBitMask is not set in CPU feature supp= orted bits + mask buffer. +**/ +BOOLEAN +IsBitMaskMatch ( + IN UINT8 *SupportedFeatureMask, + IN UINT8 *ComparedFeatureBitMask + ) +{ + UINTN Index; + UINTN BitMaskSize; + UINT8 *Data1; + UINT8 *Data2; + =20 + BitMaskSize =3D PcdGetSize (PcdCpuFeaturesSupport); + + Data1 =3D SupportedFeatureMask; + Data2 =3D ComparedFeatureBitMask; + for (Index =3D 0; Index < BitMaskSize; Index++) { + if (((*(Data1++)) & (*(Data2++))) !=3D 0) { + return TRUE; + } + } + return FALSE; +} + +/** + Collects processor data for calling processor. + + @param[in,out] Buffer The pointer to private data buffer. +**/ +VOID +EFIAPI +CollectProcessorData ( + IN OUT VOID *Buffer + ) +{ + UINTN ProcessorNumber; + CPU_FEATURES_ENTRY *CpuFeature; + REGISTER_CPU_FEATURE_INFORMATION *CpuInfo; + LIST_ENTRY *Entry; + CPU_FEATURES_DATA *CpuFeaturesData; + + CpuFeaturesData =3D GetCpuFeaturesData (); + ProcessorNumber =3D GetProcessorIndex (); + CpuInfo =3D &CpuFeaturesData->InitOrder[ProcessorNumber].CpuInfo; + // + // collect processor information + // + FillProcessorInfo (CpuInfo); + Entry =3D GetFirstNode (&CpuFeaturesData->FeatureList); + while (!IsNull (&CpuFeaturesData->FeatureList, Entry)) { + CpuFeature =3D CPU_FEATURE_ENTRY_FROM_LINK (Entry); + if (IsBitMaskMatch (CpuFeaturesData->SupportPcds, CpuFeature->FeatureM= ask)) { =20 + if (CpuFeature->SupportFunc =3D=3D NULL) { + // + // If SupportFunc is NULL, then the feature is supported. + // + SupportedMaskOr ( + CpuFeaturesData->InitOrder[ProcessorNumber].FeaturesSupportedMas= k, + CpuFeature->FeatureMask + ); + } else if (CpuFeature->SupportFunc (ProcessorNumber, CpuInfo, CpuFea= ture->ConfigData)) { + SupportedMaskOr ( + CpuFeaturesData->InitOrder[ProcessorNumber].FeaturesSupportedMas= k, + CpuFeature->FeatureMask + ); + } + } + Entry =3D Entry->ForwardLink;=20 + } +} + +/** + Dump the contents of a CPU register table. + + @param[in] ProcessorNumber The index of the CPU to show the register t= able contents + + @note This service could be called by BSP only. +**/ +VOID +DumpRegisterTableOnProcessor ( + IN UINTN ProcessorNumber + ) +{ + CPU_FEATURES_DATA *CpuFeaturesData; + UINTN FeatureIndex; + CPU_REGISTER_TABLE *RegisterTable; + CPU_REGISTER_TABLE_ENTRY *RegisterTableEntry; + CPU_REGISTER_TABLE_ENTRY *RegisterTableEntryHead; + UINT32 DebugPrintErrorLevel; + =20 + DebugPrintErrorLevel =3D (ProcessorNumber =3D=3D 0) ? DEBUG_INFO : DEBUG= _VERBOSE; + CpuFeaturesData =3D GetCpuFeaturesData (); + // + // Debug information + // + RegisterTable =3D &CpuFeaturesData->RegisterTable[ProcessorNumber]; + DEBUG ((DebugPrintErrorLevel, "RegisterTable->TableLength =3D %d\n", Reg= isterTable->TableLength)); + + RegisterTableEntryHead =3D (CPU_REGISTER_TABLE_ENTRY *) (UINTN) Register= Table->RegisterTableEntry; + + for (FeatureIndex =3D 0; FeatureIndex < RegisterTable->TableLength; Feat= ureIndex++) { + RegisterTableEntry =3D &RegisterTableEntryHead[FeatureIndex]; + switch (RegisterTableEntry->RegisterType) { + case Msr: + DEBUG (( + DebugPrintErrorLevel, + "Processor: %d: MSR: %x, Bit Start: %d, Bit Length: %d, Value: %= lx\r\n", + ProcessorNumber, + RegisterTableEntry->Index, + RegisterTableEntry->ValidBitStart, + RegisterTableEntry->ValidBitLength, + RegisterTableEntry->Value + )); + break; + case ControlRegister: + DEBUG (( + DebugPrintErrorLevel, + "Processor: %d: CR: %x, Bit Start: %d, Bit Length: %d, Value: %= lx\r\n", + ProcessorNumber, + RegisterTableEntry->Index, + RegisterTableEntry->ValidBitStart, + RegisterTableEntry->ValidBitLength, + RegisterTableEntry->Value + )); + break; + case MemoryMapped: + DEBUG (( + DebugPrintErrorLevel, + "Processor: %d: MMIO: %x, Bit Start: %d, Bit Length: %d, Value: %= lx\r\n", + ProcessorNumber, + RegisterTableEntry->Index, + RegisterTableEntry->ValidBitStart, + RegisterTableEntry->ValidBitLength, + RegisterTableEntry->Value + )); + break; + case CacheControl: + DEBUG (( + DebugPrintErrorLevel, + "Processor: %d: CACHE: %x, Bit Start: %d, Bit Length: %d, Value: %= lx\r\n", + ProcessorNumber, + RegisterTableEntry->Index, + RegisterTableEntry->ValidBitStart, + RegisterTableEntry->ValidBitLength, + RegisterTableEntry->Value + )); + break; + default: + break; + } =20 + } +} + +/** + Analysis register CPU features on each processor and save CPU setting in= CPU register table. + + @param[in] NumberOfCpus Number of processor in system + +**/ +VOID +AnalysisProcessorFeatures ( + IN UINTN NumberOfCpus + ) +{ + EFI_STATUS Status; + UINTN ProcessorNumber; + CPU_FEATURES_ENTRY *CpuFeature; + CPU_FEATURES_ENTRY *CpuFeatureInOrder; + CPU_FEATURES_INIT_ORDER *CpuInitOrder; + REGISTER_CPU_FEATURE_INFORMATION *CpuInfo; + LIST_ENTRY *Entry; + CPU_FEATURES_DATA *CpuFeaturesData; + + CpuFeaturesData =3D GetCpuFeaturesData (); + CpuFeaturesData->CapabilityPcds =3D AllocatePool (CpuFeaturesData->BitMa= skSize); + SetMem (CpuFeaturesData->CapabilityPcds, CpuFeaturesData->BitMaskSize, 0= xFF); + for (ProcessorNumber =3D 0; ProcessorNumber < NumberOfCpus; ProcessorNum= ber++) { + CpuInitOrder =3D &CpuFeaturesData->InitOrder[ProcessorNumber]; + // + // Calculate the last capability on all processors + // + SupportedMaskAnd (CpuFeaturesData->CapabilityPcds, CpuInitOrder->Featu= resSupportedMask); + } + // + // Calculate the last setting + // + + CpuFeaturesData->SettingPcds =3D AllocateCopyPool (CpuFeaturesData->BitM= askSize, CpuFeaturesData->CapabilityPcds); + SupportedMaskAnd (CpuFeaturesData->SettingPcds, CpuFeaturesData->Configu= rationPcds); + + // + // Save PCDs and display CPU PCDs + // + SetCapabilityPcd (CpuFeaturesData->CapabilityPcds); + SetSettingPcd (CpuFeaturesData->SettingPcds); + + // + // Dump the last CPU feature list + // + DEBUG_CODE ( + DEBUG ((DEBUG_INFO, "Last CPU features list...\n")); + Entry =3D GetFirstNode (&CpuFeaturesData->FeatureList); + while (!IsNull (&CpuFeaturesData->FeatureList, Entry)) { + CpuFeature =3D CPU_FEATURE_ENTRY_FROM_LINK (Entry); + if (IsBitMaskMatch (CpuFeature->FeatureMask, CpuFeaturesData->Capabi= lityPcds)) { + if (IsBitMaskMatch (CpuFeature->FeatureMask, CpuFeaturesData->Sett= ingPcds)) { + DEBUG ((DEBUG_INFO, "[Enable ] ")); + } else { + DEBUG ((DEBUG_INFO, "[Disable ] ")); + } + } else { + DEBUG ((DEBUG_INFO, "[Unsupport] ")); + } + DumpCpuFeature (CpuFeature); + Entry =3D Entry->ForwardLink; + } + DEBUG ((DEBUG_INFO, "PcdCpuFeaturesSupport:\n")); + DumpCpuFeatureMask (CpuFeaturesData->SupportPcds); + DEBUG ((DEBUG_INFO, "PcdCpuFeaturesUserConfiguration:\n")); + DumpCpuFeatureMask (CpuFeaturesData->ConfigurationPcds); + DEBUG ((DEBUG_INFO, "PcdCpuFeaturesCapability:\n")); + DumpCpuFeatureMask (CpuFeaturesData->CapabilityPcds); + DEBUG ((DEBUG_INFO, "PcdCpuFeaturesSetting:\n")); + DumpCpuFeatureMask (CpuFeaturesData->SettingPcds); + ); + + for (ProcessorNumber =3D 0; ProcessorNumber < NumberOfCpus; ProcessorNum= ber++) { + CpuInitOrder =3D &CpuFeaturesData->InitOrder[ProcessorNumber]; + Entry =3D GetFirstNode (&CpuFeaturesData->FeatureList); + while (!IsNull (&CpuFeaturesData->FeatureList, Entry)) { + // + // Insert each feature into processor's order list + // + CpuFeature =3D CPU_FEATURE_ENTRY_FROM_LINK (Entry); + if (IsBitMaskMatch (CpuFeature->FeatureMask, CpuFeaturesData->Capabi= lityPcds)) { + CpuFeatureInOrder =3D AllocateCopyPool (sizeof (CPU_FEATURES_ENTRY= ), CpuFeature); + InsertTailList (&CpuInitOrder->OrderList, &CpuFeatureInOrder->Link= ); + } + Entry =3D Entry->ForwardLink;=20 + } + // + // Go through ordered feature list to initialize CPU features + // + CpuInfo =3D &CpuFeaturesData->InitOrder[ProcessorNumber].CpuInfo; + Entry =3D GetFirstNode (&CpuInitOrder->OrderList); + while (!IsNull (&CpuInitOrder->OrderList, Entry)) { + CpuFeatureInOrder =3D CPU_FEATURE_ENTRY_FROM_LINK (Entry); + if (IsBitMaskMatch (CpuFeatureInOrder->FeatureMask, CpuFeaturesData-= >SettingPcds)) { + Status =3D CpuFeatureInOrder->InitializeFunc (ProcessorNumber, Cpu= Info, CpuFeatureInOrder->ConfigData, TRUE); + } else { + Status =3D CpuFeatureInOrder->InitializeFunc (ProcessorNumber, Cpu= Info, CpuFeatureInOrder->ConfigData, FALSE); + } + ASSERT_EFI_ERROR (Status); + Entry =3D Entry->ForwardLink;=20 + } + // + // Dump the RegisterTable + // + DumpRegisterTableOnProcessor (ProcessorNumber); + } +} + +/** + Initialize the CPU registers from a register table. + + @param[in] ProcessorNumber The index of the CPU executing this functio= n. + + @note This service could be called by BSP/APs. +**/ +VOID +ProgramProcessorRegister ( + IN UINTN ProcessorNumber + ) +{ + CPU_FEATURES_DATA *CpuFeaturesData; + CPU_REGISTER_TABLE *RegisterTable; + CPU_REGISTER_TABLE_ENTRY *RegisterTableEntry; + UINTN Index; + UINTN Value; + CPU_REGISTER_TABLE_ENTRY *RegisterTableEntryHead; + + CpuFeaturesData =3D GetCpuFeaturesData (); + RegisterTable =3D &CpuFeaturesData->RegisterTable[ProcessorNumber]; + + // + // Traverse Register Table of this logical processor + // + RegisterTableEntryHead =3D (CPU_REGISTER_TABLE_ENTRY *) (UINTN) Register= Table->RegisterTableEntry; + + for (Index =3D 0; Index < RegisterTable->TableLength; Index++) { + + RegisterTableEntry =3D &RegisterTableEntryHead[Index]; + =20 + // + // Check the type of specified register + // + switch (RegisterTableEntry->RegisterType) { + // + // The specified register is Control Register + // + case ControlRegister: + switch (RegisterTableEntry->Index) { + case 0: + Value =3D AsmReadCr0 (); + Value =3D (UINTN) BitFieldWrite64 ( + Value, + RegisterTableEntry->ValidBitStart, + RegisterTableEntry->ValidBitStart + RegisterTabl= eEntry->ValidBitLength - 1, + RegisterTableEntry->Value + ); + AsmWriteCr0 (Value); + break; + case 2: + Value =3D AsmReadCr2 (); + Value =3D (UINTN) BitFieldWrite64 ( + Value, + RegisterTableEntry->ValidBitStart, + RegisterTableEntry->ValidBitStart + RegisterTabl= eEntry->ValidBitLength - 1, + RegisterTableEntry->Value + ); + AsmWriteCr2 (Value); + break; + case 3: + Value =3D AsmReadCr3 (); + Value =3D (UINTN) BitFieldWrite64 ( + Value, + RegisterTableEntry->ValidBitStart, + RegisterTableEntry->ValidBitStart + RegisterTabl= eEntry->ValidBitLength - 1, + RegisterTableEntry->Value + ); + AsmWriteCr3 (Value); + break; + case 4: + Value =3D AsmReadCr4 (); + Value =3D (UINTN) BitFieldWrite64 ( + Value, + RegisterTableEntry->ValidBitStart, + RegisterTableEntry->ValidBitStart + RegisterTabl= eEntry->ValidBitLength - 1, + RegisterTableEntry->Value + ); + AsmWriteCr4 (Value); + break; + case 8: + // + // Do we need to support CR8? + // + break; + default: + break; + } + break; + // + // The specified register is Model Specific Register + // + case Msr: + // + // Get lock to avoid Package/Core scope MSRs programming issue in pa= rallel execution mode + // + AcquireSpinLock (&CpuFeaturesData->MsrLock); + if (RegisterTableEntry->ValidBitLength >=3D 64) { + // + // If length is not less than 64 bits, then directly write without= reading + // + AsmWriteMsr64 ( + RegisterTableEntry->Index, + RegisterTableEntry->Value + ); + } else { + // + // Set the bit section according to bit start and length + // + AsmMsrBitFieldWrite64 ( + RegisterTableEntry->Index, + RegisterTableEntry->ValidBitStart, + RegisterTableEntry->ValidBitStart + RegisterTableEntry->ValidBit= Length - 1, + RegisterTableEntry->Value + ); + } + ReleaseSpinLock (&CpuFeaturesData->MsrLock); + break; + // + // MemoryMapped operations + // + case MemoryMapped: + AcquireSpinLock (&CpuFeaturesData->MemoryMappedLock); + MmioBitFieldWrite32 ( + RegisterTableEntry->Index, + RegisterTableEntry->ValidBitStart, + RegisterTableEntry->ValidBitStart + RegisterTableEntry->ValidBitLe= ngth - 1, + (UINT32)RegisterTableEntry->Value + ); + ReleaseSpinLock (&CpuFeaturesData->MemoryMappedLock); + break; + // + // Enable or disable cache + // + case CacheControl: + // + // If value of the entry is 0, then disable cache. Otherwise, enabl= e cache. + // + if (RegisterTableEntry->Value =3D=3D 0) { + AsmDisableCache (); + } else { + AsmEnableCache (); + } + break; + + default: + break; + } + } +} + +/** + Programs registers for the calling processor. + + @param[in,out] Buffer The pointer to private data buffer. + +**/ +VOID +EFIAPI +SetProcessorRegister ( + IN OUT VOID *Buffer + ) +{ + UINTN ProcessorNumber; + + ProcessorNumber =3D GetProcessorIndex (); + ProgramProcessorRegister (ProcessorNumber); +} + +/** + Performs CPU features detection. + + This service will invoke MP service to check CPU features' + capabilities on BSP/APs. + + @note This service could be called by BSP only. +**/ +VOID +EFIAPI +CpuFeaturesDetect ( + VOID + ) +{ + UINTN NumberOfCpus; + UINTN NumberOfEnabledProcessors; + + GetNumberOfProcessor (&NumberOfCpus, &NumberOfEnabledProcessors); + + CpuInitDataInitialize (NumberOfCpus); + + // + // Wakeup all APs for data collection. + // + StartupAPsWorker (CollectProcessorData); + + // + // Collect data on BSP + // + CollectProcessorData (NULL); + + AnalysisProcessorFeatures (NumberOfCpus); +} + +/** + Performs CPU features Initialization. + + This service will invoke MP service to perform CPU features + initialization on BSP/APs per user configuration. + + @note This service could be called by BSP only. +**/ +VOID +EFIAPI +CpuFeaturesInitialize ( + VOID + ) +{ + CPU_FEATURES_DATA *CpuFeaturesData; + UINTN OldBspNumber; + + CpuFeaturesData =3D GetCpuFeaturesData (); + + OldBspNumber =3D GetProcessorIndex(); + CpuFeaturesData->BspNumber =3D OldBspNumber; + // + // Wakeup all APs for programming. + // + StartupAPsWorker (SetProcessorRegister); + // + // Programming BSP + // + SetProcessorRegister (NULL); + // + // Switch to new BSP if required + // + if (CpuFeaturesData->BspNumber !=3D OldBspNumber) { + SwitchNewBsp (CpuFeaturesData->BspNumber); + } +} diff --git a/UefiCpuPkg/Library/RegisterCpuFeaturesLib/DxeRegisterCpuFeatur= esLib.c b/UefiCpuPkg/Library/RegisterCpuFeaturesLib/DxeRegisterCpuFeaturesL= ib.c new file mode 100644 index 0000000..0063551 --- /dev/null +++ b/UefiCpuPkg/Library/RegisterCpuFeaturesLib/DxeRegisterCpuFeaturesLib.c @@ -0,0 +1,266 @@ +/** @file + CPU Register Table Library functions. + + Copyright (c) 2017, Intel Corporation. All rights reserved.
+ This program and the accompanying materials + are licensed and made available under the terms and conditions of the BS= D License + which accompanies this distribution. The full text of the license may b= e 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 IMP= LIED. + +**/ + +#include + +#include + +#include "RegisterCpuFeatures.h" + +CPU_FEATURES_DATA mCpuFeaturesData =3D {0}; +static EFI_MP_SERVICES_PROTOCOL *mMpServices =3D NULL; + +/** + Worker function to get CPU_FEATURES_DATA pointer. + + @return Pointer to CPU_FEATURES_DATA. +**/ +CPU_FEATURES_DATA * +GetCpuFeaturesData ( + VOID + ) +{ + return &mCpuFeaturesData; +} + +/** + Worker function to get EFI_MP_SERVICES_PROTOCOL pointer. + + @return Pointer to EFI_MP_SERVICES_PROTOCOL. +**/ +EFI_MP_SERVICES_PROTOCOL * +GetMpProtocol ( + VOID + ) +{ + EFI_STATUS Status; + + if (mMpServices =3D=3D NULL) { + // + // Get MP Services Protocol + // + Status =3D gBS->LocateProtocol ( + &gEfiMpServiceProtocolGuid, + NULL, + (VOID **)&mMpServices + ); + ASSERT_EFI_ERROR (Status); + } + + ASSERT (mMpServices !=3D NULL); + return mMpServices; +} + +/** + Worker function to return processor index. + + @return The processor index. +**/ +UINTN +GetProcessorIndex ( + VOID + ) +{ + EFI_STATUS Status; + UINTN ProcessorIndex; + EFI_MP_SERVICES_PROTOCOL *MpServices; + =20 + MpServices =3D GetMpProtocol (); + Status =3D MpServices->WhoAmI(MpServices, &ProcessorIndex); + ASSERT_EFI_ERROR (Status); + return ProcessorIndex; +} + +/** + Gets detailed MP-related information on the requested processor at the + instant this call is made. + + @param[in] ProcessorNumber The handle number of processor. + @param[out] ProcessorInfoBuffer A pointer to the buffer where informat= ion for + the requested processor is deposited. + + @return Status of MpServices->GetProcessorInfo(). +**/ +EFI_STATUS +GetProcessorInformation ( + IN UINTN ProcessorNumber, + OUT EFI_PROCESSOR_INFORMATION *ProcessorInfoBuffer + ) +{ + EFI_STATUS Status; + EFI_MP_SERVICES_PROTOCOL *MpServices; + =20 + MpServices =3D GetMpProtocol (); + Status =3D MpServices->GetProcessorInfo ( + MpServices, + ProcessorNumber, + ProcessorInfoBuffer + ); + return Status; +} + +/** + Worker function to execute a caller provided function on all enabled APs. + =20 + @param[in] Procedure A pointer to the function to be run = on + enabled APs of the system. +**/ +VOID +StartupAPsWorker ( + IN EFI_AP_PROCEDURE Procedure + ) +{ + EFI_STATUS Status; + EFI_MP_SERVICES_PROTOCOL *MpServices; + =20 + MpServices =3D GetMpProtocol (); + // + // Wakeup all APs + // + Status =3D MpServices->StartupAllAPs ( + MpServices, + Procedure, + FALSE, + NULL, + 0,=20 + NULL, + NULL + ); + ASSERT_EFI_ERROR (Status); +} + +/** + Worker function to switch the requested AP to be the BSP from that point= onward. + + @param[in] ProcessorNumber The handle number of AP that is to become t= he new BSP. +**/ +VOID +SwitchNewBsp ( + IN UINTN ProcessorNumber + ) +{ + EFI_STATUS Status; + EFI_MP_SERVICES_PROTOCOL *MpServices; + =20 + MpServices =3D GetMpProtocol (); + // + // Wakeup all APs + // + Status =3D MpServices->SwitchBSP ( + MpServices, + ProcessorNumber, + TRUE + ); + ASSERT_EFI_ERROR (Status); +} + +/** + Worker function to retrieve the number of logical processor in the platf= orm. + =20 + @param[out] NumberOfProcessors Pointer to the total number of l= ogical + processors in the system, includ= ing the BSP + and disabled APs. + @param[out] NumberOfEnabledProcessors Pointer to the number of enabled= logical + processors that exist in system,= including + the BSP. +**/ +VOID +GetNumberOfProcessor ( + OUT UINTN *NumberOfCpus, + OUT UINTN *NumberOfEnabledProcessors + ) +{ + EFI_STATUS Status; + EFI_MP_SERVICES_PROTOCOL *MpServices; + =20 + MpServices =3D GetMpProtocol (); + + // + // Get the number of CPUs + // + Status =3D MpServices->GetNumberOfProcessors ( + MpServices, + NumberOfCpus, + NumberOfEnabledProcessors + ); + ASSERT_EFI_ERROR (Status); +} + +/** + Allocates ACPI NVS memory to save ACPI_CPU_DATA. + + @return Pointer to allocated ACPI_CPU_DATA. +**/ +ACPI_CPU_DATA * +AllocateAcpiCpuData ( + VOID + ) +{ + // + // CpuS3DataDxe will do it. + // + ASSERT (FALSE); + return NULL; +} + +/** + Enlarges CPU register table for each processor. + + @param[in, out] RegisterTable Pointer processor's CPU register table +**/ +VOID +EnlargeRegisterTable ( + IN OUT CPU_REGISTER_TABLE *RegisterTable + ) +{ + EFI_STATUS Status; + EFI_PHYSICAL_ADDRESS Address; + UINTN AllocatePages; + + Address =3D BASE_4GB - 1; + AllocatePages =3D RegisterTable->AllocatedSize / EFI_PAGE_SIZE; + Status =3D gBS->AllocatePages ( + AllocateMaxAddress, + EfiACPIMemoryNVS, + AllocatePages + 1, + &Address + ); + ASSERT_EFI_ERROR (Status); + + // + // If there are records existing in the register table, then copy its co= ntents + // to new region and free the old one. + // + if (RegisterTable->AllocatedSize > 0) { + CopyMem ( + (VOID *) (UINTN) Address, + (VOID *) (UINTN) RegisterTable->RegisterTableEntry, + RegisterTable->AllocatedSize + ); + // + // RegisterTableEntry is allocated by gBS->AllocatePages() service. + // So, gBS->FreePages() service is used to free it. + // + gBS->FreePages ( + RegisterTable->RegisterTableEntry, + AllocatePages + ); + } + + // + // Adjust the allocated size and register table base address. + // + RegisterTable->AllocatedSize +=3D EFI_PAGE_SIZE; + RegisterTable->RegisterTableEntry =3D Address; +} diff --git a/UefiCpuPkg/Library/RegisterCpuFeaturesLib/DxeRegisterCpuFeatur= esLib.inf b/UefiCpuPkg/Library/RegisterCpuFeaturesLib/DxeRegisterCpuFeature= sLib.inf new file mode 100644 index 0000000..abffd11 --- /dev/null +++ b/UefiCpuPkg/Library/RegisterCpuFeaturesLib/DxeRegisterCpuFeaturesLib.i= nf @@ -0,0 +1,62 @@ +## @file +# Register CPU Features Library DXE instance. +# +# Copyright (c) 2017, Intel Corporation. All rights reserved.
+# This program and the accompanying materials +# are licensed and made available under the terms and conditions of the B= SD 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 IM= PLIED. +# +## + +[Defines] + INF_VERSION =3D 0x00010005 + BASE_NAME =3D DxeRegisterCpuFeaturesLib + MODULE_UNI_FILE =3D DxeRegisterCpuFeaturesLib.uni + FILE_GUID =3D ADE8F745-AA2E-49f6-8ED4-746B34867E52 + MODULE_TYPE =3D DXE_DRIVER + VERSION_STRING =3D 1.0 + LIBRARY_CLASS =3D RegisterCpuFeaturesLib|DXE_DRIVER + +# +# The following information is for reference only and not required by the = build tools. +# +# VALID_ARCHITECTURES =3D IA32 X64 +# + +[Sources.common] + DxeRegisterCpuFeaturesLib.c + RegisterCpuFeaturesLib.c + RegisterCpuFeatures.h + CpuFeaturesInitialize.c + +[Packages] + MdePkg/MdePkg.dec + UefiCpuPkg/UefiCpuPkg.dec + +[LibraryClasses] + BaseLib + DebugLib + PcdLib + LocalApicLib + BaseMemoryLib + MemoryAllocationLib + SynchronizationLib + UefiBootServicesTableLib + IoLib + +[Protocols] + gEfiMpServiceProtocolGuid ## = CONSUMES + +[Pcd] + gUefiCpuPkgTokenSpaceGuid.PcdCpuS3DataAddress ## = CONSUMES + gUefiCpuPkgTokenSpaceGuid.PcdCpuFeaturesSupport ## = CONSUMES + gUefiCpuPkgTokenSpaceGuid.PcdCpuFeaturesUserConfiguration ## = CONSUMES + gUefiCpuPkgTokenSpaceGuid.PcdCpuFeaturesCapability ## = PRODUCES + gUefiCpuPkgTokenSpaceGuid.PcdCpuFeaturesSetting ## = PRODUCES + +[Depex] + gEfiMpServiceProtocolGuid AND gEdkiiCpuFeaturesSetDoneGuid diff --git a/UefiCpuPkg/Library/RegisterCpuFeaturesLib/PeiRegisterCpuFeatur= esLib.c b/UefiCpuPkg/Library/RegisterCpuFeaturesLib/PeiRegisterCpuFeaturesL= ib.c new file mode 100644 index 0000000..12a516a --- /dev/null +++ b/UefiCpuPkg/Library/RegisterCpuFeaturesLib/PeiRegisterCpuFeaturesLib.c @@ -0,0 +1,390 @@ +/** @file + CPU Register Table Library functions. + + Copyright (c) 2016, Intel Corporation. All rights reserved.
+ This program and the accompanying materials + are licensed and made available under the terms and conditions of the BS= D License + which accompanies this distribution. The full text of the license may b= e 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 IMP= LIED. + +**/ + +#include + +#include +#include +#include +#include +#include "RegisterCpuFeatures.h" + +#define REGISTER_CPU_FEATURES_GUID \ + { \ + 0xa694c467, 0x697a, 0x446b, { 0xb9, 0x29, 0x5b, 0x14, 0xa0, 0xcf, 0x39= , 0xf } \ + } + +EFI_GUID mRegisterCpuFeaturesHobGuid =3D REGISTER_CPU_FEATURES_GUID; + +/** + Worker function to get CPU_FEATURES_DATA pointer. + + @return Pointer to CPU_FEATURES_DATA. +**/ +CPU_FEATURES_DATA * +GetCpuFeaturesData ( + VOID + ) +{ + CPU_FEATURES_DATA *CpuInitData; + EFI_HOB_GUID_TYPE *GuidHob; + VOID *DataInHob; + UINT64 Data64; + + CpuInitData =3D NULL; + GuidHob =3D GetFirstGuidHob (&mRegisterCpuFeaturesHobGuid); + if (GuidHob !=3D NULL) { + DataInHob =3D GET_GUID_HOB_DATA (GuidHob); + CpuInitData =3D (CPU_FEATURES_DATA *) (*(UINTN *) DataInHob); + ASSERT (CpuInitData !=3D NULL); + } else { + CpuInitData =3D AllocateZeroPool (sizeof (CPU_FEATURES_DATA)); + ASSERT (CpuInitData !=3D NULL); + // + // Build location of CPU MP DATA buffer in HOB + // + Data64 =3D (UINT64) (UINTN) CpuInitData; + BuildGuidDataHob ( + &mRegisterCpuFeaturesHobGuid, + (VOID *) &Data64, + sizeof (UINT64) + ); + } + + return CpuInitData; +} + +/** + Worker function to get MP PPI service pointer. + + @return PEI PPI service pointer. +**/ +EFI_PEI_MP_SERVICES_PPI * +GetMpPpi ( + VOID + ) +{ + EFI_STATUS Status; + EFI_PEI_MP_SERVICES_PPI *CpuMpPpi; + + // + // Get MP Services Protocol + // + Status =3D PeiServicesLocatePpi ( + &gEfiPeiMpServicesPpiGuid, + 0, + NULL, + (VOID **)&CpuMpPpi + ); + ASSERT_EFI_ERROR (Status); + return CpuMpPpi; +} + +/** + Worker function to return processor index. + + @return The processor index. +**/ +UINTN +GetProcessorIndex ( + VOID + ) +{ + EFI_STATUS Status; + EFI_PEI_MP_SERVICES_PPI *CpuMpPpi; + UINTN ProcessorIndex; + + CpuMpPpi =3D GetMpPpi (); + + Status =3D CpuMpPpi->WhoAmI(GetPeiServicesTablePointer (), CpuMpPpi, &Pr= ocessorIndex); + ASSERT_EFI_ERROR (Status); + return ProcessorIndex; +} + +/** + Worker function to MP-related information on the requested processor at = the + instant this call is made. + + @param[in] ProcessorNumber The handle number of processor. + @param[out] ProcessorInfoBuffer A pointer to the buffer where informat= ion for + the requested processor is deposited. + + @return Status of MpServices->GetProcessorInfo(). +**/ +EFI_STATUS +GetProcessorInformation ( + IN UINTN ProcessorNumber, + OUT EFI_PROCESSOR_INFORMATION *ProcessorInfoBuffer + ) +{ + EFI_PEI_MP_SERVICES_PPI *CpuMpPpi; + EFI_STATUS Status; + + CpuMpPpi =3D GetMpPpi (); + Status =3D CpuMpPpi->GetProcessorInfo ( + GetPeiServicesTablePointer(), + CpuMpPpi, + ProcessorNumber, + ProcessorInfoBuffer + ); + return Status; +} + +/** + Worker function to execute a caller provided function on all enabled APs. + + @param[in] Procedure A pointer to the function to be run = on + enabled APs of the system. +**/ +VOID +StartupAPsWorker ( + IN EFI_AP_PROCEDURE Procedure + ) +{ + EFI_STATUS Status; + EFI_PEI_MP_SERVICES_PPI *CpuMpPpi; + + // + // Get MP Services Protocol + // + Status =3D PeiServicesLocatePpi ( + &gEfiPeiMpServicesPpiGuid, + 0, + NULL, + (VOID **)&CpuMpPpi + ); + ASSERT_EFI_ERROR (Status); + + // + // Wakeup all APs for data collection. + // + Status =3D CpuMpPpi->StartupAllAPs ( + GetPeiServicesTablePointer (), + CpuMpPpi, + Procedure, + FALSE, + 0, + NULL + ); + ASSERT_EFI_ERROR (Status); +} + +/** + Worker function to switch the requested AP to be the BSP from that point= onward. + + @param[in] ProcessorNumber The handle number of AP that is to become t= he new BSP. +**/ +VOID +SwitchNewBsp ( + IN UINTN ProcessorNumber + ) +{ + EFI_STATUS Status; + EFI_PEI_MP_SERVICES_PPI *CpuMpPpi; + + // + // Get MP Services Protocol + // + Status =3D PeiServicesLocatePpi ( + &gEfiPeiMpServicesPpiGuid, + 0, + NULL, + (VOID **)&CpuMpPpi + ); + ASSERT_EFI_ERROR (Status); + + // + // Wakeup all APs for data collection. + // + Status =3D CpuMpPpi->SwitchBSP ( + GetPeiServicesTablePointer (), + CpuMpPpi, + ProcessorNumber, + TRUE + ); + ASSERT_EFI_ERROR (Status); +} + +/** + Worker function to retrieve the number of logical processor in the platf= orm. + + @param[out] NumberOfProcessors Pointer to the total number of l= ogical + processors in the system, includ= ing the BSP + and disabled APs. + @param[out] NumberOfEnabledProcessors Pointer to the number of enabled= logical + processors that exist in system,= including + the BSP. +**/ +VOID +GetNumberOfProcessor ( + OUT UINTN *NumberOfCpus, + OUT UINTN *NumberOfEnabledProcessors + ) +{ + EFI_STATUS Status; + EFI_PEI_MP_SERVICES_PPI *CpuMpPpi; + + // + // Get MP Services Protocol + // + Status =3D PeiServicesLocatePpi ( + &gEfiPeiMpServicesPpiGuid, + 0, + NULL, + (VOID **)&CpuMpPpi + ); + ASSERT_EFI_ERROR (Status); + + // + // Get the number of CPUs + // + Status =3D CpuMpPpi->GetNumberOfProcessors ( + GetPeiServicesTablePointer (), + CpuMpPpi, + NumberOfCpus, + NumberOfEnabledProcessors + ); + ASSERT_EFI_ERROR (Status); +} + +/** + Allocates ACPI NVS memory to save ACPI_CPU_DATA. + + @return Pointer to allocated ACPI_CPU_DATA. +**/ +ACPI_CPU_DATA * +AllocateAcpiCpuData ( + VOID + ) +{ + EFI_STATUS Status; + EFI_PEI_MP_SERVICES_PPI *CpuMpPpi; + UINTN NumberOfCpus; + UINTN NumberOfEnabledProcessors; + ACPI_CPU_DATA *AcpiCpuData; + EFI_PHYSICAL_ADDRESS Address; + UINTN TableSize; + CPU_REGISTER_TABLE *RegisterTable; + UINTN Index; + EFI_PROCESSOR_INFORMATION ProcessorInfoBuffer; + + Status =3D PeiServicesAllocatePages ( + EfiACPIMemoryNVS, + EFI_SIZE_TO_PAGES (sizeof (ACPI_CPU_DATA)), + &Address + ); + ASSERT_EFI_ERROR (Status); + AcpiCpuData =3D (ACPI_CPU_DATA *) (UINTN) Address; + ASSERT (AcpiCpuData !=3D NULL); + + // + // Get MP Services Protocol + // + Status =3D PeiServicesLocatePpi ( + &gEfiPeiMpServicesPpiGuid, + 0, + NULL, + (VOID **)&CpuMpPpi + ); + ASSERT_EFI_ERROR (Status); + + // + // Get the number of CPUs + // + Status =3D CpuMpPpi->GetNumberOfProcessors ( + GetPeiServicesTablePointer (), + CpuMpPpi, + &NumberOfCpus, + &NumberOfEnabledProcessors + ); + ASSERT_EFI_ERROR (Status); + AcpiCpuData->NumberOfCpus =3D (UINT32)NumberOfCpus; + + // + // Allocate buffer for empty RegisterTable and PreSmmInitRegisterTable f= or all CPUs + // + TableSize =3D 2 * NumberOfCpus * sizeof (CPU_REGISTER_TABLE); + Status =3D PeiServicesAllocatePages ( + EfiACPIMemoryNVS, + EFI_SIZE_TO_PAGES (TableSize), + &Address + ); + ASSERT_EFI_ERROR (Status); + RegisterTable =3D (CPU_REGISTER_TABLE *) (UINTN) Address; + + for (Index =3D 0; Index < NumberOfCpus; Index++) { + Status =3D CpuMpPpi->GetProcessorInfo ( + GetPeiServicesTablePointer (), + CpuMpPpi, + Index, + &ProcessorInfoBuffer + ); + ASSERT_EFI_ERROR (Status); + + RegisterTable[Index].InitialApicId =3D (UINT32)ProcessorInfoBuffe= r.ProcessorId; + RegisterTable[Index].TableLength =3D 0; + RegisterTable[Index].AllocatedSize =3D 0; + RegisterTable[Index].RegisterTableEntry =3D 0; + + RegisterTable[NumberOfCpus + Index].InitialApicId =3D (UINT32)Pro= cessorInfoBuffer.ProcessorId; + RegisterTable[NumberOfCpus + Index].TableLength =3D 0; + RegisterTable[NumberOfCpus + Index].AllocatedSize =3D 0; + RegisterTable[NumberOfCpus + Index].RegisterTableEntry =3D 0; + } + AcpiCpuData->RegisterTable =3D (EFI_PHYSICAL_ADDRESS)(UINTN)Re= gisterTable; + AcpiCpuData->PreSmmInitRegisterTable =3D (EFI_PHYSICAL_ADDRESS)(UINTN)(R= egisterTable + NumberOfCpus); + + return AcpiCpuData; +} + +/** + Enlarges CPU register table for each processor. + + @param[in, out] RegisterTable Pointer processor's CPU register table +**/ +VOID +EnlargeRegisterTable ( + IN OUT CPU_REGISTER_TABLE *RegisterTable + ) +{ + EFI_STATUS Status; + EFI_PHYSICAL_ADDRESS Address; + UINTN AllocatePages; + + AllocatePages =3D RegisterTable->AllocatedSize / EFI_PAGE_SIZE; + Status =3D PeiServicesAllocatePages ( + EfiACPIMemoryNVS, + AllocatePages + 1, + &Address + ); + ASSERT_EFI_ERROR (Status); + + // + // If there are records existing in the register table, then copy its co= ntents + // to new region and free the old one. + // + if (RegisterTable->AllocatedSize > 0) { + CopyMem ( + (VOID *) (UINTN) Address, + (VOID *) (UINTN) RegisterTable->RegisterTableEntry, + RegisterTable->AllocatedSize + ); + } + + // + // Adjust the allocated size and register table base address. + // + RegisterTable->AllocatedSize +=3D EFI_PAGE_SIZE; + RegisterTable->RegisterTableEntry =3D Address; +} diff --git a/UefiCpuPkg/Library/RegisterCpuFeaturesLib/PeiRegisterCpuFeatur= esLib.inf b/UefiCpuPkg/Library/RegisterCpuFeaturesLib/PeiRegisterCpuFeature= sLib.inf new file mode 100644 index 0000000..0090714 --- /dev/null +++ b/UefiCpuPkg/Library/RegisterCpuFeaturesLib/PeiRegisterCpuFeaturesLib.i= nf @@ -0,0 +1,64 @@ +## @file +# Register CPU Features Library PEI instance. +# +# Copyright (c) 2017, Intel Corporation. All rights reserved.
+# This program and the accompanying materials +# are licensed and made available under the terms and conditions of the B= SD 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 IM= PLIED. +# +## + +[Defines] + INF_VERSION =3D 0x00010005 + BASE_NAME =3D PeiRegisterCpuFeaturesLib + MODULE_UNI_FILE =3D PeiRegisterCpuFeaturesLib.uni + FILE_GUID =3D D8855DB3-8348-41B5-BDA4-385351767D41 + MODULE_TYPE =3D PEIM + VERSION_STRING =3D 1.0 + LIBRARY_CLASS =3D RegisterCpuFeaturesLib|PEIM + +# +# The following information is for reference only and not required by the = build tools. +# +# VALID_ARCHITECTURES =3D IA32 X64 +# + +[Sources.common] + PeiRegisterCpuFeaturesLib.c + RegisterCpuFeaturesLib.c + RegisterCpuFeatures.h + CpuFeaturesInitialize.c + +[Packages] + MdePkg/MdePkg.dec + UefiCpuPkg/UefiCpuPkg.dec + +[LibraryClasses] + BaseLib + DebugLib + PcdLib + LocalApicLib + BaseMemoryLib + MemoryAllocationLib + SynchronizationLib + HobLib + PeiServicesLib + PeiServicesTablePointerLib + IoLib + +[Ppis] + gEfiPeiMpServicesPpiGuid ## = CONSUMES + +[Pcd] + gUefiCpuPkgTokenSpaceGuid.PcdCpuS3DataAddress ## = CONSUMES + gUefiCpuPkgTokenSpaceGuid.PcdCpuFeaturesSupport ## = CONSUMES + gUefiCpuPkgTokenSpaceGuid.PcdCpuFeaturesUserConfiguration ## = CONSUMES + gUefiCpuPkgTokenSpaceGuid.PcdCpuFeaturesCapability ## = PRODUCES + gUefiCpuPkgTokenSpaceGuid.PcdCpuFeaturesSetting ## = PRODUCES + +[Depex] + gEfiPeiMpServicesPpiGuid AND gEdkiiCpuFeaturesSetDoneGuid diff --git a/UefiCpuPkg/Library/RegisterCpuFeaturesLib/RegisterCpuFeatures.= h b/UefiCpuPkg/Library/RegisterCpuFeaturesLib/RegisterCpuFeatures.h new file mode 100644 index 0000000..2b136b6 --- /dev/null +++ b/UefiCpuPkg/Library/RegisterCpuFeaturesLib/RegisterCpuFeatures.h @@ -0,0 +1,193 @@ +/** @file + CPU Register Table Library definitions. + + Copyright (c) 2017, Intel Corporation. All rights reserved.
+ This program and the accompanying materials + are licensed and made available under the terms and conditions of the BS= D License + which accompanies this distribution. The full text of the license may b= e 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 IMP= LIED. + +**/ + +#ifndef _REGISTER_CPU_FEATURES_H_ +#define _REGISTER_CPU_FEATURES_H_ + +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#define CPU_FEATURE_ENTRY_SIGNATURE SIGNATURE_32 ('C', 'F', 'E', 'S') + +#define CPU_FEATURE_NAME_SIZE 128 + +typedef struct { + REGISTER_CPU_FEATURE_INFORMATION CpuInfo; + UINT8 *FeaturesSupportedMask; + LIST_ENTRY OrderList; +} CPU_FEATURES_INIT_ORDER; + +typedef struct { + UINT32 Signature; + LIST_ENTRY Link; + UINT8 *FeatureMask; + CHAR8 *FeatureName; + CPU_FEATURE_GET_CONFIG_DATA GetConfigDataFunc; + CPU_FEATURE_SUPPORT SupportFunc; + CPU_FEATURE_INITIALIZE InitializeFunc; + UINT8 *BeforeFeatureBitMask; + UINT8 *AfterFeatureBitMask; + VOID *ConfigData; + BOOLEAN BeforeAll; + BOOLEAN AfterAll; +} CPU_FEATURES_ENTRY; + +typedef struct { + UINTN FeaturesCount; + UINT32 BitMaskSize; + SPIN_LOCK MsrLock; + SPIN_LOCK MemoryMappedLock; + LIST_ENTRY FeatureList; + + CPU_FEATURES_INIT_ORDER *InitOrder; + UINT8 *SupportPcds; + UINT8 *CapabilityPcds; + UINT8 *ConfigurationPcds; + UINT8 *SettingPcds; + + CPU_REGISTER_TABLE *RegisterTable; + CPU_REGISTER_TABLE *PreSmmRegisterTable; + UINTN BspNumber; +} CPU_FEATURES_DATA; + +#define CPU_FEATURE_ENTRY_FROM_LINK(a) \ + CR ( \ + (a), \ + CPU_FEATURES_ENTRY, \ + Link, \ + CPU_FEATURE_ENTRY_SIGNATURE \ + ) + +/** + Worker function to get CPU_FEATURES_DATA pointer. + + @return Pointer to CPU_FEATURES_DATA. +**/ +CPU_FEATURES_DATA * +GetCpuFeaturesData ( + VOID + ); + +/** + Enlarges CPU register table for each processor. + + @param[in, out] RegisterTable Pointer processor's CPU register table +**/ +VOID +EnlargeRegisterTable ( + IN OUT CPU_REGISTER_TABLE *RegisterTable + ); + +/** + Allocates ACPI NVS memory to save ACPI_CPU_DATA. + + @return Pointer to allocated ACPI_CPU_DATA. +**/ +ACPI_CPU_DATA * +AllocateAcpiCpuData ( + VOID + ); + +/** + Worker function to return processor index. + + @return The processor index. +**/ +UINTN +GetProcessorIndex ( + VOID + ); + +/** + Gets detailed MP-related information on the requested processor at the + instant this call is made. + + @param[in] ProcessorNumber The handle number of processor. + @param[out] ProcessorInfoBuffer A pointer to the buffer where informat= ion for + the requested processor is deposited. + + @return Status of MpServices->GetProcessorInfo(). +**/ +EFI_STATUS +GetProcessorInformation ( + IN UINTN ProcessorNumber, + OUT EFI_PROCESSOR_INFORMATION *ProcessorInfoBuffer + ); + +/** + Worker function to execute a caller provided function on all enabled APs. + + @param[in] Procedure A pointer to the function to be run = on + enabled APs of the system. +**/ +VOID +StartupAPsWorker ( + IN EFI_AP_PROCEDURE Procedure + ); + +/** + Worker function to retrieve the number of logical processor in the platf= orm. + + @param[out] NumberOfProcessors Pointer to the total number of l= ogical + processors in the system, includ= ing the BSP + and disabled APs. + @param[out] NumberOfEnabledProcessors Pointer to the number of enabled= logical + processors that exist in system,= including + the BSP. +**/ +VOID +GetNumberOfProcessor ( + OUT UINTN *NumberOfCpus, + OUT UINTN *NumberOfEnabledProcessors + ); + +/** + Worker function to switch the requested AP to be the BSP from that point= onward. + + @param[in] ProcessorNumber The handle number of AP that is to become t= he new BSP. +**/ +VOID +SwitchNewBsp ( + IN UINTN ProcessorNumber + ); + +/** + Function that uses DEBUG() macros to display the contents of a a CPU fea= ture bit mask. + + @param[in] FeatureMask A pointer to the CPU feature bit mask. +**/ +VOID +DumpCpuFeatureMask ( + IN UINT8 *FeatureMask + ); + +/** + Dump CPU feature name or CPU feature bit mask. + + @param[in] CpuFeature Pointer to CPU_FEATURES_ENTRY +**/ +VOID +DumpCpuFeature ( + IN CPU_FEATURES_ENTRY *CpuFeature + ); + +#endif diff --git a/UefiCpuPkg/Library/RegisterCpuFeaturesLib/RegisterCpuFeaturesD= xe.uni b/UefiCpuPkg/Library/RegisterCpuFeaturesLib/RegisterCpuFeaturesDxe.u= ni new file mode 100644 index 0000000..b0c313b --- /dev/null +++ b/UefiCpuPkg/Library/RegisterCpuFeaturesLib/RegisterCpuFeaturesDxe.uni @@ -0,0 +1,22 @@ +// /** @file +// CPU Register Table Library instance. +// +// CPU Register Table Library instance. +// +// Copyright (c) 2016, Intel Corporation. All rights reserved.
+// +// This program and the accompanying materials +// are licensed and made available under the terms and conditions of the B= SD 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 IM= PLIED. +// +// **/ + + +#string STR_MODULE_ABSTRACT #language en-US "CPU Register Tabl= e Library instance" + +#string STR_MODULE_DESCRIPTION #language en-US "CPU Register Tabl= e Library instance." + diff --git a/UefiCpuPkg/Library/RegisterCpuFeaturesLib/RegisterCpuFeaturesL= ib.c b/UefiCpuPkg/Library/RegisterCpuFeaturesLib/RegisterCpuFeaturesLib.c new file mode 100644 index 0000000..7a1470b --- /dev/null +++ b/UefiCpuPkg/Library/RegisterCpuFeaturesLib/RegisterCpuFeaturesLib.c @@ -0,0 +1,770 @@ +/** @file + CPU Register Table Library functions. + + Copyright (c) 2017, Intel Corporation. All rights reserved.
+ This program and the accompanying materials + are licensed and made available under the terms and conditions of the BS= D License + which accompanies this distribution. The full text of the license may b= e 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 IMP= LIED. + +**/ + +#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 =3D PcdGetSize (PcdCpuFeaturesSupport); + if (CompareMem (FirstFeatureMask, SecondFeatureMask, BitMaskSize) =3D=3D= 0) { + return TRUE; + } else { + return FALSE; + } +} + +/** + Function that uses DEBUG() macros to display the contents of a a CPU fea= ture 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 =3D PcdGetSize (PcdCpuFeaturesSupport); + Data8 =3D (UINT8 *) FeatureMask; + for (Index =3D 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 !=3D NULL) { + DEBUG ((DEBUG_INFO, "FeatureName: %a\n", CpuFeature->FeatureName)); + } else { + DEBUG ((DEBUG_INFO, "FeatureMask =3D ")); + 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 m= ask buffer. +**/ +BOOLEAN +IsBitMaskMatchCheck ( + IN UINT8 *FeatureMask, + IN UINT8 *DependentBitMask + ) +{ + UINTN Index; + UINTN BitMaskSize; + UINT8 *Data1; + UINT8 *Data2; + + BitMaskSize =3D PcdGetSize (PcdCpuFeaturesSupport); + + Data1 =3D FeatureMask; + Data2 =3D DependentBitMask; + for (Index =3D 0; Index < BitMaskSize; Index++) { + if (((*(Data1++)) & (*(Data2++))) !=3D 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 =3D GetFirstNode (FeatureList); + while (!IsNull (FeatureList, CurrentEntry)) { + Swapped =3D FALSE; + CpuFeature =3D CPU_FEATURE_ENTRY_FROM_LINK (CurrentEntry); + if (CpuFeature->BeforeAll) { + // + // Check all features dispatched before this entry + // + CheckEntry =3D GetFirstNode (FeatureList); + while (CheckEntry !=3D CurrentEntry) { + CheckFeature =3D CPU_FEATURE_ENTRY_FROM_LINK (CheckEntry); + if (!CheckFeature->BeforeAll) { + // + // If this feature has no BeforeAll flag and is dispatched befor= e CpuFeature, + // insert currentEntry before Checked feature + // + RemoveEntryList (CurrentEntry); + InsertTailList (CheckEntry, CurrentEntry); + Swapped =3D TRUE; + break; + } + CheckEntry =3D CheckEntry->ForwardLink; + } + if (Swapped) { + continue; + } + } + + if (CpuFeature->AfterAll) { + // + // Check all features dispatched after this entry + // + CheckEntry =3D GetNextNode (FeatureList, CurrentEntry); + while (!IsNull (FeatureList, CheckEntry)) { + CheckFeature =3D 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 =3D GetNextNode (FeatureList, CurrentEntry); + RemoveEntryList (CurrentEntry); + InsertHeadList (CheckEntry, CurrentEntry); + CurrentEntry =3D TempEntry; + Swapped =3D TRUE; + break; + } + CheckEntry =3D CheckEntry->ForwardLink; + } + if (Swapped) { + continue; + } + } + + if (CpuFeature->BeforeFeatureBitMask !=3D NULL) { + // + // Check all features dispatched before this entry + // + CheckEntry =3D GetFirstNode (FeatureList); + while (CheckEntry !=3D CurrentEntry) { + CheckFeature =3D CPU_FEATURE_ENTRY_FROM_LINK (CheckEntry); + if (IsBitMaskMatchCheck (CheckFeature->FeatureMask, CpuFeature->Be= foreFeatureBitMask)) { + // + // If there is dependency, swap them + // + RemoveEntryList (CurrentEntry); + InsertTailList (CheckEntry, CurrentEntry); + Swapped =3D TRUE; + break; + } + CheckEntry =3D CheckEntry->ForwardLink; + } + if (Swapped) { + continue; + } + } + + if (CpuFeature->AfterFeatureBitMask !=3D NULL) { + // + // Check all features dispatched after this entry + // + CheckEntry =3D GetNextNode (FeatureList, CurrentEntry); + while (!IsNull (FeatureList, CheckEntry)) { + CheckFeature =3D CPU_FEATURE_ENTRY_FROM_LINK (CheckEntry); + if (IsBitMaskMatchCheck (CheckFeature->FeatureMask, CpuFeature->Af= terFeatureBitMask)) { + // + // If there is dependency, swap them + // + TempEntry =3D GetNextNode (FeatureList, CurrentEntry); + RemoveEntryList (CurrentEntry); + InsertHeadList (CheckEntry, CurrentEntry); + CurrentEntry =3D TempEntry; + Swapped =3D TRUE; + break; + } + CheckEntry =3D CheckEntry->ForwardLink; + } + if (Swapped) { + continue; + } + } + // + // No swap happened, check the next feature + // + CurrentEntry =3D CurrentEntry->ForwardLink; + } +} + +/** + Worker function to register CPU Feature. + + @param[in] CpuFeature Pointer to CPU feature entry + + @retval RETURN_SUCCESS The CPU feature was successfully regis= tered. + @retval RETURN_OUT_OF_RESOURCES There are not enough resources to regi= ster + 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 =3D PcdGetSize (PcdCpuFeaturesSupport); + CpuFeaturesData =3D GetCpuFeaturesData (); + if (CpuFeaturesData->FeaturesCount =3D=3D 0) { + InitializeListHead (&CpuFeaturesData->FeatureList); + InitializeSpinLock (&CpuFeaturesData->MsrLock); + InitializeSpinLock (&CpuFeaturesData->MemoryMappedLock); + CpuFeaturesData->BitMaskSize =3D BitMaskSize; + } + ASSERT (CpuFeaturesData->BitMaskSize =3D=3D BitMaskSize); + + FeatureExist =3D FALSE; + Entry =3D GetFirstNode (&CpuFeaturesData->FeatureList); + while (!IsNull (&CpuFeaturesData->FeatureList, Entry)) { + CpuFeatureEntry =3D CPU_FEATURE_ENTRY_FROM_LINK (Entry); + if (IsCpuFeatureMatch (CpuFeature->FeatureMask, CpuFeatureEntry->Featu= reMask)) { + // + // If this feature already registered + // + FeatureExist =3D TRUE; + break; + } + Entry =3D Entry->ForwardLink; + } + + if (!FeatureExist) { + DEBUG ((DEBUG_INFO, "[NEW] ")); + DumpCpuFeature (CpuFeature); + InsertTailList (&CpuFeaturesData->FeatureList, &CpuFeature->Link); + CpuFeaturesData->FeaturesCount++; + } else { + DEBUG ((DEBUG_INFO, "[OVERRIDE] ")); + DumpCpuFeature (CpuFeature); + // + // Overwrite original parameters of CPU feature + // + if (CpuFeature->GetConfigDataFunc !=3D NULL) { + CpuFeatureEntry->GetConfigDataFunc =3D CpuFeature->GetConfigDataFunc; + } + if (CpuFeature->SupportFunc !=3D NULL) { + CpuFeatureEntry->SupportFunc =3D CpuFeature->SupportFunc; + } + if (CpuFeature->InitializeFunc !=3D NULL) { + CpuFeatureEntry->InitializeFunc =3D CpuFeature->InitializeFunc; + } + if (CpuFeature->FeatureName !=3D NULL) { + if (CpuFeatureEntry->FeatureName =3D=3D NULL) { + CpuFeatureEntry->FeatureName =3D AllocatePool (CPU_FEATURE_NAME_SI= ZE); + ASSERT (CpuFeatureEntry->FeatureName !=3D NULL); + } + Status =3D AsciiStrCpyS (CpuFeatureEntry->FeatureName, CPU_FEATURE_N= AME_SIZE, CpuFeature->FeatureName); + ASSERT_EFI_ERROR (Status); + FreePool (CpuFeature->FeatureName); + } + if (CpuFeature->BeforeFeatureBitMask !=3D NULL) { + if (CpuFeatureEntry->BeforeFeatureBitMask !=3D NULL) { + FreePool (CpuFeatureEntry->BeforeFeatureBitMask); + } + CpuFeatureEntry->BeforeFeatureBitMask =3D CpuFeature->BeforeFeatureB= itMask; + } + if (CpuFeature->AfterFeatureBitMask !=3D NULL) { + if (CpuFeatureEntry->AfterFeatureBitMask !=3D NULL) { + FreePool (CpuFeatureEntry->AfterFeatureBitMask); + } + CpuFeatureEntry->AfterFeatureBitMask =3D CpuFeature->AfterFeatureBit= Mask; + } + CpuFeatureEntry->BeforeAll =3D CpuFeature->BeforeAll; + CpuFeatureEntry->AfterAll =3D 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 !=3D NULL); + CpuFeaturesBitMask =3D *FeaturesBitMask; + if (CpuFeaturesBitMask =3D=3D NULL) { + CpuFeaturesBitMask =3D AllocateZeroPool (BitMaskSize); + ASSERT (CpuFeaturesBitMask !=3D NULL); + *FeaturesBitMask =3D CpuFeaturesBitMask; + } + + CpuFeaturesBitMask +=3D (Feature / 8); + *CpuFeaturesBitMask |=3D (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. I= f NULL, + then the most recently registered function fo= r the + CPU feature is used. If no functions are reg= istered + for a CPU feature, then the CPU configuration= data + for the registered feature is NULL. + @param SupportFunc CPU feature support function. This is an opt= ional + parameter that may be NULL. If NULL, then th= e most + recently registered function for the CPU feat= ure 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 th= e most + recently registered function for the CPU feat= ure 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 pro= vided + by the registered functions. + Values with CPU_FEATURE_BEFORE modifier are f= eatures + that must be initialized after the features p= rovided + by the registered functions are used. + Values with CPU_FEATURE_AFTER modifier are fe= atures + that must be initialized before the features = provided + by the registered functions are used. + The last argument in this variable argument l= ist must + always be CPU_FEATURE_END. + + @retval RETURN_SUCCESS The CPU feature was successfully regis= tered. + @retval RETURN_OUT_OF_RESOURCES There are not enough resources to regi= ster + 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 =3D NULL; + BeforeFeatureBitMask =3D NULL; + AfterFeatureBitMask =3D NULL; + BeforeAll =3D FALSE; + AfterAll =3D FALSE; + + BitMaskSize =3D PcdGetSize (PcdCpuFeaturesSupport); + + VA_START (Marker, InitializeFunc); + Feature =3D VA_ARG (Marker, UINT32); + while (Feature !=3D CPU_FEATURE_END) { + ASSERT ((Feature & (CPU_FEATURE_BEFORE | CPU_FEATURE_AFTER)) + !=3D (CPU_FEATURE_BEFORE | CPU_FEATURE_AFTER)); + ASSERT ((Feature & (CPU_FEATURE_BEFORE_ALL | CPU_FEATURE_AFTER_ALL)) + !=3D (CPU_FEATURE_BEFORE_ALL | CPU_FEATURE_AFTER_ALL)); + if (Feature < CPU_FEATURE_BEFORE) { + BeforeAll =3D ((Feature & CPU_FEATURE_BEFORE_ALL) !=3D 0) ? TRUE : F= ALSE; + AfterAll =3D ((Feature & CPU_FEATURE_AFTER_ALL) !=3D 0) ? TRUE : FA= LSE; + Feature &=3D ~(CPU_FEATURE_BEFORE_ALL | CPU_FEATURE_AFTER_ALL); + ASSERT (FeatureMask =3D=3D NULL); + SetCpuFeaturesBitMask (&FeatureMask, Feature, BitMaskSize); + } else if ((Feature & CPU_FEATURE_BEFORE) !=3D 0) { + SetCpuFeaturesBitMask (&BeforeFeatureBitMask, Feature & ~CPU_FEATURE= _BEFORE, BitMaskSize); + } else if ((Feature & CPU_FEATURE_AFTER) !=3D 0) { + SetCpuFeaturesBitMask (&AfterFeatureBitMask, Feature & ~CPU_FEATURE_= AFTER, BitMaskSize); + } + Feature =3D VA_ARG (Marker, UINT32); + } + VA_END (Marker); + + CpuFeature =3D AllocateZeroPool (sizeof (CPU_FEATURES_ENTRY)); + ASSERT (CpuFeature !=3D NULL); + CpuFeature->Signature =3D CPU_FEATURE_ENTRY_SIGNATURE; + CpuFeature->FeatureMask =3D FeatureMask; + CpuFeature->BeforeFeatureBitMask =3D BeforeFeatureBitMask; + CpuFeature->AfterFeatureBitMask =3D AfterFeatureBitMask; + CpuFeature->BeforeAll =3D BeforeAll; + CpuFeature->AfterAll =3D AfterAll; + CpuFeature->GetConfigDataFunc =3D GetConfigDataFunc; + CpuFeature->SupportFunc =3D SupportFunc; + CpuFeature->InitializeFunc =3D InitializeFunc; + if (FeatureName !=3D NULL) { + CpuFeature->FeatureName =3D AllocatePool (CPU_FEATURE_NAME_SI= ZE); + ASSERT (CpuFeature->FeatureName !=3D NULL); + Status =3D AsciiStrCpyS (CpuFeature->FeatureName, CPU_FEATURE_NAME_SIZ= E, FeatureName); + ASSERT_EFI_ERROR (Status); + } + + Status =3D 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 regi= ster type, + register index, bit section and value. + + @param[in] PreSmmFlag If TRUE, entry will be added into PreSmm re= gister table + If FALSE, entry will be added into register= table + @param[in] ProcessorNumber The index of the CPU to add a register tabl= e 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 =3D GetCpuFeaturesData (); + if (CpuFeaturesData->RegisterTable =3D=3D NULL) { + AcpiCpuData =3D (ACPI_CPU_DATA *) (UINTN) PcdGet64 (PcdCpuS3DataAddres= s); + if (AcpiCpuData =3D=3D NULL) { + AcpiCpuData =3D AllocateAcpiCpuData (); + ASSERT (AcpiCpuData !=3D NULL); + // + // Set PcdCpuS3DataAddress to the base address of the ACPI_CPU_DATA = structure + // + Status =3D PcdSet64S (PcdCpuS3DataAddress, (UINT64)(UINTN)AcpiCpuDat= a); + ASSERT_EFI_ERROR (Status); + } + ASSERT (AcpiCpuData->RegisterTable !=3D 0); + CpuFeaturesData->RegisterTable =3D (CPU_REGISTER_TABLE *) (UINTN) Acpi= CpuData->RegisterTable; + CpuFeaturesData->PreSmmRegisterTable =3D (CPU_REGISTER_TABLE *) (UINTN= ) AcpiCpuData->PreSmmInitRegisterTable; + } + + if (PreSmmFlag) { + RegisterTable =3D &CpuFeaturesData->PreSmmRegisterTable[ProcessorNumbe= r]; + } else { + RegisterTable =3D &CpuFeaturesData->RegisterTable[ProcessorNumber]; + } + + if (RegisterTable->TableLength =3D=3D RegisterTable->AllocatedSize / siz= eof (CPU_REGISTER_TABLE_ENTRY)) { + EnlargeRegisterTable (RegisterTable); + } + + // + // Append entry in the register table. + // + RegisterTableEntry =3D (CPU_REGISTER_TABLE_ENTRY *) (UINTN) RegisterTabl= e->RegisterTableEntry; + RegisterTableEntry[RegisterTable->TableLength].RegisterType =3D Regist= erType; + RegisterTableEntry[RegisterTable->TableLength].Index =3D Index; + RegisterTableEntry[RegisterTable->TableLength].ValidBitStart =3D ValidB= itStart; + RegisterTableEntry[RegisterTable->TableLength].ValidBitLength =3D ValidB= itLength; + RegisterTableEntry[RegisterTable->TableLength].Value =3D Value; + + RegisterTable->TableLength++; +} + +/** + Adds an entry in specified register table. + + This function adds an entry in specified register table, with given regi= ster type, + register index, bit section and value. + + @param[in] ProcessorNumber The index of the CPU to add a register tabl= e 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 =3D (UINT8)LowBitSet64 (ValueMask); + End =3D (UINT8)HighBitSet64 (ValueMask); + Length =3D 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 regi= ster type, + register index, bit section and value. + + @param[in] ProcessorNumber The index of the CPU to add a register tabl= e 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 =3D (UINT8)LowBitSet64 (ValueMask); + End =3D (UINT8)HighBitSet64 (ValueMask); + Length =3D End - Start + 1; + CpuRegisterTableWriteWorker (TRUE, ProcessorNumber, RegisterType, Index,= Start, Length, Value); +} + +/** + Worker function to determine if a CPU feature is set in input CPU featur= e 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) >=3D CpuBitMaskSize) { + return FALSE; + } + return ((*(CpuBitMask + (Feature >> 3)) & (1 << (Feature & 0x07))) !=3D = 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 P= CD + 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 P= CD + 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 P= CD + 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 bi= t mask. + + @param[in] Feature The bit number of the CPU feature to check in the P= CD + PcdCpuFeaturesUserConfiguration + + @retval TRUE The CPU feature is set in PcdCpuFeaturesUserConfiguratio= n. + @retval FALSE The CPU feature is not set in PcdCpuFeaturesUserConfigur= ation. + + @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 functio= n. + + @note This service could be called by BSP only. +**/ +VOID +EFIAPI +SwitchBspAfterFeaturesInitialize ( + IN UINTN ProcessorNumber + ) +{ + CPU_FEATURES_DATA *CpuFeaturesData; + + CpuFeaturesData =3D GetCpuFeaturesData (); + CpuFeaturesData->BspNumber =3D ProcessorNumber; +} + diff --git a/UefiCpuPkg/UefiCpuPkg.dsc b/UefiCpuPkg/UefiCpuPkg.dsc index 3922f2d..59a702f 100644 --- a/UefiCpuPkg/UefiCpuPkg.dsc +++ b/UefiCpuPkg/UefiCpuPkg.dsc @@ -1,7 +1,7 @@ ## @file # UefiCpuPkg Package # -# Copyright (c) 2007 - 2016, Intel Corporation. All rights reserved.
+# Copyright (c) 2007 - 2017, Intel Corporation. All rights reserved.
# # This program and the accompanying materials # are licensed and made available under the terms and conditions of the B= SD License @@ -76,6 +76,7 @@ HobLib|MdePkg/Library/PeiHobLib/PeiHobLib.inf LockBoxLib|MdeModulePkg/Library/SmmLockBoxLib/SmmLockBoxPeiLib.inf MpInitLib|UefiCpuPkg/Library/MpInitLib/PeiMpInitLib.inf + RegisterCpuFeaturesLib|UefiCpuPkg/Library/RegisterCpuFeaturesLib/PeiRegi= sterCpuFeaturesLib.inf =20 [LibraryClasses.IA32.PEIM, LibraryClasses.X64.PEIM] PeiServicesTablePointerLib|MdePkg/Library/PeiServicesTablePointerLibIdt/= PeiServicesTablePointerLibIdt.inf @@ -89,6 +90,7 @@ HobLib|MdePkg/Library/DxeHobLib/DxeHobLib.inf CpuExceptionHandlerLib|UefiCpuPkg/Library/CpuExceptionHandlerLib/DxeCpuE= xceptionHandlerLib.inf MpInitLib|UefiCpuPkg/Library/MpInitLib/DxeMpInitLib.inf + RegisterCpuFeaturesLib|UefiCpuPkg/Library/RegisterCpuFeaturesLib/DxeRegi= sterCpuFeaturesLib.inf =20 [LibraryClasses.common.DXE_SMM_DRIVER] SmmServicesTableLib|MdePkg/Library/SmmServicesTableLib/SmmServicesTableL= ib.inf @@ -126,6 +128,8 @@ UefiCpuPkg/Library/MpInitLib/DxeMpInitLib.inf UefiCpuPkg/Library/MtrrLib/MtrrLib.inf UefiCpuPkg/Library/PlatformSecLibNull/PlatformSecLibNull.inf + UefiCpuPkg/Library/RegisterCpuFeaturesLib/PeiRegisterCpuFeaturesLib.inf + UefiCpuPkg/Library/RegisterCpuFeaturesLib/DxeRegisterCpuFeaturesLib.inf UefiCpuPkg/Library/SmmCpuPlatformHookLibNull/SmmCpuPlatformHookLibNull.i= nf UefiCpuPkg/Library/SmmCpuFeaturesLib/SmmCpuFeaturesLib.inf UefiCpuPkg/Library/SmmCpuFeaturesLib/SmmCpuFeaturesLibStm.inf --=20 2.9.3.windows.2 _______________________________________________ edk2-devel mailing list edk2-devel@lists.01.org https://lists.01.org/mailman/listinfo/edk2-devel