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