summaryrefslogtreecommitdiff
path: root/MdeModulePkg/Library
diff options
context:
space:
mode:
authorvanjeff <vanjeff@6f19259b-4bc3-4df7-8a09-765794883524>2008-01-16 09:04:43 +0000
committervanjeff <vanjeff@6f19259b-4bc3-4df7-8a09-765794883524>2008-01-16 09:04:43 +0000
commitb290614d493ff72fc2a4410d169314e501b7e79e (patch)
tree29942aad07199e63ad6ad7571f3fbbc76eba5fb3 /MdeModulePkg/Library
parent77aa51cd891f8fd9616aaeab3fe7e2331e5ea3ec (diff)
downloadedk2-b290614d493ff72fc2a4410d169314e501b7e79e.zip
edk2-b290614d493ff72fc2a4410d169314e501b7e79e.tar.gz
edk2-b290614d493ff72fc2a4410d169314e501b7e79e.tar.bz2
Port PlatformDriOverrideDxe into R9.
1. Add one OverrideVariableGuid in MdeModulePkg 2. Add one library PlatDriOverLib used by PlatformDriOverrideDxe. 3. Add PlatformDriOverrideDxe in MdeModulePkg git-svn-id: https://edk2.svn.sourceforge.net/svnroot/edk2/trunk/edk2@4557 6f19259b-4bc3-4df7-8a09-765794883524
Diffstat (limited to 'MdeModulePkg/Library')
-rw-r--r--MdeModulePkg/Library/DxePlatDriOverLib/DxePlatDriOverLib.inf65
-rw-r--r--MdeModulePkg/Library/DxePlatDriOverLib/DxePlatDriOverLib.msa94
-rw-r--r--MdeModulePkg/Library/DxePlatDriOverLib/PlatDriOver.h121
-rw-r--r--MdeModulePkg/Library/DxePlatDriOverLib/PlatDriOverLib.c1800
4 files changed, 2080 insertions, 0 deletions
diff --git a/MdeModulePkg/Library/DxePlatDriOverLib/DxePlatDriOverLib.inf b/MdeModulePkg/Library/DxePlatDriOverLib/DxePlatDriOverLib.inf
new file mode 100644
index 0000000..1ba2d78
--- /dev/null
+++ b/MdeModulePkg/Library/DxePlatDriOverLib/DxePlatDriOverLib.inf
@@ -0,0 +1,65 @@
+#/** @file
+# Component name for module PlatDriOverLib
+#
+# FIX ME!
+# Copyright (c) 2007, Intel Corporation. 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.
+#
+#
+#**/
+
+[Defines]
+ INF_VERSION = 0x00010005
+ BASE_NAME = PlatDriOverLib
+ FILE_GUID = 8bd8d711-2736-46d7-8c81-5de68e0a9e88
+ MODULE_TYPE = DXE_DRIVER
+ VERSION_STRING = 1.0
+ LIBRARY_CLASS = PlatDriOverLib
+ EDK_RELEASE_VERSION = 0x00020000
+ EFI_SPECIFICATION_VERSION = 0x00020000
+
+
+#
+# The following information is for reference only and not required by the build tools.
+#
+# VALID_ARCHITECTURES = IA32 X64 IPF EBC
+#
+
+[Sources.common]
+ PlatDriOver.h
+ PlatDriOverLib.c
+
+[Packages]
+ MdePkg/MdePkg.dec
+ MdeModulePkg/MdeModulePkg.dec
+
+[LibraryClasses]
+ DxeServicesTableLib
+ MemoryAllocationLib
+ DevicePathLib
+ BaseLib
+ UefiLib
+ UefiBootServicesTableLib
+ UefiRuntimeServicesTableLib
+ BaseMemoryLib
+ DebugLib
+ PrintLib
+
+[Guids]
+ gEfiOverrideVariableGuid # ALWAYS_CONSUMED
+
+[Protocols]
+ gEfiFirmwareVolume2ProtocolGuid # PROTOCOL ALWAYS_CONSUMED
+ gEfiLoadedImageProtocolGuid # PROTOCOL ALWAYS_CONSUMED
+ gEfiPlatformDriverOverrideProtocolGuid # PROTOCOL ALWAYS_CONSUMED
+ gEfiBusSpecificDriverOverrideProtocolGuid # PROTOCOL ALWAYS_CONSUMED
+ gEfiDriverBindingProtocolGuid # PROTOCOL ALWAYS_CONSUMED
+ gEfiDevicePathProtocolGuid # PROTOCOL ALWAYS_CONSUMED
+
diff --git a/MdeModulePkg/Library/DxePlatDriOverLib/DxePlatDriOverLib.msa b/MdeModulePkg/Library/DxePlatDriOverLib/DxePlatDriOverLib.msa
new file mode 100644
index 0000000..f01088e
--- /dev/null
+++ b/MdeModulePkg/Library/DxePlatDriOverLib/DxePlatDriOverLib.msa
@@ -0,0 +1,94 @@
+<ModuleSurfaceArea xmlns="http://www.TianoCore.org/2006/Edk2.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
+ <MsaHeader>
+ <ModuleName>PlatDriOverLib</ModuleName>
+ <ModuleType>DXE_DRIVER</ModuleType>
+ <GuidValue>8bd8d711-2736-46d7-8c81-5de68e0a9e88</GuidValue>
+ <Version>1.0</Version>
+ <Abstract>Component name for module PlatDriOverLib</Abstract>
+ <Description>FIX ME!</Description>
+ <Copyright>Copyright (c) 2007, Intel Corporation. All rights reserved.</Copyright>
+ <License>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.</License>
+ <Specification>FRAMEWORK_BUILD_PACKAGING_SPECIFICATION 0x00000052</Specification>
+ </MsaHeader>
+ <ModuleDefinitions>
+ <SupportedArchitectures>IA32 X64 IPF EBC</SupportedArchitectures>
+ <BinaryModule>false</BinaryModule>
+ <OutputFileBasename>PlatDriOverLib</OutputFileBasename>
+ </ModuleDefinitions>
+ <LibraryClassDefinitions>
+ <LibraryClass Usage="ALWAYS_PRODUCED">
+ <Keyword>PlatDriOverLib</Keyword>
+ </LibraryClass>
+ <LibraryClass Usage="ALWAYS_CONSUMED">
+ <Keyword>PrintLib</Keyword>
+ </LibraryClass>
+ <LibraryClass Usage="ALWAYS_CONSUMED">
+ <Keyword>DebugLib</Keyword>
+ </LibraryClass>
+ <LibraryClass Usage="ALWAYS_CONSUMED">
+ <Keyword>BaseMemoryLib</Keyword>
+ </LibraryClass>
+ <LibraryClass Usage="ALWAYS_CONSUMED">
+ <Keyword>UefiRuntimeServicesTableLib</Keyword>
+ </LibraryClass>
+ <LibraryClass Usage="ALWAYS_CONSUMED">
+ <Keyword>UefiBootServicesTableLib</Keyword>
+ </LibraryClass>
+ <LibraryClass Usage="ALWAYS_CONSUMED">
+ <Keyword>UefiLib</Keyword>
+ </LibraryClass>
+ <LibraryClass Usage="ALWAYS_CONSUMED">
+ <Keyword>BaseLib</Keyword>
+ </LibraryClass>
+ <LibraryClass Usage="ALWAYS_CONSUMED">
+ <Keyword>DevicePathLib</Keyword>
+ </LibraryClass>
+ <LibraryClass Usage="ALWAYS_CONSUMED">
+ <Keyword>MemoryAllocationLib</Keyword>
+ </LibraryClass>
+ <LibraryClass Usage="ALWAYS_CONSUMED">
+ <Keyword>DxeServicesTableLib</Keyword>
+ </LibraryClass>
+ </LibraryClassDefinitions>
+ <SourceFiles>
+ <Filename>PlatDriOverLib.c</Filename>
+ <Filename>PlatDriOver.h</Filename>
+ </SourceFiles>
+ <PackageDependencies>
+ <Package PackageGuid="5e0e9358-46b6-4ae2-8218-4ab8b9bbdcec"/>
+ <Package PackageGuid="68169ab0-d41b-4009-9060-292c253ac43d"/>
+ </PackageDependencies>
+ <Protocols>
+ <Protocol Usage="ALWAYS_CONSUMED">
+ <ProtocolCName>gEfiDevicePathProtocolGuid</ProtocolCName>
+ </Protocol>
+ <Protocol Usage="ALWAYS_CONSUMED">
+ <ProtocolCName>gEfiDriverBindingProtocolGuid</ProtocolCName>
+ </Protocol>
+ <Protocol Usage="ALWAYS_CONSUMED">
+ <ProtocolCName>gEfiBusSpecificDriverOverrideProtocolGuid</ProtocolCName>
+ </Protocol>
+ <Protocol Usage="ALWAYS_CONSUMED">
+ <ProtocolCName>gEfiPlatformDriverOverrideProtocolGuid</ProtocolCName>
+ </Protocol>
+ <Protocol Usage="ALWAYS_CONSUMED">
+ <ProtocolCName>gEfiLoadedImageProtocolGuid</ProtocolCName>
+ </Protocol>
+ <Protocol Usage="ALWAYS_CONSUMED">
+ <ProtocolCName>gEfiFirmwareVolumeProtocolGuid</ProtocolCName>
+ </Protocol>
+ <Protocol Usage="ALWAYS_CONSUMED">
+ <ProtocolCName>gEfiFirmwareVolume2ProtocolGuid</ProtocolCName>
+ </Protocol>
+ </Protocols>
+ <Externs>
+ <Specification>EFI_SPECIFICATION_VERSION 0x00020000</Specification>
+ <Specification>EDK_RELEASE_VERSION 0x00020000</Specification>
+ </Externs>
+</ModuleSurfaceArea> \ No newline at end of file
diff --git a/MdeModulePkg/Library/DxePlatDriOverLib/PlatDriOver.h b/MdeModulePkg/Library/DxePlatDriOverLib/PlatDriOver.h
new file mode 100644
index 0000000..331a9bc
--- /dev/null
+++ b/MdeModulePkg/Library/DxePlatDriOverLib/PlatDriOver.h
@@ -0,0 +1,121 @@
+/** @file
+
+Copyright (c) 2007, Intel Corporation
+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.
+
+Module Name:
+
+ PlatDriOver.h
+
+Abstract:
+
+
+**/
+
+#ifndef _PLAT_DRI_OVER_H_
+#define _PLAT_DRI_OVER_H_
+
+#include <PiDxe.h>
+
+#include <Protocol/FirmwareVolume2.h>
+#include <Protocol/LoadedImage.h>
+#include <Protocol/PlatformDriverOverride.h>
+#include <Protocol/DevicePath.h>
+#include <Protocol/DriverBinding.h>
+#include <Protocol/BusSpecificDriverOverride.h>
+
+#include <Library/BaseLib.h>
+#include <Library/DebugLib.h>
+#include <Library/BaseMemoryLib.h>
+#include <Library/PrintLib.h>
+#include <Library/UefiRuntimeServicesTableLib.h>
+#include <Library/UefiBootServicesTableLib.h>
+#include <Library/UefiLib.h>
+#include <Library/DevicePathLib.h>
+#include <Library/MemoryAllocationLib.h>
+#include <Library/DxeServicesTableLib.h>
+#include <Library/PlatDriOverLib.h>
+
+#include <Guid/OverrideVariable.h>
+
+
+#define PLATFORM_OVERRIDE_ITEM_SIGNATURE EFI_SIGNATURE_32('p','d','o','i')
+ typedef struct _PLATFORM_OVERRIDE_ITEM{
+ UINTN Signature;
+ LIST_ENTRY Link;
+ UINT32 DriverInfoNum;
+ EFI_DEVICE_PATH_PROTOCOL *ControllerDevicePath;
+ LIST_ENTRY DriverInfoList; //DRIVER_IMAGE_INFO List
+ EFI_HANDLE LastReturnedImageHandle;
+} PLATFORM_OVERRIDE_ITEM;
+
+#define DRIVER_IMAGE_INFO_SIGNATURE EFI_SIGNATURE_32('p','d','i','i')
+typedef struct _DRIVER_IMAGE_INFO{
+ UINTN Signature;
+ LIST_ENTRY Link;
+ EFI_HANDLE ImageHandle;
+ EFI_DEVICE_PATH_PROTOCOL *DriverImagePath;
+ BOOLEAN UnLoadable;
+ BOOLEAN UnStartable;
+} DRIVER_IMAGE_INFO;
+
+#define DEVICE_PATH_STACK_ITEM_SIGNATURE EFI_SIGNATURE_32('d','p','s','i')
+typedef struct _DEVICE_PATH_STACK_ITEM{
+ UINTN Signature;
+ LIST_ENTRY Link;
+ EFI_DEVICE_PATH_PROTOCOL *DevicePath;
+} DEVICE_PATH_STACK_ITEM;
+
+EFI_STATUS
+EFIAPI
+PushDevPathStack (
+ IN EFI_DEVICE_PATH_PROTOCOL *DevicePath
+ );
+
+EFI_STATUS
+EFIAPI
+PopDevPathStack (
+ OUT EFI_DEVICE_PATH_PROTOCOL **DevicePath
+ );
+
+BOOLEAN
+EFIAPI
+CheckExistInStack (
+ IN EFI_DEVICE_PATH_PROTOCOL *DevicePath
+ );
+
+EFI_STATUS
+EFIAPI
+UpdateFvFileDevicePath (
+ IN OUT EFI_DEVICE_PATH_PROTOCOL ** DevicePath,
+ IN EFI_GUID *FileGuid,
+ IN EFI_HANDLE CallerImageHandle
+ );
+
+VOID *
+GetVariableAndSize (
+ IN CHAR16 *Name,
+ IN EFI_GUID *VendorGuid,
+ OUT UINTN *VariableSize
+ );
+
+EFI_STATUS
+ConnectDevicePath (
+ IN EFI_DEVICE_PATH_PROTOCOL *DevicePathToConnect
+ );
+
+EFI_STATUS
+BdsConnectDeviceByPciClassType (
+ UINT8 ClassType,
+ UINT8 SubClassCode,
+ UINT8 PI,
+ BOOLEAN Recursive
+ );
+
+#endif
diff --git a/MdeModulePkg/Library/DxePlatDriOverLib/PlatDriOverLib.c b/MdeModulePkg/Library/DxePlatDriOverLib/PlatDriOverLib.c
new file mode 100644
index 0000000..d32715b
--- /dev/null
+++ b/MdeModulePkg/Library/DxePlatDriOverLib/PlatDriOverLib.c
@@ -0,0 +1,1800 @@
+/** @file
+
+Copyright (c) 2007, Intel Corporation
+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.
+
+Module Name:
+
+ PlatDriOverLib.c
+
+Abstract:
+
+
+**/
+
+#include "PlatDriOver.h"
+
+STATIC LIST_ENTRY mDevicePathStack = INITIALIZE_LIST_HEAD_VARIABLE (mDevicePathStack);
+
+
+/**
+ Install the Platform Driver Override Protocol, and ensure there is only one Platform Driver Override Protocol
+ in the system.
+
+ @param gPlatformDriverOverride PlatformDriverOverride protocol interface which
+ needs to be installed
+
+ @retval EFI_ALREADY_STARTED There has been a Platform Driver Override
+ Protocol in the system, cannot install it again.
+ @retval Other Returned by InstallProtocolInterface
+
+**/
+EFI_STATUS
+EFIAPI
+InstallPlatformDriverOverrideProtocol (
+ EFI_PLATFORM_DRIVER_OVERRIDE_PROTOCOL *gPlatformDriverOverride
+ )
+{
+ EFI_HANDLE Handle;
+ EFI_STATUS Status;
+ UINTN HandleCount;
+ EFI_HANDLE *HandleBuffer;
+
+ //
+ // There will be only one platform driver override protocol in the system
+ // If there is another out there, someone is trying to install us again,
+ // Fail that scenario.
+ //
+ Status = gBS->LocateHandleBuffer (
+ ByProtocol,
+ &gEfiPlatformDriverOverrideProtocolGuid,
+ NULL,
+ &HandleCount,
+ &HandleBuffer
+ );
+ //
+ // If there was no error, assume there is an installation and return error
+ //
+ if (!EFI_ERROR (Status)) {
+ if (HandleBuffer != NULL) {
+ gBS->FreePool (HandleBuffer);
+ }
+ return EFI_ALREADY_STARTED;
+ }
+
+ //
+ // Install platform driver override protocol
+ //
+ Handle = NULL;
+ Status = gBS->InstallProtocolInterface (
+ &Handle,
+ &gEfiPlatformDriverOverrideProtocolGuid,
+ EFI_NATIVE_INTERFACE,
+ gPlatformDriverOverride
+ );
+ return Status;
+}
+
+
+/**
+ Free all the mapping database memory resource and initialize the mapping list entry
+
+ @param MappingDataBase Mapping database list entry pointer
+
+ @retval EFI_INVALID_PARAMETER mapping database list entry is NULL
+ @retval EFI_SUCCESS Free success
+
+**/
+EFI_STATUS
+EFIAPI
+FreeMappingDatabase (
+ IN OUT LIST_ENTRY *MappingDataBase
+ )
+{
+ LIST_ENTRY *OverrideItemListIndex;
+ LIST_ENTRY *ImageInfoListIndex;
+ PLATFORM_OVERRIDE_ITEM *OverrideItem;
+ DRIVER_IMAGE_INFO *DriverImageInfo;
+
+ if (MappingDataBase == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ OverrideItemListIndex = MappingDataBase->ForwardLink;
+ while (OverrideItemListIndex != MappingDataBase){
+ OverrideItem = CR(OverrideItemListIndex, PLATFORM_OVERRIDE_ITEM, Link, PLATFORM_OVERRIDE_ITEM_SIGNATURE);
+ //
+ // Free PLATFORM_OVERRIDE_ITEM.ControllerDevicePath[]
+ //
+ if (OverrideItem->ControllerDevicePath != NULL){
+ FreePool(OverrideItem->ControllerDevicePath);
+ }
+
+ ImageInfoListIndex = OverrideItem->DriverInfoList.ForwardLink;
+ while (ImageInfoListIndex != &OverrideItem->DriverInfoList){
+ //
+ // Free all DRIVER_IMAGE_INFO.DriverImagePath[]
+ //
+ DriverImageInfo = CR(ImageInfoListIndex, DRIVER_IMAGE_INFO, Link, DRIVER_IMAGE_INFO_SIGNATURE);
+ if (DriverImageInfo->DriverImagePath != NULL) {
+ FreePool(DriverImageInfo->DriverImagePath);
+ }
+ //
+ // Free DRIVER_IMAGE_INFO itself
+ //
+ ImageInfoListIndex = ImageInfoListIndex->ForwardLink;
+ RemoveEntryList (&DriverImageInfo->Link);
+ FreePool (DriverImageInfo);
+ }
+ //
+ // Free PLATFORM_OVERRIDE_ITEM itself
+ //
+ OverrideItemListIndex = OverrideItemListIndex->ForwardLink;
+ RemoveEntryList (&OverrideItem->Link);
+ FreePool (OverrideItem);
+ }
+
+ InitializeListHead (MappingDataBase);
+ return EFI_SUCCESS;
+}
+
+
+/**
+ Read the environment variable(s) that contain the override mappings from Controller Device Path to
+ a set of Driver Device Paths, and create the mapping database in memory with those variable info.
+ VariableLayout{
+ //
+ // NotEnd indicate whether the variable is the last one, and has no subsequent variable need to load.
+ // Each variable has MaximumVariableSize limitation, so we maybe need multi variables to store
+ // large mapping infos.
+ // The variable(s) name rule is PlatDriOver, PlatDriOver1, PlatDriOver2, ....
+ //
+ UINT32 NotEnd;
+ //
+ // The entry which contains the mapping that Controller Device Path to a set of Driver Device Paths
+ // There are often multi mapping entries in a variable.
+ //
+ UINT32 SIGNATURE; //EFI_SIGNATURE_32('p','d','o','i')
+ UINT32 DriverNum;
+ EFI_DEVICE_PATH_PROTOCOL ControllerDevicePath[];
+ EFI_DEVICE_PATH_PROTOCOL DriverDevicePath[];
+ EFI_DEVICE_PATH_PROTOCOL DriverDevicePath[];
+ EFI_DEVICE_PATH_PROTOCOL DriverDevicePath[];
+ ......
+ UINT32 SIGNATURE;
+ UINT32 DriverNum;
+ EFI_DEVICE_PATH_PROTOCOL ControllerDevicePath[];
+ EFI_DEVICE_PATH_PROTOCOL DriverDevicePath[];
+ EFI_DEVICE_PATH_PROTOCOL DriverDevicePath[];
+ EFI_DEVICE_PATH_PROTOCOL DriverDevicePath[];
+ ......
+ }
+ typedef struct _PLATFORM_OVERRIDE_ITEM{
+ UINTN Signature; //EFI_SIGNATURE_32('p','d','o','i')
+ LIST_ENTRY Link;
+ UINT32 DriverInfoNum;
+ EFI_DEVICE_PATH_PROTOCOL *ControllerDevicePath;
+ LIST_ENTRY DriverInfoList; //DRIVER_IMAGE_INFO List
+ } PLATFORM_OVERRIDE_ITEM;
+ typedef struct _DRIVER_IMAGE_INFO{
+ UINTN Signature; //EFI_SIGNATURE_32('p','d','i','i')
+ LIST_ENTRY Link;
+ EFI_HANDLE ImageHandle;
+ EFI_DEVICE_PATH_PROTOCOL *DriverImagePath;
+ BOOLEAN UnLoadable;
+ BOOLEAN UnStartable;
+ } DRIVER_IMAGE_INFO;
+
+ @param MappingDataBase Mapping database list entry pointer
+
+ @retval EFI_INVALID_PARAMETER MappingDataBase pointer is null
+ @retval EFI_NOT_FOUND Cannot find the 'PlatDriOver' NV variable
+ @retval EFI_VOLUME_CORRUPTED The found NV variable is corrupted
+ @retval EFI_SUCCESS Create the mapping database in memory
+ successfully
+
+**/
+EFI_STATUS
+EFIAPI
+InitOverridesMapping (
+ OUT LIST_ENTRY *MappingDataBase
+ )
+{
+ UINTN BufferSize;
+ VOID *VariableBuffer;
+ UINT8 *VariableIndex;
+ UINTN VariableNum;
+ CHAR16 OverrideVariableName[40];
+ UINT32 NotEnd;
+ UINT32 DriverNumber;
+ PLATFORM_OVERRIDE_ITEM *OverrideItem;
+ DRIVER_IMAGE_INFO *DriverImageInfo;
+ BOOLEAN Corrupted;
+ UINT32 Signature;
+ EFI_DEVICE_PATH_PROTOCOL *ControllerDevicePath;
+ EFI_DEVICE_PATH_PROTOCOL *DriverDevicePath;
+ UINTN Index;
+
+ if (MappingDataBase == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ VariableNum = 0;
+ Corrupted = FALSE;
+ //
+ // Check the environment variable(s) that contain the override mappings .
+ //
+ VariableBuffer = GetVariableAndSize (L"PlatDriOver", &gEfiOverrideVariableGuid, &BufferSize);
+ ASSERT ((UINTN) VariableBuffer % sizeof(UINTN) == 0);
+ VariableNum ++;
+ if (VariableBuffer == NULL) {
+ return EFI_NOT_FOUND;
+ }
+
+ do {
+ VariableIndex = VariableBuffer;
+ NotEnd = *(UINT32*) VariableIndex;
+ VariableIndex = VariableIndex + sizeof (UINT32);
+ while (VariableIndex < ((UINT8 *)VariableBuffer + BufferSize)) {
+ OverrideItem = AllocateZeroPool (sizeof (PLATFORM_OVERRIDE_ITEM));
+ ASSERT (OverrideItem != NULL);
+ OverrideItem->Signature = PLATFORM_OVERRIDE_ITEM_SIGNATURE;
+ InitializeListHead (&OverrideItem->DriverInfoList);
+ //
+ // Check SIGNATURE
+ //
+ Signature = *(UINT32 *) VariableIndex;
+ VariableIndex = VariableIndex + sizeof (UINT32);
+ if (Signature != PLATFORM_OVERRIDE_ITEM_SIGNATURE) {
+ FreePool (OverrideItem);
+ Corrupted = TRUE;
+ break;
+ }
+ //
+ // Get DriverNum
+ //
+ DriverNumber = *(UINT32*) VariableIndex;
+ OverrideItem->DriverInfoNum = DriverNumber;
+ VariableIndex = VariableIndex + sizeof (UINT32);
+ //
+ // Get ControllerDevicePath[]
+ //
+ ControllerDevicePath = (EFI_DEVICE_PATH_PROTOCOL *) VariableIndex;
+ OverrideItem->ControllerDevicePath = DuplicateDevicePath (ControllerDevicePath);
+ VariableIndex = VariableIndex + GetDevicePathSize (ControllerDevicePath);
+ //
+ // Align the VariableIndex since the controller device path may not be aligned, refer to the SaveOverridesMapping()
+ //
+ VariableIndex += ((sizeof(UINT32) - ((UINTN) (VariableIndex))) & (sizeof(UINT32) - 1));
+
+ //
+ // Get all DriverDevicePath[]
+ //
+ for (Index = 0; Index < DriverNumber; Index++) {
+ DriverImageInfo = AllocateZeroPool (sizeof (DRIVER_IMAGE_INFO));
+ ASSERT (DriverImageInfo != NULL);
+ DriverImageInfo->Signature = DRIVER_IMAGE_INFO_SIGNATURE;
+
+ DriverDevicePath = (EFI_DEVICE_PATH_PROTOCOL *) VariableIndex;
+ DriverImageInfo->DriverImagePath = DuplicateDevicePath (DriverDevicePath);
+ VariableIndex = VariableIndex + GetDevicePathSize (DriverDevicePath);
+ //
+ // Align the VariableIndex since the driver image device path may not be aligned, refer to the SaveOverridesMapping()
+ //
+ VariableIndex += ((sizeof(UINT32) - ((UINTN) (VariableIndex))) & (sizeof(UINT32) - 1));
+
+ InsertTailList (&OverrideItem->DriverInfoList, &DriverImageInfo->Link);
+ }
+ InsertTailList (MappingDataBase, &OverrideItem->Link);
+ }
+
+ FreePool (VariableBuffer);
+ if (Corrupted) {
+ FreeMappingDatabase (MappingDataBase);
+ return EFI_VOLUME_CORRUPTED;
+ }
+
+ //
+ // If has other variable(PlatDriOver1, PlatDriOver2, PlatDriOver3.....), get them.
+ // NotEnd indicate whether current variable is the end variable.
+ //
+ if (NotEnd != 0) {
+ UnicodeSPrint (OverrideVariableName, sizeof (OverrideVariableName), L"PlatDriOver%d", VariableNum);
+ VariableBuffer = GetVariableAndSize (OverrideVariableName, &gEfiOverrideVariableGuid, &BufferSize);
+ ASSERT ((UINTN) VariableBuffer % sizeof(UINTN) == 0);
+ VariableNum ++;
+ if (VariableBuffer == NULL) {
+ FreeMappingDatabase (MappingDataBase);
+ return EFI_VOLUME_CORRUPTED;
+ }
+ }
+
+ } while (NotEnd != 0);
+
+ return EFI_SUCCESS;
+}
+
+
+/**
+ Calculate the needed size in NV variable for recording a specific PLATFORM_OVERRIDE_ITEM info
+
+ @param OverrideItemListIndex a list entry point to a specific
+ PLATFORM_OVERRIDE_ITEM
+
+ @return The needed size number
+
+**/
+UINTN
+EFIAPI
+GetOneItemNeededSize (
+ IN LIST_ENTRY *OverrideItemListIndex
+ )
+{
+ UINTN NeededSize;
+ PLATFORM_OVERRIDE_ITEM *OverrideItem;
+ LIST_ENTRY *ImageInfoListIndex;
+ DRIVER_IMAGE_INFO *DriverImageInfo;
+
+
+ NeededSize = 0;
+ OverrideItem = CR(OverrideItemListIndex, PLATFORM_OVERRIDE_ITEM, Link, PLATFORM_OVERRIDE_ITEM_SIGNATURE);
+ NeededSize += sizeof (UINT32); //UINT32 SIGNATURE;
+ NeededSize += sizeof (UINT32); //UINT32 DriverNum;
+ NeededSize += GetDevicePathSize (OverrideItem->ControllerDevicePath); // ControllerDevicePath
+ //
+ // Align the controller device path
+ //
+ NeededSize += ((sizeof(UINT32) - ((UINTN) GetDevicePathSize (OverrideItem->ControllerDevicePath))) \
+ & (sizeof(UINT32) - 1));
+ ImageInfoListIndex = OverrideItem->DriverInfoList.ForwardLink;
+ while (ImageInfoListIndex != &OverrideItem->DriverInfoList){
+ DriverImageInfo = CR(ImageInfoListIndex, DRIVER_IMAGE_INFO, Link, DRIVER_IMAGE_INFO_SIGNATURE);
+ NeededSize += GetDevicePathSize (DriverImageInfo->DriverImagePath); //DriverDevicePath
+ //
+ // Align the driver image device path
+ //
+ NeededSize += ((sizeof(UINT32) - ((UINTN) GetDevicePathSize (DriverImageInfo->DriverImagePath))) \
+ & (sizeof(UINT32) - 1));
+ ImageInfoListIndex = ImageInfoListIndex->ForwardLink;
+ }
+
+ return NeededSize;
+}
+
+
+
+/**
+ Save the memory mapping database into NV environment variable(s)
+
+ @param MappingDataBase Mapping database list entry pointer
+
+ @retval EFI_INVALID_PARAMETER MappingDataBase pointer is null
+ @retval EFI_SUCCESS Save memory mapping database successfully
+
+**/
+EFI_STATUS
+EFIAPI
+SaveOverridesMapping (
+ IN LIST_ENTRY *MappingDataBase
+ )
+{
+ EFI_STATUS Status;
+ VOID *VariableBuffer;
+ UINT8 *VariableIndex;
+ UINTN NumIndex;
+ CHAR16 OverrideVariableName[40];
+ UINT32 NotEnd;
+ PLATFORM_OVERRIDE_ITEM *OverrideItem;
+ DRIVER_IMAGE_INFO *DriverImageInfo;
+ LIST_ENTRY *OverrideItemListIndex;
+ LIST_ENTRY *ItemIndex;
+ LIST_ENTRY *ImageInfoListIndex;
+ UINTN VariableNeededSize;
+ UINTN SavedSize;
+ UINT64 MaximumVariableStorageSize;
+ UINT64 RemainingVariableStorageSize;
+ UINT64 MaximumVariableSize;
+ UINTN OneItemNeededSize;
+
+ if (MappingDataBase == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if (MappingDataBase->ForwardLink == MappingDataBase) {
+ Status = DeleteOverridesVariables ();
+ return EFI_SUCCESS;
+ }
+
+ //
+ // Get the the maximum size of an individual EFI variable in current system
+ //
+ gRT->QueryVariableInfo (
+ EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_NON_VOLATILE,
+ &MaximumVariableStorageSize,
+ &RemainingVariableStorageSize,
+ &MaximumVariableSize
+ );
+
+ NumIndex = 0;
+ OverrideItemListIndex = MappingDataBase->ForwardLink;
+ while (OverrideItemListIndex != MappingDataBase) {
+ //
+ // Try to find the most proper variable size which <= MaximumVariableSize, but can contain mapping info as much as possible
+ //
+ VariableNeededSize = 0;
+ VariableNeededSize += sizeof (UINT32); //BOOLEAN NotEnd;
+ ItemIndex = OverrideItemListIndex;
+ NotEnd = FALSE;
+
+ while (ItemIndex != MappingDataBase){
+ OneItemNeededSize = GetOneItemNeededSize (ItemIndex);
+ if ((VariableNeededSize +
+ OneItemNeededSize +
+ sizeof (VARIABLE_HEADER) +
+ StrSize (L"PlatDriOver ")
+ ) >= MaximumVariableSize
+ ) {
+ NotEnd = TRUE;
+ break;
+ }
+
+ VariableNeededSize += GetOneItemNeededSize (ItemIndex);
+ ItemIndex = ItemIndex->ForwardLink;
+ }
+
+ if (NotEnd) {
+ if (VariableNeededSize == sizeof (UINT32)) {
+ //
+ // If an individual EFI variable cannot contain a single Item, return error
+ //
+ return EFI_OUT_OF_RESOURCES;
+ }
+ }
+
+ //
+ // VariableNeededSize is the most proper variable size, allocate variable buffer
+ // ItemIndex now points to the next PLATFORM_OVERRIDE_ITEM which is not covered by VariableNeededSize
+ //
+ VariableBuffer = AllocateZeroPool (VariableNeededSize);
+ ASSERT ((UINTN) VariableBuffer % sizeof(UINTN) == 0);
+
+ //
+ // Fill the variable buffer according to MappingDataBase
+ //
+ SavedSize = 0;
+ VariableIndex = VariableBuffer;
+ *(UINT32 *) VariableIndex = NotEnd;
+ VariableIndex += sizeof (UINT32); // pass NoEnd
+ SavedSize += sizeof (UINT32);
+ //
+ // ItemIndex points to the next PLATFORM_OVERRIDE_ITEM which is not covered by VariableNeededSize
+ //
+ while (OverrideItemListIndex != ItemIndex){
+ *(UINT32 *) VariableIndex = PLATFORM_OVERRIDE_ITEM_SIGNATURE;
+ VariableIndex += sizeof (UINT32); // pass SIGNATURE
+ SavedSize += sizeof (UINT32);
+
+ OverrideItem = CR(OverrideItemListIndex, PLATFORM_OVERRIDE_ITEM, Link, PLATFORM_OVERRIDE_ITEM_SIGNATURE);
+ *(UINT32 *) VariableIndex = OverrideItem->DriverInfoNum;
+ VariableIndex += sizeof (UINT32); // pass DriverNum
+ SavedSize += sizeof (UINT32);
+
+ CopyMem (VariableIndex, OverrideItem->ControllerDevicePath, GetDevicePathSize (OverrideItem->ControllerDevicePath));
+ VariableIndex += GetDevicePathSize (OverrideItem->ControllerDevicePath); // pass ControllerDevicePath
+ SavedSize += GetDevicePathSize (OverrideItem->ControllerDevicePath);
+
+ //
+ // Align the VariableIndex since the controller device path may not be aligned
+ //
+ SavedSize += ((sizeof(UINT32) - ((UINTN) (VariableIndex))) & (sizeof(UINT32) - 1));
+ VariableIndex += ((sizeof(UINT32) - ((UINTN) (VariableIndex))) & (sizeof(UINT32) - 1));
+
+ ImageInfoListIndex = OverrideItem->DriverInfoList.ForwardLink;
+ while (ImageInfoListIndex != &OverrideItem->DriverInfoList){
+ DriverImageInfo = CR(ImageInfoListIndex, DRIVER_IMAGE_INFO, Link, DRIVER_IMAGE_INFO_SIGNATURE);
+ CopyMem (VariableIndex, DriverImageInfo->DriverImagePath, GetDevicePathSize (DriverImageInfo->DriverImagePath));
+ VariableIndex += GetDevicePathSize (DriverImageInfo->DriverImagePath); // pass DriverImageDevicePath
+ SavedSize += GetDevicePathSize (DriverImageInfo->DriverImagePath);
+ //
+ // Align the VariableIndex since the driver image device path may not be aligned
+ //
+ SavedSize += ((sizeof(UINT32) - ((UINTN) (VariableIndex))) & (sizeof(UINT32) - 1));
+ VariableIndex += ((sizeof(UINT32) - ((UINTN) (VariableIndex))) & (sizeof(UINT32) - 1));
+ ImageInfoListIndex = ImageInfoListIndex->ForwardLink;
+ }
+
+ OverrideItemListIndex = OverrideItemListIndex->ForwardLink;
+ }
+
+ ASSERT (SavedSize == VariableNeededSize);
+
+ if (NumIndex == 0) {
+ UnicodeSPrint (OverrideVariableName, sizeof (OverrideVariableName), L"PlatDriOver");
+ } else {
+ UnicodeSPrint (OverrideVariableName, sizeof (OverrideVariableName), L"PlatDriOver%d", NumIndex );
+ }
+
+ Status = gRT->SetVariable (
+ OverrideVariableName,
+ &gEfiOverrideVariableGuid,
+ EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_NON_VOLATILE,
+ VariableNeededSize,
+ VariableBuffer
+ );
+ ASSERT (!EFI_ERROR(Status));
+
+ NumIndex ++;
+ FreePool (VariableBuffer);
+ }
+
+ return EFI_SUCCESS;
+}
+
+
+/**
+ Retrieves the image handle of the platform override driver for a controller in the system from the memory mapping database.
+
+ @param This A pointer to the
+ EFI_PLATFORM_DRIVER_OVERRIDE_PROTOCOL instance.
+ @param ControllerHandle The device handle of the controller to check if
+ a driver override exists.
+ @param DriverImageHandle On output, a pointer to the next driver handle.
+ Passing in a pointer to NULL, will return the
+ first driver handle for ControllerHandle.
+ @param MappingDataBase MappingDataBase - Mapping database list entry
+ pointer
+ @param CallerImageHandle The caller driver's image handle, for
+ UpdateFvFileDevicePath use.
+
+ @retval EFI_INVALID_PARAMETER The handle specified by ControllerHandle is not
+ a valid handle. Or DriverImagePath is not a
+ device path that was returned on a previous call
+ to GetDriverPath().
+ @retval EFI_NOT_FOUND A driver override for ControllerHandle was not
+ found.
+ @retval EFI_UNSUPPORTED The operation is not supported.
+ @retval EFI_SUCCESS The driver override for ControllerHandle was
+ returned in DriverImagePath.
+
+**/
+EFI_STATUS
+EFIAPI
+GetDriverFromMapping (
+ IN EFI_PLATFORM_DRIVER_OVERRIDE_PROTOCOL * This,
+ IN EFI_HANDLE ControllerHandle,
+ IN OUT EFI_HANDLE * DriverImageHandle,
+ IN LIST_ENTRY * MappingDataBase,
+ IN EFI_HANDLE CallerImageHandle
+ )
+{
+ EFI_STATUS Status;
+ EFI_DEVICE_PATH_PROTOCOL *ControllerDevicePath;
+ BOOLEAN ControllerFound;
+ BOOLEAN ImageFound;
+ EFI_HANDLE *ImageHandleBuffer;
+ UINTN ImageHandleCount;
+ UINTN Index;
+ EFI_LOADED_IMAGE_PROTOCOL *LoadedImage;
+ EFI_DRIVER_BINDING_PROTOCOL *DriverBinding;
+ BOOLEAN FoundLastReturned;
+ PLATFORM_OVERRIDE_ITEM *OverrideItem;
+ DRIVER_IMAGE_INFO *DriverImageInfo;
+ LIST_ENTRY *OverrideItemListIndex;
+ LIST_ENTRY *ImageInfoListIndex;
+ EFI_DEVICE_PATH_PROTOCOL *TempDriverImagePath;
+ EFI_HANDLE ImageHandle;
+ EFI_HANDLE Handle;
+ EFI_DEVICE_PATH_PROTOCOL *LoadedImageHandleDevicePath;
+ EFI_DEVICE_PATH_PROTOCOL *TatalFilePath;
+ EFI_BUS_SPECIFIC_DRIVER_OVERRIDE_PROTOCOL *BusSpecificDriverOverride;
+ UINTN DevicePathSize;
+
+ //
+ // Check that ControllerHandle is a valid handle
+ //
+ if (ControllerHandle == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ Status = gBS->HandleProtocol (
+ ControllerHandle,
+ &gEfiDevicePathProtocolGuid,
+ (VOID **) &ControllerDevicePath
+ );
+ if (EFI_ERROR (Status) || ControllerDevicePath == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ //
+ // Search ControllerDevicePath in MappingDataBase
+ //
+ OverrideItem = NULL;
+ ControllerFound = FALSE;
+ OverrideItemListIndex = MappingDataBase->ForwardLink;
+ while (OverrideItemListIndex != MappingDataBase){
+ OverrideItem = CR(OverrideItemListIndex, PLATFORM_OVERRIDE_ITEM, Link, PLATFORM_OVERRIDE_ITEM_SIGNATURE);
+ DevicePathSize = GetDevicePathSize (ControllerDevicePath);
+ if (DevicePathSize == GetDevicePathSize (OverrideItem->ControllerDevicePath)) {
+ if (CompareMem (
+ ControllerDevicePath,
+ OverrideItem->ControllerDevicePath,
+ GetDevicePathSize (OverrideItem->ControllerDevicePath)
+ ) == 0
+ ) {
+ ControllerFound = TRUE;
+ break;
+ }
+
+ }
+ OverrideItemListIndex = OverrideItemListIndex->ForwardLink;
+ }
+
+ if (!ControllerFound) {
+ return EFI_NOT_FOUND;
+ }
+ //
+ // Passing in a pointer to NULL, will return the first driver device path for ControllerHandle.
+ // Check whether the driverImagePath is not a device path that was returned on a previous call to GetDriverPath().
+ //
+ if (*DriverImageHandle != NULL) {
+ if (*DriverImageHandle != OverrideItem->LastReturnedImageHandle) {
+ return EFI_INVALID_PARAMETER;
+ }
+ }
+ //
+ // The GetDriverPath() maybe called recursively, because it use ConnectDevicePath() internally,
+ // so should check whether there is a dead loop.
+ // Here use a controller device path stack to record all processed controller device path during a GetDriverPath() call,
+ // and check the controller device path whether appear again during the GetDriverPath() call.
+ //
+ if (CheckExistInStack(OverrideItem->ControllerDevicePath)) {
+ //
+ // There is a dependecy dead loop if the ControllerDevicePath appear in stack twice
+ //
+ return EFI_UNSUPPORTED;
+ }
+ PushDevPathStack (OverrideItem->ControllerDevicePath);
+
+ //
+ // Check every override driver, try to load and start them
+ //
+ ImageInfoListIndex = OverrideItem->DriverInfoList.ForwardLink;
+ while (ImageInfoListIndex != &OverrideItem->DriverInfoList){
+ DriverImageInfo = CR(ImageInfoListIndex, DRIVER_IMAGE_INFO, Link, DRIVER_IMAGE_INFO_SIGNATURE);
+ if (DriverImageInfo->ImageHandle == NULL) {
+ //
+ // Skip if the image is unloadable or unstartable
+ //
+ if ((!DriverImageInfo->UnLoadable) && ((!DriverImageInfo->UnStartable))) {
+ TempDriverImagePath = DriverImageInfo->DriverImagePath;
+ //
+ // If the image device path contain a FV node, check the Fv file device path is valid. If it is invalid, try to return the valid device path.
+ // FV address maybe changes for memory layout adjust from time to time, use this funciton could promise the Fv file device path is right.
+ //
+ Status = UpdateFvFileDevicePath (&TempDriverImagePath, NULL, CallerImageHandle);
+ if (!EFI_ERROR (Status)) {
+ FreePool(DriverImageInfo->DriverImagePath);
+ DriverImageInfo->DriverImagePath = TempDriverImagePath;
+ }
+ //
+ // Get all Loaded Image protocol to check whether the driver image has been loaded and started
+ //
+ ImageFound = FALSE;
+ ImageHandleCount = 0;
+ Status = gBS->LocateHandleBuffer (
+ ByProtocol,
+ &gEfiLoadedImageProtocolGuid,
+ NULL,
+ &ImageHandleCount,
+ &ImageHandleBuffer
+ );
+ if (EFI_ERROR (Status) || (ImageHandleCount == 0)) {
+ return EFI_NOT_FOUND;
+ }
+
+ for(Index = 0; Index < ImageHandleCount; Index ++) {
+ Status = gBS->HandleProtocol (
+ ImageHandleBuffer[Index],
+ &gEfiLoadedImageProtocolGuid,
+ (VOID **) &LoadedImage
+ );
+ if (EFI_ERROR (Status)) {
+ continue;
+ }
+
+ //
+ // Get the driver image total file path
+ //
+ LoadedImageHandleDevicePath = NULL;
+ Status = gBS->HandleProtocol (
+ LoadedImage->DeviceHandle,
+ &gEfiDevicePathProtocolGuid,
+ (VOID **) &LoadedImageHandleDevicePath
+ );
+ if (EFI_ERROR (Status)) {
+ //
+ // Maybe Not all LoadedImage->DeviceHandle has valid value. Skip the invalid image.
+ //
+ continue;
+ }
+
+ TatalFilePath = AppendDevicePath (LoadedImageHandleDevicePath, LoadedImage->FilePath);
+
+ DevicePathSize = GetDevicePathSize (DriverImageInfo->DriverImagePath);
+ if (DevicePathSize == GetDevicePathSize (TatalFilePath)) {
+ if (CompareMem (
+ DriverImageInfo->DriverImagePath,
+ TatalFilePath,
+ GetDevicePathSize (TatalFilePath)
+ ) == 0
+ ) {
+ ImageFound = TRUE;
+ break;
+ }
+ }
+ }
+
+ if (ImageFound) {
+ Status = gBS->HandleProtocol (
+ ImageHandleBuffer[Index],
+ &gEfiDriverBindingProtocolGuid,
+ (VOID **) &DriverBinding
+ );
+ ASSERT (!EFI_ERROR (Status));
+ DriverImageInfo->ImageHandle = ImageHandleBuffer[Index];
+ } else {
+ //
+ // The driver image has not been loaded and started, need try to load and start it now
+ // Try to connect all device in the driver image path
+ //
+ Status = ConnectDevicePath (DriverImageInfo->DriverImagePath);
+ //
+ // check whether it points to a PCI Option Rom image, and try to use bus override protocol to get its first option rom image driver
+ //
+ TempDriverImagePath = DriverImageInfo->DriverImagePath;
+ gBS->LocateDevicePath (&gEfiDevicePathProtocolGuid, &TempDriverImagePath, &Handle);
+ //
+ // Get the Bus Specific Driver Override Protocol instance on the Controller Handle
+ //
+ Status = gBS->HandleProtocol(
+ Handle,
+ &gEfiBusSpecificDriverOverrideProtocolGuid,
+ (VOID **) &BusSpecificDriverOverride
+ );
+ if (!EFI_ERROR (Status) && (BusSpecificDriverOverride != NULL)) {
+ ImageHandle = NULL;
+ Status = BusSpecificDriverOverride->GetDriver (
+ BusSpecificDriverOverride,
+ &ImageHandle
+ );
+ if (!EFI_ERROR (Status)) {
+ Status = gBS->HandleProtocol (
+ ImageHandle,
+ &gEfiDriverBindingProtocolGuid,
+ (VOID **) &DriverBinding
+ );
+ ASSERT (!EFI_ERROR (Status));
+ DriverImageInfo->ImageHandle = ImageHandle;
+ }
+ }
+ //
+ // Skip if any device cannot be connected now, future passes through GetDriver() may be able to load that driver.
+ // Only file path media or FwVol Device Path Node remain if all device is connected
+ //
+ TempDriverImagePath = DriverImageInfo->DriverImagePath;
+ gBS->LocateDevicePath (&gEfiDevicePathProtocolGuid, &TempDriverImagePath, &Handle);
+ if (((DevicePathType (TempDriverImagePath) == MEDIA_DEVICE_PATH) &&
+ (DevicePathSubType (TempDriverImagePath) == MEDIA_FILEPATH_DP)) ||
+ (EfiGetNameGuidFromFwVolDevicePathNode ((MEDIA_FW_VOL_FILEPATH_DEVICE_PATH *) TempDriverImagePath) != NULL)
+ ) {
+ //
+ // Try to load the driver
+ //
+ TempDriverImagePath = DriverImageInfo->DriverImagePath;
+ Status = gBS->LoadImage (
+ FALSE,
+ CallerImageHandle,
+ TempDriverImagePath,
+ NULL,
+ 0,
+ &ImageHandle
+ );
+ if (!EFI_ERROR (Status)) {
+ //
+ // Try to start the driver
+ //
+ Status = gBS->StartImage (ImageHandle, NULL, NULL);
+ if (EFI_ERROR (Status)){
+ DriverImageInfo->UnStartable = TRUE;
+ DriverImageInfo->ImageHandle = NULL;
+ } else {
+ Status = gBS->HandleProtocol (
+ ImageHandle,
+ &gEfiDriverBindingProtocolGuid,
+ (VOID **) &DriverBinding
+ );
+ ASSERT (!EFI_ERROR (Status));
+ DriverImageInfo->ImageHandle = ImageHandle;
+ }
+ } else {
+ DriverImageInfo->UnLoadable = TRUE;
+ DriverImageInfo->ImageHandle = NULL;
+ }
+ }
+ }
+ FreePool (ImageHandleBuffer);
+ }
+ }
+ ImageInfoListIndex = ImageInfoListIndex->ForwardLink;
+ }
+ //
+ // Finish try to load and start the override driver of a controller, popup the controller's device path
+ //
+ PopDevPathStack (NULL);
+
+ //
+ // return the DriverImageHandle for ControllerHandle
+ //
+ FoundLastReturned = FALSE;
+ ImageInfoListIndex = OverrideItem->DriverInfoList.ForwardLink;
+ while (ImageInfoListIndex != &OverrideItem->DriverInfoList){
+ DriverImageInfo = CR(ImageInfoListIndex, DRIVER_IMAGE_INFO, Link, DRIVER_IMAGE_INFO_SIGNATURE);
+ if (DriverImageInfo->ImageHandle != NULL) {
+ if ((*DriverImageHandle == NULL) || FoundLastReturned) {
+ OverrideItem->LastReturnedImageHandle = DriverImageInfo->ImageHandle;
+ *DriverImageHandle = DriverImageInfo->ImageHandle;
+ return EFI_SUCCESS;
+ } else if (*DriverImageHandle == DriverImageInfo->ImageHandle){
+ FoundLastReturned = TRUE;
+ }
+ }
+ ImageInfoListIndex = ImageInfoListIndex->ForwardLink;
+ }
+
+ return EFI_NOT_FOUND;
+}
+
+
+/**
+ Check mapping database whether already has the mapping info which
+ records the input Controller to input DriverImage.
+ If has, the controller's total override driver number and input DriverImage's order number is return.
+
+ @param ControllerDevicePath The controller device path need to add a
+ override driver image item
+ @param DriverImageDevicePath The driver image device path need to be insert
+ @param MappingDataBase Mapping database list entry pointer
+ @param DriverInfoNum the controller's total override driver number
+ @param DriverImageNO The inserted order number
+
+ @return EFI_INVALID_PARAMETER
+ @return EFI_NOT_FOUND
+ @return EFI_SUCCESS
+
+**/
+EFI_STATUS
+EFIAPI
+CheckMapping (
+ IN EFI_DEVICE_PATH_PROTOCOL *ControllerDevicePath,
+ IN EFI_DEVICE_PATH_PROTOCOL *DriverImageDevicePath,
+ IN LIST_ENTRY * MappingDataBase,
+ OUT UINT32 *DriverInfoNum,
+ OUT UINT32 *DriverImageNO
+ )
+{
+ LIST_ENTRY *OverrideItemListIndex;
+ PLATFORM_OVERRIDE_ITEM *OverrideItem;
+ LIST_ENTRY *ImageInfoListIndex;
+ DRIVER_IMAGE_INFO *DriverImageInfo;
+ BOOLEAN Found;
+ UINT32 ImageNO;
+ UINTN DevicePathSize;
+
+ //
+ // Check that ControllerHandle is a valid handle
+ //
+ if (ControllerDevicePath == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+ if (MappingDataBase == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+ //
+ // Search ControllerDevicePath in MappingDataBase
+ //
+ Found = FALSE;
+ OverrideItem = NULL;
+ OverrideItemListIndex = MappingDataBase->ForwardLink;
+ while (OverrideItemListIndex != MappingDataBase){
+ OverrideItem = CR(OverrideItemListIndex, PLATFORM_OVERRIDE_ITEM, Link, PLATFORM_OVERRIDE_ITEM_SIGNATURE);
+ DevicePathSize = GetDevicePathSize (ControllerDevicePath);
+ if (DevicePathSize == GetDevicePathSize (OverrideItem->ControllerDevicePath)) {
+ if (CompareMem (
+ ControllerDevicePath,
+ OverrideItem->ControllerDevicePath,
+ GetDevicePathSize (OverrideItem->ControllerDevicePath)
+ ) == 0
+ ) {
+ Found = TRUE;
+ break;
+ }
+ }
+ OverrideItemListIndex = OverrideItemListIndex->ForwardLink;
+ }
+
+ if (!Found) {
+ return EFI_NOT_FOUND;
+ }
+
+ ASSERT (OverrideItem->DriverInfoNum != 0);
+ if (DriverInfoNum != NULL) {
+ *DriverInfoNum = OverrideItem->DriverInfoNum;
+ }
+
+
+ if (DriverImageDevicePath == NULL) {
+ return EFI_SUCCESS;
+ }
+ //
+ // return the DriverImageHandle for ControllerHandle
+ //
+ ImageNO = 0;
+ Found = FALSE;
+ ImageInfoListIndex = OverrideItem->DriverInfoList.ForwardLink;
+ while (ImageInfoListIndex != &OverrideItem->DriverInfoList){
+ DriverImageInfo = CR(ImageInfoListIndex, DRIVER_IMAGE_INFO, Link, DRIVER_IMAGE_INFO_SIGNATURE);
+ ImageNO++;
+ DevicePathSize = GetDevicePathSize (DriverImageDevicePath);
+ if (DevicePathSize == GetDevicePathSize (DriverImageInfo->DriverImagePath)) {
+ if (CompareMem (
+ DriverImageDevicePath,
+ DriverImageInfo->DriverImagePath,
+ GetDevicePathSize (DriverImageInfo->DriverImagePath)
+ ) == 0
+ ) {
+ Found = TRUE;
+ break;
+ }
+ }
+ ImageInfoListIndex = ImageInfoListIndex->ForwardLink;
+ }
+
+ if (!Found) {
+ return EFI_NOT_FOUND;
+ } else {
+ if (DriverImageNO != NULL) {
+ *DriverImageNO = ImageNO;
+ }
+ return EFI_SUCCESS;
+ }
+
+}
+
+
+/**
+ Insert a driver image as a controller's override driver into the mapping database.
+ The driver image's order number is indicated by DriverImageNO.
+
+ @param ControllerDevicePath The controller device path need to add a
+ override driver image item
+ @param DriverImageDevicePath The driver image device path need to be insert
+ @param MappingDataBase Mapping database list entry pointer
+ @param DriverImageNO The inserted order number
+
+ @return EFI_INVALID_PARAMETER
+ @return EFI_ALREADY_STARTED
+ @return EFI_SUCCESS
+
+**/
+EFI_STATUS
+EFIAPI
+InsertDriverImage (
+ IN EFI_DEVICE_PATH_PROTOCOL *ControllerDevicePath,
+ IN EFI_DEVICE_PATH_PROTOCOL *DriverImageDevicePath,
+ IN LIST_ENTRY *MappingDataBase,
+ IN UINT32 DriverImageNO
+ )
+{
+ EFI_STATUS Status;
+ LIST_ENTRY *OverrideItemListIndex;
+ PLATFORM_OVERRIDE_ITEM *OverrideItem;
+ LIST_ENTRY *ImageInfoListIndex;
+ DRIVER_IMAGE_INFO *DriverImageInfo;
+ BOOLEAN Found;
+ UINT32 ImageNO;
+ UINTN DevicePathSize;
+
+ //
+ // Check that ControllerHandle is a valid handle
+ //
+ if (ControllerDevicePath == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+ if (DriverImageDevicePath == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+ if (MappingDataBase == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ Status = CheckMapping (
+ ControllerDevicePath,
+ DriverImageDevicePath,
+ MappingDataBase,
+ NULL,
+ NULL
+ );
+ if (Status == EFI_SUCCESS) {
+ return EFI_ALREADY_STARTED;
+ }
+
+ //
+ // Search the input ControllerDevicePath in MappingDataBase
+ //
+ Found = FALSE;
+ OverrideItem = NULL;
+ OverrideItemListIndex = MappingDataBase->ForwardLink;
+ while (OverrideItemListIndex != MappingDataBase){
+ OverrideItem = CR(OverrideItemListIndex, PLATFORM_OVERRIDE_ITEM, Link, PLATFORM_OVERRIDE_ITEM_SIGNATURE);
+ DevicePathSize = GetDevicePathSize (ControllerDevicePath);
+ if (DevicePathSize == GetDevicePathSize (OverrideItem->ControllerDevicePath)) {
+ if (CompareMem (
+ ControllerDevicePath,
+ OverrideItem->ControllerDevicePath,
+ GetDevicePathSize (OverrideItem->ControllerDevicePath)
+ ) == 0
+ ) {
+ Found = TRUE;
+ break;
+ }
+ }
+ OverrideItemListIndex = OverrideItemListIndex->ForwardLink;
+ }
+ //
+ // If cannot find, this is a new controller item
+ // Add the Controller related PLATFORM_OVERRIDE_ITEM structrue in mapping data base
+ //
+ if (!Found) {
+ OverrideItem = AllocateZeroPool (sizeof (PLATFORM_OVERRIDE_ITEM));
+ ASSERT (OverrideItem != NULL);
+ OverrideItem->Signature = PLATFORM_OVERRIDE_ITEM_SIGNATURE;
+ OverrideItem->ControllerDevicePath = DuplicateDevicePath (ControllerDevicePath);
+ InitializeListHead (&OverrideItem->DriverInfoList);
+ InsertTailList (MappingDataBase, &OverrideItem->Link);
+ }
+
+ //
+ // Prepare the driver image related DRIVER_IMAGE_INFO structure.
+ //
+ DriverImageInfo = AllocateZeroPool (sizeof (DRIVER_IMAGE_INFO));
+ ASSERT (DriverImageInfo != NULL);
+ DriverImageInfo->Signature = DRIVER_IMAGE_INFO_SIGNATURE;
+ DriverImageInfo->DriverImagePath = DuplicateDevicePath (DriverImageDevicePath);
+ //
+ // Find the driver image wantted order location
+ //
+ ImageNO = 0;
+ Found = FALSE;
+ ImageInfoListIndex = OverrideItem->DriverInfoList.ForwardLink;
+ while (ImageInfoListIndex != &OverrideItem->DriverInfoList){
+ if (ImageNO == (DriverImageNO - 1)) {
+ //
+ // find the wantted order location, insert it
+ //
+ InsertTailList (ImageInfoListIndex, &DriverImageInfo->Link);
+ OverrideItem->DriverInfoNum ++;
+ Found = TRUE;
+ break;
+ }
+ //DriverImageInfo = CR(ImageInfoListIndex, DRIVER_IMAGE_INFO, Link, DRIVER_IMAGE_INFO_SIGNATURE);
+ ImageNO++;
+ ImageInfoListIndex = ImageInfoListIndex->ForwardLink;
+ }
+
+ if (!Found) {
+ //
+ // if not find the wantted order location, add it as last item of the controller mapping item
+ //
+ InsertTailList (&OverrideItem->DriverInfoList, &DriverImageInfo->Link);
+ OverrideItem->DriverInfoNum ++;
+ }
+
+ return EFI_SUCCESS;
+}
+
+
+/**
+ Delete a controller's override driver from the mapping database.
+
+ @param ControllerDevicePath The controller device path need to add a
+ override driver image item
+ @param DriverImageDevicePath The driver image device path need to be insert
+ @param MappingDataBase Mapping database list entry pointer
+ @param DriverImageNO The inserted order number
+
+ @return EFI_INVALID_PARAMETER
+ @return EFI_NOT_FOUND
+ @return EFI_SUCCESS
+
+**/
+EFI_STATUS
+EFIAPI
+DeleteDriverImage (
+ IN EFI_DEVICE_PATH_PROTOCOL *ControllerDevicePath,
+ IN EFI_DEVICE_PATH_PROTOCOL *DriverImageDevicePath,
+ IN LIST_ENTRY *MappingDataBase
+ )
+{
+ EFI_STATUS Status;
+ LIST_ENTRY *OverrideItemListIndex;
+ PLATFORM_OVERRIDE_ITEM *OverrideItem;
+ LIST_ENTRY *ImageInfoListIndex;
+ DRIVER_IMAGE_INFO *DriverImageInfo;
+ BOOLEAN Found;
+ UINTN DevicePathSize;
+
+ //
+ // Check that ControllerHandle is a valid handle
+ //
+ if (ControllerDevicePath == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if (MappingDataBase == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ Status = CheckMapping (
+ ControllerDevicePath,
+ DriverImageDevicePath,
+ MappingDataBase,
+ NULL,
+ NULL
+ );
+ if (Status == EFI_NOT_FOUND) {
+ return EFI_NOT_FOUND;
+ }
+
+ //
+ // Search ControllerDevicePath in MappingDataBase
+ //
+ Found = FALSE;
+ OverrideItem = NULL;
+ OverrideItemListIndex = MappingDataBase->ForwardLink;
+ while (OverrideItemListIndex != MappingDataBase){
+ OverrideItem = CR(OverrideItemListIndex, PLATFORM_OVERRIDE_ITEM, Link, PLATFORM_OVERRIDE_ITEM_SIGNATURE);
+ DevicePathSize = GetDevicePathSize (ControllerDevicePath);
+ if (DevicePathSize == GetDevicePathSize (OverrideItem->ControllerDevicePath)) {
+ if (CompareMem (
+ ControllerDevicePath,
+ OverrideItem->ControllerDevicePath,
+ GetDevicePathSize (OverrideItem->ControllerDevicePath)
+ ) == 0
+ ) {
+ Found = TRUE;
+ break;
+ }
+ }
+ OverrideItemListIndex = OverrideItemListIndex->ForwardLink;
+ }
+
+ ASSERT (Found);
+ ASSERT (OverrideItem->DriverInfoNum != 0);
+ //
+ //
+ //
+ Found = FALSE;
+ ImageInfoListIndex = OverrideItem->DriverInfoList.ForwardLink;
+ while (ImageInfoListIndex != &OverrideItem->DriverInfoList){
+ DriverImageInfo = CR(ImageInfoListIndex, DRIVER_IMAGE_INFO, Link, DRIVER_IMAGE_INFO_SIGNATURE);
+ ImageInfoListIndex = ImageInfoListIndex->ForwardLink;
+ if (DriverImageDevicePath != NULL) {
+ DevicePathSize = GetDevicePathSize (DriverImageDevicePath);
+ if (DevicePathSize == GetDevicePathSize (DriverImageInfo->DriverImagePath)) {
+ if (CompareMem (
+ DriverImageDevicePath,
+ DriverImageInfo->DriverImagePath,
+ GetDevicePathSize (DriverImageInfo->DriverImagePath)
+ ) == 0
+ ) {
+ Found = TRUE;
+ FreePool(DriverImageInfo->DriverImagePath);
+ RemoveEntryList (&DriverImageInfo->Link);
+ OverrideItem->DriverInfoNum --;
+ break;
+ }
+ }
+ } else {
+ Found = TRUE;
+ FreePool(DriverImageInfo->DriverImagePath);
+ RemoveEntryList (&DriverImageInfo->Link);
+ OverrideItem->DriverInfoNum --;
+ }
+ }
+
+ if (DriverImageDevicePath == NULL) {
+ ASSERT (OverrideItem->DriverInfoNum == 0);
+ }
+
+ if (OverrideItem->DriverInfoNum == 0) {
+ FreePool(OverrideItem->ControllerDevicePath);
+ RemoveEntryList (&OverrideItem->Link);
+ FreePool (OverrideItem);
+ }
+
+ if (!Found) {
+ return EFI_NOT_FOUND;
+ }
+
+ return EFI_SUCCESS;
+}
+
+
+/**
+ Deletes all environment variable(s) that contain the override mappings from Controller Device Path to
+ a set of Driver Device Paths.
+
+ None
+
+ @return EFI_SUCCESS
+
+**/
+EFI_STATUS
+EFIAPI
+DeleteOverridesVariables (
+ VOID
+ )
+{
+ EFI_STATUS Status;
+ VOID *VariableBuffer;
+ UINTN VariableNum;
+ UINTN BufferSize;
+ UINTN Index;
+ CHAR16 OverrideVariableName[40];
+
+ //
+ // Get environment variable(s) number
+ //
+ VariableNum =0;
+ VariableBuffer = GetVariableAndSize (L"PlatDriOver", &gEfiOverrideVariableGuid, &BufferSize);
+ VariableNum ++;
+ if (VariableBuffer == NULL) {
+ return EFI_NOT_FOUND;
+ }
+ //
+ // Check NotEnd to get all PlatDriOverX variable(s)
+ //
+ while (*(UINT32*)VariableBuffer) {
+ UnicodeSPrint (OverrideVariableName, sizeof (OverrideVariableName), L"PlatDriOver%d", VariableNum);
+ VariableBuffer = GetVariableAndSize (OverrideVariableName, &gEfiOverrideVariableGuid, &BufferSize);
+ VariableNum ++;
+ ASSERT (VariableBuffer != NULL);
+ }
+
+ Status = gRT->SetVariable (
+ L"PlatDriOver",
+ &gEfiOverrideVariableGuid,
+ EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_NON_VOLATILE,
+ 0,
+ NULL
+ );
+ ASSERT (!EFI_ERROR (Status));
+ for (Index = 1; Index < VariableNum; Index++) {
+ UnicodeSPrint (OverrideVariableName, sizeof (OverrideVariableName), L"PlatDriOver%d", Index);
+ Status = gRT->SetVariable (
+ OverrideVariableName,
+ &gEfiOverrideVariableGuid,
+ EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_NON_VOLATILE,
+ 0,
+ NULL
+ );
+ ASSERT (!EFI_ERROR (Status));
+ }
+ return EFI_SUCCESS;
+}
+
+
+/**
+ Push a controller device path into a globle device path list
+
+ @param ControllerDevicePath The controller device path need to push into
+ stack
+
+ @return EFI_SUCCESS
+
+**/
+EFI_STATUS
+EFIAPI
+PushDevPathStack (
+ IN EFI_DEVICE_PATH_PROTOCOL *DevicePath
+ )
+{
+ DEVICE_PATH_STACK_ITEM *DevicePathStackItem;
+
+ DevicePathStackItem = AllocateZeroPool (sizeof (DEVICE_PATH_STACK_ITEM));
+ ASSERT (DevicePathStackItem != NULL);
+ DevicePathStackItem->Signature = DEVICE_PATH_STACK_ITEM_SIGNATURE;
+ DevicePathStackItem->DevicePath = DuplicateDevicePath (DevicePath);
+ InsertTailList (&mDevicePathStack, &DevicePathStackItem->Link);
+ return EFI_SUCCESS;
+}
+
+
+/**
+ Pop a controller device path from a globle device path list
+
+ @param ControllerDevicePath The controller device path retrieved from stack
+
+ @return EFI_SUCCESS
+ @return EFI_NOT_FOUND
+
+**/
+EFI_STATUS
+EFIAPI
+PopDevPathStack (
+ OUT EFI_DEVICE_PATH_PROTOCOL **DevicePath
+ )
+{
+ DEVICE_PATH_STACK_ITEM *DevicePathStackItem;
+ LIST_ENTRY *ItemListIndex;
+
+ ItemListIndex = mDevicePathStack.BackLink;
+ if (ItemListIndex != &mDevicePathStack){
+ DevicePathStackItem = CR(ItemListIndex, DEVICE_PATH_STACK_ITEM, Link, DEVICE_PATH_STACK_ITEM_SIGNATURE);
+ if (DevicePath != NULL) {
+ *DevicePath = DuplicateDevicePath (DevicePathStackItem->DevicePath);
+ }
+ FreePool (DevicePathStackItem->DevicePath);
+ RemoveEntryList (&DevicePathStackItem->Link);
+ FreePool (DevicePathStackItem);
+ return EFI_SUCCESS;
+ }
+ return EFI_NOT_FOUND;
+}
+
+
+/**
+ Check whether a controller device path is in a globle device path list
+
+ @param ControllerDevicePath The controller device path need to check
+
+ @return True
+ @return False
+
+**/
+BOOLEAN
+EFIAPI
+CheckExistInStack (
+ IN EFI_DEVICE_PATH_PROTOCOL *DevicePath
+ )
+{
+ DEVICE_PATH_STACK_ITEM *DevicePathStackItem;
+ LIST_ENTRY *ItemListIndex;
+ BOOLEAN Found;
+ UINTN DevicePathSize;
+
+ Found = FALSE;
+ ItemListIndex = mDevicePathStack.BackLink;
+ while (ItemListIndex != &mDevicePathStack){
+ DevicePathStackItem = CR(ItemListIndex, DEVICE_PATH_STACK_ITEM, Link, DEVICE_PATH_STACK_ITEM_SIGNATURE);
+ DevicePathSize = GetDevicePathSize (DevicePath);
+ if (DevicePathSize == GetDevicePathSize (DevicePathStackItem->DevicePath)) {
+ if (CompareMem (
+ DevicePath,
+ DevicePathStackItem->DevicePath,
+ GetDevicePathSize (DevicePathStackItem->DevicePath)
+ ) == 0
+ ) {
+ Found = TRUE;
+ break;
+ }
+ }
+ ItemListIndex = ItemListIndex->BackLink;
+ }
+
+ return Found;
+}
+
+
+/**
+ According to a file guild, check a Fv file device path is valid. If it is invalid,
+ try to return the valid device path.
+ FV address maybe changes for memory layout adjust from time to time, use this funciton
+ could promise the Fv file device path is right.
+
+ @param DevicePath on input, the Fv file device path need to check
+ on output, the updated valid Fv file device path
+ @param FileGuid the Fv file guild
+ @param CallerImageHandle
+
+ @retval EFI_INVALID_PARAMETER the input DevicePath or FileGuid is invalid
+ parameter
+ @retval EFI_UNSUPPORTED the input DevicePath does not contain Fv file
+ guild at all
+ @retval EFI_ALREADY_STARTED the input DevicePath has pointed to Fv file, it
+ is valid
+ @retval EFI_SUCCESS has successfully updated the invalid DevicePath,
+ and return the updated device path in DevicePath
+
+**/
+EFI_STATUS
+EFIAPI
+UpdateFvFileDevicePath (
+ IN OUT EFI_DEVICE_PATH_PROTOCOL ** DevicePath,
+ IN EFI_GUID *FileGuid,
+ IN EFI_HANDLE CallerImageHandle
+ )
+{
+ EFI_DEVICE_PATH_PROTOCOL *TempDevicePath;
+ EFI_DEVICE_PATH_PROTOCOL *LastDeviceNode;
+ EFI_STATUS Status;
+ EFI_GUID *GuidPoint;
+ UINTN Index;
+ UINTN FvHandleCount;
+ EFI_HANDLE *FvHandleBuffer;
+ EFI_FV_FILETYPE Type;
+ UINTN Size;
+ EFI_FV_FILE_ATTRIBUTES Attributes;
+ UINT32 AuthenticationStatus;
+ BOOLEAN FindFvFile;
+ EFI_LOADED_IMAGE_PROTOCOL *LoadedImage;
+ EFI_FIRMWARE_VOLUME2_PROTOCOL *Fv;
+ MEDIA_FW_VOL_FILEPATH_DEVICE_PATH FvFileNode;
+ EFI_HANDLE FoundFvHandle;
+ EFI_DEVICE_PATH_PROTOCOL *NewDevicePath;
+ BOOLEAN HasFVNode;
+
+ if ((DevicePath == NULL) || (*DevicePath == NULL)) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ //
+ // Check whether the device path point to the default the input Fv file
+ //
+ TempDevicePath = *DevicePath;
+ LastDeviceNode = TempDevicePath;
+ while (!EfiIsDevicePathEnd (TempDevicePath)) {
+ LastDeviceNode = TempDevicePath;
+ TempDevicePath = EfiNextDevicePathNode (TempDevicePath);
+ }
+ GuidPoint = EfiGetNameGuidFromFwVolDevicePathNode (
+ (MEDIA_FW_VOL_FILEPATH_DEVICE_PATH *) LastDeviceNode
+ );
+ if (GuidPoint == NULL) {
+ //
+ // if this option does not points to a Fv file, just return EFI_UNSUPPORTED
+ //
+ return EFI_UNSUPPORTED;
+ }
+
+ if (FileGuid != NULL) {
+ if (!CompareGuid (GuidPoint, FileGuid)) {
+ //
+ // If the Fv file is not the input file guid, just return EFI_UNSUPPORTED
+ //
+ return EFI_UNSUPPORTED;
+ }
+ } else {
+ FileGuid = GuidPoint;
+ }
+
+ //
+ // Check to see if the device path contain memory map node
+ //
+ TempDevicePath = *DevicePath;
+ HasFVNode = FALSE;
+ while (!EfiIsDevicePathEnd (TempDevicePath)) {
+ //
+ // Use old Device Path
+ //
+ if (DevicePathType (TempDevicePath) == HARDWARE_DEVICE_PATH &&
+ DevicePathSubType (TempDevicePath) == HW_MEMMAP_DP) {
+ HasFVNode = TRUE;
+ break;
+ }
+ TempDevicePath = EfiNextDevicePathNode (TempDevicePath);
+ }
+
+ if (!HasFVNode) {
+ return EFI_UNSUPPORTED;
+ }
+
+ //
+ // Check whether the input Fv file device path is valid
+ //
+ TempDevicePath = *DevicePath;
+ FoundFvHandle = NULL;
+ Status = gBS->LocateDevicePath (
+ &gEfiFirmwareVolume2ProtocolGuid,
+ &TempDevicePath,
+ &FoundFvHandle
+ );
+ if (!EFI_ERROR (Status)) {
+ Status = gBS->HandleProtocol (
+ FoundFvHandle,
+ &gEfiFirmwareVolume2ProtocolGuid,
+ (VOID **) &Fv
+ );
+ if (!EFI_ERROR (Status)) {
+ //
+ // Set FV ReadFile Buffer as NULL, only need to check whether input Fv file exist there
+ //
+ Status = Fv->ReadFile (
+ Fv,
+ FileGuid,
+ NULL,
+ &Size,
+ &Type,
+ &Attributes,
+ &AuthenticationStatus
+ );
+ if (!EFI_ERROR (Status)) {
+ return EFI_ALREADY_STARTED;
+ }
+ }
+ }
+
+ //
+ // Look for the input wanted FV file in current FV
+ // First, try to look for in Caller own FV. Caller and input wanted FV file usually are in the same FV
+ //
+ FindFvFile = FALSE;
+ FoundFvHandle = NULL;
+ Status = gBS->HandleProtocol (
+ CallerImageHandle,
+ &gEfiLoadedImageProtocolGuid,
+ (VOID **) &LoadedImage
+ );
+ if (!EFI_ERROR (Status)) {
+ Status = gBS->HandleProtocol (
+ LoadedImage->DeviceHandle,
+ &gEfiFirmwareVolume2ProtocolGuid,
+ (VOID **) &Fv
+ );
+ if (!EFI_ERROR (Status)) {
+ Status = Fv->ReadFile (
+ Fv,
+ FileGuid,
+ NULL,
+ &Size,
+ &Type,
+ &Attributes,
+ &AuthenticationStatus
+ );
+ if (!EFI_ERROR (Status)) {
+ FindFvFile = TRUE;
+ FoundFvHandle = LoadedImage->DeviceHandle;
+ }
+ }
+ }
+ //
+ // Second, if fail to find, try to enumerate all FV
+ //
+ if (!FindFvFile) {
+ gBS->LocateHandleBuffer (
+ ByProtocol,
+ &gEfiFirmwareVolume2ProtocolGuid,
+ NULL,
+ &FvHandleCount,
+ &FvHandleBuffer
+ );
+ for (Index = 0; Index < FvHandleCount; Index++) {
+ gBS->HandleProtocol (
+ FvHandleBuffer[Index],
+ &gEfiFirmwareVolume2ProtocolGuid,
+ (VOID **) &Fv
+ );
+
+ Status = Fv->ReadFile (
+ Fv,
+ FileGuid,
+ NULL,
+ &Size,
+ &Type,
+ &Attributes,
+ &AuthenticationStatus
+ );
+ if (EFI_ERROR (Status)) {
+ //
+ // Skip if input Fv file not in the FV
+ //
+ continue;
+ }
+ FindFvFile = TRUE;
+ FoundFvHandle = FvHandleBuffer[Index];
+ break;
+ }
+ }
+
+ if (FindFvFile) {
+ //
+ // Build the shell device path
+ //
+ NewDevicePath = DevicePathFromHandle (FoundFvHandle);
+ EfiInitializeFwVolDevicepathNode (&FvFileNode, FileGuid);
+ NewDevicePath = AppendDevicePathNode (NewDevicePath, (EFI_DEVICE_PATH_PROTOCOL *) &FvFileNode);
+ *DevicePath = NewDevicePath;
+ return EFI_SUCCESS;
+ }
+ return EFI_NOT_FOUND;
+}
+
+
+/**
+ Read the EFI variable (VendorGuid/Name) and return a dynamically allocated
+ buffer, and the size of the buffer. If failure return NULL.
+
+ @param Name String part of EFI variable name
+ @param VendorGuid GUID part of EFI variable name
+ @param VariableSize Returns the size of the EFI variable that was
+ read
+
+ @return Dynamically allocated memory that contains a copy of the EFI variable.
+ @return Caller is responsible freeing the buffer.
+ @retval NULL Variable was not read
+
+**/
+VOID *
+EFIAPI
+GetVariableAndSize (
+ IN CHAR16 *Name,
+ IN EFI_GUID *VendorGuid,
+ OUT UINTN *VariableSize
+ )
+{
+ EFI_STATUS Status;
+ UINTN BufferSize;
+ VOID *Buffer;
+
+ Buffer = NULL;
+
+ //
+ // Pass in a zero size buffer to find the required buffer size.
+ //
+ BufferSize = 0;
+ Status = gRT->GetVariable (Name, VendorGuid, NULL, &BufferSize, Buffer);
+ if (Status == EFI_BUFFER_TOO_SMALL) {
+ //
+ // Allocate the buffer to return
+ //
+ Buffer = AllocateZeroPool (BufferSize);
+ if (Buffer == NULL) {
+ return NULL;
+ }
+ //
+ // Read variable into the allocated buffer.
+ //
+ Status = gRT->GetVariable (Name, VendorGuid, NULL, &BufferSize, Buffer);
+ if (EFI_ERROR (Status)) {
+ BufferSize = 0;
+ }
+ }
+
+ *VariableSize = BufferSize;
+ return Buffer;
+}
+
+
+/**
+ This function will create all handles associate with every device
+ path node. If the handle associate with one device path node can not
+ be created success, then still give one chance to do the dispatch,
+ which load the missing drivers if possible.
+
+ @param DevicePathToConnect The device path which will be connected, it can
+ be a multi-instance device path
+
+ @retval EFI_SUCCESS All handles associate with every device path
+ node have been created
+ @retval EFI_OUT_OF_RESOURCES There is no resource to create new handles
+ @retval EFI_NOT_FOUND Create the handle associate with one device
+ path node failed
+
+**/
+EFI_STATUS
+EFIAPI
+ConnectDevicePath (
+ IN EFI_DEVICE_PATH_PROTOCOL *DevicePathToConnect
+ )
+{
+ EFI_STATUS Status;
+ EFI_DEVICE_PATH_PROTOCOL *DevicePath;
+ EFI_DEVICE_PATH_PROTOCOL *CopyOfDevicePath;
+ EFI_DEVICE_PATH_PROTOCOL *Instance;
+ EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath;
+ EFI_DEVICE_PATH_PROTOCOL *Next;
+ EFI_HANDLE Handle;
+ EFI_HANDLE PreviousHandle;
+ UINTN Size;
+
+ if (DevicePathToConnect == NULL) {
+ return EFI_SUCCESS;
+ }
+
+ DevicePath = DuplicateDevicePath (DevicePathToConnect);
+ CopyOfDevicePath = DevicePath;
+ if (DevicePath == NULL) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ do {
+ //
+ // The outer loop handles multi instance device paths.
+ // Only console variables contain multiple instance device paths.
+ //
+ // After this call DevicePath points to the next Instance
+ //
+ Instance = GetNextDevicePathInstance (&DevicePath, &Size);
+ Next = Instance;
+ while (!IsDevicePathEndType (Next)) {
+ Next = NextDevicePathNode (Next);
+ }
+
+ SetDevicePathEndNode (Next);
+
+ //
+ // Start the real work of connect with RemainingDevicePath
+ //
+ PreviousHandle = NULL;
+ do {
+ //
+ // Find the handle that best matches the Device Path. If it is only a
+ // partial match the remaining part of the device path is returned in
+ // RemainingDevicePath.
+ //
+ RemainingDevicePath = Instance;
+ Status = gBS->LocateDevicePath (&gEfiDevicePathProtocolGuid, &RemainingDevicePath, &Handle);
+
+ if (!EFI_ERROR (Status)) {
+ if (Handle == PreviousHandle) {
+ //
+ // If no forward progress is made try invoking the Dispatcher.
+ // A new FV may have been added to the system an new drivers
+ // may now be found.
+ // Status == EFI_SUCCESS means a driver was dispatched
+ // Status == EFI_NOT_FOUND means no new drivers were dispatched
+ //
+ Status = gDS->Dispatch ();
+ }
+
+ if (!EFI_ERROR (Status)) {
+ PreviousHandle = Handle;
+ //
+ // Connect all drivers that apply to Handle and RemainingDevicePath,
+ // the Recursive flag is FALSE so only one level will be expanded.
+ //
+ // Do not check the connect status here, if the connect controller fail,
+ // then still give the chance to do dispatch, because partial
+ // RemainingDevicepath may be in the new FV
+ //
+ // 1. If the connect fail, RemainingDevicepath and handle will not
+ // change, so next time will do the dispatch, then dispatch's status
+ // will take effect
+ // 2. If the connect success, the RemainingDevicepath and handle will
+ // change, then avoid the dispatch, we have chance to continue the
+ // next connection
+ //
+ gBS->ConnectController (Handle, NULL, RemainingDevicePath, FALSE);
+ }
+ }
+ //
+ // Loop until RemainingDevicePath is an empty device path
+ //
+ } while (!EFI_ERROR (Status) && !IsDevicePathEnd (RemainingDevicePath));
+
+ } while (DevicePath != NULL);
+
+ if (CopyOfDevicePath != NULL) {
+ FreePool (CopyOfDevicePath);
+ }
+ //
+ // All handle with DevicePath exists in the handle database
+ //
+ return Status;
+}