--- /dev/null
+/** @file\r
+ This library is only intended to be used by PlatformBootManagerLib\r
+ to show progress bar and LOGO.\r
+\r
+Copyright (c) 2011 - 2015, Intel Corporation. All rights reserved.<BR>\r
+This program and the accompanying materials are licensed and made available under\r
+the terms and conditions of the BSD License that accompanies this distribution.\r
+The full text of the license may be found at\r
+http://opensource.org/licenses/bsd-license.php.\r
+\r
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+\r
+**/\r
+\r
+#include <PiDxe.h>\r
+#include <Protocol/SimpleTextOut.h>\r
+#include <Protocol/PlatformLogo.h>\r
+#include <Protocol/GraphicsOutput.h>\r
+#include <Protocol/UgaDraw.h>\r
+#include <Protocol/BootLogo.h>\r
+#include <Library/BaseLib.h>\r
+#include <Library/UefiLib.h>\r
+#include <Library/BaseMemoryLib.h>\r
+#include <Library/UefiBootServicesTableLib.h>\r
+#include <Library/DxeServicesLib.h>\r
+#include <Library/PcdLib.h>\r
+#include <Library/MemoryAllocationLib.h>\r
+#include <Library/DebugLib.h>\r
+#include <Library/ImageDecoderLib.h>\r
+\r
+/**\r
+ Show LOGO on all consoles.\r
+\r
+ @param[in] ImageFormat Format of the image file.\r
+ @param[in] LogoFile The file name of logo to display.\r
+ @param[in] Attribute The display attributes of the image returned.\r
+ @param[in] CoordinateX The X coordinate of the image.\r
+ @param[in] CoordinateY The Y coordinate of the image.\r
+\r
+ @retval EFI_SUCCESS Logo was displayed.\r
+ @retval EFI_UNSUPPORTED Logo was not found or cannot be displayed.\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+BootLogoEnableLogo (\r
+ IN IMAGE_FORMAT ImageFormat,\r
+ IN EFI_GUID *Logo,\r
+ IN EDKII_PLATFORM_LOGO_DISPLAY_ATTRIBUTE Attribute,\r
+ IN UINTN CoordinateX,\r
+ IN UINTN CoordinateY\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ EDKII_PLATFORM_LOGO_PROTOCOL *PlatformLogo;\r
+ UINT32 SizeOfX;\r
+ UINT32 SizeOfY;\r
+ INTN DestX;\r
+ INTN DestY;\r
+ UINT8 *ImageData;\r
+ UINTN ImageSize;\r
+ UINTN BltSize;\r
+ UINT32 Instance;\r
+ UINTN Height;\r
+ UINTN Width;\r
+ EFI_GRAPHICS_OUTPUT_BLT_PIXEL *Blt;\r
+ EFI_UGA_DRAW_PROTOCOL *UgaDraw;\r
+ UINT32 ColorDepth;\r
+ UINT32 RefreshRate;\r
+ EFI_GRAPHICS_OUTPUT_PROTOCOL *GraphicsOutput;\r
+ EFI_BOOT_LOGO_PROTOCOL *BootLogo;\r
+ UINTN NumberOfLogos;\r
+ EFI_GRAPHICS_OUTPUT_BLT_PIXEL *LogoBlt;\r
+ UINTN LogoDestX;\r
+ UINTN LogoDestY;\r
+ UINTN LogoHeight;\r
+ UINTN LogoWidth;\r
+ UINTN NewDestX;\r
+ UINTN NewDestY;\r
+ UINTN NewHeight;\r
+ UINTN NewWidth;\r
+ UINTN BufferSize;\r
+\r
+ UgaDraw = NULL;\r
+ //\r
+ // Try to open GOP first\r
+ //\r
+ Status = gBS->HandleProtocol (gST->ConsoleOutHandle, &gEfiGraphicsOutputProtocolGuid, (VOID **) &GraphicsOutput);\r
+ if (EFI_ERROR (Status) && FeaturePcdGet (PcdUgaConsumeSupport)) {\r
+ GraphicsOutput = NULL;\r
+ //\r
+ // Open GOP failed, try to open UGA\r
+ //\r
+ Status = gBS->HandleProtocol (gST->ConsoleOutHandle, &gEfiUgaDrawProtocolGuid, (VOID **) &UgaDraw);\r
+ if (EFI_ERROR (Status)) {\r
+ UgaDraw = NULL;\r
+ }\r
+ }\r
+ if (EFI_ERROR (Status)) {\r
+ return EFI_UNSUPPORTED;\r
+ }\r
+\r
+ Status = gBS->LocateProtocol (&gEdkiiPlatformLogoProtocolGuid, NULL, (VOID **) &PlatformLogo);\r
+ if (EFI_ERROR (Status)) {\r
+ PlatformLogo = NULL;\r
+ }\r
+\r
+ if ((Logo == NULL) && (PlatformLogo == NULL)) {\r
+ return EFI_UNSUPPORTED;\r
+ }\r
+\r
+ //\r
+ // Try to open Boot Logo Protocol.\r
+ //\r
+ Status = gBS->LocateProtocol (&gEfiBootLogoProtocolGuid, NULL, (VOID **) &BootLogo);\r
+ if (EFI_ERROR (Status)) {\r
+ BootLogo = NULL;\r
+ }\r
+\r
+ //\r
+ // Erase Cursor from screen\r
+ //\r
+ gST->ConOut->EnableCursor (gST->ConOut, FALSE);\r
+\r
+ if (GraphicsOutput != NULL) {\r
+ SizeOfX = GraphicsOutput->Mode->Info->HorizontalResolution;\r
+ SizeOfY = GraphicsOutput->Mode->Info->VerticalResolution;\r
+\r
+ } else {\r
+ ASSERT (UgaDraw != NULL);\r
+ Status = UgaDraw->GetMode (UgaDraw, &SizeOfX, &SizeOfY, &ColorDepth, &RefreshRate);\r
+ if (EFI_ERROR (Status)) {\r
+ return EFI_UNSUPPORTED;\r
+ }\r
+ }\r
+\r
+ Blt = NULL;\r
+ NumberOfLogos = 0;\r
+ LogoDestX = 0;\r
+ LogoDestY = 0;\r
+ LogoHeight = 0;\r
+ LogoWidth = 0;\r
+ NewDestX = 0;\r
+ NewDestY = 0;\r
+ NewHeight = 0;\r
+ NewWidth = 0;\r
+ Instance = 0;\r
+ while (TRUE) {\r
+ ImageData = NULL;\r
+ ImageSize = 0;\r
+\r
+ if (PlatformLogo != NULL) {\r
+ //\r
+ // Get image from OEMBadging protocol.\r
+ //\r
+ Status = PlatformLogo->GetImage (\r
+ PlatformLogo,\r
+ &Instance,\r
+ &ImageFormat,\r
+ &ImageData,\r
+ &ImageSize,\r
+ &Attribute,\r
+ &CoordinateX,\r
+ &CoordinateY\r
+ );\r
+ if (EFI_ERROR (Status)) {\r
+ break;\r
+ }\r
+\r
+ } else {\r
+ //\r
+ // Get the specified image from FV.\r
+ //\r
+ Status = GetSectionFromAnyFv (Logo, EFI_SECTION_RAW, 0, (VOID **) &ImageData, &ImageSize);\r
+ if (EFI_ERROR (Status)) {\r
+ return EFI_UNSUPPORTED;\r
+ }\r
+ }\r
+\r
+ if (Blt != NULL) {\r
+ FreePool (Blt);\r
+ }\r
+\r
+ Status = DecodeImage (ImageFormat, ImageData, ImageSize, &Blt, &BltSize, &Width, &Height);\r
+ FreePool (ImageData);\r
+ if (EFI_ERROR (Status)) {\r
+ if (Logo != NULL) {\r
+ //\r
+ // Directly return failure for single LOGO\r
+ //\r
+ return Status;\r
+ } else {\r
+ continue;\r
+ }\r
+ }\r
+\r
+ //\r
+ // Calculate the display position according to Attribute.\r
+ //\r
+ switch (Attribute) {\r
+ case EdkiiPlatformLogoDisplayAttributeLeftTop:\r
+ DestX = CoordinateX;\r
+ DestY = CoordinateY;\r
+ break;\r
+\r
+ case EdkiiPlatformLogoDisplayAttributeCenterTop:\r
+ DestX = (SizeOfX - Width) / 2;\r
+ DestY = CoordinateY;\r
+ break;\r
+\r
+ case EdkiiPlatformLogoDisplayAttributeRightTop:\r
+ DestX = (SizeOfX - Width - CoordinateX);\r
+ DestY = CoordinateY;;\r
+ break;\r
+\r
+ case EdkiiPlatformLogoDisplayAttributeCenterRight:\r
+ DestX = (SizeOfX - Width - CoordinateX);\r
+ DestY = (SizeOfY - Height) / 2;\r
+ break;\r
+\r
+ case EdkiiPlatformLogoDisplayAttributeRightBottom:\r
+ DestX = (SizeOfX - Width - CoordinateX);\r
+ DestY = (SizeOfY - Height - CoordinateY);\r
+ break;\r
+\r
+ case EdkiiPlatformLogoDisplayAttributeCenterBottom:\r
+ DestX = (SizeOfX - Width) / 2;\r
+ DestY = (SizeOfY - Height - CoordinateY);\r
+ break;\r
+\r
+ case EdkiiPlatformLogoDisplayAttributeLeftBottom:\r
+ DestX = CoordinateX;\r
+ DestY = (SizeOfY - Height - CoordinateY);\r
+ break;\r
+\r
+ case EdkiiPlatformLogoDisplayAttributeCenterLeft:\r
+ DestX = CoordinateX;\r
+ DestY = (SizeOfY - Height) / 2;\r
+ break;\r
+\r
+ case EdkiiPlatformLogoDisplayAttributeCenter:\r
+ DestX = (SizeOfX - Width) / 2;\r
+ DestY = (SizeOfY - Height) / 2;\r
+ break;\r
+\r
+ default:\r
+ ASSERT (FALSE);\r
+ break;\r
+ }\r
+\r
+ if ((DestX >= 0) && (DestY >= 0)) {\r
+ if (GraphicsOutput != NULL) {\r
+ Status = GraphicsOutput->Blt (\r
+ GraphicsOutput,\r
+ Blt,\r
+ EfiBltBufferToVideo,\r
+ 0,\r
+ 0,\r
+ (UINTN) DestX,\r
+ (UINTN) DestY,\r
+ Width,\r
+ Height,\r
+ Width * sizeof (EFI_GRAPHICS_OUTPUT_BLT_PIXEL)\r
+ );\r
+ } else {\r
+ ASSERT (UgaDraw != NULL);\r
+ Status = UgaDraw->Blt (\r
+ UgaDraw,\r
+ (EFI_UGA_PIXEL *) Blt,\r
+ EfiUgaBltBufferToVideo,\r
+ 0,\r
+ 0,\r
+ (UINTN) DestX,\r
+ (UINTN) DestY,\r
+ Width,\r
+ Height,\r
+ Width * sizeof (EFI_UGA_PIXEL)\r
+ );\r
+ }\r
+\r
+ //\r
+ // Report displayed Logo information.\r
+ //\r
+ if (!EFI_ERROR (Status)) {\r
+ NumberOfLogos++;\r
+\r
+ if (LogoWidth == 0) {\r
+ //\r
+ // The first Logo.\r
+ //\r
+ LogoDestX = (UINTN) DestX;\r
+ LogoDestY = (UINTN) DestY;\r
+ LogoWidth = Width;\r
+ LogoHeight = Height;\r
+ } else {\r
+ //\r
+ // Merge new logo with old one.\r
+ //\r
+ NewDestX = MIN ((UINTN) DestX, LogoDestX);\r
+ NewDestY = MIN ((UINTN) DestY, LogoDestY);\r
+ NewWidth = MAX ((UINTN) DestX + Width, LogoDestX + LogoWidth) - NewDestX;\r
+ NewHeight = MAX ((UINTN) DestY + Height, LogoDestY + LogoHeight) - NewDestY;\r
+\r
+ LogoDestX = NewDestX;\r
+ LogoDestY = NewDestY;\r
+ LogoWidth = NewWidth;\r
+ LogoHeight = NewHeight;\r
+ }\r
+ }\r
+ }\r
+\r
+ if (PlatformLogo == NULL) {\r
+ break;\r
+ }\r
+ }\r
+\r
+ if (BootLogo == NULL || NumberOfLogos == 0) {\r
+ //\r
+ // No logo displayed.\r
+ //\r
+ if (Blt != NULL) {\r
+ FreePool (Blt);\r
+ }\r
+\r
+ return Status;\r
+ }\r
+\r
+ //\r
+ // Advertise displayed Logo information.\r
+ //\r
+ if (NumberOfLogos == 1) {\r
+ //\r
+ // Only one logo displayed, use its Blt buffer directly for BootLogo protocol.\r
+ //\r
+ LogoBlt = Blt;\r
+ Status = EFI_SUCCESS;\r
+ } else {\r
+ //\r
+ // More than one Logo displayed, get merged BltBuffer using VideoToBuffer operation. \r
+ //\r
+ if (Blt != NULL) {\r
+ FreePool (Blt);\r
+ }\r
+\r
+ //\r
+ // Ensure the LogoHeight * LogoWidth * sizeof (EFI_GRAPHICS_OUTPUT_BLT_PIXEL) doesn't overflow\r
+ //\r
+ if (LogoHeight > MAX_UINTN / LogoWidth / sizeof (EFI_GRAPHICS_OUTPUT_BLT_PIXEL)) {\r
+ return EFI_UNSUPPORTED;\r
+ }\r
+ BufferSize = LogoWidth * LogoHeight * sizeof (EFI_GRAPHICS_OUTPUT_BLT_PIXEL);\r
+\r
+ LogoBlt = AllocatePool (BufferSize);\r
+ if (LogoBlt == NULL) {\r
+ return EFI_OUT_OF_RESOURCES;\r
+ }\r
+\r
+ if (GraphicsOutput != NULL) {\r
+ Status = GraphicsOutput->Blt (\r
+ GraphicsOutput,\r
+ LogoBlt,\r
+ EfiBltVideoToBltBuffer,\r
+ LogoDestX,\r
+ LogoDestY,\r
+ 0,\r
+ 0,\r
+ LogoWidth,\r
+ LogoHeight,\r
+ LogoWidth * sizeof (EFI_GRAPHICS_OUTPUT_BLT_PIXEL)\r
+ );\r
+ } else {\r
+ Status = UgaDraw->Blt (\r
+ UgaDraw,\r
+ (EFI_UGA_PIXEL *) LogoBlt,\r
+ EfiUgaVideoToBltBuffer,\r
+ LogoDestX,\r
+ LogoDestY,\r
+ 0,\r
+ 0,\r
+ LogoWidth,\r
+ LogoHeight,\r
+ LogoWidth * sizeof (EFI_UGA_PIXEL)\r
+ );\r
+ }\r
+ }\r
+\r
+ if (!EFI_ERROR (Status)) {\r
+ BootLogo->SetBootLogo (BootLogo, LogoBlt, LogoDestX, LogoDestY, LogoWidth, LogoHeight);\r
+ }\r
+ FreePool (LogoBlt);\r
+\r
+ return Status;\r
+}\r
+\r
+/**\r
+ Use SystemTable Conout to turn on video based Simple Text Out consoles. The \r
+ Simple Text Out screens will now be synced up with all non video output devices\r
+\r
+ @retval EFI_SUCCESS UGA devices are back in text mode and synced up.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+BootLogoDisableLogo (\r
+ VOID\r
+ )\r
+{\r
+\r
+ //\r
+ // Enable Cursor on Screen\r
+ //\r
+ gST->ConOut->EnableCursor (gST->ConOut, TRUE);\r
+ return EFI_SUCCESS;\r
+}\r
+\r
+\r
+/**\r
+\r
+ Update progress bar with title above it. It only works in Graphics mode.\r
+\r
+ @param TitleForeground Foreground color for Title.\r
+ @param TitleBackground Background color for Title.\r
+ @param Title Title above progress bar.\r
+ @param ProgressColor Progress bar color.\r
+ @param Progress Progress (0-100)\r
+ @param PreviousValue The previous value of the progress.\r
+\r
+ @retval EFI_STATUS Success update the progress bar\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+BootLogoUpdateProgress (\r
+ IN EFI_GRAPHICS_OUTPUT_BLT_PIXEL TitleForeground,\r
+ IN EFI_GRAPHICS_OUTPUT_BLT_PIXEL TitleBackground,\r
+ IN CHAR16 *Title,\r
+ IN EFI_GRAPHICS_OUTPUT_BLT_PIXEL ProgressColor,\r
+ IN UINTN Progress,\r
+ IN UINTN PreviousValue\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ EFI_GRAPHICS_OUTPUT_PROTOCOL *GraphicsOutput;\r
+ EFI_UGA_DRAW_PROTOCOL *UgaDraw;\r
+ UINT32 SizeOfX;\r
+ UINT32 SizeOfY;\r
+ UINT32 ColorDepth;\r
+ UINT32 RefreshRate;\r
+ EFI_GRAPHICS_OUTPUT_BLT_PIXEL Color;\r
+ UINTN BlockHeight;\r
+ UINTN BlockWidth;\r
+ UINTN BlockNum;\r
+ UINTN PosX;\r
+ UINTN PosY;\r
+ UINTN Index;\r
+\r
+ if (Progress > 100) {\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+\r
+ UgaDraw = NULL;\r
+ Status = gBS->HandleProtocol (gST->ConsoleOutHandle, &gEfiGraphicsOutputProtocolGuid, (VOID **) &GraphicsOutput);\r
+ if (EFI_ERROR (Status) && FeaturePcdGet (PcdUgaConsumeSupport)) {\r
+ GraphicsOutput = NULL;\r
+\r
+ Status = gBS->HandleProtocol (gST->ConsoleOutHandle, &gEfiUgaDrawProtocolGuid, (VOID **) &UgaDraw);\r
+ if (EFI_ERROR (Status)) {\r
+ UgaDraw = NULL;\r
+ }\r
+ }\r
+ if (EFI_ERROR (Status)) {\r
+ return EFI_UNSUPPORTED;\r
+ }\r
+\r
+ SizeOfX = 0;\r
+ SizeOfY = 0;\r
+ if (GraphicsOutput != NULL) {\r
+ SizeOfX = GraphicsOutput->Mode->Info->HorizontalResolution;\r
+ SizeOfY = GraphicsOutput->Mode->Info->VerticalResolution;\r
+ } else if (UgaDraw != NULL) {\r
+ Status = UgaDraw->GetMode (\r
+ UgaDraw,\r
+ &SizeOfX,\r
+ &SizeOfY,\r
+ &ColorDepth,\r
+ &RefreshRate\r
+ );\r
+ if (EFI_ERROR (Status)) {\r
+ return EFI_UNSUPPORTED;\r
+ }\r
+ } else {\r
+ return EFI_UNSUPPORTED;\r
+ }\r
+\r
+ BlockWidth = SizeOfX / 100;\r
+ BlockHeight = SizeOfY / 50;\r
+\r
+ BlockNum = Progress;\r
+\r
+ PosX = 0;\r
+ PosY = SizeOfY * 48 / 50;\r
+\r
+ if (BlockNum == 0) {\r
+ //\r
+ // Clear progress area\r
+ //\r
+ SetMem (&Color, sizeof (EFI_GRAPHICS_OUTPUT_BLT_PIXEL), 0x0);\r
+\r
+ if (GraphicsOutput != NULL) {\r
+ Status = GraphicsOutput->Blt (\r
+ GraphicsOutput,\r
+ &Color,\r
+ EfiBltVideoFill,\r
+ 0,\r
+ 0,\r
+ 0,\r
+ PosY - EFI_GLYPH_HEIGHT - 1,\r
+ SizeOfX,\r
+ SizeOfY - (PosY - EFI_GLYPH_HEIGHT - 1),\r
+ SizeOfX * sizeof (EFI_GRAPHICS_OUTPUT_BLT_PIXEL)\r
+ );\r
+ } else if (FeaturePcdGet (PcdUgaConsumeSupport)) {\r
+ Status = UgaDraw->Blt (\r
+ UgaDraw,\r
+ (EFI_UGA_PIXEL *) &Color,\r
+ EfiUgaVideoFill,\r
+ 0,\r
+ 0,\r
+ 0,\r
+ PosY - EFI_GLYPH_HEIGHT - 1,\r
+ SizeOfX,\r
+ SizeOfY - (PosY - EFI_GLYPH_HEIGHT - 1),\r
+ SizeOfX * sizeof (EFI_UGA_PIXEL)\r
+ );\r
+ } else {\r
+ return EFI_UNSUPPORTED;\r
+ }\r
+ }\r
+ //\r
+ // Show progress by drawing blocks\r
+ //\r
+ for (Index = PreviousValue; Index < BlockNum; Index++) {\r
+ PosX = Index * BlockWidth;\r
+ if (GraphicsOutput != NULL) {\r
+ Status = GraphicsOutput->Blt (\r
+ GraphicsOutput,\r
+ &ProgressColor,\r
+ EfiBltVideoFill,\r
+ 0,\r
+ 0,\r
+ PosX,\r
+ PosY,\r
+ BlockWidth - 1,\r
+ BlockHeight,\r
+ (BlockWidth) * sizeof (EFI_GRAPHICS_OUTPUT_BLT_PIXEL)\r
+ );\r
+ } else if (FeaturePcdGet (PcdUgaConsumeSupport)) {\r
+ Status = UgaDraw->Blt (\r
+ UgaDraw,\r
+ (EFI_UGA_PIXEL *) &ProgressColor,\r
+ EfiUgaVideoFill,\r
+ 0,\r
+ 0,\r
+ PosX,\r
+ PosY,\r
+ BlockWidth - 1,\r
+ BlockHeight,\r
+ (BlockWidth) * sizeof (EFI_UGA_PIXEL)\r
+ );\r
+ } else {\r
+ return EFI_UNSUPPORTED;\r
+ }\r
+ }\r
+\r
+ PrintXY (\r
+ (SizeOfX - StrLen (Title) * EFI_GLYPH_WIDTH) / 2,\r
+ PosY - EFI_GLYPH_HEIGHT - 1,\r
+ &TitleForeground,\r
+ &TitleBackground,\r
+ Title\r
+ );\r
+\r
+ return EFI_SUCCESS;\r
+}\r