/** @file ;****************************************************************************** ;* Copyright (c) 2012 - 2020, Insyde Software Corp. All Rights Reserved. ;* ;* You may not reproduce, distribute, publish, display, perform, modify, adapt, ;* transmit, broadcast, present, recite, release, license or otherwise exploit ;* any part of this publication in any form, by any means, without the prior ;* written permission of Insyde Software Corporation. ;* ;****************************************************************************** */ /** This module install ACPI Boot Graphics Resource Table (BGRT). Copyright (c) 2014, Intel Corporation. All rights reserved.
This program and the accompanying materials are licensed and made available under the terms and conditions of the BSD License which accompanies this distribution. The full text of the license may be found at http://opensource.org/licenses/bsd-license.php THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. **/ #include #include #include // // ACPI table information used to initialize tables. // #define EFI_ACPI_OEM_ID 'I','N','S','Y','D','E' #define EFI_ACPI_OEM_TABLE_ID SIGNATURE_64('H','2','O',' ','B','I','O','S') #define EFI_ACPI_OEM_REVISION 0x00000001 #define EFI_ACPI_CREATOR_ID SIGNATURE_32('A','C','P','I') #define EFI_ACPI_CREATOR_REVISION 0x00040000 // // Module globals. // EFI_EVENT mBootGraphicsReadyToBootEvent; EFI_EVENT mBootGraphicsLegacyBootEvent; UINTN mBootGraphicsResourceTableKey = 0; EFI_HANDLE mBootLogoHandle = NULL; BOOLEAN mIsLogoValid = FALSE; BOOLEAN mIsMonitor = FALSE; EFI_GRAPHICS_OUTPUT_BLT_PIXEL *mLogoBltBuffer = NULL; UINTN mLogoDestX = 0; UINTN mLogoDestY = 0; UINTN mLogoWidth = 0; UINTN mLogoHeight = 0; BMP_IMAGE_HEADER mBmpImageHeaderTemplate = { 'B', // CharB 'M', // CharM 0, // Size will be updated at runtime {0, 0}, // Reserved sizeof (BMP_IMAGE_HEADER), // ImageOffset sizeof (BMP_IMAGE_HEADER) - OFFSET_OF (BMP_IMAGE_HEADER, HeaderSize), // HeaderSize 0, // PixelWidth will be updated at runtime 0, // PixelHeight will be updated at runtime 1, // Planes 24, // BitPerPixel 0, // CompressionType 0, // ImageSize will be updated at runtime 0, // XPixelsPerMeter 0, // YPixelsPerMeter 0, // NumberOfColors 0 // ImportantColors }; BOOLEAN mAcpiBgrtInstalled = FALSE; EFI_ACPI_5_0_BOOT_GRAPHICS_RESOURCE_TABLE mBootGraphicsResourceTableTemplate = { { EFI_ACPI_5_0_BOOT_GRAPHICS_RESOURCE_TABLE_SIGNATURE, sizeof (EFI_ACPI_5_0_BOOT_GRAPHICS_RESOURCE_TABLE), EFI_ACPI_5_0_BOOT_GRAPHICS_RESOURCE_TABLE_REVISION, // Revision 0x00, // Checksum will be updated at runtime // // It is expected that these values will be updated at runtime. // EFI_ACPI_OEM_ID, // OEMID is a 6 bytes long field EFI_ACPI_OEM_TABLE_ID, // OEM table identification(8 bytes long) EFI_ACPI_OEM_REVISION, // OEM revision number EFI_ACPI_CREATOR_ID, // ASL compiler vendor ID EFI_ACPI_CREATOR_REVISION, // ASL compiler revision number }, EFI_ACPI_5_0_BGRT_VERSION, // Version EFI_ACPI_5_0_BGRT_STATUS_VALID, // Status EFI_ACPI_5_0_BGRT_IMAGE_TYPE_BMP, // Image Type 0, // Image Address 0, // Image Offset X 0 // Image Offset Y }; HOOKED_GOP_BLT_SET_MODE *mGopHookedList = NULL; UINTN mNumberofGops = 0; UINT32 mLogoResolutionX = 0; UINT32 mLogoResolutionY = 0; BOOLEAN mIsUpdateCoordinate = FALSE; UINTN mCurNoGopDrvBinding = 0; HOOKED_GOP_DRV_BINDING *mGopBindingHookedList = NULL; /** Update information of logo image drawn on screen. @param This The pointer to the Boot Logo protocol instance. @param BltBuffer The BLT buffer for logo drawn on screen. If BltBuffer is set to NULL, it indicates that logo image is no longer on the screen. @param DestinationX X coordinate of destination for the BltBuffer. @param DestinationY Y coordinate of destination for the BltBuffer. @param Width Width of rectangle in BltBuffer in pixels. @param Height Hight of rectangle in BltBuffer in pixels. @retval EFI_SUCCESS The boot logo information was updated. @retval EFI_INVALID_PARAMETER One of the parameters has an invalid value. @retval EFI_OUT_OF_RESOURCES The logo information was not updated due to insufficient memory resources. **/ EFI_STATUS EFIAPI SetBootLogo ( IN EFI_BOOT_LOGO_PROTOCOL *This, IN EFI_GRAPHICS_OUTPUT_BLT_PIXEL *BltBuffer OPTIONAL, IN UINTN DestinationX, IN UINTN DestinationY, IN UINTN Width, IN UINTN Height ); EFI_STATUS EFIAPI DummyBlt ( IN EFI_GRAPHICS_OUTPUT_PROTOCOL * This, IN EFI_GRAPHICS_OUTPUT_BLT_PIXEL * BltBuffer, OPTIONAL IN EFI_GRAPHICS_OUTPUT_BLT_OPERATION BltOperation, IN UINTN SourceX, IN UINTN SourceY, IN UINTN DestinationX, IN UINTN DestinationY, IN UINTN Width, IN UINTN Height, IN UINTN Delta OPTIONAL ); EFI_STATUS UninstallBootGraphicsResourceTable ( VOID ); VOID EFIAPI GopInstallCallback ( IN EFI_EVENT Event, IN VOID *Context ); EFI_STATUS EFIAPI DummySetMode ( IN EFI_GRAPHICS_OUTPUT_PROTOCOL * This, IN UINT32 ModeNumber ); VOID BgrtGetLogoCoordinate ( IN UINTN ResolutionX, IN UINTN ResolutionY, IN UINTN ImageWidth, IN UINTN ImageHeight, OUT UINTN *CoordinateX, OUT UINTN *CoordinateY ); VOID UpdateLogoPosition ( IN EFI_GRAPHICS_OUTPUT_PROTOCOL *GraphicsOutput ); VOID HookGopStartFun ( VOID ); EFI_STATUS EFIAPI DummyGopBindingStart ( IN EFI_DRIVER_BINDING_PROTOCOL *This, IN EFI_HANDLE ControllerHandle, IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath OPTIONAL ); VOID CheckGopHook ( VOID ); EFI_BOOT_LOGO_PROTOCOL mBootLogoProtocolTemplate = { SetBootLogo }; /** Update information of logo image drawn on screen. @param This The pointer to the Boot Logo protocol instance. @param BltBuffer The BLT buffer for logo drawn on screen. If BltBuffer is set to NULL, it indicates that logo image is no longer on the screen. @param DestinationX X coordinate of destination for the BltBuffer. @param DestinationY Y coordinate of destination for the BltBuffer. @param Width Width of rectangle in BltBuffer in pixels. @param Height Hight of rectangle in BltBuffer in pixels. @retval EFI_SUCCESS The boot logo information was updated. @retval EFI_INVALID_PARAMETER One of the parameters has an invalid value. @retval EFI_OUT_OF_RESOURCES The logo information was not updated due to insufficient memory resources. **/ EFI_STATUS EFIAPI SetBootLogo ( IN EFI_BOOT_LOGO_PROTOCOL *This, IN EFI_GRAPHICS_OUTPUT_BLT_PIXEL *BltBuffer OPTIONAL, IN UINTN DestinationX, IN UINTN DestinationY, IN UINTN Width, IN UINTN Height ) { UINT64 BufferSize; EFI_STATUS Status; EFI_GRAPHICS_OUTPUT_PROTOCOL *GraphicsOutput; if (BltBuffer == NULL) { mIsLogoValid = FALSE; return EFI_SUCCESS; } if (Width == 0 || Height == 0) { return EFI_INVALID_PARAMETER; } if (mLogoBltBuffer != NULL) { FreePool (mLogoBltBuffer); mLogoBltBuffer = NULL; } // // Ensure the Height * Width doesn't overflow // if (Height > DivU64x64Remainder ((UINTN) ~0, Width, NULL)) { return EFI_UNSUPPORTED; } BufferSize = MultU64x64 (Width, Height); // // Ensure the BufferSize * sizeof (EFI_GRAPHICS_OUTPUT_BLT_PIXEL) doesn't overflow // if (BufferSize > DivU64x32 ((UINTN) ~0, sizeof (EFI_GRAPHICS_OUTPUT_BLT_PIXEL))) { return EFI_UNSUPPORTED; } mLogoBltBuffer = AllocateCopyPool ( (UINTN)BufferSize * sizeof (EFI_GRAPHICS_OUTPUT_BLT_PIXEL), BltBuffer ); if (mLogoBltBuffer == NULL) { return EFI_OUT_OF_RESOURCES; } mLogoDestX = DestinationX; mLogoDestY = DestinationY; mLogoWidth = Width; mLogoHeight = Height; Status = gBS->HandleProtocol (gST->ConsoleOutHandle, &gEfiGraphicsOutputProtocolGuid, (VOID **)&GraphicsOutput); if (!EFI_ERROR (Status)) { mLogoResolutionX = GraphicsOutput->Mode->Info->HorizontalResolution; mLogoResolutionY = GraphicsOutput->Mode->Info->VerticalResolution; } if (mNumberofGops == 0) { mIsLogoValid = FALSE; } else { mIsLogoValid = TRUE; } mIsMonitor = TRUE; return EFI_SUCCESS; } /** This function calculates and updates an UINT8 checksum. @param[in] Buffer Pointer to buffer to checksum. @param[in] Size Number of bytes to checksum. **/ VOID BgrtAcpiTableChecksum ( IN UINT8 *Buffer, IN UINTN Size ) { UINTN ChecksumOffset; ChecksumOffset = OFFSET_OF (EFI_ACPI_DESCRIPTION_HEADER, Checksum); // // Set checksum to 0 first. // Buffer[ChecksumOffset] = 0; // // Update checksum value. // Buffer[ChecksumOffset] = CalculateCheckSum8 (Buffer, Size); } /** Allocate EfiReservedMemoryType below 4G memory address. This function allocates EfiReservedMemoryType below 4G memory address. @param[in] Size Size of memory to allocate. @return Allocated address for output. **/ VOID * BgrtAllocateMemoryBelow4G ( IN UINTN Size ) { UINTN Pages; EFI_PHYSICAL_ADDRESS Address; EFI_STATUS Status; VOID *Buffer; Pages = EFI_SIZE_TO_PAGES (Size); Address = 0xffffffff; // // According to the Acpi5.0, the memory type of Boot image must be the EfiBootServicesData! // and BGRT only is supported on Uefi system. // That's different to the EDKII implementation of BGRT. // The EDKII used the EfiReservedMemoryType memory type which can support the legacy and Uefi system, // but it violate the Acpi5.0 spec. // Status = gBS->AllocatePages ( AllocateMaxAddress, EfiBootServicesData, Pages, &Address ); ASSERT_EFI_ERROR (Status); Buffer = (VOID *) (UINTN) Address; ZeroMem (Buffer, Size); return Buffer; } /** Install Boot Graphics Resource Table to ACPI table. @return Status code. **/ EFI_STATUS InstallBootGraphicsResourceTable ( VOID ) { EFI_STATUS Status; EFI_ACPI_TABLE_PROTOCOL *AcpiTableProtocol; UINT8 *ImageBuffer; UINTN PaddingSize; UINTN BmpSize; UINTN OrigBmpSize; UINT8 *Image; EFI_GRAPHICS_OUTPUT_BLT_PIXEL *BltPixel; UINTN Col; UINTN Row; EFI_CONSOLE_CONTROL_PROTOCOL *ConsoleControl; EFI_CONSOLE_CONTROL_SCREEN_MODE CurrentMode; EFI_GRAPHICS_OUTPUT_PROTOCOL *GraphicsOutput; // // Check whether Boot Graphics Resource Table is already installed. // if (mAcpiBgrtInstalled) { Status = UninstallBootGraphicsResourceTable (); if (EFI_ERROR (Status)) { return Status; } } // // Get ACPI Table protocol. // Status = gBS->LocateProtocol (&gEfiAcpiTableProtocolGuid, NULL, (VOID **) &AcpiTableProtocol); if (EFI_ERROR (Status)) { return Status; } // // Check whether Logo exist. // if (mLogoBltBuffer == NULL) { Status = LogoLibSetBootLogo (); if (EFI_ERROR(Status)) { return Status; } mIsLogoValid = FALSE; } if (mLogoBltBuffer == NULL) { return EFI_OUT_OF_RESOURCES; } if (mBootGraphicsResourceTableTemplate.ImageAddress != 0) { // // reserve original BGRT buffer size // OrigBmpSize = mBmpImageHeaderTemplate.ImageSize + sizeof (BMP_IMAGE_HEADER); // // Free orignal BMP memory // if (mBootGraphicsResourceTableTemplate.ImageAddress) { gBS->FreePages(mBootGraphicsResourceTableTemplate.ImageAddress, EFI_SIZE_TO_PAGES (OrigBmpSize)); } mBootGraphicsResourceTableTemplate.ImageAddress = 0; } // // Allocate memory for BMP file. // PaddingSize = mLogoWidth & 0x3; // // First check mLogoWidth * 3 + PaddingSize doesn't overflow // if (mLogoWidth > (((UINT32) ~0) - PaddingSize) / 3 ) { return EFI_UNSUPPORTED; } // // Second check (mLogoWidth * 3 + PaddingSize) * mLogoHeight + sizeof (BMP_IMAGE_HEADER) doesn't overflow // if (mLogoHeight > (((UINT32) ~0) - sizeof (BMP_IMAGE_HEADER)) / (mLogoWidth * 3 + PaddingSize)) { return EFI_UNSUPPORTED; } BmpSize = (mLogoWidth * 3 + PaddingSize) * mLogoHeight + sizeof (BMP_IMAGE_HEADER); ImageBuffer = BgrtAllocateMemoryBelow4G (BmpSize); if (ImageBuffer == NULL) { return EFI_OUT_OF_RESOURCES; } mBmpImageHeaderTemplate.Size = (UINT32) BmpSize; mBmpImageHeaderTemplate.ImageSize = (UINT32) BmpSize - sizeof (BMP_IMAGE_HEADER); mBmpImageHeaderTemplate.PixelWidth = (UINT32) mLogoWidth; mBmpImageHeaderTemplate.PixelHeight = (UINT32) mLogoHeight; CopyMem (ImageBuffer, &mBmpImageHeaderTemplate, sizeof (BMP_IMAGE_HEADER)); // // Convert BLT buffer to BMP file. // Image = ImageBuffer + sizeof (BMP_IMAGE_HEADER); for (Row = 0; Row < mLogoHeight; Row++) { BltPixel = &mLogoBltBuffer[(mLogoHeight - Row - 1) * mLogoWidth]; if (BltPixel != NULL) { for (Col = 0; Col < mLogoWidth; Col++) { *Image++ = BltPixel->Blue; *Image++ = BltPixel->Green; *Image++ = BltPixel->Red; BltPixel++; } } // // Padding for 4 byte alignment. // Image += PaddingSize; } // // Check Screen Mode // Status = gBS->LocateProtocol (&gEfiConsoleControlProtocolGuid, NULL, (VOID **)&ConsoleControl); if (!EFI_ERROR (Status)) { ConsoleControl->GetMode (ConsoleControl, &CurrentMode, NULL, NULL); if (CurrentMode != EfiConsoleControlScreenGraphics) { mIsLogoValid = FALSE; } } mBootGraphicsResourceTableTemplate.Status = (UINT8) (mIsLogoValid ? EFI_ACPI_5_0_BGRT_STATUS_VALID : EFI_ACPI_5_0_BGRT_STATUS_INVALID); mBootGraphicsResourceTableTemplate.ImageAddress = (UINT64) (UINTN) ImageBuffer; if (mIsUpdateCoordinate == FALSE) { Status = gBS->HandleProtocol (gST->ConsoleOutHandle, &gEfiGraphicsOutputProtocolGuid, (VOID **)&GraphicsOutput); if (!EFI_ERROR (Status)) { UpdateLogoPosition (GraphicsOutput); } mIsUpdateCoordinate = TRUE; } mBootGraphicsResourceTableTemplate.ImageOffsetX = (UINT32) mLogoDestX; mBootGraphicsResourceTableTemplate.ImageOffsetY = (UINT32) mLogoDestY; // // Update Checksum. // BgrtAcpiTableChecksum ((UINT8 *) &mBootGraphicsResourceTableTemplate, sizeof (EFI_ACPI_5_0_BOOT_GRAPHICS_RESOURCE_TABLE)); // // Publish Boot Graphics Resource Table. // Status = AcpiTableProtocol->InstallAcpiTable ( AcpiTableProtocol, &mBootGraphicsResourceTableTemplate, sizeof (EFI_ACPI_5_0_BOOT_GRAPHICS_RESOURCE_TABLE), &mBootGraphicsResourceTableKey ); if (EFI_ERROR (Status)) { return Status; } mAcpiBgrtInstalled = TRUE; return Status; } /** Uninstall Boot Graphics Resource Table to ACPI table. @return Status code. **/ EFI_STATUS UninstallBootGraphicsResourceTable ( VOID ) { EFI_STATUS Status; EFI_ACPI_TABLE_PROTOCOL *AcpiTableProtocol; EFI_ACPI_SUPPORT_PROTOCOL *AcpiSupport; UINTN Index; EFI_ACPI_DESCRIPTION_HEADER *Table; UINTN Handle; EFI_ACPI_TABLE_VERSION Version; UINT8 *BytePtr; UINT8 *BytePtr2; BOOLEAN FoundBGRT; // //init local vars // AcpiSupport = NULL; Index = 0; Table = NULL; BytePtr = NULL; FoundBGRT = FALSE; // // found BGRT table // Status = gBS->LocateProtocol ( &gEfiAcpiSupportProtocolGuid, NULL, (VOID **)&AcpiSupport ); if (EFI_ERROR(Status)) { return Status; } do { Status = AcpiSupport->GetAcpiTable ( AcpiSupport, Index, (VOID **)&Table, &Version, &Handle ); if (!EFI_ERROR (Status)) { if (Table->Signature == EFI_ACPI_5_0_BOOT_GRAPHICS_RESOURCE_TABLE_SIGNATURE) { FoundBGRT = TRUE; break; } FreePool (Table); Table = NULL; } Index++; } while (Status != EFI_NOT_FOUND); if (FoundBGRT == FALSE) { return EFI_NOT_FOUND; } // // keep OEM BGRT Information // BytePtr = (UINT8*)&mBootGraphicsResourceTableTemplate; BytePtr2 = (UINT8*)Table; gBS->CopyMem (BytePtr + 10, BytePtr2 + 10, 28); FreePool (Table); // // Get ACPI Table protocol. // Status = gBS->LocateProtocol (&gEfiAcpiTableProtocolGuid, NULL, (VOID **) &AcpiTableProtocol); if (EFI_ERROR (Status)) { return Status; } if (mAcpiBgrtInstalled == TRUE) { Status = AcpiTableProtocol->UninstallAcpiTable ( AcpiTableProtocol, mBootGraphicsResourceTableKey ); } return Status; } /** Notify function for event group EFI_EVENT_GROUP_READY_TO_BOOT. This is used to install the Boot Graphics Resource Table. @param[in] Event The Event that is being processed. @param[in] Context The Event Context. **/ VOID EFIAPI BgrtReadyToBootEventNotify ( IN EFI_EVENT Event, IN VOID *Context ) { InstallBootGraphicsResourceTable (); } /** Notify function for event EFI_EVENT_LEGACY_BOOT. This is used to uninstall the Boot Graphics Resource Table. @param[in] Event The Event that is being processed. @param[in] Context The Event Context. **/ VOID EFIAPI BgrtLegacyBootEventNotify ( IN EFI_EVENT Event, IN VOID *Context ) { UninstallBootGraphicsResourceTable (); } /** The module Entry Point of the Boot Graphics Resource Table DXE driver. @param[in] ImageHandle The firmware allocated handle for the EFI image. @param[in] SystemTable A pointer to the EFI System Table. @retval EFI_SUCCESS The entry point is executed successfully. @retval Other Some error occurs when executing this entry point. **/ EFI_STATUS EFIAPI BootGraphicsDxeEntryPoint ( IN EFI_HANDLE ImageHandle, IN EFI_SYSTEM_TABLE *SystemTable ) { EFI_STATUS Status; EFI_EVENT GopInstallEvent; VOID *Registration; // // Install Boot Logo protocol. // Status = gBS->InstallMultipleProtocolInterfaces ( &mBootLogoHandle, &gEfiBootLogoProtocolGuid, &mBootLogoProtocolTemplate, NULL ); ASSERT_EFI_ERROR (Status); // // Register notify function to install BGRT on ReadyToBoot Event. // Status = gBS->CreateEventEx ( EVT_NOTIFY_SIGNAL, TPL_CALLBACK, BgrtReadyToBootEventNotify, NULL, &gEfiEventReadyToBootGuid, &mBootGraphicsReadyToBootEvent ); ASSERT_EFI_ERROR (Status); // // Create An Event to Hook Physical Gop->Blt // if (!EFI_ERROR(Status)) { Status = gBS->CreateEvent ( EVT_NOTIFY_SIGNAL, TPL_CALLBACK, GopInstallCallback, NULL, &GopInstallEvent ); if (!EFI_ERROR (Status)) { Status = gBS->RegisterProtocolNotify ( &gEfiGraphicsOutputProtocolGuid, GopInstallEvent, &Registration ); } } // // According to the description of BGRT in ACPI 5.0 spec // that the BGRT only supported on Uefi system. // Removed the Table when boot to legacy system. // Status = gBS->CreateEventEx ( EVT_NOTIFY_SIGNAL, TPL_CALLBACK, BgrtLegacyBootEventNotify, NULL, &gEfiEventLegacyBootGuid, &mBootGraphicsLegacyBootEvent ); ASSERT_EFI_ERROR (Status); return Status; } EFI_STATUS EFIAPI DummyBlt ( IN EFI_GRAPHICS_OUTPUT_PROTOCOL *This, IN EFI_GRAPHICS_OUTPUT_BLT_PIXEL *BltBuffer, OPTIONAL IN EFI_GRAPHICS_OUTPUT_BLT_OPERATION BltOperation, IN UINTN SourceX, IN UINTN SourceY, IN UINTN DestinationX, IN UINTN DestinationY, IN UINTN Width, IN UINTN Height, IN UINTN Delta OPTIONAL ) { EFI_STATUS Status; UINTN ListIndex; UINTN SizeOfInfo; EFI_GRAPHICS_OUTPUT_MODE_INFORMATION *Info; Status = EFI_SUCCESS; if (mNumberofGops <= 0) { return EFI_NOT_STARTED; } for (ListIndex = 0; ListIndex < mNumberofGops; ListIndex++) { if (mGopHookedList[ListIndex].Gop == This) { if (BltOperation == EfiBltVideoFill) { if (mGopHookedList[ListIndex].BltWidth == 0 && mGopHookedList[ListIndex].BltHeight == 0) { // // This indicates that screen has already been cleared when gop driver inits screen. // So, Save initial clear screen's context. // This->QueryMode (This, This->Mode->Mode, &SizeOfInfo, &Info); mGopHookedList[ListIndex].BltWidth = Info->HorizontalResolution; mGopHookedList[ListIndex].BltHeight = Info->VerticalResolution; mGopHookedList[ListIndex].BltColor = 0; mGopHookedList[ListIndex].BltX = 0; mGopHookedList[ListIndex].BltY = 0; } if (*(UINT32*)BltBuffer == mGopHookedList[ListIndex].BltColor && DestinationX == mGopHookedList[ListIndex].BltX && DestinationY == mGopHookedList[ListIndex].BltY && Width == mGopHookedList[ListIndex].BltWidth && Height == mGopHookedList[ListIndex].BltHeight) { // // Skip the operation if last operation same as this time // continue; } else { // // Record the last X, Y, W, H for next comparison // mGopHookedList[ListIndex].BltColor = *(UINT32*)BltBuffer; mGopHookedList[ListIndex].BltX = DestinationX; mGopHookedList[ListIndex].BltY = DestinationY; mGopHookedList[ListIndex].BltWidth = Width; mGopHookedList[ListIndex].BltHeight = Height; } } else { // // Destroy the record due to normal Blt be called // mGopHookedList[ListIndex].BltWidth = (UINTN)-1; } Status = mGopHookedList[ListIndex].HookedBlt ( This, BltBuffer, BltOperation, SourceX, SourceY, DestinationX, DestinationY, Width, Height, Delta ); } } if (BltOperation != EfiBltVideoToBltBuffer && !EFI_ERROR (Status) && mIsMonitor && mIsLogoValid && (DestinationY <= mLogoDestY + mLogoHeight)) { mIsLogoValid = FALSE; InstallBootGraphicsResourceTable (); } return Status; } VOID EFIAPI GopInstallCallback ( IN EFI_EVENT Event, IN VOID *Context ) { CheckGopHook (); HookGopStartFun (); } EFI_STATUS EFIAPI DummySetMode ( IN EFI_GRAPHICS_OUTPUT_PROTOCOL *This, IN UINT32 ModeNumber ) { EFI_STATUS Status; UINTN ListIndex; UINTN SizeOfInfo; EFI_GRAPHICS_OUTPUT_MODE_INFORMATION *Info; Status = EFI_SUCCESS; if (mNumberofGops <= 0) { return EFI_NOT_STARTED; } for (ListIndex = 0; ListIndex < mNumberofGops; ListIndex++) { if (mGopHookedList[ListIndex].Gop == This) { Status = mGopHookedList[ListIndex].HookedSetMode (This,ModeNumber); // // Get current resolution used for reduce the redundancy clear screen // This->QueryMode (This, This->Mode->Mode, &SizeOfInfo, &Info); mGopHookedList[ListIndex].BltColor = 0; mGopHookedList[ListIndex].BltX = 0; mGopHookedList[ListIndex].BltY = 0; mGopHookedList[ListIndex].BltWidth = Info->HorizontalResolution; mGopHookedList[ListIndex].BltHeight = Info->VerticalResolution; FreePool (Info); Info = NULL; } } mIsLogoValid = FALSE; if ((!EFI_ERROR (Status)) && mIsUpdateCoordinate == TRUE) { UpdateLogoPosition (This); InstallBootGraphicsResourceTable (); } return Status; } VOID UpdateLogoPosition ( IN EFI_GRAPHICS_OUTPUT_PROTOCOL *GraphicsOutput ) { if (mLogoResolutionX == GraphicsOutput->Mode->Info->HorizontalResolution && mLogoResolutionY == GraphicsOutput->Mode->Info->VerticalResolution) { return; } BgrtGetLogoCoordinate ( GraphicsOutput->Mode->Info->HorizontalResolution, GraphicsOutput->Mode->Info->VerticalResolution, mLogoWidth, mLogoHeight, &mLogoDestX, &mLogoDestY ); mLogoResolutionX = GraphicsOutput->Mode->Info->HorizontalResolution; mLogoResolutionY = GraphicsOutput->Mode->Info->VerticalResolution; mIsLogoValid = FALSE; } VOID HookGopStartFun ( VOID ) { UINTN NoHandles; EFI_HANDLE *HandleBuf; EFI_OPEN_PROTOCOL_INFORMATION_ENTRY *OpenInfoBuffer; UINTN EntryCount; UINTN Index; UINTN Index2; UINTN Index3; EFI_HANDLE ControllerHandle; EFI_PCI_IO_PROTOCOL *PciIo; UINT8 BaseClassCode; EFI_HANDLE GopDrvImgHandle; EFI_STATUS Status; UINT32 Attributes; EFI_DRIVER_BINDING_PROTOCOL *TempGopDrvBinding; // //init locals // GopDrvImgHandle = NULL; TempGopDrvBinding = NULL; // // find gop driver's binding protocol // Status = gBS->LocateHandleBuffer ( ByProtocol, &gEfiPciIoProtocolGuid, NULL, &NoHandles, &HandleBuf ); if (EFI_ERROR (Status)) { return ; } for (Index = 0; Index < NoHandles; Index++) { Status = gBS->OpenProtocolInformation ( HandleBuf[Index], &gEfiPciIoProtocolGuid, &OpenInfoBuffer, &EntryCount ); if (EFI_ERROR (Status)) { continue; } for (Index2 = 0; Index2 < EntryCount; Index2++) { ControllerHandle = OpenInfoBuffer[Index2].ControllerHandle; Attributes = OpenInfoBuffer[Index2].Attributes; if (ControllerHandle == NULL || Attributes != EFI_OPEN_PROTOCOL_BY_DRIVER) { continue; } Status = gBS->HandleProtocol ( ControllerHandle, &gEfiPciIoProtocolGuid, (VOID **)&PciIo ); ASSERT_EFI_ERROR (Status); if (EFI_ERROR (Status)) { continue; } Status = PciIo->Pci.Read ( PciIo, EfiPciIoWidthUint8, 0x0b, 1, &BaseClassCode ); ASSERT_EFI_ERROR (Status); if (EFI_ERROR (Status)) { continue; } if (BaseClassCode != PCI_CLASS_DISPLAY) { continue; } GopDrvImgHandle = OpenInfoBuffer[Index2].AgentHandle; Status = gBS->HandleProtocol ( GopDrvImgHandle, &gEfiDriverBindingProtocolGuid, (VOID **)&TempGopDrvBinding ); ASSERT_EFI_ERROR (Status); if (EFI_ERROR (Status)) { continue; } for (Index3 = 0; Index3 < mCurNoGopDrvBinding; Index3++) { if (mGopBindingHookedList != NULL && mGopBindingHookedList[Index3].GopDriverBinding == TempGopDrvBinding) { break; } } if (Index3 != mCurNoGopDrvBinding) { continue; } mGopBindingHookedList = ReallocatePool ( sizeof (HOOKED_GOP_DRV_BINDING) * mCurNoGopDrvBinding, sizeof (HOOKED_GOP_DRV_BINDING) * (mCurNoGopDrvBinding + 1), mGopBindingHookedList ); if (mGopBindingHookedList == NULL) { continue; } mCurNoGopDrvBinding += 1; mGopBindingHookedList[mCurNoGopDrvBinding - 1].GopDriverBinding = TempGopDrvBinding; mGopBindingHookedList[mCurNoGopDrvBinding - 1].HookedGopStartFun = TempGopDrvBinding->Start; TempGopDrvBinding->Start = DummyGopBindingStart; } FreePool (OpenInfoBuffer); } FreePool (HandleBuf); } EFI_STATUS EFIAPI DummyGopBindingStart ( IN EFI_DRIVER_BINDING_PROTOCOL *This, IN EFI_HANDLE ControllerHandle, IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath OPTIONAL ) { EFI_STATUS Status; UINTN ListIndex; Status = EFI_SUCCESS; if (mNumberofGops <= 0) { return EFI_NOT_STARTED; } for (ListIndex = 0; ListIndex < mCurNoGopDrvBinding; ListIndex++) { if (mGopBindingHookedList[ListIndex].GopDriverBinding == This) { Status = mGopBindingHookedList[ListIndex].HookedGopStartFun ( This, ControllerHandle, RemainingDevicePath ); CheckGopHook (); } } return Status; } VOID CheckGopHook ( VOID ) { EFI_HANDLE *HandleBuffer; UINTN NumberOfHandles; UINTN Index; EFI_DEVICE_PATH_PROTOCOL *GopDevicePath; EFI_STATUS Status; EFI_GRAPHICS_OUTPUT_PROTOCOL *GraphicsOutput; HOOKED_GOP_BLT_SET_MODE *ThisGopHookedList; UINTN GopCount; UINTN ListIndex; BOOLEAN NotInHookList; GopCount = 0; Status = gBS->LocateHandleBuffer ( ByProtocol, &gEfiGraphicsOutputProtocolGuid, NULL, &NumberOfHandles, &HandleBuffer ); if (EFI_ERROR (Status)) { return; } ThisGopHookedList = mGopHookedList; mGopHookedList = AllocateZeroPool (sizeof (HOOKED_GOP_BLT_SET_MODE) * NumberOfHandles); ASSERT (mGopHookedList != NULL); if (mGopHookedList == NULL) { return ; } for (Index = 0; Index < NumberOfHandles; Index++) { Status = gBS->HandleProtocol ( HandleBuffer[Index], &gEfiDevicePathProtocolGuid, (VOID*)&GopDevicePath ); if (EFI_ERROR (Status)) { continue; } Status = gBS->HandleProtocol ( HandleBuffer[Index], &gEfiGraphicsOutputProtocolGuid, (VOID **)&GraphicsOutput ); if (EFI_ERROR (Status)) { continue; } NotInHookList = TRUE; for (ListIndex = 0; ListIndex < mNumberofGops; ListIndex++) { if (ThisGopHookedList[ListIndex].Gop == GraphicsOutput) { NotInHookList = FALSE; mGopHookedList[GopCount].Gop = ThisGopHookedList[ListIndex].Gop; mGopHookedList[GopCount].HookedBlt = ThisGopHookedList[ListIndex].HookedBlt; mGopHookedList[GopCount].HookedSetMode = ThisGopHookedList[ListIndex].HookedSetMode; mGopHookedList[GopCount].BltColor = ThisGopHookedList[ListIndex].BltColor; mGopHookedList[GopCount].BltX = ThisGopHookedList[ListIndex].BltX; mGopHookedList[GopCount].BltY = ThisGopHookedList[ListIndex].BltY; mGopHookedList[GopCount].BltWidth = ThisGopHookedList[ListIndex].BltWidth; mGopHookedList[GopCount].BltHeight = ThisGopHookedList[ListIndex].BltHeight; if(ThisGopHookedList[ListIndex].HookedBlt == GraphicsOutput->Blt && ThisGopHookedList[ListIndex].HookedSetMode == GraphicsOutput->SetMode) { // // Need to rehook blt & setmode, since blt & setmode has been changed back by gop driver. // GraphicsOutput->Blt = DummyBlt; GraphicsOutput->SetMode = DummySetMode; } GopCount++; break; } } if (NotInHookList == TRUE) { mGopHookedList[GopCount].Gop = GraphicsOutput; mGopHookedList[GopCount].HookedBlt = GraphicsOutput->Blt; mGopHookedList[GopCount].HookedSetMode = GraphicsOutput->SetMode; GraphicsOutput->Blt = DummyBlt; GraphicsOutput->SetMode = DummySetMode; GopCount++; } } mNumberofGops = GopCount; if (ThisGopHookedList) { FreePool (ThisGopHookedList); } FreePool (HandleBuffer); }