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