mirror of
				https://git.proxmox.com/git/mirror_edk2
				synced 2025-11-04 02:40:26 +00:00 
			
		
		
		
	https://bugzilla.tianocore.org/show_bug.cgi?id=1373 Replace BSD 2-Clause License with BSD+Patent License. This change is based on the following emails: https://lists.01.org/pipermail/edk2-devel/2019-February/036260.html https://lists.01.org/pipermail/edk2-devel/2018-October/030385.html RFCs with detailed process for the license change: V3: https://lists.01.org/pipermail/edk2-devel/2019-March/038116.html V2: https://lists.01.org/pipermail/edk2-devel/2019-March/037669.html V1: https://lists.01.org/pipermail/edk2-devel/2019-March/037500.html Contributed-under: TianoCore Contribution Agreement 1.1 Signed-off-by: Michael D Kinney <michael.d.kinney@intel.com> Reviewed-by: Hao Wu <hao.a.wu@intel.com> Reviewed-by: Jian J Wang <jian.j.wang@intel.com>
		
			
				
	
	
		
			439 lines
		
	
	
		
			13 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			439 lines
		
	
	
		
			13 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
/** @file
 | 
						|
  Publishes ESRT table from Firmware Management Protocol instances
 | 
						|
 | 
						|
  Copyright (c) 2016, Microsoft Corporation
 | 
						|
  Copyright (c) 2018, Intel Corporation. All rights reserved.<BR>
 | 
						|
 | 
						|
  All rights reserved.
 | 
						|
  SPDX-License-Identifier: BSD-2-Clause-Patent
 | 
						|
 | 
						|
**/
 | 
						|
 | 
						|
#include <Uefi.h>
 | 
						|
#include <Library/BaseLib.h>
 | 
						|
#include <Library/BaseMemoryLib.h>
 | 
						|
#include <Library/MemoryAllocationLib.h>
 | 
						|
#include <Library/UefiBootServicesTableLib.h>
 | 
						|
#include <Library/DebugLib.h>
 | 
						|
#include <Library/PcdLib.h>
 | 
						|
#include <Library/UefiLib.h>
 | 
						|
#include <Protocol/FirmwareManagement.h>
 | 
						|
#include <Guid/EventGroup.h>
 | 
						|
#include <Guid/SystemResourceTable.h>
 | 
						|
 | 
						|
/**
 | 
						|
 Print ESRT to debug console.
 | 
						|
 | 
						|
 @param[in]  Table   Pointer to the ESRT table.
 | 
						|
 | 
						|
**/
 | 
						|
VOID
 | 
						|
EFIAPI
 | 
						|
PrintTable (
 | 
						|
  IN EFI_SYSTEM_RESOURCE_TABLE  *Table
 | 
						|
  );
 | 
						|
 | 
						|
//
 | 
						|
// Number of ESRT entries to grow by each time we run out of room
 | 
						|
//
 | 
						|
#define GROWTH_STEP  10
 | 
						|
 | 
						|
/**
 | 
						|
  Install EFI System Resource Table into the UEFI Configuration Table
 | 
						|
 | 
						|
  @param[in] Table                  Pointer to the ESRT.
 | 
						|
 | 
						|
  @return  Status code.
 | 
						|
 | 
						|
**/
 | 
						|
EFI_STATUS
 | 
						|
