Home | History | Annotate | Download | only in GenericBdsLib
      1 /** @file
      2   BDS Lib functions which contain all the code to connect console device
      3 
      4 Copyright (c) 2004 - 2014, 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 
     15 #include "InternalBdsLib.h"
     16 #include <IndustryStandard/Bmp.h>
     17 
     18 
     19 /**
     20   Check if we need to save the EFI variable with "ConVarName" as name
     21   as NV type
     22   If ConVarName is NULL, then ASSERT().
     23 
     24   @param ConVarName The name of the EFI variable.
     25 
     26   @retval TRUE    Set the EFI variable as NV type.
     27   @retval FALSE   EFI variable as NV type can be set NonNV.
     28 **/
     29 BOOLEAN
     30 IsNvNeed (
     31   IN CHAR16 *ConVarName
     32   )
     33 {
     34   CHAR16 *Ptr;
     35 
     36   ASSERT (ConVarName != NULL);
     37 
     38   Ptr = ConVarName;
     39 
     40   //
     41   // If the variable includes "Dev" at last, we consider
     42   // it does not support NV attribute.
     43   //
     44   while (*Ptr != L'\0') {
     45     Ptr++;
     46   }
     47 
     48   if (((INTN)((UINTN)Ptr - (UINTN)ConVarName) / sizeof (CHAR16)) <= 3) {
     49     return TRUE;
     50   }
     51 
     52   if ((*(Ptr - 3) == 'D') && (*(Ptr - 2) == 'e') && (*(Ptr - 1) == 'v')) {
     53     return FALSE;
     54   } else {
     55     return TRUE;
     56   }
     57 }
     58 
     59 /**
     60   Fill console handle in System Table if there are no valid console handle in.
     61 
     62   Firstly, check the validation of console handle in System Table. If it is invalid,
     63   update it by the first console device handle from EFI console variable.
     64 
     65   @param  VarName            The name of the EFI console variable.
     66   @param  ConsoleGuid        Specified Console protocol GUID.
     67   @param  ConsoleHandle      On IN,  console handle in System Table to be checked.
     68                              On OUT, new console handle in system table.
     69   @param  ProtocolInterface  On IN,  console protocol on console handle in System Table to be checked.
     70                              On OUT, new console protocol on new console handle in system table.
     71 
     72   @retval TRUE               System Table has been updated.
     73   @retval FALSE              System Table hasn't been updated.
     74 
     75 **/
     76 BOOLEAN
     77 UpdateSystemTableConsole (
     78   IN     CHAR16                          *VarName,
     79   IN     EFI_GUID                        *ConsoleGuid,
     80   IN OUT EFI_HANDLE                      *ConsoleHandle,
     81   IN OUT VOID                            **ProtocolInterface
     82   )
     83 {
     84   EFI_STATUS                Status;
     85   UINTN                     DevicePathSize;
     86   EFI_DEVICE_PATH_PROTOCOL  *FullDevicePath;
     87   EFI_DEVICE_PATH_PROTOCOL  *VarConsole;
     88   EFI_DEVICE_PATH_PROTOCOL  *Instance;
     89   VOID                      *Interface;
     90   EFI_HANDLE                NewHandle;
     91   EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL *TextOut;
     92 
     93   ASSERT (VarName != NULL);
     94   ASSERT (ConsoleHandle != NULL);
     95   ASSERT (ConsoleGuid != NULL);
     96   ASSERT (ProtocolInterface != NULL);
     97 
     98   if (*ConsoleHandle != NULL) {
     99     Status = gBS->HandleProtocol (
    100                    *ConsoleHandle,
    101                    ConsoleGuid,
    102                    &Interface
    103                    );
    104     if (Status == EFI_SUCCESS && Interface == *ProtocolInterface) {
    105       //
    106       // If ConsoleHandle is valid and console protocol on this handle also
    107       // also matched, just return.
    108       //
    109       return FALSE;
    110     }
    111   }
    112 
    113   //
    114   // Get all possible consoles device path from EFI variable
    115   //
    116   VarConsole = BdsLibGetVariableAndSize (
    117                 VarName,
    118                 &gEfiGlobalVariableGuid,
    119                 &DevicePathSize
    120                 );
    121   if (VarConsole == NULL) {
    122     //
    123     // If there is no any console device, just return.
    124     //
    125     return FALSE;
    126   }
    127 
    128   FullDevicePath = VarConsole;
    129 
    130   do {
    131     //
    132     // Check every instance of the console variable
    133     //
    134     Instance  = GetNextDevicePathInstance (&VarConsole, &DevicePathSize);
    135     if (Instance == NULL) {
    136       FreePool (FullDevicePath);
    137       ASSERT (FALSE);
    138     }
    139 
    140     //
    141     // Find console device handle by device path instance
    142     //
    143     Status = gBS->LocateDevicePath (
    144                    ConsoleGuid,
    145                    &Instance,
    146                    &NewHandle
    147                    );
    148     if (!EFI_ERROR (Status)) {
    149       //
    150       // Get the console protocol on this console device handle
    151       //
    152       Status = gBS->HandleProtocol (
    153                      NewHandle,
    154                      ConsoleGuid,
    155                      &Interface
    156                      );
    157       if (!EFI_ERROR (Status)) {
    158         //
    159         // Update new console handle in System Table.
    160         //
    161         *ConsoleHandle     = NewHandle;
    162         *ProtocolInterface = Interface;
    163         if (CompareGuid (ConsoleGuid, &gEfiSimpleTextOutProtocolGuid)) {
    164           //
    165           // If it is console out device, set console mode 80x25 if current mode is invalid.
    166           //
    167           TextOut = (EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL *) Interface;
    168           if (TextOut->Mode->Mode == -1) {
    169             TextOut->SetMode (TextOut, 0);
    170           }
    171         }
    172         return TRUE;
    173       }
    174     }
    175 
    176   } while (Instance != NULL);
    177 
    178   //
    179   // No any available console devcie found.
    180   //
    181   return FALSE;
    182 }
    183 
    184 /**
    185   This function update console variable based on ConVarName, it can
    186   add or remove one specific console device path from the variable
    187 
    188   @param  ConVarName               Console related variable name, ConIn, ConOut,
    189                                    ErrOut.
    190   @param  CustomizedConDevicePath  The console device path which will be added to
    191                                    the console variable ConVarName, this parameter
    192                                    can not be multi-instance.
    193   @param  ExclusiveDevicePath      The console device path which will be removed
    194                                    from the console variable ConVarName, this
    195                                    parameter can not be multi-instance.
    196 
    197   @retval EFI_UNSUPPORTED          The added device path is same to the removed one.
    198   @retval EFI_SUCCESS              Success add or remove the device path from  the
    199                                    console variable.
    200 
    201 **/
    202 EFI_STATUS
    203 EFIAPI
    204 BdsLibUpdateConsoleVariable (
    205   IN  CHAR16                    *ConVarName,
    206   IN  EFI_DEVICE_PATH_PROTOCOL  *CustomizedConDevicePath,
    207   IN  EFI_DEVICE_PATH_PROTOCOL  *ExclusiveDevicePath
    208   )
    209 {
    210   EFI_STATUS                Status;
    211   EFI_DEVICE_PATH_PROTOCOL  *VarConsole;
    212   UINTN                     DevicePathSize;
    213   EFI_DEVICE_PATH_PROTOCOL  *NewDevicePath;
    214   EFI_DEVICE_PATH_PROTOCOL  *TempNewDevicePath;
    215   UINT32                    Attributes;
    216 
    217   VarConsole      = NULL;
    218   DevicePathSize  = 0;
    219 
    220   //
    221   // Notes: check the device path point, here should check
    222   // with compare memory
    223   //
    224   if (CustomizedConDevicePath == ExclusiveDevicePath) {
    225     return EFI_UNSUPPORTED;
    226   }
    227   //
    228   // Delete the ExclusiveDevicePath from current default console
    229   //
    230   VarConsole = BdsLibGetVariableAndSize (
    231                 ConVarName,
    232                 &gEfiGlobalVariableGuid,
    233                 &DevicePathSize
    234                 );
    235 
    236   //
    237   // Initialize NewDevicePath
    238   //
    239   NewDevicePath  = VarConsole;
    240 
    241   //
    242   // If ExclusiveDevicePath is even the part of the instance in VarConsole, delete it.
    243   // In the end, NewDevicePath is the final device path.
    244   //
    245   if (ExclusiveDevicePath != NULL && VarConsole != NULL) {
    246       NewDevicePath = BdsLibDelPartMatchInstance (VarConsole, ExclusiveDevicePath);
    247   }
    248   //
    249   // Try to append customized device path to NewDevicePath.
    250   //
    251   if (CustomizedConDevicePath != NULL) {
    252     if (!BdsLibMatchDevicePaths (NewDevicePath, CustomizedConDevicePath)) {
    253       //
    254       // Check if there is part of CustomizedConDevicePath in NewDevicePath, delete it.
    255       //
    256       NewDevicePath = BdsLibDelPartMatchInstance (NewDevicePath, CustomizedConDevicePath);
    257       //
    258       // In the first check, the default console variable will be _ModuleEntryPoint,
    259       // just append current customized device path
    260       //
    261       TempNewDevicePath = NewDevicePath;
    262       NewDevicePath = AppendDevicePathInstance (NewDevicePath, CustomizedConDevicePath);
    263       if (TempNewDevicePath != NULL) {
    264         FreePool(TempNewDevicePath);
    265       }
    266     }
    267   }
    268 
    269   //
    270   // The attribute for ConInDev, ConOutDev and ErrOutDev does not include NV.
    271   //
    272   if (IsNvNeed(ConVarName)) {
    273     //
    274     // ConVarName has NV attribute.
    275     //
    276     Attributes = EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_NON_VOLATILE;
    277   } else {
    278     //
    279     // ConVarName does not have NV attribute.
    280     //
    281     Attributes = EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS;
    282   }
    283 
    284   //
    285   // Finally, Update the variable of the default console by NewDevicePath
    286   //
    287   DevicePathSize = GetDevicePathSize (NewDevicePath);
    288   Status = SetVariableAndReportStatusCodeOnError (
    289              ConVarName,
    290              &gEfiGlobalVariableGuid,
    291              Attributes,
    292              DevicePathSize,
    293              NewDevicePath
    294              );
    295   if ((DevicePathSize == 0) && (Status == EFI_NOT_FOUND)) {
    296     Status = EFI_SUCCESS;
    297   }
    298 
    299   if (VarConsole == NewDevicePath) {
    300     if (VarConsole != NULL) {
    301       FreePool(VarConsole);
    302     }
    303   } else {
    304     if (VarConsole != NULL) {
    305       FreePool(VarConsole);
    306     }
    307     if (NewDevicePath != NULL) {
    308       FreePool(NewDevicePath);
    309     }
    310   }
    311 
    312   return Status;
    313 
    314 }
    315 
    316 
    317 /**
    318   Connect the console device base on the variable ConVarName, if
    319   device path of the ConVarName is multi-instance device path and
    320   anyone of the instances is connected success, then this function
    321   will return success.
    322   If the handle associate with one device path node can not
    323   be created successfully, then still give chance to do the dispatch,
    324   which load the missing drivers if possible..
    325 
    326   @param  ConVarName               Console related variable name, ConIn, ConOut,
    327                                    ErrOut.
    328 
    329   @retval EFI_NOT_FOUND            There is not any console devices connected
    330                                    success
    331   @retval EFI_SUCCESS              Success connect any one instance of the console
    332                                    device path base on the variable ConVarName.
    333 
    334 **/
    335 EFI_STATUS
    336 EFIAPI
    337 BdsLibConnectConsoleVariable (
    338   IN  CHAR16                 *ConVarName
    339   )
    340 {
    341   EFI_STATUS                Status;
    342   EFI_DEVICE_PATH_PROTOCOL  *StartDevicePath;
    343   UINTN                     VariableSize;
    344   EFI_DEVICE_PATH_PROTOCOL  *Instance;
    345   EFI_DEVICE_PATH_PROTOCOL  *Next;
    346   EFI_DEVICE_PATH_PROTOCOL  *CopyOfDevicePath;
    347   UINTN                     Size;
    348   BOOLEAN                   DeviceExist;
    349 
    350   Status      = EFI_SUCCESS;
    351   DeviceExist = FALSE;
    352 
    353   //
    354   // Check if the console variable exist
    355   //
    356   StartDevicePath = BdsLibGetVariableAndSize (
    357                       ConVarName,
    358                       &gEfiGlobalVariableGuid,
    359                       &VariableSize
    360                       );
    361   if (StartDevicePath == NULL) {
    362     return EFI_UNSUPPORTED;
    363   }
    364 
    365   CopyOfDevicePath = StartDevicePath;
    366   do {
    367     //
    368     // Check every instance of the console variable
    369     //
    370     Instance  = GetNextDevicePathInstance (&CopyOfDevicePath, &Size);
    371     if (Instance == NULL) {
    372       FreePool (StartDevicePath);
    373       return EFI_UNSUPPORTED;
    374     }
    375 
    376     Next      = Instance;
    377     while (!IsDevicePathEndType (Next)) {
    378       Next = NextDevicePathNode (Next);
    379     }
    380 
    381     SetDevicePathEndNode (Next);
    382     //
    383     // Connect the USB console
    384     // USB console device path is a short-form device path that
    385     //  starts with the first element being a USB WWID
    386     //  or a USB Class device path
    387     //
    388     if ((DevicePathType (Instance) == MESSAGING_DEVICE_PATH) &&
    389        ((DevicePathSubType (Instance) == MSG_USB_CLASS_DP)
    390        || (DevicePathSubType (Instance) == MSG_USB_WWID_DP)
    391        )) {
    392       Status = BdsLibConnectUsbDevByShortFormDP (0xFF, Instance);
    393       if (!EFI_ERROR (Status)) {
    394         DeviceExist = TRUE;
    395       }
    396     } else {
    397       //
    398       // Connect the instance device path
    399       //
    400       Status = BdsLibConnectDevicePath (Instance);
    401 
    402       if (EFI_ERROR (Status)) {
    403         //
    404         // Delete the instance from the console varialbe
    405         //
    406         BdsLibUpdateConsoleVariable (ConVarName, NULL, Instance);
    407       } else {
    408         DeviceExist = TRUE;
    409       }
    410     }
    411     FreePool(Instance);
    412   } while (CopyOfDevicePath != NULL);
    413 
    414   FreePool (StartDevicePath);
    415 
    416   if (!DeviceExist) {
    417     return EFI_NOT_FOUND;
    418   }
    419 
    420   return EFI_SUCCESS;
    421 }
    422 
    423 /**
    424   This function will search every simpletext device in current system,
    425   and make every simpletext device as pertantial console device.
    426 
    427 **/
    428 VOID
    429 EFIAPI
    430 BdsLibConnectAllConsoles (
    431   VOID
    432   )
    433 {
    434   UINTN                     Index;
    435   EFI_DEVICE_PATH_PROTOCOL  *ConDevicePath;
    436   UINTN                     HandleCount;
    437   EFI_HANDLE                *HandleBuffer;
    438 
    439   Index         = 0;
    440   HandleCount   = 0;
    441   HandleBuffer  = NULL;
    442   ConDevicePath = NULL;
    443 
    444   //
    445   // Update all the console variables
    446   //
    447   gBS->LocateHandleBuffer (
    448           ByProtocol,
    449           &gEfiSimpleTextInProtocolGuid,
    450           NULL,
    451           &HandleCount,
    452           &HandleBuffer
    453           );
    454 
    455   for (Index = 0; Index < HandleCount; Index++) {
    456     gBS->HandleProtocol (
    457             HandleBuffer[Index],
    458             &gEfiDevicePathProtocolGuid,
    459             (VOID **) &ConDevicePath
    460             );
    461     BdsLibUpdateConsoleVariable (L"ConIn", ConDevicePath, NULL);
    462   }
    463 
    464   if (HandleBuffer != NULL) {
    465     FreePool(HandleBuffer);
    466     HandleBuffer = NULL;
    467   }
    468 
    469   gBS->LocateHandleBuffer (
    470           ByProtocol,
    471           &gEfiSimpleTextOutProtocolGuid,
    472           NULL,
    473           &HandleCount,
    474           &HandleBuffer
    475           );
    476   for (Index = 0; Index < HandleCount; Index++) {
    477     gBS->HandleProtocol (
    478             HandleBuffer[Index],
    479             &gEfiDevicePathProtocolGuid,
    480             (VOID **) &ConDevicePath
    481             );
    482     BdsLibUpdateConsoleVariable (L"ConOut", ConDevicePath, NULL);
    483     BdsLibUpdateConsoleVariable (L"ErrOut", ConDevicePath, NULL);
    484   }
    485 
    486   if (HandleBuffer != NULL) {
    487     FreePool(HandleBuffer);
    488   }
    489 
    490   //
    491   // Connect all console variables
    492   //
    493   BdsLibConnectAllDefaultConsoles ();
    494 
    495 }
    496 
    497 /**
    498   This function will connect console device base on the console
    499   device variable ConIn, ConOut and ErrOut.
    500 
    501   @retval EFI_SUCCESS              At least one of the ConIn and ConOut device have
    502                                    been connected success.
    503   @retval EFI_STATUS               Return the status of BdsLibConnectConsoleVariable ().
    504 
    505 **/
    506 EFI_STATUS
    507 EFIAPI
    508 BdsLibConnectAllDefaultConsoles (
    509   VOID
    510   )
    511 {
    512   EFI_STATUS                Status;
    513   BOOLEAN                   SystemTableUpdated;
    514 
    515   //
    516   // Connect all default console variables
    517   //
    518 
    519   //
    520   // It seems impossible not to have any ConOut device on platform,
    521   // so we check the status here.
    522   //
    523   Status = BdsLibConnectConsoleVariable (L"ConOut");
    524   if (EFI_ERROR (Status)) {
    525     return Status;
    526   }
    527 
    528   //
    529   // Insert the performance probe for Console Out
    530   //
    531   PERF_START (NULL, "ConOut", "BDS", 1);
    532   PERF_END (NULL, "ConOut", "BDS", 0);
    533 
    534   //
    535   // Because possibly the platform is legacy free, in such case,
    536   // ConIn devices (Serial Port and PS2 Keyboard ) does not exist,
    537   // so we need not check the status.
    538   //
    539   BdsLibConnectConsoleVariable (L"ConIn");
    540 
    541   //
    542   // The _ModuleEntryPoint err out var is legal.
    543   //
    544   BdsLibConnectConsoleVariable (L"ErrOut");
    545 
    546   SystemTableUpdated = FALSE;
    547   //
    548   // Fill console handles in System Table if no console device assignd.
    549   //
    550   if (UpdateSystemTableConsole (L"ConIn", &gEfiSimpleTextInProtocolGuid, &gST->ConsoleInHandle, (VOID **) &gST->ConIn)) {
    551     SystemTableUpdated = TRUE;
    552   }
    553   if (UpdateSystemTableConsole (L"ConOut", &gEfiSimpleTextOutProtocolGuid, &gST->ConsoleOutHandle, (VOID **) &gST->ConOut)) {
    554     SystemTableUpdated = TRUE;
    555   }
    556   if (UpdateSystemTableConsole (L"ErrOut", &gEfiSimpleTextOutProtocolGuid, &gST->StandardErrorHandle, (VOID **) &gST->StdErr)) {
    557     SystemTableUpdated = TRUE;
    558   }
    559 
    560   if (SystemTableUpdated) {
    561     //
    562     // Update the CRC32 in the EFI System Table header
    563     //
    564     gST->Hdr.CRC32 = 0;
    565     gBS->CalculateCrc32 (
    566           (UINT8 *) &gST->Hdr,
    567           gST->Hdr.HeaderSize,
    568           &gST->Hdr.CRC32
    569           );
    570   }
    571 
    572   return EFI_SUCCESS;
    573 
    574 }
    575 
    576 /**
    577   This function will connect console device except ConIn base on the console
    578   device variable  ConOut and ErrOut.
    579 
    580   @retval EFI_SUCCESS              At least one of the ConOut device have
    581                                    been connected success.
    582   @retval EFI_STATUS               Return the status of BdsLibConnectConsoleVariable ().
    583 
    584 **/
    585 EFI_STATUS
    586 EFIAPI
    587 BdsLibConnectAllDefaultConsolesWithOutConIn (
    588   VOID
    589   )
    590 {
    591   EFI_STATUS                Status;
    592   BOOLEAN                   SystemTableUpdated;
    593 
    594   //
    595   // Connect all default console variables except ConIn
    596   //
    597 
    598   //
    599   // It seems impossible not to have any ConOut device on platform,
    600   // so we check the status here.
    601   //
    602   Status = BdsLibConnectConsoleVariable (L"ConOut");
    603   if (EFI_ERROR (Status)) {
    604     return Status;
    605   }
    606 
    607   //
    608   // Insert the performance probe for Console Out
    609   //
    610   PERF_START (NULL, "ConOut", "BDS", 1);
    611   PERF_END (NULL, "ConOut", "BDS", 0);
    612 
    613   //
    614   // The _ModuleEntryPoint err out var is legal.
    615   //
    616   BdsLibConnectConsoleVariable (L"ErrOut");
    617 
    618   SystemTableUpdated = FALSE;
    619   //
    620   // Fill console handles in System Table if no console device assignd.
    621   //
    622   if (UpdateSystemTableConsole (L"ConOut", &gEfiSimpleTextOutProtocolGuid, &gST->ConsoleOutHandle, (VOID **) &gST->ConOut)) {
    623     SystemTableUpdated = TRUE;
    624   }
    625   if (UpdateSystemTableConsole (L"ErrOut", &gEfiSimpleTextOutProtocolGuid, &gST->StandardErrorHandle, (VOID **) &gST->StdErr)) {
    626     SystemTableUpdated = TRUE;
    627   }
    628 
    629   if (SystemTableUpdated) {
    630     //
    631     // Update the CRC32 in the EFI System Table header
    632     //
    633     gST->Hdr.CRC32 = 0;
    634     gBS->CalculateCrc32 (
    635           (UINT8 *) &gST->Hdr,
    636           gST->Hdr.HeaderSize,
    637           &gST->Hdr.CRC32
    638           );
    639   }
    640 
    641   return EFI_SUCCESS;
    642 
    643 }
    644 
    645 /**
    646   Convert a *.BMP graphics image to a GOP blt buffer. If a NULL Blt buffer
    647   is passed in a GopBlt buffer will be allocated by this routine. If a GopBlt
    648   buffer is passed in it will be used if it is big enough.
    649 
    650   @param  BmpImage      Pointer to BMP file
    651   @param  BmpImageSize  Number of bytes in BmpImage
    652   @param  GopBlt        Buffer containing GOP version of BmpImage.
    653   @param  GopBltSize    Size of GopBlt in bytes.
    654   @param  PixelHeight   Height of GopBlt/BmpImage in pixels
    655   @param  PixelWidth    Width of GopBlt/BmpImage in pixels
    656 
    657   @retval EFI_SUCCESS           GopBlt and GopBltSize are returned.
    658   @retval EFI_UNSUPPORTED       BmpImage is not a valid *.BMP image
    659   @retval EFI_BUFFER_TOO_SMALL  The passed in GopBlt buffer is not big enough.
    660                                 GopBltSize will contain the required size.
    661   @retval EFI_OUT_OF_RESOURCES  No enough buffer to allocate.
    662 
    663 **/
    664 EFI_STATUS
    665 ConvertBmpToGopBlt (
    666   IN     VOID      *BmpImage,
    667   IN     UINTN     BmpImageSize,
    668   IN OUT VOID      **GopBlt,
    669   IN OUT UINTN     *GopBltSize,
    670      OUT UINTN     *PixelHeight,
    671      OUT UINTN     *PixelWidth
    672   )
    673 {
    674   UINT8                         *Image;
    675   UINT8                         *ImageHeader;
    676   BMP_IMAGE_HEADER              *BmpHeader;
    677   BMP_COLOR_MAP                 *BmpColorMap;
    678   EFI_GRAPHICS_OUTPUT_BLT_PIXEL *BltBuffer;
    679   EFI_GRAPHICS_OUTPUT_BLT_PIXEL *Blt;
    680   UINT64                        BltBufferSize;
    681   UINTN                         Index;
    682   UINTN                         Height;
    683   UINTN                         Width;
    684   UINTN                         ImageIndex;
    685   UINT32                        DataSizePerLine;
    686   BOOLEAN                       IsAllocated;
    687   UINT32                        ColorMapNum;
    688 
    689   if (sizeof (BMP_IMAGE_HEADER) > BmpImageSize) {
    690     return EFI_INVALID_PARAMETER;
    691   }
    692 
    693   BmpHeader = (BMP_IMAGE_HEADER *) BmpImage;
    694 
    695   if (BmpHeader->CharB != 'B' || BmpHeader->CharM != 'M') {
    696     return EFI_UNSUPPORTED;
    697   }
    698 
    699   //
    700   // Doesn't support compress.
    701   //
    702   if (BmpHeader->CompressionType != 0) {
    703     return EFI_UNSUPPORTED;
    704   }
    705 
    706   //
    707   // Only support BITMAPINFOHEADER format.
    708   // BITMAPFILEHEADER + BITMAPINFOHEADER = BMP_IMAGE_HEADER
    709   //
    710   if (BmpHeader->HeaderSize != sizeof (BMP_IMAGE_HEADER) - OFFSET_OF(BMP_IMAGE_HEADER, HeaderSize)) {
    711     return EFI_UNSUPPORTED;
    712   }
    713 
    714   //
    715   // The data size in each line must be 4 byte alignment.
    716   //
    717   DataSizePerLine = ((BmpHeader->PixelWidth * BmpHeader->BitPerPixel + 31) >> 3) & (~0x3);
    718   BltBufferSize = MultU64x32 (DataSizePerLine, BmpHeader->PixelHeight);
    719   if (BltBufferSize > (UINT32) ~0) {
    720     return EFI_INVALID_PARAMETER;
    721   }
    722 
    723   if ((BmpHeader->Size != BmpImageSize) ||
    724       (BmpHeader->Size < BmpHeader->ImageOffset) ||
    725       (BmpHeader->Size - BmpHeader->ImageOffset !=  BmpHeader->PixelHeight * DataSizePerLine)) {
    726     return EFI_INVALID_PARAMETER;
    727   }
    728 
    729   //
    730   // Calculate Color Map offset in the image.
    731   //
    732   Image       = BmpImage;
    733   BmpColorMap = (BMP_COLOR_MAP *) (Image + sizeof (BMP_IMAGE_HEADER));
    734   if (BmpHeader->ImageOffset < sizeof (BMP_IMAGE_HEADER)) {
    735     return EFI_INVALID_PARAMETER;
    736   }
    737 
    738   if (BmpHeader->ImageOffset > sizeof (BMP_IMAGE_HEADER)) {
    739     switch (BmpHeader->BitPerPixel) {
    740       case 1:
    741         ColorMapNum = 2;
    742         break;
    743       case 4:
    744         ColorMapNum = 16;
    745         break;
    746       case 8:
    747         ColorMapNum = 256;
    748         break;
    749       default:
    750         ColorMapNum = 0;
    751         break;
    752       }
    753     //
    754     // BMP file may has padding data between the bmp header section and the bmp data section.
    755     //
    756     if (BmpHeader->ImageOffset - sizeof (BMP_IMAGE_HEADER) < sizeof (BMP_COLOR_MAP) * ColorMapNum) {
    757       return EFI_INVALID_PARAMETER;
    758     }
    759   }
    760 
    761   //
    762   // Calculate graphics image data address in the image
    763   //
    764   Image         = ((UINT8 *) BmpImage) + BmpHeader->ImageOffset;
    765   ImageHeader   = Image;
    766 
    767   //
    768   // Calculate the BltBuffer needed size.
    769   //
    770   BltBufferSize = MultU64x32 ((UINT64) BmpHeader->PixelWidth, BmpHeader->PixelHeight);
    771   //
    772   // Ensure the BltBufferSize * sizeof (EFI_GRAPHICS_OUTPUT_BLT_PIXEL) doesn't overflow
    773   //
    774   if (BltBufferSize > DivU64x32 ((UINTN) ~0, sizeof (EFI_GRAPHICS_OUTPUT_BLT_PIXEL))) {
    775     return EFI_UNSUPPORTED;
    776   }
    777   BltBufferSize = MultU64x32 (BltBufferSize, sizeof (EFI_GRAPHICS_OUTPUT_BLT_PIXEL));
    778 
    779   IsAllocated   = FALSE;
    780   if (*GopBlt == NULL) {
    781     //
    782     // GopBlt is not allocated by caller.
    783     //
    784     *GopBltSize = (UINTN) BltBufferSize;
    785     *GopBlt     = AllocatePool (*GopBltSize);
    786     IsAllocated = TRUE;
    787     if (*GopBlt == NULL) {
    788       return EFI_OUT_OF_RESOURCES;
    789     }
    790   } else {
    791     //
    792     // GopBlt has been allocated by caller.
    793     //
    794     if (*GopBltSize < (UINTN) BltBufferSize) {
    795       *GopBltSize = (UINTN) BltBufferSize;
    796       return EFI_BUFFER_TOO_SMALL;
    797     }
    798   }
    799 
    800   *PixelWidth   = BmpHeader->PixelWidth;
    801   *PixelHeight  = BmpHeader->PixelHeight;
    802 
    803   //
    804   // Convert image from BMP to Blt buffer format
    805   //
    806   BltBuffer = *GopBlt;
    807   for (Height = 0; Height < BmpHeader->PixelHeight; Height++) {
    808     Blt = &BltBuffer[(BmpHeader->PixelHeight - Height - 1) * BmpHeader->PixelWidth];
    809     for (Width = 0; Width < BmpHeader->PixelWidth; Width++, Image++, Blt++) {
    810       switch (BmpHeader->BitPerPixel) {
    811       case 1:
    812         //
    813         // Convert 1-bit (2 colors) BMP to 24-bit color
    814         //
    815         for (Index = 0; Index < 8 && Width < BmpHeader->PixelWidth; Index++) {
    816           Blt->Red    = BmpColorMap[((*Image) >> (7 - Index)) & 0x1].Red;
    817           Blt->Green  = BmpColorMap[((*Image) >> (7 - Index)) & 0x1].Green;
    818           Blt->Blue   = BmpColorMap[((*Image) >> (7 - Index)) & 0x1].Blue;
    819           Blt++;
    820           Width++;
    821         }
    822 
    823         Blt--;
    824         Width--;
    825         break;
    826 
    827       case 4:
    828         //
    829         // Convert 4-bit (16 colors) BMP Palette to 24-bit color
    830         //
    831         Index       = (*Image) >> 4;
    832         Blt->Red    = BmpColorMap[Index].Red;
    833         Blt->Green  = BmpColorMap[Index].Green;
    834         Blt->Blue   = BmpColorMap[Index].Blue;
    835         if (Width < (BmpHeader->PixelWidth - 1)) {
    836           Blt++;
    837           Width++;
    838           Index       = (*Image) & 0x0f;
    839           Blt->Red    = BmpColorMap[Index].Red;
    840           Blt->Green  = BmpColorMap[Index].Green;
    841           Blt->Blue   = BmpColorMap[Index].Blue;
    842         }
    843         break;
    844 
    845       case 8:
    846         //
    847         // Convert 8-bit (256 colors) BMP Palette to 24-bit color
    848         //
    849         Blt->Red    = BmpColorMap[*Image].Red;
    850         Blt->Green  = BmpColorMap[*Image].Green;
    851         Blt->Blue   = BmpColorMap[*Image].Blue;
    852         break;
    853 
    854       case 24:
    855         //
    856         // It is 24-bit BMP.
    857         //
    858         Blt->Blue   = *Image++;
    859         Blt->Green  = *Image++;
    860         Blt->Red    = *Image;
    861         break;
    862 
    863       default:
    864         //
    865         // Other bit format BMP is not supported.
    866         //
    867         if (IsAllocated) {
    868           FreePool (*GopBlt);
    869           *GopBlt = NULL;
    870         }
    871         return EFI_UNSUPPORTED;
    872         break;
    873       };
    874 
    875     }
    876 
    877     ImageIndex = (UINTN) (Image - ImageHeader);
    878     if ((ImageIndex % 4) != 0) {
    879       //
    880       // Bmp Image starts each row on a 32-bit boundary!
    881       //
    882       Image = Image + (4 - (ImageIndex % 4));
    883     }
    884   }
    885 
    886   return EFI_SUCCESS;
    887 }
    888 
    889 /**
    890   Use SystemTable Conout to stop video based Simple Text Out consoles from going
    891   to the video device. Put up LogoFile on every video device that is a console.
    892 
    893   @param[in]  LogoFile   File name of logo to display on the center of the screen.
    894 
    895   @retval EFI_SUCCESS     ConsoleControl has been flipped to graphics and logo displayed.
    896   @retval EFI_UNSUPPORTED Logo not found
    897 
    898 **/
    899 EFI_STATUS
    900 EFIAPI
    901 EnableQuietBoot (
    902   IN  EFI_GUID  *LogoFile
    903   )
    904 {
    905   EFI_STATUS                    Status;
    906   EFI_OEM_BADGING_PROTOCOL      *Badging;
    907   UINT32                        SizeOfX;
    908   UINT32                        SizeOfY;
    909   INTN                          DestX;
    910   INTN                          DestY;
    911   UINT8                         *ImageData;
    912   UINTN                         ImageSize;
    913   UINTN                         BltSize;
    914   UINT32                        Instance;
    915   EFI_BADGING_FORMAT            Format;
    916   EFI_BADGING_DISPLAY_ATTRIBUTE Attribute;
    917   UINTN                         CoordinateX;
    918   UINTN                         CoordinateY;
    919   UINTN                         Height;
    920   UINTN                         Width;
    921   EFI_GRAPHICS_OUTPUT_BLT_PIXEL *Blt;
    922   EFI_UGA_DRAW_PROTOCOL         *UgaDraw;
    923   UINT32                        ColorDepth;
    924   UINT32                        RefreshRate;
    925   EFI_GRAPHICS_OUTPUT_PROTOCOL  *GraphicsOutput;
    926   EFI_BOOT_LOGO_PROTOCOL        *BootLogo;
    927   UINTN                         NumberOfLogos;
    928   EFI_GRAPHICS_OUTPUT_BLT_PIXEL *LogoBlt;
    929   UINTN                         LogoDestX;
    930   UINTN                         LogoDestY;
    931   UINTN                         LogoHeight;
    932   UINTN                         LogoWidth;
    933   UINTN                         NewDestX;
    934   UINTN                         NewDestY;
    935   UINTN                         NewHeight;
    936   UINTN                         NewWidth;
    937   UINT64                        BufferSize;
    938 
    939   UgaDraw = NULL;
    940   //
    941   // Try to open GOP first
    942   //
    943   Status = gBS->HandleProtocol (gST->ConsoleOutHandle, &gEfiGraphicsOutputProtocolGuid, (VOID **) &GraphicsOutput);
    944   if (EFI_ERROR (Status) && FeaturePcdGet (PcdUgaConsumeSupport)) {
    945     GraphicsOutput = NULL;
    946     //
    947     // Open GOP failed, try to open UGA
    948     //
    949     Status = gBS->HandleProtocol (gST->ConsoleOutHandle, &gEfiUgaDrawProtocolGuid, (VOID **) &UgaDraw);
    950   }
    951   if (EFI_ERROR (Status)) {
    952     return EFI_UNSUPPORTED;
    953   }
    954 
    955   //
    956   // Try to open Boot Logo Protocol.
    957   //
    958   BootLogo = NULL;
    959   gBS->LocateProtocol (&gEfiBootLogoProtocolGuid, NULL, (VOID **) &BootLogo);
    960 
    961   //
    962   // Erase Cursor from screen
    963   //
    964   gST->ConOut->EnableCursor (gST->ConOut, FALSE);
    965 
    966   Badging = NULL;
    967   Status  = gBS->LocateProtocol (&gEfiOEMBadgingProtocolGuid, NULL, (VOID **) &Badging);
    968 
    969   if (GraphicsOutput != NULL) {
    970     SizeOfX = GraphicsOutput->Mode->Info->HorizontalResolution;
    971     SizeOfY = GraphicsOutput->Mode->Info->VerticalResolution;
    972 
    973   } else if (UgaDraw != NULL && FeaturePcdGet (PcdUgaConsumeSupport)) {
    974     Status = UgaDraw->GetMode (UgaDraw, &SizeOfX, &SizeOfY, &ColorDepth, &RefreshRate);
    975     if (EFI_ERROR (Status)) {
    976       return EFI_UNSUPPORTED;
    977     }
    978   } else {
    979     return EFI_UNSUPPORTED;
    980   }
    981 
    982   Blt = NULL;
    983   NumberOfLogos = 0;
    984   LogoDestX = 0;
    985   LogoDestY = 0;
    986   LogoHeight = 0;
    987   LogoWidth = 0;
    988   NewDestX = 0;
    989   NewDestY = 0;
    990   NewHeight = 0;
    991   NewWidth = 0;
    992   Instance = 0;
    993   while (1) {
    994     ImageData = NULL;
    995     ImageSize = 0;
    996 
    997     if (Badging != NULL) {
    998       //
    999       // Get image from OEMBadging protocol.
   1000       //
   1001       Status = Badging->GetImage (
   1002                           Badging,
   1003                           &Instance,
   1004                           &Format,
   1005                           &ImageData,
   1006                           &ImageSize,
   1007                           &Attribute,
   1008                           &CoordinateX,
   1009                           &CoordinateY
   1010                           );
   1011       if (EFI_ERROR (Status)) {
   1012         goto Done;
   1013       }
   1014 
   1015       //
   1016       // Currently only support BMP format.
   1017       //
   1018       if (Format != EfiBadgingFormatBMP) {
   1019         if (ImageData != NULL) {
   1020           FreePool (ImageData);
   1021         }
   1022         continue;
   1023       }
   1024     } else {
   1025       //
   1026       // Get the specified image from FV.
   1027       //
   1028       Status = GetSectionFromAnyFv (LogoFile, EFI_SECTION_RAW, 0, (VOID **) &ImageData, &ImageSize);
   1029       if (EFI_ERROR (Status)) {
   1030         return EFI_UNSUPPORTED;
   1031       }
   1032 
   1033       CoordinateX = 0;
   1034       CoordinateY = 0;
   1035       if (!FeaturePcdGet(PcdBootlogoOnlyEnable)) {
   1036         Attribute   = EfiBadgingDisplayAttributeCenter;
   1037       } else {
   1038         Attribute   = EfiBadgingDisplayAttributeCustomized;
   1039       }
   1040     }
   1041 
   1042     if (Blt != NULL) {
   1043       FreePool (Blt);
   1044     }
   1045     Blt = NULL;
   1046     Status = ConvertBmpToGopBlt (
   1047               ImageData,
   1048               ImageSize,
   1049               (VOID **) &Blt,
   1050               &BltSize,
   1051               &Height,
   1052               &Width
   1053               );
   1054     if (EFI_ERROR (Status)) {
   1055       FreePool (ImageData);
   1056 
   1057       if (Badging == NULL) {
   1058         return Status;
   1059       } else {
   1060         continue;
   1061       }
   1062     }
   1063 
   1064     //
   1065     // Calculate the display position according to Attribute.
   1066     //
   1067     switch (Attribute) {
   1068     case EfiBadgingDisplayAttributeLeftTop:
   1069       DestX = CoordinateX;
   1070       DestY = CoordinateY;
   1071       break;
   1072 
   1073     case EfiBadgingDisplayAttributeCenterTop:
   1074       DestX = (SizeOfX - Width) / 2;
   1075       DestY = CoordinateY;
   1076       break;
   1077 
   1078     case EfiBadgingDisplayAttributeRightTop:
   1079       DestX = (SizeOfX - Width - CoordinateX);
   1080       DestY = CoordinateY;;
   1081       break;
   1082 
   1083     case EfiBadgingDisplayAttributeCenterRight:
   1084       DestX = (SizeOfX - Width - CoordinateX);
   1085       DestY = (SizeOfY - Height) / 2;
   1086       break;
   1087 
   1088     case EfiBadgingDisplayAttributeRightBottom:
   1089       DestX = (SizeOfX - Width - CoordinateX);
   1090       DestY = (SizeOfY - Height - CoordinateY);
   1091       break;
   1092 
   1093     case EfiBadgingDisplayAttributeCenterBottom:
   1094       DestX = (SizeOfX - Width) / 2;
   1095       DestY = (SizeOfY - Height - CoordinateY);
   1096       break;
   1097 
   1098     case EfiBadgingDisplayAttributeLeftBottom:
   1099       DestX = CoordinateX;
   1100       DestY = (SizeOfY - Height - CoordinateY);
   1101       break;
   1102 
   1103     case EfiBadgingDisplayAttributeCenterLeft:
   1104       DestX = CoordinateX;
   1105       DestY = (SizeOfY - Height) / 2;
   1106       break;
   1107 
   1108     case EfiBadgingDisplayAttributeCenter:
   1109       DestX = (SizeOfX - Width) / 2;
   1110       DestY = (SizeOfY - Height) / 2;
   1111       break;
   1112 
   1113     case EfiBadgingDisplayAttributeCustomized:
   1114       DestX = (SizeOfX - Width) / 2;
   1115       DestY = ((SizeOfY * 382) / 1000) - Height / 2;
   1116       break;
   1117 
   1118     default:
   1119       DestX = CoordinateX;
   1120       DestY = CoordinateY;
   1121       break;
   1122     }
   1123 
   1124     if ((DestX >= 0) && (DestY >= 0)) {
   1125       if (GraphicsOutput != NULL) {
   1126         Status = GraphicsOutput->Blt (
   1127                             GraphicsOutput,
   1128                             Blt,
   1129                             EfiBltBufferToVideo,
   1130                             0,
   1131                             0,
   1132                             (UINTN) DestX,
   1133                             (UINTN) DestY,
   1134                             Width,
   1135                             Height,
   1136                             Width * sizeof (EFI_GRAPHICS_OUTPUT_BLT_PIXEL)
   1137                             );
   1138       } else if (UgaDraw != NULL && FeaturePcdGet (PcdUgaConsumeSupport)) {
   1139         Status = UgaDraw->Blt (
   1140                             UgaDraw,
   1141                             (EFI_UGA_PIXEL *) Blt,
   1142                             EfiUgaBltBufferToVideo,
   1143                             0,
   1144                             0,
   1145                             (UINTN) DestX,
   1146                             (UINTN) DestY,
   1147                             Width,
   1148                             Height,
   1149                             Width * sizeof (EFI_UGA_PIXEL)
   1150                             );
   1151       } else {
   1152         Status = EFI_UNSUPPORTED;
   1153       }
   1154 
   1155       //
   1156       // Report displayed Logo information.
   1157       //
   1158       if (!EFI_ERROR (Status)) {
   1159         NumberOfLogos++;
   1160 
   1161         if (LogoWidth == 0) {
   1162           //
   1163           // The first Logo.
   1164           //
   1165           LogoDestX = (UINTN) DestX;
   1166           LogoDestY = (UINTN) DestY;
   1167           LogoWidth = Width;
   1168           LogoHeight = Height;
   1169         } else {
   1170           //
   1171           // Merge new logo with old one.
   1172           //
   1173           NewDestX = MIN ((UINTN) DestX, LogoDestX);
   1174           NewDestY = MIN ((UINTN) DestY, LogoDestY);
   1175           NewWidth = MAX ((UINTN) DestX + Width, LogoDestX + LogoWidth) - NewDestX;
   1176           NewHeight = MAX ((UINTN) DestY + Height, LogoDestY + LogoHeight) - NewDestY;
   1177 
   1178           LogoDestX = NewDestX;
   1179           LogoDestY = NewDestY;
   1180           LogoWidth = NewWidth;
   1181           LogoHeight = NewHeight;
   1182         }
   1183       }
   1184     }
   1185 
   1186     FreePool (ImageData);
   1187 
   1188     if (Badging == NULL) {
   1189       break;
   1190     }
   1191   }
   1192 
   1193 Done:
   1194   if (BootLogo == NULL || NumberOfLogos == 0) {
   1195     //
   1196     // No logo displayed.
   1197     //
   1198     if (Blt != NULL) {
   1199       FreePool (Blt);
   1200     }
   1201 
   1202     return Status;
   1203   }
   1204 
   1205   //
   1206   // Advertise displayed Logo information.
   1207   //
   1208   if (NumberOfLogos == 1) {
   1209     //
   1210     // Only one logo displayed, use its Blt buffer directly for BootLogo protocol.
   1211     //
   1212     LogoBlt = Blt;
   1213     Status = EFI_SUCCESS;
   1214   } else {
   1215     //
   1216     // More than one Logo displayed, get merged BltBuffer using VideoToBuffer operation.
   1217     //
   1218     if (Blt != NULL) {
   1219       FreePool (Blt);
   1220     }
   1221 
   1222     //
   1223     // Ensure the LogoHeight * LogoWidth doesn't overflow
   1224     //
   1225     if (LogoHeight > DivU64x64Remainder ((UINTN) ~0, LogoWidth, NULL)) {
   1226       return EFI_UNSUPPORTED;
   1227     }
   1228     BufferSize = MultU64x64 (LogoWidth, LogoHeight);
   1229 
   1230     //
   1231     // Ensure the BufferSize * sizeof (EFI_GRAPHICS_OUTPUT_BLT_PIXEL) doesn't overflow
   1232     //
   1233     if (BufferSize > DivU64x32 ((UINTN) ~0, sizeof (EFI_GRAPHICS_OUTPUT_BLT_PIXEL))) {
   1234       return EFI_UNSUPPORTED;
   1235     }
   1236 
   1237     LogoBlt = AllocateZeroPool ((UINTN)BufferSize * sizeof (EFI_GRAPHICS_OUTPUT_BLT_PIXEL));
   1238     if (LogoBlt == NULL) {
   1239       return EFI_OUT_OF_RESOURCES;
   1240     }
   1241 
   1242     if (GraphicsOutput != NULL) {
   1243       Status = GraphicsOutput->Blt (
   1244                           GraphicsOutput,
   1245                           LogoBlt,
   1246                           EfiBltVideoToBltBuffer,
   1247                           LogoDestX,
   1248                           LogoDestY,
   1249                           0,
   1250                           0,
   1251                           LogoWidth,
   1252                           LogoHeight,
   1253                           LogoWidth * sizeof (EFI_GRAPHICS_OUTPUT_BLT_PIXEL)
   1254                           );
   1255     } else if (UgaDraw != NULL && FeaturePcdGet (PcdUgaConsumeSupport)) {
   1256       Status = UgaDraw->Blt (
   1257                           UgaDraw,
   1258                           (EFI_UGA_PIXEL *) LogoBlt,
   1259                           EfiUgaVideoToBltBuffer,
   1260                           LogoDestX,
   1261                           LogoDestY,
   1262                           0,
   1263                           0,
   1264                           LogoWidth,
   1265                           LogoHeight,
   1266                           LogoWidth * sizeof (EFI_UGA_PIXEL)
   1267                           );
   1268     } else {
   1269       Status = EFI_UNSUPPORTED;
   1270     }
   1271   }
   1272 
   1273   if (!EFI_ERROR (Status)) {
   1274     BootLogo->SetBootLogo (BootLogo, LogoBlt, LogoDestX, LogoDestY, LogoWidth, LogoHeight);
   1275   }
   1276   FreePool (LogoBlt);
   1277 
   1278   return Status;
   1279 }
   1280 
   1281 /**
   1282   Use SystemTable Conout to turn on video based Simple Text Out consoles. The
   1283   Simple Text Out screens will now be synced up with all non video output devices
   1284 
   1285   @retval EFI_SUCCESS     UGA devices are back in text mode and synced up.
   1286 
   1287 **/
   1288 EFI_STATUS
   1289 EFIAPI
   1290 DisableQuietBoot (
   1291   VOID
   1292   )
   1293 {
   1294 
   1295   //
   1296   // Enable Cursor on Screen
   1297   //
   1298   gST->ConOut->EnableCursor (gST->ConOut, TRUE);
   1299   return EFI_SUCCESS;
   1300 }
   1301 
   1302