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