]> git.proxmox.com Git - mirror_edk2.git/blame_incremental - MdeModulePkg/Library/BootLogoLib/BootLogoLib.c
MdeModulePkg: Replace BSD License with BSD+Patent License
[mirror_edk2.git] / MdeModulePkg / Library / BootLogoLib / BootLogoLib.c
... / ...
CommitLineData
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
5Copyright (c) 2011 - 2018, Intel Corporation. All rights reserved.<BR>\r
6Copyright (c) 2016, Microsoft Corporation<BR>\r
7SPDX-License-Identifier: BSD-2-Clause-Patent\r
8\r
9**/\r
10\r
11#include <Uefi.h>\r
12#include <Protocol/GraphicsOutput.h>\r
13#include <Protocol/SimpleTextOut.h>\r
14#include <Protocol/PlatformLogo.h>\r
15#include <Protocol/UgaDraw.h>\r
16#include <Protocol/BootLogo.h>\r
17#include <Protocol/BootLogo2.h>\r
18#include <Library/BaseLib.h>\r
19#include <Library/UefiLib.h>\r
20#include <Library/BaseMemoryLib.h>\r
21#include <Library/UefiBootServicesTableLib.h>\r
22#include <Library/PcdLib.h>\r
23#include <Library/MemoryAllocationLib.h>\r
24#include <Library/DebugLib.h>\r
25\r
26/**\r
27 Show LOGO returned from Edkii Platform Logo protocol on all consoles.\r
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
35 VOID\r
36 )\r
37{\r
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
55 EDKII_BOOT_LOGO2_PROTOCOL *BootLogo2;\r
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
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
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
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
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
131 Instance = 0;\r
132 DestX = 0;\r
133 DestY = 0;\r
134 while (TRUE) {\r
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
149\r
150 if (Blt != NULL) {\r
151 FreePool (Blt);\r
152 }\r
153 Blt = Image.Bitmap;\r
154\r
155 //\r
156 // Calculate the display position according to Attribute.\r
157 //\r
158 switch (Attribute) {\r
159 case EdkiiPlatformLogoDisplayAttributeLeftTop:\r
160 DestX = 0;\r
161 DestY = 0;\r
162 break;\r
163 case EdkiiPlatformLogoDisplayAttributeCenterTop:\r
164 DestX = (SizeOfX - Image.Width) / 2;\r
165 DestY = 0;\r
166 break;\r
167 case EdkiiPlatformLogoDisplayAttributeRightTop:\r
168 DestX = SizeOfX - Image.Width;\r
169 DestY = 0;\r
170 break;\r
171\r
172 case EdkiiPlatformLogoDisplayAttributeCenterLeft:\r
173 DestX = 0;\r
174 DestY = (SizeOfY - Image.Height) / 2;\r
175 break;\r
176 case EdkiiPlatformLogoDisplayAttributeCenter:\r
177 DestX = (SizeOfX - Image.Width) / 2;\r
178 DestY = (SizeOfY - Image.Height) / 2;\r
179 break;\r
180 case EdkiiPlatformLogoDisplayAttributeCenterRight:\r
181 DestX = SizeOfX - Image.Width;\r
182 DestY = (SizeOfY - Image.Height) / 2;\r
183 break;\r
184\r
185 case EdkiiPlatformLogoDisplayAttributeLeftBottom:\r
186 DestX = 0;\r
187 DestY = SizeOfY - Image.Height;\r
188 break;\r
189 case EdkiiPlatformLogoDisplayAttributeCenterBottom:\r
190 DestX = (SizeOfX - Image.Width) / 2;\r
191 DestY = SizeOfY - Image.Height;\r
192 break;\r
193 case EdkiiPlatformLogoDisplayAttributeRightBottom:\r
194 DestX = SizeOfX - Image.Width;\r
195 DestY = SizeOfY - Image.Height;\r
196 break;\r
197\r
198 default:\r
199 ASSERT (FALSE);\r
200 continue;\r
201 break;\r
202 }\r
203\r
204 DestX += OffsetX;\r
205 DestY += OffsetY;\r
206\r
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
217 Image.Width,\r
218 Image.Height,\r
219 Image.Width * sizeof (EFI_GRAPHICS_OUTPUT_BLT_PIXEL)\r
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
231 Image.Width,\r
232 Image.Height,\r
233 Image.Width * sizeof (EFI_UGA_PIXEL)\r
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
243 if (NumberOfLogos == 1) {\r
244 //\r
245 // The first Logo.\r
246 //\r
247 LogoDestX = (UINTN) DestX;\r
248 LogoDestY = (UINTN) DestY;\r
249 LogoWidth = Image.Width;\r
250 LogoHeight = Image.Height;\r
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
257 LogoWidth = MAX ((UINTN) DestX + Image.Width, LogoDestX + LogoWidth) - NewDestX;\r
258 LogoHeight = MAX ((UINTN) DestY + Image.Height, LogoDestY + LogoHeight) - NewDestY;\r
259\r
260 LogoDestX = NewDestX;\r
261 LogoDestY = NewDestY;\r
262 }\r
263 }\r
264 }\r
265 }\r
266\r
267 if ((BootLogo == NULL && BootLogo2 == NULL) || NumberOfLogos == 0) {\r
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
289 // More than one Logo displayed, get merged BltBuffer using VideoToBuffer operation.\r
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
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
356 }\r
357 FreePool (LogoBlt);\r
358\r
359 return Status;\r
360}\r
361\r
362/**\r
363 Use SystemTable Conout to turn on video based Simple Text Out consoles. The\r
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