Home | History | Annotate | Download | only in BootLogoLib
      1 /** @file
      2   This library is only intended to be used by PlatformBootManagerLib
      3   to show progress bar and LOGO.
      4 
      5 Copyright (c) 2011 - 2015, Intel Corporation. All rights reserved.<BR>
      6 This program and the accompanying materials are licensed and made available under
      7 the terms and conditions of the BSD License that accompanies this distribution.
      8 The full text of the license may be found at
      9 http://opensource.org/licenses/bsd-license.php.
     10 
     11 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
     12 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
     13 
     14 **/
     15 
     16 #include <PiDxe.h>
     17 #include <Protocol/SimpleTextOut.h>
     18 #include <Protocol/PlatformLogo.h>
     19 #include <Protocol/GraphicsOutput.h>
     20 #include <Protocol/UgaDraw.h>
     21 #include <Protocol/BootLogo.h>
     22 #include <Library/BaseLib.h>
     23 #include <Library/UefiLib.h>
     24 #include <Library/BaseMemoryLib.h>
     25 #include <Library/UefiBootServicesTableLib.h>
     26 #include <Library/DxeServicesLib.h>
     27 #include <Library/PcdLib.h>
     28 #include <Library/MemoryAllocationLib.h>
     29 #include <Library/DebugLib.h>
     30 #include <Library/ImageDecoderLib.h>
     31 
     32 /**
     33   Show LOGO on all consoles.
     34 
     35   @param[in]  ImageFormat Format of the image file.
     36   @param[in]  LogoFile    The file name of logo to display.
     37   @param[in]  Attribute   The display attributes of the image returned.
     38   @param[in]  OffsetX     The X offset of the image regarding the Attribute.
     39   @param[in]  OffsetY     The Y offset of the image regarding the Attribute.
     40 
     41   @retval EFI_SUCCESS     Logo was displayed.
     42   @retval EFI_UNSUPPORTED Logo was not found or cannot be displayed.
     43 **/
     44 EFI_STATUS
     45 EFIAPI
     46 BootLogoEnableLogo (
     47   IN  IMAGE_FORMAT                          ImageFormat,
     48   IN  EFI_GUID                              *Logo,
     49   IN  EDKII_PLATFORM_LOGO_DISPLAY_ATTRIBUTE Attribute,
     50   IN  INTN                                  OffsetX,
     51   IN  INTN                                  OffsetY
     52   )
     53 {
     54   EFI_STATUS                    Status;
     55   EDKII_PLATFORM_LOGO_PROTOCOL  *PlatformLogo;
     56   UINT32                        SizeOfX;
     57   UINT32                        SizeOfY;
     58   INTN                          DestX;
     59   INTN                          DestY;
     60   UINT8                         *ImageData;
     61   UINTN                         ImageSize;
     62   UINTN                         BltSize;
     63   UINT32                        Instance;
     64   UINTN                         Height;
     65   UINTN                         Width;
     66   EFI_GRAPHICS_OUTPUT_BLT_PIXEL *Blt;
     67   EFI_UGA_DRAW_PROTOCOL         *UgaDraw;
     68   UINT32                        ColorDepth;
     69   UINT32                        RefreshRate;
     70   EFI_GRAPHICS_OUTPUT_PROTOCOL  *GraphicsOutput;
     71   EFI_BOOT_LOGO_PROTOCOL        *BootLogo;
     72   UINTN                         NumberOfLogos;
     73   EFI_GRAPHICS_OUTPUT_BLT_PIXEL *LogoBlt;
     74   UINTN                         LogoDestX;
     75   UINTN                         LogoDestY;
     76   UINTN                         LogoHeight;
     77   UINTN                         LogoWidth;
     78   UINTN                         NewDestX;
     79   UINTN                         NewDestY;
     80   UINTN                         NewHeight;
     81   UINTN                         NewWidth;
     82   UINTN                         BufferSize;
     83 
     84   UgaDraw = NULL;
     85   //
     86   // Try to open GOP first
     87   //
     88   Status = gBS->HandleProtocol (gST->ConsoleOutHandle, &gEfiGraphicsOutputProtocolGuid, (VOID **) &GraphicsOutput);
     89   if (EFI_ERROR (Status) && FeaturePcdGet (PcdUgaConsumeSupport)) {
     90     GraphicsOutput = NULL;
     91     //
     92     // Open GOP failed, try to open UGA
     93     //
     94     Status = gBS->HandleProtocol (gST->ConsoleOutHandle, &gEfiUgaDrawProtocolGuid, (VOID **) &UgaDraw);
     95     if (EFI_ERROR (Status)) {
     96       UgaDraw = NULL;
     97     }
     98   }
     99   if (EFI_ERROR (Status)) {
    100     return EFI_UNSUPPORTED;
    101   }
    102 
    103   Status  = gBS->LocateProtocol (&gEdkiiPlatformLogoProtocolGuid, NULL, (VOID **) &PlatformLogo);
    104   if (EFI_ERROR (Status)) {
    105     PlatformLogo = NULL;
    106   }
    107 
    108   if ((Logo == NULL) && (PlatformLogo == NULL)) {
    109     return EFI_UNSUPPORTED;
    110   }
    111 
    112   //
    113   // Try to open Boot Logo Protocol.
    114   //
    115   Status = gBS->LocateProtocol (&gEfiBootLogoProtocolGuid, NULL, (VOID **) &BootLogo);
    116   if (EFI_ERROR (Status)) {
    117     BootLogo = NULL;
    118   }
    119 
    120   //
    121   // Erase Cursor from screen
    122   //
    123   gST->ConOut->EnableCursor (gST->ConOut, FALSE);
    124 
    125   if (GraphicsOutput != NULL) {
    126     SizeOfX = GraphicsOutput->Mode->Info->HorizontalResolution;
    127     SizeOfY = GraphicsOutput->Mode->Info->VerticalResolution;
    128 
    129   } else {
    130     ASSERT (UgaDraw != NULL);
    131     Status = UgaDraw->GetMode (UgaDraw, &SizeOfX, &SizeOfY, &ColorDepth, &RefreshRate);
    132     if (EFI_ERROR (Status)) {
    133       return EFI_UNSUPPORTED;
    134     }
    135   }
    136 
    137   Blt = NULL;
    138   NumberOfLogos = 0;
    139   LogoDestX = 0;
    140   LogoDestY = 0;
    141   LogoHeight = 0;
    142   LogoWidth = 0;
    143   NewDestX = 0;
    144   NewDestY = 0;
    145   NewHeight = 0;
    146   NewWidth = 0;
    147   Instance = 0;
    148   DestX = 0;
    149   DestY = 0;
    150   while (TRUE) {
    151     ImageData = NULL;
    152     ImageSize = 0;
    153 
    154     if (PlatformLogo != NULL) {
    155       //
    156       // Get image from OEMBadging protocol.
    157       //
    158       Status = PlatformLogo->GetImage (
    159                                PlatformLogo,
    160                                &Instance,
    161                                &ImageFormat,
    162                                &ImageData,
    163                                &ImageSize,
    164                                &Attribute,
    165                                &OffsetX,
    166                                &OffsetY
    167                                );
    168       if (EFI_ERROR (Status)) {
    169         break;
    170       }
    171 
    172     } else {
    173       //
    174       // Get the specified image from FV.
    175       //
    176       Status = GetSectionFromAnyFv (Logo, EFI_SECTION_RAW, 0, (VOID **) &ImageData, &ImageSize);
    177       if (EFI_ERROR (Status)) {
    178         return EFI_UNSUPPORTED;
    179       }
    180     }
    181 
    182     if (Blt != NULL) {
    183       FreePool (Blt);
    184     }
    185 
    186     Status = DecodeImage (ImageFormat, ImageData, ImageSize, &Blt, &BltSize, &Width, &Height);
    187     FreePool (ImageData);
    188     if (EFI_ERROR (Status)) {
    189       if (Logo != NULL) {
    190         //
    191         // Directly return failure for single LOGO
    192         //
    193         return Status;
    194       } else {
    195         continue;
    196       }
    197     }
    198 
    199     //
    200     // Calculate the display position according to Attribute.
    201     //
    202     switch (Attribute) {
    203     case EdkiiPlatformLogoDisplayAttributeLeftTop:
    204       DestX = 0;
    205       DestY = 0;
    206       break;
    207     case EdkiiPlatformLogoDisplayAttributeCenterTop:
    208       DestX = (SizeOfX - Width) / 2;
    209       DestY = 0;
    210       break;
    211     case EdkiiPlatformLogoDisplayAttributeRightTop:
    212       DestX = SizeOfX - Width;
    213       DestY = 0;
    214       break;
    215 
    216     case EdkiiPlatformLogoDisplayAttributeCenterLeft:
    217       DestX = 0;
    218       DestY = (SizeOfY - Height) / 2;
    219       break;
    220     case EdkiiPlatformLogoDisplayAttributeCenter:
    221       DestX = (SizeOfX - Width) / 2;
    222       DestY = (SizeOfY - Height) / 2;
    223       break;
    224     case EdkiiPlatformLogoDisplayAttributeCenterRight:
    225       DestX = SizeOfX - Width;
    226       DestY = (SizeOfY - Height) / 2;
    227       break;
    228 
    229     case EdkiiPlatformLogoDisplayAttributeLeftBottom:
    230       DestX = 0;
    231       DestY = SizeOfY - Height;
    232       break;
    233     case EdkiiPlatformLogoDisplayAttributeCenterBottom:
    234       DestX = (SizeOfX - Width) / 2;
    235       DestY = SizeOfY - Height;
    236       break;
    237     case EdkiiPlatformLogoDisplayAttributeRightBottom:
    238       DestX = SizeOfX - Width;
    239       DestY = SizeOfY - Height;
    240       break;
    241 
    242     default:
    243       ASSERT (FALSE);
    244       break;
    245     }
    246 
    247     DestX += OffsetX;
    248     DestY += OffsetY;
    249 
    250     if ((DestX >= 0) && (DestY >= 0)) {
    251       if (GraphicsOutput != NULL) {
    252         Status = GraphicsOutput->Blt (
    253                                    GraphicsOutput,
    254                                    Blt,
    255                                    EfiBltBufferToVideo,
    256                                    0,
    257                                    0,
    258                                    (UINTN) DestX,
    259                                    (UINTN) DestY,
    260                                    Width,
    261                                    Height,
    262                                    Width * sizeof (EFI_GRAPHICS_OUTPUT_BLT_PIXEL)
    263                                    );
    264       } else {
    265         ASSERT (UgaDraw != NULL);
    266         Status = UgaDraw->Blt (
    267                             UgaDraw,
    268                             (EFI_UGA_PIXEL *) Blt,
    269                             EfiUgaBltBufferToVideo,
    270                             0,
    271                             0,
    272                             (UINTN) DestX,
    273                             (UINTN) DestY,
    274                             Width,
    275                             Height,
    276                             Width * sizeof (EFI_UGA_PIXEL)
    277                             );
    278       }
    279 
    280       //
    281       // Report displayed Logo information.
    282       //
    283       if (!EFI_ERROR (Status)) {
    284         NumberOfLogos++;
    285 
    286         if (LogoWidth == 0) {
    287           //
    288           // The first Logo.
    289           //
    290           LogoDestX = (UINTN) DestX;
    291           LogoDestY = (UINTN) DestY;
    292           LogoWidth = Width;
    293           LogoHeight = Height;
    294         } else {
    295           //
    296           // Merge new logo with old one.
    297           //
    298           NewDestX = MIN ((UINTN) DestX, LogoDestX);
    299           NewDestY = MIN ((UINTN) DestY, LogoDestY);
    300           NewWidth = MAX ((UINTN) DestX + Width, LogoDestX + LogoWidth) - NewDestX;
    301           NewHeight = MAX ((UINTN) DestY + Height, LogoDestY + LogoHeight) - NewDestY;
    302 
    303           LogoDestX = NewDestX;
    304           LogoDestY = NewDestY;
    305           LogoWidth = NewWidth;
    306           LogoHeight = NewHeight;
    307         }
    308       }
    309     }
    310 
    311     if (PlatformLogo == NULL) {
    312       break;
    313     }
    314   }
    315 
    316   if (BootLogo == NULL || NumberOfLogos == 0) {
    317     //
    318     // No logo displayed.
    319     //
    320     if (Blt != NULL) {
    321       FreePool (Blt);
    322     }
    323 
    324     return Status;
    325   }
    326 
    327   //
    328   // Advertise displayed Logo information.
    329   //
    330   if (NumberOfLogos == 1) {
    331     //
    332     // Only one logo displayed, use its Blt buffer directly for BootLogo protocol.
    333     //
    334     LogoBlt = Blt;
    335     Status = EFI_SUCCESS;
    336   } else {
    337     //
    338     // More than one Logo displayed, get merged BltBuffer using VideoToBuffer operation.
    339     //
    340     if (Blt != NULL) {
    341       FreePool (Blt);
    342     }
    343 
    344     //
    345     // Ensure the LogoHeight * LogoWidth * sizeof (EFI_GRAPHICS_OUTPUT_BLT_PIXEL) doesn't overflow
    346     //
    347     if (LogoHeight > MAX_UINTN / LogoWidth / sizeof (EFI_GRAPHICS_OUTPUT_BLT_PIXEL)) {
    348       return EFI_UNSUPPORTED;
    349     }
    350     BufferSize = LogoWidth * LogoHeight * sizeof (EFI_GRAPHICS_OUTPUT_BLT_PIXEL);
    351 
    352     LogoBlt = AllocatePool (BufferSize);
    353     if (LogoBlt == NULL) {
    354       return EFI_OUT_OF_RESOURCES;
    355     }
    356 
    357     if (GraphicsOutput != NULL) {
    358       Status = GraphicsOutput->Blt (
    359                           GraphicsOutput,
    360                           LogoBlt,
    361                           EfiBltVideoToBltBuffer,
    362                           LogoDestX,
    363                           LogoDestY,
    364                           0,
    365                           0,
    366                           LogoWidth,
    367                           LogoHeight,
    368                           LogoWidth * sizeof (EFI_GRAPHICS_OUTPUT_BLT_PIXEL)
    369                           );
    370     } else {
    371       Status = UgaDraw->Blt (
    372                           UgaDraw,
    373                           (EFI_UGA_PIXEL *) LogoBlt,
    374                           EfiUgaVideoToBltBuffer,
    375                           LogoDestX,
    376                           LogoDestY,
    377                           0,
    378                           0,
    379                           LogoWidth,
    380                           LogoHeight,
    381                           LogoWidth * sizeof (EFI_UGA_PIXEL)
    382                           );
    383     }
    384   }
    385 
    386   if (!EFI_ERROR (Status)) {
    387     BootLogo->SetBootLogo (BootLogo, LogoBlt, LogoDestX, LogoDestY, LogoWidth, LogoHeight);
    388   }
    389   FreePool (LogoBlt);
    390 
    391   return Status;
    392 }
    393 
    394 /**
    395   Use SystemTable Conout to turn on video based Simple Text Out consoles. The
    396   Simple Text Out screens will now be synced up with all non video output devices
    397 
    398   @retval EFI_SUCCESS     UGA devices are back in text mode and synced up.
    399 
    400 **/
    401 EFI_STATUS
    402 EFIAPI
    403 BootLogoDisableLogo (
    404   VOID
    405   )
    406 {
    407 
    408   //
    409   // Enable Cursor on Screen
    410   //
    411   gST->ConOut->EnableCursor (gST->ConOut, TRUE);
    412   return EFI_SUCCESS;
    413 }
    414 
    415 
    416 /**
    417 
    418   Update progress bar with title above it. It only works in Graphics mode.
    419 
    420   @param TitleForeground Foreground color for Title.
    421   @param TitleBackground Background color for Title.
    422   @param Title           Title above progress bar.
    423   @param ProgressColor   Progress bar color.
    424   @param Progress        Progress (0-100)
    425   @param PreviousValue   The previous value of the progress.
    426 
    427   @retval  EFI_STATUS       Success update the progress bar
    428 
    429 **/
    430 EFI_STATUS
    431 EFIAPI
    432 BootLogoUpdateProgress (
    433   IN EFI_GRAPHICS_OUTPUT_BLT_PIXEL TitleForeground,
    434   IN EFI_GRAPHICS_OUTPUT_BLT_PIXEL TitleBackground,
    435   IN CHAR16                        *Title,
    436   IN EFI_GRAPHICS_OUTPUT_BLT_PIXEL ProgressColor,
    437   IN UINTN                         Progress,
    438   IN UINTN                         PreviousValue
    439   )
    440 {
    441   EFI_STATUS                     Status;
    442   EFI_GRAPHICS_OUTPUT_PROTOCOL   *GraphicsOutput;
    443   EFI_UGA_DRAW_PROTOCOL          *UgaDraw;
    444   UINT32                         SizeOfX;
    445   UINT32                         SizeOfY;
    446   UINT32                         ColorDepth;
    447   UINT32                         RefreshRate;
    448   EFI_GRAPHICS_OUTPUT_BLT_PIXEL  Color;
    449   UINTN                          BlockHeight;
    450   UINTN                          BlockWidth;
    451   UINTN                          BlockNum;
    452   UINTN                          PosX;
    453   UINTN                          PosY;
    454   UINTN                          Index;
    455 
    456   if (Progress > 100) {
    457     return EFI_INVALID_PARAMETER;
    458   }
    459 
    460   UgaDraw = NULL;
    461   Status = gBS->HandleProtocol (gST->ConsoleOutHandle, &gEfiGraphicsOutputProtocolGuid, (VOID **) &GraphicsOutput);
    462   if (EFI_ERROR (Status) && FeaturePcdGet (PcdUgaConsumeSupport)) {
    463     GraphicsOutput = NULL;
    464 
    465     Status = gBS->HandleProtocol (gST->ConsoleOutHandle, &gEfiUgaDrawProtocolGuid, (VOID **) &UgaDraw);
    466     if (EFI_ERROR (Status)) {
    467       UgaDraw = NULL;
    468     }
    469   }
    470   if (EFI_ERROR (Status)) {
    471     return EFI_UNSUPPORTED;
    472   }
    473 
    474   SizeOfX = 0;
    475   SizeOfY = 0;
    476   if (GraphicsOutput != NULL) {
    477     SizeOfX = GraphicsOutput->Mode->Info->HorizontalResolution;
    478     SizeOfY = GraphicsOutput->Mode->Info->VerticalResolution;
    479   } else if (UgaDraw != NULL) {
    480     Status = UgaDraw->GetMode (
    481                         UgaDraw,
    482                         &SizeOfX,
    483                         &SizeOfY,
    484                         &ColorDepth,
    485                         &RefreshRate
    486                         );
    487     if (EFI_ERROR (Status)) {
    488       return EFI_UNSUPPORTED;
    489     }
    490   } else {
    491     return EFI_UNSUPPORTED;
    492   }
    493 
    494   BlockWidth  = SizeOfX / 100;
    495   BlockHeight = SizeOfY / 50;
    496 
    497   BlockNum    = Progress;
    498 
    499   PosX        = 0;
    500   PosY        = SizeOfY * 48 / 50;
    501 
    502   if (BlockNum == 0) {
    503     //
    504     // Clear progress area
    505     //
    506     SetMem (&Color, sizeof (EFI_GRAPHICS_OUTPUT_BLT_PIXEL), 0x0);
    507 
    508     if (GraphicsOutput != NULL) {
    509       Status = GraphicsOutput->Blt (
    510                           GraphicsOutput,
    511                           &Color,
    512                           EfiBltVideoFill,
    513                           0,
    514                           0,
    515                           0,
    516                           PosY - EFI_GLYPH_HEIGHT - 1,
    517                           SizeOfX,
    518                           SizeOfY - (PosY - EFI_GLYPH_HEIGHT - 1),
    519                           SizeOfX * sizeof (EFI_GRAPHICS_OUTPUT_BLT_PIXEL)
    520                           );
    521     } else if (FeaturePcdGet (PcdUgaConsumeSupport)) {
    522       Status = UgaDraw->Blt (
    523                           UgaDraw,
    524                           (EFI_UGA_PIXEL *) &Color,
    525                           EfiUgaVideoFill,
    526                           0,
    527                           0,
    528                           0,
    529                           PosY - EFI_GLYPH_HEIGHT - 1,
    530                           SizeOfX,
    531                           SizeOfY - (PosY - EFI_GLYPH_HEIGHT - 1),
    532                           SizeOfX * sizeof (EFI_UGA_PIXEL)
    533                           );
    534     } else {
    535       return EFI_UNSUPPORTED;
    536     }
    537   }
    538   //
    539   // Show progress by drawing blocks
    540   //
    541   for (Index = PreviousValue; Index < BlockNum; Index++) {
    542     PosX = Index * BlockWidth;
    543     if (GraphicsOutput != NULL) {
    544       Status = GraphicsOutput->Blt (
    545                           GraphicsOutput,
    546                           &ProgressColor,
    547                           EfiBltVideoFill,
    548                           0,
    549                           0,
    550                           PosX,
    551                           PosY,
    552                           BlockWidth - 1,
    553                           BlockHeight,
    554                           (BlockWidth) * sizeof (EFI_GRAPHICS_OUTPUT_BLT_PIXEL)
    555                           );
    556     } else if (FeaturePcdGet (PcdUgaConsumeSupport)) {
    557       Status = UgaDraw->Blt (
    558                           UgaDraw,
    559                           (EFI_UGA_PIXEL *) &ProgressColor,
    560                           EfiUgaVideoFill,
    561                           0,
    562                           0,
    563                           PosX,
    564                           PosY,
    565                           BlockWidth - 1,
    566                           BlockHeight,
    567                           (BlockWidth) * sizeof (EFI_UGA_PIXEL)
    568                           );
    569     } else {
    570       return EFI_UNSUPPORTED;
    571     }
    572   }
    573 
    574   PrintXY (
    575     (SizeOfX - StrLen (Title) * EFI_GLYPH_WIDTH) / 2,
    576     PosY - EFI_GLYPH_HEIGHT - 1,
    577     &TitleForeground,
    578     &TitleBackground,
    579     Title
    580     );
    581 
    582   return EFI_SUCCESS;
    583 }
    584