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