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       };
    873 
    874     }
    875 
    876     ImageIndex = (UINTN) (Image - ImageHeader);
    877     if ((ImageIndex % 4) != 0) {
    878       //
    879       // Bmp Image starts each row on a 32-bit boundary!
    880       //
    881       Image = Image + (4 - (ImageIndex % 4));
    882     }
    883   }
    884 
    885   return EFI_SUCCESS;
    886 }
    887 
    888 /**
    889   Use SystemTable Conout to stop video based Simple Text Out consoles from going
    890   to the video device. Put up LogoFile on every video device that is a console.
    891 
    892   @param[in]  LogoFile   File name of logo to display on the center of the screen.
    893 
    894   @retval EFI_SUCCESS     ConsoleControl has been flipped to graphics and logo displayed.
    895   @retval EFI_UNSUPPORTED Logo not found
    896 
    897 **/
    898 EFI_STATUS
    899 EFIAPI
    900 EnableQuietBoot (
    901   IN  EFI_GUID  *LogoFile
    902   )
    903 {
    904   EFI_STATUS                    Status;
    905   EFI_OEM_BADGING_PROTOCOL      *Badging;
    906   UINT32                        SizeOfX;
    907   UINT32                        SizeOfY;
    908   INTN                          DestX;
    909   INTN                          DestY;
    910   UINT8                         *ImageData;
    911   UINTN                         ImageSize;
    912   UINTN                         BltSize;
    913   UINT32                        Instance;
    914   EFI_BADGING_FORMAT            Format;
    915   EFI_BADGING_DISPLAY_ATTRIBUTE Attribute;
    916   UINTN                         CoordinateX;
    917   UINTN                         CoordinateY;
    918   UINTN                         Height;
    919   UINTN                         Width;
    920   EFI_GRAPHICS_OUTPUT_BLT_PIXEL *Blt;
    921   EFI_UGA_DRAW_PROTOCOL         *UgaDraw;
    922   UINT32                        ColorDepth;
    923   UINT32                        RefreshRate;
    924   EFI_GRAPHICS_OUTPUT_PROTOCOL  *GraphicsOutput;
    925   EFI_BOOT_LOGO_PROTOCOL        *BootLogo;
    926   UINTN                         NumberOfLogos;
    927   EFI_GRAPHICS_OUTPUT_BLT_PIXEL *LogoBlt;
    928   UINTN                         LogoDestX;
    929   UINTN                         LogoDestY;
    930   UINTN                         LogoHeight;
    931   UINTN                         LogoWidth;
    932   UINTN                         NewDestX;
    933   UINTN                         NewDestY;
    934   UINTN                         NewHeight;
    935   UINTN                         NewWidth;
    936   UINT64                        BufferSize;
    937 
    938   UgaDraw = NULL;
    939   //
    940   // Try to open GOP first
    941   //
    942   Status = gBS->HandleProtocol (gST->ConsoleOutHandle, &gEfiGraphicsOutputProtocolGuid, (VOID **) &GraphicsOutput);
    943   if (EFI_ERROR (Status) && FeaturePcdGet (PcdUgaConsumeSupport)) {
    944     GraphicsOutput = NULL;
    945     //
    946     // Open GOP failed, try to open UGA
    947     //
    948     Status = gBS->HandleProtocol (gST->ConsoleOutHandle, &gEfiUgaDrawProtocolGuid, (VOID **) &UgaDraw);
    949   }
    950   if (EFI_ERROR (Status)) {
    951     return EFI_UNSUPPORTED;
    952   }
    953 
    954   //
    955   // Try to open Boot Logo Protocol.
    956   //
    957   BootLogo = NULL;
    958   gBS->LocateProtocol (&gEfiBootLogoProtocolGuid, NULL, (VOID **) &BootLogo);
    959 
    960   //
    961   // Erase Cursor from screen
    962   //
    963   gST->ConOut->EnableCursor (gST->ConOut, FALSE);
    964 
    965   Badging = NULL;
    966   Status  = gBS->LocateProtocol (&gEfiOEMBadgingProtocolGuid, NULL, (VOID **) &Badging);
    967 
    968   if (GraphicsOutput != NULL) {
    969     SizeOfX = GraphicsOutput->Mode->Info->HorizontalResolution;
    970     SizeOfY = GraphicsOutput->Mode->Info->VerticalResolution;
    971 
    972   } else if (UgaDraw != NULL && FeaturePcdGet (PcdUgaConsumeSupport)) {
    973     Status = UgaDraw->GetMode (UgaDraw, &SizeOfX, &SizeOfY, &ColorDepth, &RefreshRate);
    974     if (EFI_ERROR (Status)) {
    975       return EFI_UNSUPPORTED;
    976     }
    977   } else {
    978     return EFI_UNSUPPORTED;
    979   }
    980 
    981   Blt = NULL;
    982   NumberOfLogos = 0;
    983   LogoDestX = 0;
    984   LogoDestY = 0;
    985   LogoHeight = 0;
    986   LogoWidth = 0;
    987   NewDestX = 0;
    988   NewDestY = 0;
    989   NewHeight = 0;
    990   NewWidth = 0;
    991   Instance = 0;
    992   while (1) {
    993     ImageData = NULL;
    994     ImageSize = 0;
    995 
    996     if (Badging != NULL) {
    997       //
    998       // Get image from OEMBadging protocol.
    999       //
   1000       Status = Badging->GetImage (
   1001                           Badging,
   1002                           &Instance,
   1003                           &Format,
   1004                           &ImageData,
   1005                           &ImageSize,
   1006                           &Attribute,
   1007                           &CoordinateX,
   1008                           &CoordinateY
   1009                           );
   1010       if (EFI_ERROR (Status)) {
   1011         goto Done;
   1012       }
   1013 
   1014       //
   1015       // Currently only support BMP format.
   1016       //
   1017       if (Format != EfiBadgingFormatBMP) {
   1018         if (ImageData != NULL) {
   1019           FreePool (ImageData);
   1020         }
   1021         continue;
   1022       }
   1023     } else {
   1024       //
   1025       // Get the specified image from FV.
   1026       //
   1027       Status = GetSectionFromAnyFv (LogoFile, EFI_SECTION_RAW, 0, (VOID **) &ImageData, &ImageSize);
   1028       if (EFI_ERROR (Status)) {
   1029         return EFI_UNSUPPORTED;
   1030       }
   1031 
   1032       CoordinateX = 0;
   1033       CoordinateY = 0;
   1034       if (!FeaturePcdGet(PcdBootlogoOnlyEnable)) {
   1035         Attribute   = EfiBadgingDisplayAttributeCenter;
   1036       } else {
   1037         Attribute   = EfiBadgingDisplayAttributeCustomized;
   1038       }
   1039     }
   1040 
   1041     if (Blt != NULL) {
   1042       FreePool (Blt);
   1043     }
   1044     Blt = NULL;
   1045     Status = ConvertBmpToGopBlt (
   1046               ImageData,
   1047               ImageSize,
   1048               (VOID **) &Blt,
   1049               &BltSize,
   1050               &Height,
   1051               &Width
   1052               );
   1053     if (EFI_ERROR (Status)) {
   1054       FreePool (ImageData);
   1055 
   1056       if (Badging == NULL) {
   1057         return Status;
   1058       } else {
   1059         continue;
   1060       }
   1061     }
   1062 
   1063     //
   1064     // Calculate the display position according to Attribute.
   1065     //
   1066     switch (Attribute) {
   1067     case EfiBadgingDisplayAttributeLeftTop:
   1068       DestX = CoordinateX;
   1069       DestY = CoordinateY;
   1070       break;
   1071 
   1072     case EfiBadgingDisplayAttributeCenterTop:
   1073       DestX = (SizeOfX - Width) / 2;
   1074       DestY = CoordinateY;
   1075       break;
   1076 
   1077     case EfiBadgingDisplayAttributeRightTop:
   1078       DestX = (SizeOfX - Width - CoordinateX);
   1079       DestY = CoordinateY;;
   1080       break;
   1081 
   1082     case EfiBadgingDisplayAttributeCenterRight:
   1083       DestX = (SizeOfX - Width - CoordinateX);
   1084       DestY = (SizeOfY - Height) / 2;
   1085       break;
   1086 
   1087     case EfiBadgingDisplayAttributeRightBottom:
   1088       DestX = (SizeOfX - Width - CoordinateX);
   1089       DestY = (SizeOfY - Height - CoordinateY);
   1090       break;
   1091 
   1092     case EfiBadgingDisplayAttributeCenterBottom:
   1093       DestX = (SizeOfX - Width) / 2;
   1094       DestY = (SizeOfY - Height - CoordinateY);
   1095       break;
   1096 
   1097     case EfiBadgingDisplayAttributeLeftBottom:
   1098       DestX = CoordinateX;
   1099       DestY = (SizeOfY - Height - CoordinateY);
   1100       break;
   1101 
   1102     case EfiBadgingDisplayAttributeCenterLeft:
   1103       DestX = CoordinateX;
   1104       DestY = (SizeOfY - Height) / 2;
   1105       break;
   1106 
   1107     case EfiBadgingDisplayAttributeCenter:
   1108       DestX = (SizeOfX - Width) / 2;
   1109       DestY = (SizeOfY - Height) / 2;
   1110       break;
   1111 
   1112     case EfiBadgingDisplayAttributeCustomized:
   1113       DestX = (SizeOfX - Width) / 2;
   1114       DestY = ((SizeOfY * 382) / 1000) - Height / 2;
   1115       break;
   1116 
   1117     default:
   1118       DestX = CoordinateX;
   1119       DestY = CoordinateY;
   1120       break;
   1121     }
   1122 
   1123     if ((DestX >= 0) && (DestY >= 0)) {
   1124       if (GraphicsOutput != NULL) {
   1125         Status = GraphicsOutput->Blt (
   1126                             GraphicsOutput,
   1127                             Blt,
   1128                             EfiBltBufferToVideo,
   1129                             0,
   1130                             0,
   1131                             (UINTN) DestX,
   1132                             (UINTN) DestY,
   1133                             Width,
   1134                             Height,
   1135                             Width * sizeof (EFI_GRAPHICS_OUTPUT_BLT_PIXEL)
   1136                             );
   1137       } else if (UgaDraw != NULL && FeaturePcdGet (PcdUgaConsumeSupport)) {
   1138         Status = UgaDraw->Blt (
   1139                             UgaDraw,
   1140                             (EFI_UGA_PIXEL *) Blt,
   1141                             EfiUgaBltBufferToVideo,
   1142                             0,
   1143                             0,
   1144                             (UINTN) DestX,
   1145                             (UINTN) DestY,
   1146                             Width,
   1147                             Height,
   1148                             Width * sizeof (EFI_UGA_PIXEL)
   1149                             );
   1150       } else {
   1151         Status = EFI_UNSUPPORTED;
   1152       }
   1153 
   1154       //
   1155       // Report displayed Logo information.
   1156       //
   1157       if (!EFI_ERROR (Status)) {
   1158         NumberOfLogos++;
   1159 
   1160         if (LogoWidth == 0) {
   1161           //
   1162           // The first Logo.
   1163           //
   1164           LogoDestX = (UINTN) DestX;
   1165           LogoDestY = (UINTN) DestY;
   1166           LogoWidth = Width;
   1167           LogoHeight = Height;
   1168         } else {
   1169           //
   1170           // Merge new logo with old one.
   1171           //
   1172           NewDestX = MIN ((UINTN) DestX, LogoDestX);
   1173           NewDestY = MIN ((UINTN) DestY, LogoDestY);
   1174           NewWidth = MAX ((UINTN) DestX + Width, LogoDestX + LogoWidth) - NewDestX;
   1175           NewHeight = MAX ((UINTN) DestY + Height, LogoDestY + LogoHeight) - NewDestY;
   1176 
   1177           LogoDestX = NewDestX;
   1178           LogoDestY = NewDestY;
   1179           LogoWidth = NewWidth;
   1180           LogoHeight = NewHeight;
   1181         }
   1182       }
   1183     }
   1184 
   1185     FreePool (ImageData);
   1186 
   1187     if (Badging == NULL) {
   1188       break;
   1189     }
   1190   }
   1191 
   1192 Done:
   1193   if (BootLogo == NULL || NumberOfLogos == 0) {
   1194     //
   1195     // No logo displayed.
   1196     //
   1197     if (Blt != NULL) {
   1198       FreePool (Blt);
   1199     }
   1200 
   1201     return Status;
   1202   }
   1203 
   1204   //
   1205   // Advertise displayed Logo information.
   1206   //
   1207   if (NumberOfLogos == 1) {
   1208     //
   1209     // Only one logo displayed, use its Blt buffer directly for BootLogo protocol.
   1210     //
   1211     LogoBlt = Blt;
   1212     Status = EFI_SUCCESS;
   1213   } else {
   1214     //
   1215     // More than one Logo displayed, get merged BltBuffer using VideoToBuffer operation.
   1216     //
   1217     if (Blt != NULL) {
   1218       FreePool (Blt);
   1219     }
   1220 
   1221     //
   1222     // Ensure the LogoHeight * LogoWidth doesn't overflow
   1223     //
   1224     if (LogoHeight > DivU64x64Remainder ((UINTN) ~0, LogoWidth, NULL)) {
   1225       return EFI_UNSUPPORTED;
   1226     }
   1227     BufferSize = MultU64x64 (LogoWidth, LogoHeight);
   1228 
   1229     //
   1230     // Ensure the BufferSize * sizeof (EFI_GRAPHICS_OUTPUT_BLT_PIXEL) doesn't overflow
   1231     //
   1232     if (BufferSize > DivU64x32 ((UINTN) ~0, sizeof (EFI_GRAPHICS_OUTPUT_BLT_PIXEL))) {
   1233       return EFI_UNSUPPORTED;
   1234     }
   1235 
   1236     LogoBlt = AllocateZeroPool ((UINTN)BufferSize * sizeof (EFI_GRAPHICS_OUTPUT_BLT_PIXEL));
   1237     if (LogoBlt == NULL) {
   1238       return EFI_OUT_OF_RESOURCES;
   1239     }
   1240 
   1241     if (GraphicsOutput != NULL) {
   1242       Status = GraphicsOutput->Blt (
   1243                           GraphicsOutput,
   1244                           LogoBlt,
   1245                           EfiBltVideoToBltBuffer,
   1246                           LogoDestX,
   1247                           LogoDestY,
   1248                           0,
   1249                           0,
   1250                           LogoWidth,
   1251                           LogoHeight,
   1252                           LogoWidth * sizeof (EFI_GRAPHICS_OUTPUT_BLT_PIXEL)
   1253                           );
   1254     } else if (UgaDraw != NULL && FeaturePcdGet (PcdUgaConsumeSupport)) {
   1255       Status = UgaDraw->Blt (
   1256                           UgaDraw,
   1257                           (EFI_UGA_PIXEL *) LogoBlt,
   1258                           EfiUgaVideoToBltBuffer,
   1259                           LogoDestX,
   1260                           LogoDestY,
   1261                           0,
   1262                           0,
   1263                           LogoWidth,
   1264                           LogoHeight,
   1265                           LogoWidth * sizeof (EFI_UGA_PIXEL)
   1266                           );
   1267     } else {
   1268       Status = EFI_UNSUPPORTED;
   1269     }
   1270   }
   1271 
   1272   if (!EFI_ERROR (Status)) {
   1273     BootLogo->SetBootLogo (BootLogo, LogoBlt, LogoDestX, LogoDestY, LogoWidth, LogoHeight);
   1274   }
   1275   FreePool (LogoBlt);
   1276 
   1277   return Status;
   1278 }
   1279 
   1280 /**
   1281   Use SystemTable Conout to turn on video based Simple Text Out consoles. The
   1282   Simple Text Out screens will now be synced up with all non video output devices
   1283 
   1284   @retval EFI_SUCCESS     UGA devices are back in text mode and synced up.
   1285 
   1286 **/
   1287 EFI_STATUS
   1288 EFIAPI
   1289 DisableQuietBoot (
   1290   VOID
   1291   )
   1292 {
   1293 
   1294   //
   1295   // Enable Cursor on Screen
   1296   //
   1297   gST->ConOut->EnableCursor (gST->ConOut, TRUE);
   1298   return EFI_SUCCESS;
   1299 }
   1300 
   1301