OpenCorePkg/Library/OcDriverConnectionLib/OcDriverConnectionLib.c

290 lines
7.6 KiB
C

/** @file
Copyright (C) 2020, vit9696. All rights reserved.
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 <Library/MemoryAllocationLib.h>
#include <Library/DebugLib.h>
#include <Library/OcDriverConnectionLib.h>
#include <Library/UefiBootServicesTableLib.h>
#include <Protocol/PlatformDriverOverride.h>
//
// NULL-terminated list of driver handles that will be served by EFI_PLATFORM_DRIVER_OVERRIDE_PROTOCOL.
//
STATIC EFI_HANDLE *mPriorityDrivers;
//
// Saved original EFI_PLATFORM_DRIVER_OVERRIDE_PROTOCOL.GetDriver when doing override.
//
STATIC EFI_PLATFORM_DRIVER_OVERRIDE_GET_DRIVER mOrgPlatformGetDriver;
STATIC
EFI_STATUS
EFIAPI
OcPlatformGetDriver (
IN EFI_PLATFORM_DRIVER_OVERRIDE_PROTOCOL *This,
IN EFI_HANDLE ControllerHandle,
IN OUT EFI_HANDLE *DriverImageHandle
)
{
EFI_HANDLE *HandlePtr;
BOOLEAN FoundLast;
if (ControllerHandle == NULL) {
return EFI_INVALID_PARAMETER;
}
//
// We have no custom overrides.
//
if (mPriorityDrivers == NULL || mPriorityDrivers[0] == NULL) {
//
// Forward request to the original driver if we have it.
//
if (mOrgPlatformGetDriver != NULL) {
return mOrgPlatformGetDriver (This, ControllerHandle, DriverImageHandle);
}
//
// Report not found for the first request.
//
if (*DriverImageHandle == NULL) {
return EFI_NOT_FOUND;
}
//
// Report invalid parameter for the handle we could not have returned.
//
return EFI_INVALID_PARAMETER;
}
//
// Handle first driver in the overrides.
//
if (*DriverImageHandle == NULL) {
*DriverImageHandle = mPriorityDrivers[0];
return EFI_SUCCESS;
}
//
// Otherwise lookup the current driver in the list.
//
FoundLast = FALSE;
for (HandlePtr = &mPriorityDrivers[0]; HandlePtr[0] != NULL; ++HandlePtr) {
//
// Found driver in the list, return next one.
//
if (HandlePtr[0] == *DriverImageHandle) {
*DriverImageHandle = HandlePtr[1];
//
// Next driver is not last, return it.
//
if (*DriverImageHandle != NULL) {
return EFI_SUCCESS;
}
//
// Next driver is last, exit the loop.
//
FoundLast = TRUE;
break;
}
}
//
// We have no original protocol.
//
if (mOrgPlatformGetDriver == NULL) {
//
// Finalise the list by reporting not found.
//
if (FoundLast) {
return EFI_NOT_FOUND;
}
//
// Error as the passed handle is not valid.
//
return EFI_INVALID_PARAMETER;
}
//
// Forward the call to the original driver:
// - if FoundLast, then it is starting to iterating original list and DriverImageHandle
// is nulled above.
// - otherwise, then it is iterating the original list or is invalid.
//
return mOrgPlatformGetDriver (This, ControllerHandle, DriverImageHandle);
}
STATIC
EFI_STATUS
EFIAPI
OcPlatformGetDriverPath (
IN EFI_PLATFORM_DRIVER_OVERRIDE_PROTOCOL *This,
IN EFI_HANDLE ControllerHandle,
IN OUT EFI_DEVICE_PATH_PROTOCOL **DriverImagePath
)
{
return EFI_UNSUPPORTED;
}
STATIC
EFI_STATUS
EFIAPI
OcPlatformDriverLoaded (
IN EFI_PLATFORM_DRIVER_OVERRIDE_PROTOCOL *This,
IN EFI_HANDLE ControllerHandle,
IN EFI_DEVICE_PATH_PROTOCOL *DriverImagePath,
IN EFI_HANDLE DriverImageHandle
)
{
return EFI_UNSUPPORTED;
}
STATIC
EFI_PLATFORM_DRIVER_OVERRIDE_PROTOCOL
mOcPlatformDriverOverrideProtocol = {
OcPlatformGetDriver,
OcPlatformGetDriverPath,
OcPlatformDriverLoaded
};
EFI_STATUS
OcRegisterDriversToHighestPriority (
IN EFI_HANDLE *PriorityDrivers
)
{
EFI_PLATFORM_DRIVER_OVERRIDE_PROTOCOL *PlatformDriverOverride;
EFI_STATUS Status;
EFI_HANDLE NewHandle;
ASSERT (PriorityDrivers != NULL);
mPriorityDrivers = PriorityDrivers;
Status = gBS->LocateProtocol (
&gEfiPlatformDriverOverrideProtocolGuid,
NULL,
(VOID **) &PlatformDriverOverride
);
if (!EFI_ERROR(Status)) {
mOrgPlatformGetDriver = PlatformDriverOverride->GetDriver;
PlatformDriverOverride->GetDriver = OcPlatformGetDriver;
return Status;
}
NewHandle = NULL;
return gBS->InstallMultipleProtocolInterfaces (
&NewHandle,
&gEfiPlatformDriverOverrideProtocolGuid,
&mOcPlatformDriverOverrideProtocol,
NULL
);
}
EFI_STATUS
OcConnectDrivers (
VOID
)
{
EFI_STATUS Status;
UINTN HandleCount;
EFI_HANDLE *HandleBuffer;
UINTN DeviceIndex;
UINTN HandleIndex;
UINTN ProtocolIndex;
UINTN InfoIndex;
EFI_GUID **ProtocolGuids;
UINTN ProtocolCount;
EFI_OPEN_PROTOCOL_INFORMATION_ENTRY *ProtocolInfos;
UINTN ProtocolInfoCount;
BOOLEAN Connect;
//
// We locate only handles with device paths as connecting other handles
// will crash APTIO IV.
//
Status = gBS->LocateHandleBuffer (
ByProtocol,
&gEfiDevicePathProtocolGuid,
NULL,
&HandleCount,
&HandleBuffer
);
if (EFI_ERROR (Status)) {
return Status;
}
for (DeviceIndex = 0; DeviceIndex < HandleCount; ++DeviceIndex) {
//
// Only connect parent handles as we connect recursively.
// This improves the performance by more than 30 seconds
// with drives installed into Marvell SATA controllers on APTIO IV.
//
Connect = TRUE;
for (HandleIndex = 0; HandleIndex < HandleCount && Connect; ++HandleIndex) {
//
// Retrieve the list of all the protocols on each handle
//
Status = gBS->ProtocolsPerHandle (
HandleBuffer[HandleIndex],
&ProtocolGuids,
&ProtocolCount
);
if (EFI_ERROR (Status)) {
continue;
}
for (ProtocolIndex = 0; ProtocolIndex < ProtocolCount && Connect; ++ProtocolIndex) {
//
// Retrieve the list of agents that have opened each protocol
//
Status = gBS->OpenProtocolInformation (
HandleBuffer[HandleIndex],
ProtocolGuids[ProtocolIndex],
&ProtocolInfos,
&ProtocolInfoCount
);
if (!EFI_ERROR (Status)) {
for (InfoIndex = 0; InfoIndex < ProtocolInfoCount && Connect; ++InfoIndex) {
if (ProtocolInfos[InfoIndex].ControllerHandle == HandleBuffer[DeviceIndex]
&& (ProtocolInfos[InfoIndex].Attributes & EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER) == EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER) {
Connect = FALSE;
}
}
FreePool (ProtocolInfos);
}
}
FreePool (ProtocolGuids);
}
if (Connect) {
//
// We connect all handles to all drivers as otherwise fs drivers may not be seen.
//
gBS->ConnectController (HandleBuffer[DeviceIndex], NULL, NULL, TRUE);
}
}
FreePool (HandleBuffer);
return EFI_SUCCESS;
}