/** @file\r
Library functions which relates with booting.\r
\r
-Copyright (c) 2011 - 2016, Intel Corporation. All rights reserved.<BR>\r
+Copyright (c) 2011 - 2017, Intel Corporation. All rights reserved.<BR>\r
(C) Copyright 2015-2016 Hewlett Packard Enterprise Development LP<BR>\r
This program and the accompanying materials\r
are licensed and made available under the terms and conditions of the BSD License\r
}\r
\r
/**\r
- Get the file buffer using a Memory Mapped Device Path.\r
-\r
+ Return the correct FV file path.\r
FV address may change across reboot. This routine promises the FV file device path is right.\r
\r
@param FilePath The Memory Mapped Device Path to get the file buffer.\r
- @param FullPath Receive the updated FV Device Path pointint to the file.\r
- @param FileSize Receive the file buffer size.\r
\r
- @return The file buffer.\r
+ @return The updated FV Device Path pointint to the file.\r
**/\r
-VOID *\r
-BmGetFileBufferByFvFilePath (\r
- IN EFI_DEVICE_PATH_PROTOCOL *FilePath,\r
- OUT EFI_DEVICE_PATH_PROTOCOL **FullPath,\r
- OUT UINTN *FileSize\r
+EFI_DEVICE_PATH_PROTOCOL *\r
+BmAdjustFvFilePath (\r
+ IN EFI_DEVICE_PATH_PROTOCOL *FilePath\r
)\r
{\r
EFI_STATUS Status;\r
EFI_DEVICE_PATH_PROTOCOL *FvFileNode;\r
EFI_HANDLE FvHandle;\r
EFI_LOADED_IMAGE_PROTOCOL *LoadedImage;\r
- UINT32 AuthenticationStatus;\r
UINTN FvHandleCount;\r
EFI_HANDLE *FvHandles;\r
EFI_DEVICE_PATH_PROTOCOL *NewDevicePath;\r
- VOID *FileBuffer;\r
+ EFI_DEVICE_PATH_PROTOCOL *FullPath;\r
\r
//\r
// Get the file buffer by using the exactly FilePath.\r
FvFileNode = FilePath;\r
Status = gBS->LocateDevicePath (&gEfiFirmwareVolume2ProtocolGuid, &FvFileNode, &FvHandle);\r
if (!EFI_ERROR (Status)) {\r
- FileBuffer = GetFileBufferByFilePath (TRUE, FilePath, FileSize, &AuthenticationStatus);\r
- if (FileBuffer != NULL) {\r
- *FullPath = DuplicateDevicePath (FilePath);\r
- }\r
- return FileBuffer;\r
+ return DuplicateDevicePath (FilePath);\r
}\r
\r
//\r
(VOID **) &LoadedImage\r
);\r
NewDevicePath = AppendDevicePathNode (DevicePathFromHandle (LoadedImage->DeviceHandle), FvFileNode);\r
- FileBuffer = BmGetFileBufferByFvFilePath (NewDevicePath, FullPath, FileSize);\r
+ FullPath = BmAdjustFvFilePath (NewDevicePath);\r
FreePool (NewDevicePath);\r
-\r
- if (FileBuffer != NULL) {\r
- return FileBuffer;\r
+ if (FullPath != NULL) {\r
+ return FullPath;\r
}\r
\r
//\r
&FvHandleCount,\r
&FvHandles\r
);\r
- for (Index = 0; (Index < FvHandleCount) && (FileBuffer == NULL); Index++) {\r
+ for (Index = 0; Index < FvHandleCount; Index++) {\r
if (FvHandles[Index] == LoadedImage->DeviceHandle) {\r
//\r
- // Skip current FV\r
+ // Skip current FV, it was handed in first step.\r
//\r
continue;\r
}\r
NewDevicePath = AppendDevicePathNode (DevicePathFromHandle (FvHandles[Index]), FvFileNode);\r
- FileBuffer = BmGetFileBufferByFvFilePath (NewDevicePath, FullPath, FileSize);\r
+ FullPath = BmAdjustFvFilePath (NewDevicePath);\r
FreePool (NewDevicePath);\r
+ if (FullPath != NULL) {\r
+ break;\r
+ }\r
}\r
\r
if (FvHandles != NULL) {\r
FreePool (FvHandles);\r
}\r
- return FileBuffer;\r
+ return FullPath;\r
}\r
\r
/**\r
\r
@param FilePath The device path pointing to a load option.\r
It could be a short-form device path.\r
- @param FullPath Return the full device path of the load option after\r
- short-form device path expanding.\r
- Caller is responsible to free it.\r
- @param FileSize Return the load option size.\r
+ @param FullPath The full path returned by the routine in last call.\r
+ Set to NULL in first call.\r
@param ShortformNode Pointer to the USB short-form device path node in the FilePath buffer.\r
\r
- @return The load option buffer. Caller is responsible to free the memory.\r
+ @return The next possible full path pointing to the load option.\r
+ Caller is responsible to free the memory.\r
**/\r
-VOID *\r
+EFI_DEVICE_PATH_PROTOCOL *\r
BmExpandUsbDevicePath (\r
IN EFI_DEVICE_PATH_PROTOCOL *FilePath,\r
- OUT EFI_DEVICE_PATH_PROTOCOL **FullPath,\r
- OUT UINTN *FileSize,\r
- IN EFI_DEVICE_PATH_PROTOCOL *ShortformNode\r
+ IN EFI_DEVICE_PATH_PROTOCOL *FullPath,\r
+ IN EFI_DEVICE_PATH_PROTOCOL *ShortformNode\r
)\r
{\r
UINTN ParentDevicePathSize;\r
EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath;\r
- EFI_DEVICE_PATH_PROTOCOL *FullDevicePath;\r
+ EFI_DEVICE_PATH_PROTOCOL *NextFullPath;\r
EFI_HANDLE *Handles;\r
UINTN HandleCount;\r
UINTN Index;\r
- VOID *FileBuffer;\r
+ BOOLEAN GetNext;\r
\r
+ NextFullPath = NULL;\r
+ GetNext = (BOOLEAN)(FullPath == NULL);\r
ParentDevicePathSize = (UINTN) ShortformNode - (UINTN) FilePath;\r
RemainingDevicePath = NextDevicePathNode (ShortformNode);\r
- FileBuffer = NULL;\r
Handles = BmFindUsbDevice (FilePath, ParentDevicePathSize, &HandleCount);\r
\r
- for (Index = 0; (Index < HandleCount) && (FileBuffer == NULL); Index++) {\r
- FullDevicePath = AppendDevicePath (DevicePathFromHandle (Handles[Index]), RemainingDevicePath);\r
- FileBuffer = EfiBootManagerGetLoadOptionBuffer (FullDevicePath, FullPath, FileSize);\r
- FreePool (FullDevicePath);\r
+ for (Index = 0; Index < HandleCount; Index++) {\r
+ FilePath = AppendDevicePath (DevicePathFromHandle (Handles[Index]), RemainingDevicePath);\r
+ if (FilePath == NULL) {\r
+ //\r
+ // Out of memory.\r
+ //\r
+ continue;\r
+ }\r
+ NextFullPath = BmGetNextLoadOptionDevicePath (FilePath, NULL);\r
+ FreePool (FilePath);\r
+ if (NextFullPath == NULL) {\r
+ //\r
+ // No BlockIo or SimpleFileSystem under FilePath.\r
+ //\r
+ continue;\r
+ }\r
+ if (GetNext) {\r
+ break;\r
+ } else {\r
+ GetNext = (BOOLEAN)(CompareMem (NextFullPath, FullPath, GetDevicePathSize (NextFullPath)) == 0);\r
+ FreePool (NextFullPath);\r
+ NextFullPath = NULL;\r
+ }\r
}\r
\r
if (Handles != NULL) {\r
FreePool (Handles);\r
}\r
\r
- return FileBuffer;\r
+ return NextFullPath;\r
}\r
\r
/**\r
\r
@param FilePath The device path pointing to a load option.\r
It could be a short-form device path.\r
- @param FullPath Return the full device path of the load option after\r
- short-form device path expanding.\r
- Caller is responsible to free it.\r
- @param FileSize Return the load option size.\r
+ @param FullPath The full path returned by the routine in last call.\r
+ Set to NULL in first call.\r
\r
- @return The load option buffer. Caller is responsible to free the memory.\r
+ @return The next possible full path pointing to the load option.\r
+ Caller is responsible to free the memory.\r
**/\r
-VOID *\r
+EFI_DEVICE_PATH_PROTOCOL *\r
BmExpandFileDevicePath (\r
IN EFI_DEVICE_PATH_PROTOCOL *FilePath,\r
- OUT EFI_DEVICE_PATH_PROTOCOL **FullPath,\r
- OUT UINTN *FileSize\r
+ IN EFI_DEVICE_PATH_PROTOCOL *FullPath\r
)\r
{\r
EFI_STATUS Status;\r
EFI_HANDLE *Handles;\r
EFI_BLOCK_IO_PROTOCOL *BlockIo;\r
UINTN MediaType;\r
- EFI_DEVICE_PATH_PROTOCOL *FullDevicePath;\r
- VOID *FileBuffer;\r
- UINT32 AuthenticationStatus;\r
+ EFI_DEVICE_PATH_PROTOCOL *NextFullPath;\r
+ BOOLEAN GetNext;\r
\r
EfiBootManagerConnectAll ();\r
Status = gBS->LocateHandleBuffer (ByProtocol, &gEfiSimpleFileSystemProtocolGuid, NULL, &HandleCount, &Handles);\r
Handles = NULL;\r
}\r
\r
+ GetNext = (BOOLEAN)(FullPath == NULL);\r
+ NextFullPath = NULL;\r
//\r
// Enumerate all removable media devices followed by all fixed media devices,\r
// followed by media devices which don't layer on block io.\r
(MediaType == 1 && BlockIo != NULL && !BlockIo->Media->RemovableMedia) ||\r
(MediaType == 2 && BlockIo == NULL)\r
) {\r
- FullDevicePath = AppendDevicePath (DevicePathFromHandle (Handles[Index]), FilePath);\r
- FileBuffer = GetFileBufferByFilePath (TRUE, FullDevicePath, FileSize, &AuthenticationStatus);\r
- if (FileBuffer != NULL) {\r
- *FullPath = FullDevicePath;\r
- FreePool (Handles);\r
- return FileBuffer;\r
+ NextFullPath = AppendDevicePath (DevicePathFromHandle (Handles[Index]), FilePath);\r
+ if (GetNext) {\r
+ break;\r
+ } else {\r
+ GetNext = (BOOLEAN)(CompareMem (NextFullPath, FullPath, GetDevicePathSize (NextFullPath)) == 0);\r
+ FreePool (NextFullPath);\r
+ NextFullPath = NULL;\r
}\r
- FreePool (FullDevicePath);\r
}\r
}\r
+ if (NextFullPath != NULL) {\r
+ break;\r
+ }\r
}\r
\r
if (Handles != NULL) {\r
FreePool (Handles);\r
}\r
\r
- *FullPath = NULL;\r
- return NULL;\r
+ return NextFullPath;\r
}\r
\r
/**\r
\r
@param FilePath The device path pointing to a load option.\r
It could be a short-form device path.\r
- @param FullPath Return the full device path of the load option after\r
- short-form device path expanding.\r
- Caller is responsible to free it.\r
- @param FileSize Return the load option size.\r
+ @param FullPath The full path returned by the routine in last call.\r
+ Set to NULL in first call.\r
\r
- @return The load option buffer. Caller is responsible to free the memory.\r
+ @return The next possible full path pointing to the load option.\r
+ Caller is responsible to free the memory.\r
**/\r
-VOID *\r
+EFI_DEVICE_PATH_PROTOCOL *\r
BmExpandUriDevicePath (\r
IN EFI_DEVICE_PATH_PROTOCOL *FilePath,\r
- OUT EFI_DEVICE_PATH_PROTOCOL **FullPath,\r
- OUT UINTN *FileSize\r
+ IN EFI_DEVICE_PATH_PROTOCOL *FullPath\r
)\r
{\r
EFI_STATUS Status;\r
UINTN Index;\r
UINTN HandleCount;\r
EFI_HANDLE *Handles;\r
- VOID *FileBuffer;\r
+ EFI_DEVICE_PATH_PROTOCOL *NextFullPath;\r
+ EFI_DEVICE_PATH_PROTOCOL *RamDiskDevicePath;\r
+ BOOLEAN GetNext;\r
\r
EfiBootManagerConnectAll ();\r
Status = gBS->LocateHandleBuffer (ByProtocol, &gEfiLoadFileProtocolGuid, NULL, &HandleCount, &Handles);\r
Handles = NULL;\r
}\r
\r
- FileBuffer = NULL;\r
+ NextFullPath = NULL;\r
+ GetNext = (BOOLEAN)(FullPath == NULL);\r
for (Index = 0; Index < HandleCount; Index++) {\r
- FileBuffer = BmGetFileBufferFromLoadFile (Handles[Index], FilePath, FullPath, FileSize);\r
- if (FileBuffer != NULL) {\r
+ NextFullPath = BmExpandLoadFile (Handles[Index], FilePath);\r
+\r
+ if (NextFullPath == NULL) {\r
+ continue;\r
+ }\r
+\r
+ if (GetNext) {\r
break;\r
+ } else {\r
+ GetNext = (BOOLEAN)(CompareMem (NextFullPath, FullPath, GetDevicePathSize (NextFullPath)) == 0);\r
+ //\r
+ // Free the resource occupied by the RAM disk.\r
+ //\r
+ RamDiskDevicePath = BmGetRamDiskDevicePath (NextFullPath);\r
+ if (RamDiskDevicePath != NULL) {\r
+ BmDestroyRamDisk (RamDiskDevicePath);\r
+ FreePool (RamDiskDevicePath);\r
+ }\r
+ FreePool (NextFullPath);\r
+ NextFullPath = NULL;\r
}\r
}\r
\r
FreePool (Handles);\r
}\r
\r
- return FileBuffer;\r
+ return NextFullPath;\r
}\r
\r
/**\r
\r
@param FilePath The device path pointing to a load option.\r
It could be a short-form device path.\r
- @param FullPath Return the full device path of the load option after\r
- short-form device path expanding.\r
- Caller is responsible to free it.\r
- @param FileSize Return the load option size.\r
\r
- @return The load option buffer. Caller is responsible to free the memory.\r
+ @return The full device path pointing to the load option.\r
**/\r
-VOID *\r
+EFI_DEVICE_PATH_PROTOCOL *\r
BmExpandPartitionDevicePath (\r
- IN EFI_DEVICE_PATH_PROTOCOL *FilePath,\r
- OUT EFI_DEVICE_PATH_PROTOCOL **FullPath,\r
- OUT UINTN *FileSize\r
+ IN EFI_DEVICE_PATH_PROTOCOL *FilePath\r
)\r
{\r
EFI_STATUS Status;\r
UINTN BlockIoHandleCount;\r
EFI_HANDLE *BlockIoBuffer;\r
- VOID *FileBuffer;\r
EFI_DEVICE_PATH_PROTOCOL *BlockIoDevicePath;\r
UINTN Index;\r
EFI_DEVICE_PATH_PROTOCOL *CachedDevicePath;\r
EFI_DEVICE_PATH_PROTOCOL *TempNewDevicePath;\r
EFI_DEVICE_PATH_PROTOCOL *TempDevicePath;\r
+ EFI_DEVICE_PATH_PROTOCOL *FullPath;\r
UINTN CachedDevicePathSize;\r
BOOLEAN NeedAdjust;\r
EFI_DEVICE_PATH_PROTOCOL *Instance;\r
UINTN Size;\r
\r
- FileBuffer = NULL;\r
//\r
// Check if there is prestore 'HDDP' variable.\r
// If exist, search the front path which point to partition node in the variable instants.\r
ASSERT_EFI_ERROR (Status);\r
}\r
\r
+ FullPath = NULL;\r
if (CachedDevicePath != NULL) {\r
TempNewDevicePath = CachedDevicePath;\r
NeedAdjust = FALSE;\r
Status = EfiBootManagerConnectDevicePath (Instance, NULL);\r
if (!EFI_ERROR (Status)) {\r
TempDevicePath = AppendDevicePath (Instance, NextDevicePathNode (FilePath));\r
- FileBuffer = EfiBootManagerGetLoadOptionBuffer (TempDevicePath, FullPath, FileSize);\r
+ //\r
+ // TempDevicePath = ACPI()/PCI()/ATA()/Partition()\r
+ // or = ACPI()/PCI()/ATA()/Partition()/.../A.EFI\r
+ //\r
+ // When TempDevicePath = ACPI()/PCI()/ATA()/Partition(),\r
+ // it may expand to two potienal full paths (nested partition, rarely happen):\r
+ // 1. ACPI()/PCI()/ATA()/Partition()/Partition(A1)/EFI/BootX64.EFI\r
+ // 2. ACPI()/PCI()/ATA()/Partition()/Partition(A2)/EFI/BootX64.EFI\r
+ // For simplicity, only #1 is returned.\r
+ //\r
+ FullPath = BmGetNextLoadOptionDevicePath (TempDevicePath, NULL);\r
FreePool (TempDevicePath);\r
\r
- if (FileBuffer != NULL) {\r
+ if (FullPath != NULL) {\r
//\r
// Adjust the 'HDDP' instances sequence if the matched one is not first one.\r
//\r
\r
FreePool (Instance);\r
FreePool (CachedDevicePath);\r
- return FileBuffer;\r
+ return FullPath;\r
}\r
}\r
}\r
// Find the matched partition device path\r
//\r
TempDevicePath = AppendDevicePath (BlockIoDevicePath, NextDevicePathNode (FilePath));\r
- FileBuffer = EfiBootManagerGetLoadOptionBuffer (TempDevicePath, FullPath, FileSize);\r
+ FullPath = BmGetNextLoadOptionDevicePath (TempDevicePath, NULL);\r
FreePool (TempDevicePath);\r
\r
- if (FileBuffer != NULL) {\r
+ if (FullPath != NULL) {\r
BmCachePartitionDevicePath (&CachedDevicePath, BlockIoDevicePath);\r
\r
//\r
if (BlockIoBuffer != NULL) {\r
FreePool (BlockIoBuffer);\r
}\r
- return FileBuffer;\r
+ return FullPath;\r
}\r
\r
/**\r
by appending EFI_REMOVABLE_MEDIA_FILE_NAME.\r
\r
@param DevicePath The media device path pointing to a BlockIo or SimpleFileSystem instance.\r
- @param FullPath Return the full device path pointing to the load option.\r
- @param FileSize Return the size of the load option.\r
+ @param FullPath The full path returned by the routine in last call.\r
+ Set to NULL in first call.\r
\r
- @return The load option buffer.\r
+ @return The next possible full path pointing to the load option.\r
+ Caller is responsible to free the memory.\r
**/\r
-VOID *\r
+EFI_DEVICE_PATH_PROTOCOL *\r
BmExpandMediaDevicePath (\r
IN EFI_DEVICE_PATH_PROTOCOL *DevicePath,\r
- OUT EFI_DEVICE_PATH_PROTOCOL **FullPath,\r
- OUT UINTN *FileSize\r
+ IN EFI_DEVICE_PATH_PROTOCOL *FullPath\r
)\r
{\r
EFI_STATUS Status;\r
EFI_BLOCK_IO_PROTOCOL *BlockIo;\r
VOID *Buffer;\r
EFI_DEVICE_PATH_PROTOCOL *TempDevicePath;\r
+ EFI_DEVICE_PATH_PROTOCOL *NextFullPath;\r
UINTN Size;\r
UINTN TempSize;\r
EFI_HANDLE *SimpleFileSystemHandles;\r
UINTN NumberSimpleFileSystemHandles;\r
UINTN Index;\r
- VOID *FileBuffer;\r
- UINT32 AuthenticationStatus;\r
+ BOOLEAN GetNext;\r
\r
+ GetNext = (BOOLEAN)(FullPath == NULL);\r
//\r
// Check whether the device is connected\r
//\r
if (!EFI_ERROR (Status)) {\r
ASSERT (IsDevicePathEnd (TempDevicePath));\r
\r
- TempDevicePath = FileDevicePath (Handle, EFI_REMOVABLE_MEDIA_FILE_NAME);\r
- FileBuffer = GetFileBufferByFilePath (TRUE, TempDevicePath, FileSize, &AuthenticationStatus);\r
- if (FileBuffer == NULL) {\r
- FreePool (TempDevicePath);\r
- TempDevicePath = NULL;\r
+ NextFullPath = FileDevicePath (Handle, EFI_REMOVABLE_MEDIA_FILE_NAME);\r
+ //\r
+ // For device path pointing to simple file system, it only expands to one full path.\r
+ //\r
+ if (GetNext) {\r
+ return NextFullPath;\r
+ } else {\r
+ FreePool (NextFullPath);\r
+ return NULL;\r
}\r
- *FullPath = TempDevicePath;\r
- return FileBuffer;\r
}\r
\r
+ Status = gBS->LocateDevicePath (&gEfiBlockIoProtocolGuid, &TempDevicePath, &Handle);\r
+ ASSERT_EFI_ERROR (Status);\r
+\r
//\r
- // For device boot option only pointing to the removable device handle, \r
- // should make sure all its children handles (its child partion or media handles) are created and connected. \r
+ // For device boot option only pointing to the removable device handle,\r
+ // should make sure all its children handles (its child partion or media handles)\r
+ // are created and connected.\r
//\r
gBS->ConnectController (Handle, NULL, NULL, TRUE);\r
\r
// returned. After the Block IO protocol is reinstalled, subsequent\r
// Block IO read/write will success.\r
//\r
- Status = gBS->LocateDevicePath (&gEfiBlockIoProtocolGuid, &TempDevicePath, &Handle);\r
- ASSERT_EFI_ERROR (Status);\r
Status = gBS->HandleProtocol (Handle, &gEfiBlockIoProtocolGuid, (VOID **) &BlockIo);\r
ASSERT_EFI_ERROR (Status);\r
Buffer = AllocatePool (BlockIo->Media->BlockSize);\r
//\r
// Detect the the default boot file from removable Media\r
//\r
- FileBuffer = NULL;\r
- *FullPath = NULL;\r
+ NextFullPath = NULL;\r
Size = GetDevicePathSize (DevicePath) - END_DEVICE_PATH_LENGTH;\r
gBS->LocateHandleBuffer (\r
ByProtocol,\r
// Check whether the device path of boot option is part of the SimpleFileSystem handle's device path\r
//\r
if ((Size <= TempSize) && (CompareMem (TempDevicePath, DevicePath, Size) == 0)) {\r
- TempDevicePath = FileDevicePath (SimpleFileSystemHandles[Index], EFI_REMOVABLE_MEDIA_FILE_NAME);\r
- FileBuffer = GetFileBufferByFilePath (TRUE, TempDevicePath, FileSize, &AuthenticationStatus);\r
- if (FileBuffer != NULL) {\r
- *FullPath = TempDevicePath;\r
+ NextFullPath = FileDevicePath (SimpleFileSystemHandles[Index], EFI_REMOVABLE_MEDIA_FILE_NAME);\r
+ if (GetNext) {\r
break;\r
+ } else {\r
+ GetNext = (BOOLEAN)(CompareMem (NextFullPath, FullPath, GetDevicePathSize (NextFullPath)) == 0);\r
+ FreePool (NextFullPath);\r
+ NextFullPath = NULL;\r
}\r
- FreePool (TempDevicePath);\r
}\r
}\r
\r
FreePool (SimpleFileSystemHandles);\r
}\r
\r
- return FileBuffer;\r
+ return NextFullPath;\r
}\r
\r
/**\r
Get the file buffer from the file system produced by Load File instance.\r
\r
@param LoadFileHandle The handle of LoadFile instance.\r
- @param FullPath Return the full device path pointing to the load option.\r
- @param FileSize Return the size of the load option.\r
@param RamDiskHandle Return the RAM Disk handle.\r
\r
- @return The load option buffer.\r
+ @return The next possible full path pointing to the load option.\r
+ Caller is responsible to free the memory.\r
**/\r
-VOID *\r
-BmGetFileBufferFromLoadFileSystem (\r
+EFI_DEVICE_PATH_PROTOCOL *\r
+BmExpandNetworkFileSystem (\r
IN EFI_HANDLE LoadFileHandle,\r
- OUT EFI_DEVICE_PATH_PROTOCOL **FullPath,\r
- OUT UINTN *FileSize,\r
OUT EFI_HANDLE *RamDiskHandle\r
)\r
{\r
if (!EFI_ERROR (Status) &&\r
(Handle == LoadFileHandle) &&\r
(DevicePathType (Node) == MEDIA_DEVICE_PATH) && (DevicePathSubType (Node) == MEDIA_RAM_DISK_DP)) {\r
+ //\r
+ // Find the BlockIo instance populated from the LoadFile.\r
+ //\r
Handle = Handles[Index];\r
break;\r
}\r
*RamDiskHandle = Handle;\r
\r
if (Handle != NULL) {\r
- return BmExpandMediaDevicePath (DevicePathFromHandle (Handle), FullPath, FileSize);\r
+ //\r
+ // Re-use BmExpandMediaDevicePath() to get the full device path of load option.\r
+ // But assume only one SimpleFileSystem can be found under the BlockIo.\r
+ //\r
+ return BmExpandMediaDevicePath (DevicePathFromHandle (Handle), NULL);\r
} else {\r
return NULL;\r
}\r
}\r
\r
-\r
/**\r
Return the RAM Disk device path created by LoadFile.\r
\r
\r
@param LoadFileHandle The specified Load File instance.\r
@param FilePath The file path which will pass to LoadFile().\r
- @param FullPath Return the full device path pointing to the load option.\r
- @param FileSize Return the size of the load option.\r
\r
- @return The load option buffer or NULL if fails.\r
+ @return The full device path pointing to the load option buffer.\r
**/\r
-VOID *\r
-BmGetFileBufferFromLoadFile (\r
+EFI_DEVICE_PATH_PROTOCOL *\r
+BmExpandLoadFile (\r
IN EFI_HANDLE LoadFileHandle,\r
- IN EFI_DEVICE_PATH_PROTOCOL *FilePath,\r
- OUT EFI_DEVICE_PATH_PROTOCOL **FullPath,\r
- OUT UINTN *FileSize\r
+ IN EFI_DEVICE_PATH_PROTOCOL *FilePath\r
)\r
{\r
EFI_STATUS Status;\r
EFI_LOAD_FILE_PROTOCOL *LoadFile;\r
VOID *FileBuffer;\r
- BOOLEAN LoadFileSystem;\r
EFI_HANDLE RamDiskHandle;\r
UINTN BufferSize;\r
-\r
- *FileSize = 0;\r
+ EFI_DEVICE_PATH_PROTOCOL *FullPath;\r
\r
Status = gBS->OpenProtocol (\r
LoadFileHandle,\r
return NULL;\r
}\r
\r
- LoadFileSystem = (BOOLEAN) (Status == EFI_WARN_FILE_SYSTEM);\r
- FileBuffer = LoadFileSystem ? AllocateReservedPages (EFI_SIZE_TO_PAGES (BufferSize)) : AllocatePool (BufferSize);\r
+ if (Status == EFI_BUFFER_TOO_SMALL) {\r
+ //\r
+ // The load option buffer is directly returned by LoadFile.\r
+ //\r
+ return DuplicateDevicePath (DevicePathFromHandle (LoadFileHandle));\r
+ }\r
+\r
+ //\r
+ // The load option resides in a RAM disk.\r
+ //\r
+ FileBuffer = AllocateReservedPages (EFI_SIZE_TO_PAGES (BufferSize));\r
if (FileBuffer == NULL) {\r
return NULL;\r
}\r
\r
Status = LoadFile->LoadFile (LoadFile, FilePath, TRUE, &BufferSize, FileBuffer);\r
if (EFI_ERROR (Status)) {\r
- if (LoadFileSystem) {\r
- FreePages (FileBuffer, EFI_SIZE_TO_PAGES (BufferSize));\r
- } else {\r
- FreePool (FileBuffer);\r
- }\r
+ FreePages (FileBuffer, EFI_SIZE_TO_PAGES (BufferSize));\r
return NULL;\r
}\r
\r
- if (LoadFileSystem) {\r
- FileBuffer = BmGetFileBufferFromLoadFileSystem (LoadFileHandle, FullPath, FileSize, &RamDiskHandle);\r
- if (FileBuffer == NULL) {\r
- //\r
- // If there is no bootable executable in the populated\r
- //\r
- BmDestroyRamDisk (DevicePathFromHandle (RamDiskHandle));\r
- }\r
- } else {\r
- *FileSize = BufferSize;\r
- *FullPath = DuplicateDevicePath (DevicePathFromHandle (LoadFileHandle));\r
+ FullPath = BmExpandNetworkFileSystem (LoadFileHandle, &RamDiskHandle);\r
+ if (FullPath == NULL) {\r
+ //\r
+ // Free the memory occupied by the RAM disk if there is no BlockIo or SimpleFileSystem instance.\r
+ //\r
+ BmDestroyRamDisk (DevicePathFromHandle (RamDiskHandle));\r
}\r
\r
- return FileBuffer;\r
+ return FullPath;\r
}\r
\r
/**\r
- Get the file buffer from all the Load File instances.\r
+ Return the full device path pointing to the load option.\r
+\r
+ FilePath may:\r
+ 1. Exactly matches to a LoadFile instance.\r
+ 2. Cannot match to any LoadFile instance. Wide match is required.\r
+ In either case, the routine may return:\r
+ 1. A copy of FilePath when FilePath matches to a LoadFile instance and\r
+ the LoadFile returns a load option buffer.\r
+ 2. A new device path with IP and URI information updated when wide match\r
+ happens.\r
+ 3. A new device path pointing to a load option in RAM disk.\r
+ In either case, only one full device path is returned for a specified\r
+ FilePath.\r
\r
@param FilePath The media device path pointing to a LoadFile instance.\r
- @param FullPath Return the full device path pointing to the load option.\r
- @param FileSize Return the size of the load option.\r
\r
@return The load option buffer.\r
**/\r
-VOID *\r
-BmGetFileBufferFromLoadFiles (\r
- IN EFI_DEVICE_PATH_PROTOCOL *FilePath,\r
- OUT EFI_DEVICE_PATH_PROTOCOL **FullPath,\r
- OUT UINTN *FileSize\r
+EFI_DEVICE_PATH_PROTOCOL *\r
+BmExpandLoadFiles (\r
+ IN EFI_DEVICE_PATH_PROTOCOL *FilePath\r
)\r
{\r
EFI_STATUS Status;\r
return NULL;\r
}\r
\r
- return BmGetFileBufferFromLoadFile (Handle, FilePath, FullPath, FileSize);\r
+ return BmExpandLoadFile (Handle, FilePath);\r
}\r
\r
/**\r
OUT EFI_DEVICE_PATH_PROTOCOL **FullPath,\r
OUT UINTN *FileSize\r
)\r
+{\r
+ *FullPath = NULL;\r
+\r
+ EfiBootManagerConnectDevicePath (FilePath, NULL);\r
+ return BmGetNextLoadOptionBuffer (LoadOptionTypeMax, FilePath, FullPath, FileSize);\r
+}\r
+\r
+/**\r
+ Get the next possible full path pointing to the load option.\r
+ The routine doesn't guarantee the returned full path points to an existing\r
+ file, and it also doesn't guarantee the existing file is a valid load option.\r
+ BmGetNextLoadOptionBuffer() guarantees.\r
+\r
+ @param FilePath The device path pointing to a load option.\r
+ It could be a short-form device path.\r
+ @param FullPath The full path returned by the routine in last call.\r
+ Set to NULL in first call.\r
+\r
+ @return The next possible full path pointing to the load option.\r
+ Caller is responsible to free the memory.\r
+**/\r
+EFI_DEVICE_PATH_PROTOCOL *\r
+BmGetNextLoadOptionDevicePath (\r
+ IN EFI_DEVICE_PATH_PROTOCOL *FilePath,\r
+ IN EFI_DEVICE_PATH_PROTOCOL *FullPath\r
+ )\r
{\r
EFI_HANDLE Handle;\r
- VOID *FileBuffer;\r
- UINT32 AuthenticationStatus;\r
EFI_DEVICE_PATH_PROTOCOL *Node;\r
EFI_STATUS Status;\r
\r
- ASSERT ((FilePath != NULL) && (FullPath != NULL) && (FileSize != NULL));\r
-\r
- EfiBootManagerConnectDevicePath (FilePath, NULL);\r
-\r
- *FullPath = NULL;\r
- *FileSize = 0;\r
- FileBuffer = NULL;\r
+ ASSERT (FilePath != NULL);\r
\r
//\r
// Boot from media device by adding a default file name \EFI\BOOT\BOOT{machine type short-name}.EFI\r
}\r
\r
if (!EFI_ERROR (Status) && IsDevicePathEnd (Node)) {\r
- return BmExpandMediaDevicePath (FilePath, FullPath, FileSize);\r
+ return BmExpandMediaDevicePath (FilePath, FullPath);\r
}\r
\r
//\r
//\r
// Expand the Harddrive device path\r
//\r
- return BmExpandPartitionDevicePath (FilePath, FullPath, FileSize);\r
+ if (FullPath == NULL) {\r
+ return BmExpandPartitionDevicePath (FilePath);\r
+ } else {\r
+ return NULL;\r
+ }\r
} else if ((DevicePathType (FilePath) == MEDIA_DEVICE_PATH) &&\r
(DevicePathSubType (FilePath) == MEDIA_FILEPATH_DP)) {\r
//\r
// Expand the File-path device path\r
//\r
- return BmExpandFileDevicePath (FilePath, FullPath, FileSize);\r
+ return BmExpandFileDevicePath (FilePath, FullPath);\r
} else if ((DevicePathType (FilePath) == MESSAGING_DEVICE_PATH) &&\r
(DevicePathSubType (FilePath) == MSG_URI_DP)) {\r
//\r
// Expand the URI device path\r
//\r
- return BmExpandUriDevicePath (FilePath, FullPath, FileSize);\r
+ return BmExpandUriDevicePath (FilePath, FullPath);\r
} else {\r
- for (Node = FilePath; !IsDevicePathEnd (Node); Node = NextDevicePathNode (Node)) {\r
- if ((DevicePathType (Node) == MESSAGING_DEVICE_PATH) &&\r
- ((DevicePathSubType (Node) == MSG_USB_CLASS_DP) || (DevicePathSubType (Node) == MSG_USB_WWID_DP))) {\r
- break;\r
+ Node = FilePath;\r
+ Status = gBS->LocateDevicePath (&gEfiUsbIoProtocolGuid, &Node, &Handle);\r
+ if (EFI_ERROR (Status)) {\r
+ //\r
+ // Only expand the USB WWID/Class device path\r
+ // when FilePath doesn't point to a physical UsbIo controller.\r
+ // Otherwise, infinite recursion will happen.\r
+ //\r
+ for (Node = FilePath; !IsDevicePathEnd (Node); Node = NextDevicePathNode (Node)) {\r
+ if ((DevicePathType (Node) == MESSAGING_DEVICE_PATH) &&\r
+ ((DevicePathSubType (Node) == MSG_USB_CLASS_DP) || (DevicePathSubType (Node) == MSG_USB_WWID_DP))) {\r
+ break;\r
+ }\r
}\r
- }\r
\r
- if (!IsDevicePathEnd (Node)) {\r
//\r
// Expand the USB WWID/Class device path\r
//\r
- FileBuffer = BmExpandUsbDevicePath (FilePath, FullPath, FileSize, Node);\r
- if ((FileBuffer == NULL) && (FilePath == Node)) {\r
- //\r
- // Boot Option device path starts with USB Class or USB WWID device path.\r
- // For Boot Option device path which doesn't begin with the USB Class or\r
- // USB WWID device path, it's not needed to connect again here.\r
- //\r
- BmConnectUsbShortFormDevicePath (FilePath);\r
- FileBuffer = BmExpandUsbDevicePath (FilePath, FullPath, FileSize, Node);\r
+ if (!IsDevicePathEnd (Node)) {\r
+ if (FilePath == Node) {\r
+ //\r
+ // Boot Option device path starts with USB Class or USB WWID device path.\r
+ // For Boot Option device path which doesn't begin with the USB Class or\r
+ // USB WWID device path, it's not needed to connect again here.\r
+ //\r
+ BmConnectUsbShortFormDevicePath (FilePath);\r
+ }\r
+ return BmExpandUsbDevicePath (FilePath, FullPath, Node);\r
}\r
- return FileBuffer;\r
}\r
}\r
\r
//\r
- // Get file buffer from FV file path.\r
+ // For the below cases, FilePath only expands to one Full path.\r
+ // So just handle the case when FullPath == NULL.\r
+ //\r
+ if (FullPath != NULL) {\r
+ return NULL;\r
+ }\r
+\r
+ //\r
+ // Load option resides in FV.\r
//\r
if (BmIsFvFilePath (FilePath)) {\r
- return BmGetFileBufferByFvFilePath (FilePath, FullPath, FileSize);\r
+ return BmAdjustFvFilePath (FilePath);\r
}\r
\r
//\r
- // Get file buffer from simple file system.\r
+ // Load option resides in Simple File System.\r
//\r
Node = FilePath;\r
Status = gBS->LocateDevicePath (&gEfiSimpleFileSystemProtocolGuid, &Node, &Handle);\r
if (!EFI_ERROR (Status)) {\r
- FileBuffer = GetFileBufferByFilePath (TRUE, FilePath, FileSize, &AuthenticationStatus);\r
- if (FileBuffer != NULL) {\r
- *FullPath = DuplicateDevicePath (FilePath);\r
- }\r
- return FileBuffer;\r
+ return DuplicateDevicePath (FilePath);\r
}\r
\r
- return BmGetFileBufferFromLoadFiles (FilePath, FullPath, FileSize);\r
+ //\r
+ // Last chance to try: Load option may be loaded through LoadFile.\r
+ //\r
+ return BmExpandLoadFiles (FilePath);\r
}\r
\r
/**\r
ImageHandle = NULL;\r
RamDiskDevicePath = NULL;\r
if (DevicePathType (BootOption->FilePath) != BBS_DEVICE_PATH) {\r
- Status = EFI_NOT_FOUND;\r
- FileBuffer = EfiBootManagerGetLoadOptionBuffer (BootOption->FilePath, &FilePath, &FileSize);\r
+ Status = EFI_NOT_FOUND;\r
+ FilePath = NULL;\r
+ EfiBootManagerConnectDevicePath (BootOption->FilePath, NULL);\r
+ FileBuffer = BmGetNextLoadOptionBuffer (LoadOptionTypeBoot, BootOption->FilePath, &FilePath, &FileSize);\r
if (FileBuffer != NULL) {\r
RamDiskDevicePath = BmGetRamDiskDevicePath (FilePath);\r
- }\r
- DEBUG_CODE (\r
- if (FileBuffer != NULL && CompareMem (BootOption->FilePath, FilePath, GetDevicePathSize (FilePath)) != 0) {\r
- DEBUG ((EFI_D_INFO, "[Bds] DevicePath expand: "));\r
- BmPrintDp (BootOption->FilePath);\r
- DEBUG ((EFI_D_INFO, " -> "));\r
- BmPrintDp (FilePath);\r
- DEBUG ((EFI_D_INFO, "\n"));\r
- }\r
- );\r
- if (BmIsLoadOptionPeHeaderValid (BootOption->OptionType, FileBuffer, FileSize)) {\r
+\r
REPORT_STATUS_CODE (EFI_PROGRESS_CODE, PcdGet32 (PcdProgressCodeOsLoaderLoad));\r
Status = gBS->LoadImage (\r
TRUE,\r
// Only check those added by BDS\r
// so that the boot options added by end-user or OS installer won't be deleted\r
//\r
- if (EfiBootManagerFindLoadOption (&NvBootOptions[Index], BootOptions, BootOptionCount) == (UINTN) -1) {\r
+ if (EfiBootManagerFindLoadOption (&NvBootOptions[Index], BootOptions, BootOptionCount) == -1) {\r
Status = EfiBootManagerDeleteLoadOptionVariable (NvBootOptions[Index].OptionNumber, LoadOptionTypeBoot);\r
//\r
// Deleting variable with current variable implementation shouldn't fail.\r
// Add new EFI boot options to NV\r
//\r
for (Index = 0; Index < BootOptionCount; Index++) {\r
- if (EfiBootManagerFindLoadOption (&BootOptions[Index], NvBootOptions, NvBootOptionCount) == (UINTN) -1) {\r
+ if (EfiBootManagerFindLoadOption (&BootOptions[Index], NvBootOptions, NvBootOptionCount) == -1) {\r
EfiBootManagerAddLoadOptionVariable (&BootOptions[Index], (UINTN) -1);\r
//\r
// Try best to add the boot options so continue upon failure.\r