VirtualBox

source: vbox/trunk/src/VBox/Devices/EFI/FirmwareNew/MdeModulePkg/Library/UefiBootManagerLib/BmBoot.c@ 80901

Last change on this file since 80901 was 80901, checked in by vboxsync, 5 years ago

EFI/FirmwareNew: Restore ability to load the Apple provided OS loader as it is stored in a non standard location

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

© 2024 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette