summaryrefslogtreecommitdiff
path: root/OvmfPkg
diff options
context:
space:
mode:
authorLaszlo Ersek <lersek@redhat.com>2015-07-14 12:02:15 +0000
committerlersek <lersek@Edk2>2015-07-14 12:02:15 +0000
commit7ee9dc232114206bdfe9c9e5f4d8eb5ed1c917c9 (patch)
tree948b53146bfeb70b4329775fa67f07dad2c7dab5 /OvmfPkg
parentf5f9496c79e2b82002b32323f1d25ca6df6e7c8a (diff)
downloadedk2-platforms-7ee9dc232114206bdfe9c9e5f4d8eb5ed1c917c9.tar.xz
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
Diffstat (limited to 'OvmfPkg')
-rw-r--r--OvmfPkg/PciHostBridgeDxe/PciHostBridge.c54
1 files changed, 51 insertions, 3 deletions
diff --git a/OvmfPkg/PciHostBridgeDxe/PciHostBridge.c b/OvmfPkg/PciHostBridgeDxe/PciHostBridge.c
index 7ca0b6e19b..a5dbe57eb2 100644
--- a/OvmfPkg/PciHostBridgeDxe/PciHostBridge.c
+++ b/OvmfPkg/PciHostBridgeDxe/PciHostBridge.c
@@ -154,6 +154,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
@param ImageHandle Handle of driver image
@@ -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;
}