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