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