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