Home | History | Annotate | Download | only in BootGraphicsResourceTableDxe
      1 /** @file
      2   This module install ACPI Boot Graphics Resource Table (BGRT).
      3 
      4   Copyright (c) 2011 - 2013, Intel Corporation. All rights reserved.<BR>
      5   This program and the accompanying materials
      6   are licensed and made available under the terms and conditions of the BSD License
      7   which accompanies this distribution.  The full text of the license may be found at
      8   http://opensource.org/licenses/bsd-license.php
      9 
     10   THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
     11   WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
     12 **/
     13 
     14 #include <Uefi.h>
     15 
     16 #include <IndustryStandard/Acpi.h>
     17 #include <IndustryStandard/Bmp.h>
     18 
     19 #include <Protocol/AcpiTable.h>
     20 #include <Protocol/GraphicsOutput.h>
     21 #include <Protocol/BootLogo.h>
     22 
     23 #include <Guid/EventGroup.h>
     24 
     25 #include <Library/BaseLib.h>
     26 #include <Library/BaseMemoryLib.h>
     27 #include <Library/MemoryAllocationLib.h>
     28 #include <Library/UefiBootServicesTableLib.h>
     29 #include <Library/DebugLib.h>
     30 #include <Library/PcdLib.h>
     31 
     32 //
     33 // Module globals.
     34 //
     35 EFI_EVENT  mBootGraphicsReadyToBootEvent;
     36 UINTN      mBootGraphicsResourceTableKey = 0;
     37 
     38 EFI_HANDLE                     mBootLogoHandle = NULL;
     39 BOOLEAN                        mIsLogoValid = FALSE;
     40 EFI_GRAPHICS_OUTPUT_BLT_PIXEL  *mLogoBltBuffer = NULL;
     41 UINTN                          mLogoDestX = 0;
     42 UINTN                          mLogoDestY = 0;
     43 UINTN                          mLogoWidth = 0;
     44 UINTN                          mLogoHeight = 0;
     45 
     46 BMP_IMAGE_HEADER  mBmpImageHeaderTemplate = {
     47   'B',    // CharB
     48   'M',    // CharM
     49   0,      // Size will be updated at runtime
     50   {0, 0}, // Reserved
     51   sizeof (BMP_IMAGE_HEADER), // ImageOffset
     52   sizeof (BMP_IMAGE_HEADER) - OFFSET_OF (BMP_IMAGE_HEADER, HeaderSize), // HeaderSize
     53   0,      // PixelWidth will be updated at runtime
     54   0,      // PixelHeight will be updated at runtime
     55   1,      // Planes
     56   24,     // BitPerPixel
     57   0,      // CompressionType
     58   0,      // ImageSize will be updated at runtime
     59   0,      // XPixelsPerMeter
     60   0,      // YPixelsPerMeter
     61   0,      // NumberOfColors
     62   0       // ImportantColors
     63 };
     64 
     65 BOOLEAN  mAcpiBgrtInstalled = FALSE;
     66 BOOLEAN  mAcpiBgrtStatusChanged = FALSE;
     67 BOOLEAN  mAcpiBgrtBufferChanged = FALSE;
     68 
     69 EFI_ACPI_5_0_BOOT_GRAPHICS_RESOURCE_TABLE mBootGraphicsResourceTableTemplate = {
     70   {
     71     EFI_ACPI_5_0_BOOT_GRAPHICS_RESOURCE_TABLE_SIGNATURE,
     72     sizeof (EFI_ACPI_5_0_BOOT_GRAPHICS_RESOURCE_TABLE),
     73     EFI_ACPI_5_0_BOOT_GRAPHICS_RESOURCE_TABLE_REVISION,     // Revision
     74     0x00,  // Checksum will be updated at runtime
     75     //
     76     // It is expected that these values will be updated at EntryPoint.
     77     //
     78     {0x00},     // OEM ID is a 6 bytes long field
     79     0x00,       // OEM Table ID(8 bytes long)
     80     0x00,       // OEM Revision
     81     0x00,       // Creator ID
     82     0x00,       // Creator Revision
     83   },
     84   EFI_ACPI_5_0_BGRT_VERSION,         // Version
     85   EFI_ACPI_5_0_BGRT_STATUS_VALID,    // Status
     86   EFI_ACPI_5_0_BGRT_IMAGE_TYPE_BMP,  // Image Type
     87   0,                                 // Image Address
     88   0,                                 // Image Offset X
     89   0                                  // Image Offset Y
     90 };
     91 
     92 /**
     93   Update information of logo image drawn on screen.
     94 
     95   @param  This           The pointer to the Boot Logo protocol instance.
     96   @param  BltBuffer      The BLT buffer for logo drawn on screen. If BltBuffer
     97                          is set to NULL, it indicates that logo image is no
     98                          longer on the screen.
     99   @param  DestinationX   X coordinate of destination for the BltBuffer.
    100   @param  DestinationY   Y coordinate of destination for the BltBuffer.
    101   @param  Width          Width of rectangle in BltBuffer in pixels.
    102   @param  Height         Hight of rectangle in BltBuffer in pixels.
    103 
    104   @retval EFI_SUCCESS             The boot logo information was updated.
    105   @retval EFI_INVALID_PARAMETER   One of the parameters has an invalid value.
    106   @retval EFI_OUT_OF_RESOURCES    The logo information was not updated due to
    107                                   insufficient memory resources.
    108 
    109 **/
    110 EFI_STATUS
    111 EFIAPI
    112 SetBootLogo (
    113   IN EFI_BOOT_LOGO_PROTOCOL            *This,
    114   IN EFI_GRAPHICS_OUTPUT_BLT_PIXEL     *BltBuffer       OPTIONAL,
    115   IN UINTN                             DestinationX,
    116   IN UINTN                             DestinationY,
    117   IN UINTN                             Width,
    118   IN UINTN                             Height
    119   );
    120 
    121 EFI_BOOT_LOGO_PROTOCOL  mBootLogoProtocolTemplate = { SetBootLogo };
    122 
    123 /**
    124   Update information of logo image drawn on screen.
    125 
    126   @param  This           The pointer to the Boot Logo protocol instance.
    127   @param  BltBuffer      The BLT buffer for logo drawn on screen. If BltBuffer
    128                          is set to NULL, it indicates that logo image is no
    129                          longer on the screen.
    130   @param  DestinationX   X coordinate of destination for the BltBuffer.
    131   @param  DestinationY   Y coordinate of destination for the BltBuffer.
    132   @param  Width          Width of rectangle in BltBuffer in pixels.
    133   @param  Height         Hight of rectangle in BltBuffer in pixels.
    134 
    135   @retval EFI_SUCCESS             The boot logo information was updated.
    136   @retval EFI_INVALID_PARAMETER   One of the parameters has an invalid value.
    137   @retval EFI_OUT_OF_RESOURCES    The logo information was not updated due to
    138                                   insufficient memory resources.
    139 
    140 **/
    141 EFI_STATUS
    142 EFIAPI
    143 SetBootLogo (
    144   IN EFI_BOOT_LOGO_PROTOCOL            *This,
    145   IN EFI_GRAPHICS_OUTPUT_BLT_PIXEL     *BltBuffer       OPTIONAL,
    146   IN UINTN                             DestinationX,
    147   IN UINTN                             DestinationY,
    148   IN UINTN                             Width,
    149   IN UINTN                             Height
    150   )
    151 {
    152   UINT64                        BufferSize;
    153 
    154   if (BltBuffer == NULL) {
    155     mIsLogoValid = FALSE;
    156     mAcpiBgrtStatusChanged = TRUE;
    157     return EFI_SUCCESS;
    158   }
    159 
    160   if (Width == 0 || Height == 0) {
    161     return EFI_INVALID_PARAMETER;
    162   }
    163 
    164   mAcpiBgrtBufferChanged = TRUE;
    165   if (mLogoBltBuffer != NULL) {
    166     FreePool (mLogoBltBuffer);
    167     mLogoBltBuffer = NULL;
    168   }
    169 
    170   //
    171   // Ensure the Height * Width doesn't overflow
    172   //
    173   if (Height > DivU64x64Remainder ((UINTN) ~0, Width, NULL)) {
    174     return EFI_UNSUPPORTED;
    175   }
    176   BufferSize = MultU64x64 (Width, Height);
    177 
    178   //
    179   // Ensure the BufferSize * sizeof (EFI_GRAPHICS_OUTPUT_BLT_PIXEL) doesn't overflow
    180   //
    181   if (BufferSize > DivU64x32 ((UINTN) ~0, sizeof (EFI_GRAPHICS_OUTPUT_BLT_PIXEL))) {
    182     return EFI_UNSUPPORTED;
    183   }
    184 
    185   mLogoBltBuffer = AllocateCopyPool (
    186                      (UINTN)BufferSize * sizeof (EFI_GRAPHICS_OUTPUT_BLT_PIXEL),
    187                      BltBuffer
    188                      );
    189   if (mLogoBltBuffer == NULL) {
    190     return EFI_OUT_OF_RESOURCES;
    191   }
    192   mLogoDestX = DestinationX;
    193   mLogoDestY = DestinationY;
    194   mLogoWidth = Width;
    195   mLogoHeight = Height;
    196   mIsLogoValid = TRUE;
    197 
    198   return EFI_SUCCESS;
    199 }
    200 
    201 /**
    202   This function calculates and updates an UINT8 checksum.
    203 
    204   @param[in]  Buffer          Pointer to buffer to checksum.
    205   @param[in]  Size            Number of bytes to checksum.
    206 
    207 **/
    208 VOID
    209 BgrtAcpiTableChecksum (
    210   IN UINT8      *Buffer,
    211   IN UINTN      Size
    212   )
    213 {
    214   UINTN ChecksumOffset;
    215 
    216   ChecksumOffset = OFFSET_OF (EFI_ACPI_DESCRIPTION_HEADER, Checksum);
    217 
    218   //
    219   // Set checksum to 0 first.
    220   //
    221   Buffer[ChecksumOffset] = 0;
    222 
    223   //
    224   // Update checksum value.
    225   //
    226   Buffer[ChecksumOffset] = CalculateCheckSum8 (Buffer, Size);
    227 }
    228 
    229 /**
    230   Allocate EfiBootServicesData below 4G memory address.
    231 
    232   This function allocates EfiBootServicesData below 4G memory address.
    233 
    234   @param[in]  Size   Size of memory to allocate.
    235 
    236   @return Allocated address for output.
    237 
    238 **/
    239 VOID *
    240 BgrtAllocateBsDataMemoryBelow4G (
    241   IN UINTN       Size
    242   )
    243 {
    244   UINTN                 Pages;
    245   EFI_PHYSICAL_ADDRESS  Address;
    246   EFI_STATUS            Status;
    247   VOID                  *Buffer;
    248 
    249   Pages   = EFI_SIZE_TO_PAGES (Size);
    250   Address = 0xffffffff;
    251 
    252   Status = gBS->AllocatePages (
    253                   AllocateMaxAddress,
    254                   EfiBootServicesData,
    255                   Pages,
    256                   &Address
    257                   );
    258   ASSERT_EFI_ERROR (Status);
    259 
    260   Buffer = (VOID *) (UINTN) Address;
    261   ZeroMem (Buffer, Size);
    262 
    263   return Buffer;
    264 }
    265 
    266 /**
    267   Install Boot Graphics Resource Table to ACPI table.
    268 
    269   @return Status code.
    270 
    271 **/
    272 EFI_STATUS
    273 InstallBootGraphicsResourceTable (
    274   VOID
    275   )
    276 {
    277   EFI_STATUS                    Status;
    278   EFI_ACPI_TABLE_PROTOCOL       *AcpiTableProtocol;
    279   UINT8                         *ImageBuffer;
    280   UINTN                         PaddingSize;
    281   UINTN                         BmpSize;
    282   UINTN                         OrigBmpSize;
    283   UINT8                         *Image;
    284   EFI_GRAPHICS_OUTPUT_BLT_PIXEL *BltPixel;
    285   UINTN                         Col;
    286   UINTN                         Row;
    287 
    288   //
    289   // Get ACPI Table protocol.
    290   //
    291   Status = gBS->LocateProtocol (&gEfiAcpiTableProtocolGuid, NULL, (VOID **) &AcpiTableProtocol);
    292   if (EFI_ERROR (Status)) {
    293     return Status;
    294   }
    295 
    296   //
    297   // Check whether Boot Graphics Resource Table is already installed.
    298   //
    299   if (mAcpiBgrtInstalled) {
    300     if (!mAcpiBgrtStatusChanged && !mAcpiBgrtBufferChanged) {
    301       //
    302       // Nothing has changed
    303       //
    304       return EFI_SUCCESS;
    305     } else {
    306       //
    307       // If BGRT data change happens. Uninstall Orignal AcpiTable first
    308       //
    309       Status = AcpiTableProtocol->UninstallAcpiTable (
    310                                     AcpiTableProtocol,
    311                                     mBootGraphicsResourceTableKey
    312                                     );
    313       if (EFI_ERROR (Status)) {
    314         return Status;
    315       }
    316     }
    317   } else {
    318     //
    319     // Check whether Logo exist.
    320     //
    321     if ( mLogoBltBuffer == NULL) {
    322       return EFI_NOT_FOUND;
    323     }
    324   }
    325 
    326   if (mAcpiBgrtBufferChanged) {
    327     //
    328     // reserve original BGRT buffer size
    329     //
    330     OrigBmpSize = mBmpImageHeaderTemplate.ImageSize + sizeof (BMP_IMAGE_HEADER);
    331     //
    332     // Free orignal BMP memory
    333     //
    334     if (mBootGraphicsResourceTableTemplate.ImageAddress) {
    335       gBS->FreePages(mBootGraphicsResourceTableTemplate.ImageAddress, EFI_SIZE_TO_PAGES(OrigBmpSize));
    336     }
    337 
    338     //
    339     // Allocate memory for BMP file.
    340     //
    341     PaddingSize = mLogoWidth & 0x3;
    342 
    343     //
    344     // First check mLogoWidth * 3 + PaddingSize doesn't overflow
    345     //
    346     if (mLogoWidth > (((UINT32) ~0) - PaddingSize) / 3 ) {
    347       return EFI_UNSUPPORTED;
    348     }
    349 
    350     //
    351     // Second check (mLogoWidth * 3 + PaddingSize) * mLogoHeight + sizeof (BMP_IMAGE_HEADER) doesn't overflow
    352     //
    353     if (mLogoHeight > (((UINT32) ~0) - sizeof (BMP_IMAGE_HEADER)) / (mLogoWidth * 3 + PaddingSize)) {
    354       return EFI_UNSUPPORTED;
    355     }
    356 
    357     //
    358     // The image should be stored in EfiBootServicesData, allowing the system to reclaim the memory
    359     //
    360     BmpSize = (mLogoWidth * 3 + PaddingSize) * mLogoHeight + sizeof (BMP_IMAGE_HEADER);
    361     ImageBuffer = BgrtAllocateBsDataMemoryBelow4G (BmpSize);
    362     if (ImageBuffer == NULL) {
    363       return EFI_OUT_OF_RESOURCES;
    364     }
    365 
    366     mBmpImageHeaderTemplate.Size = (UINT32) BmpSize;
    367     mBmpImageHeaderTemplate.ImageSize = (UINT32) BmpSize - sizeof (BMP_IMAGE_HEADER);
    368     mBmpImageHeaderTemplate.PixelWidth = (UINT32) mLogoWidth;
    369     mBmpImageHeaderTemplate.PixelHeight = (UINT32) mLogoHeight;
    370     CopyMem (ImageBuffer, &mBmpImageHeaderTemplate, sizeof (BMP_IMAGE_HEADER));
    371 
    372     //
    373     // Convert BLT buffer to BMP file.
    374     //
    375     Image = ImageBuffer + sizeof (BMP_IMAGE_HEADER);
    376     for (Row = 0; Row < mLogoHeight; Row++) {
    377     BltPixel = &mLogoBltBuffer[(mLogoHeight - Row - 1) * mLogoWidth];
    378 
    379     for (Col = 0; Col < mLogoWidth; Col++) {
    380       *Image++ = BltPixel->Blue;
    381       *Image++ = BltPixel->Green;
    382       *Image++ = BltPixel->Red;
    383       BltPixel++;
    384     }
    385 
    386       //
    387       // Padding for 4 byte alignment.
    388       //
    389       Image += PaddingSize;
    390     }
    391     FreePool (mLogoBltBuffer);
    392     mLogoBltBuffer = NULL;
    393 
    394     mBootGraphicsResourceTableTemplate.ImageAddress = (UINT64) (UINTN) ImageBuffer;
    395     mBootGraphicsResourceTableTemplate.ImageOffsetX = (UINT32) mLogoDestX;
    396     mBootGraphicsResourceTableTemplate.ImageOffsetY = (UINT32) mLogoDestY;
    397   }
    398 
    399   mBootGraphicsResourceTableTemplate.Status = (UINT8) (mIsLogoValid ? EFI_ACPI_5_0_BGRT_STATUS_VALID : EFI_ACPI_5_0_BGRT_STATUS_INVALID);
    400 
    401   //
    402   // Update Checksum.
    403   //
    404   BgrtAcpiTableChecksum ((UINT8 *) &mBootGraphicsResourceTableTemplate, sizeof (EFI_ACPI_5_0_BOOT_GRAPHICS_RESOURCE_TABLE));
    405 
    406   //
    407   // Publish Boot Graphics Resource Table.
    408   //
    409   Status = AcpiTableProtocol->InstallAcpiTable (
    410                                 AcpiTableProtocol,
    411                                 &mBootGraphicsResourceTableTemplate,
    412                                 sizeof (EFI_ACPI_5_0_BOOT_GRAPHICS_RESOURCE_TABLE),
    413                                 &mBootGraphicsResourceTableKey
    414                                 );
    415   if (EFI_ERROR (Status)) {
    416     return Status;
    417   }
    418 
    419   mAcpiBgrtInstalled = TRUE;
    420   mAcpiBgrtStatusChanged = FALSE;
    421   mAcpiBgrtBufferChanged = FALSE;
    422 
    423   return Status;
    424 }
    425 
    426 /**
    427   Notify function for event group EFI_EVENT_GROUP_READY_TO_BOOT. This is used to
    428   install the Boot Graphics Resource Table.
    429 
    430   @param[in]  Event   The Event that is being processed.
    431   @param[in]  Context The Event Context.
    432 
    433 **/
    434 VOID
    435 EFIAPI
    436 BgrtReadyToBootEventNotify (
    437   IN EFI_EVENT        Event,
    438   IN VOID             *Context
    439   )
    440 {
    441   InstallBootGraphicsResourceTable ();
    442 }
    443 
    444 /**
    445   The module Entry Point of the Boot Graphics Resource Table DXE driver.
    446 
    447   @param[in]  ImageHandle    The firmware allocated handle for the EFI image.
    448   @param[in]  SystemTable    A pointer to the EFI System Table.
    449 
    450   @retval EFI_SUCCESS    The entry point is executed successfully.
    451   @retval Other          Some error occurs when executing this entry point.
    452 
    453 **/
    454 EFI_STATUS
    455 EFIAPI
    456 BootGraphicsDxeEntryPoint (
    457   IN EFI_HANDLE          ImageHandle,
    458   IN EFI_SYSTEM_TABLE    *SystemTable
    459   )
    460 {
    461   EFI_STATUS  Status;
    462   UINT64      OemTableId;
    463 
    464   CopyMem (
    465     mBootGraphicsResourceTableTemplate.Header.OemId,
    466     PcdGetPtr (PcdAcpiDefaultOemId),
    467     sizeof (mBootGraphicsResourceTableTemplate.Header.OemId)
    468     );
    469   OemTableId = PcdGet64 (PcdAcpiDefaultOemTableId);
    470   CopyMem (&mBootGraphicsResourceTableTemplate.Header.OemTableId, &OemTableId, sizeof (UINT64));
    471   mBootGraphicsResourceTableTemplate.Header.OemRevision      = PcdGet32 (PcdAcpiDefaultOemRevision);
    472   mBootGraphicsResourceTableTemplate.Header.CreatorId        = PcdGet32 (PcdAcpiDefaultCreatorId);
    473   mBootGraphicsResourceTableTemplate.Header.CreatorRevision  = PcdGet32 (PcdAcpiDefaultCreatorRevision);
    474 
    475   //
    476   // Install Boot Logo protocol.
    477   //
    478   Status = gBS->InstallMultipleProtocolInterfaces (
    479                   &mBootLogoHandle,
    480                   &gEfiBootLogoProtocolGuid,
    481                   &mBootLogoProtocolTemplate,
    482                   NULL
    483                   );
    484   ASSERT_EFI_ERROR (Status);
    485 
    486   //
    487   // Register notify function to install BGRT on ReadyToBoot Event.
    488   //
    489   Status = gBS->CreateEventEx (
    490                   EVT_NOTIFY_SIGNAL,
    491                   TPL_CALLBACK,
    492                   BgrtReadyToBootEventNotify,
    493                   NULL,
    494                   &gEfiEventReadyToBootGuid,
    495                   &mBootGraphicsReadyToBootEvent
    496                   );
    497   ASSERT_EFI_ERROR (Status);
    498 
    499   return Status;
    500 }
    501