| /** @file | |
| Processor power management initialization code. | |
| Copyright (c) 2013-2016 Intel Corporation. | |
| This program and the accompanying materials | |
| are licensed and made available under the terms and conditions of the BSD License | |
| which accompanies this distribution. The full text of the license may be found at | |
| http://opensource.org/licenses/bsd-license.php | |
| THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, | |
| WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. | |
| **/ | |
| #include "SmmPowerManagement.h" | |
| // | |
| // Global variables | |
| // | |
| extern EFI_ACPI_SDT_PROTOCOL *mAcpiSdt; | |
| extern EFI_ACPI_TABLE_PROTOCOL *mAcpiTable; | |
| extern EFI_GUID gPowerManagementAcpiTableStorageGuid; | |
| /** | |
| This function is the entry of processor power management initialization code. | |
| It initializes the processor's power management features based on the user | |
| configurations and hardware capabilities. | |
| **/ | |
| VOID | |
| PpmInit ( | |
| VOID | |
| ) | |
| { | |
| // | |
| // Processor Power Management Flags | |
| // | |
| mGlobalNvsAreaPtr->Cfgd = PcdGet32(PcdPpmFlags); | |
| // | |
| // Patch and publish power management related acpi tables | |
| // | |
| PpmPatchAndPublishAcpiTables(); | |
| } | |
| /** | |
| This function is to patch and publish power management related acpi tables. | |
| **/ | |
| VOID | |
| PpmPatchAndPublishAcpiTables ( | |
| VOID | |
| ) | |
| { | |
| // | |
| // Patch FADT table to enable C2,C3 | |
| // | |
| PpmPatchFadtTable(); | |
| // | |
| // Load all the power management acpi tables and patch IST table | |
| // | |
| PpmLoadAndPatchPMTables(); | |
| } | |
| /** | |
| This function is to patch PLvl2Lat and PLvl3Lat to enable C2, C3 support in OS. | |
| **/ | |
| VOID | |
| PpmPatchFadtTable ( | |
| VOID | |
| ) | |
| { | |
| EFI_STATUS Status; | |
| EFI_ACPI_DESCRIPTION_HEADER *Table; | |
| EFI_ACPI_SDT_HEADER *CurrentTable; | |
| EFI_ACPI_TABLE_VERSION Version; | |
| UINTN Index; | |
| UINTN Handle; | |
| // | |
| // Scan all the acpi tables to find FADT 2.0 | |
| // | |
| Index = 0; | |
| do { | |
| Status = mAcpiSdt->GetAcpiTable ( | |
| Index, | |
| &CurrentTable, | |
| &Version, | |
| &Handle | |
| ); | |
| if (Status == EFI_NOT_FOUND) { | |
| break; | |
| } | |
| ASSERT_EFI_ERROR (Status); | |
| Index++; | |
| } while (CurrentTable->Signature != EFI_ACPI_3_0_FIXED_ACPI_DESCRIPTION_TABLE_SIGNATURE || CurrentTable->Revision != 0x03); | |
| ASSERT (CurrentTable->Signature == EFI_ACPI_3_0_FIXED_ACPI_DESCRIPTION_TABLE_SIGNATURE); | |
| Table = NULL; | |
| Status = gBS->AllocatePool (EfiBootServicesData, CurrentTable->Length, (VOID **) &Table); | |
| ASSERT (Table != NULL); | |
| CopyMem (Table, CurrentTable, CurrentTable->Length); | |
| // | |
| // Update the ACPI table and recalculate checksum | |
| // | |
| Status = mAcpiTable->UninstallAcpiTable (mAcpiTable, Handle); | |
| if (EFI_ERROR (Status)) { | |
| // | |
| // Should not get an error here ever, but abort if we do. | |
| // | |
| return ; | |
| } | |
| // | |
| // Update the check sum | |
| // It needs to be zeroed before the checksum calculation | |
| // | |
| ((EFI_ACPI_SDT_HEADER *)Table)->Checksum = 0; | |
| ((EFI_ACPI_SDT_HEADER *)Table)->Checksum = | |
| CalculateCheckSum8 ((VOID *)Table, Table->Length); | |
| // | |
| // Add the table | |
| // | |
| Status = mAcpiTable->InstallAcpiTable ( | |
| mAcpiTable, | |
| Table, | |
| Table->Length, | |
| &Handle | |
| ); | |
| ASSERT_EFI_ERROR (Status); | |
| gBS->FreePool (Table); | |
| } | |
| VOID | |
| SsdtTableUpdate ( | |
| IN OUT EFI_ACPI_DESCRIPTION_HEADER *TableHeader | |
| ) | |
| /*++ | |
| Routine Description: | |
| Update the SSDT table | |
| Arguments: | |
| Table - The SSDT table to be patched | |
| Returns: | |
| None | |
| --*/ | |
| { | |
| UINT8 *CurrPtr; | |
| UINT8 *SsdtPointer; | |
| UINT32 *Signature; | |
| // | |
| // Loop through the ASL looking for values that we must fix up. | |
| // | |
| CurrPtr = (UINT8 *) TableHeader; | |
| for (SsdtPointer = CurrPtr; | |
| SsdtPointer <= (CurrPtr + ((EFI_ACPI_COMMON_HEADER *) CurrPtr)->Length); | |
| SsdtPointer++ | |
| ) | |
| { | |
| Signature = (UINT32 *) SsdtPointer; | |
| if ((*Signature) == SIGNATURE_32 ('P', 'M', 'B', 'A')) { | |
| switch (*(Signature+1)) { | |
| case (SIGNATURE_32 ('L', 'V', 'L', '0')): | |
| Signature[0] = PcdGet16(PcdPmbaIoBaseAddress); | |
| Signature[1] = 0; | |
| break; | |
| case (SIGNATURE_32 ('L', 'V', 'L', '2')): | |
| Signature[0] = PcdGet16(PcdPmbaIoLVL2); | |
| Signature[1] = 0; | |
| break; | |
| } | |
| } | |
| } | |
| } | |
| EFI_STATUS | |
| LocateSupportProtocol ( | |
| IN EFI_GUID *Protocol, | |
| OUT VOID **Instance, | |
| IN UINT32 Type | |
| ) | |
| /*++ | |
| Routine Description: | |
| 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. | |
| Arguments: | |
| Protocol The protocol to find. | |
| Instance Return pointer to the first instance of the protocol | |
| Returns: | |
| EFI_SUCCESS The function completed successfully. | |
| EFI_NOT_FOUND The protocol could not be located. | |
| 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; | |
| FvStatus = 0; | |
| // | |
| // 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 | |
| // | |
| Status = ((EFI_FIRMWARE_VOLUME2_PROTOCOL*) (*Instance))->ReadFile (*Instance, | |
| &gPowerManagementAcpiTableStorageGuid, | |
| 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 | |
| // | |
| gBS->FreePool (HandleBuffer); | |
| return Status; | |
| } | |
| /** | |
| This function is to load all the power management acpi tables and patch IST table. | |
| **/ | |
| VOID | |
| PpmLoadAndPatchPMTables ( | |
| VOID | |
| ) | |
| { | |
| EFI_FIRMWARE_VOLUME2_PROTOCOL *FwVol; | |
| EFI_STATUS Status; | |
| INTN Instance; | |
| EFI_ACPI_COMMON_HEADER *CurrentTable; | |
| UINTN TableHandle; | |
| UINT32 FvStatus; | |
| UINTN Size; | |
| Status = LocateSupportProtocol (&gEfiFirmwareVolume2ProtocolGuid, (VOID**)&FwVol, 1); | |
| if (EFI_ERROR (Status)) { | |
| return; | |
| } | |
| // | |
| // Read tables from the storage file. | |
| // | |
| Instance = 0; | |
| CurrentTable = NULL; | |
| while (Status == EFI_SUCCESS) { | |
| Status = FwVol->ReadSection ( | |
| FwVol, | |
| &gPowerManagementAcpiTableStorageGuid, | |
| EFI_SECTION_RAW, | |
| Instance, | |
| (VOID**)&CurrentTable, | |
| &Size, | |
| &FvStatus | |
| ); | |
| if (!EFI_ERROR(Status)) { | |
| SsdtTableUpdate ((EFI_ACPI_DESCRIPTION_HEADER *) CurrentTable); | |
| // | |
| // Update the check sum | |
| // It needs to be zeroed before the checksum calculation | |
| // | |
| ((EFI_ACPI_SDT_HEADER *)CurrentTable)->Checksum = 0; | |
| ((EFI_ACPI_SDT_HEADER *)CurrentTable)->Checksum = (UINT8) | |
| CalculateCheckSum8 ((VOID *)CurrentTable, CurrentTable->Length); | |
| // | |
| // Add the table | |
| // | |
| TableHandle = 0; | |
| Status = mAcpiTable->InstallAcpiTable ( | |
| mAcpiTable, | |
| CurrentTable, | |
| CurrentTable->Length, | |
| &TableHandle | |
| ); | |
| ASSERT_EFI_ERROR (Status); | |
| // | |
| // Increment the instance | |
| // | |
| Instance++; | |
| CurrentTable = NULL; | |
| } | |
| } | |
| } |