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