/** @file\r
Library functions which relates with booting.\r
\r
+(C) Copyright 2015 Hewlett-Packard Development Company, L.P.<BR>\r
Copyright (c) 2011 - 2015, Intel Corporation. All rights reserved.<BR>\r
This program and the accompanying materials\r
are licensed and made available under the terms and conditions of the BSD License\r
EFI_BOOT_MANAGER_REFRESH_LEGACY_BOOT_OPTION mBmRefreshLegacyBootOption = NULL;\r
EFI_BOOT_MANAGER_LEGACY_BOOT mBmLegacyBoot = NULL;\r
\r
+LIST_ENTRY mPlatformBootDescriptionHandlers = INITIALIZE_LIST_HEAD_VARIABLE (mPlatformBootDescriptionHandlers);\r
+\r
///\r
/// This GUID is used for an EFI Variable that stores the front device pathes\r
/// for a partial device path that starts with the HD node.\r
@retval MessageNetworkBoot If given device path contains MESSAGING_DEVICE_PATH type device path node\r
and its last device path node's subtype is MSG_MAC_ADDR_DP, MSG_VLAN_DP,\r
MSG_IPv4_DP or MSG_IPv6_DP.\r
+ @retval MessageHttpBoot If given device path contains MESSAGING_DEVICE_PATH type device path node\r
+ and its last device path node's subtype is MSG_URI_DP.\r
@retval UnsupportedBoot If tiven device path doesn't match the above condition, it's not supported.\r
\r
**/\r
// If the device path not only point to driver device, it is not a messaging device path,\r
//\r
if (!IsDevicePathEndType (NextNode)) {\r
- break;\r
+ continue;\r
}\r
\r
switch (DevicePathSubType (Node)) {\r
case MSG_IPv6_DP:\r
return BmMessageNetworkBoot;\r
break;\r
+\r
+ case MSG_URI_DP:\r
+ return BmMessageHttpBoot;\r
+ break;\r
}\r
}\r
}\r
CHAR16 *SerialNumber;\r
CHAR16 *Description;\r
EFI_USB_DEVICE_DESCRIPTOR DevDesc;\r
+ UINTN DescMaxSize;\r
\r
Status = gBS->HandleProtocol (\r
Handle,\r
return NULL;\r
}\r
\r
- Description = AllocateZeroPool (StrSize (Manufacturer) + StrSize (Product) + StrSize (SerialNumber));\r
+ DescMaxSize = StrSize (Manufacturer) + StrSize (Product) + StrSize (SerialNumber);\r
+ Description = AllocateZeroPool (DescMaxSize);\r
ASSERT (Description != NULL);\r
- StrCat (Description, Manufacturer);\r
- StrCat (Description, L" ");\r
+ StrCatS (Description, DescMaxSize/sizeof(CHAR16), Manufacturer);\r
+ StrCatS (Description, DescMaxSize/sizeof(CHAR16), L" ");\r
\r
- StrCat (Description, Product); \r
- StrCat (Description, L" ");\r
+ StrCatS (Description, DescMaxSize/sizeof(CHAR16), Product); \r
+ StrCatS (Description, DescMaxSize/sizeof(CHAR16), L" ");\r
\r
- StrCat (Description, SerialNumber);\r
+ StrCatS (Description, DescMaxSize/sizeof(CHAR16), SerialNumber);\r
\r
if (Manufacturer != &NullChar) {\r
FreePool (Manufacturer);\r
IN EFI_HANDLE Handle\r
)\r
{\r
- EFI_STATUS Status;\r
- CHAR16 *Description;\r
- EFI_BLOCK_IO_PROTOCOL *BlockIo;\r
+ EFI_STATUS Status;\r
+ CHAR16 *Description;\r
+ EFI_BLOCK_IO_PROTOCOL *BlockIo;\r
+ EFI_SIMPLE_FILE_SYSTEM_PROTOCOL *Fs;\r
\r
switch (BmDevicePathType (DevicePathFromHandle (Handle))) {\r
case BmAcpiFloppyBoot:\r
}\r
break;\r
\r
+ case BmMessageNetworkBoot:\r
+ Description = L"Network";\r
+ break;\r
+\r
+ case BmMessageHttpBoot:\r
+ Description = L"Http";\r
+ break;\r
+\r
default:\r
- Description = L"Misc Device";\r
+ Status = gBS->HandleProtocol (Handle, &gEfiSimpleFileSystemProtocolGuid, (VOID **) &Fs);\r
+ if (!EFI_ERROR (Status)) {\r
+ Description = L"Non-Block Boot Device";\r
+ } else {\r
+ Description = L"Misc Device";\r
+ }\r
break;\r
}\r
\r
return AllocateCopyPool (StrSize (Description), Description);\r
}\r
\r
-BM_GET_BOOT_DESCRIPTION mBmGetBootDescription[] = {\r
+/**\r
+ Register the platform provided boot description handler.\r
+\r
+ @param Handler The platform provided boot description handler\r
+\r
+ @retval EFI_SUCCESS The handler was registered successfully.\r
+ @retval EFI_ALREADY_STARTED The handler was already registered.\r
+ @retval EFI_OUT_OF_RESOURCES There is not enough resource to perform the registration.\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+EfiBootManagerRegisterBootDescriptionHandler (\r
+ IN EFI_BOOT_MANAGER_BOOT_DESCRIPTION_HANDLER Handler\r
+ )\r
+{\r
+ LIST_ENTRY *Link;\r
+ BM_BOOT_DESCRIPTION_ENTRY *Entry;\r
+\r
+ for ( Link = GetFirstNode (&mPlatformBootDescriptionHandlers)\r
+ ; !IsNull (&mPlatformBootDescriptionHandlers, Link)\r
+ ; Link = GetNextNode (&mPlatformBootDescriptionHandlers, Link)\r
+ ) {\r
+ Entry = CR (Link, BM_BOOT_DESCRIPTION_ENTRY, Link, BM_BOOT_DESCRIPTION_ENTRY_SIGNATURE);\r
+ if (Entry->Handler == Handler) {\r
+ return EFI_ALREADY_STARTED;\r
+ }\r
+ }\r
+\r
+ Entry = AllocatePool (sizeof (BM_BOOT_DESCRIPTION_ENTRY));\r
+ if (Entry == NULL) {\r
+ return EFI_OUT_OF_RESOURCES;\r
+ }\r
+\r
+ Entry->Signature = BM_BOOT_DESCRIPTION_ENTRY_SIGNATURE;\r
+ Entry->Handler = Handler;\r
+ InsertTailList (&mPlatformBootDescriptionHandlers, &Entry->Link);\r
+ return EFI_SUCCESS;\r
+}\r
+\r
+BM_GET_BOOT_DESCRIPTION mBmBootDescriptionHandlers[] = {\r
BmGetUsbDescription,\r
BmGetDescriptionFromDiskInfo,\r
BmGetMiscDescription\r
};\r
\r
+/**\r
+ Return the boot description for the controller.\r
+\r
+ @param Handle Controller handle.\r
+\r
+ @return The description string.\r
+**/\r
+CHAR16 *\r
+BmGetBootDescription (\r
+ IN EFI_HANDLE Handle\r
+ )\r
+{\r
+ LIST_ENTRY *Link;\r
+ BM_BOOT_DESCRIPTION_ENTRY *Entry;\r
+ CHAR16 *Description;\r
+ CHAR16 *DefaultDescription;\r
+ CHAR16 *Temp;\r
+ UINTN Index;\r
+\r
+ //\r
+ // Firstly get the default boot description\r
+ //\r
+ DefaultDescription = NULL;\r
+ for (Index = 0; Index < sizeof (mBmBootDescriptionHandlers) / sizeof (mBmBootDescriptionHandlers[0]); Index++) {\r
+ DefaultDescription = mBmBootDescriptionHandlers[Index] (Handle);\r
+ if (DefaultDescription != NULL) {\r
+ //\r
+ // Avoid description confusion between UEFI & Legacy boot option by adding "UEFI " prefix\r
+ // ONLY for core provided boot description handler.\r
+ //\r
+ Temp = AllocatePool (StrSize (DefaultDescription) + sizeof (mBmUefiPrefix)); \r
+ ASSERT (Temp != NULL);\r
+ StrCpyS ( Temp, \r
+ (StrSize (DefaultDescription) + sizeof (mBmUefiPrefix))/sizeof(CHAR16), \r
+ mBmUefiPrefix\r
+ );\r
+ StrCatS ( Temp, \r
+ (StrSize (DefaultDescription) + sizeof (mBmUefiPrefix))/sizeof(CHAR16), \r
+ DefaultDescription\r
+ );\r
+ FreePool (DefaultDescription);\r
+ DefaultDescription = Temp;\r
+ break;\r
+ }\r
+ }\r
+ ASSERT (DefaultDescription != NULL);\r
+\r
+ //\r
+ // Secondly query platform for the better boot description\r
+ //\r
+ for ( Link = GetFirstNode (&mPlatformBootDescriptionHandlers)\r
+ ; !IsNull (&mPlatformBootDescriptionHandlers, Link)\r
+ ; Link = GetNextNode (&mPlatformBootDescriptionHandlers, Link)\r
+ ) {\r
+ Entry = CR (Link, BM_BOOT_DESCRIPTION_ENTRY, Link, BM_BOOT_DESCRIPTION_ENTRY_SIGNATURE);\r
+ Description = Entry->Handler (Handle, DefaultDescription);\r
+ if (Description != NULL) {\r
+ FreePool (DefaultDescription);\r
+ return Description;\r
+ }\r
+ }\r
+\r
+ return DefaultDescription;\r
+}\r
+\r
/**\r
Check whether a USB device match the specified USB WWID device path. This\r
function follows "Load Option Processing" behavior in UEFI specification.\r
EFI_DEVICE_PATH_PROTOCOL *UsbIoDevicePath;\r
EFI_USB_IO_PROTOCOL *UsbIo;\r
UINTN Index;\r
- UINTN UsbIoDevicePathSize;\r
BOOLEAN Matched;\r
\r
ASSERT (UsbIoHandleCount != NULL); \r
UsbIoDevicePath = DevicePathFromHandle (UsbIoHandles[Index]);\r
Matched = FALSE;\r
if (!EFI_ERROR (Status) && (UsbIoDevicePath != NULL)) {\r
- UsbIoDevicePathSize = GetDevicePathSize (UsbIoDevicePath) - END_DEVICE_PATH_LENGTH;\r
\r
//\r
// Compare starting part of UsbIoHandle's device path with ParentDevicePath.\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
//\r
+ Node = FilePath;\r
+ Status = gBS->LocateDevicePath (&gEfiLoadFileProtocolGuid, &Node, &Handle);\r
FileBuffer = GetFileBufferByFilePath (TRUE, FilePath, FileSize, &AuthenticationStatus);\r
if (FileBuffer != NULL) {\r
- *FullPath = DuplicateDevicePath (FilePath);\r
+ if (EFI_ERROR (Status)) {\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
}\r
\r
return FileBuffer;\r
);\r
}\r
\r
+/**\r
+ Enumerate all boot option descriptions and append " 2"/" 3"/... to make\r
+ unique description.\r
+\r
+ @param BootOptions Array of boot options.\r
+ @param BootOptionCount Count of boot options.\r
+**/\r
+VOID\r
+BmMakeBootOptionDescriptionUnique (\r
+ EFI_BOOT_MANAGER_LOAD_OPTION *BootOptions,\r
+ UINTN BootOptionCount\r
+ )\r
+{\r
+ UINTN Base;\r
+ UINTN Index;\r
+ UINTN DescriptionSize;\r
+ UINTN MaxSuffixSize;\r
+ BOOLEAN *Visited;\r
+ UINTN MatchCount;\r
+\r
+ if (BootOptionCount == 0) {\r
+ return;\r
+ }\r
+\r
+ //\r
+ // Calculate the maximum buffer size for the number suffix.\r
+ // The initial sizeof (CHAR16) is for the blank space before the number.\r
+ //\r
+ MaxSuffixSize = sizeof (CHAR16);\r
+ for (Index = BootOptionCount; Index != 0; Index = Index / 10) {\r
+ MaxSuffixSize += sizeof (CHAR16);\r
+ }\r
+\r
+ Visited = AllocateZeroPool (sizeof (BOOLEAN) * BootOptionCount);\r
+ ASSERT (Visited != NULL);\r
+\r
+ for (Base = 0; Base < BootOptionCount; Base++) {\r
+ if (!Visited[Base]) {\r
+ MatchCount = 1;\r
+ Visited[Base] = TRUE;\r
+ DescriptionSize = StrSize (BootOptions[Base].Description);\r
+ for (Index = Base + 1; Index < BootOptionCount; Index++) {\r
+ if (!Visited[Index] && StrCmp (BootOptions[Base].Description, BootOptions[Index].Description) == 0) {\r
+ Visited[Index] = TRUE;\r
+ MatchCount++;\r
+ FreePool (BootOptions[Index].Description);\r
+ BootOptions[Index].Description = AllocatePool (DescriptionSize + MaxSuffixSize);\r
+ UnicodeSPrint (\r
+ BootOptions[Index].Description, DescriptionSize + MaxSuffixSize,\r
+ L"%s %d",\r
+ BootOptions[Base].Description, MatchCount\r
+ );\r
+ }\r
+ }\r
+ }\r
+ }\r
+\r
+ FreePool (Visited);\r
+}\r
+\r
/**\r
Emuerate all possible bootable medias in the following order:\r
1. Removable BlockIo - The boot option only points to the removable media\r
{\r
EFI_STATUS Status;\r
EFI_BOOT_MANAGER_LOAD_OPTION *BootOptions;\r
- UINT16 NonBlockNumber;\r
UINTN HandleCount;\r
EFI_HANDLE *Handles;\r
EFI_BLOCK_IO_PROTOCOL *BlkIo;\r
UINTN Removable;\r
UINTN Index;\r
- UINTN FunctionIndex;\r
- CHAR16 *Temp;\r
- CHAR16 *DescriptionPtr;\r
- CHAR16 Description[30];\r
+ CHAR16 *Description;\r
\r
ASSERT (BootOptionCount != NULL);\r
\r
continue;\r
}\r
\r
- DescriptionPtr = NULL;\r
- for (FunctionIndex = 0; FunctionIndex < sizeof (mBmGetBootDescription) / sizeof (mBmGetBootDescription[0]); FunctionIndex++) {\r
- DescriptionPtr = mBmGetBootDescription[FunctionIndex] (Handles[Index]);\r
- if (DescriptionPtr != NULL) {\r
- break;\r
- }\r
- }\r
-\r
- if (DescriptionPtr == NULL) {\r
- continue;\r
- }\r
-\r
- //\r
- // Avoid description confusion between UEFI & Legacy boot option by adding "UEFI " prefix\r
- //\r
- Temp = AllocatePool (StrSize (DescriptionPtr) + sizeof (mBmUefiPrefix)); \r
- ASSERT (Temp != NULL);\r
- StrCpy (Temp, mBmUefiPrefix);\r
- StrCat (Temp, DescriptionPtr);\r
- FreePool (DescriptionPtr);\r
- DescriptionPtr = Temp;\r
-\r
+ Description = BmGetBootDescription (Handles[Index]);\r
BootOptions = ReallocatePool (\r
sizeof (EFI_BOOT_MANAGER_LOAD_OPTION) * (*BootOptionCount),\r
sizeof (EFI_BOOT_MANAGER_LOAD_OPTION) * (*BootOptionCount + 1),\r
LoadOptionNumberUnassigned,\r
LoadOptionTypeBoot,\r
LOAD_OPTION_ACTIVE,\r
- DescriptionPtr,\r
+ Description,\r
DevicePathFromHandle (Handles[Index]),\r
NULL,\r
0\r
);\r
ASSERT_EFI_ERROR (Status);\r
\r
- FreePool (DescriptionPtr);\r
+ FreePool (Description);\r
}\r
}\r
\r
//\r
// Parse simple file system not based on block io\r
//\r
- NonBlockNumber = 0;\r
gBS->LocateHandleBuffer (\r
ByProtocol,\r
&gEfiSimpleFileSystemProtocolGuid,\r
//\r
continue;\r
}\r
- UnicodeSPrint (Description, sizeof (Description), NonBlockNumber > 0 ? L"%s %d" : L"%s", L"UEFI Non-Block Boot Device", NonBlockNumber);\r
- \r
+ Description = BmGetBootDescription (Handles[Index]);\r
BootOptions = ReallocatePool (\r
sizeof (EFI_BOOT_MANAGER_LOAD_OPTION) * (*BootOptionCount),\r
sizeof (EFI_BOOT_MANAGER_LOAD_OPTION) * (*BootOptionCount + 1),\r
0\r
);\r
ASSERT_EFI_ERROR (Status);\r
+ FreePool (Description);\r
}\r
\r
if (HandleCount != 0) {\r
);\r
for (Index = 0; Index < HandleCount; Index++) {\r
\r
- UnicodeSPrint (Description, sizeof (Description), Index > 0 ? L"%s %d" : L"%s", L"UEFI Network", Index);\r
-\r
+ Description = BmGetBootDescription (Handles[Index]);\r
BootOptions = ReallocatePool (\r
sizeof (EFI_BOOT_MANAGER_LOAD_OPTION) * (*BootOptionCount),\r
sizeof (EFI_BOOT_MANAGER_LOAD_OPTION) * (*BootOptionCount + 1),\r
0\r
);\r
ASSERT_EFI_ERROR (Status);\r
+ FreePool (Description);\r
}\r
\r
if (HandleCount != 0) {\r
FreePool (Handles);\r
}\r
\r
+ BmMakeBootOptionDescriptionUnique (BootOptions, *BootOptionCount);\r
return BootOptions;\r
}\r
\r