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