/** @file This library retrieve the EFI_BOOT_SERVICES pointer from EFI system table in library's constructor and allow overriding its properties. Copyright (c) 2006 - 2018, Intel Corporation. All rights reserved.
Copyright (c) 2020, vit9696. All rights reserved.
SPDX-License-Identifier: BSD-2-Clause-Patent **/ #include #include #include #include typedef struct OC_REGISTERED_PROTOCOL_ { EFI_GUID *ProtocolGuid; VOID *ProtocolInstance; BOOLEAN Override; } OC_REGISTERED_PROTOCOL; EFI_HANDLE gImageHandle = NULL; EFI_SYSTEM_TABLE *gST = NULL; EFI_BOOT_SERVICES *gBS = NULL; STATIC EFI_CONNECT_CONTROLLER mConnectController = NULL; STATIC EFI_LOCATE_PROTOCOL mLocateProtocol = NULL; STATIC OC_REGISTERED_PROTOCOL mRegisteredProtocols[8]; STATIC UINTN mRegisteredProtocolCount = 0; STATIC EFI_STATUS EFIAPI OcConnectController ( IN EFI_HANDLE ControllerHandle, IN EFI_HANDLE *DriverImageHandle OPTIONAL, IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath OPTIONAL, IN BOOLEAN Recursive ) { EFI_STATUS Status; VOID *DevicePath; if (ControllerHandle == NULL) { return EFI_INVALID_PARAMETER; } // // Do not connect controllers without device paths. // // REF: https://bugzilla.tianocore.org/show_bug.cgi?id=2460 // // Doing this reduces the amount of needless work during device // connection and resolves issues with firmwares that freeze // when connecting handles without device paths. // Status = gBS->HandleProtocol ( ControllerHandle, &gEfiDevicePathProtocolGuid, &DevicePath ); if (EFI_ERROR (Status)) { return EFI_NOT_FOUND; } Status = mConnectController ( ControllerHandle, DriverImageHandle, RemainingDevicePath, Recursive ); return Status; } STATIC EFI_STATUS EFIAPI OcLocateProtocol ( IN EFI_GUID *Protocol, IN VOID *Registration OPTIONAL, OUT VOID **Interface ) { EFI_STATUS Status; UINTN Index; if (Protocol == NULL || Interface == NULL) { return EFI_INVALID_PARAMETER; } // // Process overriding protocols first. // for (Index = 0; Index < mRegisteredProtocolCount; ++Index) { if (mRegisteredProtocols[Index].Override && CompareGuid (mRegisteredProtocols[Index].ProtocolGuid, Protocol)) { *Interface = mRegisteredProtocols[Index].ProtocolInstance; return EFI_SUCCESS; } } // // Call the original function second. // Status = mLocateProtocol ( Protocol, Registration, Interface ); // // Process fallback protocols third. // if (EFI_ERROR (Status)) { for (Index = 0; Index < mRegisteredProtocolCount; ++Index) { if (!mRegisteredProtocols[Index].Override && CompareGuid (mRegisteredProtocols[Index].ProtocolGuid, Protocol)) { *Interface = mRegisteredProtocols[Index].ProtocolInstance; return EFI_SUCCESS; } } } return Status; } EFI_STATUS OcRegisterBootServicesProtocol ( IN EFI_GUID *ProtocolGuid, IN VOID *ProtocolInstance, IN BOOLEAN Override ) { if (mRegisteredProtocolCount == ARRAY_SIZE (mRegisteredProtocols)) { return EFI_OUT_OF_RESOURCES; } mRegisteredProtocols[mRegisteredProtocolCount].ProtocolGuid = ProtocolGuid; mRegisteredProtocols[mRegisteredProtocolCount].ProtocolInstance = ProtocolInstance; mRegisteredProtocols[mRegisteredProtocolCount].Override = Override; return EFI_SUCCESS; } EFI_STATUS EFIAPI OcBootServicesTableLibConstructor ( IN EFI_HANDLE ImageHandle, IN EFI_SYSTEM_TABLE *SystemTable ) { EFI_STATUS Status; // // Assert on invalid startup arguments. // ASSERT (ImageHandle != NULL); ASSERT (SystemTable != NULL); ASSERT (SystemTable->BootServices != NULL); // // Cache the Image Handle // gImageHandle = ImageHandle; // // Allocate a copy of EFI Boot Services Table. // Status = SystemTable->BootServices->AllocatePool ( EfiBootServicesData, SystemTable->BootServices->Hdr.HeaderSize, (VOID **) &gBS ); if (EFI_ERROR (Status)) { return Status; } // // Copy the original EFI Boot Services Table into our custom table. // CopyMem ( gBS, SystemTable->BootServices, SystemTable->BootServices->Hdr.HeaderSize ); // // Override ConnectController and LocateProtocol functions and rehash. // mConnectController = gBS->ConnectController; mLocateProtocol = gBS->LocateProtocol; gBS->ConnectController = OcConnectController; gBS->LocateProtocol = OcLocateProtocol; gBS->Hdr.CRC32 = 0; SystemTable->BootServices->CalculateCrc32 ( gBS, gBS->Hdr.HeaderSize, &gBS->Hdr.CRC32 ); // // Allocate a copy of EFI System Table. // Status = SystemTable->BootServices->AllocatePool ( EfiBootServicesData, SystemTable->Hdr.HeaderSize, (VOID **) &gST ); if (EFI_ERROR (Status)) { gBS->FreePool (gBS); return Status; } // // Copy the original EFI System Table into our custom table. // CopyMem ( gST, SystemTable, SystemTable->Hdr.HeaderSize ); // // Override BootServices pointer and rehash. // gST->BootServices = gBS; gST->Hdr.CRC32 = 0; SystemTable->BootServices->CalculateCrc32 ( gST, gST->Hdr.HeaderSize, &gST->Hdr.CRC32 ); return EFI_SUCCESS; } EFI_STATUS EFIAPI OcBootServicesTableLibDestructor ( IN CONST EFI_HANDLE ImageHandle, IN EFI_SYSTEM_TABLE * CONST SystemTable ) { // // Free memory for table copies. // SystemTable->BootServices->FreePool (gBS); SystemTable->BootServices->FreePool (gST); return EFI_SUCCESS; }