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         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
EnableQuietBoot(IN EFI_GUID * LogoFile)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
DisableQuietBoot(VOID)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