OvmfPkg: PciHostBridgeDxe: release resources on driver entry failure

The entry point of the driver, InitializePciHostBridge(), leaks resources
(and installed protocols) in the following cases:

- The first root bridge protocol installation fails. In this case, the
  host bridge protocol is left installed, but the driver exits with an
  error.

- The second or a later root bridge protocol installation fails. In this
  case, the host bridge protocol, and all prior root bridge protocols, are
  left installed, even though the driver exits with an error.

Handle errors correctly: roll back / release / uninstall resources when
aborting the driver.

Cc: Jordan Justen <jordan.l.justen@intel.com>
Contributed-under: TianoCore Contribution Agreement 1.0
Signed-off-by: Laszlo Ersek <lersek@redhat.com>
Regression-tested-by: Gabriel Somlo <somlo@cmu.edu>
Reviewed-by: Jordan Justen <jordan.l.justen@intel.com>

git-svn-id: https://svn.code.sf.net/p/edk2/code/trunk/edk2@17959 6f19259b-4bc3-4df7-8a09-765794883524
This commit is contained in:
Laszlo Ersek 2015-07-14 12:02:15 +00:00 committed by lersek
parent f5f9496c79
commit 7ee9dc2321
1 changed files with 51 additions and 3 deletions

View File

@ -153,6 +153,32 @@ FreePrivateData:
}
/**
Uninitialize and free a root bridge set up with InitRootBridge().
On return, the EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL instance and the device path
will have been released, freeing RootBus->Handle as well.
param[in] RootBus The private PCI_ROOT_BRIDGE_INSTANCE that has been created
with InitRootBridge(), and should be released.
**/
STATIC
VOID
UninitRootBridge (
IN PCI_ROOT_BRIDGE_INSTANCE *RootBus
)
{
EFI_STATUS Status;
Status = gBS->UninstallMultipleProtocolInterfaces (RootBus->Handle,
&gEfiDevicePathProtocolGuid, &RootBus->DevicePath,
&gEfiPciRootBridgeIoProtocolGuid, &RootBus->Io,
NULL);
ASSERT_EFI_ERROR (Status);
FreePool (RootBus);
}
/**
Entry point of this driver
@ -174,6 +200,7 @@ InitializePciHostBridge (
UINTN RootBridgeNumber;
PCI_HOST_BRIDGE_INSTANCE *HostBridge;
PCI_ROOT_BRIDGE_INSTANCE *RootBus;
EFI_STATUS UninstallStatus;
mDriverImageHandle = ImageHandle;
@ -196,8 +223,7 @@ InitializePciHostBridge (
NULL
);
if (EFI_ERROR (Status)) {
FreePool (HostBridge);
return EFI_DEVICE_ERROR;
goto FreeHostBridge;
}
for (RootBridgeNumber = 0;
@ -209,12 +235,34 @@ InitializePciHostBridge (
&RootBus
);
if (EFI_ERROR (Status)) {
return Status;
goto RollbackProtocols;
}
InsertTailList (&HostBridge->Head, &RootBus->Link);
}
return EFI_SUCCESS;
RollbackProtocols:
while (!IsListEmpty (&HostBridge->Head)) {
LIST_ENTRY *Entry;
Entry = GetFirstNode (&HostBridge->Head);
RemoveEntryList (Entry);
RootBus = DRIVER_INSTANCE_FROM_LIST_ENTRY (Entry);
UninitRootBridge (RootBus);
}
UninstallStatus = gBS->UninstallMultipleProtocolInterfaces (
HostBridge->HostBridgeHandle,
&gEfiPciHostBridgeResourceAllocationProtocolGuid,
&HostBridge->ResAlloc,
NULL
);
ASSERT_EFI_ERROR (UninstallStatus);
FreeHostBridge:
FreePool (HostBridge);
return Status;
}