]> git.proxmox.com Git - mirror_edk2.git/blame - MdeModulePkg/Library/UefiBootManagerLib/BmBoot.c
MdeModulePkg/UefiBootManagerLib: fix LoadImage/StartImage status code rep.
[mirror_edk2.git] / MdeModulePkg / Library / UefiBootManagerLib / BmBoot.c
CommitLineData
067ed98a
RN
1/** @file\r
2 Library functions which relates with booting.\r
3\r
b4e1ad87 4Copyright (c) 2011 - 2019, 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
5cc67962
LE
1670/**\r
1671 Report status code with EFI_RETURN_STATUS_EXTENDED_DATA about LoadImage() or\r
1672 StartImage() failure.\r
1673\r
1674 @param[in] ErrorCode An Error Code in the Software Class, DXE Boot\r
1675 Service Driver Subclass. ErrorCode will be used to\r
1676 compose the Value parameter for status code\r
1677 reporting. Must be one of\r
1678 EFI_SW_DXE_BS_EC_BOOT_OPTION_LOAD_ERROR and\r
1679 EFI_SW_DXE_BS_EC_BOOT_OPTION_FAILED.\r
1680\r
1681 @param[in] FailureStatus The failure status returned by the boot service\r
1682 that should be reported.\r
1683**/\r
1684VOID\r
1685BmReportLoadFailure (\r
1686 IN UINT32 ErrorCode,\r
1687 IN EFI_STATUS FailureStatus\r
1688 )\r
1689{\r
1690 EFI_RETURN_STATUS_EXTENDED_DATA ExtendedData;\r
1691\r
1692 if (!ReportErrorCodeEnabled ()) {\r
1693 return;\r
1694 }\r
1695\r
1696 ASSERT (\r
1697 (ErrorCode == EFI_SW_DXE_BS_EC_BOOT_OPTION_LOAD_ERROR) ||\r
1698 (ErrorCode == EFI_SW_DXE_BS_EC_BOOT_OPTION_FAILED)\r
1699 );\r
1700\r
1701 ZeroMem (&ExtendedData, sizeof (ExtendedData));\r
1702 ExtendedData.ReturnStatus = FailureStatus;\r
1703\r
1704 REPORT_STATUS_CODE_EX (\r
1705 (EFI_ERROR_CODE | EFI_ERROR_MINOR),\r
1706 (EFI_SOFTWARE_DXE_BS_DRIVER | ErrorCode),\r
1707 0,\r
1708 NULL,\r
1709 NULL,\r
1710 &ExtendedData.DataHeader + 1,\r
1711 sizeof (ExtendedData) - sizeof (ExtendedData.DataHeader)\r
1712 );\r
1713}\r
1714\r
067ed98a
RN
1715/**\r
1716 Attempt to boot the EFI boot option. This routine sets L"BootCurent" and\r
1717 also signals the EFI ready to boot event. If the device path for the option\r
d1102dba
LG
1718 starts with a BBS device path a legacy boot is attempted via the registered\r
1719 gLegacyBoot function. Short form device paths are also supported via this\r
067ed98a
RN
1720 rountine. A device path starting with MEDIA_HARDDRIVE_DP, MSG_USB_WWID_DP,\r
1721 MSG_USB_CLASS_DP gets expaned out to find the first device that matches.\r
d1102dba
LG
1722 If the BootOption Device Path fails the removable media boot algorithm\r
1723 is attempted (\EFI\BOOTIA32.EFI, \EFI\BOOTX64.EFI,... only one file type\r
067ed98a
RN
1724 is tried per processor type)\r
1725\r
1726 @param BootOption Boot Option to try and boot.\r
1727 On return, BootOption->Status contains the boot status.\r
1728 EFI_SUCCESS BootOption was booted\r
1729 EFI_UNSUPPORTED A BBS device path was found with no valid callback\r
1730 registered via EfiBootManagerInitialize().\r
1731 EFI_NOT_FOUND The BootOption was not found on the system\r
1732 !EFI_SUCCESS BootOption failed with this error status\r
1733\r
1734**/\r
1735VOID\r
1736EFIAPI\r
1737EfiBootManagerBoot (\r
1738 IN EFI_BOOT_MANAGER_LOAD_OPTION *BootOption\r
1739 )\r
1740{\r
1741 EFI_STATUS Status;\r
1742 EFI_HANDLE ImageHandle;\r
1743 EFI_LOADED_IMAGE_PROTOCOL *ImageInfo;\r
1744 UINT16 Uint16;\r
1745 UINTN OptionNumber;\r
1746 UINTN OriginalOptionNumber;\r
1747 EFI_DEVICE_PATH_PROTOCOL *FilePath;\r
339ae051 1748 EFI_DEVICE_PATH_PROTOCOL *RamDiskDevicePath;\r
067ed98a
RN
1749 VOID *FileBuffer;\r
1750 UINTN FileSize;\r
1751 EFI_BOOT_LOGO_PROTOCOL *BootLogo;\r
1752 EFI_EVENT LegacyBootEvent;\r
1753\r
1754 if (BootOption == NULL) {\r
1755 return;\r
1756 }\r
1757\r
1758 if (BootOption->FilePath == NULL || BootOption->OptionType != LoadOptionTypeBoot) {\r
1759 BootOption->Status = EFI_INVALID_PARAMETER;\r
1760 return;\r
1761 }\r
1762\r
1763 //\r
1764 // 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
1765 //\r
1766 OptionNumber = BmFindBootOptionInVariable (BootOption);\r
1767 if (OptionNumber == LoadOptionNumberUnassigned) {\r
1768 Status = BmGetFreeOptionNumber (LoadOptionTypeBoot, &Uint16);\r
1769 if (!EFI_ERROR (Status)) {\r
1770 //\r
1771 // Save the BootOption->OptionNumber to restore later\r
1772 //\r
1773 OptionNumber = Uint16;\r
1774 OriginalOptionNumber = BootOption->OptionNumber;\r
1775 BootOption->OptionNumber = OptionNumber;\r
1776 Status = EfiBootManagerLoadOptionToVariable (BootOption);\r
1777 BootOption->OptionNumber = OriginalOptionNumber;\r
1778 }\r
1779\r
1780 if (EFI_ERROR (Status)) {\r
1781 DEBUG ((EFI_D_ERROR, "[Bds] Failed to create Boot#### for a temporary boot - %r!\n", Status));\r
1782 BootOption->Status = Status;\r
1783 return ;\r
1784 }\r
1785 }\r
1786\r
1787 //\r
1788 // 2. Set BootCurrent\r
1789 //\r
1790 Uint16 = (UINT16) OptionNumber;\r
1791 BmSetVariableAndReportStatusCodeOnError (\r
1792 L"BootCurrent",\r
1793 &gEfiGlobalVariableGuid,\r
1794 EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS,\r
1795 sizeof (UINT16),\r
1796 &Uint16\r
1797 );\r
1798\r
1799 //\r
1800 // 3. Signal the EVT_SIGNAL_READY_TO_BOOT event when we are about to load and execute\r
1801 // the boot option.\r
1802 //\r
7c69fbf2 1803 if (BmIsBootManagerMenuFilePath (BootOption->FilePath)) {\r
067ed98a
RN
1804 DEBUG ((EFI_D_INFO, "[Bds] Booting Boot Manager Menu.\n"));\r
1805 BmStopHotkeyService (NULL, NULL);\r
1806 } else {\r
1807 EfiSignalEventReadyToBoot();\r
1808 //\r
1809 // Report Status Code to indicate ReadyToBoot was signalled\r
1810 //\r
1811 REPORT_STATUS_CODE (EFI_PROGRESS_CODE, (EFI_SOFTWARE_DXE_BS_DRIVER | EFI_SW_DXE_BS_PC_READY_TO_BOOT_EVENT));\r
1812 //\r
1813 // 4. Repair system through DriverHealth protocol\r
1814 //\r
72208a9a 1815 BmRepairAllControllers (0);\r
067ed98a
RN
1816 }\r
1817\r
1818 PERF_START_EX (gImageHandle, "BdsAttempt", NULL, 0, (UINT32) OptionNumber);\r
1819\r
1820 //\r
3a986a35
RN
1821 // 5. Adjust the different type memory page number just before booting\r
1822 // and save the updated info into the variable for next boot to use\r
1823 //\r
1824 BmSetMemoryTypeInformationVariable (\r
1825 (BOOLEAN) ((BootOption->Attributes & LOAD_OPTION_CATEGORY) == LOAD_OPTION_CATEGORY_BOOT)\r
1826 );\r
1827\r
1828 //\r
1829 // 6. Load EFI boot option to ImageHandle\r
067ed98a 1830 //\r
3a986a35
RN
1831 DEBUG_CODE_BEGIN ();\r
1832 if (BootOption->Description == NULL) {\r
1833 DEBUG ((DEBUG_INFO | DEBUG_LOAD, "[Bds]Booting from unknown device path\n"));\r
1834 } else {\r
1835 DEBUG ((DEBUG_INFO | DEBUG_LOAD, "[Bds]Booting %s\n", BootOption->Description));\r
1836 }\r
1837 DEBUG_CODE_END ();\r
1838\r
339ae051
RN
1839 ImageHandle = NULL;\r
1840 RamDiskDevicePath = NULL;\r
067ed98a 1841 if (DevicePathType (BootOption->FilePath) != BBS_DEVICE_PATH) {\r
08eff917
RN
1842 Status = EFI_NOT_FOUND;\r
1843 FilePath = NULL;\r
1844 EfiBootManagerConnectDevicePath (BootOption->FilePath, NULL);\r
1845 FileBuffer = BmGetNextLoadOptionBuffer (LoadOptionTypeBoot, BootOption->FilePath, &FilePath, &FileSize);\r
339ae051
RN
1846 if (FileBuffer != NULL) {\r
1847 RamDiskDevicePath = BmGetRamDiskDevicePath (FilePath);\r
08eff917 1848\r
067ed98a
RN
1849 REPORT_STATUS_CODE (EFI_PROGRESS_CODE, PcdGet32 (PcdProgressCodeOsLoaderLoad));\r
1850 Status = gBS->LoadImage (\r
1851 TRUE,\r
1852 gImageHandle,\r
1853 FilePath,\r
1854 FileBuffer,\r
1855 FileSize,\r
1856 &ImageHandle\r
1857 );\r
1858 }\r
1859 if (FileBuffer != NULL) {\r
1860 FreePool (FileBuffer);\r
1861 }\r
1862 if (FilePath != NULL) {\r
1863 FreePool (FilePath);\r
1864 }\r
1865\r
1866 if (EFI_ERROR (Status)) {\r
1867 //\r
c2cf8720 1868 // Report Status Code with the failure status to indicate that the failure to load boot option\r
067ed98a 1869 //\r
5cc67962 1870 BmReportLoadFailure (EFI_SW_DXE_BS_EC_BOOT_OPTION_LOAD_ERROR, Status);\r
067ed98a 1871 BootOption->Status = Status;\r
339ae051
RN
1872 //\r
1873 // Destroy the RAM disk\r
1874 //\r
1875 if (RamDiskDevicePath != NULL) {\r
1876 BmDestroyRamDisk (RamDiskDevicePath);\r
1877 FreePool (RamDiskDevicePath);\r
1878 }\r
067ed98a
RN
1879 return;\r
1880 }\r
1881 }\r
1882\r
067ed98a
RN
1883 //\r
1884 // Check to see if we should legacy BOOT. If yes then do the legacy boot\r
1885 // Write boot to OS performance data for Legacy boot\r
1886 //\r
1887 if ((DevicePathType (BootOption->FilePath) == BBS_DEVICE_PATH) && (DevicePathSubType (BootOption->FilePath) == BBS_BBS_DP)) {\r
1888 if (mBmLegacyBoot != NULL) {\r
1889 //\r
1890 // Write boot to OS performance data for legacy boot.\r
1891 //\r
1892 PERF_CODE (\r
1893 //\r
1894 // Create an event to be signalled when Legacy Boot occurs to write performance data.\r
1895 //\r
1896 Status = EfiCreateEventLegacyBootEx(\r
1897 TPL_NOTIFY,\r
3a039a56 1898 BmEndOfBdsPerfCode,\r
d1102dba 1899 NULL,\r
067ed98a
RN
1900 &LegacyBootEvent\r
1901 );\r
1902 ASSERT_EFI_ERROR (Status);\r
1903 );\r
1904\r
1905 mBmLegacyBoot (BootOption);\r
1906 } else {\r
1907 BootOption->Status = EFI_UNSUPPORTED;\r
1908 }\r
1909\r
1910 PERF_END_EX (gImageHandle, "BdsAttempt", NULL, 0, (UINT32) OptionNumber);\r
1911 return;\r
1912 }\r
d1102dba 1913\r
067ed98a
RN
1914 //\r
1915 // Provide the image with its load options\r
1916 //\r
1917 Status = gBS->HandleProtocol (ImageHandle, &gEfiLoadedImageProtocolGuid, (VOID **) &ImageInfo);\r
1918 ASSERT_EFI_ERROR (Status);\r
1919\r
404bd442
RN
1920 if (!BmIsAutoCreateBootOption (BootOption)) {\r
1921 ImageInfo->LoadOptionsSize = BootOption->OptionalDataSize;\r
1922 ImageInfo->LoadOptions = BootOption->OptionalData;\r
1923 }\r
067ed98a
RN
1924\r
1925 //\r
1926 // Clean to NULL because the image is loaded directly from the firmwares boot manager.\r
1927 //\r
1928 ImageInfo->ParentHandle = NULL;\r
1929\r
1930 //\r
1931 // Before calling the image, enable the Watchdog Timer for 5 minutes period\r
1932 //\r
1933 gBS->SetWatchdogTimer (5 * 60, 0x0000, 0x00, NULL);\r
1934\r
1935 //\r
1936 // Write boot to OS performance data for UEFI boot\r
1937 //\r
1938 PERF_CODE (\r
3a039a56 1939 BmEndOfBdsPerfCode (NULL, NULL);\r
067ed98a
RN
1940 );\r
1941\r
1942 REPORT_STATUS_CODE (EFI_PROGRESS_CODE, PcdGet32 (PcdProgressCodeOsLoaderStart));\r
1943\r
1944 Status = gBS->StartImage (ImageHandle, &BootOption->ExitDataSize, &BootOption->ExitData);\r
1945 DEBUG ((DEBUG_INFO | DEBUG_LOAD, "Image Return Status = %r\n", Status));\r
1946 BootOption->Status = Status;\r
1947 if (EFI_ERROR (Status)) {\r
1948 //\r
c2cf8720 1949 // Report Status Code with the failure status to indicate that boot failure\r
067ed98a 1950 //\r
5cc67962 1951 BmReportLoadFailure (EFI_SW_DXE_BS_EC_BOOT_OPTION_FAILED, Status);\r
067ed98a
RN
1952 }\r
1953 PERF_END_EX (gImageHandle, "BdsAttempt", NULL, 0, (UINT32) OptionNumber);\r
1954\r
339ae051
RN
1955 //\r
1956 // Destroy the RAM disk\r
1957 //\r
1958 if (RamDiskDevicePath != NULL) {\r
1959 BmDestroyRamDisk (RamDiskDevicePath);\r
1960 FreePool (RamDiskDevicePath);\r
1961 }\r
1962\r
067ed98a
RN
1963 //\r
1964 // Clear the Watchdog Timer after the image returns\r
1965 //\r
1966 gBS->SetWatchdogTimer (0x0000, 0x0000, 0x0000, NULL);\r
1967\r
1968 //\r
1969 // Set Logo status invalid after trying one boot option\r
1970 //\r
1971 BootLogo = NULL;\r
1972 Status = gBS->LocateProtocol (&gEfiBootLogoProtocolGuid, NULL, (VOID **) &BootLogo);\r
1973 if (!EFI_ERROR (Status) && (BootLogo != NULL)) {\r
1974 Status = BootLogo->SetBootLogo (BootLogo, NULL, 0, 0, 0, 0);\r
1975 ASSERT_EFI_ERROR (Status);\r
1976 }\r
1977\r
1978 //\r
1979 // Clear Boot Current\r
1980 //\r
1981 Status = gRT->SetVariable (\r
1982 L"BootCurrent",\r
1983 &gEfiGlobalVariableGuid,\r
1984 0,\r
1985 0,\r
1986 NULL\r
1987 );\r
1988 //\r
1989 // Deleting variable with current variable implementation shouldn't fail.\r
1990 // When BootXXXX (e.g.: BootManagerMenu) boots BootYYYY, exiting BootYYYY causes BootCurrent deleted,\r
1991 // exiting BootXXXX causes deleting BootCurrent returns EFI_NOT_FOUND.\r
1992 //\r
1993 ASSERT (Status == EFI_SUCCESS || Status == EFI_NOT_FOUND);\r
1994}\r
1995\r
1996/**\r
1997 Check whether there is a instance in BlockIoDevicePath, which contain multi device path\r
1998 instances, has the same partition node with HardDriveDevicePath device path\r
1999\r
2000 @param BlockIoDevicePath Multi device path instances which need to check\r
2001 @param HardDriveDevicePath A device path which starts with a hard drive media\r
2002 device path.\r
2003\r
2004 @retval TRUE There is a matched device path instance.\r
2005 @retval FALSE There is no matched device path instance.\r
2006\r
2007**/\r
2008BOOLEAN\r
2009BmMatchPartitionDevicePathNode (\r
2010 IN EFI_DEVICE_PATH_PROTOCOL *BlockIoDevicePath,\r
2011 IN HARDDRIVE_DEVICE_PATH *HardDriveDevicePath\r
2012 )\r
2013{\r
2014 HARDDRIVE_DEVICE_PATH *Node;\r
2015\r
2016 if ((BlockIoDevicePath == NULL) || (HardDriveDevicePath == NULL)) {\r
2017 return FALSE;\r
2018 }\r
2019\r
2020 //\r
02021d2e 2021 // Match all the partition device path nodes including the nested partition nodes\r
067ed98a
RN
2022 //\r
2023 while (!IsDevicePathEnd (BlockIoDevicePath)) {\r
2024 if ((DevicePathType (BlockIoDevicePath) == MEDIA_DEVICE_PATH) &&\r
2025 (DevicePathSubType (BlockIoDevicePath) == MEDIA_HARDDRIVE_DP)\r
2026 ) {\r
02021d2e
GL
2027 //\r
2028 // See if the harddrive device path in blockio matches the orig Hard Drive Node\r
2029 //\r
2030 Node = (HARDDRIVE_DEVICE_PATH *) BlockIoDevicePath;\r
2031\r
2032 //\r
2033 // Match Signature and PartitionNumber.\r
2034 // Unused bytes in Signature are initiaized with zeros.\r
2035 //\r
2036 if ((Node->PartitionNumber == HardDriveDevicePath->PartitionNumber) &&\r
2037 (Node->MBRType == HardDriveDevicePath->MBRType) &&\r
2038 (Node->SignatureType == HardDriveDevicePath->SignatureType) &&\r
2039 (CompareMem (Node->Signature, HardDriveDevicePath->Signature, sizeof (Node->Signature)) == 0)) {\r
2040 return TRUE;\r
2041 }\r
067ed98a
RN
2042 }\r
2043\r
2044 BlockIoDevicePath = NextDevicePathNode (BlockIoDevicePath);\r
2045 }\r
2046\r
02021d2e 2047 return FALSE;\r
067ed98a
RN
2048}\r
2049\r
2050/**\r
2051 Emuerate all possible bootable medias in the following order:\r
2052 1. Removable BlockIo - The boot option only points to the removable media\r
2053 device, like USB key, DVD, Floppy etc.\r
2054 2. Fixed BlockIo - The boot option only points to a Fixed blockIo device,\r
2055 like HardDisk.\r
2056 3. Non-BlockIo SimpleFileSystem - The boot option points to a device supporting\r
2057 SimpleFileSystem Protocol, but not supporting BlockIo\r
2058 protocol.\r
d1102dba 2059 4. LoadFile - The boot option points to the media supporting\r
067ed98a
RN
2060 LoadFile protocol.\r
2061 Reference: UEFI Spec chapter 3.3 Boot Option Variables Default Boot Behavior\r
2062\r
2063 @param BootOptionCount Return the boot option count which has been found.\r
2064\r
2065 @retval Pointer to the boot option array.\r
2066**/\r
2067EFI_BOOT_MANAGER_LOAD_OPTION *\r
2068BmEnumerateBootOptions (\r
2069 UINTN *BootOptionCount\r
2070 )\r
2071{\r
2072 EFI_STATUS Status;\r
2073 EFI_BOOT_MANAGER_LOAD_OPTION *BootOptions;\r
067ed98a
RN
2074 UINTN HandleCount;\r
2075 EFI_HANDLE *Handles;\r
2076 EFI_BLOCK_IO_PROTOCOL *BlkIo;\r
2077 UINTN Removable;\r
2078 UINTN Index;\r
f41c71d2 2079 CHAR16 *Description;\r
067ed98a
RN
2080\r
2081 ASSERT (BootOptionCount != NULL);\r
2082\r
2083 *BootOptionCount = 0;\r
2084 BootOptions = NULL;\r
2085\r
2086 //\r
2087 // Parse removable block io followed by fixed block io\r
2088 //\r
2089 gBS->LocateHandleBuffer (\r
2090 ByProtocol,\r
2091 &gEfiBlockIoProtocolGuid,\r
2092 NULL,\r
2093 &HandleCount,\r
2094 &Handles\r
2095 );\r
2096\r
2097 for (Removable = 0; Removable < 2; Removable++) {\r
2098 for (Index = 0; Index < HandleCount; Index++) {\r
2099 Status = gBS->HandleProtocol (\r
2100 Handles[Index],\r
2101 &gEfiBlockIoProtocolGuid,\r
2102 (VOID **) &BlkIo\r
2103 );\r
2104 if (EFI_ERROR (Status)) {\r
2105 continue;\r
2106 }\r
2107\r
2108 //\r
2109 // Skip the logical partitions\r
2110 //\r
2111 if (BlkIo->Media->LogicalPartition) {\r
2112 continue;\r
2113 }\r
2114\r
2115 //\r
2116 // Skip the fixed block io then the removable block io\r
2117 //\r
2118 if (BlkIo->Media->RemovableMedia == ((Removable == 0) ? FALSE : TRUE)) {\r
2119 continue;\r
2120 }\r
2121\r
f41c71d2 2122 Description = BmGetBootDescription (Handles[Index]);\r
067ed98a
RN
2123 BootOptions = ReallocatePool (\r
2124 sizeof (EFI_BOOT_MANAGER_LOAD_OPTION) * (*BootOptionCount),\r
2125 sizeof (EFI_BOOT_MANAGER_LOAD_OPTION) * (*BootOptionCount + 1),\r
2126 BootOptions\r
2127 );\r
2128 ASSERT (BootOptions != NULL);\r
2129\r
2130 Status = EfiBootManagerInitializeLoadOption (\r
2131 &BootOptions[(*BootOptionCount)++],\r
2132 LoadOptionNumberUnassigned,\r
2133 LoadOptionTypeBoot,\r
2134 LOAD_OPTION_ACTIVE,\r
f41c71d2 2135 Description,\r
067ed98a
RN
2136 DevicePathFromHandle (Handles[Index]),\r
2137 NULL,\r
2138 0\r
2139 );\r
2140 ASSERT_EFI_ERROR (Status);\r
2141\r
f41c71d2 2142 FreePool (Description);\r
067ed98a
RN
2143 }\r
2144 }\r
2145\r
2146 if (HandleCount != 0) {\r
2147 FreePool (Handles);\r
2148 }\r
2149\r
2150 //\r
2151 // Parse simple file system not based on block io\r
2152 //\r
067ed98a
RN
2153 gBS->LocateHandleBuffer (\r
2154 ByProtocol,\r
2155 &gEfiSimpleFileSystemProtocolGuid,\r
2156 NULL,\r
2157 &HandleCount,\r
2158 &Handles\r
2159 );\r
2160 for (Index = 0; Index < HandleCount; Index++) {\r
2161 Status = gBS->HandleProtocol (\r
2162 Handles[Index],\r
2163 &gEfiBlockIoProtocolGuid,\r
2164 (VOID **) &BlkIo\r
2165 );\r
2166 if (!EFI_ERROR (Status)) {\r
2167 //\r
2168 // Skip if the file system handle supports a BlkIo protocol, which we've handled in above\r
2169 //\r
2170 continue;\r
2171 }\r
f41c71d2 2172 Description = BmGetBootDescription (Handles[Index]);\r
067ed98a
RN
2173 BootOptions = ReallocatePool (\r
2174 sizeof (EFI_BOOT_MANAGER_LOAD_OPTION) * (*BootOptionCount),\r
2175 sizeof (EFI_BOOT_MANAGER_LOAD_OPTION) * (*BootOptionCount + 1),\r
2176 BootOptions\r
2177 );\r
2178 ASSERT (BootOptions != NULL);\r
2179\r
2180 Status = EfiBootManagerInitializeLoadOption (\r
2181 &BootOptions[(*BootOptionCount)++],\r
2182 LoadOptionNumberUnassigned,\r
2183 LoadOptionTypeBoot,\r
2184 LOAD_OPTION_ACTIVE,\r
2185 Description,\r
2186 DevicePathFromHandle (Handles[Index]),\r
2187 NULL,\r
2188 0\r
2189 );\r
2190 ASSERT_EFI_ERROR (Status);\r
f41c71d2 2191 FreePool (Description);\r
067ed98a
RN
2192 }\r
2193\r
2194 if (HandleCount != 0) {\r
2195 FreePool (Handles);\r
2196 }\r
2197\r
2198 //\r
2f014788 2199 // Parse load file protocol\r
067ed98a
RN
2200 //\r
2201 gBS->LocateHandleBuffer (\r
2202 ByProtocol,\r
2203 &gEfiLoadFileProtocolGuid,\r
2204 NULL,\r
2205 &HandleCount,\r
2206 &Handles\r
2207 );\r
2208 for (Index = 0; Index < HandleCount; Index++) {\r
8953d69a
LG
2209 //\r
2210 // Ignore BootManagerMenu. its boot option will be created by EfiBootManagerGetBootManagerMenu().\r
2211 //\r
2212 if (BmIsBootManagerMenuFilePath (DevicePathFromHandle (Handles[Index]))) {\r
2213 continue;\r
2214 }\r
067ed98a 2215\r
f41c71d2 2216 Description = BmGetBootDescription (Handles[Index]);\r
067ed98a
RN
2217 BootOptions = ReallocatePool (\r
2218 sizeof (EFI_BOOT_MANAGER_LOAD_OPTION) * (*BootOptionCount),\r
2219 sizeof (EFI_BOOT_MANAGER_LOAD_OPTION) * (*BootOptionCount + 1),\r
2220 BootOptions\r
2221 );\r
2222 ASSERT (BootOptions != NULL);\r
2223\r
2224 Status = EfiBootManagerInitializeLoadOption (\r
2225 &BootOptions[(*BootOptionCount)++],\r
2226 LoadOptionNumberUnassigned,\r
2227 LoadOptionTypeBoot,\r
8953d69a 2228 LOAD_OPTION_ACTIVE,\r
067ed98a
RN
2229 Description,\r
2230 DevicePathFromHandle (Handles[Index]),\r
2231 NULL,\r
2232 0\r
2233 );\r
2234 ASSERT_EFI_ERROR (Status);\r
f41c71d2 2235 FreePool (Description);\r
067ed98a
RN
2236 }\r
2237\r
2238 if (HandleCount != 0) {\r
2239 FreePool (Handles);\r
2240 }\r
2241\r
d948fe96 2242 BmMakeBootOptionDescriptionUnique (BootOptions, *BootOptionCount);\r
067ed98a
RN
2243 return BootOptions;\r
2244}\r
2245\r
2246/**\r
2247 The function enumerates all boot options, creates them and registers them in the BootOrder variable.\r
2248**/\r
2249VOID\r
2250EFIAPI\r
2251EfiBootManagerRefreshAllBootOption (\r
2252 VOID\r
2253 )\r
2254{\r
2255 EFI_STATUS Status;\r
2256 EFI_BOOT_MANAGER_LOAD_OPTION *NvBootOptions;\r
2257 UINTN NvBootOptionCount;\r
2258 EFI_BOOT_MANAGER_LOAD_OPTION *BootOptions;\r
2259 UINTN BootOptionCount;\r
2260 UINTN Index;\r
2261\r
2262 //\r
2263 // Optionally refresh the legacy boot option\r
2264 //\r
2265 if (mBmRefreshLegacyBootOption != NULL) {\r
2266 mBmRefreshLegacyBootOption ();\r
2267 }\r
2268\r
2269 BootOptions = BmEnumerateBootOptions (&BootOptionCount);\r
2270 NvBootOptions = EfiBootManagerGetLoadOptions (&NvBootOptionCount, LoadOptionTypeBoot);\r
2271\r
2272 //\r
2273 // Mark the boot option as added by BDS by setting OptionalData to a special GUID\r
2274 //\r
2275 for (Index = 0; Index < BootOptionCount; Index++) {\r
2276 BootOptions[Index].OptionalData = AllocateCopyPool (sizeof (EFI_GUID), &mBmAutoCreateBootOptionGuid);\r
2277 BootOptions[Index].OptionalDataSize = sizeof (EFI_GUID);\r
2278 }\r
2279\r
2280 //\r
2281 // Remove invalid EFI boot options from NV\r
2282 //\r
2283 for (Index = 0; Index < NvBootOptionCount; Index++) {\r
d1102dba 2284 if (((DevicePathType (NvBootOptions[Index].FilePath) != BBS_DEVICE_PATH) ||\r
067ed98a 2285 (DevicePathSubType (NvBootOptions[Index].FilePath) != BBS_BBS_DP)\r
404bd442 2286 ) && BmIsAutoCreateBootOption (&NvBootOptions[Index])\r
067ed98a
RN
2287 ) {\r
2288 //\r
2289 // Only check those added by BDS\r
2290 // so that the boot options added by end-user or OS installer won't be deleted\r
2291 //\r
51dee9a4 2292 if (EfiBootManagerFindLoadOption (&NvBootOptions[Index], BootOptions, BootOptionCount) == -1) {\r
067ed98a
RN
2293 Status = EfiBootManagerDeleteLoadOptionVariable (NvBootOptions[Index].OptionNumber, LoadOptionTypeBoot);\r
2294 //\r
2295 // Deleting variable with current variable implementation shouldn't fail.\r
2296 //\r
2297 ASSERT_EFI_ERROR (Status);\r
2298 }\r
2299 }\r
2300 }\r
2301\r
2302 //\r
2303 // Add new EFI boot options to NV\r
2304 //\r
2305 for (Index = 0; Index < BootOptionCount; Index++) {\r
51dee9a4 2306 if (EfiBootManagerFindLoadOption (&BootOptions[Index], NvBootOptions, NvBootOptionCount) == -1) {\r
067ed98a
RN
2307 EfiBootManagerAddLoadOptionVariable (&BootOptions[Index], (UINTN) -1);\r
2308 //\r
2309 // Try best to add the boot options so continue upon failure.\r
2310 //\r
2311 }\r
2312 }\r
2313\r
2314 EfiBootManagerFreeLoadOptions (BootOptions, BootOptionCount);\r
2315 EfiBootManagerFreeLoadOptions (NvBootOptions, NvBootOptionCount);\r
2316}\r
2317\r
2318/**\r
e58f1ae5 2319 This function is called to get or create the boot option for the Boot Manager Menu.\r
067ed98a
RN
2320\r
2321 The Boot Manager Menu is shown after successfully booting a boot option.\r
2322 Assume the BootManagerMenuFile is in the same FV as the module links to this library.\r
2323\r
2324 @param BootOption Return the boot option of the Boot Manager Menu\r
2325\r
2326 @retval EFI_SUCCESS Successfully register the Boot Manager Menu.\r
e58f1ae5
SW
2327 @retval EFI_NOT_FOUND The Boot Manager Menu cannot be found.\r
2328 @retval others Return status of gRT->SetVariable (). BootOption still points\r
2329 to the Boot Manager Menu even the Status is not EFI_SUCCESS\r
2330 and EFI_NOT_FOUND.\r
067ed98a
RN
2331**/\r
2332EFI_STATUS\r
2333BmRegisterBootManagerMenu (\r
2334 OUT EFI_BOOT_MANAGER_LOAD_OPTION *BootOption\r
2335 )\r
2336{\r
2337 EFI_STATUS Status;\r
2338 CHAR16 *Description;\r
2339 UINTN DescriptionLength;\r
2340 EFI_DEVICE_PATH_PROTOCOL *DevicePath;\r
2341 EFI_LOADED_IMAGE_PROTOCOL *LoadedImage;\r
2342 MEDIA_FW_VOL_FILEPATH_DEVICE_PATH FileNode;\r
2f014788
LG
2343 UINTN HandleCount;\r
2344 EFI_HANDLE *Handles;\r
2345 UINTN Index;\r
e58f1ae5
SW
2346 VOID *Data;\r
2347 UINTN DataSize;\r
067ed98a 2348\r
2f014788 2349 DevicePath = NULL;\r
e9e44f65 2350 Description = NULL;\r
e58f1ae5 2351 //\r
7c69fbf2 2352 // Try to find BootManagerMenu from LoadFile protocol\r
e58f1ae5 2353 //\r
2f014788
LG
2354 gBS->LocateHandleBuffer (\r
2355 ByProtocol,\r
2356 &gEfiLoadFileProtocolGuid,\r
2357 NULL,\r
2358 &HandleCount,\r
2359 &Handles\r
2360 );\r
2361 for (Index = 0; Index < HandleCount; Index++) {\r
7c69fbf2 2362 if (BmIsBootManagerMenuFilePath (DevicePathFromHandle (Handles[Index]))) {\r
2f014788
LG
2363 DevicePath = DuplicateDevicePath (DevicePathFromHandle (Handles[Index]));\r
2364 Description = BmGetBootDescription (Handles[Index]);\r
2365 break;\r
2366 }\r
2367 }\r
2368 if (HandleCount != 0) {\r
2369 FreePool (Handles);\r
067ed98a
RN
2370 }\r
2371\r
2f014788
LG
2372 if (DevicePath == NULL) {\r
2373 Data = NULL;\r
2374 Status = GetSectionFromFv (\r
2375 PcdGetPtr (PcdBootManagerMenuFile),\r
2376 EFI_SECTION_PE32,\r
2377 0,\r
2378 (VOID **) &Data,\r
2379 &DataSize\r
2380 );\r
2381 if (Data != NULL) {\r
2382 FreePool (Data);\r
2383 }\r
2384 if (EFI_ERROR (Status)) {\r
2385 DEBUG ((EFI_D_WARN, "[Bds]BootManagerMenu FFS section can not be found, skip its boot option registration\n"));\r
2386 return EFI_NOT_FOUND;\r
2387 }\r
2388\r
2389 //\r
2390 // Get BootManagerMenu application's description from EFI User Interface Section.\r
2391 //\r
2392 Status = GetSectionFromFv (\r
2393 PcdGetPtr (PcdBootManagerMenuFile),\r
2394 EFI_SECTION_USER_INTERFACE,\r
2395 0,\r
2396 (VOID **) &Description,\r
2397 &DescriptionLength\r
2398 );\r
2399 if (EFI_ERROR (Status)) {\r
2400 Description = NULL;\r
2401 }\r
2402\r
2403 EfiInitializeFwVolDevicepathNode (&FileNode, PcdGetPtr (PcdBootManagerMenuFile));\r
2404 Status = gBS->HandleProtocol (\r
2405 gImageHandle,\r
2406 &gEfiLoadedImageProtocolGuid,\r
2407 (VOID **) &LoadedImage\r
2408 );\r
2409 ASSERT_EFI_ERROR (Status);\r
2410 DevicePath = AppendDevicePathNode (\r
2411 DevicePathFromHandle (LoadedImage->DeviceHandle),\r
2412 (EFI_DEVICE_PATH_PROTOCOL *) &FileNode\r
2413 );\r
2414 ASSERT (DevicePath != NULL);\r
2415 }\r
067ed98a
RN
2416\r
2417 Status = EfiBootManagerInitializeLoadOption (\r
2418 BootOption,\r
2419 LoadOptionNumberUnassigned,\r
2420 LoadOptionTypeBoot,\r
2421 LOAD_OPTION_CATEGORY_APP | LOAD_OPTION_ACTIVE | LOAD_OPTION_HIDDEN,\r
2422 (Description != NULL) ? Description : L"Boot Manager Menu",\r
2423 DevicePath,\r
2424 NULL,\r
2425 0\r
2426 );\r
2427 ASSERT_EFI_ERROR (Status);\r
2428 FreePool (DevicePath);\r
2429 if (Description != NULL) {\r
2430 FreePool (Description);\r
2431 }\r
2432\r
2433 DEBUG_CODE (\r
2434 EFI_BOOT_MANAGER_LOAD_OPTION *BootOptions;\r
2435 UINTN BootOptionCount;\r
2436\r
2437 BootOptions = EfiBootManagerGetLoadOptions (&BootOptionCount, LoadOptionTypeBoot);\r
5d3a9896 2438 ASSERT (EfiBootManagerFindLoadOption (BootOption, BootOptions, BootOptionCount) == -1);\r
067ed98a
RN
2439 EfiBootManagerFreeLoadOptions (BootOptions, BootOptionCount);\r
2440 );\r
2441\r
2442 return EfiBootManagerAddLoadOptionVariable (BootOption, 0);\r
2443}\r
2444\r
2445/**\r
2446 Return the boot option corresponding to the Boot Manager Menu.\r
2447 It may automatically create one if the boot option hasn't been created yet.\r
e58f1ae5 2448\r
067ed98a
RN
2449 @param BootOption Return the Boot Manager Menu.\r
2450\r
2451 @retval EFI_SUCCESS The Boot Manager Menu is successfully returned.\r
e58f1ae5
SW
2452 @retval EFI_NOT_FOUND The Boot Manager Menu cannot be found.\r
2453 @retval others Return status of gRT->SetVariable (). BootOption still points\r
2454 to the Boot Manager Menu even the Status is not EFI_SUCCESS\r
2455 and EFI_NOT_FOUND.\r
067ed98a
RN
2456**/\r
2457EFI_STATUS\r
2458EFIAPI\r
2459EfiBootManagerGetBootManagerMenu (\r
2460 EFI_BOOT_MANAGER_LOAD_OPTION *BootOption\r
2461 )\r
2462{\r
2463 EFI_STATUS Status;\r
2464 UINTN BootOptionCount;\r
2465 EFI_BOOT_MANAGER_LOAD_OPTION *BootOptions;\r
2466 UINTN Index;\r
d1102dba 2467\r
067ed98a
RN
2468 BootOptions = EfiBootManagerGetLoadOptions (&BootOptionCount, LoadOptionTypeBoot);\r
2469\r
2470 for (Index = 0; Index < BootOptionCount; Index++) {\r
7c69fbf2 2471 if (BmIsBootManagerMenuFilePath (BootOptions[Index].FilePath)) {\r
067ed98a
RN
2472 Status = EfiBootManagerInitializeLoadOption (\r
2473 BootOption,\r
2474 BootOptions[Index].OptionNumber,\r
2475 BootOptions[Index].OptionType,\r
2476 BootOptions[Index].Attributes,\r
2477 BootOptions[Index].Description,\r
2478 BootOptions[Index].FilePath,\r
2479 BootOptions[Index].OptionalData,\r
2480 BootOptions[Index].OptionalDataSize\r
2481 );\r
2482 ASSERT_EFI_ERROR (Status);\r
2483 break;\r
067ed98a
RN
2484 }\r
2485 }\r
2486\r
2487 EfiBootManagerFreeLoadOptions (BootOptions, BootOptionCount);\r
2488\r
2489 //\r
2490 // Automatically create the Boot#### for Boot Manager Menu when not found.\r
2491 //\r
2492 if (Index == BootOptionCount) {\r
2493 return BmRegisterBootManagerMenu (BootOption);\r
2494 } else {\r
2495 return EFI_SUCCESS;\r
2496 }\r
2497}\r
2498\r
b4e1ad87
CC
2499/**\r
2500 Get the next possible full path pointing to the load option.\r
2501 The routine doesn't guarantee the returned full path points to an existing\r
2502 file, and it also doesn't guarantee the existing file is a valid load option.\r
2503 BmGetNextLoadOptionBuffer() guarantees.\r
2504\r
2505 @param FilePath The device path pointing to a load option.\r
2506 It could be a short-form device path.\r
2507 @param FullPath The full path returned by the routine in last call.\r
2508 Set to NULL in first call.\r
2509\r
2510 @return The next possible full path pointing to the load option.\r
2511 Caller is responsible to free the memory.\r
2512**/\r
2513EFI_DEVICE_PATH_PROTOCOL *\r
68a4e15e
CC
2514EFIAPI\r
2515EfiBootManagerGetNextLoadOptionDevicePath (\r
b4e1ad87
CC
2516 IN EFI_DEVICE_PATH_PROTOCOL *FilePath,\r
2517 IN EFI_DEVICE_PATH_PROTOCOL *FullPath\r
2518 )\r
2519{\r
2520 return BmGetNextLoadOptionDevicePath(FilePath, FullPath);\r
2521}\r