diff --git a/Library/OcDevicePathLib/ExpandDevicePath.c b/Library/OcDevicePathLib/ExpandDevicePath.c
new file mode 100644
index 00000000..9dca8a6e
--- /dev/null
+++ b/Library/OcDevicePathLib/ExpandDevicePath.c
@@ -0,0 +1,1060 @@
+/** @file
+ Library functions which relates with booting.
+
+Copyright (c) 2011 - 2019, Intel Corporation. All rights reserved.
+(C) Copyright 2015-2016 Hewlett Packard Enterprise Development LP
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include
+
+#include
+
+#include
+#include
+#include
+#include
+#include
+
+#include
+#include
+#include
+#include
+#include
+#include
+
+// CHANGE: Track InternalConnectAll() execution status.
+STATIC BOOLEAN mConnectAllExecuted = FALSE;
+
+// CHANGE: Added from UefiBootManagerLib
+/**
+ Connect all the drivers to all the controllers.
+
+ This function makes sure all the current system drivers manage the correspoinding
+ controllers if have. And at the same time, makes sure all the system controllers
+ have driver to manage it if have.
+**/
+VOID
+InternalConnectAll (
+ VOID
+ )
+{
+ EFI_STATUS Status;
+ UINTN HandleCount;
+ EFI_HANDLE *HandleBuffer;
+ UINTN Index;
+
+ // CHANGE: Report execution status.
+ mConnectAllExecuted = TRUE;
+
+ //
+ // Connect All EFI 1.10 drivers following EFI 1.10 algorithm
+ // CHANGE: Only connect device handles. Do not call gDS->Dispatch().
+ //
+ Status = gBS->LocateHandleBuffer (
+ ByProtocol,
+ &gEfiDevicePathProtocolGuid,
+ NULL,
+ &HandleCount,
+ &HandleBuffer
+ );
+ if (!EFI_ERROR (Status)) {
+ for (Index = 0; Index < HandleCount; Index++) {
+ gBS->ConnectController (HandleBuffer[Index], NULL, NULL, TRUE);
+ }
+
+ FreePool (HandleBuffer);
+ }
+}
+
+/**
+ Get the next possible full path pointing to the load option.
+ The routine doesn't guarantee the returned full path points to an existing
+ file, and it also doesn't guarantee the existing file is a valid load option.
+
+ @param FilePath The device path pointing to a load option.
+ It could be a short-form device path.
+ @param FullPath The full path returned by the routine in last call.
+ Set to NULL in first call.
+
+ @return The next possible full path pointing to the load option.
+ Caller is responsible to free the memory.
+**/
+EFI_DEVICE_PATH_PROTOCOL *
+OcGetNextLoadOptionDevicePath (
+ IN EFI_DEVICE_PATH_PROTOCOL *FilePath,
+ IN EFI_DEVICE_PATH_PROTOCOL *FullPath
+ );
+
+/**
+ Check whether a USB device match the specified USB Class device path. This
+ function follows "Load Option Processing" behavior in UEFI specification.
+
+ @param UsbIo USB I/O protocol associated with the USB device.
+ @param UsbClass The USB Class device path to match.
+
+ @retval TRUE The USB device match the USB Class device path.
+ @retval FALSE The USB device does not match the USB Class device path.
+
+**/
+STATIC
+BOOLEAN
+BmMatchUsbClass (
+ IN EFI_USB_IO_PROTOCOL *UsbIo,
+ IN USB_CLASS_DEVICE_PATH *UsbClass
+ )
+{
+ EFI_STATUS Status;
+ EFI_USB_DEVICE_DESCRIPTOR DevDesc;
+ EFI_USB_INTERFACE_DESCRIPTOR IfDesc;
+ UINT8 DeviceClass;
+ UINT8 DeviceSubClass;
+ UINT8 DeviceProtocol;
+
+ if ((DevicePathType (UsbClass) != MESSAGING_DEVICE_PATH) ||
+ (DevicePathSubType (UsbClass) != MSG_USB_CLASS_DP)){
+ return FALSE;
+ }
+
+ //
+ // Check Vendor Id and Product Id.
+ //
+ Status = UsbIo->UsbGetDeviceDescriptor (UsbIo, &DevDesc);
+ if (EFI_ERROR (Status)) {
+ return FALSE;
+ }
+
+ if ((UsbClass->VendorId != 0xffff) &&
+ (UsbClass->VendorId != DevDesc.IdVendor)) {
+ return FALSE;
+ }
+
+ if ((UsbClass->ProductId != 0xffff) &&
+ (UsbClass->ProductId != DevDesc.IdProduct)) {
+ return FALSE;
+ }
+
+ DeviceClass = DevDesc.DeviceClass;
+ DeviceSubClass = DevDesc.DeviceSubClass;
+ DeviceProtocol = DevDesc.DeviceProtocol;
+ if (DeviceClass == 0) {
+ //
+ // If Class in Device Descriptor is set to 0, use the Class, SubClass and
+ // Protocol in Interface Descriptor instead.
+ //
+ Status = UsbIo->UsbGetInterfaceDescriptor (UsbIo, &IfDesc);
+ if (EFI_ERROR (Status)) {
+ return FALSE;
+ }
+
+ DeviceClass = IfDesc.InterfaceClass;
+ DeviceSubClass = IfDesc.InterfaceSubClass;
+ DeviceProtocol = IfDesc.InterfaceProtocol;
+ }
+
+ //
+ // Check Class, SubClass and Protocol.
+ //
+ if ((UsbClass->DeviceClass != 0xff) &&
+ (UsbClass->DeviceClass != DeviceClass)) {
+ return FALSE;
+ }
+
+ if ((UsbClass->DeviceSubClass != 0xff) &&
+ (UsbClass->DeviceSubClass != DeviceSubClass)) {
+ return FALSE;
+ }
+
+ if ((UsbClass->DeviceProtocol != 0xff) &&
+ (UsbClass->DeviceProtocol != DeviceProtocol)) {
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+/**
+ Check whether a USB device match the specified USB WWID device path. This
+ function follows "Load Option Processing" behavior in UEFI specification.
+
+ @param UsbIo USB I/O protocol associated with the USB device.
+ @param UsbWwid The USB WWID device path to match.
+
+ @retval TRUE The USB device match the USB WWID device path.
+ @retval FALSE The USB device does not match the USB WWID device path.
+
+**/
+STATIC
+BOOLEAN
+BmMatchUsbWwid (
+ IN EFI_USB_IO_PROTOCOL *UsbIo,
+ IN USB_WWID_DEVICE_PATH *UsbWwid
+ )
+{
+ EFI_STATUS Status;
+ EFI_USB_DEVICE_DESCRIPTOR DevDesc;
+ EFI_USB_INTERFACE_DESCRIPTOR IfDesc;
+ UINT16 *LangIdTable;
+ UINT16 TableSize;
+ UINT16 Index;
+ CHAR16 *CompareStr;
+ UINTN CompareLen;
+ CHAR16 *SerialNumberStr;
+ UINTN Length;
+
+ if ((DevicePathType (UsbWwid) != MESSAGING_DEVICE_PATH) ||
+ (DevicePathSubType (UsbWwid) != MSG_USB_WWID_DP)) {
+ return FALSE;
+ }
+
+ //
+ // Check Vendor Id and Product Id.
+ //
+ Status = UsbIo->UsbGetDeviceDescriptor (UsbIo, &DevDesc);
+ if (EFI_ERROR (Status)) {
+ return FALSE;
+ }
+ if ((DevDesc.IdVendor != UsbWwid->VendorId) ||
+ (DevDesc.IdProduct != UsbWwid->ProductId)) {
+ return FALSE;
+ }
+
+ //
+ // Check Interface Number.
+ //
+ Status = UsbIo->UsbGetInterfaceDescriptor (UsbIo, &IfDesc);
+ if (EFI_ERROR (Status)) {
+ return FALSE;
+ }
+ if (IfDesc.InterfaceNumber != UsbWwid->InterfaceNumber) {
+ return FALSE;
+ }
+
+ //
+ // Check Serial Number.
+ //
+ if (DevDesc.StrSerialNumber == 0) {
+ return FALSE;
+ }
+
+ //
+ // Get all supported languages.
+ //
+ TableSize = 0;
+ LangIdTable = NULL;
+ Status = UsbIo->UsbGetSupportedLanguages (UsbIo, &LangIdTable, &TableSize);
+ if (EFI_ERROR (Status) || (TableSize == 0) || (LangIdTable == NULL)) {
+ return FALSE;
+ }
+
+ //
+ // Serial number in USB WWID device path is the last 64-or-less UTF-16 characters.
+ //
+ CompareStr = (CHAR16 *) (UINTN) (UsbWwid + 1);
+ CompareLen = (DevicePathNodeLength (UsbWwid) - sizeof (USB_WWID_DEVICE_PATH)) / sizeof (CHAR16);
+ if (CompareStr[CompareLen - 1] == L'\0') {
+ CompareLen--;
+ }
+
+ //
+ // Compare serial number in each supported language.
+ //
+ for (Index = 0; Index < TableSize / sizeof (UINT16); Index++) {
+ SerialNumberStr = NULL;
+ Status = UsbIo->UsbGetStringDescriptor (
+ UsbIo,
+ LangIdTable[Index],
+ DevDesc.StrSerialNumber,
+ &SerialNumberStr
+ );
+ if (EFI_ERROR (Status) || (SerialNumberStr == NULL)) {
+ continue;
+ }
+
+ Length = StrLen (SerialNumberStr);
+ if ((Length >= CompareLen) &&
+ (CompareMem (SerialNumberStr + Length - CompareLen, CompareStr, CompareLen * sizeof (CHAR16)) == 0)) {
+ FreePool (SerialNumberStr);
+ return TRUE;
+ }
+
+ FreePool (SerialNumberStr);
+ }
+
+ return FALSE;
+}
+
+/**
+ Find a USB device which match the specified short-form device path start with
+ USB Class or USB WWID device path. If ParentDevicePath is NULL, this function
+ will search in all USB devices of the platform. If ParentDevicePath is not NULL,
+ this function will only search in its child devices.
+
+ @param DevicePath The device path that contains USB Class or USB WWID device path.
+ @param ParentDevicePathSize The length of the device path before the USB Class or
+ USB WWID device path.
+ @param UsbIoHandleCount A pointer to the count of the returned USB IO handles.
+
+ @retval NULL The matched USB IO handles cannot be found.
+ @retval other The matched USB IO handles.
+
+**/
+STATIC
+EFI_HANDLE *
+BmFindUsbDevice (
+ IN EFI_DEVICE_PATH_PROTOCOL *DevicePath,
+ IN UINTN ParentDevicePathSize,
+ OUT UINTN *UsbIoHandleCount
+ )
+{
+ EFI_STATUS Status;
+ EFI_HANDLE *UsbIoHandles;
+ EFI_DEVICE_PATH_PROTOCOL *UsbIoDevicePath;
+ EFI_USB_IO_PROTOCOL *UsbIo;
+ UINTN Index;
+ BOOLEAN Matched;
+
+ ASSERT (UsbIoHandleCount != NULL);
+
+ //
+ // Get all UsbIo Handles.
+ //
+ Status = gBS->LocateHandleBuffer (
+ ByProtocol,
+ &gEfiUsbIoProtocolGuid,
+ NULL,
+ UsbIoHandleCount,
+ &UsbIoHandles
+ );
+ if (EFI_ERROR (Status)) {
+ *UsbIoHandleCount = 0;
+ UsbIoHandles = NULL;
+ }
+
+ for (Index = 0; Index < *UsbIoHandleCount; ) {
+ //
+ // Get the Usb IO interface.
+ //
+ Status = gBS->HandleProtocol(
+ UsbIoHandles[Index],
+ &gEfiUsbIoProtocolGuid,
+ (VOID **) &UsbIo
+ );
+ UsbIoDevicePath = DevicePathFromHandle (UsbIoHandles[Index]);
+ Matched = FALSE;
+ if (!EFI_ERROR (Status) && (UsbIoDevicePath != NULL)) {
+
+ //
+ // Compare starting part of UsbIoHandle's device path with ParentDevicePath.
+ //
+ if (CompareMem (UsbIoDevicePath, DevicePath, ParentDevicePathSize) == 0) {
+ if (BmMatchUsbClass (UsbIo, (USB_CLASS_DEVICE_PATH *) ((UINTN) DevicePath + ParentDevicePathSize)) ||
+ BmMatchUsbWwid (UsbIo, (USB_WWID_DEVICE_PATH *) ((UINTN) DevicePath + ParentDevicePathSize))) {
+ Matched = TRUE;
+ }
+ }
+ }
+
+ if (!Matched) {
+ (*UsbIoHandleCount) --;
+ CopyMem (&UsbIoHandles[Index], &UsbIoHandles[Index + 1], (*UsbIoHandleCount - Index) * sizeof (EFI_HANDLE));
+ } else {
+ Index++;
+ }
+ }
+
+ return UsbIoHandles;
+}
+
+/**
+ Expand USB Class or USB WWID device path node to be full device path of a USB
+ device in platform.
+
+ This function support following 4 cases:
+ 1) Boot Option device path starts with a USB Class or USB WWID device path,
+ and there is no Media FilePath device path in the end.
+ In this case, it will follow Removable Media Boot Behavior.
+ 2) Boot Option device path starts with a USB Class or USB WWID device path,
+ and ended with Media FilePath device path.
+ 3) Boot Option device path starts with a full device path to a USB Host Controller,
+ contains a USB Class or USB WWID device path node, while not ended with Media
+ FilePath device path. In this case, it will follow Removable Media Boot Behavior.
+ 4) Boot Option device path starts with a full device path to a USB Host Controller,
+ contains a USB Class or USB WWID device path node, and ended with Media
+ FilePath device path.
+
+ @param FilePath The device path pointing to a load option.
+ It could be a short-form device path.
+ @param FullPath The full path returned by the routine in last call.
+ Set to NULL in first call.
+ @param ShortformNode Pointer to the USB short-form device path node in the FilePath buffer.
+
+ @return The next possible full path pointing to the load option.
+ Caller is responsible to free the memory.
+**/
+STATIC
+EFI_DEVICE_PATH_PROTOCOL *
+BmExpandUsbDevicePath (
+ IN EFI_DEVICE_PATH_PROTOCOL *FilePath,
+ IN EFI_DEVICE_PATH_PROTOCOL *FullPath,
+ IN EFI_DEVICE_PATH_PROTOCOL *ShortformNode
+ )
+{
+ UINTN ParentDevicePathSize;
+ EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath;
+ EFI_DEVICE_PATH_PROTOCOL *NextFullPath;
+ EFI_HANDLE *Handles;
+ UINTN HandleCount;
+ UINTN Index;
+ BOOLEAN GetNext;
+
+ NextFullPath = NULL;
+ GetNext = (BOOLEAN)(FullPath == NULL);
+ ParentDevicePathSize = (UINTN) ShortformNode - (UINTN) FilePath;
+ RemainingDevicePath = NextDevicePathNode (ShortformNode);
+ Handles = BmFindUsbDevice (FilePath, ParentDevicePathSize, &HandleCount);
+
+ for (Index = 0; Index < HandleCount; Index++) {
+ FilePath = AppendDevicePath (DevicePathFromHandle (Handles[Index]), RemainingDevicePath);
+ if (FilePath == NULL) {
+ //
+ // Out of memory.
+ //
+ continue;
+ }
+ NextFullPath = OcGetNextLoadOptionDevicePath (FilePath, NULL);
+ FreePool (FilePath);
+ if (NextFullPath == NULL) {
+ //
+ // No BlockIo or SimpleFileSystem under FilePath.
+ //
+ continue;
+ }
+ if (GetNext) {
+ break;
+ } else {
+ GetNext = (BOOLEAN)(CompareMem (NextFullPath, FullPath, GetDevicePathSize (NextFullPath)) == 0);
+ FreePool (NextFullPath);
+ NextFullPath = NULL;
+ }
+ }
+
+ if (Handles != NULL) {
+ FreePool (Handles);
+ }
+
+ return NextFullPath;
+}
+
+/**
+ Expand the media device path which points to a BlockIo or SimpleFileSystem instance.
+
+ @param DevicePath The media device path pointing to a BlockIo or SimpleFileSystem instance.
+ @param FullPath The full path returned by the routine in last call.
+ Set to NULL in first call.
+
+ @return The next possible full path pointing to the load option.
+ Caller is responsible to free the memory.
+**/
+STATIC
+EFI_DEVICE_PATH_PROTOCOL *
+BmExpandMediaDevicePath (
+ IN EFI_DEVICE_PATH_PROTOCOL *DevicePath,
+ IN EFI_DEVICE_PATH_PROTOCOL *FullPath,
+ IN EFI_HANDLE Handle
+ )
+{
+ EFI_STATUS Status;
+ EFI_BLOCK_IO_PROTOCOL *BlockIo;
+ VOID *Buffer;
+ EFI_DEVICE_PATH_PROTOCOL *TempDevicePath;
+ EFI_DEVICE_PATH_PROTOCOL *NextFullPath;
+ UINTN Size;
+ UINTN TempSize;
+ EFI_HANDLE *SimpleFileSystemHandles;
+ UINTN NumberSimpleFileSystemHandles;
+ UINTN Index;
+ BOOLEAN GetNext;
+
+ GetNext = (BOOLEAN)(FullPath == NULL);
+ //
+ // Check whether the device is connected
+ // CHANGE: This branch has been removed as it has been covered by a caller change
+ //
+
+ // CHANGE: Get Handle via parameter as the function is called by the caller too
+
+ //
+ // For device boot option only pointing to the removable device handle,
+ // should make sure all its children handles (its child partion or media handles)
+ // are created and connected.
+ //
+ gBS->ConnectController (Handle, NULL, NULL, TRUE);
+
+ //
+ // Issue a dummy read to the device to check for media change.
+ // When the removable media is changed, any Block IO read/write will
+ // cause the BlockIo protocol be reinstalled and EFI_MEDIA_CHANGED is
+ // returned. After the Block IO protocol is reinstalled, subsequent
+ // Block IO read/write will success.
+ //
+ Status = gBS->HandleProtocol (Handle, &gEfiBlockIoProtocolGuid, (VOID **) &BlockIo);
+ // CHANGE: Do not ASSERT.
+ if (EFI_ERROR (Status)) {
+ return NULL;
+ }
+ Buffer = AllocatePool (BlockIo->Media->BlockSize);
+ if (Buffer != NULL) {
+ BlockIo->ReadBlocks (
+ BlockIo,
+ BlockIo->Media->MediaId,
+ 0,
+ BlockIo->Media->BlockSize,
+ Buffer
+ );
+ FreePool (Buffer);
+ }
+
+ //
+ // Detect the the default boot file from removable Media
+ //
+ NextFullPath = NULL;
+ Size = GetDevicePathSize (DevicePath) - END_DEVICE_PATH_LENGTH;
+ gBS->LocateHandleBuffer (
+ ByProtocol,
+ &gEfiSimpleFileSystemProtocolGuid,
+ NULL,
+ &NumberSimpleFileSystemHandles,
+ &SimpleFileSystemHandles
+ );
+ for (Index = 0; Index < NumberSimpleFileSystemHandles; Index++) {
+ //
+ // Get the device path size of SimpleFileSystem handle
+ //
+ TempDevicePath = DevicePathFromHandle (SimpleFileSystemHandles[Index]);
+ TempSize = GetDevicePathSize (TempDevicePath) - END_DEVICE_PATH_LENGTH;
+ //
+ // Check whether the device path of boot option is part of the SimpleFileSystem handle's device path
+ //
+ if ((Size <= TempSize) && (CompareMem (TempDevicePath, DevicePath, Size) == 0)) {
+ // CHANGE: Do not append EFI boot file.
+ NextFullPath = DuplicateDevicePath (TempDevicePath);
+ if (GetNext) {
+ break;
+ } else {
+ GetNext = (BOOLEAN)(CompareMem (NextFullPath, FullPath, GetDevicePathSize (NextFullPath)) == 0);
+ FreePool (NextFullPath);
+ NextFullPath = NULL;
+ }
+ }
+ }
+
+ if (SimpleFileSystemHandles != NULL) {
+ FreePool (SimpleFileSystemHandles);
+ }
+
+ return NextFullPath;
+}
+
+/**
+ Get the file buffer from the specified Load File instance.
+
+ @param LoadFileHandle The specified Load File instance.
+ @param FilePath The file path which will pass to LoadFile().
+
+ @return The full device path pointing to the load option buffer.
+**/
+STATIC
+EFI_DEVICE_PATH_PROTOCOL *
+BmExpandLoadFile (
+ IN EFI_HANDLE LoadFileHandle,
+ IN EFI_DEVICE_PATH_PROTOCOL *FilePath
+ )
+{
+ EFI_STATUS Status;
+ EFI_LOAD_FILE_PROTOCOL *LoadFile;
+ VOID *FileBuffer;
+ UINTN BufferSize;
+
+ Status = gBS->OpenProtocol (
+ LoadFileHandle,
+ &gEfiLoadFileProtocolGuid,
+ (VOID **) &LoadFile,
+ gImageHandle,
+ NULL,
+ EFI_OPEN_PROTOCOL_GET_PROTOCOL
+ );
+ ASSERT_EFI_ERROR (Status);
+
+ FileBuffer = NULL;
+ BufferSize = 0;
+ Status = LoadFile->LoadFile (LoadFile, FilePath, TRUE, &BufferSize, FileBuffer);
+ if ((Status != EFI_WARN_FILE_SYSTEM) && (Status != EFI_BUFFER_TOO_SMALL)) {
+ return NULL;
+ }
+
+ if (Status == EFI_BUFFER_TOO_SMALL) {
+ //
+ // The load option buffer is directly returned by LoadFile.
+ //
+ return DuplicateDevicePath (DevicePathFromHandle (LoadFileHandle));
+ }
+
+ //
+ // The load option resides in a RAM disk.
+ // CHANGE: Removed RAM disk support.
+ //
+ return NULL;
+}
+
+/**
+ Return the full device path pointing to the load option.
+
+ FilePath may:
+ 1. Exactly matches to a LoadFile instance.
+ 2. Cannot match to any LoadFile instance. Wide match is required.
+ In either case, the routine may return:
+ 1. A copy of FilePath when FilePath matches to a LoadFile instance and
+ the LoadFile returns a load option buffer.
+ 2. A new device path with IP and URI information updated when wide match
+ happens.
+ 3. A new device path pointing to a load option in RAM disk.
+ In either case, only one full device path is returned for a specified
+ FilePath.
+
+ @param FilePath The media device path pointing to a LoadFile instance.
+
+ @return The load option buffer.
+**/
+STATIC
+EFI_DEVICE_PATH_PROTOCOL *
+BmExpandLoadFiles (
+ IN EFI_DEVICE_PATH_PROTOCOL *FilePath
+ )
+{
+ EFI_STATUS Status;
+ EFI_HANDLE Handle;
+ EFI_DEVICE_PATH_PROTOCOL *Node;
+
+ //
+ // Get file buffer from load file instance.
+ //
+ Node = FilePath;
+ Status = gBS->LocateDevicePath (&gEfiLoadFileProtocolGuid, &Node, &Handle);
+ if (!EFI_ERROR (Status) && IsDevicePathEnd (Node)) {
+ //
+ // When wide match happens, pass full device path to LoadFile (),
+ // otherwise, pass remaining device path to LoadFile ().
+ //
+ FilePath = Node;
+ }
+ // CHANGE: Removed HTTP support.
+
+ if (Handle == NULL) {
+ return NULL;
+ }
+
+ return BmExpandLoadFile (Handle, FilePath);
+}
+
+/**
+ Expand URI device path node to be full device path in platform.
+
+ @param FilePath The device path pointing to a load option.
+ It could be a short-form device path.
+ @param FullPath The full path returned by the routine in last call.
+ Set to NULL in first call.
+
+ @return The next possible full path pointing to the load option.
+ Caller is responsible to free the memory.
+**/
+STATIC
+EFI_DEVICE_PATH_PROTOCOL *
+BmExpandUriDevicePath (
+ IN EFI_DEVICE_PATH_PROTOCOL *FilePath,
+ IN EFI_DEVICE_PATH_PROTOCOL *FullPath
+ )
+{
+ EFI_STATUS Status;
+ UINTN Index;
+ UINTN HandleCount;
+ EFI_HANDLE *Handles;
+ EFI_DEVICE_PATH_PROTOCOL *NextFullPath;
+ BOOLEAN GetNext;
+
+ // CHANGE: Only connect all on failure.
+ Status = gBS->LocateHandleBuffer (ByProtocol, &gEfiLoadFileProtocolGuid, NULL, &HandleCount, &Handles);
+ if (EFI_ERROR (Status)) {
+ HandleCount = 0;
+ Handles = NULL;
+ }
+
+ NextFullPath = NULL;
+ GetNext = (BOOLEAN)(FullPath == NULL);
+ for (Index = 0; Index < HandleCount; Index++) {
+ NextFullPath = BmExpandLoadFile (Handles[Index], FilePath);
+
+ if (NextFullPath == NULL) {
+ continue;
+ }
+
+ if (GetNext) {
+ break;
+ } else {
+ GetNext = (BOOLEAN)(CompareMem (NextFullPath, FullPath, GetDevicePathSize (NextFullPath)) == 0);
+ //
+ // Free the resource occupied by the RAM disk.
+ // CHANGE: RAM Disk support removed.
+ //
+ FreePool (NextFullPath);
+ NextFullPath = NULL;
+ }
+ }
+
+ if (Handles != NULL) {
+ FreePool (Handles);
+ }
+
+ if ((NextFullPath == NULL) && !mConnectAllExecuted) {
+ InternalConnectAll ();
+ return BmExpandUriDevicePath (FilePath, FullPath);
+ }
+
+ return NextFullPath;
+}
+
+/**
+ Check whether there is a instance in BlockIoDevicePath, which contain multi device path
+ instances, has the same partition node with HardDriveDevicePath device path
+
+ @param BlockIoDevicePath Multi device path instances which need to check
+ @param HardDriveDevicePath A device path which starts with a hard drive media
+ device path.
+
+ @retval TRUE There is a matched device path instance.
+ @retval FALSE There is no matched device path instance.
+
+**/
+STATIC
+BOOLEAN
+BmMatchPartitionDevicePathNode (
+ IN EFI_DEVICE_PATH_PROTOCOL *BlockIoDevicePath,
+ IN HARDDRIVE_DEVICE_PATH *HardDriveDevicePath
+ )
+{
+ HARDDRIVE_DEVICE_PATH *Node;
+
+ if ((BlockIoDevicePath == NULL) || (HardDriveDevicePath == NULL)) {
+ return FALSE;
+ }
+
+ //
+ // Match all the partition device path nodes including the nested partition nodes
+ //
+ while (!IsDevicePathEnd (BlockIoDevicePath)) {
+ if ((DevicePathType (BlockIoDevicePath) == MEDIA_DEVICE_PATH) &&
+ (DevicePathSubType (BlockIoDevicePath) == MEDIA_HARDDRIVE_DP)
+ ) {
+ //
+ // See if the harddrive device path in blockio matches the orig Hard Drive Node
+ //
+ Node = (HARDDRIVE_DEVICE_PATH *) BlockIoDevicePath;
+
+ //
+ // Match Signature and PartitionNumber.
+ // Unused bytes in Signature are initiaized with zeros.
+ //
+ if ((Node->PartitionNumber == HardDriveDevicePath->PartitionNumber) &&
+ (Node->MBRType == HardDriveDevicePath->MBRType) &&
+ (Node->SignatureType == HardDriveDevicePath->SignatureType) &&
+ (CompareMem (Node->Signature, HardDriveDevicePath->Signature, sizeof (Node->Signature)) == 0)) {
+ return TRUE;
+ }
+ }
+
+ BlockIoDevicePath = NextDevicePathNode (BlockIoDevicePath);
+ }
+
+ return FALSE;
+}
+
+/**
+ Expand a device path that starts with a hard drive media device path node to be a
+ full device path that includes the full hardware path to the device. We need
+ to do this so it can be booted. As an optimization the front match (the part point
+ to the partition node. E.g. ACPI() /PCI()/ATA()/Partition() ) is saved in a variable
+ so a connect all is not required on every boot. All successful history device path
+ which point to partition node (the front part) will be saved.
+
+ @param FilePath The device path pointing to a load option.
+ It could be a short-form device path.
+
+ @return The full device path pointing to the load option.
+**/
+STATIC
+EFI_DEVICE_PATH_PROTOCOL *
+BmExpandPartitionDevicePath (
+ IN EFI_DEVICE_PATH_PROTOCOL *FilePath
+ )
+{
+ EFI_STATUS Status;
+ UINTN BlockIoHandleCount;
+ EFI_HANDLE *BlockIoBuffer;
+ EFI_DEVICE_PATH_PROTOCOL *BlockIoDevicePath;
+ UINTN Index;
+ EFI_DEVICE_PATH_PROTOCOL *TempDevicePath;
+ EFI_DEVICE_PATH_PROTOCOL *FullPath;
+
+ // CHANGE: Remove HDDP variable code.
+
+ FullPath = NULL;
+ //
+ // If we get here we fail to find or 'HDDP' not exist, and now we need
+ // to search all devices in the system for a matched partition
+ //
+ // CHANGE: Only connect all on failure.
+ //
+ Status = gBS->LocateHandleBuffer (ByProtocol, &gEfiBlockIoProtocolGuid, NULL, &BlockIoHandleCount, &BlockIoBuffer);
+ if (EFI_ERROR (Status)) {
+ BlockIoHandleCount = 0;
+ BlockIoBuffer = NULL;
+ }
+ //
+ // Loop through all the device handles that support the BLOCK_IO Protocol
+ //
+ for (Index = 0; Index < BlockIoHandleCount; Index++) {
+ BlockIoDevicePath = DevicePathFromHandle (BlockIoBuffer[Index]);
+ if (BlockIoDevicePath == NULL) {
+ continue;
+ }
+
+ if (BmMatchPartitionDevicePathNode (BlockIoDevicePath, (HARDDRIVE_DEVICE_PATH *) FilePath)) {
+ //
+ // Find the matched partition device path
+ //
+ TempDevicePath = AppendDevicePath (BlockIoDevicePath, NextDevicePathNode (FilePath));
+ FullPath = OcGetNextLoadOptionDevicePath (TempDevicePath, NULL);
+ FreePool (TempDevicePath);
+
+ if (FullPath != NULL) {
+ break;
+ }
+ }
+ }
+
+ if (BlockIoBuffer != NULL) {
+ FreePool (BlockIoBuffer);
+ }
+
+ if ((FullPath == NULL) && !mConnectAllExecuted) {
+ InternalConnectAll ();
+ return BmExpandPartitionDevicePath (FilePath);
+ }
+
+ return FullPath;
+}
+
+/**
+ Connect the specific Usb device which match the short form device path,
+ and whose bus is determined by Host Controller (Uhci or Ehci).
+
+ @param DevicePath A short-form device path that starts with the first
+ element being a USB WWID or a USB Class device
+ path
+
+ @return EFI_INVALID_PARAMETER DevicePath is NULL pointer.
+ DevicePath is not a USB device path.
+
+ @return EFI_SUCCESS Success to connect USB device
+ @return EFI_NOT_FOUND Fail to find handle for USB controller to connect.
+
+**/
+STATIC
+EFI_STATUS
+BmConnectUsbShortFormDevicePath (
+ IN EFI_DEVICE_PATH_PROTOCOL *DevicePath
+ )
+{
+ EFI_STATUS Status;
+ EFI_HANDLE *Handles;
+ UINTN HandleCount;
+ UINTN Index;
+ EFI_PCI_IO_PROTOCOL *PciIo;
+ UINT8 Class[3];
+ BOOLEAN AtLeastOneConnected;
+
+ //
+ // Check the passed in parameters
+ //
+ if (DevicePath == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if ((DevicePathType (DevicePath) != MESSAGING_DEVICE_PATH) ||
+ ((DevicePathSubType (DevicePath) != MSG_USB_CLASS_DP) && (DevicePathSubType (DevicePath) != MSG_USB_WWID_DP))
+ ) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ //
+ // Find the usb host controller firstly, then connect with the remaining device path
+ //
+ AtLeastOneConnected = FALSE;
+ Status = gBS->LocateHandleBuffer (
+ ByProtocol,
+ &gEfiPciIoProtocolGuid,
+ NULL,
+ &HandleCount,
+ &Handles
+ );
+ if (!EFI_ERROR (Status)) {
+ for (Index = 0; Index < HandleCount; Index++) {
+ Status = gBS->HandleProtocol (
+ Handles[Index],
+ &gEfiPciIoProtocolGuid,
+ (VOID **) &PciIo
+ );
+ if (!EFI_ERROR (Status)) {
+ //
+ // Check whether the Pci device is the wanted usb host controller
+ //
+ Status = PciIo->Pci.Read (PciIo, EfiPciIoWidthUint8, 0x09, 3, &Class);
+ if (!EFI_ERROR (Status) &&
+ ((PCI_CLASS_SERIAL == Class[2]) && (PCI_CLASS_SERIAL_USB == Class[1]))
+ ) {
+ Status = gBS->ConnectController (
+ Handles[Index],
+ NULL,
+ DevicePath,
+ FALSE
+ );
+ if (!EFI_ERROR(Status)) {
+ AtLeastOneConnected = TRUE;
+ }
+ }
+ }
+ }
+
+ if (Handles != NULL) {
+ FreePool (Handles);
+ }
+ }
+
+ return AtLeastOneConnected ? EFI_SUCCESS : EFI_NOT_FOUND;
+}
+
+/**
+ Get the next possible full path pointing to the load option.
+ The routine doesn't guarantee the returned full path points to an existing
+ file, and it also doesn't guarantee the existing file is a valid load option.
+
+ @param FilePath The device path pointing to a load option.
+ It could be a short-form device path.
+ @param FullPath The full path returned by the routine in last call.
+ Set to NULL in first call.
+
+ @return The next possible full path pointing to the load option.
+ Caller is responsible to free the memory.
+**/
+EFI_DEVICE_PATH_PROTOCOL *
+OcGetNextLoadOptionDevicePath (
+ IN EFI_DEVICE_PATH_PROTOCOL *FilePath,
+ IN EFI_DEVICE_PATH_PROTOCOL *FullPath
+ )
+{
+ EFI_HANDLE Handle;
+ EFI_DEVICE_PATH_PROTOCOL *Node;
+ EFI_STATUS Status;
+
+ ASSERT (FilePath != NULL);
+
+ //
+ // CHANGE: If SimpleFileSystem is located, the device path is already expanded.
+ //
+ Node = FilePath;
+ Status = gBS->LocateDevicePath (&gEfiSimpleFileSystemProtocolGuid, &Node, &Handle);
+ if (!EFI_ERROR (Status)) {
+ if (FullPath != NULL) {
+ return NULL;
+ }
+
+ return DuplicateDevicePath (FilePath);
+ }
+
+ Status = gBS->LocateDevicePath (&gEfiBlockIoProtocolGuid, &Node, &Handle);
+ if (!EFI_ERROR (Status) && IsDevicePathEnd (Node)) {
+ return BmExpandMediaDevicePath (FilePath, FullPath, Handle);
+ }
+
+ // CHANGE: File Path node support removed.
+
+ //
+ // Expand the short-form device path to full device path
+ //
+ if ((DevicePathType (FilePath) == MEDIA_DEVICE_PATH) &&
+ (DevicePathSubType (FilePath) == MEDIA_HARDDRIVE_DP)) {
+ //
+ // Expand the Harddrive device path
+ //
+ if (FullPath == NULL) {
+ return BmExpandPartitionDevicePath (FilePath);
+ } else {
+ return NULL;
+ }
+ } else if ((DevicePathType (FilePath) == MESSAGING_DEVICE_PATH) &&
+ (DevicePathSubType (FilePath) == MSG_URI_DP)) {
+ //
+ // Expand the URI device path
+ //
+ return BmExpandUriDevicePath (FilePath, FullPath);
+ } else {
+ Node = FilePath;
+ Status = gBS->LocateDevicePath (&gEfiUsbIoProtocolGuid, &Node, &Handle);
+ if (EFI_ERROR (Status)) {
+ //
+ // Only expand the USB WWID/Class device path
+ // when FilePath doesn't point to a physical UsbIo controller.
+ // Otherwise, infinite recursion will happen.
+ //
+ for (Node = FilePath; !IsDevicePathEnd (Node); Node = NextDevicePathNode (Node)) {
+ if ((DevicePathType (Node) == MESSAGING_DEVICE_PATH) &&
+ ((DevicePathSubType (Node) == MSG_USB_CLASS_DP) || (DevicePathSubType (Node) == MSG_USB_WWID_DP))) {
+ break;
+ }
+ }
+
+ //
+ // Expand the USB WWID/Class device path
+ //
+ if (!IsDevicePathEnd (Node)) {
+ if (FilePath == Node) {
+ //
+ // Boot Option device path starts with USB Class or USB WWID device path.
+ // For Boot Option device path which doesn't begin with the USB Class or
+ // USB WWID device path, it's not needed to connect again here.
+ //
+ BmConnectUsbShortFormDevicePath (FilePath);
+ }
+ return BmExpandUsbDevicePath (FilePath, FullPath, Node);
+ }
+ }
+ }
+
+ //
+ // For the below cases, FilePath only expands to one Full path.
+ // So just handle the case when FullPath == NULL.
+ //
+ if (FullPath != NULL) {
+ return NULL;
+ }
+
+ // CHANGE: SimleFileSystem case has been covered at the beginning of the function
+
+ // CHANGE: Removed FV support.
+
+ //
+ // Last chance to try: Load option may be loaded through LoadFile.
+ //
+ return BmExpandLoadFiles (FilePath);
+}