VirtualBox

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

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

EFI/Firmware/UefiBootManagerLib: Restore old behavior until the blessed file support is working properly

  • Property svn:eol-style set to native
File size: 81.4 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
1010 *ppwszFileName = EFI_REMOVABLE_MEDIA_FILE_NAME;
1011
1012 Status = gBS->HandleProtocol(hSFs, &gEfiSimpleFileSystemProtocolGuid, (void **)&pSFs);
1013 if (!EFI_ERROR(Status))
1014 {
1015 Status = pSFs->OpenVolume(pSFs, &pRoot);
1016 if (!EFI_ERROR(Status))
1017 {
1018#if 1
1019# define VBOX_EFI_APPLE_MEDIA_FILE_NAME L"\\System\\Library\\CoreServices\\boot.efi"
1020 EFI_FILE_PROTOCOL *pFile = NULL;
1021
1022 Status = pRoot->Open(pRoot, &pFile, VBOX_EFI_APPLE_MEDIA_FILE_NAME, EFI_FILE_MODE_READ,
1023 EFI_FILE_READ_ONLY | EFI_FILE_HIDDEN | EFI_FILE_SYSTEM);
1024 if (!EFI_ERROR(Status))
1025 {
1026 *ppwszFileName = VBOX_EFI_APPLE_MEDIA_FILE_NAME;
1027 pFile->Close(pFile);
1028 }
1029#else /* Doesn't quite work yet. */
1030 VBOX_FS_BLESSED_FILE *Buffer = NULL;
1031 UINTN BufferSize = 0;
1032
1033 Status = pRoot->GetInfo(pRoot, &gVBoxFsBlessedFileInfoGuid, &BufferSize, Buffer);
1034 if (Status == EFI_BUFFER_TOO_SMALL) {
1035 Buffer = AllocatePool (BufferSize);
1036 ASSERT (Buffer != NULL);
1037
1038 /** @todo We might leak this allocation but it doesn't really matter as it
1039 * is of type BootServicesData and will be reclaimed by the OS when it boots.
1040 */
1041 Status = pRoot->GetInfo(pRoot, &gVBoxFsBlessedFileInfoGuid, &BufferSize, Buffer);
1042 if (!EFI_ERROR(Status))
1043 {
1044 DEBUG ((EFI_D_INFO, "[Bds] VBoxBmQueryMediaFileNameForSFs: Got blessed file info %s\n", &Buffer->BlessedFile[0]));
1045 *ppwszFileName = &Buffer->BlessedFile[0];
1046 }
1047 }
1048#endif
1049
1050 pRoot->Close(pRoot);
1051 }
1052 }
1053
1054 return EFI_SUCCESS;
1055}
1056#endif
1057
1058/**
1059 Expand the media device path which points to a BlockIo or SimpleFileSystem instance
1060 by appending EFI_REMOVABLE_MEDIA_FILE_NAME.
1061
1062 @param DevicePath The media device path pointing to a BlockIo or SimpleFileSystem instance.
1063 @param FullPath The full path returned by the routine in last call.
1064 Set to NULL in first call.
1065
1066 @return The next possible full path pointing to the load option.
1067 Caller is responsible to free the memory.
1068**/
1069EFI_DEVICE_PATH_PROTOCOL *
1070BmExpandMediaDevicePath (
1071 IN EFI_DEVICE_PATH_PROTOCOL *DevicePath,
1072 IN EFI_DEVICE_PATH_PROTOCOL *FullPath
1073 )
1074{
1075 EFI_STATUS Status;
1076 EFI_HANDLE Handle;
1077 EFI_BLOCK_IO_PROTOCOL *BlockIo;
1078 VOID *Buffer;
1079 EFI_DEVICE_PATH_PROTOCOL *TempDevicePath;
1080 EFI_DEVICE_PATH_PROTOCOL *NextFullPath;
1081 UINTN Size;
1082 UINTN TempSize;
1083 EFI_HANDLE *SimpleFileSystemHandles;
1084 UINTN NumberSimpleFileSystemHandles;
1085 UINTN Index;
1086 BOOLEAN GetNext;
1087#ifdef VBOX
1088 CHAR16 *pwszFilename = NULL;
1089#endif
1090
1091 GetNext = (BOOLEAN)(FullPath == NULL);
1092
1093 //
1094 // Check whether the device is connected
1095 //
1096 TempDevicePath = DevicePath;
1097 Status = gBS->LocateDevicePath (&gEfiSimpleFileSystemProtocolGuid, &TempDevicePath, &Handle);
1098 if (!EFI_ERROR (Status)) {
1099 ASSERT (IsDevicePathEnd (TempDevicePath));
1100
1101#ifndef VBOX
1102 NextFullPath = FileDevicePath (Handle, EFI_REMOVABLE_MEDIA_FILE_NAME);
1103#else
1104 Status = VBoxBmQueryMediaFileNameForSFs(Handle, &pwszFilename);
1105 if (!EFI_ERROR(Status))
1106 NextFullPath = FileDevicePath (Handle, pwszFilename);
1107 else
1108 return NULL;
1109#endif
1110 //
1111 // For device path pointing to simple file system, it only expands to one full path.
1112 //
1113 if (GetNext) {
1114 return NextFullPath;
1115 } else {
1116 FreePool (NextFullPath);
1117 return NULL;
1118 }
1119 }
1120
1121 Status = gBS->LocateDevicePath (&gEfiBlockIoProtocolGuid, &TempDevicePath, &Handle);
1122 ASSERT_EFI_ERROR (Status);
1123
1124 //
1125 // For device boot option only pointing to the removable device handle,
1126 // should make sure all its children handles (its child partion or media handles)
1127 // are created and connected.
1128 //
1129 gBS->ConnectController (Handle, NULL, NULL, TRUE);
1130
1131 //
1132 // Issue a dummy read to the device to check for media change.
1133 // When the removable media is changed, any Block IO read/write will
1134 // cause the BlockIo protocol be reinstalled and EFI_MEDIA_CHANGED is
1135 // returned. After the Block IO protocol is reinstalled, subsequent
1136 // Block IO read/write will success.
1137 //
1138 Status = gBS->HandleProtocol (Handle, &gEfiBlockIoProtocolGuid, (VOID **) &BlockIo);
1139 ASSERT_EFI_ERROR (Status);
1140 if (EFI_ERROR (Status)) {
1141 return NULL;
1142 }
1143 Buffer = AllocatePool (BlockIo->Media->BlockSize);
1144 if (Buffer != NULL) {
1145 BlockIo->ReadBlocks (
1146 BlockIo,
1147 BlockIo->Media->MediaId,
1148 0,
1149 BlockIo->Media->BlockSize,
1150 Buffer
1151 );
1152 FreePool (Buffer);
1153 }
1154
1155 //
1156 // Detect the the default boot file from removable Media
1157 //
1158 NextFullPath = NULL;
1159 Size = GetDevicePathSize (DevicePath) - END_DEVICE_PATH_LENGTH;
1160 gBS->LocateHandleBuffer (
1161 ByProtocol,
1162 &gEfiSimpleFileSystemProtocolGuid,
1163 NULL,
1164 &NumberSimpleFileSystemHandles,
1165 &SimpleFileSystemHandles
1166 );
1167 for (Index = 0; Index < NumberSimpleFileSystemHandles; Index++) {
1168 //
1169 // Get the device path size of SimpleFileSystem handle
1170 //
1171 TempDevicePath = DevicePathFromHandle (SimpleFileSystemHandles[Index]);
1172 TempSize = GetDevicePathSize (TempDevicePath) - END_DEVICE_PATH_LENGTH;
1173 //
1174 // Check whether the device path of boot option is part of the SimpleFileSystem handle's device path
1175 //
1176 if ((Size <= TempSize) && (CompareMem (TempDevicePath, DevicePath, Size) == 0)) {
1177#ifndef VBOX
1178 NextFullPath = FileDevicePath (SimpleFileSystemHandles[Index], EFI_REMOVABLE_MEDIA_FILE_NAME);
1179#else
1180 Status = VBoxBmQueryMediaFileNameForSFs(SimpleFileSystemHandles[Index], &pwszFilename);
1181 if (!EFI_ERROR(Status))
1182 NextFullPath = FileDevicePath (SimpleFileSystemHandles[Index], pwszFilename);
1183 else
1184 return NULL;
1185#endif
1186 if (GetNext) {
1187 break;
1188 } else {
1189 GetNext = (BOOLEAN)(CompareMem (NextFullPath, FullPath, GetDevicePathSize (NextFullPath)) == 0);
1190 FreePool (NextFullPath);
1191 NextFullPath = NULL;
1192 }
1193 }
1194 }
1195
1196 if (SimpleFileSystemHandles != NULL) {
1197 FreePool (SimpleFileSystemHandles);
1198 }
1199
1200 return NextFullPath;
1201}
1202
1203/**
1204 Check whether Left and Right are the same without matching the specific
1205 device path data in IP device path and URI device path node.
1206
1207 @retval TRUE Left and Right are the same.
1208 @retval FALSE Left and Right are the different.
1209**/
1210BOOLEAN
1211BmMatchHttpBootDevicePath (
1212 IN EFI_DEVICE_PATH_PROTOCOL *Left,
1213 IN EFI_DEVICE_PATH_PROTOCOL *Right
1214 )
1215{
1216 for (; !IsDevicePathEnd (Left) && !IsDevicePathEnd (Right)
1217 ; Left = NextDevicePathNode (Left), Right = NextDevicePathNode (Right)
1218 ) {
1219 if (CompareMem (Left, Right, DevicePathNodeLength (Left)) != 0) {
1220 if ((DevicePathType (Left) != MESSAGING_DEVICE_PATH) || (DevicePathType (Right) != MESSAGING_DEVICE_PATH)) {
1221 return FALSE;
1222 }
1223
1224 if (DevicePathSubType (Left) == MSG_DNS_DP) {
1225 Left = NextDevicePathNode (Left);
1226 }
1227
1228 if (DevicePathSubType (Right) == MSG_DNS_DP) {
1229 Right = NextDevicePathNode (Right);
1230 }
1231
1232 if (((DevicePathSubType (Left) != MSG_IPv4_DP) || (DevicePathSubType (Right) != MSG_IPv4_DP)) &&
1233 ((DevicePathSubType (Left) != MSG_IPv6_DP) || (DevicePathSubType (Right) != MSG_IPv6_DP)) &&
1234 ((DevicePathSubType (Left) != MSG_URI_DP) || (DevicePathSubType (Right) != MSG_URI_DP))
1235 ) {
1236 return FALSE;
1237 }
1238 }
1239 }
1240 return (BOOLEAN) (IsDevicePathEnd (Left) && IsDevicePathEnd (Right));
1241}
1242
1243/**
1244 Get the file buffer from the file system produced by Load File instance.
1245
1246 @param LoadFileHandle The handle of LoadFile instance.
1247 @param RamDiskHandle Return the RAM Disk handle.
1248
1249 @return The next possible full path pointing to the load option.
1250 Caller is responsible to free the memory.
1251**/
1252EFI_DEVICE_PATH_PROTOCOL *
1253BmExpandNetworkFileSystem (
1254 IN EFI_HANDLE LoadFileHandle,
1255 OUT EFI_HANDLE *RamDiskHandle
1256 )
1257{
1258 EFI_STATUS Status;
1259 EFI_HANDLE Handle;
1260 EFI_HANDLE *Handles;
1261 UINTN HandleCount;
1262 UINTN Index;
1263 EFI_DEVICE_PATH_PROTOCOL *Node;
1264
1265 Status = gBS->LocateHandleBuffer (
1266 ByProtocol,
1267 &gEfiBlockIoProtocolGuid,
1268 NULL,
1269 &HandleCount,
1270 &Handles
1271 );
1272 if (EFI_ERROR (Status)) {
1273 Handles = NULL;
1274 HandleCount = 0;
1275 }
1276
1277 Handle = NULL;
1278 for (Index = 0; Index < HandleCount; Index++) {
1279 Node = DevicePathFromHandle (Handles[Index]);
1280 Status = gBS->LocateDevicePath (&gEfiLoadFileProtocolGuid, &Node, &Handle);
1281 if (!EFI_ERROR (Status) &&
1282 (Handle == LoadFileHandle) &&
1283 (DevicePathType (Node) == MEDIA_DEVICE_PATH) && (DevicePathSubType (Node) == MEDIA_RAM_DISK_DP)) {
1284 //
1285 // Find the BlockIo instance populated from the LoadFile.
1286 //
1287 Handle = Handles[Index];
1288 break;
1289 }
1290 }
1291
1292 if (Handles != NULL) {
1293 FreePool (Handles);
1294 }
1295
1296 if (Index == HandleCount) {
1297 Handle = NULL;
1298 }
1299
1300 *RamDiskHandle = Handle;
1301
1302 if (Handle != NULL) {
1303 //
1304 // Re-use BmExpandMediaDevicePath() to get the full device path of load option.
1305 // But assume only one SimpleFileSystem can be found under the BlockIo.
1306 //
1307 return BmExpandMediaDevicePath (DevicePathFromHandle (Handle), NULL);
1308 } else {
1309 return NULL;
1310 }
1311}
1312
1313/**
1314 Return the RAM Disk device path created by LoadFile.
1315
1316 @param FilePath The source file path.
1317
1318 @return Callee-to-free RAM Disk device path
1319**/
1320EFI_DEVICE_PATH_PROTOCOL *
1321BmGetRamDiskDevicePath (
1322 IN EFI_DEVICE_PATH_PROTOCOL *FilePath
1323 )
1324{
1325 EFI_STATUS Status;
1326 EFI_DEVICE_PATH_PROTOCOL *RamDiskDevicePath;
1327 EFI_DEVICE_PATH_PROTOCOL *Node;
1328 EFI_HANDLE Handle;
1329
1330 Node = FilePath;
1331 Status = gBS->LocateDevicePath (&gEfiLoadFileProtocolGuid, &Node, &Handle);
1332 if (!EFI_ERROR (Status) &&
1333 (DevicePathType (Node) == MEDIA_DEVICE_PATH) &&
1334 (DevicePathSubType (Node) == MEDIA_RAM_DISK_DP)
1335 ) {
1336
1337 //
1338 // Construct the device path pointing to RAM Disk
1339 //
1340 Node = NextDevicePathNode (Node);
1341 RamDiskDevicePath = DuplicateDevicePath (FilePath);
1342 ASSERT (RamDiskDevicePath != NULL);
1343 SetDevicePathEndNode ((VOID *) ((UINTN) RamDiskDevicePath + ((UINTN) Node - (UINTN) FilePath)));
1344 return RamDiskDevicePath;
1345 }
1346
1347 return NULL;
1348}
1349
1350/**
1351 Return the buffer and buffer size occupied by the RAM Disk.
1352
1353 @param RamDiskDevicePath RAM Disk device path.
1354 @param RamDiskSizeInPages Return RAM Disk size in pages.
1355
1356 @retval RAM Disk buffer.
1357**/
1358VOID *
1359BmGetRamDiskMemoryInfo (
1360 IN EFI_DEVICE_PATH_PROTOCOL *RamDiskDevicePath,
1361 OUT UINTN *RamDiskSizeInPages
1362 )
1363{
1364
1365 EFI_STATUS Status;
1366 EFI_HANDLE Handle;
1367 UINT64 StartingAddr;
1368 UINT64 EndingAddr;
1369
1370 ASSERT (RamDiskDevicePath != NULL);
1371
1372 *RamDiskSizeInPages = 0;
1373
1374 //
1375 // Get the buffer occupied by RAM Disk.
1376 //
1377 Status = gBS->LocateDevicePath (&gEfiLoadFileProtocolGuid, &RamDiskDevicePath, &Handle);
1378 ASSERT_EFI_ERROR (Status);
1379 ASSERT ((DevicePathType (RamDiskDevicePath) == MEDIA_DEVICE_PATH) &&
1380 (DevicePathSubType (RamDiskDevicePath) == MEDIA_RAM_DISK_DP));
1381 StartingAddr = ReadUnaligned64 ((UINT64 *) ((MEDIA_RAM_DISK_DEVICE_PATH *) RamDiskDevicePath)->StartingAddr);
1382 EndingAddr = ReadUnaligned64 ((UINT64 *) ((MEDIA_RAM_DISK_DEVICE_PATH *) RamDiskDevicePath)->EndingAddr);
1383 *RamDiskSizeInPages = EFI_SIZE_TO_PAGES ((UINTN) (EndingAddr - StartingAddr + 1));
1384 return (VOID *) (UINTN) StartingAddr;
1385}
1386
1387/**
1388 Destroy the RAM Disk.
1389
1390 The destroy operation includes to call RamDisk.Unregister to
1391 unregister the RAM DISK from RAM DISK driver, free the memory
1392 allocated for the RAM Disk.
1393
1394 @param RamDiskDevicePath RAM Disk device path.
1395**/
1396VOID
1397BmDestroyRamDisk (
1398 IN EFI_DEVICE_PATH_PROTOCOL *RamDiskDevicePath
1399 )
1400{
1401 EFI_STATUS Status;
1402 VOID *RamDiskBuffer;
1403 UINTN RamDiskSizeInPages;
1404
1405 ASSERT (RamDiskDevicePath != NULL);
1406
1407 RamDiskBuffer = BmGetRamDiskMemoryInfo (RamDiskDevicePath, &RamDiskSizeInPages);
1408
1409 //
1410 // Destroy RAM Disk.
1411 //
1412 if (mRamDisk == NULL) {
1413 Status = gBS->LocateProtocol (&gEfiRamDiskProtocolGuid, NULL, (VOID *) &mRamDisk);
1414 ASSERT_EFI_ERROR (Status);
1415 }
1416 Status = mRamDisk->Unregister (RamDiskDevicePath);
1417 ASSERT_EFI_ERROR (Status);
1418 FreePages (RamDiskBuffer, RamDiskSizeInPages);
1419}
1420
1421/**
1422 Get the file buffer from the specified Load File instance.
1423
1424 @param LoadFileHandle The specified Load File instance.
1425 @param FilePath The file path which will pass to LoadFile().
1426
1427 @return The full device path pointing to the load option buffer.
1428**/
1429EFI_DEVICE_PATH_PROTOCOL *
1430BmExpandLoadFile (
1431 IN EFI_HANDLE LoadFileHandle,
1432 IN EFI_DEVICE_PATH_PROTOCOL *FilePath
1433 )
1434{
1435 EFI_STATUS Status;
1436 EFI_LOAD_FILE_PROTOCOL *LoadFile;
1437 VOID *FileBuffer;
1438 EFI_HANDLE RamDiskHandle;
1439 UINTN BufferSize;
1440 EFI_DEVICE_PATH_PROTOCOL *FullPath;
1441
1442 Status = gBS->OpenProtocol (
1443 LoadFileHandle,
1444 &gEfiLoadFileProtocolGuid,
1445 (VOID **) &LoadFile,
1446 gImageHandle,
1447 NULL,
1448 EFI_OPEN_PROTOCOL_GET_PROTOCOL
1449 );
1450 ASSERT_EFI_ERROR (Status);
1451
1452 FileBuffer = NULL;
1453 BufferSize = 0;
1454 Status = LoadFile->LoadFile (LoadFile, FilePath, TRUE, &BufferSize, FileBuffer);
1455 if ((Status != EFI_WARN_FILE_SYSTEM) && (Status != EFI_BUFFER_TOO_SMALL)) {
1456 return NULL;
1457 }
1458
1459 if (Status == EFI_BUFFER_TOO_SMALL) {
1460 //
1461 // The load option buffer is directly returned by LoadFile.
1462 //
1463 return DuplicateDevicePath (DevicePathFromHandle (LoadFileHandle));
1464 }
1465
1466 //
1467 // The load option resides in a RAM disk.
1468 //
1469 FileBuffer = AllocateReservedPages (EFI_SIZE_TO_PAGES (BufferSize));
1470 if (FileBuffer == NULL) {
1471 return NULL;
1472 }
1473
1474 Status = LoadFile->LoadFile (LoadFile, FilePath, TRUE, &BufferSize, FileBuffer);
1475 if (EFI_ERROR (Status)) {
1476 FreePages (FileBuffer, EFI_SIZE_TO_PAGES (BufferSize));
1477 return NULL;
1478 }
1479
1480 FullPath = BmExpandNetworkFileSystem (LoadFileHandle, &RamDiskHandle);
1481 if (FullPath == NULL) {
1482 //
1483 // Free the memory occupied by the RAM disk if there is no BlockIo or SimpleFileSystem instance.
1484 //
1485 BmDestroyRamDisk (DevicePathFromHandle (RamDiskHandle));
1486 }
1487
1488 return FullPath;
1489}
1490
1491/**
1492 Return the full device path pointing to the load option.
1493
1494 FilePath may:
1495 1. Exactly matches to a LoadFile instance.
1496 2. Cannot match to any LoadFile instance. Wide match is required.
1497 In either case, the routine may return:
1498 1. A copy of FilePath when FilePath matches to a LoadFile instance and
1499 the LoadFile returns a load option buffer.
1500 2. A new device path with IP and URI information updated when wide match
1501 happens.
1502 3. A new device path pointing to a load option in RAM disk.
1503 In either case, only one full device path is returned for a specified
1504 FilePath.
1505
1506 @param FilePath The media device path pointing to a LoadFile instance.
1507
1508 @return The load option buffer.
1509**/
1510EFI_DEVICE_PATH_PROTOCOL *
1511BmExpandLoadFiles (
1512 IN EFI_DEVICE_PATH_PROTOCOL *FilePath
1513 )
1514{
1515 EFI_STATUS Status;
1516 EFI_HANDLE Handle;
1517 EFI_HANDLE *Handles;
1518 UINTN HandleCount;
1519 UINTN Index;
1520 EFI_DEVICE_PATH_PROTOCOL *Node;
1521
1522 //
1523 // Get file buffer from load file instance.
1524 //
1525 Node = FilePath;
1526 Status = gBS->LocateDevicePath (&gEfiLoadFileProtocolGuid, &Node, &Handle);
1527 if (!EFI_ERROR (Status) && IsDevicePathEnd (Node)) {
1528 //
1529 // When wide match happens, pass full device path to LoadFile (),
1530 // otherwise, pass remaining device path to LoadFile ().
1531 //
1532 FilePath = Node;
1533 } else {
1534 Handle = NULL;
1535 //
1536 // Use wide match algorithm to find one when
1537 // cannot find a LoadFile instance to exactly match the FilePath
1538 //
1539 Status = gBS->LocateHandleBuffer (
1540 ByProtocol,
1541 &gEfiLoadFileProtocolGuid,
1542 NULL,
1543 &HandleCount,
1544 &Handles
1545 );
1546 if (EFI_ERROR (Status)) {
1547 Handles = NULL;
1548 HandleCount = 0;
1549 }
1550 for (Index = 0; Index < HandleCount; Index++) {
1551 if (BmMatchHttpBootDevicePath (DevicePathFromHandle (Handles[Index]), FilePath)) {
1552 Handle = Handles[Index];
1553 break;
1554 }
1555 }
1556 if (Handles != NULL) {
1557 FreePool (Handles);
1558 }
1559 }
1560
1561 if (Handle == NULL) {
1562 return NULL;
1563 }
1564
1565 return BmExpandLoadFile (Handle, FilePath);
1566}
1567
1568/**
1569 Get the load option by its device path.
1570
1571 @param FilePath The device path pointing to a load option.
1572 It could be a short-form device path.
1573 @param FullPath Return the full device path of the load option after
1574 short-form device path expanding.
1575 Caller is responsible to free it.
1576 @param FileSize Return the load option size.
1577
1578 @return The load option buffer. Caller is responsible to free the memory.
1579**/
1580VOID *
1581EFIAPI
1582EfiBootManagerGetLoadOptionBuffer (
1583 IN EFI_DEVICE_PATH_PROTOCOL *FilePath,
1584 OUT EFI_DEVICE_PATH_PROTOCOL **FullPath,
1585 OUT UINTN *FileSize
1586 )
1587{
1588 *FullPath = NULL;
1589
1590 EfiBootManagerConnectDevicePath (FilePath, NULL);
1591 return BmGetNextLoadOptionBuffer (LoadOptionTypeMax, FilePath, FullPath, FileSize);
1592}
1593
1594/**
1595 Get the next possible full path pointing to the load option.
1596 The routine doesn't guarantee the returned full path points to an existing
1597 file, and it also doesn't guarantee the existing file is a valid load option.
1598 BmGetNextLoadOptionBuffer() guarantees.
1599
1600 @param FilePath The device path pointing to a load option.
1601 It could be a short-form device path.
1602 @param FullPath The full path returned by the routine in last call.
1603 Set to NULL in first call.
1604
1605 @return The next possible full path pointing to the load option.
1606 Caller is responsible to free the memory.
1607**/
1608EFI_DEVICE_PATH_PROTOCOL *
1609BmGetNextLoadOptionDevicePath (
1610 IN EFI_DEVICE_PATH_PROTOCOL *FilePath,
1611 IN EFI_DEVICE_PATH_PROTOCOL *FullPath
1612 )
1613{
1614 EFI_HANDLE Handle;
1615 EFI_DEVICE_PATH_PROTOCOL *Node;
1616 EFI_STATUS Status;
1617
1618 ASSERT (FilePath != NULL);
1619
1620 //
1621 // Boot from media device by adding a default file name \EFI\BOOT\BOOT{machine type short-name}.EFI
1622 //
1623 Node = FilePath;
1624 Status = gBS->LocateDevicePath (&gEfiSimpleFileSystemProtocolGuid, &Node, &Handle);
1625 if (EFI_ERROR (Status)) {
1626 Status = gBS->LocateDevicePath (&gEfiBlockIoProtocolGuid, &Node, &Handle);
1627 }
1628
1629 if (!EFI_ERROR (Status) && IsDevicePathEnd (Node)) {
1630 return BmExpandMediaDevicePath (FilePath, FullPath);
1631 }
1632
1633 //
1634 // Expand the short-form device path to full device path
1635 //
1636 if ((DevicePathType (FilePath) == MEDIA_DEVICE_PATH) &&
1637 (DevicePathSubType (FilePath) == MEDIA_HARDDRIVE_DP)) {
1638 //
1639 // Expand the Harddrive device path
1640 //
1641 if (FullPath == NULL) {
1642 return BmExpandPartitionDevicePath (FilePath);
1643 } else {
1644 return NULL;
1645 }
1646 } else if ((DevicePathType (FilePath) == MEDIA_DEVICE_PATH) &&
1647 (DevicePathSubType (FilePath) == MEDIA_FILEPATH_DP)) {
1648 //
1649 // Expand the File-path device path
1650 //
1651 return BmExpandFileDevicePath (FilePath, FullPath);
1652 } else if ((DevicePathType (FilePath) == MESSAGING_DEVICE_PATH) &&
1653 (DevicePathSubType (FilePath) == MSG_URI_DP)) {
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 break;
1671 }
1672 }
1673
1674 //
1675 // Expand the USB WWID/Class device path
1676 //
1677 if (!IsDevicePathEnd (Node)) {
1678 if (FilePath == Node) {
1679 //
1680 // Boot Option device path starts with USB Class or USB WWID device path.
1681 // For Boot Option device path which doesn't begin with the USB Class or
1682 // USB WWID device path, it's not needed to connect again here.
1683 //
1684 BmConnectUsbShortFormDevicePath (FilePath);
1685 }
1686 return BmExpandUsbDevicePath (FilePath, FullPath, Node);
1687 }
1688 }
1689 }
1690
1691 //
1692 // For the below cases, FilePath only expands to one Full path.
1693 // So just handle the case when FullPath == NULL.
1694 //
1695 if (FullPath != NULL) {
1696 return NULL;
1697 }
1698
1699 //
1700 // Load option resides in FV.
1701 //
1702 if (BmIsFvFilePath (FilePath)) {
1703 return BmAdjustFvFilePath (FilePath);
1704 }
1705
1706 //
1707 // Load option resides in Simple File System.
1708 //
1709 Node = FilePath;
1710 Status = gBS->LocateDevicePath (&gEfiSimpleFileSystemProtocolGuid, &Node, &Handle);
1711 if (!EFI_ERROR (Status)) {
1712 return DuplicateDevicePath (FilePath);
1713 }
1714
1715 //
1716 // Last chance to try: Load option may be loaded through LoadFile.
1717 //
1718 return BmExpandLoadFiles (FilePath);
1719}
1720
1721/**
1722 Check if it's a Device Path pointing to BootManagerMenu.
1723
1724 @param DevicePath Input device path.
1725
1726 @retval TRUE The device path is BootManagerMenu File Device Path.
1727 @retval FALSE The device path is NOT BootManagerMenu File Device Path.
1728**/
1729BOOLEAN
1730BmIsBootManagerMenuFilePath (
1731 EFI_DEVICE_PATH_PROTOCOL *DevicePath
1732)
1733{
1734 EFI_HANDLE FvHandle;
1735 VOID *NameGuid;
1736 EFI_STATUS Status;
1737
1738 Status = gBS->LocateDevicePath (&gEfiFirmwareVolume2ProtocolGuid, &DevicePath, &FvHandle);
1739 if (!EFI_ERROR (Status)) {
1740 NameGuid = EfiGetNameGuidFromFwVolDevicePathNode ((CONST MEDIA_FW_VOL_FILEPATH_DEVICE_PATH *) DevicePath);
1741 if (NameGuid != NULL) {
1742 return CompareGuid (NameGuid, PcdGetPtr (PcdBootManagerMenuFile));
1743 }
1744 }
1745
1746 return FALSE;
1747}
1748
1749/**
1750 Report status code with EFI_RETURN_STATUS_EXTENDED_DATA about LoadImage() or
1751 StartImage() failure.
1752
1753 @param[in] ErrorCode An Error Code in the Software Class, DXE Boot
1754 Service Driver Subclass. ErrorCode will be used to
1755 compose the Value parameter for status code
1756 reporting. Must be one of
1757 EFI_SW_DXE_BS_EC_BOOT_OPTION_LOAD_ERROR and
1758 EFI_SW_DXE_BS_EC_BOOT_OPTION_FAILED.
1759
1760 @param[in] FailureStatus The failure status returned by the boot service
1761 that should be reported.
1762**/
1763VOID
1764BmReportLoadFailure (
1765 IN UINT32 ErrorCode,
1766 IN EFI_STATUS FailureStatus
1767 )
1768{
1769 EFI_RETURN_STATUS_EXTENDED_DATA ExtendedData;
1770
1771 if (!ReportErrorCodeEnabled ()) {
1772 return;
1773 }
1774
1775 ASSERT (
1776 (ErrorCode == EFI_SW_DXE_BS_EC_BOOT_OPTION_LOAD_ERROR) ||
1777 (ErrorCode == EFI_SW_DXE_BS_EC_BOOT_OPTION_FAILED)
1778 );
1779
1780 ZeroMem (&ExtendedData, sizeof (ExtendedData));
1781 ExtendedData.ReturnStatus = FailureStatus;
1782
1783 REPORT_STATUS_CODE_EX (
1784 (EFI_ERROR_CODE | EFI_ERROR_MINOR),
1785 (EFI_SOFTWARE_DXE_BS_DRIVER | ErrorCode),
1786 0,
1787 NULL,
1788 NULL,
1789 &ExtendedData.DataHeader + 1,
1790 sizeof (ExtendedData) - sizeof (ExtendedData.DataHeader)
1791 );
1792}
1793
1794/**
1795 Attempt to boot the EFI boot option. This routine sets L"BootCurent" and
1796 also signals the EFI ready to boot event. If the device path for the option
1797 starts with a BBS device path a legacy boot is attempted via the registered
1798 gLegacyBoot function. Short form device paths are also supported via this
1799 rountine. A device path starting with MEDIA_HARDDRIVE_DP, MSG_USB_WWID_DP,
1800 MSG_USB_CLASS_DP gets expaned out to find the first device that matches.
1801 If the BootOption Device Path fails the removable media boot algorithm
1802 is attempted (\EFI\BOOTIA32.EFI, \EFI\BOOTX64.EFI,... only one file type
1803 is tried per processor type)
1804
1805 @param BootOption Boot Option to try and boot.
1806 On return, BootOption->Status contains the boot status.
1807 EFI_SUCCESS BootOption was booted
1808 EFI_UNSUPPORTED A BBS device path was found with no valid callback
1809 registered via EfiBootManagerInitialize().
1810 EFI_NOT_FOUND The BootOption was not found on the system
1811 !EFI_SUCCESS BootOption failed with this error status
1812
1813**/
1814VOID
1815EFIAPI
1816EfiBootManagerBoot (
1817 IN EFI_BOOT_MANAGER_LOAD_OPTION *BootOption
1818 )
1819{
1820 EFI_STATUS Status;
1821 EFI_HANDLE ImageHandle;
1822 EFI_LOADED_IMAGE_PROTOCOL *ImageInfo;
1823 UINT16 Uint16;
1824 UINTN OptionNumber;
1825 UINTN OriginalOptionNumber;
1826 EFI_DEVICE_PATH_PROTOCOL *FilePath;
1827 EFI_DEVICE_PATH_PROTOCOL *RamDiskDevicePath;
1828 VOID *FileBuffer;
1829 UINTN FileSize;
1830 EFI_BOOT_LOGO_PROTOCOL *BootLogo;
1831 EFI_EVENT LegacyBootEvent;
1832
1833 if (BootOption == NULL) {
1834 return;
1835 }
1836
1837 if (BootOption->FilePath == NULL || BootOption->OptionType != LoadOptionTypeBoot) {
1838 BootOption->Status = EFI_INVALID_PARAMETER;
1839 return;
1840 }
1841
1842 //
1843 // 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")
1844 //
1845 OptionNumber = BmFindBootOptionInVariable (BootOption);
1846 if (OptionNumber == LoadOptionNumberUnassigned) {
1847 Status = BmGetFreeOptionNumber (LoadOptionTypeBoot, &Uint16);
1848 if (!EFI_ERROR (Status)) {
1849 //
1850 // Save the BootOption->OptionNumber to restore later
1851 //
1852 OptionNumber = Uint16;
1853 OriginalOptionNumber = BootOption->OptionNumber;
1854 BootOption->OptionNumber = OptionNumber;
1855 Status = EfiBootManagerLoadOptionToVariable (BootOption);
1856 BootOption->OptionNumber = OriginalOptionNumber;
1857 }
1858
1859 if (EFI_ERROR (Status)) {
1860 DEBUG ((EFI_D_ERROR, "[Bds] Failed to create Boot#### for a temporary boot - %r!\n", Status));
1861 BootOption->Status = Status;
1862 return ;
1863 }
1864 }
1865
1866 //
1867 // 2. Set BootCurrent
1868 //
1869 Uint16 = (UINT16) OptionNumber;
1870 BmSetVariableAndReportStatusCodeOnError (
1871 L"BootCurrent",
1872 &gEfiGlobalVariableGuid,
1873 EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS,
1874 sizeof (UINT16),
1875 &Uint16
1876 );
1877
1878 //
1879 // 3. Signal the EVT_SIGNAL_READY_TO_BOOT event when we are about to load and execute
1880 // the boot option.
1881 //
1882 if (BmIsBootManagerMenuFilePath (BootOption->FilePath)) {
1883 DEBUG ((EFI_D_INFO, "[Bds] Booting Boot Manager Menu.\n"));
1884 BmStopHotkeyService (NULL, NULL);
1885 } else {
1886 EfiSignalEventReadyToBoot();
1887 //
1888 // Report Status Code to indicate ReadyToBoot was signalled
1889 //
1890 REPORT_STATUS_CODE (EFI_PROGRESS_CODE, (EFI_SOFTWARE_DXE_BS_DRIVER | EFI_SW_DXE_BS_PC_READY_TO_BOOT_EVENT));
1891 //
1892 // 4. Repair system through DriverHealth protocol
1893 //
1894 BmRepairAllControllers (0);
1895 }
1896
1897 PERF_START_EX (gImageHandle, "BdsAttempt", NULL, 0, (UINT32) OptionNumber);
1898
1899 //
1900 // 5. Adjust the different type memory page number just before booting
1901 // and save the updated info into the variable for next boot to use
1902 //
1903 BmSetMemoryTypeInformationVariable (
1904 (BOOLEAN) ((BootOption->Attributes & LOAD_OPTION_CATEGORY) == LOAD_OPTION_CATEGORY_BOOT)
1905 );
1906
1907 //
1908 // 6. Load EFI boot option to ImageHandle
1909 //
1910 DEBUG_CODE_BEGIN ();
1911 if (BootOption->Description == NULL) {
1912 DEBUG ((DEBUG_INFO | DEBUG_LOAD, "[Bds]Booting from unknown device path\n"));
1913 } else {
1914 DEBUG ((DEBUG_INFO | DEBUG_LOAD, "[Bds]Booting %s\n", BootOption->Description));
1915 }
1916 DEBUG_CODE_END ();
1917
1918 ImageHandle = NULL;
1919 RamDiskDevicePath = NULL;
1920 if (DevicePathType (BootOption->FilePath) != BBS_DEVICE_PATH) {
1921 Status = EFI_NOT_FOUND;
1922 FilePath = NULL;
1923 EfiBootManagerConnectDevicePath (BootOption->FilePath, NULL);
1924 FileBuffer = BmGetNextLoadOptionBuffer (LoadOptionTypeBoot, BootOption->FilePath, &FilePath, &FileSize);
1925 if (FileBuffer != NULL) {
1926 RamDiskDevicePath = BmGetRamDiskDevicePath (FilePath);
1927
1928 REPORT_STATUS_CODE (EFI_PROGRESS_CODE, PcdGet32 (PcdProgressCodeOsLoaderLoad));
1929 Status = gBS->LoadImage (
1930 TRUE,
1931 gImageHandle,
1932 FilePath,
1933 FileBuffer,
1934 FileSize,
1935 &ImageHandle
1936 );
1937 }
1938 if (FileBuffer != NULL) {
1939 FreePool (FileBuffer);
1940 }
1941 if (FilePath != NULL) {
1942 FreePool (FilePath);
1943 }
1944
1945 if (EFI_ERROR (Status)) {
1946 //
1947 // Report Status Code with the failure status to indicate that the failure to load boot option
1948 //
1949 BmReportLoadFailure (EFI_SW_DXE_BS_EC_BOOT_OPTION_LOAD_ERROR, Status);
1950 BootOption->Status = Status;
1951 //
1952 // Destroy the RAM disk
1953 //
1954 if (RamDiskDevicePath != NULL) {
1955 BmDestroyRamDisk (RamDiskDevicePath);
1956 FreePool (RamDiskDevicePath);
1957 }
1958 return;
1959 }
1960 }
1961
1962 //
1963 // Check to see if we should legacy BOOT. If yes then do the legacy boot
1964 // Write boot to OS performance data for Legacy boot
1965 //
1966 if ((DevicePathType (BootOption->FilePath) == BBS_DEVICE_PATH) && (DevicePathSubType (BootOption->FilePath) == BBS_BBS_DP)) {
1967 if (mBmLegacyBoot != NULL) {
1968 //
1969 // Write boot to OS performance data for legacy boot.
1970 //
1971 PERF_CODE (
1972 //
1973 // Create an event to be signalled when Legacy Boot occurs to write performance data.
1974 //
1975 Status = EfiCreateEventLegacyBootEx(
1976 TPL_NOTIFY,
1977 BmEndOfBdsPerfCode,
1978 NULL,
1979 &LegacyBootEvent
1980 );
1981 ASSERT_EFI_ERROR (Status);
1982 );
1983
1984 mBmLegacyBoot (BootOption);
1985 } else {
1986 BootOption->Status = EFI_UNSUPPORTED;
1987 }
1988
1989 PERF_END_EX (gImageHandle, "BdsAttempt", NULL, 0, (UINT32) OptionNumber);
1990 return;
1991 }
1992
1993 //
1994 // Provide the image with its load options
1995 //
1996 Status = gBS->HandleProtocol (ImageHandle, &gEfiLoadedImageProtocolGuid, (VOID **) &ImageInfo);
1997 ASSERT_EFI_ERROR (Status);
1998
1999 if (!BmIsAutoCreateBootOption (BootOption)) {
2000 ImageInfo->LoadOptionsSize = BootOption->OptionalDataSize;
2001 ImageInfo->LoadOptions = BootOption->OptionalData;
2002 }
2003
2004 //
2005 // Clean to NULL because the image is loaded directly from the firmwares boot manager.
2006 //
2007 ImageInfo->ParentHandle = NULL;
2008
2009 //
2010 // Before calling the image, enable the Watchdog Timer for 5 minutes period
2011 //
2012 gBS->SetWatchdogTimer (5 * 60, 0x0000, 0x00, NULL);
2013
2014 //
2015 // Write boot to OS performance data for UEFI boot
2016 //
2017 PERF_CODE (
2018 BmEndOfBdsPerfCode (NULL, NULL);
2019 );
2020
2021 REPORT_STATUS_CODE (EFI_PROGRESS_CODE, PcdGet32 (PcdProgressCodeOsLoaderStart));
2022
2023 Status = gBS->StartImage (ImageHandle, &BootOption->ExitDataSize, &BootOption->ExitData);
2024 DEBUG ((DEBUG_INFO | DEBUG_LOAD, "Image Return Status = %r\n", Status));
2025 BootOption->Status = Status;
2026 if (EFI_ERROR (Status)) {
2027 //
2028 // Report Status Code with the failure status to indicate that boot failure
2029 //
2030 BmReportLoadFailure (EFI_SW_DXE_BS_EC_BOOT_OPTION_FAILED, Status);
2031 }
2032 PERF_END_EX (gImageHandle, "BdsAttempt", NULL, 0, (UINT32) OptionNumber);
2033
2034 //
2035 // Destroy the RAM disk
2036 //
2037 if (RamDiskDevicePath != NULL) {
2038 BmDestroyRamDisk (RamDiskDevicePath);
2039 FreePool (RamDiskDevicePath);
2040 }
2041
2042 //
2043 // Clear the Watchdog Timer after the image returns
2044 //
2045 gBS->SetWatchdogTimer (0x0000, 0x0000, 0x0000, NULL);
2046
2047 //
2048 // Set Logo status invalid after trying one boot option
2049 //
2050 BootLogo = NULL;
2051 Status = gBS->LocateProtocol (&gEfiBootLogoProtocolGuid, NULL, (VOID **) &BootLogo);
2052 if (!EFI_ERROR (Status) && (BootLogo != NULL)) {
2053 Status = BootLogo->SetBootLogo (BootLogo, NULL, 0, 0, 0, 0);
2054 ASSERT_EFI_ERROR (Status);
2055 }
2056
2057 //
2058 // Clear Boot Current
2059 //
2060 Status = gRT->SetVariable (
2061 L"BootCurrent",
2062 &gEfiGlobalVariableGuid,
2063 0,
2064 0,
2065 NULL
2066 );
2067 //
2068 // Deleting variable with current variable implementation shouldn't fail.
2069 // When BootXXXX (e.g.: BootManagerMenu) boots BootYYYY, exiting BootYYYY causes BootCurrent deleted,
2070 // exiting BootXXXX causes deleting BootCurrent returns EFI_NOT_FOUND.
2071 //
2072 ASSERT (Status == EFI_SUCCESS || Status == EFI_NOT_FOUND);
2073}
2074
2075/**
2076 Check whether there is a instance in BlockIoDevicePath, which contain multi device path
2077 instances, has the same partition node with HardDriveDevicePath device path
2078
2079 @param BlockIoDevicePath Multi device path instances which need to check
2080 @param HardDriveDevicePath A device path which starts with a hard drive media
2081 device path.
2082
2083 @retval TRUE There is a matched device path instance.
2084 @retval FALSE There is no matched device path instance.
2085
2086**/
2087BOOLEAN
2088BmMatchPartitionDevicePathNode (
2089 IN EFI_DEVICE_PATH_PROTOCOL *BlockIoDevicePath,
2090 IN HARDDRIVE_DEVICE_PATH *HardDriveDevicePath
2091 )
2092{
2093 HARDDRIVE_DEVICE_PATH *Node;
2094
2095 if ((BlockIoDevicePath == NULL) || (HardDriveDevicePath == NULL)) {
2096 return FALSE;
2097 }
2098
2099 //
2100 // Match all the partition device path nodes including the nested partition nodes
2101 //
2102 while (!IsDevicePathEnd (BlockIoDevicePath)) {
2103 if ((DevicePathType (BlockIoDevicePath) == MEDIA_DEVICE_PATH) &&
2104 (DevicePathSubType (BlockIoDevicePath) == MEDIA_HARDDRIVE_DP)
2105 ) {
2106 //
2107 // See if the harddrive device path in blockio matches the orig Hard Drive Node
2108 //
2109 Node = (HARDDRIVE_DEVICE_PATH *) BlockIoDevicePath;
2110
2111 //
2112 // Match Signature and PartitionNumber.
2113 // Unused bytes in Signature are initiaized with zeros.
2114 //
2115 if ((Node->PartitionNumber == HardDriveDevicePath->PartitionNumber) &&
2116 (Node->MBRType == HardDriveDevicePath->MBRType) &&
2117 (Node->SignatureType == HardDriveDevicePath->SignatureType) &&
2118 (CompareMem (Node->Signature, HardDriveDevicePath->Signature, sizeof (Node->Signature)) == 0)) {
2119 return TRUE;
2120 }
2121 }
2122
2123 BlockIoDevicePath = NextDevicePathNode (BlockIoDevicePath);
2124 }
2125
2126 return FALSE;
2127}
2128
2129/**
2130 Emuerate all possible bootable medias in the following order:
2131 1. Removable BlockIo - The boot option only points to the removable media
2132 device, like USB key, DVD, Floppy etc.
2133 2. Fixed BlockIo - The boot option only points to a Fixed blockIo device,
2134 like HardDisk.
2135 3. Non-BlockIo SimpleFileSystem - The boot option points to a device supporting
2136 SimpleFileSystem Protocol, but not supporting BlockIo
2137 protocol.
2138 4. LoadFile - The boot option points to the media supporting
2139 LoadFile protocol.
2140 Reference: UEFI Spec chapter 3.3 Boot Option Variables Default Boot Behavior
2141
2142 @param BootOptionCount Return the boot option count which has been found.
2143
2144 @retval Pointer to the boot option array.
2145**/
2146EFI_BOOT_MANAGER_LOAD_OPTION *
2147BmEnumerateBootOptions (
2148 UINTN *BootOptionCount
2149 )
2150{
2151 EFI_STATUS Status;
2152 EFI_BOOT_MANAGER_LOAD_OPTION *BootOptions;
2153 UINTN HandleCount;
2154 EFI_HANDLE *Handles;
2155 EFI_BLOCK_IO_PROTOCOL *BlkIo;
2156 UINTN Removable;
2157 UINTN Index;
2158 CHAR16 *Description;
2159
2160 ASSERT (BootOptionCount != NULL);
2161
2162 *BootOptionCount = 0;
2163 BootOptions = NULL;
2164
2165 //
2166 // Parse removable block io followed by fixed block io
2167 //
2168 gBS->LocateHandleBuffer (
2169 ByProtocol,
2170 &gEfiBlockIoProtocolGuid,
2171 NULL,
2172 &HandleCount,
2173 &Handles
2174 );
2175
2176 for (Removable = 0; Removable < 2; Removable++) {
2177 for (Index = 0; Index < HandleCount; Index++) {
2178 Status = gBS->HandleProtocol (
2179 Handles[Index],
2180 &gEfiBlockIoProtocolGuid,
2181 (VOID **) &BlkIo
2182 );
2183 if (EFI_ERROR (Status)) {
2184 continue;
2185 }
2186
2187 //
2188 // Skip the logical partitions
2189 //
2190 if (BlkIo->Media->LogicalPartition) {
2191 continue;
2192 }
2193
2194 //
2195 // Skip the fixed block io then the removable block io
2196 //
2197 if (BlkIo->Media->RemovableMedia == ((Removable == 0) ? FALSE : TRUE)) {
2198 continue;
2199 }
2200
2201 Description = BmGetBootDescription (Handles[Index]);
2202 BootOptions = ReallocatePool (
2203 sizeof (EFI_BOOT_MANAGER_LOAD_OPTION) * (*BootOptionCount),
2204 sizeof (EFI_BOOT_MANAGER_LOAD_OPTION) * (*BootOptionCount + 1),
2205 BootOptions
2206 );
2207 ASSERT (BootOptions != NULL);
2208
2209 Status = EfiBootManagerInitializeLoadOption (
2210 &BootOptions[(*BootOptionCount)++],
2211 LoadOptionNumberUnassigned,
2212 LoadOptionTypeBoot,
2213 LOAD_OPTION_ACTIVE,
2214 Description,
2215 DevicePathFromHandle (Handles[Index]),
2216 NULL,
2217 0
2218 );
2219 ASSERT_EFI_ERROR (Status);
2220
2221 FreePool (Description);
2222 }
2223 }
2224
2225 if (HandleCount != 0) {
2226 FreePool (Handles);
2227 }
2228
2229 //
2230 // Parse simple file system not based on block io
2231 //
2232 gBS->LocateHandleBuffer (
2233 ByProtocol,
2234 &gEfiSimpleFileSystemProtocolGuid,
2235 NULL,
2236 &HandleCount,
2237 &Handles
2238 );
2239 for (Index = 0; Index < HandleCount; Index++) {
2240 Status = gBS->HandleProtocol (
2241 Handles[Index],
2242 &gEfiBlockIoProtocolGuid,
2243 (VOID **) &BlkIo
2244 );
2245 if (!EFI_ERROR (Status)) {
2246 //
2247 // Skip if the file system handle supports a BlkIo protocol, which we've handled in above
2248 //
2249 continue;
2250 }
2251 Description = BmGetBootDescription (Handles[Index]);
2252 BootOptions = ReallocatePool (
2253 sizeof (EFI_BOOT_MANAGER_LOAD_OPTION) * (*BootOptionCount),
2254 sizeof (EFI_BOOT_MANAGER_LOAD_OPTION) * (*BootOptionCount + 1),
2255 BootOptions
2256 );
2257 ASSERT (BootOptions != NULL);
2258
2259 Status = EfiBootManagerInitializeLoadOption (
2260 &BootOptions[(*BootOptionCount)++],
2261 LoadOptionNumberUnassigned,
2262 LoadOptionTypeBoot,
2263 LOAD_OPTION_ACTIVE,
2264 Description,
2265 DevicePathFromHandle (Handles[Index]),
2266 NULL,
2267 0
2268 );
2269 ASSERT_EFI_ERROR (Status);
2270 FreePool (Description);
2271 }
2272
2273 if (HandleCount != 0) {
2274 FreePool (Handles);
2275 }
2276
2277 //
2278 // Parse load file protocol
2279 //
2280 gBS->LocateHandleBuffer (
2281 ByProtocol,
2282 &gEfiLoadFileProtocolGuid,
2283 NULL,
2284 &HandleCount,
2285 &Handles
2286 );
2287 for (Index = 0; Index < HandleCount; Index++) {
2288 //
2289 // Ignore BootManagerMenu. its boot option will be created by EfiBootManagerGetBootManagerMenu().
2290 //
2291 if (BmIsBootManagerMenuFilePath (DevicePathFromHandle (Handles[Index]))) {
2292 continue;
2293 }
2294
2295 Description = BmGetBootDescription (Handles[Index]);
2296 BootOptions = ReallocatePool (
2297 sizeof (EFI_BOOT_MANAGER_LOAD_OPTION) * (*BootOptionCount),
2298 sizeof (EFI_BOOT_MANAGER_LOAD_OPTION) * (*BootOptionCount + 1),
2299 BootOptions
2300 );
2301 ASSERT (BootOptions != NULL);
2302
2303 Status = EfiBootManagerInitializeLoadOption (
2304 &BootOptions[(*BootOptionCount)++],
2305 LoadOptionNumberUnassigned,
2306 LoadOptionTypeBoot,
2307 LOAD_OPTION_ACTIVE,
2308 Description,
2309 DevicePathFromHandle (Handles[Index]),
2310 NULL,
2311 0
2312 );
2313 ASSERT_EFI_ERROR (Status);
2314 FreePool (Description);
2315 }
2316
2317 if (HandleCount != 0) {
2318 FreePool (Handles);
2319 }
2320
2321 BmMakeBootOptionDescriptionUnique (BootOptions, *BootOptionCount);
2322 return BootOptions;
2323}
2324
2325/**
2326 The function enumerates all boot options, creates them and registers them in the BootOrder variable.
2327**/
2328VOID
2329EFIAPI
2330EfiBootManagerRefreshAllBootOption (
2331 VOID
2332 )
2333{
2334 EFI_STATUS Status;
2335 EFI_BOOT_MANAGER_LOAD_OPTION *NvBootOptions;
2336 UINTN NvBootOptionCount;
2337 EFI_BOOT_MANAGER_LOAD_OPTION *BootOptions;
2338 UINTN BootOptionCount;
2339 UINTN Index;
2340
2341 //
2342 // Optionally refresh the legacy boot option
2343 //
2344 if (mBmRefreshLegacyBootOption != NULL) {
2345 mBmRefreshLegacyBootOption ();
2346 }
2347
2348 BootOptions = BmEnumerateBootOptions (&BootOptionCount);
2349 NvBootOptions = EfiBootManagerGetLoadOptions (&NvBootOptionCount, LoadOptionTypeBoot);
2350
2351 //
2352 // Mark the boot option as added by BDS by setting OptionalData to a special GUID
2353 //
2354 for (Index = 0; Index < BootOptionCount; Index++) {
2355 BootOptions[Index].OptionalData = AllocateCopyPool (sizeof (EFI_GUID), &mBmAutoCreateBootOptionGuid);
2356 BootOptions[Index].OptionalDataSize = sizeof (EFI_GUID);
2357 }
2358
2359 //
2360 // Remove invalid EFI boot options from NV
2361 //
2362 for (Index = 0; Index < NvBootOptionCount; Index++) {
2363 if (((DevicePathType (NvBootOptions[Index].FilePath) != BBS_DEVICE_PATH) ||
2364 (DevicePathSubType (NvBootOptions[Index].FilePath) != BBS_BBS_DP)
2365 ) && BmIsAutoCreateBootOption (&NvBootOptions[Index])
2366 ) {
2367 //
2368 // Only check those added by BDS
2369 // so that the boot options added by end-user or OS installer won't be deleted
2370 //
2371 if (EfiBootManagerFindLoadOption (&NvBootOptions[Index], BootOptions, BootOptionCount) == -1) {
2372 Status = EfiBootManagerDeleteLoadOptionVariable (NvBootOptions[Index].OptionNumber, LoadOptionTypeBoot);
2373 //
2374 // Deleting variable with current variable implementation shouldn't fail.
2375 //
2376 ASSERT_EFI_ERROR (Status);
2377 }
2378 }
2379 }
2380
2381 //
2382 // Add new EFI boot options to NV
2383 //
2384 for (Index = 0; Index < BootOptionCount; Index++) {
2385 if (EfiBootManagerFindLoadOption (&BootOptions[Index], NvBootOptions, NvBootOptionCount) == -1) {
2386 EfiBootManagerAddLoadOptionVariable (&BootOptions[Index], (UINTN) -1);
2387 //
2388 // Try best to add the boot options so continue upon failure.
2389 //
2390 }
2391 }
2392
2393 EfiBootManagerFreeLoadOptions (BootOptions, BootOptionCount);
2394 EfiBootManagerFreeLoadOptions (NvBootOptions, NvBootOptionCount);
2395}
2396
2397/**
2398 This function is called to get or create the boot option for the Boot Manager Menu.
2399
2400 The Boot Manager Menu is shown after successfully booting a boot option.
2401 Assume the BootManagerMenuFile is in the same FV as the module links to this library.
2402
2403 @param BootOption Return the boot option of the Boot Manager Menu
2404
2405 @retval EFI_SUCCESS Successfully register the Boot Manager Menu.
2406 @retval EFI_NOT_FOUND The Boot Manager Menu cannot be found.
2407 @retval others Return status of gRT->SetVariable (). BootOption still points
2408 to the Boot Manager Menu even the Status is not EFI_SUCCESS
2409 and EFI_NOT_FOUND.
2410**/
2411EFI_STATUS
2412BmRegisterBootManagerMenu (
2413 OUT EFI_BOOT_MANAGER_LOAD_OPTION *BootOption
2414 )
2415{
2416 EFI_STATUS Status;
2417 CHAR16 *Description;
2418 UINTN DescriptionLength;
2419 EFI_DEVICE_PATH_PROTOCOL *DevicePath;
2420 EFI_LOADED_IMAGE_PROTOCOL *LoadedImage;
2421 MEDIA_FW_VOL_FILEPATH_DEVICE_PATH FileNode;
2422 UINTN HandleCount;
2423 EFI_HANDLE *Handles;
2424 UINTN Index;
2425 VOID *Data;
2426 UINTN DataSize;
2427
2428 DevicePath = NULL;
2429 Description = NULL;
2430 //
2431 // Try to find BootManagerMenu from LoadFile protocol
2432 //
2433 gBS->LocateHandleBuffer (
2434 ByProtocol,
2435 &gEfiLoadFileProtocolGuid,
2436 NULL,
2437 &HandleCount,
2438 &Handles
2439 );
2440 for (Index = 0; Index < HandleCount; Index++) {
2441 if (BmIsBootManagerMenuFilePath (DevicePathFromHandle (Handles[Index]))) {
2442 DevicePath = DuplicateDevicePath (DevicePathFromHandle (Handles[Index]));
2443 Description = BmGetBootDescription (Handles[Index]);
2444 break;
2445 }
2446 }
2447 if (HandleCount != 0) {
2448 FreePool (Handles);
2449 }
2450
2451 if (DevicePath == NULL) {
2452 Data = NULL;
2453 Status = GetSectionFromFv (
2454 PcdGetPtr (PcdBootManagerMenuFile),
2455 EFI_SECTION_PE32,
2456 0,
2457 (VOID **) &Data,
2458 &DataSize
2459 );
2460 if (Data != NULL) {
2461 FreePool (Data);
2462 }
2463 if (EFI_ERROR (Status)) {
2464 DEBUG ((EFI_D_WARN, "[Bds]BootManagerMenu FFS section can not be found, skip its boot option registration\n"));
2465 return EFI_NOT_FOUND;
2466 }
2467
2468 //
2469 // Get BootManagerMenu application's description from EFI User Interface Section.
2470 //
2471 Status = GetSectionFromFv (
2472 PcdGetPtr (PcdBootManagerMenuFile),
2473 EFI_SECTION_USER_INTERFACE,
2474 0,
2475 (VOID **) &Description,
2476 &DescriptionLength
2477 );
2478 if (EFI_ERROR (Status)) {
2479 Description = NULL;
2480 }
2481
2482 EfiInitializeFwVolDevicepathNode (&FileNode, PcdGetPtr (PcdBootManagerMenuFile));
2483 Status = gBS->HandleProtocol (
2484 gImageHandle,
2485 &gEfiLoadedImageProtocolGuid,
2486 (VOID **) &LoadedImage
2487 );
2488 ASSERT_EFI_ERROR (Status);
2489 DevicePath = AppendDevicePathNode (
2490 DevicePathFromHandle (LoadedImage->DeviceHandle),
2491 (EFI_DEVICE_PATH_PROTOCOL *) &FileNode
2492 );
2493 ASSERT (DevicePath != NULL);
2494 }
2495
2496 Status = EfiBootManagerInitializeLoadOption (
2497 BootOption,
2498 LoadOptionNumberUnassigned,
2499 LoadOptionTypeBoot,
2500 LOAD_OPTION_CATEGORY_APP | LOAD_OPTION_ACTIVE | LOAD_OPTION_HIDDEN,
2501 (Description != NULL) ? Description : L"Boot Manager Menu",
2502 DevicePath,
2503 NULL,
2504 0
2505 );
2506 ASSERT_EFI_ERROR (Status);
2507 FreePool (DevicePath);
2508 if (Description != NULL) {
2509 FreePool (Description);
2510 }
2511
2512 DEBUG_CODE (
2513 EFI_BOOT_MANAGER_LOAD_OPTION *BootOptions;
2514 UINTN BootOptionCount;
2515
2516 BootOptions = EfiBootManagerGetLoadOptions (&BootOptionCount, LoadOptionTypeBoot);
2517 ASSERT (EfiBootManagerFindLoadOption (BootOption, BootOptions, BootOptionCount) == -1);
2518 EfiBootManagerFreeLoadOptions (BootOptions, BootOptionCount);
2519 );
2520
2521 return EfiBootManagerAddLoadOptionVariable (BootOption, 0);
2522}
2523
2524/**
2525 Return the boot option corresponding to the Boot Manager Menu.
2526 It may automatically create one if the boot option hasn't been created yet.
2527
2528 @param BootOption Return the Boot Manager Menu.
2529
2530 @retval EFI_SUCCESS The Boot Manager Menu is successfully returned.
2531 @retval EFI_NOT_FOUND The Boot Manager Menu cannot be found.
2532 @retval others Return status of gRT->SetVariable (). BootOption still points
2533 to the Boot Manager Menu even the Status is not EFI_SUCCESS
2534 and EFI_NOT_FOUND.
2535**/
2536EFI_STATUS
2537EFIAPI
2538EfiBootManagerGetBootManagerMenu (
2539 EFI_BOOT_MANAGER_LOAD_OPTION *BootOption
2540 )
2541{
2542 EFI_STATUS Status;
2543 UINTN BootOptionCount;
2544 EFI_BOOT_MANAGER_LOAD_OPTION *BootOptions;
2545 UINTN Index;
2546
2547 BootOptions = EfiBootManagerGetLoadOptions (&BootOptionCount, LoadOptionTypeBoot);
2548
2549 for (Index = 0; Index < BootOptionCount; Index++) {
2550 if (BmIsBootManagerMenuFilePath (BootOptions[Index].FilePath)) {
2551 Status = EfiBootManagerInitializeLoadOption (
2552 BootOption,
2553 BootOptions[Index].OptionNumber,
2554 BootOptions[Index].OptionType,
2555 BootOptions[Index].Attributes,
2556 BootOptions[Index].Description,
2557 BootOptions[Index].FilePath,
2558 BootOptions[Index].OptionalData,
2559 BootOptions[Index].OptionalDataSize
2560 );
2561 ASSERT_EFI_ERROR (Status);
2562 break;
2563 }
2564 }
2565
2566 EfiBootManagerFreeLoadOptions (BootOptions, BootOptionCount);
2567
2568 //
2569 // Automatically create the Boot#### for Boot Manager Menu when not found.
2570 //
2571 if (Index == BootOptionCount) {
2572 return BmRegisterBootManagerMenu (BootOption);
2573 } else {
2574 return EFI_SUCCESS;
2575 }
2576}
2577
2578/**
2579 Get the next possible full path pointing to the load option.
2580 The routine doesn't guarantee the returned full path points to an existing
2581 file, and it also doesn't guarantee the existing file is a valid load option.
2582 BmGetNextLoadOptionBuffer() guarantees.
2583
2584 @param FilePath The device path pointing to a load option.
2585 It could be a short-form device path.
2586 @param FullPath The full path returned by the routine in last call.
2587 Set to NULL in first call.
2588
2589 @return The next possible full path pointing to the load option.
2590 Caller is responsible to free the memory.
2591**/
2592EFI_DEVICE_PATH_PROTOCOL *
2593EFIAPI
2594EfiBootManagerGetNextLoadOptionDevicePath (
2595 IN EFI_DEVICE_PATH_PROTOCOL *FilePath,
2596 IN EFI_DEVICE_PATH_PROTOCOL *FullPath
2597 )
2598{
2599 return BmGetNextLoadOptionDevicePath(FilePath, FullPath);
2600}
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