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