]> git.proxmox.com Git - mirror_edk2.git/blob - MdeModulePkg/Library/BootLogoLib/BootLogoLib.c
MdeModulePkg: Add BootLogoLib to provide interfaces about logo display.
[mirror_edk2.git] / MdeModulePkg / Library / BootLogoLib / BootLogoLib.c
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] CoordinateX The X coordinate of the image.
39 @param[in] CoordinateY The Y coordinate of the image.
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
46 BootLogoEnableLogo (
47 IN IMAGE_FORMAT ImageFormat,
48 IN EFI_GUID *Logo,
49 IN EDKII_PLATFORM_LOGO_DISPLAY_ATTRIBUTE Attribute,
50 IN UINTN CoordinateX,
51 IN UINTN CoordinateY
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 while (TRUE) {
149 ImageData = NULL;
150 ImageSize = 0;
151
152 if (PlatformLogo != NULL) {
153 //
154 // Get image from OEMBadging protocol.
155 //
156 Status = PlatformLogo->GetImage (
157 PlatformLogo,
158 &Instance,
159 &ImageFormat,
160 &ImageData,
161 &ImageSize,
162 &Attribute,
163 &CoordinateX,
164 &CoordinateY
165 );
166 if (EFI_ERROR (Status)) {
167 break;
168 }
169
170 } else {
171 //
172 // Get the specified image from FV.
173 //
174 Status = GetSectionFromAnyFv (Logo, EFI_SECTION_RAW, 0, (VOID **) &ImageData, &ImageSize);
175 if (EFI_ERROR (Status)) {
176 return EFI_UNSUPPORTED;
177 }
178 }
179
180 if (Blt != NULL) {
181 FreePool (Blt);
182 }
183
184 Status = DecodeImage (ImageFormat, ImageData, ImageSize, &Blt, &BltSize, &Width, &Height);
185 FreePool (ImageData);
186 if (EFI_ERROR (Status)) {
187 if (Logo != NULL) {
188 //
189 // Directly return failure for single LOGO
190 //
191 return Status;
192 } else {
193 continue;
194 }
195 }
196
197 //
198 // Calculate the display position according to Attribute.
199 //
200 switch (Attribute) {
201 case EdkiiPlatformLogoDisplayAttributeLeftTop:
202 DestX = CoordinateX;
203 DestY = CoordinateY;
204 break;
205
206 case EdkiiPlatformLogoDisplayAttributeCenterTop:
207 DestX = (SizeOfX - Width) / 2;
208 DestY = CoordinateY;
209 break;
210
211 case EdkiiPlatformLogoDisplayAttributeRightTop:
212 DestX = (SizeOfX - Width - CoordinateX);
213 DestY = CoordinateY;;
214 break;
215
216 case EdkiiPlatformLogoDisplayAttributeCenterRight:
217 DestX = (SizeOfX - Width - CoordinateX);
218 DestY = (SizeOfY - Height) / 2;
219 break;
220
221 case EdkiiPlatformLogoDisplayAttributeRightBottom:
222 DestX = (SizeOfX - Width - CoordinateX);
223 DestY = (SizeOfY - Height - CoordinateY);
224 break;
225
226 case EdkiiPlatformLogoDisplayAttributeCenterBottom:
227 DestX = (SizeOfX - Width) / 2;
228 DestY = (SizeOfY - Height - CoordinateY);
229 break;
230
231 case EdkiiPlatformLogoDisplayAttributeLeftBottom:
232 DestX = CoordinateX;
233 DestY = (SizeOfY - Height - CoordinateY);
234 break;
235
236 case EdkiiPlatformLogoDisplayAttributeCenterLeft:
237 DestX = CoordinateX;
238 DestY = (SizeOfY - Height) / 2;
239 break;
240
241 case EdkiiPlatformLogoDisplayAttributeCenter:
242 DestX = (SizeOfX - Width) / 2;
243 DestY = (SizeOfY - Height) / 2;
244 break;
245
246 default:
247 ASSERT (FALSE);
248 break;
249 }
250
251 if ((DestX >= 0) && (DestY >= 0)) {
252 if (GraphicsOutput != NULL) {
253 Status = GraphicsOutput->Blt (
254 GraphicsOutput,
255 Blt,
256 EfiBltBufferToVideo,
257 0,
258 0,
259 (UINTN) DestX,
260 (UINTN) DestY,
261 Width,
262 Height,
263 Width * sizeof (EFI_GRAPHICS_OUTPUT_BLT_PIXEL)
264 );
265 } else {
266 ASSERT (UgaDraw != NULL);
267 Status = UgaDraw->Blt (
268 UgaDraw,
269 (EFI_UGA_PIXEL *) Blt,
270 EfiUgaBltBufferToVideo,
271 0,
272 0,
273 (UINTN) DestX,
274 (UINTN) DestY,
275 Width,
276 Height,
277 Width * sizeof (EFI_UGA_PIXEL)
278 );
279 }
280
281 //
282 // Report displayed Logo information.
283 //
284 if (!EFI_ERROR (Status)) {
285 NumberOfLogos++;
286
287 if (LogoWidth == 0) {
288 //
289 // The first Logo.
290 //
291 LogoDestX = (UINTN) DestX;
292 LogoDestY = (UINTN) DestY;
293 LogoWidth = Width;
294 LogoHeight = Height;
295 } else {
296 //
297 // Merge new logo with old one.
298 //
299 NewDestX = MIN ((UINTN) DestX, LogoDestX);
300 NewDestY = MIN ((UINTN) DestY, LogoDestY);
301 NewWidth = MAX ((UINTN) DestX + Width, LogoDestX + LogoWidth) - NewDestX;
302 NewHeight = MAX ((UINTN) DestY + Height, LogoDestY + LogoHeight) - NewDestY;
303
304 LogoDestX = NewDestX;
305 LogoDestY = NewDestY;
306 LogoWidth = NewWidth;
307 LogoHeight = NewHeight;
308 }
309 }
310 }
311
312 if (PlatformLogo == NULL) {
313 break;
314 }
315 }
316
317 if (BootLogo == NULL || NumberOfLogos == 0) {
318 //
319 // No logo displayed.
320 //
321 if (Blt != NULL) {
322 FreePool (Blt);
323 }
324
325 return Status;
326 }
327
328 //
329 // Advertise displayed Logo information.
330 //
331 if (NumberOfLogos == 1) {
332 //
333 // Only one logo displayed, use its Blt buffer directly for BootLogo protocol.
334 //
335 LogoBlt = Blt;
336 Status = EFI_SUCCESS;
337 } else {
338 //
339 // More than one Logo displayed, get merged BltBuffer using VideoToBuffer operation.
340 //
341 if (Blt != NULL) {
342 FreePool (Blt);
343 }
344
345 //
346 // Ensure the LogoHeight * LogoWidth * sizeof (EFI_GRAPHICS_OUTPUT_BLT_PIXEL) doesn't overflow
347 //
348 if (LogoHeight > MAX_UINTN / LogoWidth / sizeof (EFI_GRAPHICS_OUTPUT_BLT_PIXEL)) {
349 return EFI_UNSUPPORTED;
350 }
351 BufferSize = LogoWidth * LogoHeight * sizeof (EFI_GRAPHICS_OUTPUT_BLT_PIXEL);
352
353 LogoBlt = AllocatePool (BufferSize);
354 if (LogoBlt == NULL) {
355 return EFI_OUT_OF_RESOURCES;
356 }
357
358 if (GraphicsOutput != NULL) {
359 Status = GraphicsOutput->Blt (
360 GraphicsOutput,
361 LogoBlt,
362 EfiBltVideoToBltBuffer,
363 LogoDestX,
364 LogoDestY,
365 0,
366 0,
367 LogoWidth,
368 LogoHeight,
369 LogoWidth * sizeof (EFI_GRAPHICS_OUTPUT_BLT_PIXEL)
370 );
371 } else {
372 Status = UgaDraw->Blt (
373 UgaDraw,
374 (EFI_UGA_PIXEL *) LogoBlt,
375 EfiUgaVideoToBltBuffer,
376 LogoDestX,
377 LogoDestY,
378 0,
379 0,
380 LogoWidth,
381 LogoHeight,
382 LogoWidth * sizeof (EFI_UGA_PIXEL)
383 );
384 }
385 }
386
387 if (!EFI_ERROR (Status)) {
388 BootLogo->SetBootLogo (BootLogo, LogoBlt, LogoDestX, LogoDestY, LogoWidth, LogoHeight);
389 }
390 FreePool (LogoBlt);
391
392 return Status;
393 }
394
395 /**
396 Use SystemTable Conout to turn on video based Simple Text Out consoles. The
397 Simple Text Out screens will now be synced up with all non video output devices
398
399 @retval EFI_SUCCESS UGA devices are back in text mode and synced up.
400
401 **/
402 EFI_STATUS
403 EFIAPI
404 BootLogoDisableLogo (
405 VOID
406 )
407 {
408
409 //
410 // Enable Cursor on Screen
411 //
412 gST->ConOut->EnableCursor (gST->ConOut, TRUE);
413 return EFI_SUCCESS;
414 }
415
416
417 /**
418
419 Update progress bar with title above it. It only works in Graphics mode.
420
421 @param TitleForeground Foreground color for Title.
422 @param TitleBackground Background color for Title.
423 @param Title Title above progress bar.
424 @param ProgressColor Progress bar color.
425 @param Progress Progress (0-100)
426 @param PreviousValue The previous value of the progress.
427
428 @retval EFI_STATUS Success update the progress bar
429
430 **/
431 EFI_STATUS
432 EFIAPI
433 BootLogoUpdateProgress (
434 IN EFI_GRAPHICS_OUTPUT_BLT_PIXEL TitleForeground,
435 IN EFI_GRAPHICS_OUTPUT_BLT_PIXEL TitleBackground,
436 IN CHAR16 *Title,
437 IN EFI_GRAPHICS_OUTPUT_BLT_PIXEL ProgressColor,
438 IN UINTN Progress,
439 IN UINTN PreviousValue
440 )
441 {
442 EFI_STATUS Status;
443 EFI_GRAPHICS_OUTPUT_PROTOCOL *GraphicsOutput;
444 EFI_UGA_DRAW_PROTOCOL *UgaDraw;
445 UINT32 SizeOfX;
446 UINT32 SizeOfY;
447 UINT32 ColorDepth;
448 UINT32 RefreshRate;
449 EFI_GRAPHICS_OUTPUT_BLT_PIXEL Color;
450 UINTN BlockHeight;
451 UINTN BlockWidth;
452 UINTN BlockNum;
453 UINTN PosX;
454 UINTN PosY;
455 UINTN Index;
456
457 if (Progress > 100) {
458 return EFI_INVALID_PARAMETER;
459 }
460
461 UgaDraw = NULL;
462 Status = gBS->HandleProtocol (gST->ConsoleOutHandle, &gEfiGraphicsOutputProtocolGuid, (VOID **) &GraphicsOutput);
463 if (EFI_ERROR (Status) && FeaturePcdGet (PcdUgaConsumeSupport)) {
464 GraphicsOutput = NULL;
465
466 Status = gBS->HandleProtocol (gST->ConsoleOutHandle, &gEfiUgaDrawProtocolGuid, (VOID **) &UgaDraw);
467 if (EFI_ERROR (Status)) {
468 UgaDraw = NULL;
469 }
470 }
471 if (EFI_ERROR (Status)) {
472 return EFI_UNSUPPORTED;
473 }
474
475 SizeOfX = 0;
476 SizeOfY = 0;
477 if (GraphicsOutput != NULL) {
478 SizeOfX = GraphicsOutput->Mode->Info->HorizontalResolution;
479 SizeOfY = GraphicsOutput->Mode->Info->VerticalResolution;
480 } else if (UgaDraw != NULL) {
481 Status = UgaDraw->GetMode (
482 UgaDraw,
483 &SizeOfX,
484 &SizeOfY,
485 &ColorDepth,
486 &RefreshRate
487 );
488 if (EFI_ERROR (Status)) {
489 return EFI_UNSUPPORTED;
490 }
491 } else {
492 return EFI_UNSUPPORTED;
493 }
494
495 BlockWidth = SizeOfX / 100;
496 BlockHeight = SizeOfY / 50;
497
498 BlockNum = Progress;
499
500 PosX = 0;
501 PosY = SizeOfY * 48 / 50;
502
503 if (BlockNum == 0) {
504 //
505 // Clear progress area
506 //
507 SetMem (&Color, sizeof (EFI_GRAPHICS_OUTPUT_BLT_PIXEL), 0x0);
508
509 if (GraphicsOutput != NULL) {
510 Status = GraphicsOutput->Blt (
511 GraphicsOutput,
512 &Color,
513 EfiBltVideoFill,
514 0,
515 0,
516 0,
517 PosY - EFI_GLYPH_HEIGHT - 1,
518 SizeOfX,
519 SizeOfY - (PosY - EFI_GLYPH_HEIGHT - 1),
520 SizeOfX * sizeof (EFI_GRAPHICS_OUTPUT_BLT_PIXEL)
521 );
522 } else if (FeaturePcdGet (PcdUgaConsumeSupport)) {
523 Status = UgaDraw->Blt (
524 UgaDraw,
525 (EFI_UGA_PIXEL *) &Color,
526 EfiUgaVideoFill,
527 0,
528 0,
529 0,
530 PosY - EFI_GLYPH_HEIGHT - 1,
531 SizeOfX,
532 SizeOfY - (PosY - EFI_GLYPH_HEIGHT - 1),
533 SizeOfX * sizeof (EFI_UGA_PIXEL)
534 );
535 } else {
536 return EFI_UNSUPPORTED;
537 }
538 }
539 //
540 // Show progress by drawing blocks
541 //
542 for (Index = PreviousValue; Index < BlockNum; Index++) {
543 PosX = Index * BlockWidth;
544 if (GraphicsOutput != NULL) {
545 Status = GraphicsOutput->Blt (
546 GraphicsOutput,
547 &ProgressColor,
548 EfiBltVideoFill,
549 0,
550 0,
551 PosX,
552 PosY,
553 BlockWidth - 1,
554 BlockHeight,
555 (BlockWidth) * sizeof (EFI_GRAPHICS_OUTPUT_BLT_PIXEL)
556 );
557 } else if (FeaturePcdGet (PcdUgaConsumeSupport)) {
558 Status = UgaDraw->Blt (
559 UgaDraw,
560 (EFI_UGA_PIXEL *) &ProgressColor,
561 EfiUgaVideoFill,
562 0,
563 0,
564 PosX,
565 PosY,
566 BlockWidth - 1,
567 BlockHeight,
568 (BlockWidth) * sizeof (EFI_UGA_PIXEL)
569 );
570 } else {
571 return EFI_UNSUPPORTED;
572 }
573 }
574
575 PrintXY (
576 (SizeOfX - StrLen (Title) * EFI_GLYPH_WIDTH) / 2,
577 PosY - EFI_GLYPH_HEIGHT - 1,
578 &TitleForeground,
579 &TitleBackground,
580 Title
581 );
582
583 return EFI_SUCCESS;
584 }