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