alder_lake_bios/Insyde/InsydeModulePkg/Universal/Acpi/WpbtDxe/WpbtDxe.c

483 lines
12 KiB
C

/** @file
This module install ACPI Windows Platform Binary Table (WPBT).
;******************************************************************************
;* 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 <Uefi.h>
#include <PiDxe.h>
#include "WpbtDxe.h"
#include <Protocol/AcpiTable.h>
#include <Protocol/FirmwareVolume2.h>
#include <Protocol/AcpiWpbt.h>
#include <Guid/EventGroup.h>
#include <Guid/EventLegacyBios.h>
#include <Library/BaseLib.h>
#include <Library/BaseMemoryLib.h>
#include <Library/UefiLib.h>
#include <Library/UefiBootServicesTableLib.h>
#include <Library/DebugLib.h>
#include <Library/MemoryAllocationLib.h>
#include <Library/H2OLib.h>
//
// ACPI table information used to initialize tables.
//
#define EFI_ACPI_OEM_ID 'I','N','S','Y','D','E'
#define EFI_ACPI_OEM_TABLE_ID SIGNATURE_64('H','2','O',' ','B','I','O','S')
#define EFI_ACPI_OEM_REVISION 0x00000001
#define EFI_ACPI_CREATOR_ID SIGNATURE_32('A','C','P','I')
#define EFI_ACPI_CREATOR_REVISION 0x00040000
//
// Module globals.
//
UINTN mPlatformBinaryResourceTableKey = 0;
//
// WPBT conent
//
EFI_GUID mFileGuid;
UINT16 mArgLength;
BOOLEAN mAcpiWpbtInstalled = FALSE;
EFI_ACPI_5_0_PLATFORM_BINARY_TABLE mPlatformBinaryTableTemplate = {
{
EFI_ACPI_5_0_PLATFORM_BINARY_TABLE_SIGNATURE,
sizeof (EFI_ACPI_5_0_PLATFORM_BINARY_TABLE),
EFI_ACPI_5_0_PLATFORM_BINARY_TABLE_REVISION, // Revision
0x00, // Checksum will be updated at runtime
//
// It is expected that these values will be updated at runtime.
//
EFI_ACPI_OEM_ID, // OEMID is a 6 bytes long field
EFI_ACPI_OEM_TABLE_ID, // OEM table identification(8 bytes long)
EFI_ACPI_OEM_REVISION, // OEM revision number
EFI_ACPI_CREATOR_ID, // ASL compiler vendor ID
EFI_ACPI_CREATOR_REVISION, // ASL compiler revision number
},
0, // BinarySize
0, // BinaryLocation
EFI_ACPI_5_0_WPBT_CONTENT_LAYOUT, // Content Layout
EFI_ACPI_5_0_WPBT_CONTENT_TYPE, // Content Type
0 // ArgLength
};
EFI_ACPI_5_0_PLATFORM_BINARY_TABLE *mPlatformBinaryTable; // dynamically allocated for variable-length arg
EFI_STATUS
EFIAPI
LocatePlatformBinary (
IN EFI_ACPI_WPBT_PROTOCOL *This,
IN EFI_GUID *FileGuid,
IN UINT16 ArgLength,
IN CHAR16 *Arg
);
EFI_ACPI_WPBT_PROTOCOL mAcpiWpbtProtocolTemplate = { LocatePlatformBinary };
/**
Function of EFI_ACPI_WPBT_PROTOCOL,
for sample driver to pass the file guid of binary.
@param [in] This
@param [in] FileGuid
@param [in] ArgLength The length (in bytes) of the input string for the binary execution
@param [in] Arg
@retval EFI_OUT_OF_RESOURCES
@retval EFI_SUCCESS
**/
EFI_STATUS
EFIAPI
LocatePlatformBinary (
IN EFI_ACPI_WPBT_PROTOCOL *This,
IN EFI_GUID *FileGuid,
IN UINT16 ArgLength,
IN CHAR16 *Arg
)
{
CHAR16 *PtrArg;
CopyGuid (&mFileGuid, FileGuid);
//
// ArgLength should be multiples of sizeof (CHAR16)
//
if ((ArgLength % (sizeof (CHAR16))) != 0) {
DEBUG ((EFI_D_ERROR, "Invalid ArgLength: (%d) \n", ArgLength));
return EFI_INVALID_PARAMETER;
}
mArgLength = ArgLength;
//
// allocate real PlatformBinaryTable
//
mPlatformBinaryTable = AllocateRuntimePool ((sizeof (EFI_ACPI_5_0_PLATFORM_BINARY_TABLE) + mArgLength));
if (mPlatformBinaryTable == NULL) {
return EFI_OUT_OF_RESOURCES;
}
CopyMem (mPlatformBinaryTable, &mPlatformBinaryTableTemplate, sizeof (EFI_ACPI_5_0_PLATFORM_BINARY_TABLE));
//
// update Header->Length
//
mPlatformBinaryTable->Header.Length = (UINT32)(sizeof (EFI_ACPI_5_0_PLATFORM_BINARY_TABLE) + mArgLength);
if (mArgLength > 0) {
PtrArg = (CHAR16 *)((UINT8 *)(mPlatformBinaryTable) + sizeof (EFI_ACPI_5_0_PLATFORM_BINARY_TABLE));
CopyMem (PtrArg, Arg, mArgLength);
} //end if (>0)
return EFI_SUCCESS;
}
/**
This function calculates and updates an UINT8 checksum.
@param [in] Buffer
@param [in] Size Number of bytes to checksum.
@retval None
**/
VOID
WpbtAcpiTableChecksum (
IN UINT8 *Buffer,
IN UINTN Size
)
{
UINTN ChecksumOffset;
ChecksumOffset = OFFSET_OF (EFI_ACPI_DESCRIPTION_HEADER, Checksum);
//
// Set checksum to 0 first.
//
Buffer[ChecksumOffset] = 0;
//
// Update checksum value.
//
Buffer[ChecksumOffset] = CalculateCheckSum8 (Buffer, Size);
}
/**
Install Windows Platform Binary Table to ACPI table.
@param None
@return Status code
**/
EFI_STATUS
InstallWindowsPlatformBinaryTable (
VOID
)
{
EFI_STATUS Status;
EFI_ACPI_TABLE_PROTOCOL *AcpiTableProtocol;
UINTN FvHandleCount;
EFI_HANDLE *FvHandleBuffer;
UINTN Index;
EFI_FIRMWARE_VOLUME2_PROTOCOL *Fv;
UINT8 *LoadBuffer;
UINTN Size;
UINT32 AuthenticationStatus;
UINT8 Temp;
EFI_GUID ZeroGuid;
//
// variables initialization
//
LoadBuffer = &Temp;
Size = 1;
Fv = NULL;
ZeroMem (&ZeroGuid, sizeof (EFI_GUID));
if (mAcpiWpbtInstalled) {
return EFI_SUCCESS;
}
if (CompareGuid (&ZeroGuid, &mFileGuid)) {
return EFI_INVALID_PARAMETER;
}
Status = gBS->LocateProtocol (&gEfiAcpiTableProtocolGuid, NULL, (VOID **) &AcpiTableProtocol);
if (EFI_ERROR (Status)) {
DEBUG ((EFI_D_ERROR, "Locate AcpiTableProtocol failed: (%r) \n", Status));
return Status;
}
//
// Locate binary file location
//
gBS->LocateHandleBuffer (
ByProtocol,
&gEfiFirmwareVolume2ProtocolGuid,
NULL,
&FvHandleCount,
&FvHandleBuffer
);
for (Index = 0; Index < FvHandleCount; Index++) {
gBS->HandleProtocol (
FvHandleBuffer[Index],
&gEfiFirmwareVolume2ProtocolGuid,
(VOID **) &Fv
);
//
// the binary file is encapsulated as EFI_SECTION_RAW
//
Status = Fv->ReadSection (
Fv,
&mFileGuid,
EFI_SECTION_RAW,
0,
(VOID **)&LoadBuffer,
&Size,
&AuthenticationStatus
);
if (Status == EFI_WARN_BUFFER_TOO_SMALL || Status == EFI_BUFFER_TOO_SMALL) {
LoadBuffer = H2OAcpiReclaimAllocate (Size);
Status = Fv->ReadSection (
Fv,
&mFileGuid,
EFI_SECTION_RAW,
0,
(VOID **)&LoadBuffer,
&Size,
&AuthenticationStatus
);
if (EFI_ERROR (Status)) {
DEBUG ((EFI_D_ERROR, "ReadSection with LoadBuffer failed: (%r) \n", Status));
return Status;
}
} //end if (BUFFER_TOO_SMALL)
if (!EFI_ERROR (Status)) {
break;
}
} //end for (Index)
//
// can't read the file
//
if (Index == FvHandleCount) {
DEBUG ((EFI_D_ERROR, "Can not ReadFile: (%r) \n", Status));
return Status;
}
//
// initialize WPBT members
//
mPlatformBinaryTable->BinarySize = (UINT32)Size;
mPlatformBinaryTable->BinaryLocation = (UINT64)(UINTN)LoadBuffer;
mPlatformBinaryTable->Layout = EFI_ACPI_5_0_WPBT_CONTENT_LAYOUT;
mPlatformBinaryTable->Type = EFI_ACPI_5_0_WPBT_CONTENT_TYPE;
mPlatformBinaryTable->ArgLength = mArgLength;
//
// Update Checksum.
//
WpbtAcpiTableChecksum ((UINT8 *)mPlatformBinaryTable, (sizeof (EFI_ACPI_5_0_PLATFORM_BINARY_TABLE) + mPlatformBinaryTable->ArgLength));
//
// Publish Windows Platform Binary Table.
//
Status = AcpiTableProtocol->InstallAcpiTable (
AcpiTableProtocol,
mPlatformBinaryTable,
(sizeof (EFI_ACPI_5_0_PLATFORM_BINARY_TABLE) + mPlatformBinaryTable->ArgLength),
&mPlatformBinaryResourceTableKey
);
if (EFI_ERROR (Status)) {
DEBUG ((EFI_D_ERROR, "InstallAcpiTable failed: (%r) \n", Status));
return Status;
}
mAcpiWpbtInstalled = TRUE;
FreePool (mPlatformBinaryTable);
mPlatformBinaryTable = NULL;
return Status;
}
/**
Uninstall Windows Platform Binary Table to ACPI table.
@param None
@return Status code
**/
EFI_STATUS
UninstallWindowsPlatformBinaryTable (
VOID
)
{
EFI_STATUS Status;
EFI_ACPI_TABLE_PROTOCOL *AcpiTableProtocol;
//
// Get ACPI Table protocol.
//
Status = gBS->LocateProtocol (&gEfiAcpiTableProtocolGuid, NULL, (VOID **) &AcpiTableProtocol);
if (EFI_ERROR (Status)) {
return Status;
}
if (mAcpiWpbtInstalled == TRUE) {
Status = AcpiTableProtocol->UninstallAcpiTable (
AcpiTableProtocol,
mPlatformBinaryResourceTableKey
);
}
if (mPlatformBinaryTable) {
FreePool (mPlatformBinaryTable);
}
return Status;
}
/**
Notify function for event group EFI_EVENT_GROUP_READY_TO_BOOT.
This is used to install the Windows Platform Binary Table.
@param [in] Event The registered event
@param [in] Context
@retval None
**/
VOID
EFIAPI
WpbtReadyToBootEventNotify (
IN EFI_EVENT Event,
IN VOID *Context
)
{
InstallWindowsPlatformBinaryTable ();
gBS->CloseEvent (Event);
}
/**
Notify function for event EFI_EVENT_LEGACY_BOOT.
This is used to install the Windows Platform Binary Table.
@param [in] Event The registered event
@param [in] Context
@retval None
**/
VOID
EFIAPI
WpbtLegacyBootEventNotify (
IN EFI_EVENT Event,
IN VOID *Context
)
{
UninstallWindowsPlatformBinaryTable ();
gBS->CloseEvent (Event);
}
/**
The module Entry Point of the Windows Platform Binary Table DXE driver.
@param [in] ImageHandle The firmware allocated handle for the EFI image.
@param [in] SystemTable A pointer to the EFI System Table.
@return Status code
**/
EFI_STATUS
EFIAPI
PlatformBinaryDxeEntryPoint (
IN EFI_HANDLE ImageHandle,
IN EFI_SYSTEM_TABLE *SystemTable
)
{
EFI_STATUS Status;
EFI_EVENT PlatformBinaryReadyToBootEvent;
EFI_EVENT PlatformBinaryLegacyBootEvent;
EFI_HANDLE PlatformBinaryHandle = NULL;
//
// initialize global variables
//
ZeroMem (&mFileGuid, sizeof (EFI_GUID));
mArgLength = 0;
mPlatformBinaryTable = NULL;
//
// Install Platform Binary protocol.
//
Status = gBS->InstallMultipleProtocolInterfaces (
&PlatformBinaryHandle,
&gEfiAcpiWpbtProtocolGuid,
&mAcpiWpbtProtocolTemplate,
NULL
);
ASSERT_EFI_ERROR (Status);
//
// Register notify function to install WPBT on ReadyToBoot Event.
//
Status = gBS->CreateEventEx (
EVT_NOTIFY_SIGNAL,
TPL_CALLBACK,
WpbtReadyToBootEventNotify,
NULL,
&gEfiEventReadyToBootGuid,
&PlatformBinaryReadyToBootEvent
);
ASSERT_EFI_ERROR (Status);
//
// According to the description of WPBT
// that the WPBT only supported on pure Uefi system.
// Removed the Table when boot to legacy system.
//
Status = gBS->CreateEventEx (
EVT_NOTIFY_SIGNAL,
TPL_CALLBACK,
WpbtLegacyBootEventNotify,
NULL,
&gEfiEventLegacyBootGuid,
&PlatformBinaryLegacyBootEvent
);
ASSERT_EFI_ERROR (Status);
return Status;
}