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