1/** @file
2  BDS Lib functions which contain all the code to connect console device
3
4Copyright (c) 2004 - 2014, Intel Corporation. All rights reserved.<BR>
5This program and the accompanying materials
6are licensed and made available under the terms and conditions of the BSD License
7which accompanies this distribution.  The full text of the license may be found at
8http://opensource.org/licenses/bsd-license.php
9
10THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
11WITHOUT 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**/
29BOOLEAN
30IsNvNeed (
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**/
76BOOLEAN
77UpdateSystemTableConsole (
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**/
202EFI_STATUS
203EFIAPI
204BdsLibUpdateConsoleVariable (
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**/
335EFI_STATUS
336EFIAPI
337BdsLibConnectConsoleVariable (
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**/
428VOID
429EFIAPI
430BdsLibConnectAllConsoles (
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**/
506EFI_STATUS
507EFIAPI
508BdsLibConnectAllDefaultConsoles (
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**/
585EFI_STATUS
586EFIAPI
587BdsLibConnectAllDefaultConsolesWithOutConIn (
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**/
664EFI_STATUS
665ConvertBmpToGopBlt (
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**/
898EFI_STATUS
899EFIAPI
900EnableQuietBoot (
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
1192Done:
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**/
1287EFI_STATUS
1288EFIAPI
1289DisableQuietBoot (
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