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