]> git.proxmox.com Git - mirror_edk2.git/blame - MdeModulePkg/Library/UefiBootManagerLib/BmBoot.c
MdeModulePkg/Bds: Fix VS2010/VS2012 build failure.
[mirror_edk2.git] / MdeModulePkg / Library / UefiBootManagerLib / BmBoot.c
CommitLineData
067ed98a
RN
1/** @file\r
2 Library functions which relates with booting.\r
3\r
525839ed 4Copyright (c) 2011 - 2016, Intel Corporation. All rights reserved.<BR>\r
5d3a9896 5(C) Copyright 2015 Hewlett Packard Enterprise Development LP<BR>\r
067ed98a
RN
6This program and the accompanying materials\r
7are licensed and made available under the terms and conditions of the BSD License\r
8which accompanies this distribution. The full text of the license may be found at\r
9http://opensource.org/licenses/bsd-license.php\r
10\r
11THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
12WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
13\r
14**/\r
15\r
16#include "InternalBm.h"\r
17\r
18#define VENDOR_IDENTIFICATION_OFFSET 3\r
19#define VENDOR_IDENTIFICATION_LENGTH 8\r
20#define PRODUCT_IDENTIFICATION_OFFSET 11\r
21#define PRODUCT_IDENTIFICATION_LENGTH 16\r
22\r
23CONST UINT16 mBmUsbLangId = 0x0409; // English\r
24CHAR16 mBmUefiPrefix[] = L"UEFI ";\r
25\r
26EFI_BOOT_MANAGER_REFRESH_LEGACY_BOOT_OPTION mBmRefreshLegacyBootOption = NULL;\r
27EFI_BOOT_MANAGER_LEGACY_BOOT mBmLegacyBoot = NULL;\r
28\r
f41c71d2
RN
29LIST_ENTRY mPlatformBootDescriptionHandlers = INITIALIZE_LIST_HEAD_VARIABLE (mPlatformBootDescriptionHandlers);\r
30\r
067ed98a
RN
31///\r
32/// This GUID is used for an EFI Variable that stores the front device pathes\r
33/// for a partial device path that starts with the HD node.\r
34///\r
35EFI_GUID mBmHardDriveBootVariableGuid = { 0xfab7e9e1, 0x39dd, 0x4f2b, { 0x84, 0x08, 0xe2, 0x0e, 0x90, 0x6c, 0xb6, 0xde } };\r
36EFI_GUID mBmAutoCreateBootOptionGuid = { 0x8108ac4e, 0x9f11, 0x4d59, { 0x85, 0x0e, 0xe2, 0x1a, 0x52, 0x2c, 0x59, 0xb2 } };\r
37\r
38/**\r
39 The function registers the legacy boot support capabilities.\r
40\r
41 @param RefreshLegacyBootOption The function pointer to create all the legacy boot options.\r
42 @param LegacyBoot The function pointer to boot the legacy boot option.\r
43**/\r
44VOID\r
45EFIAPI\r
46EfiBootManagerRegisterLegacyBootSupport (\r
47 EFI_BOOT_MANAGER_REFRESH_LEGACY_BOOT_OPTION RefreshLegacyBootOption,\r
48 EFI_BOOT_MANAGER_LEGACY_BOOT LegacyBoot\r
49 )\r
50{\r
51 mBmRefreshLegacyBootOption = RefreshLegacyBootOption;\r
52 mBmLegacyBoot = LegacyBoot;\r
53}\r
54\r
404bd442
RN
55/**\r
56 Return TRUE when the boot option is auto-created instead of manually added.\r
57\r
58 @param BootOption Pointer to the boot option to check.\r
59\r
60 @retval TRUE The boot option is auto-created.\r
61 @retval FALSE The boot option is manually added.\r
62**/\r
63BOOLEAN\r
64BmIsAutoCreateBootOption (\r
65 EFI_BOOT_MANAGER_LOAD_OPTION *BootOption\r
66 )\r
67{\r
68 if ((BootOption->OptionalDataSize == sizeof (EFI_GUID)) &&\r
69 CompareGuid ((EFI_GUID *) BootOption->OptionalData, &mBmAutoCreateBootOptionGuid)\r
70 ) {\r
71 return TRUE;\r
72 } else {\r
73 return FALSE;\r
74 }\r
75}\r
76\r
067ed98a
RN
77/**\r
78 For a bootable Device path, return its boot type.\r
79\r
80 @param DevicePath The bootable device Path to check\r
81\r
82 @retval AcpiFloppyBoot If given device path contains ACPI_DEVICE_PATH type device path node\r
83 which HID is floppy device.\r
84 @retval MessageAtapiBoot If given device path contains MESSAGING_DEVICE_PATH type device path node\r
85 and its last device path node's subtype is MSG_ATAPI_DP.\r
86 @retval MessageSataBoot If given device path contains MESSAGING_DEVICE_PATH type device path node\r
87 and its last device path node's subtype is MSG_SATA_DP.\r
88 @retval MessageScsiBoot If given device path contains MESSAGING_DEVICE_PATH type device path node\r
89 and its last device path node's subtype is MSG_SCSI_DP.\r
90 @retval MessageUsbBoot If given device path contains MESSAGING_DEVICE_PATH type device path node\r
91 and its last device path node's subtype is MSG_USB_DP.\r
92 @retval MessageNetworkBoot If given device path contains MESSAGING_DEVICE_PATH type device path node\r
93 and its last device path node's subtype is MSG_MAC_ADDR_DP, MSG_VLAN_DP,\r
94 MSG_IPv4_DP or MSG_IPv6_DP.\r
ebf735f1
RN
95 @retval MessageHttpBoot If given device path contains MESSAGING_DEVICE_PATH type device path node\r
96 and its last device path node's subtype is MSG_URI_DP.\r
067ed98a
RN
97 @retval UnsupportedBoot If tiven device path doesn't match the above condition, it's not supported.\r
98\r
99**/\r
100BM_BOOT_TYPE\r
101BmDevicePathType (\r
102 IN EFI_DEVICE_PATH_PROTOCOL *DevicePath\r
103 )\r
104{\r
105 EFI_DEVICE_PATH_PROTOCOL *Node;\r
106 EFI_DEVICE_PATH_PROTOCOL *NextNode;\r
107\r
108 ASSERT (DevicePath != NULL);\r
109\r
110 for (Node = DevicePath; !IsDevicePathEndType (Node); Node = NextDevicePathNode (Node)) {\r
111 switch (DevicePathType (Node)) {\r
112\r
113 case ACPI_DEVICE_PATH:\r
114 if (EISA_ID_TO_NUM (((ACPI_HID_DEVICE_PATH *) Node)->HID) == 0x0604) {\r
115 return BmAcpiFloppyBoot;\r
116 }\r
117 break;\r
118\r
119 case HARDWARE_DEVICE_PATH:\r
120 if (DevicePathSubType (Node) == HW_CONTROLLER_DP) {\r
121 return BmHardwareDeviceBoot;\r
122 }\r
123 break;\r
124\r
125 case MESSAGING_DEVICE_PATH:\r
126 //\r
127 // Skip LUN device node\r
128 //\r
129 NextNode = Node;\r
130 do {\r
131 NextNode = NextDevicePathNode (NextNode);\r
132 } while (\r
133 (DevicePathType (NextNode) == MESSAGING_DEVICE_PATH) &&\r
134 (DevicePathSubType(NextNode) == MSG_DEVICE_LOGICAL_UNIT_DP)\r
135 );\r
136\r
137 //\r
138 // If the device path not only point to driver device, it is not a messaging device path,\r
139 //\r
140 if (!IsDevicePathEndType (NextNode)) {\r
ebf735f1 141 continue;\r
067ed98a
RN
142 }\r
143\r
144 switch (DevicePathSubType (Node)) {\r
145 case MSG_ATAPI_DP:\r
146 return BmMessageAtapiBoot;\r
147 break;\r
148\r
149 case MSG_SATA_DP:\r
150 return BmMessageSataBoot;\r
151 break;\r
152\r
153 case MSG_USB_DP:\r
154 return BmMessageUsbBoot;\r
155 break;\r
156\r
157 case MSG_SCSI_DP:\r
158 return BmMessageScsiBoot;\r
159 break;\r
160\r
161 case MSG_MAC_ADDR_DP:\r
162 case MSG_VLAN_DP:\r
163 case MSG_IPv4_DP:\r
164 case MSG_IPv6_DP:\r
165 return BmMessageNetworkBoot;\r
166 break;\r
ebf735f1
RN
167\r
168 case MSG_URI_DP:\r
169 return BmMessageHttpBoot;\r
170 break;\r
067ed98a
RN
171 }\r
172 }\r
173 }\r
174\r
175 return BmMiscBoot;\r
176}\r
177\r
178/**\r
179 Find the boot option in the NV storage and return the option number.\r
180\r
181 @param OptionToFind Boot option to be checked.\r
182\r
183 @return The option number of the found boot option.\r
184\r
185**/\r
186UINTN\r
187BmFindBootOptionInVariable (\r
188 IN EFI_BOOT_MANAGER_LOAD_OPTION *OptionToFind\r
189 )\r
190{\r
191 EFI_STATUS Status;\r
192 EFI_BOOT_MANAGER_LOAD_OPTION BootOption;\r
193 UINTN OptionNumber;\r
194 CHAR16 OptionName[BM_OPTION_NAME_LEN];\r
195 EFI_BOOT_MANAGER_LOAD_OPTION *BootOptions;\r
196 UINTN BootOptionCount;\r
197 UINTN Index;\r
198 \r
199 OptionNumber = LoadOptionNumberUnassigned;\r
200\r
201 //\r
202 // Try to match the variable exactly if the option number is assigned\r
203 //\r
204 if (OptionToFind->OptionNumber != LoadOptionNumberUnassigned) {\r
205 UnicodeSPrint (\r
206 OptionName, sizeof (OptionName), L"%s%04x",\r
207 mBmLoadOptionName[OptionToFind->OptionType], OptionToFind->OptionNumber\r
208 );\r
209 Status = EfiBootManagerVariableToLoadOption (OptionName, &BootOption);\r
210\r
211 if (!EFI_ERROR (Status)) {\r
212 ASSERT (OptionToFind->OptionNumber == BootOption.OptionNumber);\r
213 if ((OptionToFind->Attributes == BootOption.Attributes) &&\r
214 (StrCmp (OptionToFind->Description, BootOption.Description) == 0) &&\r
215 (CompareMem (OptionToFind->FilePath, BootOption.FilePath, GetDevicePathSize (OptionToFind->FilePath)) == 0) &&\r
216 (OptionToFind->OptionalDataSize == BootOption.OptionalDataSize) &&\r
217 (CompareMem (OptionToFind->OptionalData, BootOption.OptionalData, OptionToFind->OptionalDataSize) == 0)\r
218 ) {\r
219 OptionNumber = OptionToFind->OptionNumber;\r
220 }\r
221 EfiBootManagerFreeLoadOption (&BootOption);\r
222 }\r
223 }\r
224\r
225 //\r
226 // The option number assigned is either incorrect or unassigned.\r
227 //\r
228 if (OptionNumber == LoadOptionNumberUnassigned) {\r
229 BootOptions = EfiBootManagerGetLoadOptions (&BootOptionCount, LoadOptionTypeBoot);\r
230\r
5d3a9896 231 Index = EfiBootManagerFindLoadOption (OptionToFind, BootOptions, BootOptionCount);\r
067ed98a
RN
232 if (Index != -1) {\r
233 OptionNumber = BootOptions[Index].OptionNumber;\r
234 }\r
235\r
236 EfiBootManagerFreeLoadOptions (BootOptions, BootOptionCount);\r
237 }\r
238\r
239 return OptionNumber;\r
240}\r
241\r
242/**\r
243 Get the file buffer using a Memory Mapped Device Path.\r
244\r
245 FV address may change across reboot. This routine promises the FV file device path is right.\r
246\r
525839ed 247 @param FilePath The Memory Mapped Device Path to get the file buffer.\r
067ed98a
RN
248 @param FullPath Receive the updated FV Device Path pointint to the file.\r
249 @param FileSize Receive the file buffer size.\r
250\r
251 @return The file buffer.\r
252**/\r
253VOID *\r
525839ed
RN
254BmGetFileBufferByFvFilePath (\r
255 IN EFI_DEVICE_PATH_PROTOCOL *FilePath,\r
067ed98a
RN
256 OUT EFI_DEVICE_PATH_PROTOCOL **FullPath,\r
257 OUT UINTN *FileSize\r
258 )\r
259{\r
260 EFI_STATUS Status;\r
261 UINTN Index;\r
262 EFI_DEVICE_PATH_PROTOCOL *FvFileNode;\r
263 EFI_HANDLE FvHandle;\r
264 EFI_LOADED_IMAGE_PROTOCOL *LoadedImage;\r
265 UINT32 AuthenticationStatus;\r
266 UINTN FvHandleCount;\r
267 EFI_HANDLE *FvHandles;\r
268 EFI_DEVICE_PATH_PROTOCOL *NewDevicePath;\r
269 VOID *FileBuffer;\r
525839ed
RN
270\r
271 //\r
272 // Get the file buffer by using the exactly FilePath.\r
273 //\r
274 FvFileNode = FilePath;\r
067ed98a
RN
275 Status = gBS->LocateDevicePath (&gEfiFirmwareVolume2ProtocolGuid, &FvFileNode, &FvHandle);\r
276 if (!EFI_ERROR (Status)) {\r
525839ed 277 FileBuffer = GetFileBufferByFilePath (TRUE, FilePath, FileSize, &AuthenticationStatus);\r
067ed98a 278 if (FileBuffer != NULL) {\r
525839ed 279 *FullPath = DuplicateDevicePath (FilePath);\r
067ed98a
RN
280 }\r
281 return FileBuffer;\r
282 }\r
283\r
525839ed
RN
284 //\r
285 // Only wide match other FVs if it's a memory mapped FV file path.\r
286 //\r
287 if ((DevicePathType (FilePath) != HARDWARE_DEVICE_PATH) || (DevicePathSubType (FilePath) != HW_MEMMAP_DP)) {\r
288 return NULL;\r
289 }\r
290\r
291 FvFileNode = NextDevicePathNode (FilePath);\r
067ed98a
RN
292\r
293 //\r
294 // Firstly find the FV file in current FV\r
295 //\r
296 gBS->HandleProtocol (\r
297 gImageHandle,\r
298 &gEfiLoadedImageProtocolGuid,\r
299 (VOID **) &LoadedImage\r
300 );\r
301 NewDevicePath = AppendDevicePathNode (DevicePathFromHandle (LoadedImage->DeviceHandle), FvFileNode);\r
525839ed 302 FileBuffer = BmGetFileBufferByFvFilePath (NewDevicePath, FullPath, FileSize);\r
067ed98a
RN
303 FreePool (NewDevicePath);\r
304\r
305 if (FileBuffer != NULL) {\r
306 return FileBuffer;\r
307 }\r
308\r
309 //\r
310 // Secondly find the FV file in all other FVs\r
311 //\r
312 gBS->LocateHandleBuffer (\r
313 ByProtocol,\r
314 &gEfiFirmwareVolume2ProtocolGuid,\r
315 NULL,\r
316 &FvHandleCount,\r
317 &FvHandles\r
318 );\r
319 for (Index = 0; (Index < FvHandleCount) && (FileBuffer == NULL); Index++) {\r
320 if (FvHandles[Index] == LoadedImage->DeviceHandle) {\r
321 //\r
322 // Skip current FV\r
323 //\r
324 continue;\r
325 }\r
326 NewDevicePath = AppendDevicePathNode (DevicePathFromHandle (FvHandles[Index]), FvFileNode);\r
525839ed 327 FileBuffer = BmGetFileBufferByFvFilePath (NewDevicePath, FullPath, FileSize);\r
067ed98a
RN
328 FreePool (NewDevicePath);\r
329 }\r
330 \r
331 if (FvHandles != NULL) {\r
332 FreePool (FvHandles);\r
333 }\r
334 return FileBuffer;\r
335}\r
336\r
337/**\r
525839ed 338 Check if it's a Device Path pointing to FV file.\r
067ed98a
RN
339 \r
340 The function doesn't garentee the device path points to existing FV file.\r
341\r
342 @param DevicePath Input device path.\r
343\r
525839ed
RN
344 @retval TRUE The device path is a FV File Device Path.\r
345 @retval FALSE The device path is NOT a FV File Device Path.\r
067ed98a
RN
346**/\r
347BOOLEAN\r
525839ed 348BmIsFvFilePath (\r
067ed98a
RN
349 IN EFI_DEVICE_PATH_PROTOCOL *DevicePath\r
350 )\r
351{\r
525839ed
RN
352 EFI_STATUS Status;\r
353 EFI_HANDLE Handle;\r
354 EFI_DEVICE_PATH_PROTOCOL *Node;\r
355\r
356 Node = DevicePath;\r
357 Status = gBS->LocateDevicePath (&gEfiFirmwareVolume2ProtocolGuid, &Node, &Handle);\r
358 if (!EFI_ERROR (Status)) {\r
359 return TRUE;\r
360 }\r
067ed98a
RN
361\r
362 if ((DevicePathType (DevicePath) == HARDWARE_DEVICE_PATH) && (DevicePathSubType (DevicePath) == HW_MEMMAP_DP)) {\r
525839ed
RN
363 DevicePath = NextDevicePathNode (DevicePath);\r
364 if ((DevicePathType (DevicePath) == MEDIA_DEVICE_PATH) && (DevicePathSubType (DevicePath) == MEDIA_PIWG_FW_FILE_DP)) {\r
365 return IsDevicePathEnd (NextDevicePathNode (DevicePath));\r
067ed98a
RN
366 }\r
367 }\r
067ed98a
RN
368 return FALSE;\r
369}\r
370\r
371/**\r
372 Check whether a USB device match the specified USB Class device path. This\r
373 function follows "Load Option Processing" behavior in UEFI specification.\r
374\r
375 @param UsbIo USB I/O protocol associated with the USB device.\r
376 @param UsbClass The USB Class device path to match.\r
377\r
378 @retval TRUE The USB device match the USB Class device path.\r
379 @retval FALSE The USB device does not match the USB Class device path.\r
380\r
381**/\r
382BOOLEAN\r
383BmMatchUsbClass (\r
384 IN EFI_USB_IO_PROTOCOL *UsbIo,\r
385 IN USB_CLASS_DEVICE_PATH *UsbClass\r
386 )\r
387{\r
388 EFI_STATUS Status;\r
389 EFI_USB_DEVICE_DESCRIPTOR DevDesc;\r
390 EFI_USB_INTERFACE_DESCRIPTOR IfDesc;\r
391 UINT8 DeviceClass;\r
392 UINT8 DeviceSubClass;\r
393 UINT8 DeviceProtocol;\r
394\r
395 if ((DevicePathType (UsbClass) != MESSAGING_DEVICE_PATH) ||\r
396 (DevicePathSubType (UsbClass) != MSG_USB_CLASS_DP)){\r
397 return FALSE;\r
398 }\r
399\r
400 //\r
401 // Check Vendor Id and Product Id.\r
402 //\r
403 Status = UsbIo->UsbGetDeviceDescriptor (UsbIo, &DevDesc);\r
404 if (EFI_ERROR (Status)) {\r
405 return FALSE;\r
406 }\r
407\r
408 if ((UsbClass->VendorId != 0xffff) &&\r
409 (UsbClass->VendorId != DevDesc.IdVendor)) {\r
410 return FALSE;\r
411 }\r
412\r
413 if ((UsbClass->ProductId != 0xffff) &&\r
414 (UsbClass->ProductId != DevDesc.IdProduct)) {\r
415 return FALSE;\r
416 }\r
417\r
418 DeviceClass = DevDesc.DeviceClass;\r
419 DeviceSubClass = DevDesc.DeviceSubClass;\r
420 DeviceProtocol = DevDesc.DeviceProtocol;\r
421 if (DeviceClass == 0) {\r
422 //\r
423 // If Class in Device Descriptor is set to 0, use the Class, SubClass and\r
424 // Protocol in Interface Descriptor instead.\r
425 //\r
426 Status = UsbIo->UsbGetInterfaceDescriptor (UsbIo, &IfDesc);\r
427 if (EFI_ERROR (Status)) {\r
428 return FALSE;\r
429 }\r
430\r
431 DeviceClass = IfDesc.InterfaceClass;\r
432 DeviceSubClass = IfDesc.InterfaceSubClass;\r
433 DeviceProtocol = IfDesc.InterfaceProtocol;\r
434 }\r
435\r
436 //\r
437 // Check Class, SubClass and Protocol.\r
438 //\r
439 if ((UsbClass->DeviceClass != 0xff) &&\r
440 (UsbClass->DeviceClass != DeviceClass)) {\r
441 return FALSE;\r
442 }\r
443\r
444 if ((UsbClass->DeviceSubClass != 0xff) &&\r
445 (UsbClass->DeviceSubClass != DeviceSubClass)) {\r
446 return FALSE;\r
447 }\r
448\r
449 if ((UsbClass->DeviceProtocol != 0xff) &&\r
450 (UsbClass->DeviceProtocol != DeviceProtocol)) {\r
451 return FALSE;\r
452 }\r
453\r
454 return TRUE;\r
455}\r
456\r
457/**\r
458 Eliminate the extra spaces in the Str to one space.\r
459\r
460 @param Str Input string info.\r
461**/\r
462VOID\r
463BmEliminateExtraSpaces (\r
464 IN CHAR16 *Str\r
465 )\r
466{\r
467 UINTN Index;\r
468 UINTN ActualIndex;\r
469\r
470 for (Index = 0, ActualIndex = 0; Str[Index] != L'\0'; Index++) {\r
471 if ((Str[Index] != L' ') || ((ActualIndex > 0) && (Str[ActualIndex - 1] != L' '))) {\r
472 Str[ActualIndex++] = Str[Index];\r
473 }\r
474 }\r
475 Str[ActualIndex] = L'\0';\r
476}\r
477\r
478/**\r
479 Try to get the controller's ATA/ATAPI description.\r
480\r
481 @param Handle Controller handle.\r
482\r
483 @return The description string.\r
484**/\r
485CHAR16 *\r
486BmGetDescriptionFromDiskInfo (\r
487 IN EFI_HANDLE Handle\r
488 )\r
489{\r
490 UINTN Index;\r
491 EFI_STATUS Status;\r
492 EFI_DISK_INFO_PROTOCOL *DiskInfo;\r
493 UINT32 BufferSize;\r
494 EFI_ATAPI_IDENTIFY_DATA IdentifyData;\r
495 EFI_SCSI_INQUIRY_DATA InquiryData;\r
496 CHAR16 *Description;\r
497 UINTN Length;\r
498 CONST UINTN ModelNameLength = 40;\r
499 CONST UINTN SerialNumberLength = 20;\r
500 CHAR8 *StrPtr;\r
501 UINT8 Temp;\r
502\r
503 Description = NULL;\r
504\r
505 Status = gBS->HandleProtocol (\r
506 Handle,\r
507 &gEfiDiskInfoProtocolGuid,\r
508 (VOID **) &DiskInfo\r
509 );\r
510 if (EFI_ERROR (Status)) {\r
511 return NULL;\r
512 }\r
513\r
514 if (CompareGuid (&DiskInfo->Interface, &gEfiDiskInfoAhciInterfaceGuid) || \r
515 CompareGuid (&DiskInfo->Interface, &gEfiDiskInfoIdeInterfaceGuid)) {\r
516 BufferSize = sizeof (EFI_ATAPI_IDENTIFY_DATA);\r
517 Status = DiskInfo->Identify (\r
518 DiskInfo,\r
519 &IdentifyData,\r
520 &BufferSize\r
521 );\r
522 if (!EFI_ERROR (Status)) {\r
523 Description = AllocateZeroPool ((ModelNameLength + SerialNumberLength + 2) * sizeof (CHAR16));\r
524 ASSERT (Description != NULL);\r
525 for (Index = 0; Index + 1 < ModelNameLength; Index += 2) {\r
526 Description[Index] = (CHAR16) IdentifyData.ModelName[Index + 1];\r
527 Description[Index + 1] = (CHAR16) IdentifyData.ModelName[Index];\r
528 }\r
529\r
530 Length = Index;\r
531 Description[Length++] = L' ';\r
532\r
533 for (Index = 0; Index + 1 < SerialNumberLength; Index += 2) {\r
534 Description[Length + Index] = (CHAR16) IdentifyData.SerialNo[Index + 1];\r
535 Description[Length + Index + 1] = (CHAR16) IdentifyData.SerialNo[Index];\r
536 }\r
537 Length += Index;\r
538 Description[Length++] = L'\0';\r
539 ASSERT (Length == ModelNameLength + SerialNumberLength + 2);\r
540\r
541 BmEliminateExtraSpaces (Description);\r
542 }\r
543 } else if (CompareGuid (&DiskInfo->Interface, &gEfiDiskInfoScsiInterfaceGuid)) {\r
544 BufferSize = sizeof (EFI_SCSI_INQUIRY_DATA);\r
545 Status = DiskInfo->Inquiry (\r
546 DiskInfo,\r
547 &InquiryData,\r
548 &BufferSize\r
549 );\r
550 if (!EFI_ERROR (Status)) {\r
551 Description = AllocateZeroPool ((VENDOR_IDENTIFICATION_LENGTH + PRODUCT_IDENTIFICATION_LENGTH + 2) * sizeof (CHAR16));\r
552 ASSERT (Description != NULL);\r
553\r
554 //\r
555 // Per SCSI spec, EFI_SCSI_INQUIRY_DATA.Reserved_5_95[3 - 10] save the Verdor identification\r
556 // EFI_SCSI_INQUIRY_DATA.Reserved_5_95[11 - 26] save the product identification, \r
557 // Here combine the vendor identification and product identification to the description.\r
558 //\r
559 StrPtr = (CHAR8 *) (&InquiryData.Reserved_5_95[VENDOR_IDENTIFICATION_OFFSET]);\r
560 Temp = StrPtr[VENDOR_IDENTIFICATION_LENGTH];\r
561 StrPtr[VENDOR_IDENTIFICATION_LENGTH] = '\0';\r
562 AsciiStrToUnicodeStr (StrPtr, Description);\r
563 StrPtr[VENDOR_IDENTIFICATION_LENGTH] = Temp;\r
564\r
565 //\r
566 // Add one space at the middle of vendor information and product information.\r
567 //\r
568 Description[VENDOR_IDENTIFICATION_LENGTH] = L' ';\r
569\r
570 StrPtr = (CHAR8 *) (&InquiryData.Reserved_5_95[PRODUCT_IDENTIFICATION_OFFSET]);\r
571 StrPtr[PRODUCT_IDENTIFICATION_LENGTH] = '\0';\r
572 AsciiStrToUnicodeStr (StrPtr, Description + VENDOR_IDENTIFICATION_LENGTH + 1);\r
573\r
574 BmEliminateExtraSpaces (Description);\r
575 }\r
576 }\r
577\r
578 return Description;\r
579}\r
580\r
581/**\r
582 Try to get the controller's USB description.\r
583\r
584 @param Handle Controller handle.\r
585\r
586 @return The description string.\r
587**/\r
588CHAR16 *\r
589BmGetUsbDescription (\r
590 IN EFI_HANDLE Handle\r
591 )\r
592{\r
593 EFI_STATUS Status;\r
594 EFI_USB_IO_PROTOCOL *UsbIo;\r
595 CHAR16 NullChar;\r
596 CHAR16 *Manufacturer;\r
597 CHAR16 *Product;\r
598 CHAR16 *SerialNumber;\r
599 CHAR16 *Description;\r
600 EFI_USB_DEVICE_DESCRIPTOR DevDesc;\r
b6344b37 601 UINTN DescMaxSize;\r
067ed98a
RN
602\r
603 Status = gBS->HandleProtocol (\r
604 Handle,\r
605 &gEfiUsbIoProtocolGuid,\r
606 (VOID **) &UsbIo\r
607 );\r
608 if (EFI_ERROR (Status)) {\r
609 return NULL;\r
610 }\r
611\r
612 NullChar = L'\0';\r
613\r
614 Status = UsbIo->UsbGetDeviceDescriptor (UsbIo, &DevDesc);\r
615 if (EFI_ERROR (Status)) {\r
616 return NULL;\r
617 }\r
618\r
619 Status = UsbIo->UsbGetStringDescriptor (\r
620 UsbIo,\r
621 mBmUsbLangId,\r
622 DevDesc.StrManufacturer,\r
623 &Manufacturer\r
624 );\r
625 if (EFI_ERROR (Status)) {\r
626 Manufacturer = &NullChar;\r
627 }\r
628 \r
629 Status = UsbIo->UsbGetStringDescriptor (\r
630 UsbIo,\r
631 mBmUsbLangId,\r
632 DevDesc.StrProduct,\r
633 &Product\r
634 );\r
635 if (EFI_ERROR (Status)) {\r
636 Product = &NullChar;\r
637 }\r
638 \r
639 Status = UsbIo->UsbGetStringDescriptor (\r
640 UsbIo,\r
641 mBmUsbLangId,\r
642 DevDesc.StrSerialNumber,\r
643 &SerialNumber\r
644 );\r
645 if (EFI_ERROR (Status)) {\r
646 SerialNumber = &NullChar;\r
647 }\r
648\r
649 if ((Manufacturer == &NullChar) &&\r
650 (Product == &NullChar) &&\r
651 (SerialNumber == &NullChar)\r
652 ) {\r
653 return NULL;\r
654 }\r
655\r
b6344b37
QS
656 DescMaxSize = StrSize (Manufacturer) + StrSize (Product) + StrSize (SerialNumber);\r
657 Description = AllocateZeroPool (DescMaxSize);\r
067ed98a 658 ASSERT (Description != NULL);\r
b6344b37
QS
659 StrCatS (Description, DescMaxSize/sizeof(CHAR16), Manufacturer);\r
660 StrCatS (Description, DescMaxSize/sizeof(CHAR16), L" ");\r
067ed98a 661\r
b6344b37
QS
662 StrCatS (Description, DescMaxSize/sizeof(CHAR16), Product); \r
663 StrCatS (Description, DescMaxSize/sizeof(CHAR16), L" ");\r
067ed98a 664\r
b6344b37 665 StrCatS (Description, DescMaxSize/sizeof(CHAR16), SerialNumber);\r
067ed98a
RN
666\r
667 if (Manufacturer != &NullChar) {\r
668 FreePool (Manufacturer);\r
669 }\r
670 if (Product != &NullChar) {\r
671 FreePool (Product);\r
672 }\r
673 if (SerialNumber != &NullChar) {\r
674 FreePool (SerialNumber);\r
675 }\r
676\r
677 BmEliminateExtraSpaces (Description);\r
678\r
679 return Description;\r
680}\r
681\r
682/**\r
683 Return the boot description for the controller based on the type.\r
684\r
685 @param Handle Controller handle.\r
686\r
687 @return The description string.\r
688**/\r
689CHAR16 *\r
690BmGetMiscDescription (\r
691 IN EFI_HANDLE Handle\r
692 )\r
693{\r
f41c71d2
RN
694 EFI_STATUS Status;\r
695 CHAR16 *Description;\r
696 EFI_BLOCK_IO_PROTOCOL *BlockIo;\r
697 EFI_SIMPLE_FILE_SYSTEM_PROTOCOL *Fs;\r
067ed98a
RN
698\r
699 switch (BmDevicePathType (DevicePathFromHandle (Handle))) {\r
700 case BmAcpiFloppyBoot:\r
701 Description = L"Floppy";\r
702 break;\r
703\r
704 case BmMessageAtapiBoot:\r
705 case BmMessageSataBoot:\r
706 Status = gBS->HandleProtocol (Handle, &gEfiBlockIoProtocolGuid, (VOID **) &BlockIo);\r
707 ASSERT_EFI_ERROR (Status);\r
708 //\r
709 // Assume a removable SATA device should be the DVD/CD device\r
710 //\r
711 Description = BlockIo->Media->RemovableMedia ? L"DVD/CDROM" : L"Hard Drive";\r
712 break;\r
713\r
714 case BmMessageUsbBoot:\r
715 Description = L"USB Device";\r
716 break;\r
717\r
718 case BmMessageScsiBoot:\r
719 Description = L"SCSI Device";\r
720 break;\r
721\r
722 case BmHardwareDeviceBoot:\r
723 Status = gBS->HandleProtocol (Handle, &gEfiBlockIoProtocolGuid, (VOID **) &BlockIo);\r
724 if (!EFI_ERROR (Status)) {\r
725 Description = BlockIo->Media->RemovableMedia ? L"Removable Disk" : L"Hard Drive";\r
726 } else {\r
727 Description = L"Misc Device";\r
728 }\r
729 break;\r
730\r
f41c71d2
RN
731 case BmMessageNetworkBoot:\r
732 Description = L"Network";\r
733 break;\r
734\r
ebf735f1
RN
735 case BmMessageHttpBoot:\r
736 Description = L"Http";\r
737 break;\r
738\r
067ed98a 739 default:\r
f41c71d2
RN
740 Status = gBS->HandleProtocol (Handle, &gEfiSimpleFileSystemProtocolGuid, (VOID **) &Fs);\r
741 if (!EFI_ERROR (Status)) {\r
742 Description = L"Non-Block Boot Device";\r
743 } else {\r
744 Description = L"Misc Device";\r
745 }\r
067ed98a
RN
746 break;\r
747 }\r
748\r
749 return AllocateCopyPool (StrSize (Description), Description);\r
750}\r
751\r
f41c71d2
RN
752/**\r
753 Register the platform provided boot description handler.\r
754\r
755 @param Handler The platform provided boot description handler\r
756\r
757 @retval EFI_SUCCESS The handler was registered successfully.\r
758 @retval EFI_ALREADY_STARTED The handler was already registered.\r
759 @retval EFI_OUT_OF_RESOURCES There is not enough resource to perform the registration.\r
760**/\r
761EFI_STATUS\r
762EFIAPI\r
763EfiBootManagerRegisterBootDescriptionHandler (\r
764 IN EFI_BOOT_MANAGER_BOOT_DESCRIPTION_HANDLER Handler\r
765 )\r
766{\r
767 LIST_ENTRY *Link;\r
768 BM_BOOT_DESCRIPTION_ENTRY *Entry;\r
769\r
770 for ( Link = GetFirstNode (&mPlatformBootDescriptionHandlers)\r
771 ; !IsNull (&mPlatformBootDescriptionHandlers, Link)\r
772 ; Link = GetNextNode (&mPlatformBootDescriptionHandlers, Link)\r
773 ) {\r
774 Entry = CR (Link, BM_BOOT_DESCRIPTION_ENTRY, Link, BM_BOOT_DESCRIPTION_ENTRY_SIGNATURE);\r
775 if (Entry->Handler == Handler) {\r
776 return EFI_ALREADY_STARTED;\r
777 }\r
778 }\r
779\r
780 Entry = AllocatePool (sizeof (BM_BOOT_DESCRIPTION_ENTRY));\r
781 if (Entry == NULL) {\r
782 return EFI_OUT_OF_RESOURCES;\r
783 }\r
784\r
785 Entry->Signature = BM_BOOT_DESCRIPTION_ENTRY_SIGNATURE;\r
786 Entry->Handler = Handler;\r
787 InsertTailList (&mPlatformBootDescriptionHandlers, &Entry->Link);\r
788 return EFI_SUCCESS;\r
789}\r
790\r
791BM_GET_BOOT_DESCRIPTION mBmBootDescriptionHandlers[] = {\r
067ed98a
RN
792 BmGetUsbDescription,\r
793 BmGetDescriptionFromDiskInfo,\r
794 BmGetMiscDescription\r
795};\r
796\r
f41c71d2
RN
797/**\r
798 Return the boot description for the controller.\r
799\r
800 @param Handle Controller handle.\r
801\r
802 @return The description string.\r
803**/\r
804CHAR16 *\r
805BmGetBootDescription (\r
806 IN EFI_HANDLE Handle\r
807 )\r
808{\r
809 LIST_ENTRY *Link;\r
810 BM_BOOT_DESCRIPTION_ENTRY *Entry;\r
811 CHAR16 *Description;\r
812 CHAR16 *DefaultDescription;\r
813 CHAR16 *Temp;\r
814 UINTN Index;\r
815\r
816 //\r
817 // Firstly get the default boot description\r
818 //\r
819 DefaultDescription = NULL;\r
820 for (Index = 0; Index < sizeof (mBmBootDescriptionHandlers) / sizeof (mBmBootDescriptionHandlers[0]); Index++) {\r
821 DefaultDescription = mBmBootDescriptionHandlers[Index] (Handle);\r
822 if (DefaultDescription != NULL) {\r
823 //\r
824 // Avoid description confusion between UEFI & Legacy boot option by adding "UEFI " prefix\r
825 // ONLY for core provided boot description handler.\r
826 //\r
827 Temp = AllocatePool (StrSize (DefaultDescription) + sizeof (mBmUefiPrefix)); \r
828 ASSERT (Temp != NULL);\r
b6344b37
QS
829 StrCpyS ( Temp, \r
830 (StrSize (DefaultDescription) + sizeof (mBmUefiPrefix))/sizeof(CHAR16), \r
831 mBmUefiPrefix\r
832 );\r
833 StrCatS ( Temp, \r
834 (StrSize (DefaultDescription) + sizeof (mBmUefiPrefix))/sizeof(CHAR16), \r
835 DefaultDescription\r
836 );\r
f41c71d2
RN
837 FreePool (DefaultDescription);\r
838 DefaultDescription = Temp;\r
839 break;\r
840 }\r
841 }\r
842 ASSERT (DefaultDescription != NULL);\r
843\r
844 //\r
845 // Secondly query platform for the better boot description\r
846 //\r
847 for ( Link = GetFirstNode (&mPlatformBootDescriptionHandlers)\r
848 ; !IsNull (&mPlatformBootDescriptionHandlers, Link)\r
849 ; Link = GetNextNode (&mPlatformBootDescriptionHandlers, Link)\r
850 ) {\r
851 Entry = CR (Link, BM_BOOT_DESCRIPTION_ENTRY, Link, BM_BOOT_DESCRIPTION_ENTRY_SIGNATURE);\r
852 Description = Entry->Handler (Handle, DefaultDescription);\r
853 if (Description != NULL) {\r
854 FreePool (DefaultDescription);\r
855 return Description;\r
856 }\r
857 }\r
858\r
859 return DefaultDescription;\r
860}\r
861\r
067ed98a
RN
862/**\r
863 Check whether a USB device match the specified USB WWID device path. This\r
864 function follows "Load Option Processing" behavior in UEFI specification.\r
865\r
866 @param UsbIo USB I/O protocol associated with the USB device.\r
867 @param UsbWwid The USB WWID device path to match.\r
868\r
869 @retval TRUE The USB device match the USB WWID device path.\r
870 @retval FALSE The USB device does not match the USB WWID device path.\r
871\r
872**/\r
873BOOLEAN\r
874BmMatchUsbWwid (\r
875 IN EFI_USB_IO_PROTOCOL *UsbIo,\r
876 IN USB_WWID_DEVICE_PATH *UsbWwid\r
877 )\r
878{\r
879 EFI_STATUS Status;\r
880 EFI_USB_DEVICE_DESCRIPTOR DevDesc;\r
881 EFI_USB_INTERFACE_DESCRIPTOR IfDesc;\r
882 UINT16 *LangIdTable;\r
883 UINT16 TableSize;\r
884 UINT16 Index;\r
885 CHAR16 *CompareStr;\r
886 UINTN CompareLen;\r
887 CHAR16 *SerialNumberStr;\r
888 UINTN Length;\r
889\r
890 if ((DevicePathType (UsbWwid) != MESSAGING_DEVICE_PATH) ||\r
891 (DevicePathSubType (UsbWwid) != MSG_USB_WWID_DP)) {\r
892 return FALSE;\r
893 }\r
894\r
895 //\r
896 // Check Vendor Id and Product Id.\r
897 //\r
898 Status = UsbIo->UsbGetDeviceDescriptor (UsbIo, &DevDesc);\r
899 if (EFI_ERROR (Status)) {\r
900 return FALSE;\r
901 }\r
902 if ((DevDesc.IdVendor != UsbWwid->VendorId) ||\r
903 (DevDesc.IdProduct != UsbWwid->ProductId)) {\r
904 return FALSE;\r
905 }\r
906\r
907 //\r
908 // Check Interface Number.\r
909 //\r
910 Status = UsbIo->UsbGetInterfaceDescriptor (UsbIo, &IfDesc);\r
911 if (EFI_ERROR (Status)) {\r
912 return FALSE;\r
913 }\r
914 if (IfDesc.InterfaceNumber != UsbWwid->InterfaceNumber) {\r
915 return FALSE;\r
916 }\r
917\r
918 //\r
919 // Check Serial Number.\r
920 //\r
921 if (DevDesc.StrSerialNumber == 0) {\r
922 return FALSE;\r
923 }\r
924\r
925 //\r
926 // Get all supported languages.\r
927 //\r
928 TableSize = 0;\r
929 LangIdTable = NULL;\r
930 Status = UsbIo->UsbGetSupportedLanguages (UsbIo, &LangIdTable, &TableSize);\r
931 if (EFI_ERROR (Status) || (TableSize == 0) || (LangIdTable == NULL)) {\r
932 return FALSE;\r
933 }\r
934\r
935 //\r
936 // Serial number in USB WWID device path is the last 64-or-less UTF-16 characters.\r
937 //\r
938 CompareStr = (CHAR16 *) (UINTN) (UsbWwid + 1);\r
939 CompareLen = (DevicePathNodeLength (UsbWwid) - sizeof (USB_WWID_DEVICE_PATH)) / sizeof (CHAR16);\r
940 if (CompareStr[CompareLen - 1] == L'\0') {\r
941 CompareLen--;\r
942 }\r
943\r
944 //\r
945 // Compare serial number in each supported language.\r
946 //\r
947 for (Index = 0; Index < TableSize / sizeof (UINT16); Index++) {\r
948 SerialNumberStr = NULL;\r
949 Status = UsbIo->UsbGetStringDescriptor (\r
950 UsbIo,\r
951 LangIdTable[Index],\r
952 DevDesc.StrSerialNumber,\r
953 &SerialNumberStr\r
954 );\r
955 if (EFI_ERROR (Status) || (SerialNumberStr == NULL)) {\r
956 continue;\r
957 }\r
958\r
959 Length = StrLen (SerialNumberStr);\r
960 if ((Length >= CompareLen) &&\r
961 (CompareMem (SerialNumberStr + Length - CompareLen, CompareStr, CompareLen * sizeof (CHAR16)) == 0)) {\r
962 FreePool (SerialNumberStr);\r
963 return TRUE;\r
964 }\r
965\r
966 FreePool (SerialNumberStr);\r
967 }\r
968\r
969 return FALSE;\r
970}\r
971\r
972/**\r
973 Find a USB device which match the specified short-form device path start with \r
974 USB Class or USB WWID device path. If ParentDevicePath is NULL, this function\r
975 will search in all USB devices of the platform. If ParentDevicePath is not NULL,\r
976 this function will only search in its child devices.\r
977\r
978 @param DevicePath The device path that contains USB Class or USB WWID device path.\r
979 @param ParentDevicePathSize The length of the device path before the USB Class or \r
980 USB WWID device path.\r
981 @param UsbIoHandleCount A pointer to the count of the returned USB IO handles.\r
982\r
983 @retval NULL The matched USB IO handles cannot be found.\r
984 @retval other The matched USB IO handles.\r
985\r
986**/\r
987EFI_HANDLE *\r
988BmFindUsbDevice (\r
989 IN EFI_DEVICE_PATH_PROTOCOL *DevicePath,\r
990 IN UINTN ParentDevicePathSize,\r
991 OUT UINTN *UsbIoHandleCount\r
992 )\r
993{\r
994 EFI_STATUS Status;\r
995 EFI_HANDLE *UsbIoHandles;\r
996 EFI_DEVICE_PATH_PROTOCOL *UsbIoDevicePath;\r
997 EFI_USB_IO_PROTOCOL *UsbIo;\r
998 UINTN Index;\r
067ed98a
RN
999 BOOLEAN Matched;\r
1000\r
1001 ASSERT (UsbIoHandleCount != NULL); \r
1002\r
1003 //\r
1004 // Get all UsbIo Handles.\r
1005 //\r
1006 Status = gBS->LocateHandleBuffer (\r
1007 ByProtocol,\r
1008 &gEfiUsbIoProtocolGuid,\r
1009 NULL,\r
1010 UsbIoHandleCount,\r
1011 &UsbIoHandles\r
1012 );\r
1013 if (EFI_ERROR (Status)) {\r
1014 *UsbIoHandleCount = 0;\r
1015 UsbIoHandles = NULL;\r
1016 }\r
1017\r
1018 for (Index = 0; Index < *UsbIoHandleCount; ) {\r
1019 //\r
1020 // Get the Usb IO interface.\r
1021 //\r
1022 Status = gBS->HandleProtocol(\r
1023 UsbIoHandles[Index],\r
1024 &gEfiUsbIoProtocolGuid,\r
1025 (VOID **) &UsbIo\r
1026 );\r
1027 UsbIoDevicePath = DevicePathFromHandle (UsbIoHandles[Index]);\r
1028 Matched = FALSE;\r
1029 if (!EFI_ERROR (Status) && (UsbIoDevicePath != NULL)) {\r
067ed98a
RN
1030\r
1031 //\r
1032 // Compare starting part of UsbIoHandle's device path with ParentDevicePath.\r
1033 //\r
1034 if (CompareMem (UsbIoDevicePath, DevicePath, ParentDevicePathSize) == 0) {\r
1035 if (BmMatchUsbClass (UsbIo, (USB_CLASS_DEVICE_PATH *) ((UINTN) DevicePath + ParentDevicePathSize)) ||\r
1036 BmMatchUsbWwid (UsbIo, (USB_WWID_DEVICE_PATH *) ((UINTN) DevicePath + ParentDevicePathSize))) {\r
1037 Matched = TRUE;\r
1038 }\r
1039 }\r
1040 }\r
1041\r
1042 if (!Matched) {\r
1043 (*UsbIoHandleCount) --;\r
1044 CopyMem (&UsbIoHandles[Index], &UsbIoHandles[Index + 1], (*UsbIoHandleCount - Index) * sizeof (EFI_HANDLE));\r
1045 } else {\r
1046 Index++;\r
1047 }\r
1048 }\r
1049\r
1050 return UsbIoHandles;\r
1051}\r
1052\r
1053/**\r
1054 Expand USB Class or USB WWID device path node to be full device path of a USB\r
1055 device in platform.\r
1056\r
1057 This function support following 4 cases:\r
1058 1) Boot Option device path starts with a USB Class or USB WWID device path,\r
1059 and there is no Media FilePath device path in the end.\r
1060 In this case, it will follow Removable Media Boot Behavior.\r
1061 2) Boot Option device path starts with a USB Class or USB WWID device path,\r
1062 and ended with Media FilePath device path.\r
1063 3) Boot Option device path starts with a full device path to a USB Host Controller,\r
1064 contains a USB Class or USB WWID device path node, while not ended with Media\r
1065 FilePath device path. In this case, it will follow Removable Media Boot Behavior.\r
1066 4) Boot Option device path starts with a full device path to a USB Host Controller,\r
1067 contains a USB Class or USB WWID device path node, and ended with Media\r
1068 FilePath device path.\r
1069\r
1070 @param FilePath The device path pointing to a load option.\r
1071 It could be a short-form device path.\r
1072 @param FullPath Return the full device path of the load option after\r
1073 short-form device path expanding.\r
1074 Caller is responsible to free it.\r
1075 @param FileSize Return the load option size.\r
1076 @param ShortformNode Pointer to the USB short-form device path node in the FilePath buffer.\r
1077\r
1078 @return The load option buffer. Caller is responsible to free the memory.\r
1079**/\r
1080VOID *\r
1081BmExpandUsbDevicePath (\r
1082 IN EFI_DEVICE_PATH_PROTOCOL *FilePath,\r
1083 OUT EFI_DEVICE_PATH_PROTOCOL **FullPath,\r
1084 OUT UINTN *FileSize,\r
1085 IN EFI_DEVICE_PATH_PROTOCOL *ShortformNode\r
1086 )\r
1087{\r
1088 UINTN ParentDevicePathSize;\r
1089 EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath;\r
1090 EFI_DEVICE_PATH_PROTOCOL *FullDevicePath;\r
1091 EFI_HANDLE *Handles;\r
1092 UINTN HandleCount;\r
1093 UINTN Index;\r
1094 VOID *FileBuffer;\r
1095\r
1096 ParentDevicePathSize = (UINTN) ShortformNode - (UINTN) FilePath;\r
1097 RemainingDevicePath = NextDevicePathNode (ShortformNode);\r
1098 FileBuffer = NULL;\r
1099 Handles = BmFindUsbDevice (FilePath, ParentDevicePathSize, &HandleCount);\r
1100\r
1101 for (Index = 0; (Index < HandleCount) && (FileBuffer == NULL); Index++) {\r
1102 FullDevicePath = AppendDevicePath (DevicePathFromHandle (Handles[Index]), RemainingDevicePath);\r
1103 FileBuffer = BmGetLoadOptionBuffer (FullDevicePath, FullPath, FileSize);\r
1104 FreePool (FullDevicePath);\r
1105 }\r
1106\r
1107 if (Handles != NULL) {\r
1108 FreePool (Handles);\r
1109 }\r
1110\r
1111 return FileBuffer;\r
1112}\r
1113\r
ccb66799
RN
1114/**\r
1115 Expand File-path device path node to be full device path in platform.\r
1116\r
1117 @param FilePath The device path pointing to a load option.\r
1118 It could be a short-form device path.\r
1119 @param FullPath Return the full device path of the load option after\r
1120 short-form device path expanding.\r
1121 Caller is responsible to free it.\r
1122 @param FileSize Return the load option size.\r
1123\r
1124 @return The load option buffer. Caller is responsible to free the memory.\r
1125**/\r
1126VOID *\r
1127BmExpandFileDevicePath (\r
1128 IN EFI_DEVICE_PATH_PROTOCOL *FilePath,\r
1129 OUT EFI_DEVICE_PATH_PROTOCOL **FullPath,\r
1130 OUT UINTN *FileSize\r
1131 )\r
1132{\r
1133 EFI_STATUS Status;\r
1134 UINTN Index;\r
1135 UINTN HandleCount;\r
1136 EFI_HANDLE *Handles;\r
1137 EFI_BLOCK_IO_PROTOCOL *BlockIo;\r
1138 UINTN MediaType;\r
1139 EFI_DEVICE_PATH_PROTOCOL *FullDevicePath;\r
1140 VOID *FileBuffer;\r
1141 UINT32 AuthenticationStatus;\r
1142 \r
1143 EfiBootManagerConnectAll ();\r
1144 Status = gBS->LocateHandleBuffer (ByProtocol, &gEfiSimpleFileSystemProtocolGuid, NULL, &HandleCount, &Handles);\r
1145 if (EFI_ERROR (Status)) {\r
1146 HandleCount = 0;\r
1147 Handles = NULL;\r
1148 }\r
1149\r
1150 //\r
1151 // Enumerate all removable media devices followed by all fixed media devices,\r
1152 // followed by media devices which don't layer on block io.\r
1153 //\r
1154 for (MediaType = 0; MediaType < 3; MediaType++) {\r
1155 for (Index = 0; Index < HandleCount; Index++) {\r
1156 Status = gBS->HandleProtocol (Handles[Index], &gEfiBlockIoProtocolGuid, (VOID *) &BlockIo);\r
1157 if (EFI_ERROR (Status)) {\r
1158 BlockIo = NULL;\r
1159 }\r
1160 if ((MediaType == 0 && BlockIo != NULL && BlockIo->Media->RemovableMedia) ||\r
1161 (MediaType == 1 && BlockIo != NULL && !BlockIo->Media->RemovableMedia) ||\r
1162 (MediaType == 2 && BlockIo == NULL)\r
1163 ) {\r
1164 FullDevicePath = AppendDevicePath (DevicePathFromHandle (Handles[Index]), FilePath);\r
1165 FileBuffer = GetFileBufferByFilePath (TRUE, FullDevicePath, FileSize, &AuthenticationStatus);\r
1166 if (FileBuffer != NULL) {\r
1167 *FullPath = FullDevicePath;\r
1168 FreePool (Handles);\r
1169 return FileBuffer;\r
1170 }\r
1171 FreePool (FullDevicePath);\r
1172 }\r
1173 }\r
1174 }\r
1175\r
1176 if (Handles != NULL) {\r
1177 FreePool (Handles);\r
1178 }\r
1179\r
1180 *FullPath = NULL;\r
1181 return NULL;\r
1182}\r
1183\r
4a285ec1
RN
1184/**\r
1185 Expand URI device path node to be full device path in platform.\r
1186\r
1187 @param FilePath The device path pointing to a load option.\r
1188 It could be a short-form device path.\r
1189 @param FullPath Return the full device path of the load option after\r
1190 short-form device path expanding.\r
1191 Caller is responsible to free it.\r
1192 @param FileSize Return the load option size.\r
1193\r
1194 @return The load option buffer. Caller is responsible to free the memory.\r
1195**/\r
1196VOID *\r
1197BmExpandUriDevicePath (\r
1198 IN EFI_DEVICE_PATH_PROTOCOL *FilePath,\r
1199 OUT EFI_DEVICE_PATH_PROTOCOL **FullPath,\r
1200 OUT UINTN *FileSize\r
1201 )\r
1202{\r
1203 EFI_STATUS Status;\r
1204 UINTN Index;\r
1205 UINTN HandleCount;\r
1206 EFI_HANDLE *Handles;\r
1207 EFI_LOAD_FILE_PROTOCOL *LoadFile;\r
1208 VOID *FileBuffer;\r
1209\r
1210 EfiBootManagerConnectAll ();\r
1211 Status = gBS->LocateHandleBuffer (ByProtocol, &gEfiLoadFileProtocolGuid, NULL, &HandleCount, &Handles);\r
1212 if (EFI_ERROR (Status)) {\r
1213 HandleCount = 0;\r
1214 Handles = NULL;\r
1215 }\r
1216\r
1217 FileBuffer = NULL;\r
1218\r
1219 for (Index = 0; Index < HandleCount; Index++) {\r
1220 Status = gBS->HandleProtocol (Handles[Index], &gEfiLoadFileProtocolGuid, (VOID *) &LoadFile);\r
1221 ASSERT_EFI_ERROR (Status);\r
1222\r
1223 FileBuffer = NULL;\r
1224 Status = LoadFile->LoadFile (LoadFile, FilePath, TRUE, FileSize, FileBuffer);\r
1225 if (Status == EFI_BUFFER_TOO_SMALL) {\r
1226 FileBuffer = AllocatePool (*FileSize);\r
1227 if (FileBuffer == NULL) {\r
1228 break;\r
1229 }\r
1230 Status = LoadFile->LoadFile (LoadFile, FilePath, TRUE, FileSize, FileBuffer);\r
1231 }\r
1232\r
1233 if (!EFI_ERROR (Status)) {\r
f5c12172
RN
1234 //\r
1235 // LoadFile() returns a file buffer mapping to a file system.\r
1236 //\r
1237 if (Status == EFI_WARN_FILE_SYSTEM) {\r
1238 return BmGetFileBufferFromLoadFileFileSystem (Handles[Index], FullPath, FileSize);\r
1239 }\r
1240\r
1241 ASSERT (Status == EFI_SUCCESS);\r
4a285ec1
RN
1242 *FullPath = DuplicateDevicePath (DevicePathFromHandle (Handles[Index]));\r
1243 break;\r
1244 }\r
1245\r
1246 if (FileBuffer != NULL) {\r
1247 FreePool (FileBuffer);\r
1248 }\r
1249 }\r
1250\r
1251 if (Handles != NULL) {\r
1252 FreePool (Handles);\r
1253 }\r
1254\r
1255 return FileBuffer;\r
1256}\r
1257\r
067ed98a
RN
1258/**\r
1259 Save the partition DevicePath to the CachedDevicePath as the first instance.\r
1260\r
1261 @param CachedDevicePath The device path cache.\r
1262 @param DevicePath The partition device path to be cached.\r
1263**/\r
1264VOID\r
1265BmCachePartitionDevicePath (\r
1266 IN OUT EFI_DEVICE_PATH_PROTOCOL **CachedDevicePath,\r
1267 IN EFI_DEVICE_PATH_PROTOCOL *DevicePath\r
1268 )\r
1269{\r
1270 EFI_DEVICE_PATH_PROTOCOL *TempDevicePath;\r
1271 UINTN Count;\r
1272 \r
1273 if (BmMatchDevicePaths (*CachedDevicePath, DevicePath)) {\r
1274 TempDevicePath = *CachedDevicePath;\r
1275 *CachedDevicePath = BmDelPartMatchInstance (*CachedDevicePath, DevicePath);\r
1276 FreePool (TempDevicePath);\r
1277 }\r
1278\r
1279 if (*CachedDevicePath == NULL) {\r
1280 *CachedDevicePath = DuplicateDevicePath (DevicePath);\r
1281 return;\r
1282 }\r
1283\r
1284 TempDevicePath = *CachedDevicePath;\r
1285 *CachedDevicePath = AppendDevicePathInstance (DevicePath, *CachedDevicePath);\r
1286 if (TempDevicePath != NULL) {\r
1287 FreePool (TempDevicePath);\r
1288 }\r
1289\r
1290 //\r
1291 // Here limit the device path instance number to 12, which is max number for a system support 3 IDE controller\r
1292 // If the user try to boot many OS in different HDs or partitions, in theory, the 'HDDP' variable maybe become larger and larger.\r
1293 //\r
1294 Count = 0;\r
1295 TempDevicePath = *CachedDevicePath;\r
1296 while (!IsDevicePathEnd (TempDevicePath)) {\r
1297 TempDevicePath = NextDevicePathNode (TempDevicePath);\r
1298 //\r
1299 // Parse one instance\r
1300 //\r
1301 while (!IsDevicePathEndType (TempDevicePath)) {\r
1302 TempDevicePath = NextDevicePathNode (TempDevicePath);\r
1303 }\r
1304 Count++;\r
1305 //\r
1306 // If the CachedDevicePath variable contain too much instance, only remain 12 instances.\r
1307 //\r
1308 if (Count == 12) {\r
1309 SetDevicePathEndNode (TempDevicePath);\r
1310 break;\r
1311 }\r
1312 }\r
1313}\r
1314\r
1315/**\r
1316 Expand a device path that starts with a hard drive media device path node to be a\r
1317 full device path that includes the full hardware path to the device. We need\r
1318 to do this so it can be booted. As an optimization the front match (the part point\r
1319 to the partition node. E.g. ACPI() /PCI()/ATA()/Partition() ) is saved in a variable\r
1320 so a connect all is not required on every boot. All successful history device path\r
1321 which point to partition node (the front part) will be saved.\r
1322\r
1323 @param FilePath The device path pointing to a load option.\r
1324 It could be a short-form device path.\r
1325 @param FullPath Return the full device path of the load option after\r
1326 short-form device path expanding.\r
1327 Caller is responsible to free it.\r
1328 @param FileSize Return the load option size.\r
1329\r
1330 @return The load option buffer. Caller is responsible to free the memory.\r
1331**/\r
1332VOID *\r
1333BmExpandPartitionDevicePath (\r
1334 IN EFI_DEVICE_PATH_PROTOCOL *FilePath,\r
1335 OUT EFI_DEVICE_PATH_PROTOCOL **FullPath,\r
1336 OUT UINTN *FileSize\r
1337 )\r
1338{\r
1339 EFI_STATUS Status;\r
1340 UINTN BlockIoHandleCount;\r
1341 EFI_HANDLE *BlockIoBuffer;\r
1342 VOID *FileBuffer;\r
1343 EFI_DEVICE_PATH_PROTOCOL *BlockIoDevicePath;\r
1344 UINTN Index;\r
1345 EFI_DEVICE_PATH_PROTOCOL *CachedDevicePath;\r
1346 EFI_DEVICE_PATH_PROTOCOL *TempNewDevicePath;\r
1347 EFI_DEVICE_PATH_PROTOCOL *TempDevicePath;\r
1348 UINTN CachedDevicePathSize;\r
1349 BOOLEAN NeedAdjust;\r
1350 EFI_DEVICE_PATH_PROTOCOL *Instance;\r
1351 UINTN Size;\r
1352\r
1353 FileBuffer = NULL;\r
1354 //\r
1355 // Check if there is prestore 'HDDP' variable.\r
1356 // If exist, search the front path which point to partition node in the variable instants.\r
1357 // If fail to find or 'HDDP' not exist, reconnect all and search in all system\r
1358 //\r
1359 GetVariable2 (L"HDDP", &mBmHardDriveBootVariableGuid, (VOID **) &CachedDevicePath, &CachedDevicePathSize);\r
1360\r
1361 //\r
1362 // Delete the invalid 'HDDP' variable.\r
1363 //\r
1364 if ((CachedDevicePath != NULL) && !IsDevicePathValid (CachedDevicePath, CachedDevicePathSize)) {\r
1365 FreePool (CachedDevicePath);\r
1366 CachedDevicePath = NULL;\r
1367 Status = gRT->SetVariable (\r
1368 L"HDDP",\r
1369 &mBmHardDriveBootVariableGuid,\r
1370 0,\r
1371 0,\r
1372 NULL\r
1373 );\r
1374 ASSERT_EFI_ERROR (Status);\r
1375 }\r
1376\r
1377 if (CachedDevicePath != NULL) {\r
1378 TempNewDevicePath = CachedDevicePath;\r
1379 NeedAdjust = FALSE;\r
1380 do {\r
1381 //\r
1382 // Check every instance of the variable\r
1383 // First, check whether the instance contain the partition node, which is needed for distinguishing multi\r
1384 // partial partition boot option. Second, check whether the instance could be connected.\r
1385 //\r
1386 Instance = GetNextDevicePathInstance (&TempNewDevicePath, &Size);\r
1387 if (BmMatchPartitionDevicePathNode (Instance, (HARDDRIVE_DEVICE_PATH *) FilePath)) {\r
1388 //\r
1389 // Connect the device path instance, the device path point to hard drive media device path node\r
1390 // e.g. ACPI() /PCI()/ATA()/Partition()\r
1391 //\r
1392 Status = EfiBootManagerConnectDevicePath (Instance, NULL);\r
1393 if (!EFI_ERROR (Status)) {\r
1394 TempDevicePath = AppendDevicePath (Instance, NextDevicePathNode (FilePath));\r
1395 FileBuffer = BmGetLoadOptionBuffer (TempDevicePath, FullPath, FileSize);\r
1396 FreePool (TempDevicePath);\r
1397\r
1398 if (FileBuffer != NULL) {\r
1399 //\r
1400 // Adjust the 'HDDP' instances sequence if the matched one is not first one.\r
1401 //\r
1402 if (NeedAdjust) {\r
1403 BmCachePartitionDevicePath (&CachedDevicePath, Instance);\r
1404 //\r
1405 // Save the matching Device Path so we don't need to do a connect all next time\r
1406 // Failing to save only impacts performance next time expanding the short-form device path\r
1407 //\r
1408 Status = gRT->SetVariable (\r
1409 L"HDDP",\r
1410 &mBmHardDriveBootVariableGuid,\r
1411 EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_NON_VOLATILE,\r
1412 GetDevicePathSize (CachedDevicePath),\r
1413 CachedDevicePath\r
1414 );\r
1415 }\r
1416\r
1417 FreePool (Instance);\r
1418 FreePool (CachedDevicePath);\r
1419 return FileBuffer;\r
1420 }\r
1421 }\r
1422 }\r
1423 //\r
1424 // Come here means the first instance is not matched\r
1425 //\r
1426 NeedAdjust = TRUE;\r
1427 FreePool(Instance);\r
1428 } while (TempNewDevicePath != NULL);\r
1429 }\r
1430\r
1431 //\r
1432 // If we get here we fail to find or 'HDDP' not exist, and now we need\r
1433 // to search all devices in the system for a matched partition\r
1434 //\r
1435 EfiBootManagerConnectAll ();\r
1436 Status = gBS->LocateHandleBuffer (ByProtocol, &gEfiBlockIoProtocolGuid, NULL, &BlockIoHandleCount, &BlockIoBuffer);\r
1437 if (EFI_ERROR (Status)) {\r
1438 BlockIoHandleCount = 0;\r
1439 BlockIoBuffer = NULL;\r
1440 }\r
1441 //\r
1442 // Loop through all the device handles that support the BLOCK_IO Protocol\r
1443 //\r
1444 for (Index = 0; Index < BlockIoHandleCount; Index++) {\r
1445 BlockIoDevicePath = DevicePathFromHandle (BlockIoBuffer[Index]);\r
1446 if (BlockIoDevicePath == NULL) {\r
1447 continue;\r
1448 }\r
1449\r
1450 if (BmMatchPartitionDevicePathNode (BlockIoDevicePath, (HARDDRIVE_DEVICE_PATH *) FilePath)) {\r
1451 //\r
1452 // Find the matched partition device path\r
1453 //\r
1454 TempDevicePath = AppendDevicePath (BlockIoDevicePath, NextDevicePathNode (FilePath));\r
1455 FileBuffer = BmGetLoadOptionBuffer (TempDevicePath, FullPath, FileSize);\r
1456 FreePool (TempDevicePath);\r
1457\r
1458 if (FileBuffer != NULL) {\r
1459 BmCachePartitionDevicePath (&CachedDevicePath, BlockIoDevicePath);\r
1460\r
1461 //\r
1462 // Save the matching Device Path so we don't need to do a connect all next time\r
1463 // Failing to save only impacts performance next time expanding the short-form device path\r
1464 //\r
1465 Status = gRT->SetVariable (\r
1466 L"HDDP",\r
1467 &mBmHardDriveBootVariableGuid,\r
1468 EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_NON_VOLATILE,\r
1469 GetDevicePathSize (CachedDevicePath),\r
1470 CachedDevicePath\r
1471 );\r
1472\r
1473 break;\r
1474 }\r
1475 }\r
1476 }\r
1477\r
1478 if (CachedDevicePath != NULL) {\r
1479 FreePool (CachedDevicePath);\r
1480 }\r
1481 if (BlockIoBuffer != NULL) {\r
1482 FreePool (BlockIoBuffer);\r
1483 }\r
1484 return FileBuffer;\r
1485}\r
1486\r
1487/**\r
1488 Expand the media device path which points to a BlockIo or SimpleFileSystem instance\r
1489 by appending EFI_REMOVABLE_MEDIA_FILE_NAME.\r
1490\r
1491 @param DevicePath The media device path pointing to a BlockIo or SimpleFileSystem instance.\r
1492 @param FullPath Return the full device path pointing to the load option.\r
1493 @param FileSize Return the size of the load option.\r
1494\r
1495 @return The load option buffer.\r
1496**/\r
1497VOID *\r
1498BmExpandMediaDevicePath (\r
1499 IN EFI_DEVICE_PATH_PROTOCOL *DevicePath,\r
1500 OUT EFI_DEVICE_PATH_PROTOCOL **FullPath,\r
1501 OUT UINTN *FileSize\r
1502 )\r
1503{\r
1504 EFI_STATUS Status;\r
1505 EFI_HANDLE Handle;\r
1506 EFI_BLOCK_IO_PROTOCOL *BlockIo;\r
1507 VOID *Buffer;\r
1508 EFI_DEVICE_PATH_PROTOCOL *TempDevicePath;\r
1509 UINTN Size;\r
1510 UINTN TempSize;\r
1511 EFI_HANDLE *SimpleFileSystemHandles;\r
1512 UINTN NumberSimpleFileSystemHandles;\r
1513 UINTN Index;\r
1514 VOID *FileBuffer;\r
1515 UINT32 AuthenticationStatus;\r
1516\r
1517 //\r
1518 // Check whether the device is connected\r
1519 //\r
1520 TempDevicePath = DevicePath;\r
1521 Status = gBS->LocateDevicePath (&gEfiSimpleFileSystemProtocolGuid, &TempDevicePath, &Handle);\r
1522 if (!EFI_ERROR (Status)) {\r
1523 ASSERT (IsDevicePathEnd (TempDevicePath));\r
1524\r
1525 TempDevicePath = FileDevicePath (Handle, EFI_REMOVABLE_MEDIA_FILE_NAME);\r
1526 FileBuffer = GetFileBufferByFilePath (TRUE, TempDevicePath, FileSize, &AuthenticationStatus);\r
1527 if (FileBuffer == NULL) {\r
1528 FreePool (TempDevicePath);\r
1529 TempDevicePath = NULL;\r
1530 }\r
1531 *FullPath = TempDevicePath;\r
1532 return FileBuffer;\r
1533 }\r
1534\r
1535 //\r
1536 // For device boot option only pointing to the removable device handle, \r
1537 // should make sure all its children handles (its child partion or media handles) are created and connected. \r
1538 //\r
1539 gBS->ConnectController (Handle, NULL, NULL, TRUE);\r
1540\r
1541 //\r
1542 // Issue a dummy read to the device to check for media change.\r
1543 // When the removable media is changed, any Block IO read/write will\r
1544 // cause the BlockIo protocol be reinstalled and EFI_MEDIA_CHANGED is\r
1545 // returned. After the Block IO protocol is reinstalled, subsequent\r
1546 // Block IO read/write will success.\r
1547 //\r
1548 Status = gBS->LocateDevicePath (&gEfiBlockIoProtocolGuid, &TempDevicePath, &Handle);\r
1549 ASSERT_EFI_ERROR (Status);\r
1550 Status = gBS->HandleProtocol (Handle, &gEfiBlockIoProtocolGuid, (VOID **) &BlockIo);\r
1551 ASSERT_EFI_ERROR (Status);\r
1552 Buffer = AllocatePool (BlockIo->Media->BlockSize);\r
1553 if (Buffer != NULL) {\r
1554 BlockIo->ReadBlocks (\r
1555 BlockIo,\r
1556 BlockIo->Media->MediaId,\r
1557 0,\r
1558 BlockIo->Media->BlockSize,\r
1559 Buffer\r
1560 );\r
1561 FreePool (Buffer);\r
1562 }\r
1563\r
1564 //\r
1565 // Detect the the default boot file from removable Media\r
1566 //\r
1567 FileBuffer = NULL;\r
1568 *FullPath = NULL;\r
1569 Size = GetDevicePathSize (DevicePath) - END_DEVICE_PATH_LENGTH;\r
1570 gBS->LocateHandleBuffer (\r
1571 ByProtocol,\r
1572 &gEfiSimpleFileSystemProtocolGuid,\r
1573 NULL,\r
1574 &NumberSimpleFileSystemHandles,\r
1575 &SimpleFileSystemHandles\r
1576 );\r
1577 for (Index = 0; Index < NumberSimpleFileSystemHandles; Index++) {\r
1578 //\r
1579 // Get the device path size of SimpleFileSystem handle\r
1580 //\r
1581 TempDevicePath = DevicePathFromHandle (SimpleFileSystemHandles[Index]);\r
1582 TempSize = GetDevicePathSize (TempDevicePath) - END_DEVICE_PATH_LENGTH;\r
1583 //\r
1584 // Check whether the device path of boot option is part of the SimpleFileSystem handle's device path\r
1585 //\r
1586 if ((Size <= TempSize) && (CompareMem (TempDevicePath, DevicePath, Size) == 0)) {\r
1587 TempDevicePath = FileDevicePath (SimpleFileSystemHandles[Index], EFI_REMOVABLE_MEDIA_FILE_NAME);\r
1588 FileBuffer = GetFileBufferByFilePath (TRUE, TempDevicePath, FileSize, &AuthenticationStatus);\r
1589 if (FileBuffer != NULL) {\r
1590 *FullPath = TempDevicePath;\r
1591 break;\r
1592 }\r
1593 FreePool (TempDevicePath);\r
1594 }\r
1595 }\r
1596\r
1597 if (SimpleFileSystemHandles != NULL) {\r
1598 FreePool (SimpleFileSystemHandles);\r
1599 }\r
1600\r
1601 return FileBuffer;\r
1602}\r
1603\r
bf5328f0
RN
1604/**\r
1605 Check whether Left and Right are the same without matching the specific\r
1606 device path data in IP device path and URI device path node.\r
1607\r
1608 @retval TRUE Left and Right are the same.\r
1609 @retval FALSE Left and Right are the different.\r
1610**/\r
1611BOOLEAN\r
1612BmMatchHttpBootDevicePath (\r
1613 IN EFI_DEVICE_PATH_PROTOCOL *Left,\r
1614 IN EFI_DEVICE_PATH_PROTOCOL *Right\r
1615 )\r
1616{\r
1617 for (; !IsDevicePathEnd (Left) && !IsDevicePathEnd (Right)\r
1618 ; Left = NextDevicePathNode (Left), Right = NextDevicePathNode (Right)\r
1619 ) {\r
1620 if (CompareMem (Left, Right, DevicePathNodeLength (Left)) != 0) {\r
1621 if ((DevicePathType (Left) != MESSAGING_DEVICE_PATH) || (DevicePathType (Right) != MESSAGING_DEVICE_PATH)) {\r
1622 return FALSE;\r
1623 }\r
1624\r
1625 if (((DevicePathSubType (Left) != MSG_IPv4_DP) || (DevicePathSubType (Right) != MSG_IPv4_DP)) &&\r
1626 ((DevicePathSubType (Left) != MSG_IPv6_DP) || (DevicePathSubType (Right) != MSG_IPv6_DP)) &&\r
1627 ((DevicePathSubType (Left) != MSG_URI_DP) || (DevicePathSubType (Right) != MSG_URI_DP))\r
1628 ) {\r
1629 return FALSE;\r
1630 }\r
1631 }\r
1632 }\r
1633 return (BOOLEAN) (IsDevicePathEnd (Left) && IsDevicePathEnd (Right));\r
1634}\r
1635\r
f5c12172
RN
1636/**\r
1637 Get the file buffer from the file system produced by Load File instance.\r
1638\r
1639 @param LoadFileHandle The handle of LoadFile instance.\r
1640 @param FullPath Return the full device path pointing to the load option.\r
1641 @param FileSize Return the size of the load option.\r
1642\r
1643 @return The load option buffer.\r
1644**/\r
1645VOID *\r
1646BmGetFileBufferFromLoadFileFileSystem (\r
1647 IN EFI_HANDLE LoadFileHandle,\r
1648 OUT EFI_DEVICE_PATH_PROTOCOL **FullPath,\r
1649 OUT UINTN *FileSize\r
1650 )\r
1651{\r
1652 EFI_STATUS Status;\r
1653 EFI_HANDLE Handle;\r
1654 EFI_HANDLE *Handles;\r
1655 UINTN HandleCount;\r
1656 UINTN Index;\r
1657 EFI_DEVICE_PATH_PROTOCOL *Node;\r
1658\r
1659 Status = gBS->LocateHandleBuffer (\r
1660 ByProtocol,\r
1661 &gEfiBlockIoProtocolGuid,\r
1662 NULL,\r
1663 &HandleCount,\r
1664 &Handles\r
1665 );\r
1666 if (EFI_ERROR (Status)) {\r
1667 Handles = NULL;\r
1668 HandleCount = 0;\r
1669 }\r
eeab16c8
RN
1670\r
1671 Handle = NULL;\r
f5c12172
RN
1672 for (Index = 0; Index < HandleCount; Index++) {\r
1673 Node = DevicePathFromHandle (Handles[Index]);\r
1674 Status = gBS->LocateDevicePath (&gEfiLoadFileProtocolGuid, &Node, &Handle);\r
1675 if (!EFI_ERROR (Status) &&\r
1676 (Handle == LoadFileHandle) &&\r
1677 (DevicePathType (Node) == MEDIA_DEVICE_PATH) && (DevicePathSubType (Node) == MEDIA_RAM_DISK_DP)) {\r
1678 Handle = Handles[Index];\r
1679 break;\r
1680 }\r
1681 }\r
1682\r
1683 if (Handles != NULL) {\r
1684 FreePool (Handles);\r
1685 }\r
1686\r
1687 if (Index != HandleCount) {\r
1688 return BmExpandMediaDevicePath (DevicePathFromHandle (Handle), FullPath, FileSize);\r
1689 } else {\r
1690 return NULL;\r
1691 }\r
1692}\r
1693\r
bf5328f0
RN
1694/**\r
1695 Get the file buffer from Load File instance.\r
1696\r
1697 @param FilePath The media device path pointing to a LoadFile instance.\r
1698 @param FullPath Return the full device path pointing to the load option.\r
1699 @param FileSize Return the size of the load option.\r
1700\r
1701 @return The load option buffer.\r
1702**/\r
1703VOID *\r
1704BmGetFileBufferFromLoadFile (\r
1705 IN EFI_DEVICE_PATH_PROTOCOL *FilePath,\r
1706 OUT EFI_DEVICE_PATH_PROTOCOL **FullPath,\r
1707 OUT UINTN *FileSize\r
1708 )\r
1709{\r
1710 EFI_STATUS Status;\r
1711 EFI_HANDLE Handle;\r
1712 VOID *FileBuffer;\r
1713 EFI_HANDLE *Handles;\r
1714 UINTN HandleCount;\r
1715 UINTN Index;\r
1716 EFI_DEVICE_PATH_PROTOCOL *Node;\r
1717 EFI_LOAD_FILE_PROTOCOL *LoadFile;\r
1718 UINTN BufferSize;\r
1719\r
1720 //\r
1721 // Get file buffer from load file instance.\r
1722 //\r
1723 Node = FilePath;\r
1724 Status = gBS->LocateDevicePath (&gEfiLoadFileProtocolGuid, &Node, &Handle);\r
1725 if (!EFI_ERROR (Status) && IsDevicePathEnd (Node)) {\r
1726 //\r
1727 // When wide match happens, pass full device path to LoadFile (),\r
1728 // otherwise, pass remaining device path to LoadFile ().\r
1729 //\r
1730 FilePath = Node;\r
1731 } else {\r
1732 Handle = NULL;\r
1733 //\r
1734 // Use wide match algorithm to find one when\r
1735 // cannot find a LoadFile instance to exactly match the FilePath\r
1736 //\r
1737 Status = gBS->LocateHandleBuffer (\r
1738 ByProtocol,\r
1739 &gEfiLoadFileProtocolGuid,\r
1740 NULL,\r
1741 &HandleCount,\r
1742 &Handles\r
1743 );\r
1744 if (EFI_ERROR (Status)) {\r
1745 Handles = NULL;\r
1746 HandleCount = 0;\r
1747 }\r
1748 for (Index = 0; Index < HandleCount; Index++) {\r
1749 if (BmMatchHttpBootDevicePath (DevicePathFromHandle (Handles[Index]), FilePath)) {\r
1750 Handle = Handles[Index];\r
1751 break;\r
1752 }\r
1753 }\r
1754 if (Handles != NULL) {\r
1755 FreePool (Handles);\r
1756 }\r
1757 }\r
1758\r
1759 if (Handle == NULL) {\r
1760 return NULL;\r
1761 }\r
1762\r
1763 Status = gBS->HandleProtocol (Handle, &gEfiLoadFileProtocolGuid, (VOID **) &LoadFile);\r
1764 ASSERT_EFI_ERROR (Status);\r
1765\r
1766 BufferSize = 0;\r
1767 FileBuffer = NULL;\r
1768 Status = LoadFile->LoadFile (LoadFile, FilePath, TRUE, &BufferSize, FileBuffer);\r
1769 if (Status == EFI_BUFFER_TOO_SMALL) {\r
1770 FileBuffer = AllocatePool (BufferSize);\r
1771 if (FileBuffer != NULL) {\r
1772 Status = EFI_SUCCESS;\r
1773 }\r
1774 }\r
1775\r
1776 if (!EFI_ERROR (Status)) {\r
1777 Status = LoadFile->LoadFile (LoadFile, FilePath, TRUE, &BufferSize, FileBuffer);\r
1778 }\r
1779\r
1780 if (!EFI_ERROR (Status)) {\r
f5c12172
RN
1781 //\r
1782 // LoadFile() returns a file buffer mapping to a file system.\r
1783 //\r
1784 if (Status == EFI_WARN_FILE_SYSTEM) {\r
1785 return BmGetFileBufferFromLoadFileFileSystem (Handle, FullPath, FileSize);\r
1786 }\r
1787\r
1788 ASSERT (Status == EFI_SUCCESS);\r
bf5328f0
RN
1789 //\r
1790 // LoadFile () may cause the device path of the Handle be updated.\r
1791 //\r
1792 *FullPath = DuplicateDevicePath (DevicePathFromHandle (Handle));\r
1793 *FileSize = BufferSize;\r
1794 return FileBuffer;\r
1795 } else {\r
1796 return NULL;\r
1797 }\r
1798}\r
1799\r
067ed98a
RN
1800/**\r
1801 Get the load option by its device path.\r
1802\r
1803 @param FilePath The device path pointing to a load option.\r
1804 It could be a short-form device path.\r
1805 @param FullPath Return the full device path of the load option after\r
1806 short-form device path expanding.\r
1807 Caller is responsible to free it.\r
1808 @param FileSize Return the load option size.\r
1809\r
1810 @return The load option buffer. Caller is responsible to free the memory.\r
1811**/\r
1812VOID *\r
1813BmGetLoadOptionBuffer (\r
1814 IN EFI_DEVICE_PATH_PROTOCOL *FilePath,\r
1815 OUT EFI_DEVICE_PATH_PROTOCOL **FullPath,\r
1816 OUT UINTN *FileSize\r
1817 )\r
1818{\r
1819 EFI_HANDLE Handle;\r
1820 VOID *FileBuffer;\r
1821 UINT32 AuthenticationStatus;\r
1822 EFI_DEVICE_PATH_PROTOCOL *Node;\r
1823 EFI_STATUS Status;\r
1824\r
1825 ASSERT ((FilePath != NULL) && (FullPath != NULL) && (FileSize != NULL));\r
1826\r
1827 EfiBootManagerConnectDevicePath (FilePath, NULL);\r
1828\r
1829 *FullPath = NULL;\r
1830 *FileSize = 0;\r
1831 FileBuffer = NULL;\r
1832\r
1833 //\r
1834 // Boot from media device by adding a default file name \EFI\BOOT\BOOT{machine type short-name}.EFI\r
1835 //\r
1836 Node = FilePath;\r
1837 Status = gBS->LocateDevicePath (&gEfiSimpleFileSystemProtocolGuid, &Node, &Handle);\r
1838 if (EFI_ERROR (Status)) {\r
1839 Status = gBS->LocateDevicePath (&gEfiBlockIoProtocolGuid, &Node, &Handle);\r
1840 }\r
1841\r
1842 if (!EFI_ERROR (Status) && IsDevicePathEnd (Node)) {\r
1843 return BmExpandMediaDevicePath (FilePath, FullPath, FileSize);\r
1844 }\r
1845\r
1846 //\r
1847 // Expand the short-form device path to full device path\r
1848 //\r
1849 if ((DevicePathType (FilePath) == MEDIA_DEVICE_PATH) &&\r
1850 (DevicePathSubType (FilePath) == MEDIA_HARDDRIVE_DP)) {\r
1851 //\r
1852 // Expand the Harddrive device path\r
1853 //\r
1854 return BmExpandPartitionDevicePath (FilePath, FullPath, FileSize);\r
ccb66799
RN
1855 } else if ((DevicePathType (FilePath) == MEDIA_DEVICE_PATH) &&\r
1856 (DevicePathSubType (FilePath) == MEDIA_FILEPATH_DP)) {\r
1857 //\r
1858 // Expand the File-path device path\r
1859 //\r
1860 return BmExpandFileDevicePath (FilePath, FullPath, FileSize);\r
4a285ec1
RN
1861 } else if ((DevicePathType (FilePath) == MESSAGING_DEVICE_PATH) &&\r
1862 (DevicePathSubType (FilePath) == MSG_URI_DP)) {\r
1863 //\r
1864 // Expand the URI device path\r
1865 //\r
1866 return BmExpandUriDevicePath (FilePath, FullPath, FileSize);\r
067ed98a
RN
1867 } else {\r
1868 for (Node = FilePath; !IsDevicePathEnd (Node); Node = NextDevicePathNode (Node)) {\r
1869 if ((DevicePathType (Node) == MESSAGING_DEVICE_PATH) &&\r
1870 ((DevicePathSubType (Node) == MSG_USB_CLASS_DP) || (DevicePathSubType (Node) == MSG_USB_WWID_DP))) {\r
1871 break;\r
1872 }\r
1873 }\r
1874\r
1875 if (!IsDevicePathEnd (Node)) {\r
1876 //\r
1877 // Expand the USB WWID/Class device path\r
1878 //\r
1879 FileBuffer = BmExpandUsbDevicePath (FilePath, FullPath, FileSize, Node);\r
1880 if ((FileBuffer == NULL) && (FilePath == Node)) {\r
1881 //\r
1882 // Boot Option device path starts with USB Class or USB WWID device path.\r
1883 // For Boot Option device path which doesn't begin with the USB Class or\r
1884 // USB WWID device path, it's not needed to connect again here.\r
1885 //\r
1886 BmConnectUsbShortFormDevicePath (FilePath);\r
1887 FileBuffer = BmExpandUsbDevicePath (FilePath, FullPath, FileSize, Node);\r
1888 }\r
1889 return FileBuffer;\r
1890 }\r
1891 }\r
1892\r
1893 //\r
525839ed 1894 // Get file buffer from FV file path.\r
067ed98a 1895 //\r
525839ed
RN
1896 if (BmIsFvFilePath (FilePath)) {\r
1897 return BmGetFileBufferByFvFilePath (FilePath, FullPath, FileSize);\r
067ed98a
RN
1898 }\r
1899\r
1900 //\r
bf5328f0 1901 // Get file buffer from simple file system.\r
067ed98a 1902 //\r
de6c0eff 1903 Node = FilePath;\r
bf5328f0
RN
1904 Status = gBS->LocateDevicePath (&gEfiSimpleFileSystemProtocolGuid, &Node, &Handle);\r
1905 if (!EFI_ERROR (Status)) {\r
1906 FileBuffer = GetFileBufferByFilePath (TRUE, FilePath, FileSize, &AuthenticationStatus);\r
1907 if (FileBuffer != NULL) {\r
de6c0eff 1908 *FullPath = DuplicateDevicePath (FilePath);\r
de6c0eff 1909 }\r
bf5328f0 1910 return FileBuffer;\r
067ed98a
RN
1911 }\r
1912\r
bf5328f0 1913 return BmGetFileBufferFromLoadFile (FilePath, FullPath, FileSize);\r
067ed98a
RN
1914}\r
1915\r
1916/**\r
1917 Attempt to boot the EFI boot option. This routine sets L"BootCurent" and\r
1918 also signals the EFI ready to boot event. If the device path for the option\r
1919 starts with a BBS device path a legacy boot is attempted via the registered \r
1920 gLegacyBoot function. Short form device paths are also supported via this \r
1921 rountine. A device path starting with MEDIA_HARDDRIVE_DP, MSG_USB_WWID_DP,\r
1922 MSG_USB_CLASS_DP gets expaned out to find the first device that matches.\r
1923 If the BootOption Device Path fails the removable media boot algorithm \r
1924 is attempted (\EFI\BOOTIA32.EFI, \EFI\BOOTX64.EFI,... only one file type \r
1925 is tried per processor type)\r
1926\r
1927 @param BootOption Boot Option to try and boot.\r
1928 On return, BootOption->Status contains the boot status.\r
1929 EFI_SUCCESS BootOption was booted\r
1930 EFI_UNSUPPORTED A BBS device path was found with no valid callback\r
1931 registered via EfiBootManagerInitialize().\r
1932 EFI_NOT_FOUND The BootOption was not found on the system\r
1933 !EFI_SUCCESS BootOption failed with this error status\r
1934\r
1935**/\r
1936VOID\r
1937EFIAPI\r
1938EfiBootManagerBoot (\r
1939 IN EFI_BOOT_MANAGER_LOAD_OPTION *BootOption\r
1940 )\r
1941{\r
1942 EFI_STATUS Status;\r
1943 EFI_HANDLE ImageHandle;\r
1944 EFI_LOADED_IMAGE_PROTOCOL *ImageInfo;\r
1945 UINT16 Uint16;\r
1946 UINTN OptionNumber;\r
1947 UINTN OriginalOptionNumber;\r
1948 EFI_DEVICE_PATH_PROTOCOL *FilePath;\r
1949 EFI_DEVICE_PATH_PROTOCOL *Node;\r
1950 EFI_HANDLE FvHandle;\r
1951 VOID *FileBuffer;\r
1952 UINTN FileSize;\r
1953 EFI_BOOT_LOGO_PROTOCOL *BootLogo;\r
1954 EFI_EVENT LegacyBootEvent;\r
1955\r
1956 if (BootOption == NULL) {\r
1957 return;\r
1958 }\r
1959\r
1960 if (BootOption->FilePath == NULL || BootOption->OptionType != LoadOptionTypeBoot) {\r
1961 BootOption->Status = EFI_INVALID_PARAMETER;\r
1962 return;\r
1963 }\r
1964\r
1965 //\r
1966 // 1. Create Boot#### for a temporary boot if there is no match Boot#### (i.e. a boot by selected a EFI Shell using "Boot From File")\r
1967 //\r
1968 OptionNumber = BmFindBootOptionInVariable (BootOption);\r
1969 if (OptionNumber == LoadOptionNumberUnassigned) {\r
1970 Status = BmGetFreeOptionNumber (LoadOptionTypeBoot, &Uint16);\r
1971 if (!EFI_ERROR (Status)) {\r
1972 //\r
1973 // Save the BootOption->OptionNumber to restore later\r
1974 //\r
1975 OptionNumber = Uint16;\r
1976 OriginalOptionNumber = BootOption->OptionNumber;\r
1977 BootOption->OptionNumber = OptionNumber;\r
1978 Status = EfiBootManagerLoadOptionToVariable (BootOption);\r
1979 BootOption->OptionNumber = OriginalOptionNumber;\r
1980 }\r
1981\r
1982 if (EFI_ERROR (Status)) {\r
1983 DEBUG ((EFI_D_ERROR, "[Bds] Failed to create Boot#### for a temporary boot - %r!\n", Status));\r
1984 BootOption->Status = Status;\r
1985 return ;\r
1986 }\r
1987 }\r
1988\r
1989 //\r
1990 // 2. Set BootCurrent\r
1991 //\r
1992 Uint16 = (UINT16) OptionNumber;\r
1993 BmSetVariableAndReportStatusCodeOnError (\r
1994 L"BootCurrent",\r
1995 &gEfiGlobalVariableGuid,\r
1996 EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS,\r
1997 sizeof (UINT16),\r
1998 &Uint16\r
1999 );\r
2000\r
2001 //\r
2002 // 3. Signal the EVT_SIGNAL_READY_TO_BOOT event when we are about to load and execute\r
2003 // the boot option.\r
2004 //\r
2005 Node = BootOption->FilePath;\r
2006 Status = gBS->LocateDevicePath (&gEfiFirmwareVolume2ProtocolGuid, &Node, &FvHandle);\r
2007 if (!EFI_ERROR (Status) && CompareGuid (\r
2008 EfiGetNameGuidFromFwVolDevicePathNode ((CONST MEDIA_FW_VOL_FILEPATH_DEVICE_PATH *) Node),\r
2009 PcdGetPtr (PcdBootManagerMenuFile)\r
2010 )) {\r
2011 DEBUG ((EFI_D_INFO, "[Bds] Booting Boot Manager Menu.\n"));\r
2012 BmStopHotkeyService (NULL, NULL);\r
2013 } else {\r
2014 EfiSignalEventReadyToBoot();\r
2015 //\r
2016 // Report Status Code to indicate ReadyToBoot was signalled\r
2017 //\r
2018 REPORT_STATUS_CODE (EFI_PROGRESS_CODE, (EFI_SOFTWARE_DXE_BS_DRIVER | EFI_SW_DXE_BS_PC_READY_TO_BOOT_EVENT));\r
2019 //\r
2020 // 4. Repair system through DriverHealth protocol\r
2021 //\r
2022 BmRepairAllControllers ();\r
2023 }\r
2024\r
2025 PERF_START_EX (gImageHandle, "BdsAttempt", NULL, 0, (UINT32) OptionNumber);\r
2026\r
2027 //\r
2028 // 5. Load EFI boot option to ImageHandle\r
2029 //\r
2030 ImageHandle = NULL;\r
2031 if (DevicePathType (BootOption->FilePath) != BBS_DEVICE_PATH) {\r
2032 Status = EFI_NOT_FOUND;\r
2033 FileBuffer = BmGetLoadOptionBuffer (BootOption->FilePath, &FilePath, &FileSize);\r
2034 DEBUG_CODE (\r
2035 if (FileBuffer != NULL && CompareMem (BootOption->FilePath, FilePath, GetDevicePathSize (FilePath)) != 0) {\r
2036 DEBUG ((EFI_D_INFO, "[Bds] DevicePath expand: "));\r
2037 BmPrintDp (BootOption->FilePath);\r
2038 DEBUG ((EFI_D_INFO, " -> "));\r
2039 BmPrintDp (FilePath);\r
2040 DEBUG ((EFI_D_INFO, "\n"));\r
2041 }\r
2042 );\r
2043 if (BmIsLoadOptionPeHeaderValid (BootOption->OptionType, FileBuffer, FileSize)) {\r
2044 REPORT_STATUS_CODE (EFI_PROGRESS_CODE, PcdGet32 (PcdProgressCodeOsLoaderLoad));\r
2045 Status = gBS->LoadImage (\r
2046 TRUE,\r
2047 gImageHandle,\r
2048 FilePath,\r
2049 FileBuffer,\r
2050 FileSize,\r
2051 &ImageHandle\r
2052 );\r
2053 }\r
2054 if (FileBuffer != NULL) {\r
2055 FreePool (FileBuffer);\r
2056 }\r
2057 if (FilePath != NULL) {\r
2058 FreePool (FilePath);\r
2059 }\r
2060\r
2061 if (EFI_ERROR (Status)) {\r
2062 //\r
2063 // Report Status Code to indicate that the failure to load boot option\r
2064 //\r
2065 REPORT_STATUS_CODE (\r
2066 EFI_ERROR_CODE | EFI_ERROR_MINOR,\r
2067 (EFI_SOFTWARE_DXE_BS_DRIVER | EFI_SW_DXE_BS_EC_BOOT_OPTION_LOAD_ERROR)\r
2068 );\r
2069 BootOption->Status = Status;\r
2070 return;\r
2071 }\r
2072 }\r
2073\r
2074 //\r
2075 // 6. Adjust the different type memory page number just before booting\r
2076 // and save the updated info into the variable for next boot to use\r
2077 //\r
665b26ba
RN
2078 BmSetMemoryTypeInformationVariable (\r
2079 (BOOLEAN) ((BootOption->Attributes & LOAD_OPTION_CATEGORY) == LOAD_OPTION_CATEGORY_BOOT)\r
2080 );\r
067ed98a
RN
2081\r
2082 DEBUG_CODE_BEGIN();\r
2083 if (BootOption->Description == NULL) {\r
2084 DEBUG ((DEBUG_INFO | DEBUG_LOAD, "[Bds]Booting from unknown device path\n"));\r
2085 } else {\r
2086 DEBUG ((DEBUG_INFO | DEBUG_LOAD, "[Bds]Booting %s\n", BootOption->Description));\r
2087 }\r
2088 DEBUG_CODE_END();\r
2089\r
2090 //\r
2091 // Check to see if we should legacy BOOT. If yes then do the legacy boot\r
2092 // Write boot to OS performance data for Legacy boot\r
2093 //\r
2094 if ((DevicePathType (BootOption->FilePath) == BBS_DEVICE_PATH) && (DevicePathSubType (BootOption->FilePath) == BBS_BBS_DP)) {\r
2095 if (mBmLegacyBoot != NULL) {\r
2096 //\r
2097 // Write boot to OS performance data for legacy boot.\r
2098 //\r
2099 PERF_CODE (\r
2100 //\r
2101 // Create an event to be signalled when Legacy Boot occurs to write performance data.\r
2102 //\r
2103 Status = EfiCreateEventLegacyBootEx(\r
2104 TPL_NOTIFY,\r
2105 BmWriteBootToOsPerformanceData,\r
2106 NULL, \r
2107 &LegacyBootEvent\r
2108 );\r
2109 ASSERT_EFI_ERROR (Status);\r
2110 );\r
2111\r
2112 mBmLegacyBoot (BootOption);\r
2113 } else {\r
2114 BootOption->Status = EFI_UNSUPPORTED;\r
2115 }\r
2116\r
2117 PERF_END_EX (gImageHandle, "BdsAttempt", NULL, 0, (UINT32) OptionNumber);\r
2118 return;\r
2119 }\r
2120 \r
2121 //\r
2122 // Provide the image with its load options\r
2123 //\r
2124 Status = gBS->HandleProtocol (ImageHandle, &gEfiLoadedImageProtocolGuid, (VOID **) &ImageInfo);\r
2125 ASSERT_EFI_ERROR (Status);\r
2126\r
404bd442
RN
2127 if (!BmIsAutoCreateBootOption (BootOption)) {\r
2128 ImageInfo->LoadOptionsSize = BootOption->OptionalDataSize;\r
2129 ImageInfo->LoadOptions = BootOption->OptionalData;\r
2130 }\r
067ed98a
RN
2131\r
2132 //\r
2133 // Clean to NULL because the image is loaded directly from the firmwares boot manager.\r
2134 //\r
2135 ImageInfo->ParentHandle = NULL;\r
2136\r
2137 //\r
2138 // Before calling the image, enable the Watchdog Timer for 5 minutes period\r
2139 //\r
2140 gBS->SetWatchdogTimer (5 * 60, 0x0000, 0x00, NULL);\r
2141\r
2142 //\r
2143 // Write boot to OS performance data for UEFI boot\r
2144 //\r
2145 PERF_CODE (\r
2146 BmWriteBootToOsPerformanceData (NULL, NULL);\r
2147 );\r
2148\r
2149 REPORT_STATUS_CODE (EFI_PROGRESS_CODE, PcdGet32 (PcdProgressCodeOsLoaderStart));\r
2150\r
2151 Status = gBS->StartImage (ImageHandle, &BootOption->ExitDataSize, &BootOption->ExitData);\r
2152 DEBUG ((DEBUG_INFO | DEBUG_LOAD, "Image Return Status = %r\n", Status));\r
2153 BootOption->Status = Status;\r
2154 if (EFI_ERROR (Status)) {\r
2155 //\r
2156 // Report Status Code to indicate that boot failure\r
2157 //\r
2158 REPORT_STATUS_CODE (\r
2159 EFI_ERROR_CODE | EFI_ERROR_MINOR,\r
2160 (EFI_SOFTWARE_DXE_BS_DRIVER | EFI_SW_DXE_BS_EC_BOOT_OPTION_FAILED)\r
2161 );\r
2162 }\r
2163 PERF_END_EX (gImageHandle, "BdsAttempt", NULL, 0, (UINT32) OptionNumber);\r
2164\r
2165 //\r
2166 // Clear the Watchdog Timer after the image returns\r
2167 //\r
2168 gBS->SetWatchdogTimer (0x0000, 0x0000, 0x0000, NULL);\r
2169\r
2170 //\r
2171 // Set Logo status invalid after trying one boot option\r
2172 //\r
2173 BootLogo = NULL;\r
2174 Status = gBS->LocateProtocol (&gEfiBootLogoProtocolGuid, NULL, (VOID **) &BootLogo);\r
2175 if (!EFI_ERROR (Status) && (BootLogo != NULL)) {\r
2176 Status = BootLogo->SetBootLogo (BootLogo, NULL, 0, 0, 0, 0);\r
2177 ASSERT_EFI_ERROR (Status);\r
2178 }\r
2179\r
2180 //\r
2181 // Clear Boot Current\r
2182 //\r
2183 Status = gRT->SetVariable (\r
2184 L"BootCurrent",\r
2185 &gEfiGlobalVariableGuid,\r
2186 0,\r
2187 0,\r
2188 NULL\r
2189 );\r
2190 //\r
2191 // Deleting variable with current variable implementation shouldn't fail.\r
2192 // When BootXXXX (e.g.: BootManagerMenu) boots BootYYYY, exiting BootYYYY causes BootCurrent deleted,\r
2193 // exiting BootXXXX causes deleting BootCurrent returns EFI_NOT_FOUND.\r
2194 //\r
2195 ASSERT (Status == EFI_SUCCESS || Status == EFI_NOT_FOUND);\r
2196}\r
2197\r
2198/**\r
2199 Check whether there is a instance in BlockIoDevicePath, which contain multi device path\r
2200 instances, has the same partition node with HardDriveDevicePath device path\r
2201\r
2202 @param BlockIoDevicePath Multi device path instances which need to check\r
2203 @param HardDriveDevicePath A device path which starts with a hard drive media\r
2204 device path.\r
2205\r
2206 @retval TRUE There is a matched device path instance.\r
2207 @retval FALSE There is no matched device path instance.\r
2208\r
2209**/\r
2210BOOLEAN\r
2211BmMatchPartitionDevicePathNode (\r
2212 IN EFI_DEVICE_PATH_PROTOCOL *BlockIoDevicePath,\r
2213 IN HARDDRIVE_DEVICE_PATH *HardDriveDevicePath\r
2214 )\r
2215{\r
2216 HARDDRIVE_DEVICE_PATH *Node;\r
2217\r
2218 if ((BlockIoDevicePath == NULL) || (HardDriveDevicePath == NULL)) {\r
2219 return FALSE;\r
2220 }\r
2221\r
2222 //\r
2223 // find the partition device path node\r
2224 //\r
2225 while (!IsDevicePathEnd (BlockIoDevicePath)) {\r
2226 if ((DevicePathType (BlockIoDevicePath) == MEDIA_DEVICE_PATH) &&\r
2227 (DevicePathSubType (BlockIoDevicePath) == MEDIA_HARDDRIVE_DP)\r
2228 ) {\r
2229 break;\r
2230 }\r
2231\r
2232 BlockIoDevicePath = NextDevicePathNode (BlockIoDevicePath);\r
2233 }\r
2234\r
2235 if (IsDevicePathEnd (BlockIoDevicePath)) {\r
2236 return FALSE;\r
2237 }\r
2238\r
2239 //\r
2240 // See if the harddrive device path in blockio matches the orig Hard Drive Node\r
2241 //\r
2242 Node = (HARDDRIVE_DEVICE_PATH *) BlockIoDevicePath;\r
2243\r
2244 //\r
2245 // Match Signature and PartitionNumber.\r
2246 // Unused bytes in Signature are initiaized with zeros.\r
2247 //\r
2248 return (BOOLEAN) (\r
2249 (Node->PartitionNumber == HardDriveDevicePath->PartitionNumber) &&\r
2250 (Node->MBRType == HardDriveDevicePath->MBRType) &&\r
2251 (Node->SignatureType == HardDriveDevicePath->SignatureType) &&\r
2252 (CompareMem (Node->Signature, HardDriveDevicePath->Signature, sizeof (Node->Signature)) == 0)\r
2253 );\r
2254}\r
2255\r
d948fe96
RN
2256/**\r
2257 Enumerate all boot option descriptions and append " 2"/" 3"/... to make\r
2258 unique description.\r
2259\r
2260 @param BootOptions Array of boot options.\r
2261 @param BootOptionCount Count of boot options.\r
2262**/\r
2263VOID\r
2264BmMakeBootOptionDescriptionUnique (\r
2265 EFI_BOOT_MANAGER_LOAD_OPTION *BootOptions,\r
2266 UINTN BootOptionCount\r
2267 )\r
2268{\r
2269 UINTN Base;\r
2270 UINTN Index;\r
2271 UINTN DescriptionSize;\r
2272 UINTN MaxSuffixSize;\r
2273 BOOLEAN *Visited;\r
2274 UINTN MatchCount;\r
2275\r
2276 if (BootOptionCount == 0) {\r
2277 return;\r
2278 }\r
2279\r
2280 //\r
2281 // Calculate the maximum buffer size for the number suffix.\r
2282 // The initial sizeof (CHAR16) is for the blank space before the number.\r
2283 //\r
2284 MaxSuffixSize = sizeof (CHAR16);\r
2285 for (Index = BootOptionCount; Index != 0; Index = Index / 10) {\r
2286 MaxSuffixSize += sizeof (CHAR16);\r
2287 }\r
2288\r
2289 Visited = AllocateZeroPool (sizeof (BOOLEAN) * BootOptionCount);\r
2290 ASSERT (Visited != NULL);\r
2291\r
2292 for (Base = 0; Base < BootOptionCount; Base++) {\r
2293 if (!Visited[Base]) {\r
2294 MatchCount = 1;\r
2295 Visited[Base] = TRUE;\r
2296 DescriptionSize = StrSize (BootOptions[Base].Description);\r
2297 for (Index = Base + 1; Index < BootOptionCount; Index++) {\r
2298 if (!Visited[Index] && StrCmp (BootOptions[Base].Description, BootOptions[Index].Description) == 0) {\r
2299 Visited[Index] = TRUE;\r
2300 MatchCount++;\r
2301 FreePool (BootOptions[Index].Description);\r
2302 BootOptions[Index].Description = AllocatePool (DescriptionSize + MaxSuffixSize);\r
2303 UnicodeSPrint (\r
2304 BootOptions[Index].Description, DescriptionSize + MaxSuffixSize,\r
2305 L"%s %d",\r
2306 BootOptions[Base].Description, MatchCount\r
2307 );\r
2308 }\r
2309 }\r
2310 }\r
2311 }\r
2312\r
2313 FreePool (Visited);\r
2314}\r
2315\r
067ed98a
RN
2316/**\r
2317 Emuerate all possible bootable medias in the following order:\r
2318 1. Removable BlockIo - The boot option only points to the removable media\r
2319 device, like USB key, DVD, Floppy etc.\r
2320 2. Fixed BlockIo - The boot option only points to a Fixed blockIo device,\r
2321 like HardDisk.\r
2322 3. Non-BlockIo SimpleFileSystem - The boot option points to a device supporting\r
2323 SimpleFileSystem Protocol, but not supporting BlockIo\r
2324 protocol.\r
2325 4. LoadFile - The boot option points to the media supporting \r
2326 LoadFile protocol.\r
2327 Reference: UEFI Spec chapter 3.3 Boot Option Variables Default Boot Behavior\r
2328\r
2329 @param BootOptionCount Return the boot option count which has been found.\r
2330\r
2331 @retval Pointer to the boot option array.\r
2332**/\r
2333EFI_BOOT_MANAGER_LOAD_OPTION *\r
2334BmEnumerateBootOptions (\r
2335 UINTN *BootOptionCount\r
2336 )\r
2337{\r
2338 EFI_STATUS Status;\r
2339 EFI_BOOT_MANAGER_LOAD_OPTION *BootOptions;\r
067ed98a
RN
2340 UINTN HandleCount;\r
2341 EFI_HANDLE *Handles;\r
2342 EFI_BLOCK_IO_PROTOCOL *BlkIo;\r
2343 UINTN Removable;\r
2344 UINTN Index;\r
f41c71d2 2345 CHAR16 *Description;\r
067ed98a
RN
2346\r
2347 ASSERT (BootOptionCount != NULL);\r
2348\r
2349 *BootOptionCount = 0;\r
2350 BootOptions = NULL;\r
2351\r
2352 //\r
2353 // Parse removable block io followed by fixed block io\r
2354 //\r
2355 gBS->LocateHandleBuffer (\r
2356 ByProtocol,\r
2357 &gEfiBlockIoProtocolGuid,\r
2358 NULL,\r
2359 &HandleCount,\r
2360 &Handles\r
2361 );\r
2362\r
2363 for (Removable = 0; Removable < 2; Removable++) {\r
2364 for (Index = 0; Index < HandleCount; Index++) {\r
2365 Status = gBS->HandleProtocol (\r
2366 Handles[Index],\r
2367 &gEfiBlockIoProtocolGuid,\r
2368 (VOID **) &BlkIo\r
2369 );\r
2370 if (EFI_ERROR (Status)) {\r
2371 continue;\r
2372 }\r
2373\r
2374 //\r
2375 // Skip the logical partitions\r
2376 //\r
2377 if (BlkIo->Media->LogicalPartition) {\r
2378 continue;\r
2379 }\r
2380\r
2381 //\r
2382 // Skip the fixed block io then the removable block io\r
2383 //\r
2384 if (BlkIo->Media->RemovableMedia == ((Removable == 0) ? FALSE : TRUE)) {\r
2385 continue;\r
2386 }\r
2387\r
f41c71d2 2388 Description = BmGetBootDescription (Handles[Index]);\r
067ed98a
RN
2389 BootOptions = ReallocatePool (\r
2390 sizeof (EFI_BOOT_MANAGER_LOAD_OPTION) * (*BootOptionCount),\r
2391 sizeof (EFI_BOOT_MANAGER_LOAD_OPTION) * (*BootOptionCount + 1),\r
2392 BootOptions\r
2393 );\r
2394 ASSERT (BootOptions != NULL);\r
2395\r
2396 Status = EfiBootManagerInitializeLoadOption (\r
2397 &BootOptions[(*BootOptionCount)++],\r
2398 LoadOptionNumberUnassigned,\r
2399 LoadOptionTypeBoot,\r
2400 LOAD_OPTION_ACTIVE,\r
f41c71d2 2401 Description,\r
067ed98a
RN
2402 DevicePathFromHandle (Handles[Index]),\r
2403 NULL,\r
2404 0\r
2405 );\r
2406 ASSERT_EFI_ERROR (Status);\r
2407\r
f41c71d2 2408 FreePool (Description);\r
067ed98a
RN
2409 }\r
2410 }\r
2411\r
2412 if (HandleCount != 0) {\r
2413 FreePool (Handles);\r
2414 }\r
2415\r
2416 //\r
2417 // Parse simple file system not based on block io\r
2418 //\r
067ed98a
RN
2419 gBS->LocateHandleBuffer (\r
2420 ByProtocol,\r
2421 &gEfiSimpleFileSystemProtocolGuid,\r
2422 NULL,\r
2423 &HandleCount,\r
2424 &Handles\r
2425 );\r
2426 for (Index = 0; Index < HandleCount; Index++) {\r
2427 Status = gBS->HandleProtocol (\r
2428 Handles[Index],\r
2429 &gEfiBlockIoProtocolGuid,\r
2430 (VOID **) &BlkIo\r
2431 );\r
2432 if (!EFI_ERROR (Status)) {\r
2433 //\r
2434 // Skip if the file system handle supports a BlkIo protocol, which we've handled in above\r
2435 //\r
2436 continue;\r
2437 }\r
f41c71d2 2438 Description = BmGetBootDescription (Handles[Index]);\r
067ed98a
RN
2439 BootOptions = ReallocatePool (\r
2440 sizeof (EFI_BOOT_MANAGER_LOAD_OPTION) * (*BootOptionCount),\r
2441 sizeof (EFI_BOOT_MANAGER_LOAD_OPTION) * (*BootOptionCount + 1),\r
2442 BootOptions\r
2443 );\r
2444 ASSERT (BootOptions != NULL);\r
2445\r
2446 Status = EfiBootManagerInitializeLoadOption (\r
2447 &BootOptions[(*BootOptionCount)++],\r
2448 LoadOptionNumberUnassigned,\r
2449 LoadOptionTypeBoot,\r
2450 LOAD_OPTION_ACTIVE,\r
2451 Description,\r
2452 DevicePathFromHandle (Handles[Index]),\r
2453 NULL,\r
2454 0\r
2455 );\r
2456 ASSERT_EFI_ERROR (Status);\r
f41c71d2 2457 FreePool (Description);\r
067ed98a
RN
2458 }\r
2459\r
2460 if (HandleCount != 0) {\r
2461 FreePool (Handles);\r
2462 }\r
2463\r
2464 //\r
2465 // Parse load file, assuming UEFI Network boot option\r
2466 //\r
2467 gBS->LocateHandleBuffer (\r
2468 ByProtocol,\r
2469 &gEfiLoadFileProtocolGuid,\r
2470 NULL,\r
2471 &HandleCount,\r
2472 &Handles\r
2473 );\r
2474 for (Index = 0; Index < HandleCount; Index++) {\r
2475\r
f41c71d2 2476 Description = BmGetBootDescription (Handles[Index]);\r
067ed98a
RN
2477 BootOptions = ReallocatePool (\r
2478 sizeof (EFI_BOOT_MANAGER_LOAD_OPTION) * (*BootOptionCount),\r
2479 sizeof (EFI_BOOT_MANAGER_LOAD_OPTION) * (*BootOptionCount + 1),\r
2480 BootOptions\r
2481 );\r
2482 ASSERT (BootOptions != NULL);\r
2483\r
2484 Status = EfiBootManagerInitializeLoadOption (\r
2485 &BootOptions[(*BootOptionCount)++],\r
2486 LoadOptionNumberUnassigned,\r
2487 LoadOptionTypeBoot,\r
2488 LOAD_OPTION_ACTIVE,\r
2489 Description,\r
2490 DevicePathFromHandle (Handles[Index]),\r
2491 NULL,\r
2492 0\r
2493 );\r
2494 ASSERT_EFI_ERROR (Status);\r
f41c71d2 2495 FreePool (Description);\r
067ed98a
RN
2496 }\r
2497\r
2498 if (HandleCount != 0) {\r
2499 FreePool (Handles);\r
2500 }\r
2501\r
d948fe96 2502 BmMakeBootOptionDescriptionUnique (BootOptions, *BootOptionCount);\r
067ed98a
RN
2503 return BootOptions;\r
2504}\r
2505\r
2506/**\r
2507 The function enumerates all boot options, creates them and registers them in the BootOrder variable.\r
2508**/\r
2509VOID\r
2510EFIAPI\r
2511EfiBootManagerRefreshAllBootOption (\r
2512 VOID\r
2513 )\r
2514{\r
2515 EFI_STATUS Status;\r
2516 EFI_BOOT_MANAGER_LOAD_OPTION *NvBootOptions;\r
2517 UINTN NvBootOptionCount;\r
2518 EFI_BOOT_MANAGER_LOAD_OPTION *BootOptions;\r
2519 UINTN BootOptionCount;\r
2520 UINTN Index;\r
2521\r
2522 //\r
2523 // Optionally refresh the legacy boot option\r
2524 //\r
2525 if (mBmRefreshLegacyBootOption != NULL) {\r
2526 mBmRefreshLegacyBootOption ();\r
2527 }\r
2528\r
2529 BootOptions = BmEnumerateBootOptions (&BootOptionCount);\r
2530 NvBootOptions = EfiBootManagerGetLoadOptions (&NvBootOptionCount, LoadOptionTypeBoot);\r
2531\r
2532 //\r
2533 // Mark the boot option as added by BDS by setting OptionalData to a special GUID\r
2534 //\r
2535 for (Index = 0; Index < BootOptionCount; Index++) {\r
2536 BootOptions[Index].OptionalData = AllocateCopyPool (sizeof (EFI_GUID), &mBmAutoCreateBootOptionGuid);\r
2537 BootOptions[Index].OptionalDataSize = sizeof (EFI_GUID);\r
2538 }\r
2539\r
2540 //\r
2541 // Remove invalid EFI boot options from NV\r
2542 //\r
2543 for (Index = 0; Index < NvBootOptionCount; Index++) {\r
2544 if (((DevicePathType (NvBootOptions[Index].FilePath) != BBS_DEVICE_PATH) || \r
2545 (DevicePathSubType (NvBootOptions[Index].FilePath) != BBS_BBS_DP)\r
404bd442 2546 ) && BmIsAutoCreateBootOption (&NvBootOptions[Index])\r
067ed98a
RN
2547 ) {\r
2548 //\r
2549 // Only check those added by BDS\r
2550 // so that the boot options added by end-user or OS installer won't be deleted\r
2551 //\r
5d3a9896 2552 if (EfiBootManagerFindLoadOption (&NvBootOptions[Index], BootOptions, BootOptionCount) == (UINTN) -1) {\r
067ed98a
RN
2553 Status = EfiBootManagerDeleteLoadOptionVariable (NvBootOptions[Index].OptionNumber, LoadOptionTypeBoot);\r
2554 //\r
2555 // Deleting variable with current variable implementation shouldn't fail.\r
2556 //\r
2557 ASSERT_EFI_ERROR (Status);\r
2558 }\r
2559 }\r
2560 }\r
2561\r
2562 //\r
2563 // Add new EFI boot options to NV\r
2564 //\r
2565 for (Index = 0; Index < BootOptionCount; Index++) {\r
5d3a9896 2566 if (EfiBootManagerFindLoadOption (&BootOptions[Index], NvBootOptions, NvBootOptionCount) == (UINTN) -1) {\r
067ed98a
RN
2567 EfiBootManagerAddLoadOptionVariable (&BootOptions[Index], (UINTN) -1);\r
2568 //\r
2569 // Try best to add the boot options so continue upon failure.\r
2570 //\r
2571 }\r
2572 }\r
2573\r
2574 EfiBootManagerFreeLoadOptions (BootOptions, BootOptionCount);\r
2575 EfiBootManagerFreeLoadOptions (NvBootOptions, NvBootOptionCount);\r
2576}\r
2577\r
2578/**\r
2579 This function is called to create the boot option for the Boot Manager Menu.\r
2580\r
2581 The Boot Manager Menu is shown after successfully booting a boot option.\r
2582 Assume the BootManagerMenuFile is in the same FV as the module links to this library.\r
2583\r
2584 @param BootOption Return the boot option of the Boot Manager Menu\r
2585\r
2586 @retval EFI_SUCCESS Successfully register the Boot Manager Menu.\r
2587 @retval Status Return status of gRT->SetVariable (). BootOption still points\r
2588 to the Boot Manager Menu even the Status is not EFI_SUCCESS.\r
2589**/\r
2590EFI_STATUS\r
2591BmRegisterBootManagerMenu (\r
2592 OUT EFI_BOOT_MANAGER_LOAD_OPTION *BootOption\r
2593 )\r
2594{\r
2595 EFI_STATUS Status;\r
2596 CHAR16 *Description;\r
2597 UINTN DescriptionLength;\r
2598 EFI_DEVICE_PATH_PROTOCOL *DevicePath;\r
2599 EFI_LOADED_IMAGE_PROTOCOL *LoadedImage;\r
2600 MEDIA_FW_VOL_FILEPATH_DEVICE_PATH FileNode;\r
2601\r
2602 Status = GetSectionFromFv (\r
2603 PcdGetPtr (PcdBootManagerMenuFile),\r
2604 EFI_SECTION_USER_INTERFACE,\r
2605 0,\r
2606 (VOID **) &Description,\r
2607 &DescriptionLength\r
2608 );\r
2609 if (EFI_ERROR (Status)) {\r
2610 Description = NULL;\r
2611 }\r
2612\r
2613 EfiInitializeFwVolDevicepathNode (&FileNode, PcdGetPtr (PcdBootManagerMenuFile));\r
2614 Status = gBS->HandleProtocol (\r
2615 gImageHandle,\r
2616 &gEfiLoadedImageProtocolGuid,\r
2617 (VOID **) &LoadedImage\r
2618 );\r
2619 ASSERT_EFI_ERROR (Status);\r
2620 DevicePath = AppendDevicePathNode (\r
2621 DevicePathFromHandle (LoadedImage->DeviceHandle),\r
2622 (EFI_DEVICE_PATH_PROTOCOL *) &FileNode\r
2623 );\r
2624 ASSERT (DevicePath != NULL);\r
2625\r
2626 Status = EfiBootManagerInitializeLoadOption (\r
2627 BootOption,\r
2628 LoadOptionNumberUnassigned,\r
2629 LoadOptionTypeBoot,\r
2630 LOAD_OPTION_CATEGORY_APP | LOAD_OPTION_ACTIVE | LOAD_OPTION_HIDDEN,\r
2631 (Description != NULL) ? Description : L"Boot Manager Menu",\r
2632 DevicePath,\r
2633 NULL,\r
2634 0\r
2635 );\r
2636 ASSERT_EFI_ERROR (Status);\r
2637 FreePool (DevicePath);\r
2638 if (Description != NULL) {\r
2639 FreePool (Description);\r
2640 }\r
2641\r
2642 DEBUG_CODE (\r
2643 EFI_BOOT_MANAGER_LOAD_OPTION *BootOptions;\r
2644 UINTN BootOptionCount;\r
2645\r
2646 BootOptions = EfiBootManagerGetLoadOptions (&BootOptionCount, LoadOptionTypeBoot);\r
5d3a9896 2647 ASSERT (EfiBootManagerFindLoadOption (BootOption, BootOptions, BootOptionCount) == -1);\r
067ed98a
RN
2648 EfiBootManagerFreeLoadOptions (BootOptions, BootOptionCount);\r
2649 );\r
2650\r
2651 return EfiBootManagerAddLoadOptionVariable (BootOption, 0);\r
2652}\r
2653\r
2654/**\r
2655 Return the boot option corresponding to the Boot Manager Menu.\r
2656 It may automatically create one if the boot option hasn't been created yet.\r
2657 \r
2658 @param BootOption Return the Boot Manager Menu.\r
2659\r
2660 @retval EFI_SUCCESS The Boot Manager Menu is successfully returned.\r
2661 @retval Status Return status of gRT->SetVariable (). BootOption still points\r
2662 to the Boot Manager Menu even the Status is not EFI_SUCCESS.\r
2663**/\r
2664EFI_STATUS\r
2665EFIAPI\r
2666EfiBootManagerGetBootManagerMenu (\r
2667 EFI_BOOT_MANAGER_LOAD_OPTION *BootOption\r
2668 )\r
2669{\r
2670 EFI_STATUS Status;\r
2671 UINTN BootOptionCount;\r
2672 EFI_BOOT_MANAGER_LOAD_OPTION *BootOptions;\r
2673 UINTN Index;\r
2674 EFI_DEVICE_PATH_PROTOCOL *Node;\r
2675 EFI_HANDLE FvHandle;\r
2676 \r
2677 BootOptions = EfiBootManagerGetLoadOptions (&BootOptionCount, LoadOptionTypeBoot);\r
2678\r
2679 for (Index = 0; Index < BootOptionCount; Index++) {\r
2680 Node = BootOptions[Index].FilePath;\r
2681 Status = gBS->LocateDevicePath (&gEfiFirmwareVolume2ProtocolGuid, &Node, &FvHandle);\r
2682 if (!EFI_ERROR (Status)) {\r
2683 if (CompareGuid (\r
2684 EfiGetNameGuidFromFwVolDevicePathNode ((CONST MEDIA_FW_VOL_FILEPATH_DEVICE_PATH *) Node),\r
2685 PcdGetPtr (PcdBootManagerMenuFile)\r
2686 )\r
2687 ) { \r
2688 Status = EfiBootManagerInitializeLoadOption (\r
2689 BootOption,\r
2690 BootOptions[Index].OptionNumber,\r
2691 BootOptions[Index].OptionType,\r
2692 BootOptions[Index].Attributes,\r
2693 BootOptions[Index].Description,\r
2694 BootOptions[Index].FilePath,\r
2695 BootOptions[Index].OptionalData,\r
2696 BootOptions[Index].OptionalDataSize\r
2697 );\r
2698 ASSERT_EFI_ERROR (Status);\r
2699 break;\r
2700 }\r
2701 }\r
2702 }\r
2703\r
2704 EfiBootManagerFreeLoadOptions (BootOptions, BootOptionCount);\r
2705\r
2706 //\r
2707 // Automatically create the Boot#### for Boot Manager Menu when not found.\r
2708 //\r
2709 if (Index == BootOptionCount) {\r
2710 return BmRegisterBootManagerMenu (BootOption);\r
2711 } else {\r
2712 return EFI_SUCCESS;\r
2713 }\r
2714}\r
2715\r