InstallEfiSystemResourceTableInUefiConfigurationTable (
 | 
						|
  IN EFI_SYSTEM_RESOURCE_TABLE      *Table
 | 
						|
  )
 | 
						|
{
 | 
						|
  EFI_STATUS Status;
 | 
						|
 | 
						|
  Status = EFI_SUCCESS;
 | 
						|
  if (Table->FwResourceCount == 0) {
 | 
						|
    DEBUG ((DEBUG_ERROR, "EsrtFmpDxe: Can't install ESRT table because it has zero Entries. \n"));
 | 
						|
    Status = EFI_UNSUPPORTED;
 | 
						|
  } else {
 | 
						|
    //
 | 
						|
    // Install the pointer into config table
 | 
						|
    //
 | 
						|
    Status = gBS->InstallConfigurationTable (&gEfiSystemResourceTableGuid, Table);
 | 
						|
    if (EFI_ERROR (Status)) {
 | 
						|
      DEBUG ((DEBUG_ERROR, "EsrtFmpDxe: Can't install ESRT table.  Status: %r. \n", Status));
 | 
						|
    } else {
 | 
						|
      DEBUG ((DEBUG_INFO, "EsrtFmpDxe: Installed ESRT table. \n"));
 | 
						|
    }
 | 
						|
  }
 | 
						|
  return Status;
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
  Return if this FMP is a system FMP or a device FMP, based upon FmpImageInfo.
 | 
						|
 | 
						|
  @param[in] FmpImageInfo A pointer to EFI_FIRMWARE_IMAGE_DESCRIPTOR
 | 
						|
 | 
						|
  @return TRUE  It is a system FMP.
 | 
						|
  @return FALSE It is a device FMP.
 | 
						|
**/
 | 
						|
BOOLEAN
 | 
						|
IsSystemFmp (
 | 
						|
  IN EFI_FIRMWARE_IMAGE_DESCRIPTOR  *FmpImageInfo
 | 
						|
  )
 | 
						|
{
 | 
						|
  GUID   *Guid;
 | 
						|
  UINTN  Count;
 | 
						|
  UINTN  Index;
 | 
						|
 | 
						|
  Guid  = PcdGetPtr (PcdSystemFmpCapsuleImageTypeIdGuid);
 | 
						|
  Count = PcdGetSize (PcdSystemFmpCapsuleImageTypeIdGuid) / sizeof(GUID);
 | 
						|
 | 
						|
  for (Index = 0; Index < Count; Index++, Guid++) {
 | 
						|
    if (CompareGuid (&FmpImageInfo->ImageTypeId, Guid)) {
 | 
						|
      return TRUE;
 | 
						|
    }
 | 
						|
  }
 | 
						|
 | 
						|
  return FALSE;
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
  Function to create a single ESRT Entry and add it to the ESRT
 | 
						|
  given a FMP descriptor.  If the guid is already in the ESRT it
 | 
						|
  will be ignored.  The ESRT will grow if it does not have enough room.
 | 
						|
 | 
						|
  @param[in, out] Table             On input, pointer to the pointer to the ESRT.
 | 
						|
                                    On output, same as input or pointer to the pointer
 | 
						|
                                    to new enlarged ESRT.
 | 
						|
  @param[in]      FmpImageInfoBuf   Pointer to the EFI_FIRMWARE_IMAGE_DESCRIPTOR.
 | 
						|
  @param[in]      FmpVersion        FMP Version.
 | 
						|
 | 
						|
  @return  Status code.
 | 
						|
 | 
						|
**/
 | 
						|
EFI_STATUS
 | 
						|
CreateEsrtEntry (
 | 
						|
  IN OUT EFI_SYSTEM_RESOURCE_TABLE  **Table,
 | 
						|
  IN EFI_FIRMWARE_IMAGE_DESCRIPTOR  *FmpImageInfoBuf,
 | 
						|
  IN UINT32                         FmpVersion
 | 
						|
  )
 | 
						|
{
 | 
						|
  UINTN                      Index;
 | 
						|
  EFI_SYSTEM_RESOURCE_ENTRY  *Entry;
 | 
						|
  UINTN                      NewSize;
 | 
						|
  EFI_SYSTEM_RESOURCE_TABLE  *NewTable;
 | 
						|
 | 
						|
  Index = 0;
 | 
						|
  Entry = NULL;
 | 
						|
 | 
						|
  Entry = (EFI_SYSTEM_RESOURCE_ENTRY *)((*Table) + 1);
 | 
						|
  //
 | 
						|
  // Make sure Guid isn't already in the list
 | 
						|
  //
 | 
						|
  for (Index = 0; Index < (*Table)->FwResourceCount; Index++) {
 | 
						|
    if (CompareGuid (&Entry->FwClass, &FmpImageInfoBuf->ImageTypeId)) {
 | 
						|
      DEBUG ((DEBUG_ERROR, "EsrtFmpDxe: ESRT Entry already exists for FMP Instance with GUID %g\n", &Entry->FwClass));
 | 
						|
      return EFI_INVALID_PARAMETER;
 | 
						|
    }
 | 
						|
    Entry++;
 | 
						|
  }
 | 
						|
 | 
						|
  //
 | 
						|
  // Grow table if needed
 | 
						|
  //
 | 
						|
  if ((*Table)->FwResourceCount >= (*Table)->FwResourceCountMax) {
 | 
						|
    NewSize  = (((*Table)->FwResourceCountMax + GROWTH_STEP) * sizeof (EFI_SYSTEM_RESOURCE_ENTRY)) + sizeof (EFI_SYSTEM_RESOURCE_TABLE);
 | 
						|
    NewTable = AllocateZeroPool (NewSize);
 | 
						|
    if (NewTable == NULL) {
 | 
						|
      DEBUG ((DEBUG_ERROR, "EsrtFmpDxe: Failed to allocate memory larger table for ESRT. \n"));
 | 
						|
      return EFI_OUT_OF_RESOURCES;
 | 
						|
    }
 | 
						|
    //
 | 
						|
    // Copy the whole old table into new table buffer
 | 
						|
    //
 | 
						|
    CopyMem (
 | 
						|
      NewTable,
 | 
						|
      (*Table),
 | 
						|
      (((*Table)->FwResourceCountMax) * sizeof (EFI_SYSTEM_RESOURCE_ENTRY)) + sizeof (EFI_SYSTEM_RESOURCE_TABLE)
 | 
						|
      );
 | 
						|
    //
 | 
						|
    // Update max
 | 
						|
    //
 | 
						|
    NewTable->FwResourceCountMax = NewTable->FwResourceCountMax + GROWTH_STEP;
 | 
						|
    //
 | 
						|
    // Free old table
 | 
						|
    //
 | 
						|
    FreePool ((*Table));
 | 
						|
    //
 | 
						|
    // Reassign pointer to new table.
 | 
						|
    //
 | 
						|
    (*Table) = NewTable;
 | 
						|
  }
 | 
						|
 | 
						|
  //
 | 
						|
  // ESRT table has enough room for the new entry so add new entry
 | 
						|
  //
 | 
						|
  Entry = (EFI_SYSTEM_RESOURCE_ENTRY *)(((UINT8 *)(*Table)) + sizeof (EFI_SYSTEM_RESOURCE_TABLE));
 | 
						|
  //
 | 
						|
  // Move to the location of new entry
 | 
						|
  //
 | 
						|
  Entry = Entry + (*Table)->FwResourceCount;
 | 
						|
  //
 | 
						|
  // Increment resource count
 | 
						|
  //
 | 
						|
  (*Table)->FwResourceCount++;
 | 
						|
 | 
						|
  CopyGuid (&Entry->FwClass, &FmpImageInfoBuf->ImageTypeId);
 | 
						|
 | 
						|
  if (IsSystemFmp (FmpImageInfoBuf)) {
 | 
						|
    DEBUG ((DEBUG_INFO, "EsrtFmpDxe: Found an ESRT entry for a System Device.\n"));
 | 
						|
    Entry->FwType = (UINT32)(ESRT_FW_TYPE_SYSTEMFIRMWARE);
 | 
						|
  } else {
 | 
						|
    Entry->FwType = (UINT32)(ESRT_FW_TYPE_DEVICEFIRMWARE);
 | 
						|
  }
 | 
						|
 | 
						|
  Entry->FwVersion = FmpImageInfoBuf->Version;
 | 
						|
  Entry->LowestSupportedFwVersion = 0;
 | 
						|
  Entry->CapsuleFlags = 0;
 | 
						|
  Entry->LastAttemptVersion = 0;
 | 
						|
  Entry->LastAttemptStatus = 0;
 | 
						|
 | 
						|
  //
 | 
						|
  // VERSION 2 has Lowest Supported
 | 
						|
  //
 | 
						|
  if (FmpVersion >= 2) {
 | 
						|
    Entry->LowestSupportedFwVersion = FmpImageInfoBuf->LowestSupportedImageVersion;
 | 
						|
  }
 | 
						|
 | 
						|
  //
 | 
						|
  // VERSION 3 supports last attempt values
 | 
						|
  //
 | 
						|
  if (FmpVersion >= 3) {
 | 
						|
    Entry->LastAttemptVersion = FmpImageInfoBuf->LastAttemptVersion;
 | 
						|
    Entry->LastAttemptStatus = FmpImageInfoBuf->LastAttemptStatus;
 | 
						|
  }
 | 
						|
 | 
						|
  return EFI_SUCCESS;
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
  Function to create ESRT based on FMP Instances.
 | 
						|
  Create ESRT table, get the descriptors from FMP Instance and
 | 
						|
  create ESRT entries (ESRE).
 | 
						|
 | 
						|
  @return Pointer to the ESRT created.
 | 
						|
 | 
						|
**/
 | 
						|
EFI_SYSTEM_RESOURCE_TABLE *
 | 
						|
CreateFmpBasedEsrt (
 | 
						|
  VOID
 | 
						|
  )
 | 
						|
{
 | 
						|
  EFI_STATUS                        Status;
 | 
						|
  EFI_SYSTEM_RESOURCE_TABLE         *Table;
 | 
						|
  UINTN                             NoProtocols;
 | 
						|
  VOID                              **Buffer;
 | 
						|
  UINTN                             Index;
 | 
						|
  EFI_FIRMWARE_MANAGEMENT_PROTOCOL  *Fmp;
 | 
						|
  UINTN                             DescriptorSize;
 | 
						|
  EFI_FIRMWARE_IMAGE_DESCRIPTOR     *FmpImageInfoBuf;
 | 
						|
  EFI_FIRMWARE_IMAGE_DESCRIPTOR     *FmpImageInfoBufOrg;
 | 
						|
  UINT8                             FmpImageInfoCount;
 | 
						|
  UINT32                            FmpImageInfoDescriptorVer;
 | 
						|
  UINTN                             ImageInfoSize;
 | 
						|
  UINT32                            PackageVersion;
 | 
						|
  CHAR16                            *PackageVersionName;
 | 
						|
 | 
						|
  Status             = EFI_SUCCESS;
 | 
						|
  Table              = NULL;
 | 
						|
  NoProtocols        = 0;
 | 
						|
  Buffer             = NULL;
 | 
						|
  PackageVersionName = NULL;
 | 
						|
  FmpImageInfoBuf    = NULL;
 | 
						|
  FmpImageInfoBufOrg = NULL;
 | 
						|
  Fmp                = NULL;
 | 
						|
 | 
						|
  Status = EfiLocateProtocolBuffer (
 | 
						|
             &gEfiFirmwareManagementProtocolGuid,
 | 
						|
             &NoProtocols,
 | 
						|
             &Buffer
 | 
						|
             );
 | 
						|
  if (EFI_ERROR(Status) || (Buffer == NULL)) {
 | 
						|
    return NULL;
 | 
						|
  }
 | 
						|
 | 
						|
  //
 | 
						|
  // Allocate Memory for table
 | 
						|
  //
 | 
						|
  Table = AllocateZeroPool (
 | 
						|
             (GROWTH_STEP * sizeof (EFI_SYSTEM_RESOURCE_ENTRY)) + sizeof (EFI_SYSTEM_RESOURCE_TABLE)
 | 
						|
             );
 | 
						|
  if (Table == NULL) {
 | 
						|
    DEBUG ((DEBUG_ERROR, "EsrtFmpDxe: Failed to allocate memory for ESRT.\n"));
 | 
						|
    gBS->FreePool (Buffer);
 | 
						|
    return NULL;
 | 
						|
  }
 | 
						|
 | 
						|
  Table->FwResourceCount    = 0;
 | 
						|
  Table->FwResourceCountMax = GROWTH_STEP;
 | 
						|
  Table->FwResourceVersion  = EFI_SYSTEM_RESOURCE_TABLE_FIRMWARE_RESOURCE_VERSION;
 | 
						|
 | 
						|
  for (Index = 0; Index < NoProtocols; Index++) {
 | 
						|
    Fmp = (EFI_FIRMWARE_MANAGEMENT_PROTOCOL *) Buffer[Index];
 | 
						|
 | 
						|
    ImageInfoSize = 0;
 | 
						|
    Status = Fmp->GetImageInfo (
 | 
						|
                    Fmp,                         // FMP Pointer
 | 
						|
                    &ImageInfoSize,              // Buffer Size (in this case 0)
 | 
						|
                    NULL,                        // NULL so we can get size
 | 
						|
                    &FmpImageInfoDescriptorVer,  // DescriptorVersion
 | 
						|
                    &FmpImageInfoCount,          // DescriptorCount
 | 
						|
                    &DescriptorSize,             // DescriptorSize
 | 
						|
                    &PackageVersion,             // PackageVersion
 | 
						|
                    &PackageVersionName          // PackageVersionName
 | 
						|
                    );
 | 
						|
 | 
						|
    if (Status != EFI_BUFFER_TOO_SMALL) {
 | 
						|
      DEBUG ((DEBUG_ERROR, "EsrtFmpDxe: Unexpected Failure in GetImageInfo.  Status = %r\n", Status));
 | 
						|
      continue;
 | 
						|
    }
 | 
						|
 | 
						|
    FmpImageInfoBuf = AllocateZeroPool (ImageInfoSize);
 | 
						|
    if (FmpImageInfoBuf == NULL) {
 | 
						|
      DEBUG ((DEBUG_ERROR, "EsrtFmpDxe: Failed to get memory for descriptors.\n"));
 | 
						|
      continue;
 | 
						|
    }
 | 
						|
 | 
						|
    FmpImageInfoBufOrg = FmpImageInfoBuf;
 | 
						|
    PackageVersionName = NULL;
 | 
						|
    Status = Fmp->GetImageInfo (
 | 
						|
                    Fmp,
 | 
						|
                    &ImageInfoSize,              // ImageInfoSize
 | 
						|
                    FmpImageInfoBuf,             // ImageInfo
 | 
						|
                    &FmpImageInfoDescriptorVer,  // DescriptorVersion
 | 
						|
                    &FmpImageInfoCount,          // DescriptorCount
 | 
						|
                    &DescriptorSize,             // DescriptorSize
 | 
						|
                    &PackageVersion,             // PackageVersion
 | 
						|
                    &PackageVersionName          // PackageVersionName
 | 
						|
                    );
 | 
						|
    if (EFI_ERROR (Status)) {
 | 
						|
      DEBUG ((DEBUG_ERROR, "EsrtFmpDxe: Failure in GetImageInfo.  Status = %r\n", Status));
 | 
						|
      FreePool (FmpImageInfoBufOrg);
 | 
						|
      FmpImageInfoBufOrg = NULL;
 | 
						|
      continue;
 | 
						|
    }
 | 
						|
 | 
						|
    //
 | 
						|
    // Check each descriptor and read from the one specified
 | 
						|
    //
 | 
						|
    while (FmpImageInfoCount > 0) {
 | 
						|
      //
 | 
						|
      // If the descriptor has the IN USE bit set, create ESRT entry otherwise ignore.
 | 
						|
      //
 | 
						|
      if ((FmpImageInfoBuf->AttributesSetting & FmpImageInfoBuf->AttributesSupported & IMAGE_ATTRIBUTE_IN_USE) == IMAGE_ATTRIBUTE_IN_USE) {
 | 
						|
        //
 | 
						|
        // Create ESRT entry
 | 
						|
        //
 | 
						|
        CreateEsrtEntry (&Table, FmpImageInfoBuf, FmpImageInfoDescriptorVer);
 | 
						|
      }
 | 
						|
      FmpImageInfoCount--;
 | 
						|
      //
 | 
						|
      // Increment the buffer pointer ahead by the size of the descriptor
 | 
						|
      //
 | 
						|
      FmpImageInfoBuf = (EFI_FIRMWARE_IMAGE_DESCRIPTOR *)(((UINT8 *)FmpImageInfoBuf) + DescriptorSize);
 | 
						|
    }
 | 
						|
 | 
						|
    if (PackageVersionName != NULL) {
 | 
						|
      FreePool (PackageVersionName);
 | 
						|
      PackageVersionName = NULL;
 | 
						|
    }
 | 
						|
    FreePool (FmpImageInfoBufOrg);
 | 
						|
    FmpImageInfoBufOrg = NULL;
 | 
						|
  }
 | 
						|
 | 
						|
  gBS->FreePool (Buffer);
 | 
						|
  return Table;
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
  Notify function for event group EFI_EVENT_GROUP_READY_TO_BOOT. This is used to
 | 
						|
  install the Efi System Resource Table.
 | 
						|
 | 
						|
  @param[in]  Event    The Event that is being processed.
 | 
						|
  @param[in]  Context  The Event Context.
 | 
						|
 | 
						|
**/
 | 
						|
VOID
 | 
						|
EFIAPI
 | 
						|
EsrtReadyToBootEventNotify (
 | 
						|
  IN EFI_EVENT  Event,
 | 
						|
  IN VOID       *Context
 | 
						|
  )
 | 
						|
{
 | 
						|
  EFI_STATUS                 Status;
 | 
						|
  EFI_SYSTEM_RESOURCE_TABLE  *Table;
 | 
						|
 | 
						|
  Table = CreateFmpBasedEsrt ();
 | 
						|
  if (Table != NULL) {
 | 
						|
    //
 | 
						|
    // Print table on debug builds
 | 
						|
    //
 | 
						|
    DEBUG_CODE_BEGIN ();
 | 
						|
    PrintTable (Table);
 | 
						|
    DEBUG_CODE_END ();
 | 
						|
 | 
						|
    Status = InstallEfiSystemResourceTableInUefiConfigurationTable (Table);
 | 
						|
    if (EFI_ERROR (Status)) {
 | 
						|
      FreePool (Table);
 | 
						|
    }
 | 
						|
  } else {
 | 
						|
    DEBUG ((DEBUG_ERROR, "EsrtFmpDxe: Can't install ESRT table because it is NULL. \n"));
 | 
						|
  }
 | 
						|
 | 
						|
  //
 | 
						|
  // Close the event to prevent it be signalled again.
 | 
						|
  //
 | 
						|
  gBS->CloseEvent (Event);
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
  The module Entry Point of the Efi System Resource Table DXE driver.
 | 
						|
 | 
						|
  @param[in]  ImageHandle  The firmware allocated handle for the EFI image.
 | 
						|
  @param[in]  SystemTable  A pointer to the EFI System Table.
 | 
						|
 | 
						|
  @retval  EFI_SUCCESS  The entry point is executed successfully.
 | 
						|
  @retval  Other        Some error occurs when executing this entry point.
 | 
						|
 | 
						|
**/
 | 
						|
EFI_STATUS
 | 
						|
EFIAPI
 | 
						|
EsrtFmpEntryPoint (
 | 
						|
  IN EFI_HANDLE        ImageHandle,
 | 
						|
  IN EFI_SYSTEM_TABLE  *SystemTable
 | 
						|
  )
 | 
						|
{
 | 
						|
  EFI_STATUS  Status;
 | 
						|
  EFI_EVENT   EsrtReadyToBootEvent;
 | 
						|
 | 
						|
  //
 | 
						|
  // Register notify function to install ESRT on ReadyToBoot Event.
 | 
						|
  //
 | 
						|
  Status = EfiCreateEventReadyToBootEx (
 | 
						|
             TPL_CALLBACK,
 | 
						|
             EsrtReadyToBootEventNotify,
 | 
						|
             NULL,
 | 
						|
             &EsrtReadyToBootEvent
 | 
						|
             );
 | 
						|
 | 
						|
  ASSERT_EFI_ERROR (Status);
 | 
						|
  if (EFI_ERROR (Status)) {
 | 
						|
    DEBUG ((DEBUG_ERROR, "EsrtFmpDxe: Failed to register for ready to boot\n"));
 | 
						|
  }
 | 
						|
 | 
						|
  return Status;
 | 
						|
}
 |