• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /** @file
2   This library is only intended to be used by PlatformBootManagerLib
3   to show progress bar and LOGO.
4 
5 Copyright (c) 2011 - 2015, Intel Corporation. All rights reserved.<BR>
6 This program and the accompanying materials are licensed and made available under
7 the terms and conditions of the BSD License that accompanies this distribution.
8 The full text of the license may be found at
9 http://opensource.org/licenses/bsd-license.php.
10 
11 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
12 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
13 
14 **/
15 
16 #include <PiDxe.h>
17 #include <Protocol/SimpleTextOut.h>
18 #include <Protocol/PlatformLogo.h>
19 #include <Protocol/GraphicsOutput.h>
20 #include <Protocol/UgaDraw.h>
21 #include <Protocol/BootLogo.h>
22 #include <Library/BaseLib.h>
23 #include <Library/UefiLib.h>
24 #include <Library/BaseMemoryLib.h>
25 #include <Library/UefiBootServicesTableLib.h>
26 #include <Library/DxeServicesLib.h>
27 #include <Library/PcdLib.h>
28 #include <Library/MemoryAllocationLib.h>
29 #include <Library/DebugLib.h>
30 #include <Library/ImageDecoderLib.h>
31 
32 /**
33   Show LOGO on all consoles.
34 
35   @param[in]  ImageFormat Format of the image file.
36   @param[in]  LogoFile    The file name of logo to display.
37   @param[in]  Attribute   The display attributes of the image returned.
38   @param[in]  OffsetX     The X offset of the image regarding the Attribute.
39   @param[in]  OffsetY     The Y offset of the image regarding the Attribute.
40 
41   @retval EFI_SUCCESS     Logo was displayed.
42   @retval EFI_UNSUPPORTED Logo was not found or cannot be displayed.
43 **/
44 EFI_STATUS
45 EFIAPI
BootLogoEnableLogo(IN IMAGE_FORMAT ImageFormat,IN EFI_GUID * Logo,IN EDKII_PLATFORM_LOGO_DISPLAY_ATTRIBUTE Attribute,IN INTN OffsetX,IN INTN OffsetY)46 BootLogoEnableLogo (
47   IN  IMAGE_FORMAT                          ImageFormat,
48   IN  EFI_GUID                              *Logo,
49   IN  EDKII_PLATFORM_LOGO_DISPLAY_ATTRIBUTE Attribute,
50   IN  INTN                                  OffsetX,
51   IN  INTN                                  OffsetY
52   )
53 {
54   EFI_STATUS                    Status;
55   EDKII_PLATFORM_LOGO_PROTOCOL  *PlatformLogo;
56   UINT32                        SizeOfX;
57   UINT32                        SizeOfY;
58   INTN                          DestX;
59   INTN                          DestY;
60   UINT8                         *ImageData;
61   UINTN                         ImageSize;
62   UINTN                         BltSize;
63   UINT32                        Instance;
64   UINTN                         Height;
65   UINTN                         Width;
66   EFI_GRAPHICS_OUTPUT_BLT_PIXEL *Blt;
67   EFI_UGA_DRAW_PROTOCOL         *UgaDraw;
68   UINT32                        ColorDepth;
69   UINT32                        RefreshRate;
70   EFI_GRAPHICS_OUTPUT_PROTOCOL  *GraphicsOutput;
71   EFI_BOOT_LOGO_PROTOCOL        *BootLogo;
72   UINTN                         NumberOfLogos;
73   EFI_GRAPHICS_OUTPUT_BLT_PIXEL *LogoBlt;
74   UINTN                         LogoDestX;
75   UINTN                         LogoDestY;
76   UINTN                         LogoHeight;
77   UINTN                         LogoWidth;
78   UINTN                         NewDestX;
79   UINTN                         NewDestY;
80   UINTN                         NewHeight;
81   UINTN                         NewWidth;
82   UINTN                         BufferSize;
83 
84   UgaDraw = NULL;
85   //
86   // Try to open GOP first
87   //
88   Status = gBS->HandleProtocol (gST->ConsoleOutHandle, &gEfiGraphicsOutputProtocolGuid, (VOID **) &GraphicsOutput);
89   if (EFI_ERROR (Status) && FeaturePcdGet (PcdUgaConsumeSupport)) {
90     GraphicsOutput = NULL;
91     //
92     // Open GOP failed, try to open UGA
93     //
94     Status = gBS->HandleProtocol (gST->ConsoleOutHandle, &gEfiUgaDrawProtocolGuid, (VOID **) &UgaDraw);
95     if (EFI_ERROR (Status)) {
96       UgaDraw = NULL;
97     }
98   }
99   if (EFI_ERROR (Status)) {
100     return EFI_UNSUPPORTED;
101   }
102 
103   Status  = gBS->LocateProtocol (&gEdkiiPlatformLogoProtocolGuid, NULL, (VOID **) &PlatformLogo);
104   if (EFI_ERROR (Status)) {
105     PlatformLogo = NULL;
106   }
107 
108   if ((Logo == NULL) && (PlatformLogo == NULL)) {
109     return EFI_UNSUPPORTED;
110   }
111 
112   //
113   // Try to open Boot Logo Protocol.
114   //
115   Status = gBS->LocateProtocol (&gEfiBootLogoProtocolGuid, NULL, (VOID **) &BootLogo);
116   if (EFI_ERROR (Status)) {
117     BootLogo = NULL;
118   }
119 
120   //
121   // Erase Cursor from screen
122   //
123   gST->ConOut->EnableCursor (gST->ConOut, FALSE);
124 
125   if (GraphicsOutput != NULL) {
126     SizeOfX = GraphicsOutput->Mode->Info->HorizontalResolution;
127     SizeOfY = GraphicsOutput->Mode->Info->VerticalResolution;
128 
129   } else {
130     ASSERT (UgaDraw != NULL);
131     Status = UgaDraw->GetMode (UgaDraw, &SizeOfX, &SizeOfY, &ColorDepth, &RefreshRate);
132     if (EFI_ERROR (Status)) {
133       return EFI_UNSUPPORTED;
134     }
135   }
136 
137   Blt = NULL;
138   NumberOfLogos = 0;
139   LogoDestX = 0;
140   LogoDestY = 0;
141   LogoHeight = 0;
142   LogoWidth = 0;
143   NewDestX = 0;
144   NewDestY = 0;
145   NewHeight = 0;
146   NewWidth = 0;
147   Instance = 0;
148   DestX = 0;
149   DestY = 0;
150   while (TRUE) {
151     ImageData = NULL;
152     ImageSize = 0;
153 
154     if (PlatformLogo != NULL) {
155       //
156       // Get image from OEMBadging protocol.
157       //
158       Status = PlatformLogo->GetImage (
159                                PlatformLogo,
160                                &Instance,
161                                &ImageFormat,
162                                &ImageData,
163                                &ImageSize,
164                                &Attribute,
165                                &OffsetX,
166                                &OffsetY
167                                );
168       if (EFI_ERROR (Status)) {
169         break;
170       }
171 
172     } else {
173       //
174       // Get the specified image from FV.
175       //
176       Status = GetSectionFromAnyFv (Logo, EFI_SECTION_RAW, 0, (VOID **) &ImageData, &ImageSize);
177       if (EFI_ERROR (Status)) {
178         return EFI_UNSUPPORTED;
179       }
180     }
181 
182     if (Blt != NULL) {
183       FreePool (Blt);
184     }
185 
186     Status = DecodeImage (ImageFormat, ImageData, ImageSize, &Blt, &BltSize, &Width, &Height);
187     FreePool (ImageData);
188     if (EFI_ERROR (Status)) {
189       if (Logo != NULL) {
190         //
191         // Directly return failure for single LOGO
192         //
193         return Status;
194       } else {
195         continue;
196       }
197     }
198 
199     //
200     // Calculate the display position according to Attribute.
201     //
202     switch (Attribute) {
203     case EdkiiPlatformLogoDisplayAttributeLeftTop:
204       DestX = 0;
205       DestY = 0;
206       break;
207     case EdkiiPlatformLogoDisplayAttributeCenterTop:
208       DestX = (SizeOfX - Width) / 2;
209       DestY = 0;
210       break;
211     case EdkiiPlatformLogoDisplayAttributeRightTop:
212       DestX = SizeOfX - Width;
213       DestY = 0;
214       break;
215 
216     case EdkiiPlatformLogoDisplayAttributeCenterLeft:
217       DestX = 0;
218       DestY = (SizeOfY - Height) / 2;
219       break;
220     case EdkiiPlatformLogoDisplayAttributeCenter:
221       DestX = (SizeOfX - Width) / 2;
222       DestY = (SizeOfY - Height) / 2;
223       break;
224     case EdkiiPlatformLogoDisplayAttributeCenterRight:
225       DestX = SizeOfX - Width;
226       DestY = (SizeOfY - Height) / 2;
227       break;
228 
229     case EdkiiPlatformLogoDisplayAttributeLeftBottom:
230       DestX = 0;
231       DestY = SizeOfY - Height;
232       break;
233     case EdkiiPlatformLogoDisplayAttributeCenterBottom:
234       DestX = (SizeOfX - Width) / 2;
235       DestY = SizeOfY - Height;
236       break;
237     case EdkiiPlatformLogoDisplayAttributeRightBottom:
238       DestX = SizeOfX - Width;
239       DestY = SizeOfY - Height;
240       break;
241 
242     default:
243       ASSERT (FALSE);
244       break;
245     }
246 
247     DestX += OffsetX;
248     DestY += OffsetY;
249 
250     if ((DestX >= 0) && (DestY >= 0)) {
251       if (GraphicsOutput != NULL) {
252         Status = GraphicsOutput->Blt (
253                                    GraphicsOutput,
254                                    Blt,
255                                    EfiBltBufferToVideo,
256                                    0,
257                                    0,
258                                    (UINTN) DestX,
259                                    (UINTN) DestY,
260                                    Width,
261                                    Height,
262                                    Width * sizeof (EFI_GRAPHICS_OUTPUT_BLT_PIXEL)
263                                    );
264       } else {
265         ASSERT (UgaDraw != NULL);
266         Status = UgaDraw->Blt (
267                             UgaDraw,
268                             (EFI_UGA_PIXEL *) Blt,
269                             EfiUgaBltBufferToVideo,
270                             0,
271                             0,
272                             (UINTN) DestX,
273                             (UINTN) DestY,
274                             Width,
275                             Height,
276                             Width * sizeof (EFI_UGA_PIXEL)
277                             );
278       }
279 
280       //
281       // Report displayed Logo information.
282       //
283       if (!EFI_ERROR (Status)) {
284         NumberOfLogos++;
285 
286         if (LogoWidth == 0) {
287           //
288           // The first Logo.
289           //
290           LogoDestX = (UINTN) DestX;
291           LogoDestY = (UINTN) DestY;
292           LogoWidth = Width;
293           LogoHeight = Height;
294         } else {
295           //
296           // Merge new logo with old one.
297           //
298           NewDestX = MIN ((UINTN) DestX, LogoDestX);
299           NewDestY = MIN ((UINTN) DestY, LogoDestY);
300           NewWidth = MAX ((UINTN) DestX + Width, LogoDestX + LogoWidth) - NewDestX;
301           NewHeight = MAX ((UINTN) DestY + Height, LogoDestY + LogoHeight) - NewDestY;
302 
303           LogoDestX = NewDestX;
304           LogoDestY = NewDestY;
305           LogoWidth = NewWidth;
306           LogoHeight = NewHeight;
307         }
308       }
309     }
310 
311     if (PlatformLogo == NULL) {
312       break;
313     }
314   }
315 
316   if (BootLogo == NULL || NumberOfLogos == 0) {
317     //
318     // No logo displayed.
319     //
320     if (Blt != NULL) {
321       FreePool (Blt);
322     }
323 
324     return Status;
325   }
326 
327   //
328   // Advertise displayed Logo information.
329   //
330   if (NumberOfLogos == 1) {
331     //
332     // Only one logo displayed, use its Blt buffer directly for BootLogo protocol.
333     //
334     LogoBlt = Blt;
335     Status = EFI_SUCCESS;
336   } else {
337     //
338     // More than one Logo displayed, get merged BltBuffer using VideoToBuffer operation.
339     //
340     if (Blt != NULL) {
341       FreePool (Blt);
342     }
343 
344     //
345     // Ensure the LogoHeight * LogoWidth * sizeof (EFI_GRAPHICS_OUTPUT_BLT_PIXEL) doesn't overflow
346     //
347     if (LogoHeight > MAX_UINTN / LogoWidth / sizeof (EFI_GRAPHICS_OUTPUT_BLT_PIXEL)) {
348       return EFI_UNSUPPORTED;
349     }
350     BufferSize = LogoWidth * LogoHeight * sizeof (EFI_GRAPHICS_OUTPUT_BLT_PIXEL);
351 
352     LogoBlt = AllocatePool (BufferSize);
353     if (LogoBlt == NULL) {
354       return EFI_OUT_OF_RESOURCES;
355     }
356 
357     if (GraphicsOutput != NULL) {
358       Status = GraphicsOutput->Blt (
359                           GraphicsOutput,
360                           LogoBlt,
361                           EfiBltVideoToBltBuffer,
362                           LogoDestX,
363                           LogoDestY,
364                           0,
365                           0,
366                           LogoWidth,
367                           LogoHeight,
368                           LogoWidth * sizeof (EFI_GRAPHICS_OUTPUT_BLT_PIXEL)
369                           );
370     } else {
371       Status = UgaDraw->Blt (
372                           UgaDraw,
373                           (EFI_UGA_PIXEL *) LogoBlt,
374                           EfiUgaVideoToBltBuffer,
375                           LogoDestX,
376                           LogoDestY,
377                           0,
378                           0,
379                           LogoWidth,
380                           LogoHeight,
381                           LogoWidth * sizeof (EFI_UGA_PIXEL)
382                           );
383     }
384   }
385 
386   if (!EFI_ERROR (Status)) {
387     BootLogo->SetBootLogo (BootLogo, LogoBlt, LogoDestX, LogoDestY, LogoWidth, LogoHeight);
388   }
389   FreePool (LogoBlt);
390 
391   return Status;
392 }
393 
394 /**
395   Use SystemTable Conout to turn on video based Simple Text Out consoles. The
396   Simple Text Out screens will now be synced up with all non video output devices
397 
398   @retval EFI_SUCCESS     UGA devices are back in text mode and synced up.
399 
400 **/
401 EFI_STATUS
402 EFIAPI
BootLogoDisableLogo(VOID)403 BootLogoDisableLogo (
404   VOID
405   )
406 {
407 
408   //
409   // Enable Cursor on Screen
410   //
411   gST->ConOut->EnableCursor (gST->ConOut, TRUE);
412   return EFI_SUCCESS;
413 }
414 
415 
416 /**
417 
418   Update progress bar with title above it. It only works in Graphics mode.
419 
420   @param TitleForeground Foreground color for Title.
421   @param TitleBackground Background color for Title.
422   @param Title           Title above progress bar.
423   @param ProgressColor   Progress bar color.
424   @param Progress        Progress (0-100)
425   @param PreviousValue   The previous value of the progress.
426 
427   @retval  EFI_STATUS       Success update the progress bar
428 
429 **/
430 EFI_STATUS
431 EFIAPI
BootLogoUpdateProgress(IN EFI_GRAPHICS_OUTPUT_BLT_PIXEL TitleForeground,IN EFI_GRAPHICS_OUTPUT_BLT_PIXEL TitleBackground,IN CHAR16 * Title,IN EFI_GRAPHICS_OUTPUT_BLT_PIXEL ProgressColor,IN UINTN Progress,IN UINTN PreviousValue)432 BootLogoUpdateProgress (
433   IN EFI_GRAPHICS_OUTPUT_BLT_PIXEL TitleForeground,
434   IN EFI_GRAPHICS_OUTPUT_BLT_PIXEL TitleBackground,
435   IN CHAR16                        *Title,
436   IN EFI_GRAPHICS_OUTPUT_BLT_PIXEL ProgressColor,
437   IN UINTN                         Progress,
438   IN UINTN                         PreviousValue
439   )
440 {
441   EFI_STATUS                     Status;
442   EFI_GRAPHICS_OUTPUT_PROTOCOL   *GraphicsOutput;
443   EFI_UGA_DRAW_PROTOCOL          *UgaDraw;
444   UINT32                         SizeOfX;
445   UINT32                         SizeOfY;
446   UINT32                         ColorDepth;
447   UINT32                         RefreshRate;
448   EFI_GRAPHICS_OUTPUT_BLT_PIXEL  Color;
449   UINTN                          BlockHeight;
450   UINTN                          BlockWidth;
451   UINTN                          BlockNum;
452   UINTN                          PosX;
453   UINTN                          PosY;
454   UINTN                          Index;
455 
456   if (Progress > 100) {
457     return EFI_INVALID_PARAMETER;
458   }
459 
460   UgaDraw = NULL;
461   Status = gBS->HandleProtocol (gST->ConsoleOutHandle, &gEfiGraphicsOutputProtocolGuid, (VOID **) &GraphicsOutput);
462   if (EFI_ERROR (Status) && FeaturePcdGet (PcdUgaConsumeSupport)) {
463     GraphicsOutput = NULL;
464 
465     Status = gBS->HandleProtocol (gST->ConsoleOutHandle, &gEfiUgaDrawProtocolGuid, (VOID **) &UgaDraw);
466     if (EFI_ERROR (Status)) {
467       UgaDraw = NULL;
468     }
469   }
470   if (EFI_ERROR (Status)) {
471     return EFI_UNSUPPORTED;
472   }
473 
474   SizeOfX = 0;
475   SizeOfY = 0;
476   if (GraphicsOutput != NULL) {
477     SizeOfX = GraphicsOutput->Mode->Info->HorizontalResolution;
478     SizeOfY = GraphicsOutput->Mode->Info->VerticalResolution;
479   } else if (UgaDraw != NULL) {
480     Status = UgaDraw->GetMode (
481                         UgaDraw,
482                         &SizeOfX,
483                         &SizeOfY,
484                         &ColorDepth,
485                         &RefreshRate
486                         );
487     if (EFI_ERROR (Status)) {
488       return EFI_UNSUPPORTED;
489     }
490   } else {
491     return EFI_UNSUPPORTED;
492   }
493 
494   BlockWidth  = SizeOfX / 100;
495   BlockHeight = SizeOfY / 50;
496 
497   BlockNum    = Progress;
498 
499   PosX        = 0;
500   PosY        = SizeOfY * 48 / 50;
501 
502   if (BlockNum == 0) {
503     //
504     // Clear progress area
505     //
506     SetMem (&Color, sizeof (EFI_GRAPHICS_OUTPUT_BLT_PIXEL), 0x0);
507 
508     if (GraphicsOutput != NULL) {
509       Status = GraphicsOutput->Blt (
510                           GraphicsOutput,
511                           &Color,
512                           EfiBltVideoFill,
513                           0,
514                           0,
515                           0,
516                           PosY - EFI_GLYPH_HEIGHT - 1,
517                           SizeOfX,
518                           SizeOfY - (PosY - EFI_GLYPH_HEIGHT - 1),
519                           SizeOfX * sizeof (EFI_GRAPHICS_OUTPUT_BLT_PIXEL)
520                           );
521     } else if (FeaturePcdGet (PcdUgaConsumeSupport)) {
522       Status = UgaDraw->Blt (
523                           UgaDraw,
524                           (EFI_UGA_PIXEL *) &Color,
525                           EfiUgaVideoFill,
526                           0,
527                           0,
528                           0,
529                           PosY - EFI_GLYPH_HEIGHT - 1,
530                           SizeOfX,
531                           SizeOfY - (PosY - EFI_GLYPH_HEIGHT - 1),
532                           SizeOfX * sizeof (EFI_UGA_PIXEL)
533                           );
534     } else {
535       return EFI_UNSUPPORTED;
536     }
537   }
538   //
539   // Show progress by drawing blocks
540   //
541   for (Index = PreviousValue; Index < BlockNum; Index++) {
542     PosX = Index * BlockWidth;
543     if (GraphicsOutput != NULL) {
544       Status = GraphicsOutput->Blt (
545                           GraphicsOutput,
546                           &ProgressColor,
547                           EfiBltVideoFill,
548                           0,
549                           0,
550                           PosX,
551                           PosY,
552                           BlockWidth - 1,
553                           BlockHeight,
554                           (BlockWidth) * sizeof (EFI_GRAPHICS_OUTPUT_BLT_PIXEL)
555                           );
556     } else if (FeaturePcdGet (PcdUgaConsumeSupport)) {
557       Status = UgaDraw->Blt (
558                           UgaDraw,
559                           (EFI_UGA_PIXEL *) &ProgressColor,
560                           EfiUgaVideoFill,
561                           0,
562                           0,
563                           PosX,
564                           PosY,
565                           BlockWidth - 1,
566                           BlockHeight,
567                           (BlockWidth) * sizeof (EFI_UGA_PIXEL)
568                           );
569     } else {
570       return EFI_UNSUPPORTED;
571     }
572   }
573 
574   PrintXY (
575     (SizeOfX - StrLen (Title) * EFI_GLYPH_WIDTH) / 2,
576     PosY - EFI_GLYPH_HEIGHT - 1,
577     &TitleForeground,
578     &TitleBackground,
579     Title
580     );
581 
582   return EFI_SUCCESS;
583 }
584