| /** @file | |
| This module install ACPI Boot Graphics Resource Table (BGRT). | |
| Copyright (c) 2011 - 2018, Intel Corporation. All rights reserved.<BR> | |
| Copyright (c) 2016, Microsoft Corporation<BR> | |
| SPDX-License-Identifier: BSD-2-Clause-Patent | |
| **/ | |
| #include <Uefi.h> | |
| #include <IndustryStandard/Acpi.h> | |
| #include <Protocol/AcpiTable.h> | |
| #include <Protocol/GraphicsOutput.h> | |
| #include <Protocol/BootLogo.h> | |
| #include <Protocol/BootLogo2.h> | |
| #include <Guid/EventGroup.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/SafeIntLib.h> | |
| #include <Library/BmpSupportLib.h> | |
| /** | |
| Update information of logo image drawn on screen. | |
| @param[in] This The pointer to the Boot Logo protocol 2 instance. | |
| @param[in] BltBuffer The BLT buffer for logo drawn on screen. If BltBuffer | |
| is set to NULL, it indicates that logo image is no | |
| longer on the screen. | |
| @param[in] DestinationX X coordinate of destination for the BltBuffer. | |
| @param[in] DestinationY Y coordinate of destination for the BltBuffer. | |
| @param[in] Width Width of rectangle in BltBuffer in pixels. | |
| @param[in] Height Hight of rectangle in BltBuffer in pixels. | |
| @retval EFI_SUCCESS The boot logo information was updated. | |
| @retval EFI_INVALID_PARAMETER One of the parameters has an invalid value. | |
| @retval EFI_OUT_OF_RESOURCES The logo information was not updated due to | |
| insufficient memory resources. | |
| **/ | |
| EFI_STATUS | |
| EFIAPI | |
| SetBootLogo ( | |
| IN EFI_BOOT_LOGO_PROTOCOL *This, | |
| IN EFI_GRAPHICS_OUTPUT_BLT_PIXEL *BltBuffer OPTIONAL, | |
| IN UINTN DestinationX, | |
| IN UINTN DestinationY, | |
| IN UINTN Width, | |
| IN UINTN Height | |
| ); | |
| /** | |
| Update information of logo image drawn on screen. | |
| @param[in] This The pointer to the Boot Logo protocol 2 instance. | |
| @param[in] BltBuffer The BLT buffer for logo drawn on screen. If BltBuffer | |
| is set to NULL, it indicates that logo image is no | |
| longer on the screen. | |
| @param[in] DestinationX X coordinate of destination for the BltBuffer. | |
| @param[in] DestinationY Y coordinate of destination for the BltBuffer. | |
| @param[in] Width Width of rectangle in BltBuffer in pixels. | |
| @param[in] Height Hight of rectangle in BltBuffer in pixels. | |
| @retval EFI_SUCCESS The boot logo information was updated. | |
| @retval EFI_INVALID_PARAMETER One of the parameters has an invalid value. | |
| @retval EFI_OUT_OF_RESOURCES The logo information was not updated due to | |
| insufficient memory resources. | |
| **/ | |
| EFI_STATUS | |
| EFIAPI | |
| SetBootLogo2 ( | |
| IN EDKII_BOOT_LOGO2_PROTOCOL *This, | |
| IN EFI_GRAPHICS_OUTPUT_BLT_PIXEL *BltBuffer OPTIONAL, | |
| IN UINTN DestinationX, | |
| IN UINTN DestinationY, | |
| IN UINTN Width, | |
| IN UINTN Height | |
| ); | |
| /** | |
| Get the location of the boot logo on the screen. | |
| @param[in] This The pointer to the Boot Logo Protocol 2 instance | |
| @param[out] BltBuffer Returns pointer to the GOP BLT buffer that was | |
| previously registered with SetBootLogo2(). The | |
| buffer returned must not be modified or freed. | |
| @param[out] DestinationX Returns the X start position of the GOP BLT buffer | |
| that was previously registered with SetBootLogo2(). | |
| @param[out] DestinationY Returns the Y start position of the GOP BLT buffer | |
| that was previously registered with SetBootLogo2(). | |
| @param[out] Width Returns the width of the GOP BLT buffer | |
| that was previously registered with SetBootLogo2(). | |
| @param[out] Height Returns the height of the GOP BLT buffer | |
| that was previously registered with SetBootLogo2(). | |
| @retval EFI_SUCCESS The location of the boot logo was returned. | |
| @retval EFI_NOT_READY The boot logo has not been set. | |
| @retval EFI_INVALID_PARAMETER BltBuffer is NULL. | |
| @retval EFI_INVALID_PARAMETER DestinationX is NULL. | |
| @retval EFI_INVALID_PARAMETER DestinationY is NULL. | |
| @retval EFI_INVALID_PARAMETER Width is NULL. | |
| @retval EFI_INVALID_PARAMETER Height is NULL. | |
| **/ | |
| EFI_STATUS | |
| EFIAPI | |
| GetBootLogo2 ( | |
| IN EDKII_BOOT_LOGO2_PROTOCOL *This, | |
| OUT EFI_GRAPHICS_OUTPUT_BLT_PIXEL **BltBuffer, | |
| OUT UINTN *DestinationX, | |
| OUT UINTN *DestinationY, | |
| OUT UINTN *Width, | |
| OUT UINTN *Height | |
| ); | |
| // | |
| // Boot Logo Protocol Handle | |
| // | |
| EFI_HANDLE mBootLogoHandle = NULL; | |
| // | |
| // Boot Logo Protocol Instance | |
| // | |
| EFI_BOOT_LOGO_PROTOCOL mBootLogoProtocolTemplate = { | |
| SetBootLogo | |
| }; | |
| /// | |
| /// Boot Logo 2 Protocol instance | |
| /// | |
| EDKII_BOOT_LOGO2_PROTOCOL mBootLogo2ProtocolTemplate = { | |
| SetBootLogo2, | |
| GetBootLogo2 | |
| }; | |
| EFI_EVENT mBootGraphicsReadyToBootEvent; | |
| UINTN mBootGraphicsResourceTableKey = 0; | |
| BOOLEAN mIsLogoValid = FALSE; | |
| EFI_GRAPHICS_OUTPUT_BLT_PIXEL *mLogoBltBuffer = NULL; | |
| UINTN mLogoDestX = 0; | |
| UINTN mLogoDestY = 0; | |
| UINTN mLogoWidth = 0; | |
| UINTN mLogoHeight = 0; | |
| BOOLEAN mAcpiBgrtInstalled = FALSE; | |
| BOOLEAN mAcpiBgrtStatusChanged = FALSE; | |
| BOOLEAN mAcpiBgrtBufferChanged = FALSE; | |
| // | |
| // ACPI Boot Graphics Resource Table template | |
| // | |
| EFI_ACPI_5_0_BOOT_GRAPHICS_RESOURCE_TABLE mBootGraphicsResourceTableTemplate = { | |
| { | |
| EFI_ACPI_5_0_BOOT_GRAPHICS_RESOURCE_TABLE_SIGNATURE, | |
| sizeof (EFI_ACPI_5_0_BOOT_GRAPHICS_RESOURCE_TABLE), | |
| EFI_ACPI_5_0_BOOT_GRAPHICS_RESOURCE_TABLE_REVISION, // Revision | |
| 0x00, // Checksum will be updated at runtime | |
| // | |
| // It is expected that these values will be updated at EntryPoint. | |
| // | |
| { 0x00 }, // OEM ID is a 6 bytes long field | |
| 0x00, // OEM Table ID(8 bytes long) | |
| 0x00, // OEM Revision | |
| 0x00, // Creator ID | |
| 0x00, // Creator Revision | |
| }, | |
| EFI_ACPI_5_0_BGRT_VERSION, // Version | |
| EFI_ACPI_5_0_BGRT_STATUS_VALID, // Status | |
| EFI_ACPI_5_0_BGRT_IMAGE_TYPE_BMP, // Image Type | |
| 0, // Image Address | |
| 0, // Image Offset X | |
| 0 // Image Offset Y | |
| }; | |
| /** | |
| Update information of logo image drawn on screen. | |
| @param This The pointer to the Boot Logo protocol instance. | |
| @param BltBuffer The BLT buffer for logo drawn on screen. If BltBuffer | |
| is set to NULL, it indicates that logo image is no | |
| longer on the screen. | |
| @param DestinationX X coordinate of destination for the BltBuffer. | |
| @param DestinationY Y coordinate of destination for the BltBuffer. | |
| @param Width Width of rectangle in BltBuffer in pixels. | |
| @param Height Hight of rectangle in BltBuffer in pixels. | |
| @retval EFI_SUCCESS The boot logo information was updated. | |
| @retval EFI_INVALID_PARAMETER One of the parameters has an invalid value. | |
| @retval EFI_OUT_OF_RESOURCES The logo information was not updated due to | |
| insufficient memory resources. | |
| **/ | |
| EFI_STATUS | |
| EFIAPI | |
| SetBootLogo ( | |
| IN EFI_BOOT_LOGO_PROTOCOL *This, | |
| IN EFI_GRAPHICS_OUTPUT_BLT_PIXEL *BltBuffer OPTIONAL, | |
| IN UINTN DestinationX, | |
| IN UINTN DestinationY, | |
| IN UINTN Width, | |
| IN UINTN Height | |
| ) | |
| { | |
| // | |
| // Call same service in Boot Logo 2 Protocol | |
| // | |
| return SetBootLogo2 ( | |
| &mBootLogo2ProtocolTemplate, | |
| BltBuffer, | |
| DestinationX, | |
| DestinationY, | |
| Width, | |
| Height | |
| ); | |
| } | |
| /** | |
| Update information of logo image drawn on screen. | |
| @param[in] This The pointer to the Boot Logo protocol 2 instance. | |
| @param[in] BltBuffer The BLT buffer for logo drawn on screen. If BltBuffer | |
| is set to NULL, it indicates that logo image is no | |
| longer on the screen. | |
| @param[in] DestinationX X coordinate of destination for the BltBuffer. | |
| @param[in] DestinationY Y coordinate of destination for the BltBuffer. | |
| @param[in] Width Width of rectangle in BltBuffer in pixels. | |
| @param[in] Height Hight of rectangle in BltBuffer in pixels. | |
| @retval EFI_SUCCESS The boot logo information was updated. | |
| @retval EFI_INVALID_PARAMETER One of the parameters has an invalid value. | |
| @retval EFI_OUT_OF_RESOURCES The logo information was not updated due to | |
| insufficient memory resources. | |
| **/ | |
| EFI_STATUS | |
| EFIAPI | |
| SetBootLogo2 ( | |
| IN EDKII_BOOT_LOGO2_PROTOCOL *This, | |
| IN EFI_GRAPHICS_OUTPUT_BLT_PIXEL *BltBuffer OPTIONAL, | |
| IN UINTN DestinationX, | |
| IN UINTN DestinationY, | |
| IN UINTN Width, | |
| IN UINTN Height | |
| ) | |
| { | |
| EFI_STATUS Status; | |
| UINTN BufferSize; | |
| UINT32 Result32; | |
| if (BltBuffer == NULL) { | |
| mIsLogoValid = FALSE; | |
| mAcpiBgrtStatusChanged = TRUE; | |
| return EFI_SUCCESS; | |
| } | |
| // | |
| // Width and height are not allowed to be zero. | |
| // | |
| if ((Width == 0) || (Height == 0)) { | |
| return EFI_INVALID_PARAMETER; | |
| } | |
| // | |
| // Verify destination, width, and height do not overflow 32-bit values. | |
| // The Boot Graphics Resource Table only has 32-bit fields for these values. | |
| // | |
| Status = SafeUintnToUint32 (DestinationX, &Result32); | |
| if (EFI_ERROR (Status)) { | |
| return EFI_INVALID_PARAMETER; | |
| } | |
| Status = SafeUintnToUint32 (DestinationY, &Result32); | |
| if (EFI_ERROR (Status)) { | |
| return EFI_INVALID_PARAMETER; | |
| } | |
| Status = SafeUintnToUint32 (Width, &Result32); | |
| if (EFI_ERROR (Status)) { | |
| return EFI_INVALID_PARAMETER; | |
| } | |
| Status = SafeUintnToUint32 (Height, &Result32); | |
| if (EFI_ERROR (Status)) { | |
| return EFI_INVALID_PARAMETER; | |
| } | |
| // | |
| // Ensure the Height * Width * sizeof (EFI_GRAPHICS_OUTPUT_BLT_PIXEL) does | |
| // not overflow UINTN | |
| // | |
| Status = SafeUintnMult ( | |
| Width, | |
| Height, | |
| &BufferSize | |
| ); | |
| if (EFI_ERROR (Status)) { | |
| return EFI_UNSUPPORTED; | |
| } | |
| Status = SafeUintnMult ( | |
| BufferSize, | |
| sizeof (EFI_GRAPHICS_OUTPUT_BLT_PIXEL), | |
| &BufferSize | |
| ); | |
| if (EFI_ERROR (Status)) { | |
| return EFI_UNSUPPORTED; | |
| } | |
| // | |
| // Update state | |
| // | |
| mAcpiBgrtBufferChanged = TRUE; | |
| // | |
| // Free old logo buffer | |
| // | |
| if (mLogoBltBuffer != NULL) { | |
| FreePool (mLogoBltBuffer); | |
| mLogoBltBuffer = NULL; | |
| } | |
| // | |
| // Allocate new logo buffer | |
| // | |
| mLogoBltBuffer = AllocateCopyPool (BufferSize, BltBuffer); | |
| if (mLogoBltBuffer == NULL) { | |
| return EFI_OUT_OF_RESOURCES; | |
| } | |
| mLogoDestX = DestinationX; | |
| mLogoDestY = DestinationY; | |
| mLogoWidth = Width; | |
| mLogoHeight = Height; | |
| mIsLogoValid = TRUE; | |
| return EFI_SUCCESS; | |
| } | |
| /** | |
| Get the location of the boot logo on the screen. | |
| @param[in] This The pointer to the Boot Logo Protocol 2 instance | |
| @param[out] BltBuffer Returns pointer to the GOP BLT buffer that was | |
| previously registered with SetBootLogo2(). The | |
| buffer returned must not be modified or freed. | |
| @param[out] DestinationX Returns the X start position of the GOP BLT buffer | |
| that was previously registered with SetBootLogo2(). | |
| @param[out] DestinationY Returns the Y start position of the GOP BLT buffer | |
| that was previously registered with SetBootLogo2(). | |
| @param[out] Width Returns the width of the GOP BLT buffer | |
| that was previously registered with SetBootLogo2(). | |
| @param[out] Height Returns the height of the GOP BLT buffer | |
| that was previously registered with SetBootLogo2(). | |
| @retval EFI_SUCCESS The location of the boot logo was returned. | |
| @retval EFI_NOT_READY The boot logo has not been set. | |
| @retval EFI_INVALID_PARAMETER BltBuffer is NULL. | |
| @retval EFI_INVALID_PARAMETER DestinationX is NULL. | |
| @retval EFI_INVALID_PARAMETER DestinationY is NULL. | |
| @retval EFI_INVALID_PARAMETER Width is NULL. | |
| @retval EFI_INVALID_PARAMETER Height is NULL. | |
| **/ | |
| EFI_STATUS | |
| EFIAPI | |
| GetBootLogo2 ( | |
| IN EDKII_BOOT_LOGO2_PROTOCOL *This, | |
| OUT EFI_GRAPHICS_OUTPUT_BLT_PIXEL **BltBuffer, | |
| OUT UINTN *DestinationX, | |
| OUT UINTN *DestinationY, | |
| OUT UINTN *Width, | |
| OUT UINTN *Height | |
| ) | |
| { | |
| // | |
| // If the boot logo has not been set with SetBootLogo() or SetBootLogo() was | |
| // called with a NULL BltBuffer then the boot logo is not valid and | |
| // EFI_NOT_READY is returned. | |
| // | |
| if (mLogoBltBuffer == NULL) { | |
| DEBUG ((DEBUG_ERROR, "Request to get boot logo location before boot logo has been set.\n")); | |
| return EFI_NOT_READY; | |
| } | |
| // | |
| // Make sure none of the boot logo location parameters are NULL. | |
| // | |
| if ((BltBuffer == NULL) || (DestinationX == NULL) || (DestinationY == NULL) || | |
| (Width == NULL) || (Height == NULL)) | |
| { | |
| return EFI_INVALID_PARAMETER; | |
| } | |
| // | |
| // Boot logo is valid. Return values from module globals. | |
| // | |
| *BltBuffer = mLogoBltBuffer; | |
| *DestinationX = mLogoDestX; | |
| *DestinationY = mLogoDestY; | |
| *Width = mLogoWidth; | |
| *Height = mLogoHeight; | |
| return EFI_SUCCESS; | |
| } | |
| /** | |
| Notify function for event group EFI_EVENT_GROUP_READY_TO_BOOT. This is used to | |
| install the Boot Graphics Resource Table. | |
| @param[in] Event The Event that is being processed. | |
| @param[in] Context The Event Context. | |
| **/ | |
| VOID | |
| EFIAPI | |
| BgrtReadyToBootEventNotify ( | |
| IN EFI_EVENT Event, | |
| IN VOID *Context | |
| ) | |
| { | |
| EFI_STATUS Status; | |
| EFI_ACPI_TABLE_PROTOCOL *AcpiTableProtocol; | |
| VOID *ImageBuffer; | |
| UINT32 BmpSize; | |
| // | |
| // Get ACPI Table protocol. | |
| // | |
| Status = gBS->LocateProtocol ( | |
| &gEfiAcpiTableProtocolGuid, | |
| NULL, | |
| (VOID **)&AcpiTableProtocol | |
| ); | |
| if (EFI_ERROR (Status)) { | |
| return; | |
| } | |
| // | |
| // Check whether Boot Graphics Resource Table is already installed. | |
| // | |
| if (mAcpiBgrtInstalled) { | |
| if (!mAcpiBgrtStatusChanged && !mAcpiBgrtBufferChanged) { | |
| // | |
| // Nothing has changed | |
| // | |
| return; | |
| } else { | |
| // | |
| // If BGRT data change happens, then uninstall orignal AcpiTable first | |
| // | |
| Status = AcpiTableProtocol->UninstallAcpiTable ( | |
| AcpiTableProtocol, | |
| mBootGraphicsResourceTableKey | |
| ); | |
| if (EFI_ERROR (Status)) { | |
| return; | |
| } | |
| } | |
| } else { | |
| // | |
| // Check whether Logo exists | |
| // | |
| if (mLogoBltBuffer == NULL) { | |
| return; | |
| } | |
| } | |
| if (mAcpiBgrtBufferChanged) { | |
| // | |
| // Free the old BMP image buffer | |
| // | |
| ImageBuffer = (UINT8 *)(UINTN)mBootGraphicsResourceTableTemplate.ImageAddress; | |
| if (ImageBuffer != NULL) { | |
| FreePool (ImageBuffer); | |
| } | |
| // | |
| // Convert GOP Blt buffer to BMP image. Pass in ImageBuffer set to NULL | |
| // so the BMP image is allocated by TranslateGopBltToBmp(). | |
| // | |
| ImageBuffer = NULL; | |
| Status = TranslateGopBltToBmp ( | |
| mLogoBltBuffer, | |
| (UINT32)mLogoHeight, | |
| (UINT32)mLogoWidth, | |
| &ImageBuffer, | |
| &BmpSize | |
| ); | |
| if (EFI_ERROR (Status)) { | |
| return; | |
| } | |
| // | |
| // Free the logo buffer | |
| // | |
| FreePool (mLogoBltBuffer); | |
| mLogoBltBuffer = NULL; | |
| // | |
| // Update BMP image fields of the Boot Graphics Resource Table | |
| // | |
| mBootGraphicsResourceTableTemplate.ImageAddress = (UINT64)(UINTN)ImageBuffer; | |
| mBootGraphicsResourceTableTemplate.ImageOffsetX = (UINT32)mLogoDestX; | |
| mBootGraphicsResourceTableTemplate.ImageOffsetY = (UINT32)mLogoDestY; | |
| } | |
| // | |
| // Update Status field of Boot Graphics Resource Table | |
| // | |
| if (mIsLogoValid) { | |
| mBootGraphicsResourceTableTemplate.Status = EFI_ACPI_5_0_BGRT_STATUS_VALID; | |
| } else { | |
| mBootGraphicsResourceTableTemplate.Status = EFI_ACPI_5_0_BGRT_STATUS_INVALID; | |
| } | |
| // | |
| // Update Checksum of Boot Graphics Resource Table | |
| // | |
| mBootGraphicsResourceTableTemplate.Header.Checksum = 0; | |
| mBootGraphicsResourceTableTemplate.Header.Checksum = | |
| CalculateCheckSum8 ( | |
| (UINT8 *)&mBootGraphicsResourceTableTemplate, | |
| sizeof (EFI_ACPI_5_0_BOOT_GRAPHICS_RESOURCE_TABLE) | |
| ); | |
| // | |
| // Publish Boot Graphics Resource Table. | |
| // | |
| Status = AcpiTableProtocol->InstallAcpiTable ( | |
| AcpiTableProtocol, | |
| &mBootGraphicsResourceTableTemplate, | |
| sizeof (EFI_ACPI_5_0_BOOT_GRAPHICS_RESOURCE_TABLE), | |
| &mBootGraphicsResourceTableKey | |
| ); | |
| if (EFI_ERROR (Status)) { | |
| return; | |
| } | |
| mAcpiBgrtInstalled = TRUE; | |
| mAcpiBgrtStatusChanged = FALSE; | |
| mAcpiBgrtBufferChanged = FALSE; | |
| } | |
| /** | |
| The module Entry Point of the Boot Graphics 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 | |
| BootGraphicsDxeEntryPoint ( | |
| IN EFI_HANDLE ImageHandle, | |
| IN EFI_SYSTEM_TABLE *SystemTable | |
| ) | |
| { | |
| EFI_STATUS Status; | |
| EFI_ACPI_DESCRIPTION_HEADER *Header; | |
| // | |
| // Update Header fields of Boot Graphics Resource Table from PCDs | |
| // | |
| Header = &mBootGraphicsResourceTableTemplate.Header; | |
| ZeroMem (Header->OemId, sizeof (Header->OemId)); | |
| CopyMem ( | |
| Header->OemId, | |
| PcdGetPtr (PcdAcpiDefaultOemId), | |
| MIN (PcdGetSize (PcdAcpiDefaultOemId), sizeof (Header->OemId)) | |
| ); | |
| WriteUnaligned64 (&Header->OemTableId, PcdGet64 (PcdAcpiDefaultOemTableId)); | |
| Header->OemRevision = PcdGet32 (PcdAcpiDefaultOemRevision); | |
| Header->CreatorId = PcdGet32 (PcdAcpiDefaultCreatorId); | |
| Header->CreatorRevision = PcdGet32 (PcdAcpiDefaultCreatorRevision); | |
| // | |
| // Install Boot Logo and Boot Logo 2 Protocols. | |
| // | |
| Status = gBS->InstallMultipleProtocolInterfaces ( | |
| &mBootLogoHandle, | |
| &gEfiBootLogoProtocolGuid, | |
| &mBootLogoProtocolTemplate, | |
| &gEdkiiBootLogo2ProtocolGuid, | |
| &mBootLogo2ProtocolTemplate, | |
| NULL | |
| ); | |
| ASSERT_EFI_ERROR (Status); | |
| // | |
| // Register notify function to install BGRT on ReadyToBoot Event. | |
| // | |
| Status = gBS->CreateEventEx ( | |
| EVT_NOTIFY_SIGNAL, | |
| TPL_CALLBACK, | |
| BgrtReadyToBootEventNotify, | |
| NULL, | |
| &gEfiEventReadyToBootGuid, | |
| &mBootGraphicsReadyToBootEvent | |
| ); | |
| ASSERT_EFI_ERROR (Status); | |
| return Status; | |
| } |