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