alder_lake_bios/Insyde/InsydeModulePkg/Universal/Acpi/AcpiPlatformDxe/FacsUpdateCommon.c

602 lines
18 KiB
C

/** @file
;******************************************************************************
;* Copyright (c) 2013 - 2020, Insyde Software Corp. All Rights Reserved.
;*
;* You may not reproduce, distribute, publish, display, perform, modify, adapt,
;* transmit, broadcast, present, recite, release, license or otherwise exploit
;* any part of this publication in any form, by any means, without the prior
;* written permission of Insyde Software Corporation.
;*
;******************************************************************************
*/
#include <PiDxe.h>
#include <Guid/H2OCp.h>
#include <Library/UefiLib.h>
#include <Library/BaseLib.h>
#include <Library/UefiBootServicesTableLib.h>
#include <Library/UefiRuntimeServicesTableLib.h>
#include <Library/BaseMemoryLib.h>
#include <Library/DebugLib.h>
#include <Library/PcdLib.h>
#include <Library/DxeOemSvcKernelLib.h>
#include <Library/PciExpressLib.h>
#include <Library/KernelConfigLib.h>
#include <Library/BvdtLib.h>
#include <Library/H2OCpLib.h>
#include <Library/MemoryAllocationLib.h>
#include <Protocol/AcpiSupport.h>
#include <Protocol/AcpiS3Save.h>
#include <Protocol/GraphicsOutput.h>
#include <IndustryStandard/Acpi.h>
#include <IndustryStandard/Pci22.h>
#include <KernelSetupConfig.h>
EFI_ACPI_S3_SAVE mS3Save;
/**
To get PersistentMemory Pages.
@param[out] PersistentMemPages PersistentMemory Pages
@return EFI_SUCCESS Get PersistentMemory Pages success
@return Other Get PersistentMemory Pages fail.
**/
EFI_STATUS
GetPersistentMemoryPages (
OUT UINT64 *PersistentMemPages
)
{
EFI_STATUS Status;
EFI_MEMORY_DESCRIPTOR *EfiMemoryMap;
UINTN EfiMapKey;
UINTN EfiDescriptorSize;
UINTN EfiMemoryMapSize;
EFI_MEMORY_DESCRIPTOR *EfiMemoryMapEnd;
EFI_MEMORY_DESCRIPTOR *EfiEntry;
UINT32 EfiDescriptorVersion;
EfiMemoryMapSize = 0;
EfiMemoryMap = NULL;
Status = gBS->GetMemoryMap (
&EfiMemoryMapSize,
EfiMemoryMap,
&EfiMapKey,
&EfiDescriptorSize,
&EfiDescriptorVersion
);
while (Status == EFI_BUFFER_TOO_SMALL) {
EfiMemoryMap = AllocatePool (EfiMemoryMapSize);
if (EfiMemoryMap == NULL) {
return EFI_OUT_OF_RESOURCES;
}
Status = gBS->GetMemoryMap (
&EfiMemoryMapSize,
EfiMemoryMap,
&EfiMapKey,
&EfiDescriptorSize,
&EfiDescriptorVersion
);
if (EFI_ERROR (Status)) {
FreePool (EfiMemoryMap);
EfiMemoryMap = NULL;
}
}
if (EfiMemoryMap == NULL) {
return EFI_ABORTED;
}
EfiEntry = EfiMemoryMap;
EfiMemoryMapEnd = (EFI_MEMORY_DESCRIPTOR *) ((UINT8 *) EfiMemoryMap + EfiMemoryMapSize);
*PersistentMemPages = 0;
while (EfiEntry < EfiMemoryMapEnd) {
if (EfiEntry->Type == EfiPersistentMemory){
*PersistentMemPages += EfiEntry->NumberOfPages;
}
EfiEntry = NEXT_MEMORY_DESCRIPTOR (EfiEntry, EfiDescriptorSize);
}
FreePool (EfiMemoryMap);
return Status;
}
/**
To get secure boot state hardware signature value.
@return UINT32 Hardware signature value for secure boot state.
**/
STATIC
UINT32
GetSecureBootHardwareSignatureValue (
VOID
)
{
UINT8 SecureBoot;
UINTN BufferSize;
EFI_STATUS Status;
UINT8 Buffer[21];
UINT32 Crc32;
//
// Using L"SecureBoot" and variable data to calculate CRC32 value fro secure boot state hardware
// signature to identify the differences between other hardware signature settings.
//
BufferSize = sizeof (UINT8);
Status = gRT->GetVariable (L"SecureBoot", &gEfiGlobalVariableGuid, NULL, &BufferSize, &SecureBoot);
if (EFI_ERROR (Status)) {
SecureBoot = 0xFF;
}
CopyMem (Buffer, L"SecureBoot", StrLen (L"SecureBoot") * sizeof (CHAR16));
Buffer [StrLen (L"SecureBoot") * sizeof (CHAR16)] = SecureBoot;
Crc32 = 0;
Status = gBS->CalculateCrc32 (Buffer, StrLen (L"SecureBoot") * sizeof (CHAR16) + sizeof (UINT8), &Crc32);
ASSERT_EFI_ERROR (Status);
return Crc32;
}
/**
To get GOP resolution hardware signature value.
@return Hardware signature value for GOP resolution or zero if there is no GOP on system.
**/
UINT32
GetGopResolutionHardwareSignatureValue (
VOID
)
{
EFI_STATUS Status;
EFI_GRAPHICS_OUTPUT_PROTOCOL *GraphicsOutput;
Status = gBS->HandleProtocol (gST->ConsoleOutHandle, &gEfiGraphicsOutputProtocolGuid, (VOID **) &GraphicsOutput);
if (EFI_ERROR(Status)) {
return 0;
}
return (GraphicsOutput->Mode->Info->HorizontalResolution * 2) + GraphicsOutput->Mode->Info->VerticalResolution;
}
/**
To get TPM hardware signature value.
@return Hardware signature value for TPM
**/
UINT32
GetTpmHardwareSignatureValue (
VOID
)
{
EFI_STATUS Status;
UINT32 Crc32;
Crc32 = 0;
Status = gBS->CalculateCrc32 ((VOID *)PcdGetPtr (PcdTpmInstanceGuid), sizeof (EFI_GUID), &Crc32);
ASSERT_EFI_ERROR (Status);
return Crc32;
}
/**
To get BIOS version hardware signature value.
@return UINT32 Hardware signature value for BIOS version.
**/
STATIC
UINT32
GetBiosVersionSignatureValue (
VOID
)
{
UINTN StrLen;
CHAR16 Str[BVDT_MAX_STR_SIZE];
EFI_STATUS Status;
UINT32 Crc32;
StrLen = BVDT_MAX_STR_SIZE;
Status = GetBvdtInfo ((BVDT_TYPE) BvdtBiosVer, &StrLen, Str);
if (EFI_ERROR (Status)) {
return 0;
}
Crc32 = 0;
Status = gBS->CalculateCrc32 (Str, StrLen * sizeof (CHAR16), &Crc32);
ASSERT_EFI_ERROR (Status);
return Crc32;
}
/**
To determine Hardware Signature by kernel default algorithm.
@param[out] HardwareSignature Value of Hardware Signature.
@retval None.
**/
VOID
DefaultUpdateAcpiFacsHardwareSignature (
OUT UINT32 *HardwareSignature
)
{
EFI_STATUS Status;
UINTN Bus;
UINTN BusLimit;
UINTN Device;
UINTN DeviceLimit;
UINTN Function;
UINTN FunctionLimit;
UINT16 ClassCode;
UINT8 HeaderType;
UINT8 Value8;
UINT64 PersistentMemPages;
Bus = 0;
BusLimit = 0;
Device = 0;
DeviceLimit = 0;
Function = 0;
FunctionLimit = 0;
ClassCode = 0;
HeaderType = 0;
Value8 = 0;
//
// Set Hardware Signature, the algorithm to calculate signature value depends on customization.
//
*HardwareSignature = 0;
BusLimit = 1;
for ( Bus = 0 ; Bus <= BusLimit ; Bus++ ) {
for ( Device = 0 ; Device <= 0x1F ; Device++ ) {
FunctionLimit = 7;
for ( Function = 0 ; Function <= FunctionLimit ; Function++ ) {
//
// 1. Check header type & class code
//
HeaderType = PciExpressRead8 (PCI_EXPRESS_LIB_ADDRESS (
Bus,
Device,
Function,
PCI_HEADER_TYPE_OFFSET));
ClassCode = PciExpressRead16 (PCI_EXPRESS_LIB_ADDRESS (
Bus,
Device,
Function,
PCI_CLASSCODE_OFFSET + 1));
if (Function == 0) {
if (ClassCode == 0xFFFF) {
break;
}
if (!(HeaderType & HEADER_TYPE_MULTI_FUNCTION)) {
FunctionLimit = 0;
}
}
if (ClassCode == 0xFFFF) {
continue;
}
if (ClassCode == ((PCI_CLASS_BRIDGE << 8) | PCI_CLASS_BRIDGE_P2P)) {
Value8 = PciExpressRead8 (PCI_EXPRESS_LIB_ADDRESS (
Bus,
Device,
Function,
PCI_BRIDGE_SUBORDINATE_BUS_REGISTER_OFFSET));
if (Value8 > BusLimit) {
BusLimit = Value8;
}
}
*HardwareSignature += PciExpressRead16 (PCI_EXPRESS_LIB_ADDRESS (
Bus,
Device,
Function,
PCI_VENDOR_ID_OFFSET));
*HardwareSignature += PciExpressRead16 (PCI_EXPRESS_LIB_ADDRESS (
Bus,
Device,
Function,
PCI_DEVICE_ID_OFFSET));
*HardwareSignature += PciExpressRead8 (PCI_EXPRESS_LIB_ADDRESS (
Bus,
Device,
Function,
PCI_REVISION_ID_OFFSET));
}
}
}
*HardwareSignature += GetSecureBootHardwareSignatureValue ();
*HardwareSignature += GetGopResolutionHardwareSignatureValue ();
*HardwareSignature += GetTpmHardwareSignatureValue ();
*HardwareSignature += GetBiosVersionSignatureValue ();
//
// ACPI 6.0 add PersistentMemory included FACS hardware signature.
//
PersistentMemPages = 0;
Status = GetPersistentMemoryPages (&PersistentMemPages);
if (!EFI_ERROR (Status)) {
*HardwareSignature += (UINT32) PersistentMemPages;
}
}
/**
Internal function to initialize H2O_BDS_CP_UPDATE_ACPI_FACS_DATA data and trigger gH2OBdsCpUpdateAcpiFacsGuid checkpoint.
@param[in] AcpiFacs Pointer to ACPI FACS table.
@retval EFI_SUCCESS Trigger gH2OBdsCpLegacyPrepareToBootAfterGuid checkpoint successfully.
@return Other Other error occurred while triggering gH2OBdsCpLegacyPrepareToBootAfterGuid checkpoint.
**/
STATIC
EFI_STATUS
TriggerBdsCpUpdateAcpiFacs (
IN EFI_ACPI_1_0_FIRMWARE_ACPI_CONTROL_STRUCTURE *AcpiFacs
)
{
EFI_STATUS Status;
H2O_BDS_CP_UPDATE_ACPI_FACS_DATA CpData;
EFI_ACPI_1_0_FIRMWARE_ACPI_CONTROL_STRUCTURE AcpiFacsBuf;
CopyMem (&AcpiFacsBuf, AcpiFacs, sizeof (EFI_ACPI_1_0_FIRMWARE_ACPI_CONTROL_STRUCTURE));
CpData.Size = sizeof (H2O_BDS_CP_UPDATE_ACPI_FACS_DATA);
CpData.Status = H2O_CP_TASK_NORMAL;
CpData.AcpiFacs = &AcpiFacsBuf;
DEBUG_CP ((DEBUG_INFO, "Checkpoint Trigger: %g\n", &gH2OBdsCpUpdateAcpiFacsGuid));
Status = H2OCpTrigger (&gH2OBdsCpUpdateAcpiFacsGuid, &CpData);
DEBUG_CP ((DEBUG_INFO, "Checkpoint Result: %x\n", CpData.Status));
if (CpData.Status == H2O_CP_TASK_UPDATE) {
CopyMem (AcpiFacs, CpData.AcpiFacs, sizeof (EFI_ACPI_1_0_FIRMWARE_ACPI_CONTROL_STRUCTURE));
}
return Status;
}
/**
Update FACS Hardware Signature
@return None.
**/
VOID
EFIAPI
UpdateFacsHardwareSignatureFn (
VOID
)
{
EFI_STATUS Status;
EFI_ACPI_DESCRIPTION_HEADER *Table;
INTN Index;
UINTN Handle;
EFI_ACPI_TABLE_VERSION Version;
EFI_ACPI_SUPPORT_PROTOCOL *AcpiSupport;
Index = 0;
Status = gBS->LocateProtocol (&gEfiAcpiSupportProtocolGuid, NULL, (VOID **)&AcpiSupport);
ASSERT_EFI_ERROR (Status);
//
// Search for FACS table
//
while (1) {
Table = NULL;
Status = AcpiSupport->GetAcpiTable (AcpiSupport, Index, (VOID **)&Table, &Version, &Handle);
if (Status == EFI_NOT_FOUND) {
break;
}
//
// Updates once the table found
//
if (Table->Signature == EFI_ACPI_1_0_FIRMWARE_ACPI_CONTROL_STRUCTURE_SIGNATURE) {
//
// Update Hardware Signature with kernel default algorithm.
//
DefaultUpdateAcpiFacsHardwareSignature (
&(((EFI_ACPI_1_0_FIRMWARE_ACPI_CONTROL_STRUCTURE*)(UINTN)Table)->HardwareSignature)
);
if (FeaturePcdGet (PcdH2OBdsCpUpdateAcpiFacsSupported)) {
TriggerBdsCpUpdateAcpiFacs ((EFI_ACPI_1_0_FIRMWARE_ACPI_CONTROL_STRUCTURE*)(UINTN)Table);
}
//
// OemServices for updating Hardware Signature.
//
DEBUG_OEM_SVC ((DEBUG_INFO, "OemKernelServices Call: OemSvcUpdateAcpiFacsHardwareSignature \n"));
Status = OemSvcUpdateAcpiFacsHardwareSignature (
&(((EFI_ACPI_1_0_FIRMWARE_ACPI_CONTROL_STRUCTURE*)(UINTN)Table)->HardwareSignature)
);
DEBUG_OEM_SVC ((DEBUG_INFO, "OemKernelServices OemSvcUpdateAcpiFacsHardwareSignature Status: %r\n", Status));
if (!EFI_ERROR (Status)) {
//
// Oemservices has already updated hardware signature so free the acpi table.
//
FreePool ( Table );
return ;
}
//
// If OemServices status is not EFI_SUCCESS (EFI_MEDIA_CHANGED or EFI_UNSUPPORTED),
// kernel will update hardware signature.
//
AcpiSupport->SetAcpiTable (AcpiSupport, Table, TRUE, Version, &Handle);
FreePool ( Table );
return ;
}
FreePool ( Table );
Index++;
}
}
/**
Recheck Update FACS Hardware Signature event.
@param Event Event instance
@param Context Event Context.
@return None.
**/
STATIC
VOID
EFIAPI
FacsHwSignReadyToBootCallBack (
IN EFI_EVENT Event,
IN VOID *Context
)
{
EFI_STATUS Status;
EFI_ACPI_S3_SAVE_PROTOCOL *AcpiS3Save;
gBS->CloseEvent (Event);
Status = gBS->LocateProtocol (&gEfiAcpiS3SaveProtocolGuid, NULL, (VOID **)&AcpiS3Save);
if (EFI_ERROR (Status)) {
UpdateFacsHardwareSignatureFn();
}
}
/**
Update FACS Hardware Signature, and call S3Save function.
@param This A pointer to the EFI_ACPI_S3_SAVE_PROTOCOL instance.
@param LegacyMemoryAddress The base address of legacy memory.
@return None.
**/
VOID
EFIAPI
UpdateFacsHardwareSignature (
IN EFI_ACPI_S3_SAVE_PROTOCOL *This,
IN VOID *LegacyMemoryAddress
)
{
This->S3Save = mS3Save;
UpdateFacsHardwareSignatureFn();
This->S3Save (This, LegacyMemoryAddress);
}
/**
Notification event handler to do AcpiS3Save hook point
@param[in] Event The Event whose notification function is being invoked.
@param[in] Context Pointer to the notification function's context.
@retval None
**/
VOID
EFIAPI
AcpiS3SaveHookCallBack (
IN EFI_EVENT Event,
IN VOID *Context
)
{
EFI_STATUS Status;
EFI_ACPI_S3_SAVE_PROTOCOL *AcpiS3Save;
Status = gBS->LocateProtocol (&gEfiAcpiS3SaveProtocolGuid, NULL, (VOID **)&AcpiS3Save);
if (EFI_ERROR (Status)) {
return;
}
mS3Save = AcpiS3Save->S3Save;
AcpiS3Save->S3Save = (EFI_ACPI_S3_SAVE)UpdateFacsHardwareSignature;
}
/**
AcpiS3Save hook point, we have to promise update Facs table before save s3 information.
So, hook AcpiS3Save->S3Save.
It will not hook this point if it does not install gEfiAcpiS3SaveProtocolGuid.
@param None.
@return EFI_SUCCESS
**/
EFI_STATUS
AcpiS3SaveHook (
VOID
)
{
EFI_STATUS Status;
EFI_ACPI_S3_SAVE_PROTOCOL *AcpiS3Save;
EFI_EVENT UpdateFacsHardwareSignatureEvent;
VOID *Registration;
Status = gBS->LocateProtocol (&gEfiAcpiS3SaveProtocolGuid, NULL, (VOID **)&AcpiS3Save);
if (EFI_ERROR (Status)) {
EfiCreateProtocolNotifyEvent (
&gEfiAcpiS3SaveProtocolGuid,
TPL_NOTIFY,
AcpiS3SaveHookCallBack,
NULL,
&Registration
);
Status = EfiCreateEventReadyToBootEx (
TPL_CALLBACK - 1,
FacsHwSignReadyToBootCallBack,
NULL,
&UpdateFacsHardwareSignatureEvent
);
ASSERT_EFI_ERROR (Status);
return EFI_SUCCESS;
}
mS3Save = AcpiS3Save->S3Save;
AcpiS3Save->S3Save = (EFI_ACPI_S3_SAVE)UpdateFacsHardwareSignature;
return EFI_SUCCESS;
}
/**
Update FACS table content
Depends on ACPI Version option in Setup Variable for the 64 bits table support.
@param Table The table to update
@param SetupVariable SETUP Variable pointer
@return EFI_SUCCESS Update table success
**/
EFI_STATUS
FacsUpdateCommon (
IN OUT EFI_ACPI_COMMON_HEADER *Table
)
{
KERNEL_CONFIGURATION SetupVariable;
EFI_STATUS Status;
Status = GetKernelConfiguration (&SetupVariable);
if (EFI_ERROR (Status)) {
SetupVariable.AcpiVer = 3;
}
switch (SetupVariable.AcpiVer) {
case 0x07:
case 0x06:
case 0x05:
case 0x04:
case 0x03:
case 0x02:
((EFI_ACPI_4_0_FIRMWARE_ACPI_CONTROL_STRUCTURE *)(Table))->Version = EFI_ACPI_4_0_FIRMWARE_ACPI_CONTROL_STRUCTURE_VERSION; //0x02
((EFI_ACPI_4_0_FIRMWARE_ACPI_CONTROL_STRUCTURE *)(Table))->OspmFlags = 0;
(Table)->Length = sizeof(EFI_ACPI_4_0_FIRMWARE_ACPI_CONTROL_STRUCTURE);
((EFI_ACPI_4_0_FIRMWARE_ACPI_CONTROL_STRUCTURE *)(Table))->Flags &= ~EFI_ACPI_4_0_64BIT_WAKE_SUPPORTED_F;
break;
case 0x01:
(Table)->Length = sizeof(EFI_ACPI_3_0_FIRMWARE_ACPI_CONTROL_STRUCTURE);
break;
case 0:
default:
((EFI_ACPI_3_0_FIRMWARE_ACPI_CONTROL_STRUCTURE *)(Table))->Version = 0;
(Table)->Length = sizeof(EFI_ACPI_1_0_FIRMWARE_ACPI_CONTROL_STRUCTURE);
break;
}
AcpiS3SaveHook ();
return EFI_SUCCESS;
}