summaryrefslogtreecommitdiff
path: root/ReferenceCode/AcpiTables/Cppc/Dxe/Cppc.c
diff options
context:
space:
mode:
Diffstat (limited to 'ReferenceCode/AcpiTables/Cppc/Dxe/Cppc.c')
-rw-r--r--ReferenceCode/AcpiTables/Cppc/Dxe/Cppc.c863
1 files changed, 863 insertions, 0 deletions
diff --git a/ReferenceCode/AcpiTables/Cppc/Dxe/Cppc.c b/ReferenceCode/AcpiTables/Cppc/Dxe/Cppc.c
new file mode 100644
index 0000000..9da9b1a
--- /dev/null
+++ b/ReferenceCode/AcpiTables/Cppc/Dxe/Cppc.c
@@ -0,0 +1,863 @@
+/** @file
+ This DXE driver configures and supports Collaborative Processor Performance Control (CPPC).
+
+@copyright
+ Copyright (c) 2012 Intel Corporation. All rights reserved
+ This software and associated documentation (if any) is furnished
+ under a license and may only be used or copied in accordance
+ with the terms of the license. Except as permitted by such
+ license, no part of this software or documentation may be
+ reproduced, stored in a retrieval system, or transmitted in any
+ form or by any means without the express written consent of
+ Intel Corporation.
+
+ This file contains an 'Intel Peripheral Driver' and uniquely
+ identified as "Intel Reference Module" and is
+ licensed for Intel CPUs and chipsets under the terms of your
+ license agreement with Intel or your vendor. This file may
+ be modified by the user, subject to additional terms of the
+ license agreement
+
+**/
+#include "Cppc.h"
+
+ACPI_PLATFORM_POLICY_PROTOCOL *mAcpiPlatformPolicyProtocol;
+
+extern EFI_RUNTIME_SERVICES *gRT;
+extern EFI_BOOT_SERVICES *gBS;
+
+EFI_PHYSICAL_ADDRESS mCppcBaseAddressMem = 0;
+
+///
+/// Driver entry point
+///
+EFI_DRIVER_ENTRY_POINT (InitializeCppc)
+
+EFI_STATUS
+InitializeCppc (
+ IN EFI_HANDLE ImageHandle,
+ IN EFI_SYSTEM_TABLE *SystemTable
+ )
+/**
+@brief
+ Cppc DXE support.
+
+ @param[in] ImageHandle - Pointer to the loaded image protocol for this driver
+ @param[in] SystemTable - Pointer to the EFI System Table
+
+ @retval EFI_SUCCESS - The driver installed/initialized correctly.
+**/
+{
+ EFI_STATUS Status;
+ VOID *MemoryPointer;
+ UINT64 MsrValue;
+
+ gRT = SystemTable->RuntimeServices;
+ gBS = SystemTable->BootServices;
+
+ ///
+ /// Initialize the EFI Runtime Library
+ ///
+ DxeInitializeDriverLib (ImageHandle, SystemTable);
+
+ ///
+ /// S3 boot script
+ ///
+ INITIALIZE_SCRIPT (ImageHandle, SystemTable);
+
+ ///
+ /// Locate platform configuration information and copy it to a global variable.
+ ///
+ Status = gBS->LocateProtocol (
+ &gAcpiPlatformPolicyProtocolGuid,
+ NULL,
+ (VOID **) &mAcpiPlatformPolicyProtocol
+ );
+ if (EFI_ERROR(Status)) {
+ DEBUG ((EFI_D_ERROR, "CPPC: No Platform Policy Protocol available.\n"));
+ ASSERT_EFI_ERROR(Status);
+ return Status;
+ } else {
+ DEBUG ((EFI_D_ERROR, "CPPC: Platform Policy Protocol is loaded.\n"));
+ }
+
+ ///
+ /// Enable or disable CPPC depending on platform policy.
+ ///
+ if (mAcpiPlatformPolicyProtocol->EnableCppc == 0) {
+ DEBUG ((EFI_D_ERROR, "CPPC is disabled by platform policy. \n"));
+ return EFI_SUCCESS;
+ }
+
+ ///
+ /// Check if Haswell traditional, Haswell ULT or Crystal Well CPU.
+ ///
+ if(!(IsCpuSupported())){
+ DEBUG ((EFI_D_ERROR, "CPPC not supported in this CPU. \n"));
+ return EFI_SUCCESS;
+ }
+
+ ///
+ /// Check if Mobile CPU.
+ ///
+ if(!(IS_SA_DEVICE_ID_MOBILE (McD0PciCfg16 (R_SA_MC_DEVICE_ID)))) {
+ DEBUG ((EFI_D_ERROR, "CPPC not supported in this CPU. (not mobile) \n"));
+ return EFI_SUCCESS;
+ }
+
+ ///
+ /// Check if processor supports EE Policy capability.
+ ///
+ MsrValue = EfiReadMsr (EFI_MSR_POWER_CTL);
+ if (((UINT32)MsrValue & BIT18) != BIT18) {
+ DEBUG ((EFI_D_ERROR, "CPPC not supported in this CPU. (no Energy Efficient Policy capability) \n"));
+ return EFI_SUCCESS;
+ }
+
+ gST = SystemTable;
+ gDS = NULL;
+ Status = EfiGetSystemConfigurationTable (&gEfiDxeServicesTableGuid, (VOID**) &gDS);
+
+ ///
+ /// Allocate 4kb of runtime memory.
+ ///
+ Status = (gBS->AllocatePool) (EfiACPIMemoryNVS, CPPC_SIZE, &MemoryPointer);
+ if (EFI_ERROR (Status)) {
+ DEBUG ((EFI_D_ERROR, "CPPC: No Memory Buffer available.\n"));
+ ASSERT_EFI_ERROR(Status);
+ return Status;
+ } else {
+ mCppcBaseAddressMem = (EFI_PHYSICAL_ADDRESS) MemoryPointer;
+ ZeroMem ((VOID *)(UINTN)mCppcBaseAddressMem, CPPC_SIZE);
+ DEBUG((EFI_D_ERROR, "CPPC: PCCA memory buffer address: %x\n", mCppcBaseAddressMem));
+ }
+
+ ///
+ /// Add the Platform Communications Channel Table signature.
+ ///
+ CopyMem ((VOID *)(UINTN)mCppcBaseAddressMem, "PCC" , 3);
+
+ ///
+ /// Load the SSDT Table for the CPPC ACPI objects.
+ ///
+ LoadAcpiTables ();
+
+ ///
+ /// Load the ACPI 5.0 PCC Table.
+ ///
+ LoadAcpiTablesPcct ();
+
+ ///
+ /// Load the ACPI 5.0 _CPC objects.
+ ///
+ LoadAcpiTablesCpc ();
+
+ return EFI_SUCCESS;
+}
+
+VOID
+LoadAcpiTables(
+ VOID
+ )
+/**
+@brief
+ This procedure loads the CPPC SSDT table.
+
+ @param[in] None
+
+ @retval None
+
+**/
+{
+ EFI_STATUS Status;
+ EFI_HANDLE *HandleBuffer;
+ UINTN NumberOfHandles;
+ UINTN Index;
+ EFI_FIRMWARE_VOLUME_PROTOCOL *FwVol;
+ EFI_ACPI_TABLE_PROTOCOL *AcpiTable;
+ INTN Instance;
+ EFI_ACPI_COMMON_HEADER *Table;
+ UINTN Size;
+ EFI_FV_FILETYPE FileType;
+ EFI_FV_FILE_ATTRIBUTES Attributes;
+ UINT32 FvStatus;
+ EFI_ACPI_DESCRIPTION_HEADER *TableHeader;
+ UINTN TableHandle;
+ EFI_ACPI_TABLE_VERSION Version;
+ BOOLEAN LoadTable;
+ NAME_LAYOUT *NamePtr;
+ UINT8 *CurrPtr;
+ UINT32 *Signature;
+ UINT8 UpdateCounter;
+
+ FwVol = NULL;
+ Table = NULL;
+
+ ///
+ /// Locate FV protocol.
+ ///
+ Status = gBS->LocateHandleBuffer (
+ ByProtocol,
+ &gEfiFirmwareVolumeProtocolGuid,
+ NULL,
+ &NumberOfHandles,
+ &HandleBuffer
+ );
+ ASSERT_EFI_ERROR (Status);
+
+ ///
+ /// Look for FV with ACPI storage file
+ ///
+ for (Index = 0; Index < NumberOfHandles; Index++) {
+
+ ///
+ /// Get the protocol on this handle
+ /// This should not fail because of LocateHandleBuffer
+ ///
+ Status = gBS->HandleProtocol (
+ HandleBuffer[Index],
+ &gEfiFirmwareVolumeProtocolGuid,
+ (VOID **) &FwVol
+ );
+ ASSERT_EFI_ERROR (Status);
+
+ if ((Status == EFI_SUCCESS) && (FwVol != NULL)) {
+ ///
+ /// See if it has the ACPI storage file
+ ///
+ Size = 0;
+ FvStatus = 0;
+ Status = FwVol->ReadFile (
+ FwVol,
+ &gCppcAcpiTableStorageGuid,
+ NULL,
+ &Size,
+ &FileType,
+ &Attributes,
+ &FvStatus
+ );
+
+ ///
+ /// If we found it, then we are done
+ ///
+ if (Status == EFI_SUCCESS) {
+ break;
+ }
+ }
+ }
+
+ ///
+ /// Our exit status is determined by the success of the previous operations
+ /// If the protocol was found, Instance already points to it.
+ ///
+ /// Free any allocated buffers
+ ///
+ FreePool (HandleBuffer);
+
+ ///
+ /// Sanity check that we found our data file
+ ///
+ ASSERT (FwVol);
+ if (FwVol == NULL) {
+ return;
+ }
+
+ ///
+ /// By default, a table belongs in all ACPI table versions published.
+ ///
+ Version = EFI_ACPI_TABLE_VERSION_1_0B | EFI_ACPI_TABLE_VERSION_2_0 | EFI_ACPI_TABLE_VERSION_3_0;
+
+ ///
+ /// Find the Table protocol
+ ///
+ Status = gBS->LocateProtocol (&gEfiAcpiTableProtocolGuid, NULL, (VOID **) &AcpiTable);
+
+ ///
+ /// Read tables from the storage file.
+ ///
+ Instance = 0;
+
+ while (Status == EFI_SUCCESS) {
+ ///
+ /// Read the ACPI tables
+ ///
+ Status = FwVol->ReadSection (
+ FwVol,
+ &gCppcAcpiTableStorageGuid,
+ EFI_SECTION_RAW,
+ Instance,
+ (VOID **) &Table,
+ &Size,
+ &FvStatus
+ );
+
+ if (!EFI_ERROR (Status)) {
+
+ LoadTable = FALSE;
+ TableHeader = (EFI_ACPI_DESCRIPTION_HEADER *) Table;
+
+ switch (((EFI_ACPI_DESCRIPTION_HEADER*) TableHeader)->OemTableId) {
+
+ case EFI_SIGNATURE_64 ('C', 'p', 'p', 'c', 'T', 'a', 'b', 'l'):
+ ///
+ /// This is Cppc SSDT. Cppc should be enabled if we reach here so load the table.
+ ///
+ LoadTable = TRUE;
+ DEBUG ((EFI_D_ERROR, "CPPC: Found Cppc SSDT signature.\n"));
+
+ UpdateCounter = 3; // Number of objects to initialize.
+ for (CurrPtr = (UINT8 *) TableHeader; ((CurrPtr <= ((UINT8 *) TableHeader + TableHeader->Length))) && UpdateCounter !=0; CurrPtr++) {
+ Signature = (UINT32 *) (CurrPtr + 1);
+ ///
+ /// Patch PCCA with the address of the CPPC shared memory buffer.
+ ///
+ if ((*CurrPtr == AML_NAME_OP) && (*Signature == EFI_SIGNATURE_32 ('P', 'C', 'C', 'A'))) {
+ NamePtr = (NAME_LAYOUT *) CurrPtr;
+ if (mCppcBaseAddressMem != 0){
+ NamePtr->Value = (UINT32) mCppcBaseAddressMem;
+ }
+ UpdateCounter--;
+ DEBUG((EFI_D_ERROR, "CPPC: PCCA pointer updated in SSDT: %x\n", mCppcBaseAddressMem));
+ }
+ ///
+ /// Patch PCCS with the size of the CPPC shared memory buffer.
+ ///
+ if ((*CurrPtr == AML_NAME_OP) && (*Signature == EFI_SIGNATURE_32 ('P', 'C', 'C', 'S'))) {
+ NamePtr = (NAME_LAYOUT *) CurrPtr;
+ NamePtr->Value = (UINT32) CPPC_SIZE;
+ UpdateCounter--;
+ DEBUG((EFI_D_ERROR, "CPPC: PCCS length updated in SSDT: %x\n", CPPC_SIZE));
+ }
+ ///
+ /// Patch PENB with the CPPC Enable/Disable Flag.
+ ///
+ if ((*CurrPtr == AML_NAME_OP) && (*Signature == EFI_SIGNATURE_32 ('P', 'E', 'N', 'B'))) {
+ NamePtr = (NAME_LAYOUT *) CurrPtr;
+ NamePtr->Value = (UINT32) mAcpiPlatformPolicyProtocol->EnableCppc;
+ UpdateCounter--;
+ DEBUG((EFI_D_ERROR, "CPPC: PENB updated in SSDT: %x\n", (UINT32) mAcpiPlatformPolicyProtocol->EnableCppc));
+ }
+ }
+ break;
+
+ default:
+ break;
+ }
+
+ ///
+ /// Add the table
+ ///
+ if (LoadTable) {
+ TableHandle = 0;
+ Status = AcpiTable->InstallAcpiTable (
+ AcpiTable,
+ Table,
+ Table->Length,
+ &TableHandle
+ );
+ }
+
+ ///
+ /// Increment the instance
+ ///
+ Instance++;
+ Table = NULL;
+ }
+ }
+}
+
+VOID
+LoadAcpiTablesPcct(
+ VOID
+ )
+/**
+@brief
+ This procedure loads the ACPI 5.0 PCCT table.
+
+ @param[in] None
+
+ @retval None
+
+**/
+{
+ EFI_STATUS Status;
+ EFI_HANDLE *HandleBuffer;
+ UINTN NumberOfHandles;
+ UINTN Index;
+ EFI_FIRMWARE_VOLUME_PROTOCOL *FwVol;
+ EFI_ACPI_TABLE_PROTOCOL *AcpiTable;
+ INTN Instance;
+ EFI_ACPI_COMMON_HEADER *Table;
+ UINTN Size;
+ EFI_FV_FILETYPE FileType;
+ EFI_FV_FILE_ATTRIBUTES Attributes;
+ UINT32 FvStatus;
+ EFI_ACPI_DESCRIPTION_HEADER *TableHeader;
+ UINTN TableHandle;
+ EFI_ACPI_TABLE_VERSION Version;
+ BOOLEAN LoadTable;
+ EFI_ACPI_5_0_PLATFORM_COMMUNICATION_CHANNEL_TABLE_HEADER *PcctHeaderPtr;
+ EFI_ACPI_5_0_PCCT_SUBSPACE_GENERIC *PcctPtr;
+ UINT8 *CurrPtr;
+ UINT32 *Signature;
+ UINT8 UpdateCounter;
+
+ FwVol = NULL;
+ Table = NULL;
+
+ ///
+ /// Locate FV protocol.
+ ///
+ Status = gBS->LocateHandleBuffer (
+ ByProtocol,
+ &gEfiFirmwareVolumeProtocolGuid,
+ NULL,
+ &NumberOfHandles,
+ &HandleBuffer
+ );
+ ASSERT_EFI_ERROR (Status);
+
+ ///
+ /// Look for FV with ACPI storage file
+ ///
+ for (Index = 0; Index < NumberOfHandles; Index++) {
+
+ ///
+ /// Get the protocol on this handle
+ /// This should not fail because of LocateHandleBuffer
+ ///
+ Status = gBS->HandleProtocol (
+ HandleBuffer[Index],
+ &gEfiFirmwareVolumeProtocolGuid,
+ (VOID **) &FwVol
+ );
+ ASSERT_EFI_ERROR (Status);
+
+ if ((Status == EFI_SUCCESS) && (FwVol != NULL)) {
+ ///
+ /// See if it has the ACPI storage file
+ ///
+ Size = 0;
+ FvStatus = 0;
+ Status = FwVol->ReadFile (
+ FwVol,
+ &gCppcAcpiTableStorageGuid,
+ NULL,
+ &Size,
+ &FileType,
+ &Attributes,
+ &FvStatus
+ );
+
+ ///
+ /// If we found it, then we are done
+ ///
+ if (Status == EFI_SUCCESS) {
+ break;
+ }
+ }
+ }
+
+ ///
+ /// Our exit status is determined by the success of the previous operations
+ /// If the protocol was found, Instance already points to it.
+ ///
+ /// Free any allocated buffers
+ ///
+ FreePool (HandleBuffer);
+
+ ///
+ /// Sanity check that we found our data file
+ ///
+ ASSERT (FwVol);
+ if (FwVol == NULL) {
+ return;
+ }
+
+ ///
+ /// By default, a table belongs in all ACPI table versions published.
+ ///
+ Version = EFI_ACPI_TABLE_VERSION_1_0B | EFI_ACPI_TABLE_VERSION_2_0 | EFI_ACPI_TABLE_VERSION_3_0;
+
+ ///
+ /// Find the Table protocol
+ ///
+ Status = gBS->LocateProtocol (&gEfiAcpiTableProtocolGuid, NULL, (VOID **) &AcpiTable);
+
+ ///
+ /// Read tables from the storage file.
+ ///
+ Instance = 0;
+
+ while (Status == EFI_SUCCESS) {
+ ///
+ /// Read the ACPI tables
+ ///
+ Status = FwVol->ReadSection (
+ FwVol,
+ &gCppcAcpiTableStorageGuid,
+ EFI_SECTION_RAW,
+ Instance,
+ (VOID **) &Table,
+ &Size,
+ &FvStatus
+ );
+
+ if (!EFI_ERROR (Status)) {
+
+ LoadTable = FALSE;
+ TableHeader = (EFI_ACPI_DESCRIPTION_HEADER *) Table;
+
+ switch (((EFI_ACPI_DESCRIPTION_HEADER*) TableHeader)->OemTableId) {
+
+ case EFI_SIGNATURE_64 ('P', 'c', 'c', 't', 'T', 'a', 'b', 'l'):
+ ///
+ /// This is PCCT. Cppc should be enabled if we reach here so load the table.
+ ///
+ LoadTable = TRUE;
+ DEBUG ((EFI_D_ERROR, "PCCT: Found PCCT signature.\n"));
+
+ UpdateCounter = 1; /// Number of objects to initialize.
+ for (CurrPtr = (UINT8 *) TableHeader; ((CurrPtr <= ((UINT8 *) TableHeader + TableHeader->Length))) && UpdateCounter !=0; CurrPtr++) {
+ Signature = (UINT32 *) (CurrPtr + 1);
+ ///
+ /// Patch the EFI_ACPI_5_0_PCCT_SUBSPACE_GENERIC structure.
+ ///
+ if ((*CurrPtr == AML_NAME_OP) && (*Signature == EFI_SIGNATURE_32 ('P', 'C', 'C', 'T'))) {
+ CurrPtr -= sizeof (EFI_ACPI_DESCRIPTION_HEADER); // backup the current pointer in order to use the PCCT header structure
+ PcctHeaderPtr = (EFI_ACPI_5_0_PLATFORM_COMMUNICATION_CHANNEL_TABLE_HEADER *) CurrPtr;
+ PcctHeaderPtr->Flags = (UINT32) mAcpiPlatformPolicyProtocol->EnableCppcPlatformSCI;
+ PcctHeaderPtr->Reserved = 0;
+
+ CurrPtr += sizeof (EFI_ACPI_5_0_PLATFORM_COMMUNICATION_CHANNEL_TABLE_HEADER);
+ PcctPtr = (EFI_ACPI_5_0_PCCT_SUBSPACE_GENERIC *) CurrPtr;
+ PcctPtr->Type = 0x0;
+ PcctPtr->Length = 62;
+ PcctPtr->BaseAddress = mCppcBaseAddressMem; /// Shared memory address
+ PcctPtr->AddressLength = CPPC_SIZE; /// sizeof(Shared memory) in bytes
+
+ PcctPtr->DoorbellRegister.AddressSpaceId = 1; /// IO address type
+ PcctPtr->DoorbellRegister.RegisterBitWidth = 8; /// byte
+ PcctPtr->DoorbellRegister.RegisterBitOffset = 0x0; /// offset=0
+ PcctPtr->DoorbellRegister.AccessSize = 1; /// byte access
+ PcctPtr->DoorbellRegister.Address = MmioRead16 (MmPciExpressAddress (0,0, PCI_DEV_NUM_ICH_LPC, 0, R_ACPI_BAR)) &~BIT0;
+ PcctPtr->DoorbellRegister.Address += R_ACPI_GPE_CNTL; /// PMBASE + GPE_CNTL register offset
+ PcctPtr->DoorbellPreserve = 0xFD; /// preserve all bits except bit 1
+ PcctPtr->DoorbellWrite = 2; /// write bit 1 = 1 to trigger GPE
+ PcctPtr->NominalLatency = 5000; /// 5ms
+ PcctPtr->MaximumPeriodicAccessRate = 0x0;
+ PcctPtr->MinimumRequestTurnaroundTime = 0x0;
+
+ UpdateCounter--;
+ DEBUG((EFI_D_ERROR, "PCCT: Patch the EFI_ACPI_5_0_PCCT_SUBSPACE_GENERIC structure.\n"));
+ }
+ }
+ break;
+
+ default:
+ break;
+ }
+
+ ///
+ /// Add the table
+ ///
+ if (LoadTable) {
+ TableHandle = 0;
+ Status = AcpiTable->InstallAcpiTable (
+ AcpiTable,
+ Table,
+ Table->Length,
+ &TableHandle
+ );
+ }
+
+ ///
+ /// Increment the instance
+ ///
+ Instance++;
+ Table = NULL;
+ }
+ }
+}
+
+VOID
+LoadAcpiTablesCpc(
+ VOID
+ )
+/**
+@brief
+ Load ACPI SSDT tables.
+
+ @param[in] None
+
+ @retval None
+
+**/
+{
+ EFI_STATUS Status;
+ EFI_HANDLE *HandleBuffer;
+ UINTN NumberOfHandles;
+ UINTN Index;
+ EFI_FIRMWARE_VOLUME_PROTOCOL *FwVol;
+ EFI_ACPI_TABLE_PROTOCOL *AcpiTable;
+ INTN Instance;
+ EFI_ACPI_COMMON_HEADER *Table;
+ UINTN Size;
+ EFI_FV_FILETYPE FileType;
+ EFI_FV_FILE_ATTRIBUTES Attributes;
+ UINT32 FvStatus;
+ EFI_ACPI_DESCRIPTION_HEADER *TableHeader;
+ UINTN TableHandle;
+ EFI_ACPI_TABLE_VERSION Version;
+ BOOLEAN LoadTable;
+
+ FwVol = NULL;
+ Table = NULL;
+
+ ///
+ /// Locate FV protocol.
+ ///
+ Status = gBS->LocateHandleBuffer (
+ ByProtocol,
+ &gEfiFirmwareVolumeProtocolGuid,
+ NULL,
+ &NumberOfHandles,
+ &HandleBuffer
+ );
+ ASSERT_EFI_ERROR (Status);
+
+ ///
+ /// Look for FV with ACPI storage file
+ ///
+ for (Index = 0; Index < NumberOfHandles; Index++) {
+
+ ///
+ /// Get the protocol on this handle
+ /// This should not fail because of LocateHandleBuffer
+ ///
+ Status = gBS->HandleProtocol (
+ HandleBuffer[Index],
+ &gEfiFirmwareVolumeProtocolGuid,
+ (VOID **) &FwVol
+ );
+ ASSERT_EFI_ERROR (Status);
+
+ if ((Status == EFI_SUCCESS) && (FwVol != NULL)) {
+ ///
+ /// See if it has the ACPI storage file
+ ///
+ Size = 0;
+ FvStatus = 0;
+ Status = FwVol->ReadFile (
+ FwVol,
+ &gCppcAcpiTableStorageGuid,
+ NULL,
+ &Size,
+ &FileType,
+ &Attributes,
+ &FvStatus
+ );
+
+ ///
+ /// If we found it, then we are done
+ ///
+ if (Status == EFI_SUCCESS) {
+ break;
+ }
+ }
+ }
+
+ ///
+ /// Our exit status is determined by the success of the previous operations
+ /// If the protocol was found, Instance already points to it.
+ ///
+ /// Free any allocated buffers
+ ///
+ FreePool (HandleBuffer);
+
+ ///
+ /// Sanity check that we found our data file
+ ///
+ ASSERT (FwVol);
+ if (FwVol == NULL) {
+ return;
+ }
+
+ ///
+ /// By default, a table belongs in all ACPI table versions published.
+ ///
+ Version = EFI_ACPI_TABLE_VERSION_1_0B | EFI_ACPI_TABLE_VERSION_2_0 | EFI_ACPI_TABLE_VERSION_3_0;
+
+ ///
+ /// Find the Table protocol
+ ///
+ Status = gBS->LocateProtocol (&gEfiAcpiTableProtocolGuid, NULL, (VOID **) &AcpiTable);
+
+ ///
+ /// Read tables from the storage file.
+ ///
+ Instance = 0;
+
+ while (Status == EFI_SUCCESS) {
+ ///
+ /// Read the ACPI tables
+ ///
+ Status = FwVol->ReadSection (
+ FwVol,
+ &gCppcAcpiTableStorageGuid,
+ EFI_SECTION_RAW,
+ Instance,
+ (VOID **) &Table,
+ &Size,
+ &FvStatus
+ );
+
+ if (!EFI_ERROR (Status)) {
+
+ LoadTable = FALSE;
+ TableHeader = (EFI_ACPI_DESCRIPTION_HEADER *) Table;
+
+ switch (((EFI_ACPI_DESCRIPTION_HEADER*) TableHeader)->OemTableId) {
+
+ case EFI_SIGNATURE_64 ('C', 'p', 'c', '_', 'T', 'a', 'b', 'l'):
+ ///
+ /// This is the _CPC SSDT. Cppc should be enabled if we reach here so load the table.
+ ///
+ LoadTable = TRUE;
+ DEBUG ((EFI_D_ERROR, "CPPC: Found _CPC SSDT signature.\n"));
+ break;
+
+ default:
+ break;
+ }
+
+ ///
+ /// Add the table
+ ///
+ if (LoadTable) {
+ TableHandle = 0;
+ Status = AcpiTable->InstallAcpiTable (
+ AcpiTable,
+ Table,
+ Table->Length,
+ &TableHandle
+ );
+ }
+
+ ///
+ /// Increment the instance
+ ///
+ Instance++;
+ Table = NULL;
+ }
+ }
+}
+
+EFI_STATUS
+LocateSupportProtocol (
+ IN EFI_GUID *Protocol,
+ OUT VOID **Instance,
+ IN BOOLEAN Type
+ )
+/**
+ @brief
+ Locate the first instance of a protocol. If the protocol requested is an
+ FV protocol, then it will return the first FV that contains the ACPI table
+ storage file.
+
+ @param[in] The protocol to find.
+ @param[in] Return pointer to the first instance of the protocol
+ @param[in] TRUE if the desired protocol is a FV protocol
+
+ @retval EFI_SUCCESS - The function completed successfully.
+ @retval EFI_NOT_FOUND - The protocol could not be located.
+ @retval EFI_OUT_OF_RESOURCES - There are not enough resources to find the protocol.
+**/
+{
+ EFI_STATUS Status;
+ EFI_HANDLE *HandleBuffer;
+ UINTN NumberOfHandles;
+ EFI_FV_FILETYPE FileType;
+ UINT32 FvStatus;
+ EFI_FV_FILE_ATTRIBUTES Attributes;
+ UINTN Size;
+ UINTN i;
+
+ ///
+ /// Locate protocol.
+ ///
+ Status = gBS->LocateHandleBuffer (
+ ByProtocol,
+ Protocol,
+ NULL,
+ &NumberOfHandles,
+ &HandleBuffer
+ );
+ if (EFI_ERROR (Status)) {
+
+ ///
+ /// Defined errors at this time are not found and out of resources.
+ ///
+ return Status;
+ }
+
+ ///
+ /// Looking for FV with ACPI storage file
+ ///
+ for (i = 0; i < NumberOfHandles; i++) {
+
+ ///
+ /// Get the protocol on this handle
+ /// This should not fail because of LocateHandleBuffer
+ ///
+ Status = gBS->HandleProtocol (
+ HandleBuffer[i],
+ Protocol,
+ Instance
+ );
+ ASSERT_EFI_ERROR (Status);
+
+ if (!Type) {
+
+ ///
+ /// Not looking for the FV protocol, so find the first instance of the
+ /// protocol. There should not be any errors because our handle buffer
+ /// should always contain at least one or LocateHandleBuffer would have
+ /// returned not found.
+ ///
+ break;
+ }
+
+ ///
+ /// See if it has the ACPI storage file
+ ///
+ Size = 0;
+ FvStatus = 0;
+ Status = ((EFI_FIRMWARE_VOLUME_PROTOCOL *) (*Instance))->ReadFile (
+ *Instance,
+ &gCppcAcpiTableStorageGuid,
+ NULL,
+ &Size,
+ &FileType,
+ &Attributes,
+ &FvStatus
+ );
+
+ ///
+ /// If we found it, then we are done
+ ///
+ if (Status == EFI_SUCCESS) {
+ break;
+ }
+ }
+
+ ///
+ /// Our exit status is determined by the success of the previous operations
+ /// If the protocol was found, Instance already points to it.
+ ///
+ /// Free any allocated buffers
+ ///
+ FreePool (HandleBuffer);
+
+ return Status;
+}