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