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