mirror of
https://github.com/CloverHackyColor/CloverBootloader.git
synced 2024-12-25 16:37:42 +01:00
517 lines
18 KiB
C++
517 lines
18 KiB
C++
/*
|
|
* refit/scan/bootscreen.c
|
|
*
|
|
* All rights reserved.
|
|
*
|
|
* Redistribution and use in source and binary forms, with or without
|
|
* modification, are permitted provided that the following conditions are
|
|
* met:
|
|
*
|
|
* * Redistributions of source code must retain the above copyright
|
|
* notice, this list of conditions and the following disclaimer.
|
|
*
|
|
* * Redistributions in binary form must reproduce the above copyright
|
|
* notice, this list of conditions and the following disclaimer in the
|
|
* documentation and/or other materials provided with the
|
|
* distribution.
|
|
*
|
|
* * Neither the name of Christoph Pfisterer nor the names of the
|
|
* contributors may be used to endorse or promote products derived
|
|
* from this software without specific prior written permission.
|
|
*
|
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
|
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
|
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
|
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
|
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
|
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
|
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
|
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
|
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
|
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
|
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
*/
|
|
|
|
#include "entry_scan.h"
|
|
|
|
#ifndef DEBUG_ALL
|
|
#define DEBUG_LOCK_BOOT_SCREEN 1
|
|
#else
|
|
#define DEBUG_LOCK_BOOT_SCREEN DEBUG_ALL
|
|
#endif
|
|
|
|
#if DEBUG_LOCK_BOOT_SCREEN == 0
|
|
#define DBG(...)
|
|
#else
|
|
#define DBG(...) DebugLog(DEBUG_LOCK_BOOT_SCREEN, __VA_ARGS__)
|
|
#endif
|
|
|
|
// Each time a new graphics protocol is opened,
|
|
// lock it and save the information here
|
|
typedef struct LOCKED_GRAPHICS LOCKED_GRAPHICS;
|
|
struct LOCKED_GRAPHICS
|
|
{
|
|
LOCKED_GRAPHICS *Next;
|
|
EFI_HANDLE Owner;
|
|
EFI_HANDLE Agent;
|
|
EFI_HANDLE Controller;
|
|
UINT16 GOPCount;
|
|
UINT16 UGACount;
|
|
EFI_GRAPHICS_OUTPUT_PROTOCOL *GOPInterface;
|
|
EFI_GRAPHICS_OUTPUT_PROTOCOL GOP;
|
|
EFI_GRAPHICS_OUTPUT_PROTOCOL_MODE GOPMode;
|
|
EFI_GRAPHICS_OUTPUT_MODE_INFORMATION GOPInfo;
|
|
EFI_UGA_DRAW_PROTOCOL *UGAInterface;
|
|
EFI_UGA_DRAW_PROTOCOL UGA;
|
|
};
|
|
|
|
// The old boot services saved to restore later
|
|
static EFI_BOOT_SERVICES OldBootServices;
|
|
// The locked graphics collection
|
|
static LOCKED_GRAPHICS *LockedGraphics;
|
|
// The screen lock
|
|
static BOOLEAN ScreenIsLocked;
|
|
|
|
static EFI_STATUS EFIAPI LockedGOPBlt(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)
|
|
{
|
|
return EFI_SUCCESS;
|
|
}
|
|
static EFI_STATUS EFIAPI LockedGOPSetMode(IN EFI_GRAPHICS_OUTPUT_PROTOCOL *This, IN UINT32 ModeNumber)
|
|
{
|
|
if ((This == NULL) || (ModeNumber != 0)) {
|
|
return EFI_INVALID_PARAMETER;
|
|
}
|
|
return EFI_SUCCESS;
|
|
}
|
|
static EFI_STATUS EFIAPI LockedGOPQueryMode(IN EFI_GRAPHICS_OUTPUT_PROTOCOL *This, IN UINT32 ModeNumber, OUT UINTN *SizeOfInfo, OUT EFI_GRAPHICS_OUTPUT_MODE_INFORMATION **Info)
|
|
{
|
|
if ((This == NULL) ||
|
|
(This->Mode == NULL) ||
|
|
(This->Mode->Info == NULL) ||
|
|
(SizeOfInfo == NULL) ||
|
|
(Info == NULL) ||
|
|
(ModeNumber != 0)) {
|
|
return EFI_INVALID_PARAMETER;
|
|
}
|
|
*Info = This->Mode->Info;
|
|
*SizeOfInfo = This->Mode->SizeOfInfo;
|
|
return EFI_SUCCESS;
|
|
}
|
|
|
|
static EFI_STATUS AddLockedGraphicsGOP(IN EFI_HANDLE Handle, IN EFI_HANDLE AgentHandle, IN EFI_HANDLE ControllerHandle, IN EFI_GRAPHICS_OUTPUT_PROTOCOL *GOPInterface)
|
|
{
|
|
BOOLEAN Modify = TRUE;
|
|
LOCKED_GRAPHICS *Ptr = LockedGraphics;
|
|
if ((Handle == NULL) ||
|
|
(AgentHandle == NULL) ||
|
|
(GOPInterface == NULL)) {
|
|
return EFI_INVALID_PARAMETER;
|
|
}
|
|
// Check if this is already been locked
|
|
while (Ptr != NULL) {
|
|
if ((Ptr->Owner == Handle) &&
|
|
(Ptr->Agent == AgentHandle) &&
|
|
(Ptr->Controller == ControllerHandle)) {
|
|
if (Ptr->GOPCount == 0) {
|
|
break;
|
|
}
|
|
++(Ptr->GOPCount);
|
|
return EFI_SUCCESS;
|
|
}
|
|
if (Ptr->GOPInterface == GOPInterface) {
|
|
Modify = FALSE;
|
|
}
|
|
Ptr = Ptr->Next;
|
|
}
|
|
// Create a new locked graphics if needed
|
|
if (Ptr == NULL) {
|
|
Ptr = (LOCKED_GRAPHICS *)AllocateZeroPool(sizeof(LOCKED_GRAPHICS));
|
|
if (Ptr == NULL) {
|
|
return EFI_OUT_OF_RESOURCES;
|
|
}
|
|
// Add to list
|
|
Ptr->Next = LockedGraphics;
|
|
LockedGraphics = Ptr;
|
|
}
|
|
// Store these elements for later
|
|
Ptr->Owner = Handle;
|
|
Ptr->Agent = AgentHandle;
|
|
Ptr->Controller = ControllerHandle;
|
|
CopyMem(&(Ptr->GOP), GOPInterface, sizeof(EFI_GRAPHICS_OUTPUT_PROTOCOL));
|
|
CopyMem(&(Ptr->GOPMode), GOPInterface->Mode, sizeof(EFI_GRAPHICS_OUTPUT_PROTOCOL_MODE));
|
|
CopyMem(&(Ptr->GOPInfo), GOPInterface->Mode->Info, GOPInterface->Mode->SizeOfInfo);
|
|
Ptr->GOPInterface = GOPInterface;
|
|
Ptr->GOPCount = 1;
|
|
// Alter the interface
|
|
if (Modify) {
|
|
GOPInterface->Blt = LockedGOPBlt;
|
|
GOPInterface->SetMode = LockedGOPSetMode;
|
|
GOPInterface->QueryMode = LockedGOPQueryMode;
|
|
if (GOPInterface->Mode != NULL) {
|
|
UINTN BufferSize = (1024 * 768 * 4); // (GOPInterface->Mode->Info->HorizontalResolution * GOPInterface->Mode->Info->VerticalResolution * 4);
|
|
GOPInterface->Mode->MaxMode = 1;
|
|
GOPInterface->Mode->Mode = 0;
|
|
GOPInterface->Mode->SizeOfInfo = sizeof(EFI_GRAPHICS_OUTPUT_MODE_INFORMATION);
|
|
DBG("Custom boot framebuffer 0x%X 0x%X\n", GOPInterface->Mode->FrameBufferBase, GOPInterface->Mode->FrameBufferSize);
|
|
GOPInterface->Mode->FrameBufferBase = (EFI_PHYSICAL_ADDRESS)(UINTN)(GOPInterface->Mode->FrameBufferBase + GOPInterface->Mode->FrameBufferSize);
|
|
GOPInterface->Mode->FrameBufferSize = BufferSize;
|
|
DBG("Custom boot GOP: 0x%X @0x%X 0x%X", GOPInterface, GOPInterface->Mode->FrameBufferBase, BufferSize);
|
|
if (GOPInterface->Mode->Info != NULL) {
|
|
// /*
|
|
GOPInterface->Mode->Info->Version = 0;
|
|
GOPInterface->Mode->Info->HorizontalResolution = 1024;
|
|
GOPInterface->Mode->Info->PixelsPerScanLine = 1024;
|
|
GOPInterface->Mode->Info->VerticalResolution = 768;
|
|
GOPInterface->Mode->Info->PixelFormat = PixelBlueGreenRedReserved8BitPerColor;
|
|
// */
|
|
DBG(" %d(%d)x%d", GOPInterface->Mode->Info->HorizontalResolution, GOPInterface->Mode->Info->PixelsPerScanLine, GOPInterface->Mode->Info->VerticalResolution);
|
|
}
|
|
DBG("\n");
|
|
}
|
|
}
|
|
return EFI_SUCCESS;
|
|
}
|
|
static EFI_STATUS RestoreLockedGraphicsGOP(IN LOCKED_GRAPHICS *Graphics)
|
|
{
|
|
if (Graphics == NULL) {
|
|
return EFI_INVALID_PARAMETER;
|
|
}
|
|
if (Graphics->GOPInterface == NULL) {
|
|
Graphics->GOPCount = 0;
|
|
return EFI_SUCCESS;
|
|
}
|
|
// Restore GOP
|
|
CopyMem(Graphics->GOPInterface, &(Graphics->GOP), sizeof(EFI_GRAPHICS_OUTPUT_PROTOCOL));
|
|
if (Graphics->GOPInterface->Mode != NULL) {
|
|
// Restore mode
|
|
CopyMem(Graphics->GOPInterface->Mode, &(Graphics->GOPMode), sizeof(EFI_GRAPHICS_OUTPUT_PROTOCOL_MODE));
|
|
if (Graphics->GOPInterface->Mode->Info != NULL) {
|
|
// Restore info
|
|
CopyMem(Graphics->GOPInterface->Mode->Info, &(Graphics->GOPInfo), sizeof(EFI_GRAPHICS_OUTPUT_MODE_INFORMATION));
|
|
}
|
|
}
|
|
Graphics->GOPInterface = NULL;
|
|
Graphics->GOPCount = 0;
|
|
return EFI_SUCCESS;
|
|
}
|
|
static EFI_STATUS RemoveLockedGraphics(IN LOCKED_GRAPHICS *Graphics)
|
|
{
|
|
if (Graphics == NULL) {
|
|
return EFI_INVALID_PARAMETER;
|
|
}
|
|
// Only remove if not in use
|
|
if ((Graphics->GOPInterface != NULL) ||
|
|
(Graphics->UGAInterface != NULL)) {
|
|
return EFI_SUCCESS;
|
|
}
|
|
// Check if first one
|
|
if (Graphics == LockedGraphics) {
|
|
LockedGraphics = Graphics->Next;
|
|
FreePool(Graphics);
|
|
return EFI_SUCCESS;
|
|
} else if (LockedGraphics != NULL) {
|
|
// Check the next ones
|
|
LOCKED_GRAPHICS *Ptr = LockedGraphics;
|
|
while (Ptr->Next != NULL) {
|
|
if (Ptr->Next == Graphics) {
|
|
Ptr->Next = Graphics->Next;
|
|
FreePool(Graphics);
|
|
return EFI_SUCCESS;
|
|
}
|
|
Ptr = Ptr->Next;
|
|
}
|
|
}
|
|
// Not found
|
|
return EFI_NOT_FOUND;
|
|
}
|
|
static EFI_STATUS RemoveLockedGraphicsGOP(IN EFI_HANDLE Handle, IN EFI_HANDLE AgentHandle, IN EFI_HANDLE ControllerHandle)
|
|
{
|
|
LOCKED_GRAPHICS *Ptr = LockedGraphics;
|
|
while (Ptr != NULL) {
|
|
if ((Ptr->Owner == Handle) ||
|
|
(Ptr->Agent == AgentHandle) ||
|
|
(Ptr->Controller == ControllerHandle)) {
|
|
if (Ptr->GOPCount <= 1) {
|
|
EFI_STATUS Status = RestoreLockedGraphicsGOP(Ptr);
|
|
if (EFI_ERROR(Status)) {
|
|
return Status;
|
|
}
|
|
return RemoveLockedGraphics(Ptr);
|
|
}
|
|
--(Ptr->GOPCount);
|
|
return EFI_SUCCESS;
|
|
}
|
|
Ptr = Ptr->Next;
|
|
}
|
|
return EFI_NOT_FOUND;
|
|
}
|
|
|
|
static EFI_STATUS EFIAPI LockedUGASetMode(IN EFI_UGA_DRAW_PROTOCOL *This, IN UINT32 HorizontalResolution, IN UINT32 VerticalResolution, IN UINT32 ColorDepth, IN UINT32 RefreshRate)
|
|
{
|
|
return EFI_UNSUPPORTED;
|
|
}
|
|
static EFI_STATUS EFIAPI LockedUGABlt(IN EFI_UGA_DRAW_PROTOCOL *This, IN EFI_UGA_PIXEL *BltBuffer, OPTIONAL IN EFI_UGA_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)
|
|
{
|
|
return EFI_SUCCESS;
|
|
}
|
|
|
|
static EFI_STATUS RestoreLockedGraphicsUGA(IN LOCKED_GRAPHICS *Graphics)
|
|
{
|
|
if (Graphics == NULL) {
|
|
return EFI_INVALID_PARAMETER;
|
|
}
|
|
if (Graphics->UGAInterface == NULL) {
|
|
Graphics->UGACount = 0;
|
|
return EFI_SUCCESS;
|
|
}
|
|
// Restore UGA
|
|
CopyMem(Graphics->UGAInterface, &(Graphics->UGA), sizeof(EFI_UGA_DRAW_PROTOCOL));
|
|
Graphics->UGAInterface = NULL;
|
|
Graphics->UGACount = 0;
|
|
return EFI_SUCCESS;
|
|
}
|
|
static EFI_STATUS RemoveLockedGraphicsUGA(IN EFI_HANDLE Handle, IN EFI_HANDLE AgentHandle, IN EFI_HANDLE ControllerHandle)
|
|
{
|
|
LOCKED_GRAPHICS *Ptr = LockedGraphics;
|
|
while (Ptr != NULL) {
|
|
if ((Ptr->Owner == Handle) ||
|
|
(Ptr->Agent == AgentHandle) ||
|
|
(Ptr->Controller == ControllerHandle)) {
|
|
if (Ptr->UGACount <= 1) {
|
|
EFI_STATUS Status = RestoreLockedGraphicsUGA(Ptr);
|
|
if (EFI_ERROR(Status)) {
|
|
return Status;
|
|
}
|
|
return RemoveLockedGraphics(Ptr);
|
|
}
|
|
--(Ptr->UGACount);
|
|
return EFI_SUCCESS;
|
|
}
|
|
Ptr = Ptr->Next;
|
|
}
|
|
return EFI_NOT_FOUND;
|
|
}
|
|
|
|
static EFI_STATUS AddLockedGraphicsUGA(IN EFI_HANDLE Handle, IN EFI_HANDLE AgentHandle, IN EFI_HANDLE ControllerHandle, IN EFI_UGA_DRAW_PROTOCOL *UGAInterface)
|
|
{
|
|
BOOLEAN Modify = TRUE;
|
|
LOCKED_GRAPHICS *Ptr = LockedGraphics;
|
|
if ((Handle == NULL) ||
|
|
(AgentHandle == NULL) ||
|
|
(UGAInterface == NULL)) {
|
|
return EFI_INVALID_PARAMETER;
|
|
}
|
|
// Check if this is already been locked
|
|
while (Ptr != NULL) {
|
|
if ((Ptr->Owner == Handle) &&
|
|
(Ptr->Agent == AgentHandle) &&
|
|
(Ptr->Controller == ControllerHandle)) {
|
|
if (Ptr->UGACount == 0) {
|
|
break;
|
|
}
|
|
++(Ptr->UGACount);
|
|
return EFI_SUCCESS;
|
|
}
|
|
if (Ptr->UGAInterface == UGAInterface) {
|
|
Modify = FALSE;
|
|
}
|
|
Ptr = Ptr->Next;
|
|
}
|
|
// Create a new locked graphics if needed
|
|
if (Ptr == NULL) {
|
|
Ptr = (LOCKED_GRAPHICS *)AllocateZeroPool(sizeof(LOCKED_GRAPHICS));
|
|
if (Ptr == NULL) {
|
|
return EFI_OUT_OF_RESOURCES;
|
|
}
|
|
// Add to list
|
|
Ptr->Next = LockedGraphics;
|
|
LockedGraphics = Ptr;
|
|
}
|
|
// Store these elements for later
|
|
Ptr->Owner = Handle;
|
|
Ptr->Agent = AgentHandle;
|
|
Ptr->Controller = ControllerHandle;
|
|
CopyMem(&(Ptr->UGA), UGAInterface, sizeof(EFI_UGA_DRAW_PROTOCOL));
|
|
Ptr->UGAInterface = UGAInterface;
|
|
Ptr->UGACount = 1;
|
|
// Alter the interface
|
|
if (Modify) {
|
|
UGAInterface->Blt = LockedUGABlt;
|
|
UGAInterface->SetMode = LockedUGASetMode;
|
|
}
|
|
return EFI_SUCCESS;
|
|
}
|
|
|
|
static EFI_STATUS EFIAPI LockedOpenProtocol(IN EFI_HANDLE Handle, IN EFI_GUID *Protocol, OUT VOID **Interface OPTIONAL, IN EFI_HANDLE AgentHandle, IN EFI_HANDLE ControllerHandle, IN UINT32 Attributes)
|
|
{
|
|
if ((Attributes & EFI_OPEN_PROTOCOL_GET_PROTOCOL) != 0) {
|
|
if ((Protocol == NULL) || (Interface == NULL)) {
|
|
return EFI_INVALID_PARAMETER;
|
|
}
|
|
if (CompareMem(Protocol, &gEfiGraphicsOutputProtocolGuid, sizeof(EFI_GUID)) == 0) {
|
|
EFI_GRAPHICS_OUTPUT_PROTOCOL *GOPInterface = NULL;
|
|
// Open the actual protocol
|
|
EFI_STATUS Status = OldBootServices.OpenProtocol(Handle, Protocol, (VOID **)&GOPInterface, AgentHandle, ControllerHandle, Attributes);
|
|
if (EFI_ERROR(Status)) {
|
|
return Status;
|
|
}
|
|
if (GOPInterface == NULL) {
|
|
return EFI_NOT_FOUND;
|
|
}
|
|
// Save this protocol for later and alter it
|
|
if (EFI_ERROR(Status = AddLockedGraphicsGOP(Handle, AgentHandle, ControllerHandle, GOPInterface))) {
|
|
return Status;
|
|
}
|
|
// Return the altered protocol
|
|
*Interface = GOPInterface;
|
|
return EFI_SUCCESS;
|
|
} else if (CompareMem(Protocol, &gEfiUgaDrawProtocolGuid, sizeof(EFI_GUID)) == 0) {
|
|
EFI_UGA_DRAW_PROTOCOL *UGAInterface = NULL;
|
|
// Open the actual protocol
|
|
EFI_STATUS Status = OldBootServices.OpenProtocol(Handle, Protocol, (VOID **)&UGAInterface, AgentHandle, ControllerHandle, Attributes);
|
|
if (EFI_ERROR(Status)) {
|
|
return Status;
|
|
}
|
|
if (UGAInterface == NULL) {
|
|
return EFI_NOT_FOUND;
|
|
}
|
|
// Save this protocol for later and alter it
|
|
if (EFI_ERROR(Status = AddLockedGraphicsUGA(Handle, AgentHandle, ControllerHandle, UGAInterface))) {
|
|
return Status;
|
|
}
|
|
// Return the altered protocol
|
|
*Interface = UGAInterface;
|
|
return EFI_SUCCESS;
|
|
}
|
|
}
|
|
return OldBootServices.OpenProtocol(Handle, Protocol, Interface, AgentHandle, ControllerHandle, Attributes);
|
|
}
|
|
|
|
static EFI_STATUS EFIAPI LockedCloseProtocol(IN EFI_HANDLE Handle, IN EFI_GUID *Protocol, IN EFI_HANDLE AgentHandle, IN EFI_HANDLE ControllerHandle)
|
|
{
|
|
if (Handle == SelfImageHandle) {
|
|
if (Protocol == NULL) {
|
|
return EFI_INVALID_PARAMETER;
|
|
}
|
|
if (CompareMem(Protocol, &gEfiGraphicsOutputProtocolGuid, sizeof(EFI_GUID)) == 0) {
|
|
// Remove a reference to locked graphics
|
|
EFI_STATUS Status = RemoveLockedGraphicsGOP(Handle, AgentHandle, ControllerHandle);
|
|
if (EFI_ERROR(Status)) {
|
|
return Status;
|
|
}
|
|
} else if (CompareMem(Protocol, &gEfiUgaDrawProtocolGuid, sizeof(EFI_GUID)) == 0) {
|
|
// Remove a reference to locked graphics
|
|
EFI_STATUS Status = RemoveLockedGraphicsUGA(Handle, AgentHandle, ControllerHandle);
|
|
if (EFI_ERROR(Status)) {
|
|
return Status;
|
|
}
|
|
}
|
|
}
|
|
return OldBootServices.CloseProtocol(Handle, Protocol, AgentHandle, ControllerHandle);
|
|
}
|
|
|
|
// Lock the graphics GOP
|
|
static EFI_STATUS LockGraphicsGOP(VOID)
|
|
{
|
|
EFI_HANDLE *Buffer;
|
|
VOID *Interface;
|
|
UINTN i, Size = 0;
|
|
// Get needed buffer size
|
|
EFI_STATUS Status = gBS->LocateHandle(ByProtocol, &gEfiGraphicsOutputProtocolGuid, NULL, &Size, NULL);
|
|
if ((Status != EFI_BUFFER_TOO_SMALL) || (Size == 0)) {
|
|
return Status;
|
|
}
|
|
// Allocate buffer
|
|
Buffer = (EFI_HANDLE *)AllocatePool(Size);
|
|
if (Buffer == NULL) {
|
|
return EFI_OUT_OF_RESOURCES;
|
|
}
|
|
// Locate handles for GOP
|
|
Status = gBS->LocateHandle(ByProtocol, &gEfiGraphicsOutputProtocolGuid, NULL, &Size, Buffer);
|
|
if (EFI_ERROR(Status)) {
|
|
return Status;
|
|
}
|
|
// Open GOP protocols, they will be modified by our modified boot services
|
|
Size /= sizeof(EFI_HANDLE *);
|
|
for (i = 0; i < Size; ++i) {
|
|
gBS->OpenProtocol(Buffer[i], &gEfiGraphicsOutputProtocolGuid, &Interface, SelfImageHandle, NULL, EFI_OPEN_PROTOCOL_GET_PROTOCOL);
|
|
}
|
|
return EFI_SUCCESS;
|
|
}
|
|
|
|
// Lock the graphics UGA
|
|
static EFI_STATUS LockGraphicsUGA(VOID)
|
|
{
|
|
EFI_HANDLE *Buffer;
|
|
VOID *Interface;
|
|
UINTN i, Size = 0;
|
|
// Get needed buffer size
|
|
EFI_STATUS Status = gBS->LocateHandle(ByProtocol, &gEfiUgaDrawProtocolGuid, NULL, &Size, NULL);
|
|
if ((Status != EFI_BUFFER_TOO_SMALL) || (Size == 0)) {
|
|
return Status;
|
|
}
|
|
// Allocate buffer
|
|
Buffer = (EFI_HANDLE *)AllocatePool(Size);
|
|
if (Buffer == NULL) {
|
|
return EFI_OUT_OF_RESOURCES;
|
|
}
|
|
// Locate handles for UGA
|
|
Status = gBS->LocateHandle(ByProtocol, &gEfiUgaDrawProtocolGuid, NULL, &Size, Buffer);
|
|
if (EFI_ERROR(Status)) {
|
|
return Status;
|
|
}
|
|
// Open UGA protocols, they will be modified by our modified boot services
|
|
Size /= sizeof(EFI_HANDLE *);
|
|
for (i = 0; i < Size; ++i) {
|
|
gBS->OpenProtocol(Buffer[i], &gEfiUgaDrawProtocolGuid, &Interface, SelfImageHandle, NULL, EFI_OPEN_PROTOCOL_GET_PROTOCOL);
|
|
}
|
|
return EFI_SUCCESS;
|
|
}
|
|
|
|
// Lock the graphics
|
|
EFI_STATUS LockBootScreen(VOID)
|
|
{
|
|
// Make sure we're not locked
|
|
if (ScreenIsLocked) {
|
|
DBG("Custom boot screen is already locked\n");
|
|
return EFI_ACCESS_DENIED;
|
|
}
|
|
DBG("Custom boot lock\n");
|
|
// Lock open and close protocol
|
|
CopyMem(&OldBootServices, gBS, sizeof(EFI_BOOT_SERVICES));
|
|
gBS->OpenProtocol = LockedOpenProtocol;
|
|
gBS->CloseProtocol = LockedCloseProtocol;
|
|
gBS->Hdr.CRC32 = 0;
|
|
gBS->CalculateCrc32(gBS, gBS->Hdr.HeaderSize, &(gBS->Hdr.CRC32));
|
|
// Find graphics and modify them
|
|
LockGraphicsGOP();
|
|
LockGraphicsUGA();
|
|
// Lock screen
|
|
ScreenIsLocked = TRUE;
|
|
return EFI_SUCCESS;
|
|
}
|
|
|
|
// Unlock the graphics
|
|
EFI_STATUS UnlockBootScreen(VOID)
|
|
{
|
|
// Make sure we're locked
|
|
if (!ScreenIsLocked) {
|
|
DBG("Custom boot screen is not locked\n");
|
|
return EFI_NOT_READY;
|
|
}
|
|
DBG("Custom boot unlock\n");
|
|
// Remove all locked graphics
|
|
while (LockedGraphics != NULL) {
|
|
LOCKED_GRAPHICS *Ptr = LockedGraphics;
|
|
LockedGraphics = Ptr->Next;
|
|
RestoreLockedGraphicsGOP(Ptr);
|
|
RestoreLockedGraphicsUGA(Ptr);
|
|
RemoveLockedGraphics(Ptr);
|
|
}
|
|
// Restore locate handle, open and close protocol
|
|
CopyMem(gBS, &OldBootServices, sizeof(EFI_BOOT_SERVICES));
|
|
// Unlock
|
|
ScreenIsLocked = FALSE;
|
|
return EFI_SUCCESS;
|
|
}
|