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
IsNvNeed(IN CHAR16 * ConVarName)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
UpdateSystemTableConsole(IN CHAR16 * VarName,IN EFI_GUID * ConsoleGuid,IN OUT EFI_HANDLE * ConsoleHandle,IN OUT VOID ** ProtocolInterface)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
BdsLibUpdateConsoleVariable(IN CHAR16 * ConVarName,IN EFI_DEVICE_PATH_PROTOCOL * CustomizedConDevicePath,IN EFI_DEVICE_PATH_PROTOCOL * ExclusiveDevicePath)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
BdsLibConnectConsoleVariable(IN CHAR16 * ConVarName)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
BdsLibConnectAllConsoles(VOID)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
BdsLibConnectAllDefaultConsoles(VOID)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
BdsLibConnectAllDefaultConsolesWithOutConIn(VOID)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
ConvertBmpToGopBlt(IN VOID * BmpImage,IN UINTN BmpImageSize,IN OUT VOID ** GopBlt,IN OUT UINTN * GopBltSize,OUT UINTN * PixelHeight,OUT UINTN * PixelWidth)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
EnableQuietBoot(IN EFI_GUID * LogoFile)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
DisableQuietBoot(VOID)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