]> git.proxmox.com Git - mirror_edk2.git/blob - MdeModulePkg/Library/UefiBootManagerLib/BmBoot.c
MdeModulePkg/UefiBootManager: Unload image on EFI_SECURITY_VIOLATION
[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 // With EFI_SECURITY_VIOLATION retval, the Image was loaded and an ImageHandle was created
1866 // with a valid EFI_LOADED_IMAGE_PROTOCOL, but the image can not be started right now.
1867 // If the caller doesn't have the option to defer the execution of an image, we should
1868 // unload image for the EFI_SECURITY_VIOLATION to avoid resource leak.
1869 //
1870 if (Status == EFI_SECURITY_VIOLATION) {
1871 gBS->UnloadImage (ImageHandle);
1872 }
1873 //
1874 // Report Status Code with the failure status to indicate that the failure to load boot option
1875 //
1876 BmReportLoadFailure (EFI_SW_DXE_BS_EC_BOOT_OPTION_LOAD_ERROR, Status);
1877 BootOption->Status = Status;
1878 //
1879 // Destroy the RAM disk
1880 //
1881 if (RamDiskDevicePath != NULL) {
1882 BmDestroyRamDisk (RamDiskDevicePath);
1883 FreePool (RamDiskDevicePath);
1884 }
1885 return;
1886 }
1887 }
1888
1889 //
1890 // Check to see if we should legacy BOOT. If yes then do the legacy boot
1891 // Write boot to OS performance data for Legacy boot
1892 //
1893 if ((DevicePathType (BootOption->FilePath) == BBS_DEVICE_PATH) && (DevicePathSubType (BootOption->FilePath) == BBS_BBS_DP)) {
1894 if (mBmLegacyBoot != NULL) {
1895 //
1896 // Write boot to OS performance data for legacy boot.
1897 //
1898 PERF_CODE (
1899 //
1900 // Create an event to be signalled when Legacy Boot occurs to write performance data.
1901 //
1902 Status = EfiCreateEventLegacyBootEx(
1903 TPL_NOTIFY,
1904 BmEndOfBdsPerfCode,
1905 NULL,
1906 &LegacyBootEvent
1907 );
1908 ASSERT_EFI_ERROR (Status);
1909 );
1910
1911 mBmLegacyBoot (BootOption);
1912 } else {
1913 BootOption->Status = EFI_UNSUPPORTED;
1914 }
1915
1916 PERF_END_EX (gImageHandle, "BdsAttempt", NULL, 0, (UINT32) OptionNumber);
1917 return;
1918 }
1919
1920 //
1921 // Provide the image with its load options
1922 //
1923 Status = gBS->HandleProtocol (ImageHandle, &gEfiLoadedImageProtocolGuid, (VOID **) &ImageInfo);
1924 ASSERT_EFI_ERROR (Status);
1925
1926 if (!BmIsAutoCreateBootOption (BootOption)) {
1927 ImageInfo->LoadOptionsSize = BootOption->OptionalDataSize;
1928 ImageInfo->LoadOptions = BootOption->OptionalData;
1929 }
1930
1931 //
1932 // Clean to NULL because the image is loaded directly from the firmwares boot manager.
1933 //
1934 ImageInfo->ParentHandle = NULL;
1935
1936 //
1937 // Before calling the image, enable the Watchdog Timer for 5 minutes period
1938 //
1939 gBS->SetWatchdogTimer (5 * 60, 0x0000, 0x00, NULL);
1940
1941 //
1942 // Write boot to OS performance data for UEFI boot
1943 //
1944 PERF_CODE (
1945 BmEndOfBdsPerfCode (NULL, NULL);
1946 );
1947
1948 REPORT_STATUS_CODE (EFI_PROGRESS_CODE, PcdGet32 (PcdProgressCodeOsLoaderStart));
1949
1950 Status = gBS->StartImage (ImageHandle, &BootOption->ExitDataSize, &BootOption->ExitData);
1951 DEBUG ((DEBUG_INFO | DEBUG_LOAD, "Image Return Status = %r\n", Status));
1952 BootOption->Status = Status;
1953 if (EFI_ERROR (Status)) {
1954 //
1955 // Report Status Code with the failure status to indicate that boot failure
1956 //
1957 BmReportLoadFailure (EFI_SW_DXE_BS_EC_BOOT_OPTION_FAILED, Status);
1958 }
1959 PERF_END_EX (gImageHandle, "BdsAttempt", NULL, 0, (UINT32) OptionNumber);
1960
1961 //
1962 // Destroy the RAM disk
1963 //
1964 if (RamDiskDevicePath != NULL) {
1965 BmDestroyRamDisk (RamDiskDevicePath);
1966 FreePool (RamDiskDevicePath);
1967 }
1968
1969 //
1970 // Clear the Watchdog Timer after the image returns
1971 //
1972 gBS->SetWatchdogTimer (0x0000, 0x0000, 0x0000, NULL);
1973
1974 //
1975 // Set Logo status invalid after trying one boot option
1976 //
1977 BootLogo = NULL;
1978 Status = gBS->LocateProtocol (&gEfiBootLogoProtocolGuid, NULL, (VOID **) &BootLogo);
1979 if (!EFI_ERROR (Status) && (BootLogo != NULL)) {
1980 Status = BootLogo->SetBootLogo (BootLogo, NULL, 0, 0, 0, 0);
1981 ASSERT_EFI_ERROR (Status);
1982 }
1983
1984 //
1985 // Clear Boot Current
1986 //
1987 Status = gRT->SetVariable (
1988 L"BootCurrent",
1989 &gEfiGlobalVariableGuid,
1990 0,
1991 0,
1992 NULL
1993 );
1994 //
1995 // Deleting variable with current variable implementation shouldn't fail.
1996 // When BootXXXX (e.g.: BootManagerMenu) boots BootYYYY, exiting BootYYYY causes BootCurrent deleted,
1997 // exiting BootXXXX causes deleting BootCurrent returns EFI_NOT_FOUND.
1998 //
1999 ASSERT (Status == EFI_SUCCESS || Status == EFI_NOT_FOUND);
2000 }
2001
2002 /**
2003 Check whether there is a instance in BlockIoDevicePath, which contain multi device path
2004 instances, has the same partition node with HardDriveDevicePath device path
2005
2006 @param BlockIoDevicePath Multi device path instances which need to check
2007 @param HardDriveDevicePath A device path which starts with a hard drive media
2008 device path.
2009
2010 @retval TRUE There is a matched device path instance.
2011 @retval FALSE There is no matched device path instance.
2012
2013 **/
2014 BOOLEAN
2015 BmMatchPartitionDevicePathNode (
2016 IN EFI_DEVICE_PATH_PROTOCOL *BlockIoDevicePath,
2017 IN HARDDRIVE_DEVICE_PATH *HardDriveDevicePath
2018 )
2019 {
2020 HARDDRIVE_DEVICE_PATH *Node;
2021
2022 if ((BlockIoDevicePath == NULL) || (HardDriveDevicePath == NULL)) {
2023 return FALSE;
2024 }
2025
2026 //
2027 // Match all the partition device path nodes including the nested partition nodes
2028 //
2029 while (!IsDevicePathEnd (BlockIoDevicePath)) {
2030 if ((DevicePathType (BlockIoDevicePath) == MEDIA_DEVICE_PATH) &&
2031 (DevicePathSubType (BlockIoDevicePath) == MEDIA_HARDDRIVE_DP)
2032 ) {
2033 //
2034 // See if the harddrive device path in blockio matches the orig Hard Drive Node
2035 //
2036 Node = (HARDDRIVE_DEVICE_PATH *) BlockIoDevicePath;
2037
2038 //
2039 // Match Signature and PartitionNumber.
2040 // Unused bytes in Signature are initiaized with zeros.
2041 //
2042 if ((Node->PartitionNumber == HardDriveDevicePath->PartitionNumber) &&
2043 (Node->MBRType == HardDriveDevicePath->MBRType) &&
2044 (Node->SignatureType == HardDriveDevicePath->SignatureType) &&
2045 (CompareMem (Node->Signature, HardDriveDevicePath->Signature, sizeof (Node->Signature)) == 0)) {
2046 return TRUE;
2047 }
2048 }
2049
2050 BlockIoDevicePath = NextDevicePathNode (BlockIoDevicePath);
2051 }
2052
2053 return FALSE;
2054 }
2055
2056 /**
2057 Emuerate all possible bootable medias in the following order:
2058 1. Removable BlockIo - The boot option only points to the removable media
2059 device, like USB key, DVD, Floppy etc.
2060 2. Fixed BlockIo - The boot option only points to a Fixed blockIo device,
2061 like HardDisk.
2062 3. Non-BlockIo SimpleFileSystem - The boot option points to a device supporting
2063 SimpleFileSystem Protocol, but not supporting BlockIo
2064 protocol.
2065 4. LoadFile - The boot option points to the media supporting
2066 LoadFile protocol.
2067 Reference: UEFI Spec chapter 3.3 Boot Option Variables Default Boot Behavior
2068
2069 @param BootOptionCount Return the boot option count which has been found.
2070
2071 @retval Pointer to the boot option array.
2072 **/
2073 EFI_BOOT_MANAGER_LOAD_OPTION *
2074 BmEnumerateBootOptions (
2075 UINTN *BootOptionCount
2076 )
2077 {
2078 EFI_STATUS Status;
2079 EFI_BOOT_MANAGER_LOAD_OPTION *BootOptions;
2080 UINTN HandleCount;
2081 EFI_HANDLE *Handles;
2082 EFI_BLOCK_IO_PROTOCOL *BlkIo;
2083 UINTN Removable;
2084 UINTN Index;
2085 CHAR16 *Description;
2086
2087 ASSERT (BootOptionCount != NULL);
2088
2089 *BootOptionCount = 0;
2090 BootOptions = NULL;
2091
2092 //
2093 // Parse removable block io followed by fixed block io
2094 //
2095 gBS->LocateHandleBuffer (
2096 ByProtocol,
2097 &gEfiBlockIoProtocolGuid,
2098 NULL,
2099 &HandleCount,
2100 &Handles
2101 );
2102
2103 for (Removable = 0; Removable < 2; Removable++) {
2104 for (Index = 0; Index < HandleCount; Index++) {
2105 Status = gBS->HandleProtocol (
2106 Handles[Index],
2107 &gEfiBlockIoProtocolGuid,
2108 (VOID **) &BlkIo
2109 );
2110 if (EFI_ERROR (Status)) {
2111 continue;
2112 }
2113
2114 //
2115 // Skip the logical partitions
2116 //
2117 if (BlkIo->Media->LogicalPartition) {
2118 continue;
2119 }
2120
2121 //
2122 // Skip the fixed block io then the removable block io
2123 //
2124 if (BlkIo->Media->RemovableMedia == ((Removable == 0) ? FALSE : TRUE)) {
2125 continue;
2126 }
2127
2128 Description = BmGetBootDescription (Handles[Index]);
2129 BootOptions = ReallocatePool (
2130 sizeof (EFI_BOOT_MANAGER_LOAD_OPTION) * (*BootOptionCount),
2131 sizeof (EFI_BOOT_MANAGER_LOAD_OPTION) * (*BootOptionCount + 1),
2132 BootOptions
2133 );
2134 ASSERT (BootOptions != NULL);
2135
2136 Status = EfiBootManagerInitializeLoadOption (
2137 &BootOptions[(*BootOptionCount)++],
2138 LoadOptionNumberUnassigned,
2139 LoadOptionTypeBoot,
2140 LOAD_OPTION_ACTIVE,
2141 Description,
2142 DevicePathFromHandle (Handles[Index]),
2143 NULL,
2144 0
2145 );
2146 ASSERT_EFI_ERROR (Status);
2147
2148 FreePool (Description);
2149 }
2150 }
2151
2152 if (HandleCount != 0) {
2153 FreePool (Handles);
2154 }
2155
2156 //
2157 // Parse simple file system not based on block io
2158 //
2159 gBS->LocateHandleBuffer (
2160 ByProtocol,
2161 &gEfiSimpleFileSystemProtocolGuid,
2162 NULL,
2163 &HandleCount,
2164 &Handles
2165 );
2166 for (Index = 0; Index < HandleCount; Index++) {
2167 Status = gBS->HandleProtocol (
2168 Handles[Index],
2169 &gEfiBlockIoProtocolGuid,
2170 (VOID **) &BlkIo
2171 );
2172 if (!EFI_ERROR (Status)) {
2173 //
2174 // Skip if the file system handle supports a BlkIo protocol, which we've handled in above
2175 //
2176 continue;
2177 }
2178 Description = BmGetBootDescription (Handles[Index]);
2179 BootOptions = ReallocatePool (
2180 sizeof (EFI_BOOT_MANAGER_LOAD_OPTION) * (*BootOptionCount),
2181 sizeof (EFI_BOOT_MANAGER_LOAD_OPTION) * (*BootOptionCount + 1),
2182 BootOptions
2183 );
2184 ASSERT (BootOptions != NULL);
2185
2186 Status = EfiBootManagerInitializeLoadOption (
2187 &BootOptions[(*BootOptionCount)++],
2188 LoadOptionNumberUnassigned,
2189 LoadOptionTypeBoot,
2190 LOAD_OPTION_ACTIVE,
2191 Description,
2192 DevicePathFromHandle (Handles[Index]),
2193 NULL,
2194 0
2195 );
2196 ASSERT_EFI_ERROR (Status);
2197 FreePool (Description);
2198 }
2199
2200 if (HandleCount != 0) {
2201 FreePool (Handles);
2202 }
2203
2204 //
2205 // Parse load file protocol
2206 //
2207 gBS->LocateHandleBuffer (
2208 ByProtocol,
2209 &gEfiLoadFileProtocolGuid,
2210 NULL,
2211 &HandleCount,
2212 &Handles
2213 );
2214 for (Index = 0; Index < HandleCount; Index++) {
2215 //
2216 // Ignore BootManagerMenu. its boot option will be created by EfiBootManagerGetBootManagerMenu().
2217 //
2218 if (BmIsBootManagerMenuFilePath (DevicePathFromHandle (Handles[Index]))) {
2219 continue;
2220 }
2221
2222 Description = BmGetBootDescription (Handles[Index]);
2223 BootOptions = ReallocatePool (
2224 sizeof (EFI_BOOT_MANAGER_LOAD_OPTION) * (*BootOptionCount),
2225 sizeof (EFI_BOOT_MANAGER_LOAD_OPTION) * (*BootOptionCount + 1),
2226 BootOptions
2227 );
2228 ASSERT (BootOptions != NULL);
2229
2230 Status = EfiBootManagerInitializeLoadOption (
2231 &BootOptions[(*BootOptionCount)++],
2232 LoadOptionNumberUnassigned,
2233 LoadOptionTypeBoot,
2234 LOAD_OPTION_ACTIVE,
2235 Description,
2236 DevicePathFromHandle (Handles[Index]),
2237 NULL,
2238 0
2239 );
2240 ASSERT_EFI_ERROR (Status);
2241 FreePool (Description);
2242 }
2243
2244 if (HandleCount != 0) {
2245 FreePool (Handles);
2246 }
2247
2248 BmMakeBootOptionDescriptionUnique (BootOptions, *BootOptionCount);
2249 return BootOptions;
2250 }
2251
2252 /**
2253 The function enumerates all boot options, creates them and registers them in the BootOrder variable.
2254 **/
2255 VOID
2256 EFIAPI
2257 EfiBootManagerRefreshAllBootOption (
2258 VOID
2259 )
2260 {
2261 EFI_STATUS Status;
2262 EFI_BOOT_MANAGER_LOAD_OPTION *NvBootOptions;
2263 UINTN NvBootOptionCount;
2264 EFI_BOOT_MANAGER_LOAD_OPTION *BootOptions;
2265 UINTN BootOptionCount;
2266 UINTN Index;
2267
2268 //
2269 // Optionally refresh the legacy boot option
2270 //
2271 if (mBmRefreshLegacyBootOption != NULL) {
2272 mBmRefreshLegacyBootOption ();
2273 }
2274
2275 BootOptions = BmEnumerateBootOptions (&BootOptionCount);
2276 NvBootOptions = EfiBootManagerGetLoadOptions (&NvBootOptionCount, LoadOptionTypeBoot);
2277
2278 //
2279 // Mark the boot option as added by BDS by setting OptionalData to a special GUID
2280 //
2281 for (Index = 0; Index < BootOptionCount; Index++) {
2282 BootOptions[Index].OptionalData = AllocateCopyPool (sizeof (EFI_GUID), &mBmAutoCreateBootOptionGuid);
2283 BootOptions[Index].OptionalDataSize = sizeof (EFI_GUID);
2284 }
2285
2286 //
2287 // Remove invalid EFI boot options from NV
2288 //
2289 for (Index = 0; Index < NvBootOptionCount; Index++) {
2290 if (((DevicePathType (NvBootOptions[Index].FilePath) != BBS_DEVICE_PATH) ||
2291 (DevicePathSubType (NvBootOptions[Index].FilePath) != BBS_BBS_DP)
2292 ) && BmIsAutoCreateBootOption (&NvBootOptions[Index])
2293 ) {
2294 //
2295 // Only check those added by BDS
2296 // so that the boot options added by end-user or OS installer won't be deleted
2297 //
2298 if (EfiBootManagerFindLoadOption (&NvBootOptions[Index], BootOptions, BootOptionCount) == -1) {
2299 Status = EfiBootManagerDeleteLoadOptionVariable (NvBootOptions[Index].OptionNumber, LoadOptionTypeBoot);
2300 //
2301 // Deleting variable with current variable implementation shouldn't fail.
2302 //
2303 ASSERT_EFI_ERROR (Status);
2304 }
2305 }
2306 }
2307
2308 //
2309 // Add new EFI boot options to NV
2310 //
2311 for (Index = 0; Index < BootOptionCount; Index++) {
2312 if (EfiBootManagerFindLoadOption (&BootOptions[Index], NvBootOptions, NvBootOptionCount) == -1) {
2313 EfiBootManagerAddLoadOptionVariable (&BootOptions[Index], (UINTN) -1);
2314 //
2315 // Try best to add the boot options so continue upon failure.
2316 //
2317 }
2318 }
2319
2320 EfiBootManagerFreeLoadOptions (BootOptions, BootOptionCount);
2321 EfiBootManagerFreeLoadOptions (NvBootOptions, NvBootOptionCount);
2322 }
2323
2324 /**
2325 This function is called to get or create the boot option for the Boot Manager Menu.
2326
2327 The Boot Manager Menu is shown after successfully booting a boot option.
2328 Assume the BootManagerMenuFile is in the same FV as the module links to this library.
2329
2330 @param BootOption Return the boot option of the Boot Manager Menu
2331
2332 @retval EFI_SUCCESS Successfully register the Boot Manager Menu.
2333 @retval EFI_NOT_FOUND The Boot Manager Menu cannot be found.
2334 @retval others Return status of gRT->SetVariable (). BootOption still points
2335 to the Boot Manager Menu even the Status is not EFI_SUCCESS
2336 and EFI_NOT_FOUND.
2337 **/
2338 EFI_STATUS
2339 BmRegisterBootManagerMenu (
2340 OUT EFI_BOOT_MANAGER_LOAD_OPTION *BootOption
2341 )
2342 {
2343 EFI_STATUS Status;
2344 CHAR16 *Description;
2345 UINTN DescriptionLength;
2346 EFI_DEVICE_PATH_PROTOCOL *DevicePath;
2347 EFI_LOADED_IMAGE_PROTOCOL *LoadedImage;
2348 MEDIA_FW_VOL_FILEPATH_DEVICE_PATH FileNode;
2349 UINTN HandleCount;
2350 EFI_HANDLE *Handles;
2351 UINTN Index;
2352 VOID *Data;
2353 UINTN DataSize;
2354
2355 DevicePath = NULL;
2356 Description = NULL;
2357 //
2358 // Try to find BootManagerMenu from LoadFile protocol
2359 //
2360 gBS->LocateHandleBuffer (
2361 ByProtocol,
2362 &gEfiLoadFileProtocolGuid,
2363 NULL,
2364 &HandleCount,
2365 &Handles
2366 );
2367 for (Index = 0; Index < HandleCount; Index++) {
2368 if (BmIsBootManagerMenuFilePath (DevicePathFromHandle (Handles[Index]))) {
2369 DevicePath = DuplicateDevicePath (DevicePathFromHandle (Handles[Index]));
2370 Description = BmGetBootDescription (Handles[Index]);
2371 break;
2372 }
2373 }
2374 if (HandleCount != 0) {
2375 FreePool (Handles);
2376 }
2377
2378 if (DevicePath == NULL) {
2379 Data = NULL;
2380 Status = GetSectionFromFv (
2381 PcdGetPtr (PcdBootManagerMenuFile),
2382 EFI_SECTION_PE32,
2383 0,
2384 (VOID **) &Data,
2385 &DataSize
2386 );
2387 if (Data != NULL) {
2388 FreePool (Data);
2389 }
2390 if (EFI_ERROR (Status)) {
2391 DEBUG ((EFI_D_WARN, "[Bds]BootManagerMenu FFS section can not be found, skip its boot option registration\n"));
2392 return EFI_NOT_FOUND;
2393 }
2394
2395 //
2396 // Get BootManagerMenu application's description from EFI User Interface Section.
2397 //
2398 Status = GetSectionFromFv (
2399 PcdGetPtr (PcdBootManagerMenuFile),
2400 EFI_SECTION_USER_INTERFACE,
2401 0,
2402 (VOID **) &Description,
2403 &DescriptionLength
2404 );
2405 if (EFI_ERROR (Status)) {
2406 Description = NULL;
2407 }
2408
2409 EfiInitializeFwVolDevicepathNode (&FileNode, PcdGetPtr (PcdBootManagerMenuFile));
2410 Status = gBS->HandleProtocol (
2411 gImageHandle,
2412 &gEfiLoadedImageProtocolGuid,
2413 (VOID **) &LoadedImage
2414 );
2415 ASSERT_EFI_ERROR (Status);
2416 DevicePath = AppendDevicePathNode (
2417 DevicePathFromHandle (LoadedImage->DeviceHandle),
2418 (EFI_DEVICE_PATH_PROTOCOL *) &FileNode
2419 );
2420 ASSERT (DevicePath != NULL);
2421 }
2422
2423 Status = EfiBootManagerInitializeLoadOption (
2424 BootOption,
2425 LoadOptionNumberUnassigned,
2426 LoadOptionTypeBoot,
2427 LOAD_OPTION_CATEGORY_APP | LOAD_OPTION_ACTIVE | LOAD_OPTION_HIDDEN,
2428 (Description != NULL) ? Description : L"Boot Manager Menu",
2429 DevicePath,
2430 NULL,
2431 0
2432 );
2433 ASSERT_EFI_ERROR (Status);
2434 FreePool (DevicePath);
2435 if (Description != NULL) {
2436 FreePool (Description);
2437 }
2438
2439 DEBUG_CODE (
2440 EFI_BOOT_MANAGER_LOAD_OPTION *BootOptions;
2441 UINTN BootOptionCount;
2442
2443 BootOptions = EfiBootManagerGetLoadOptions (&BootOptionCount, LoadOptionTypeBoot);
2444 ASSERT (EfiBootManagerFindLoadOption (BootOption, BootOptions, BootOptionCount) == -1);
2445 EfiBootManagerFreeLoadOptions (BootOptions, BootOptionCount);
2446 );
2447
2448 return EfiBootManagerAddLoadOptionVariable (BootOption, 0);
2449 }
2450
2451 /**
2452 Return the boot option corresponding to the Boot Manager Menu.
2453 It may automatically create one if the boot option hasn't been created yet.
2454
2455 @param BootOption Return the Boot Manager Menu.
2456
2457 @retval EFI_SUCCESS The Boot Manager Menu is successfully returned.
2458 @retval EFI_NOT_FOUND The Boot Manager Menu cannot be found.
2459 @retval others Return status of gRT->SetVariable (). BootOption still points
2460 to the Boot Manager Menu even the Status is not EFI_SUCCESS
2461 and EFI_NOT_FOUND.
2462 **/
2463 EFI_STATUS
2464 EFIAPI
2465 EfiBootManagerGetBootManagerMenu (
2466 EFI_BOOT_MANAGER_LOAD_OPTION *BootOption
2467 )
2468 {
2469 EFI_STATUS Status;
2470 UINTN BootOptionCount;
2471 EFI_BOOT_MANAGER_LOAD_OPTION *BootOptions;
2472 UINTN Index;
2473
2474 BootOptions = EfiBootManagerGetLoadOptions (&BootOptionCount, LoadOptionTypeBoot);
2475
2476 for (Index = 0; Index < BootOptionCount; Index++) {
2477 if (BmIsBootManagerMenuFilePath (BootOptions[Index].FilePath)) {
2478 Status = EfiBootManagerInitializeLoadOption (
2479 BootOption,
2480 BootOptions[Index].OptionNumber,
2481 BootOptions[Index].OptionType,
2482 BootOptions[Index].Attributes,
2483 BootOptions[Index].Description,
2484 BootOptions[Index].FilePath,
2485 BootOptions[Index].OptionalData,
2486 BootOptions[Index].OptionalDataSize
2487 );
2488 ASSERT_EFI_ERROR (Status);
2489 break;
2490 }
2491 }
2492
2493 EfiBootManagerFreeLoadOptions (BootOptions, BootOptionCount);
2494
2495 //
2496 // Automatically create the Boot#### for Boot Manager Menu when not found.
2497 //
2498 if (Index == BootOptionCount) {
2499 return BmRegisterBootManagerMenu (BootOption);
2500 } else {
2501 return EFI_SUCCESS;
2502 }
2503 }
2504
2505 /**
2506 Get the next possible full path pointing to the load option.
2507 The routine doesn't guarantee the returned full path points to an existing
2508 file, and it also doesn't guarantee the existing file is a valid load option.
2509 BmGetNextLoadOptionBuffer() guarantees.
2510
2511 @param FilePath The device path pointing to a load option.
2512 It could be a short-form device path.
2513 @param FullPath The full path returned by the routine in last call.
2514 Set to NULL in first call.
2515
2516 @return The next possible full path pointing to the load option.
2517 Caller is responsible to free the memory.
2518 **/
2519 EFI_DEVICE_PATH_PROTOCOL *
2520 EFIAPI
2521 EfiBootManagerGetNextLoadOptionDevicePath (
2522 IN EFI_DEVICE_PATH_PROTOCOL *FilePath,
2523 IN EFI_DEVICE_PATH_PROTOCOL *FullPath
2524 )
2525 {
2526 return BmGetNextLoadOptionDevicePath(FilePath, FullPath);
2527 }