/** @file\r
Library functions which relates with booting.\r
\r
-Copyright (c) 2011 - 2015, Intel Corporation. All rights reserved.<BR>\r
+Copyright (c) 2011 - 2016, Intel Corporation. All rights reserved.<BR>\r
(C) Copyright 2015 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
mBmLegacyBoot = LegacyBoot;\r
}\r
\r
+/**\r
+ Return TRUE when the boot option is auto-created instead of manually added.\r
+\r
+ @param BootOption Pointer to the boot option to check.\r
+\r
+ @retval TRUE The boot option is auto-created.\r
+ @retval FALSE The boot option is manually added.\r
+**/\r
+BOOLEAN\r
+BmIsAutoCreateBootOption (\r
+ EFI_BOOT_MANAGER_LOAD_OPTION *BootOption\r
+ )\r
+{\r
+ if ((BootOption->OptionalDataSize == sizeof (EFI_GUID)) &&\r
+ CompareGuid ((EFI_GUID *) BootOption->OptionalData, &mBmAutoCreateBootOptionGuid)\r
+ ) {\r
+ return TRUE;\r
+ } else {\r
+ return FALSE;\r
+ }\r
+}\r
+\r
/**\r
For a bootable Device path, return its boot type.\r
\r
\r
FV address may change across reboot. This routine promises the FV file device path is right.\r
\r
- @param DevicePath The Memory Mapped Device Path to get the file buffer.\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
**/\r
VOID *\r
-BmGetFileBufferByMemmapFv (\r
- IN EFI_DEVICE_PATH_PROTOCOL *DevicePath,\r
+BmGetFileBufferByFvFilePath (\r
+ IN EFI_DEVICE_PATH_PROTOCOL *FilePath,\r
OUT EFI_DEVICE_PATH_PROTOCOL **FullPath,\r
OUT UINTN *FileSize\r
)\r
EFI_HANDLE *FvHandles;\r
EFI_DEVICE_PATH_PROTOCOL *NewDevicePath;\r
VOID *FileBuffer;\r
- \r
- FvFileNode = DevicePath;\r
+\r
+ //\r
+ // Get the file buffer by using the exactly FilePath.\r
+ //\r
+ FvFileNode = FilePath;\r
Status = gBS->LocateDevicePath (&gEfiFirmwareVolume2ProtocolGuid, &FvFileNode, &FvHandle);\r
if (!EFI_ERROR (Status)) {\r
- FileBuffer = GetFileBufferByFilePath (TRUE, DevicePath, FileSize, &AuthenticationStatus);\r
+ FileBuffer = GetFileBufferByFilePath (TRUE, FilePath, FileSize, &AuthenticationStatus);\r
if (FileBuffer != NULL) {\r
- *FullPath = DuplicateDevicePath (DevicePath);\r
+ *FullPath = DuplicateDevicePath (FilePath);\r
}\r
return FileBuffer;\r
}\r
\r
- FvFileNode = NextDevicePathNode (DevicePath);\r
+ //\r
+ // Only wide match other FVs if it's a memory mapped FV file path.\r
+ //\r
+ if ((DevicePathType (FilePath) != HARDWARE_DEVICE_PATH) || (DevicePathSubType (FilePath) != HW_MEMMAP_DP)) {\r
+ return NULL;\r
+ }\r
+\r
+ FvFileNode = NextDevicePathNode (FilePath);\r
\r
//\r
// Firstly find the FV file in current FV\r
(VOID **) &LoadedImage\r
);\r
NewDevicePath = AppendDevicePathNode (DevicePathFromHandle (LoadedImage->DeviceHandle), FvFileNode);\r
- FileBuffer = BmGetFileBufferByMemmapFv (NewDevicePath, FullPath, FileSize);\r
+ FileBuffer = BmGetFileBufferByFvFilePath (NewDevicePath, FullPath, FileSize);\r
FreePool (NewDevicePath);\r
\r
if (FileBuffer != NULL) {\r
continue;\r
}\r
NewDevicePath = AppendDevicePathNode (DevicePathFromHandle (FvHandles[Index]), FvFileNode);\r
- FileBuffer = BmGetFileBufferByMemmapFv (NewDevicePath, FullPath, FileSize);\r
+ FileBuffer = BmGetFileBufferByFvFilePath (NewDevicePath, FullPath, FileSize);\r
FreePool (NewDevicePath);\r
}\r
\r
}\r
\r
/**\r
- Check if it's a Memory Mapped FV Device Path.\r
+ Check if it's a Device Path pointing to FV file.\r
\r
The function doesn't garentee the device path points to existing FV file.\r
\r
@param DevicePath Input device path.\r
\r
- @retval TRUE The device path is a Memory Mapped FV Device Path.\r
- @retval FALSE The device path is NOT a Memory Mapped FV Device Path.\r
+ @retval TRUE The device path is a FV File Device Path.\r
+ @retval FALSE The device path is NOT a FV File Device Path.\r
**/\r
BOOLEAN\r
-BmIsMemmapFvFilePath (\r
+BmIsFvFilePath (\r
IN EFI_DEVICE_PATH_PROTOCOL *DevicePath\r
)\r
{\r
- EFI_DEVICE_PATH_PROTOCOL *FileNode;\r
+ EFI_STATUS Status;\r
+ EFI_HANDLE Handle;\r
+ EFI_DEVICE_PATH_PROTOCOL *Node;\r
+\r
+ Node = DevicePath;\r
+ Status = gBS->LocateDevicePath (&gEfiFirmwareVolume2ProtocolGuid, &Node, &Handle);\r
+ if (!EFI_ERROR (Status)) {\r
+ return TRUE;\r
+ }\r
\r
if ((DevicePathType (DevicePath) == HARDWARE_DEVICE_PATH) && (DevicePathSubType (DevicePath) == HW_MEMMAP_DP)) {\r
- FileNode = NextDevicePathNode (DevicePath);\r
- if ((DevicePathType (FileNode) == MEDIA_DEVICE_PATH) && (DevicePathSubType (FileNode) == MEDIA_PIWG_FW_FILE_DP)) {\r
- return IsDevicePathEnd (NextDevicePathNode (FileNode));\r
+ DevicePath = NextDevicePathNode (DevicePath);\r
+ if ((DevicePathType (DevicePath) == MEDIA_DEVICE_PATH) && (DevicePathSubType (DevicePath) == MEDIA_PIWG_FW_FILE_DP)) {\r
+ return IsDevicePathEnd (NextDevicePathNode (DevicePath));\r
}\r
}\r
-\r
return FALSE;\r
}\r
\r
return FileBuffer;\r
}\r
\r
+/**\r
+ Expand File-path device path node to be full device path in platform.\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
+**/\r
+VOID *\r
+BmExpandFileDevicePath (\r
+ IN EFI_DEVICE_PATH_PROTOCOL *FilePath,\r
+ OUT EFI_DEVICE_PATH_PROTOCOL **FullPath,\r
+ OUT UINTN *FileSize\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ UINTN Index;\r
+ UINTN HandleCount;\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
+ \r
+ EfiBootManagerConnectAll ();\r
+ Status = gBS->LocateHandleBuffer (ByProtocol, &gEfiSimpleFileSystemProtocolGuid, NULL, &HandleCount, &Handles);\r
+ if (EFI_ERROR (Status)) {\r
+ HandleCount = 0;\r
+ Handles = NULL;\r
+ }\r
+\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
+ //\r
+ for (MediaType = 0; MediaType < 3; MediaType++) {\r
+ for (Index = 0; Index < HandleCount; Index++) {\r
+ Status = gBS->HandleProtocol (Handles[Index], &gEfiBlockIoProtocolGuid, (VOID *) &BlockIo);\r
+ if (EFI_ERROR (Status)) {\r
+ BlockIo = NULL;\r
+ }\r
+ if ((MediaType == 0 && BlockIo != NULL && BlockIo->Media->RemovableMedia) ||\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
+ }\r
+ FreePool (FullDevicePath);\r
+ }\r
+ }\r
+ }\r
+\r
+ if (Handles != NULL) {\r
+ FreePool (Handles);\r
+ }\r
+\r
+ *FullPath = NULL;\r
+ return NULL;\r
+}\r
+\r
/**\r
Save the partition DevicePath to the CachedDevicePath as the first instance.\r
\r
return FileBuffer;\r
}\r
\r
+/**\r
+ Check whether Left and Right are the same without matching the specific\r
+ device path data in IP device path and URI device path node.\r
+\r
+ @retval TRUE Left and Right are the same.\r
+ @retval FALSE Left and Right are the different.\r
+**/\r
+BOOLEAN\r
+BmMatchHttpBootDevicePath (\r
+ IN EFI_DEVICE_PATH_PROTOCOL *Left,\r
+ IN EFI_DEVICE_PATH_PROTOCOL *Right\r
+ )\r
+{\r
+ for (; !IsDevicePathEnd (Left) && !IsDevicePathEnd (Right)\r
+ ; Left = NextDevicePathNode (Left), Right = NextDevicePathNode (Right)\r
+ ) {\r
+ if (CompareMem (Left, Right, DevicePathNodeLength (Left)) != 0) {\r
+ if ((DevicePathType (Left) != MESSAGING_DEVICE_PATH) || (DevicePathType (Right) != MESSAGING_DEVICE_PATH)) {\r
+ return FALSE;\r
+ }\r
+\r
+ if (((DevicePathSubType (Left) != MSG_IPv4_DP) || (DevicePathSubType (Right) != MSG_IPv4_DP)) &&\r
+ ((DevicePathSubType (Left) != MSG_IPv6_DP) || (DevicePathSubType (Right) != MSG_IPv6_DP)) &&\r
+ ((DevicePathSubType (Left) != MSG_URI_DP) || (DevicePathSubType (Right) != MSG_URI_DP))\r
+ ) {\r
+ return FALSE;\r
+ }\r
+ }\r
+ }\r
+ return (BOOLEAN) (IsDevicePathEnd (Left) && IsDevicePathEnd (Right));\r
+}\r
+\r
+/**\r
+ Get the file buffer from Load File instance.\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
+BmGetFileBufferFromLoadFile (\r
+ IN EFI_DEVICE_PATH_PROTOCOL *FilePath,\r
+ OUT EFI_DEVICE_PATH_PROTOCOL **FullPath,\r
+ OUT UINTN *FileSize\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ EFI_HANDLE Handle;\r
+ VOID *FileBuffer;\r
+ EFI_HANDLE *Handles;\r
+ UINTN HandleCount;\r
+ UINTN Index;\r
+ EFI_DEVICE_PATH_PROTOCOL *Node;\r
+ EFI_LOAD_FILE_PROTOCOL *LoadFile;\r
+ UINTN BufferSize;\r
+\r
+ //\r
+ // Get file buffer from load file instance.\r
+ //\r
+ Node = FilePath;\r
+ Status = gBS->LocateDevicePath (&gEfiLoadFileProtocolGuid, &Node, &Handle);\r
+ if (!EFI_ERROR (Status) && IsDevicePathEnd (Node)) {\r
+ //\r
+ // When wide match happens, pass full device path to LoadFile (),\r
+ // otherwise, pass remaining device path to LoadFile ().\r
+ //\r
+ FilePath = Node;\r
+ } else {\r
+ Handle = NULL;\r
+ //\r
+ // Use wide match algorithm to find one when\r
+ // cannot find a LoadFile instance to exactly match the FilePath\r
+ //\r
+ Status = gBS->LocateHandleBuffer (\r
+ ByProtocol,\r
+ &gEfiLoadFileProtocolGuid,\r
+ NULL,\r
+ &HandleCount,\r
+ &Handles\r
+ );\r
+ if (EFI_ERROR (Status)) {\r
+ Handles = NULL;\r
+ HandleCount = 0;\r
+ }\r
+ for (Index = 0; Index < HandleCount; Index++) {\r
+ if (BmMatchHttpBootDevicePath (DevicePathFromHandle (Handles[Index]), FilePath)) {\r
+ Handle = Handles[Index];\r
+ break;\r
+ }\r
+ }\r
+ if (Handles != NULL) {\r
+ FreePool (Handles);\r
+ }\r
+ }\r
+\r
+ if (Handle == NULL) {\r
+ return NULL;\r
+ }\r
+\r
+ Status = gBS->HandleProtocol (Handle, &gEfiLoadFileProtocolGuid, (VOID **) &LoadFile);\r
+ ASSERT_EFI_ERROR (Status);\r
+\r
+ BufferSize = 0;\r
+ FileBuffer = NULL;\r
+ Status = LoadFile->LoadFile (LoadFile, FilePath, TRUE, &BufferSize, FileBuffer);\r
+ if (Status == EFI_BUFFER_TOO_SMALL) {\r
+ FileBuffer = AllocatePool (BufferSize);\r
+ if (FileBuffer != NULL) {\r
+ Status = EFI_SUCCESS;\r
+ }\r
+ }\r
+\r
+ if (!EFI_ERROR (Status)) {\r
+ Status = LoadFile->LoadFile (LoadFile, FilePath, TRUE, &BufferSize, FileBuffer);\r
+ }\r
+\r
+ if (!EFI_ERROR (Status)) {\r
+ //\r
+ // LoadFile () may cause the device path of the Handle be updated.\r
+ //\r
+ *FullPath = DuplicateDevicePath (DevicePathFromHandle (Handle));\r
+ *FileSize = BufferSize;\r
+ return FileBuffer;\r
+ } else {\r
+ return NULL;\r
+ }\r
+}\r
+\r
/**\r
Get the load option by its device path.\r
\r
// Expand the Harddrive device path\r
//\r
return BmExpandPartitionDevicePath (FilePath, FullPath, FileSize);\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
} else {\r
for (Node = FilePath; !IsDevicePathEnd (Node); Node = NextDevicePathNode (Node)) {\r
if ((DevicePathType (Node) == MESSAGING_DEVICE_PATH) &&\r
}\r
\r
//\r
- // Fix up the boot option path if it points to a FV in memory map style of device path\r
+ // Get file buffer from FV file path.\r
//\r
- if (BmIsMemmapFvFilePath (FilePath)) {\r
- return BmGetFileBufferByMemmapFv (FilePath, FullPath, FileSize);\r
+ if (BmIsFvFilePath (FilePath)) {\r
+ return BmGetFileBufferByFvFilePath (FilePath, FullPath, FileSize);\r
}\r
\r
//\r
- // Directly reads the load option when it doesn't reside in simple file system instance (LoadFile/LoadFile2),\r
- // or it directly points to a file in simple file system instance.\r
+ // Get file buffer from simple file system.\r
//\r
Node = FilePath;\r
- Status = gBS->LocateDevicePath (&gEfiLoadFileProtocolGuid, &Node, &Handle);\r
- FileBuffer = GetFileBufferByFilePath (TRUE, FilePath, FileSize, &AuthenticationStatus);\r
- if (FileBuffer != NULL) {\r
- if (EFI_ERROR (Status)) {\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
- } else {\r
- //\r
- // LoadFile () may cause the device path of the Handle be updated.\r
- //\r
- *FullPath = AppendDevicePath (DevicePathFromHandle (Handle), Node);\r
}\r
+ return FileBuffer;\r
}\r
\r
- return FileBuffer;\r
+ return BmGetFileBufferFromLoadFile (FilePath, FullPath, FileSize);\r
}\r
\r
/**\r
// 6. Adjust the different type memory page number just before booting\r
// and save the updated info into the variable for next boot to use\r
//\r
- if ((BootOption->Attributes & LOAD_OPTION_CATEGORY) == LOAD_OPTION_CATEGORY_BOOT) {\r
- if (PcdGetBool (PcdResetOnMemoryTypeInformationChange)) {\r
- BmSetMemoryTypeInformationVariable ();\r
- }\r
- }\r
+ BmSetMemoryTypeInformationVariable (\r
+ (BOOLEAN) ((BootOption->Attributes & LOAD_OPTION_CATEGORY) == LOAD_OPTION_CATEGORY_BOOT)\r
+ );\r
\r
DEBUG_CODE_BEGIN();\r
if (BootOption->Description == NULL) {\r
Status = gBS->HandleProtocol (ImageHandle, &gEfiLoadedImageProtocolGuid, (VOID **) &ImageInfo);\r
ASSERT_EFI_ERROR (Status);\r
\r
- ImageInfo->LoadOptionsSize = BootOption->OptionalDataSize;\r
- ImageInfo->LoadOptions = BootOption->OptionalData;\r
+ if (!BmIsAutoCreateBootOption (BootOption)) {\r
+ ImageInfo->LoadOptionsSize = BootOption->OptionalDataSize;\r
+ ImageInfo->LoadOptions = BootOption->OptionalData;\r
+ }\r
\r
//\r
// Clean to NULL because the image is loaded directly from the firmwares boot manager.\r
for (Index = 0; Index < NvBootOptionCount; Index++) {\r
if (((DevicePathType (NvBootOptions[Index].FilePath) != BBS_DEVICE_PATH) || \r
(DevicePathSubType (NvBootOptions[Index].FilePath) != BBS_BBS_DP)\r
- ) &&\r
- (NvBootOptions[Index].OptionalDataSize == sizeof (EFI_GUID)) &&\r
- CompareGuid ((EFI_GUID *) NvBootOptions[Index].OptionalData, &mBmAutoCreateBootOptionGuid)\r
+ ) && BmIsAutoCreateBootOption (&NvBootOptions[Index])\r
) {\r
//\r
// Only check those added by BDS\r