2 BDS Lib functions which relate with create or process the boot option.
4 Copyright (c) 2004 - 2008, Intel Corporation. <BR>
5 All rights reserved. This program and the accompanying materials
6 are licensed and made available under the terms and conditions of the BSD License
7 which accompanies this distribution. The full text of the license may be found at
8 http://opensource.org/licenses/bsd-license.php
10 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
11 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
15 #include "InternalBdsLib.h"
17 BOOLEAN mEnumBootDevice
= FALSE
;
20 /// This GUID is used for an EFI Variable that stores the front device pathes
21 /// for a partial device path that starts with the HD node.
23 EFI_GUID mHdBootVariablePrivateGuid
= { 0xfab7e9e1, 0x39dd, 0x4f2b, { 0x84, 0x8, 0xe2, 0xe, 0x90, 0x6c, 0xb6, 0xde } };
28 Boot the legacy system with the boot option
30 @param Option The legacy boot option which have BBS device path
32 @retval EFI_UNSUPPORTED There is no legacybios protocol, do not support
34 @retval EFI_STATUS Return the status of LegacyBios->LegacyBoot ().
39 IN BDS_COMMON_OPTION
*Option
43 EFI_LEGACY_BIOS_PROTOCOL
*LegacyBios
;
45 Status
= gBS
->LocateProtocol (&gEfiLegacyBiosProtocolGuid
, NULL
, (VOID
**) &LegacyBios
);
46 if (EFI_ERROR (Status
)) {
48 // If no LegacyBios protocol we do not support legacy boot
50 return EFI_UNSUPPORTED
;
53 // Notes: if we seperate the int 19, then we don't need to refresh BBS
55 BdsRefreshBbsTableForBoot (Option
);
58 // Write boot to OS performance data to a file
61 WriteBootToOsPerformanceData ();
64 DEBUG ((DEBUG_INFO
| DEBUG_LOAD
, "Legacy Boot: %S\n", Option
->Description
));
65 return LegacyBios
->LegacyBoot (
67 (BBS_BBS_DEVICE_PATH
*) Option
->DevicePath
,
68 Option
->LoadOptionsSize
,
75 Process the boot option follow the EFI 1.1 specification and
76 special treat the legacy boot option with BBS_DEVICE_PATH.
78 @param Option The boot option need to be processed
79 @param DevicePath The device path which describe where to load the
80 boot image or the legcy BBS device path to boot
82 @param ExitDataSize Returned directly from gBS->StartImage ()
83 @param ExitData Returned directly from gBS->StartImage ()
85 @retval EFI_SUCCESS Status from gBS->StartImage ()
86 @retval EFI_NOT_FOUND If the Device Path is not found in the system
91 BdsLibBootViaBootOption (
92 IN BDS_COMMON_OPTION
* Option
,
93 IN EFI_DEVICE_PATH_PROTOCOL
* DevicePath
,
94 OUT UINTN
*ExitDataSize
,
95 OUT CHAR16
**ExitData OPTIONAL
100 EFI_HANDLE ImageHandle
;
101 EFI_DEVICE_PATH_PROTOCOL
*FilePath
;
102 EFI_LOADED_IMAGE_PROTOCOL
*ImageInfo
;
103 EFI_DEVICE_PATH_PROTOCOL
*WorkingDevicePath
;
104 EFI_ACPI_S3_SAVE_PROTOCOL
*AcpiS3Save
;
105 LIST_ENTRY TempBootLists
;
108 // Record the performance data for End of BDS
110 PERF_END (0, BDS_TOK
, NULL
, 0);
116 // Notes: put EFI64 ROM Shadow Solution
118 EFI64_SHADOW_ALL_LEGACY_ROM ();
121 // Notes: this code can be remove after the s3 script table
122 // hook on the event EVT_SIGNAL_READY_TO_BOOT or
123 // EVT_SIGNAL_LEGACY_BOOT
125 Status
= gBS
->LocateProtocol (&gEfiAcpiS3SaveProtocolGuid
, NULL
, (VOID
**) &AcpiS3Save
);
126 if (!EFI_ERROR (Status
)) {
127 AcpiS3Save
->S3Save (AcpiS3Save
, NULL
);
130 // If it's Device Path that starts with a hard drive path, append it with the front part to compose a
133 WorkingDevicePath
= NULL
;
134 if ((DevicePathType (DevicePath
) == MEDIA_DEVICE_PATH
) &&
135 (DevicePathSubType (DevicePath
) == MEDIA_HARDDRIVE_DP
)) {
136 WorkingDevicePath
= BdsExpandPartitionPartialDevicePathToFull (
137 (HARDDRIVE_DEVICE_PATH
*)DevicePath
139 if (WorkingDevicePath
!= NULL
) {
140 DevicePath
= WorkingDevicePath
;
144 // Signal the EVT_SIGNAL_READY_TO_BOOT event
146 EfiSignalEventReadyToBoot();
154 &gEfiGlobalVariableGuid
,
155 EFI_VARIABLE_BOOTSERVICE_ACCESS
| EFI_VARIABLE_RUNTIME_ACCESS
,
160 if ((DevicePathType (Option
->DevicePath
) == BBS_DEVICE_PATH
) &&
161 (DevicePathSubType (Option
->DevicePath
) == BBS_BBS_DP
)
164 // Check to see if we should legacy BOOT. If yes then do the legacy boot
166 return BdsLibDoLegacyBoot (Option
);
170 // If the boot option point to Internal FV shell, make sure it is valid
172 Status
= BdsLibUpdateFvFileDevicePath (&DevicePath
, &gEfiShellFileGuid
);
173 if (!EFI_ERROR(Status
)) {
174 if (Option
->DevicePath
!= NULL
) {
175 FreePool(Option
->DevicePath
);
177 Option
->DevicePath
= AllocateZeroPool (GetDevicePathSize (DevicePath
));
178 CopyMem (Option
->DevicePath
, DevicePath
, GetDevicePathSize (DevicePath
));
180 // Update the shell boot option
182 InitializeListHead (&TempBootLists
);
183 BdsLibRegisterNewOption (&TempBootLists
, DevicePath
, L
"EFI Internal Shell", L
"BootOrder");
186 // free the temporary device path created by BdsLibUpdateFvFileDevicePath()
188 FreePool (DevicePath
);
189 DevicePath
= Option
->DevicePath
;
192 DEBUG ((DEBUG_INFO
| DEBUG_LOAD
, "Booting %S\n", Option
->Description
));
194 Status
= gBS
->LoadImage (
204 // If we didn't find an image directly, we need to try as if it is a removable device boot opotion
205 // and load the image according to the default boot behavior for removable device.
207 if (EFI_ERROR (Status
)) {
209 // check if there is a bootable removable media could be found in this device path ,
210 // and get the bootable media handle
212 Handle
= BdsLibGetBootableHandle(DevicePath
);
213 if (Handle
== NULL
) {
217 // Load the default boot file \EFI\BOOT\boot{machinename}.EFI from removable Media
218 // machinename is ia32, ia64, x64, ...
220 FilePath
= FileDevicePath (Handle
, (CONST CHAR16
*)PcdGetPtr(PcdDefaultBootFileName
));
221 if (FilePath
!= NULL
) {
222 Status
= gBS
->LoadImage (
230 if (EFI_ERROR (Status
)) {
232 // The DevicePath failed, and it's not a valid
233 // removable media device.
240 if (EFI_ERROR (Status
)) {
242 // It there is any error from the Boot attempt exit now.
247 // Provide the image with it's load options
249 Status
= gBS
->HandleProtocol (ImageHandle
, &gEfiLoadedImageProtocolGuid
, (VOID
**) &ImageInfo
);
250 ASSERT_EFI_ERROR (Status
);
252 if (Option
->LoadOptionsSize
!= 0) {
253 ImageInfo
->LoadOptionsSize
= Option
->LoadOptionsSize
;
254 ImageInfo
->LoadOptions
= Option
->LoadOptions
;
257 // Before calling the image, enable the Watchdog Timer for
258 // the 5 Minute period
260 gBS
->SetWatchdogTimer (5 * 60, 0x0000, 0x00, NULL
);
262 Status
= gBS
->StartImage (ImageHandle
, ExitDataSize
, ExitData
);
263 DEBUG ((DEBUG_INFO
| DEBUG_LOAD
, "Image Return Status = %r\n", Status
));
266 // Clear the Watchdog Timer after the image returns
268 gBS
->SetWatchdogTimer (0x0000, 0x0000, 0x0000, NULL
);
272 // Clear Boot Current
276 &gEfiGlobalVariableGuid
,
277 EFI_VARIABLE_BOOTSERVICE_ACCESS
| EFI_VARIABLE_RUNTIME_ACCESS
,
287 Expand a device path that starts with a hard drive media device path node to be a
288 full device path that includes the full hardware path to the device. We need
289 to do this so it can be booted. As an optimizaiton the front match (the part point
290 to the partition node. E.g. ACPI() /PCI()/ATA()/Partition() ) is saved in a variable
291 so a connect all is not required on every boot. All successful history device path
292 which point to partition node (the front part) will be saved.
294 @param HardDriveDevicePath EFI Device Path to boot, if it starts with a hard
295 drive media device path.
296 @return A Pointer to the full device path or NULL if a valid Hard Drive devic path
300 EFI_DEVICE_PATH_PROTOCOL
*
302 BdsExpandPartitionPartialDevicePathToFull (
303 IN HARDDRIVE_DEVICE_PATH
*HardDriveDevicePath
307 UINTN BlockIoHandleCount
;
308 EFI_HANDLE
*BlockIoBuffer
;
309 EFI_DEVICE_PATH_PROTOCOL
*FullDevicePath
;
310 EFI_DEVICE_PATH_PROTOCOL
*BlockIoDevicePath
;
311 EFI_DEVICE_PATH_PROTOCOL
*DevicePath
;
314 EFI_DEVICE_PATH_PROTOCOL
*CachedDevicePath
;
315 EFI_DEVICE_PATH_PROTOCOL
*TempNewDevicePath
;
316 UINTN CachedDevicePathSize
;
319 EFI_DEVICE_PATH_PROTOCOL
*Instance
;
322 FullDevicePath
= NULL
;
324 // Check if there is prestore 'HDDP' variable.
325 // If exist, search the front path which point to partition node in the variable instants.
326 // If fail to find or 'HDDP' not exist, reconnect all and search in all system
328 CachedDevicePath
= BdsLibGetVariableAndSize (
330 &mHdBootVariablePrivateGuid
,
331 &CachedDevicePathSize
334 if (CachedDevicePath
!= NULL
) {
335 TempNewDevicePath
= CachedDevicePath
;
340 // Check every instance of the variable
341 // First, check wheather the instance contain the partition node, which is needed for distinguishing multi
342 // partial partition boot option. Second, check wheather the instance could be connected.
344 Instance
= GetNextDevicePathInstance (&TempNewDevicePath
, &Size
);
345 if (MatchPartitionDevicePathNode (Instance
, HardDriveDevicePath
)) {
347 // Connect the device path instance, the device path point to hard drive media device path node
348 // e.g. ACPI() /PCI()/ATA()/Partition()
350 Status
= BdsLibConnectDevicePath (Instance
);
351 if (!EFI_ERROR (Status
)) {
357 // Come here means the first instance is not matched
361 } while (TempNewDevicePath
!= NULL
);
365 // Find the matched device path.
366 // Append the file path infomration from the boot option and return the fully expanded device path.
368 DevicePath
= NextDevicePathNode ((EFI_DEVICE_PATH_PROTOCOL
*) HardDriveDevicePath
);
369 FullDevicePath
= AppendDevicePath (Instance
, DevicePath
);
372 // Adjust the 'HDDP' instances sequense if the matched one is not first one.
376 // First delete the matched instance.
378 TempNewDevicePath
= CachedDevicePath
;
379 CachedDevicePath
= BdsLibDelPartMatchInstance (CachedDevicePath
, Instance
);
380 FreePool (TempNewDevicePath
);
383 // Second, append the remaining parth after the matched instance
385 TempNewDevicePath
= CachedDevicePath
;
386 CachedDevicePath
= AppendDevicePathInstance (Instance
, CachedDevicePath
);
387 FreePool (TempNewDevicePath
);
389 // Save the matching Device Path so we don't need to do a connect all next time
391 Status
= gRT
->SetVariable (
393 &mHdBootVariablePrivateGuid
,
394 EFI_VARIABLE_BOOTSERVICE_ACCESS
| EFI_VARIABLE_RUNTIME_ACCESS
| EFI_VARIABLE_NON_VOLATILE
,
395 GetDevicePathSize (CachedDevicePath
),
401 FreePool (CachedDevicePath
);
402 return FullDevicePath
;
407 // If we get here we fail to find or 'HDDP' not exist, and now we need
408 // to seach all devices in the system for a matched partition
410 BdsLibConnectAllDriversToAllControllers ();
411 Status
= gBS
->LocateHandleBuffer (ByProtocol
, &gEfiBlockIoProtocolGuid
, NULL
, &BlockIoHandleCount
, &BlockIoBuffer
);
412 if (EFI_ERROR (Status
) || BlockIoHandleCount
== 0) {
414 // If there was an error or there are no device handles that support
415 // the BLOCK_IO Protocol, then return.
420 // Loop through all the device handles that support the BLOCK_IO Protocol
422 for (Index
= 0; Index
< BlockIoHandleCount
; Index
++) {
424 Status
= gBS
->HandleProtocol (BlockIoBuffer
[Index
], &gEfiDevicePathProtocolGuid
, (VOID
*) &BlockIoDevicePath
);
425 if (EFI_ERROR (Status
) || BlockIoDevicePath
== NULL
) {
429 if (MatchPartitionDevicePathNode (BlockIoDevicePath
, HardDriveDevicePath
)) {
431 // Find the matched partition device path
433 DevicePath
= NextDevicePathNode ((EFI_DEVICE_PATH_PROTOCOL
*) HardDriveDevicePath
);
434 FullDevicePath
= AppendDevicePath (BlockIoDevicePath
, DevicePath
);
437 // Save the matched patition device path in 'HDDP' variable
439 if (CachedDevicePath
!= NULL
) {
441 // Save the matched patition device path as first instance of 'HDDP' variable
443 if (BdsLibMatchDevicePaths (CachedDevicePath
, BlockIoDevicePath
)) {
444 TempNewDevicePath
= CachedDevicePath
;
445 CachedDevicePath
= BdsLibDelPartMatchInstance (CachedDevicePath
, BlockIoDevicePath
);
446 FreePool(TempNewDevicePath
);
448 TempNewDevicePath
= CachedDevicePath
;
449 CachedDevicePath
= AppendDevicePathInstance (BlockIoDevicePath
, CachedDevicePath
);
450 FreePool(TempNewDevicePath
);
452 TempNewDevicePath
= CachedDevicePath
;
453 CachedDevicePath
= AppendDevicePathInstance (BlockIoDevicePath
, CachedDevicePath
);
454 FreePool(TempNewDevicePath
);
457 // Here limit the device path instance number to 12, which is max number for a system support 3 IDE controller
458 // If the user try to boot many OS in different HDs or partitions, in theary, the 'HDDP' variable maybe become larger and larger.
461 TempNewDevicePath
= CachedDevicePath
;
462 while (!IsDevicePathEnd (TempNewDevicePath
)) {
463 TempNewDevicePath
= NextDevicePathNode (TempNewDevicePath
);
465 // Parse one instance
467 while (!IsDevicePathEndType (TempNewDevicePath
)) {
468 TempNewDevicePath
= NextDevicePathNode (TempNewDevicePath
);
472 // If the CachedDevicePath variable contain too much instance, only remain 12 instances.
474 if (InstanceNum
>= 12) {
475 SetDevicePathEndNode (TempNewDevicePath
);
480 CachedDevicePath
= DuplicateDevicePath (BlockIoDevicePath
);
484 // Save the matching Device Path so we don't need to do a connect all next time
486 Status
= gRT
->SetVariable (
488 &mHdBootVariablePrivateGuid
,
489 EFI_VARIABLE_BOOTSERVICE_ACCESS
| EFI_VARIABLE_RUNTIME_ACCESS
| EFI_VARIABLE_NON_VOLATILE
,
490 GetDevicePathSize (CachedDevicePath
),
498 FreePool (CachedDevicePath
);
499 if (BlockIoBuffer
!= NULL
) {
500 FreePool (BlockIoBuffer
);
502 return FullDevicePath
;
506 Check whether there is a instance in BlockIoDevicePath, which contain multi device path
507 instances, has the same partition node with HardDriveDevicePath device path
509 @param BlockIoDevicePath Multi device path instances which need to check
510 @param HardDriveDevicePath A device path which starts with a hard drive media
513 @retval TRUE There is a matched device path instance FALSE
514 @retval FALSE There is no matched device path instance
519 MatchPartitionDevicePathNode (
520 IN EFI_DEVICE_PATH_PROTOCOL
*BlockIoDevicePath
,
521 IN HARDDRIVE_DEVICE_PATH
*HardDriveDevicePath
524 HARDDRIVE_DEVICE_PATH
*TmpHdPath
;
525 EFI_DEVICE_PATH_PROTOCOL
*DevicePath
;
527 EFI_DEVICE_PATH_PROTOCOL
*BlockIoHdDevicePathNode
;
529 if ((BlockIoDevicePath
== NULL
) || (HardDriveDevicePath
== NULL
)) {
534 // Make PreviousDevicePath == the device path node before the end node
536 DevicePath
= BlockIoDevicePath
;
537 BlockIoHdDevicePathNode
= NULL
;
540 // find the partition device path node
542 while (!IsDevicePathEnd (DevicePath
)) {
543 if ((DevicePathType (DevicePath
) == MEDIA_DEVICE_PATH
) &&
544 (DevicePathSubType (DevicePath
) == MEDIA_HARDDRIVE_DP
)
546 BlockIoHdDevicePathNode
= DevicePath
;
550 DevicePath
= NextDevicePathNode (DevicePath
);
553 if (BlockIoHdDevicePathNode
== NULL
) {
557 // See if the harddrive device path in blockio matches the orig Hard Drive Node
559 TmpHdPath
= (HARDDRIVE_DEVICE_PATH
*) BlockIoHdDevicePathNode
;
563 // Check for the match
565 if ((TmpHdPath
->MBRType
== HardDriveDevicePath
->MBRType
) &&
566 (TmpHdPath
->SignatureType
== HardDriveDevicePath
->SignatureType
)) {
567 switch (TmpHdPath
->SignatureType
) {
568 case SIGNATURE_TYPE_GUID
:
569 Match
= CompareGuid ((EFI_GUID
*)TmpHdPath
->Signature
, (EFI_GUID
*)HardDriveDevicePath
->Signature
);
571 case SIGNATURE_TYPE_MBR
:
572 Match
= (BOOLEAN
)(*((UINT32
*)(&(TmpHdPath
->Signature
[0]))) == ReadUnaligned32((UINT32
*)(&(HardDriveDevicePath
->Signature
[0]))));
584 Delete the boot option associated with the handle passed in.
586 @param Handle The handle which present the device path to create
589 @retval EFI_SUCCESS Delete the boot option success
590 @retval EFI_NOT_FOUND If the Device Path is not found in the system
591 @retval EFI_OUT_OF_RESOURCES Lack of memory resource
592 @retval Other Error return value from SetVariable()
596 BdsLibDeleteOptionFromHandle (
601 UINT8
*BootOptionVar
;
603 UINTN BootOptionSize
;
606 UINT16 BootOption
[BOOT_OPTION_MAX_CHAR
];
607 UINTN DevicePathSize
;
608 UINTN OptionDevicePathSize
;
609 EFI_DEVICE_PATH_PROTOCOL
*DevicePath
;
610 EFI_DEVICE_PATH_PROTOCOL
*OptionDevicePath
;
613 Status
= EFI_SUCCESS
;
618 // Check "BootOrder" variable, if no, means there is no any boot order.
620 BootOrder
= BdsLibGetVariableAndSize (
622 &gEfiGlobalVariableGuid
,
625 if (BootOrder
== NULL
) {
626 return EFI_NOT_FOUND
;
630 // Convert device handle to device path protocol instance
632 DevicePath
= DevicePathFromHandle (Handle
);
633 if (DevicePath
== NULL
) {
634 return EFI_NOT_FOUND
;
636 DevicePathSize
= GetDevicePathSize (DevicePath
);
639 // Loop all boot order variable and find the matching device path
642 while (Index
< BootOrderSize
/ sizeof (UINT16
)) {
643 UnicodeSPrint (BootOption
, sizeof (BootOption
), L
"Boot%04x", BootOrder
[Index
]);
644 BootOptionVar
= BdsLibGetVariableAndSize (
646 &gEfiGlobalVariableGuid
,
650 if (BootOptionVar
== NULL
) {
651 FreePool (BootOrder
);
652 return EFI_OUT_OF_RESOURCES
;
655 TempPtr
= BootOptionVar
;
656 TempPtr
+= sizeof (UINT32
) + sizeof (UINT16
);
657 TempPtr
+= StrSize ((CHAR16
*) TempPtr
);
658 OptionDevicePath
= (EFI_DEVICE_PATH_PROTOCOL
*) TempPtr
;
659 OptionDevicePathSize
= GetDevicePathSize (OptionDevicePath
);
662 // Check whether the device path match
664 if ((OptionDevicePathSize
== DevicePathSize
) &&
665 (CompareMem (DevicePath
, OptionDevicePath
, DevicePathSize
) == 0)) {
666 BdsDeleteBootOption (BootOrder
[Index
], BootOrder
, &BootOrderSize
);
667 FreePool (BootOptionVar
);
671 FreePool (BootOptionVar
);
676 // Adjust number of boot option for "BootOrder" variable.
678 Status
= gRT
->SetVariable (
680 &gEfiGlobalVariableGuid
,
681 EFI_VARIABLE_BOOTSERVICE_ACCESS
| EFI_VARIABLE_RUNTIME_ACCESS
| EFI_VARIABLE_NON_VOLATILE
,
686 FreePool (BootOrder
);
693 Delete all invalid EFI boot options. The probable invalid boot option could
694 be Removable media or Network boot device.
696 @retval EFI_SUCCESS Delete all invalid boot option success
697 @retval EFI_NOT_FOUND Variable "BootOrder" is not found
698 @retval EFI_OUT_OF_RESOURCES Lack of memory resource
699 @retval Other Error return value from SetVariable()
703 BdsDeleteAllInvalidEfiBootOption (
708 UINT8
*BootOptionVar
;
710 UINTN BootOptionSize
;
714 UINT16 BootOption
[BOOT_OPTION_MAX_CHAR
];
715 EFI_DEVICE_PATH_PROTOCOL
*OptionDevicePath
;
718 Status
= EFI_SUCCESS
;
723 // Check "BootOrder" variable firstly, this variable hold the number of boot options
725 BootOrder
= BdsLibGetVariableAndSize (
727 &gEfiGlobalVariableGuid
,
730 if (NULL
== BootOrder
) {
731 return EFI_NOT_FOUND
;
735 while (Index
< BootOrderSize
/ sizeof (UINT16
)) {
736 UnicodeSPrint (BootOption
, sizeof (BootOption
), L
"Boot%04x", BootOrder
[Index
]);
737 BootOptionVar
= BdsLibGetVariableAndSize (
739 &gEfiGlobalVariableGuid
,
742 if (NULL
== BootOptionVar
) {
743 FreePool (BootOrder
);
744 return EFI_OUT_OF_RESOURCES
;
747 TempPtr
= BootOptionVar
;
748 TempPtr
+= sizeof (UINT32
) + sizeof (UINT16
);
749 TempPtr
+= StrSize ((CHAR16
*) TempPtr
);
750 OptionDevicePath
= (EFI_DEVICE_PATH_PROTOCOL
*) TempPtr
;
753 // Skip legacy boot option (BBS boot device)
755 if ((DevicePathType (OptionDevicePath
) == BBS_DEVICE_PATH
) &&
756 (DevicePathSubType (OptionDevicePath
) == BBS_BBS_DP
)) {
757 FreePool (BootOptionVar
);
762 if (!BdsLibIsValidEFIBootOptDevicePath (OptionDevicePath
, FALSE
)) {
764 // Delete this invalid boot option "Boot####"
766 Status
= gRT
->SetVariable (
768 &gEfiGlobalVariableGuid
,
769 EFI_VARIABLE_BOOTSERVICE_ACCESS
| EFI_VARIABLE_RUNTIME_ACCESS
| EFI_VARIABLE_NON_VOLATILE
,
774 // Mark this boot option in boot order as deleted
776 BootOrder
[Index
] = 0xffff;
779 FreePool (BootOptionVar
);
784 // Adjust boot order array
787 for (Index
= 0; Index
< BootOrderSize
/ sizeof (UINT16
); Index
++) {
788 if (BootOrder
[Index
] != 0xffff) {
789 BootOrder
[Index2
] = BootOrder
[Index
];
793 Status
= gRT
->SetVariable (
795 &gEfiGlobalVariableGuid
,
796 EFI_VARIABLE_BOOTSERVICE_ACCESS
| EFI_VARIABLE_RUNTIME_ACCESS
| EFI_VARIABLE_NON_VOLATILE
,
797 Index2
* sizeof (UINT16
),
801 FreePool (BootOrder
);
808 This function will enumerate all possible boot device in the system,
809 it will only excute once of every boot.
811 @param BdsBootOptionList The header of the link list which indexed all
814 @retval EFI_SUCCESS Finished all the boot device enumerate and create
815 the boot option base on that boot device
820 BdsLibEnumerateAllBootOption (
821 IN OUT LIST_ENTRY
*BdsBootOptionList
829 UINT16 NonBlockNumber
;
830 UINTN NumberBlockIoHandles
;
831 EFI_HANDLE
*BlockIoHandles
;
832 EFI_BLOCK_IO_PROTOCOL
*BlkIo
;
834 UINTN NumberSimpleNetworkHandles
;
835 EFI_HANDLE
*SimpleNetworkHandles
;
837 EFI_HANDLE
*FvHandleBuffer
;
838 EFI_FV_FILETYPE Type
;
840 EFI_FV_FILE_ATTRIBUTES Attributes
;
841 UINT32 AuthenticationStatus
;
842 EFI_FIRMWARE_VOLUME2_PROTOCOL
*Fv
;
843 EFI_DEVICE_PATH_PROTOCOL
*DevicePath
;
844 UINTN DevicePathType
;
846 EFI_HANDLE
*FileSystemHandles
;
847 UINTN NumberFileSystemHandles
;
849 EFI_IMAGE_DOS_HEADER DosHeader
;
850 EFI_IMAGE_OPTIONAL_HEADER_UNION HdrData
;
851 EFI_IMAGE_OPTIONAL_HEADER_PTR_UNION Hdr
;
857 ZeroMem (Buffer
, sizeof (Buffer
));
860 // If the boot device enumerate happened, just get the boot
861 // device from the boot order variable
863 if (mEnumBootDevice
) {
864 BdsLibBuildOptionFromVar (BdsBootOptionList
, L
"BootOrder");
869 // Notes: this dirty code is to get the legacy boot option from the
870 // BBS table and create to variable as the EFI boot option, it should
871 // be removed after the CSM can provide legacy boot option directly
873 REFRESH_LEGACY_BOOT_OPTIONS
;
876 // Delete invalid boot option
878 BdsDeleteAllInvalidEfiBootOption ();
881 // Parse removable media
883 gBS
->LocateHandleBuffer (
885 &gEfiBlockIoProtocolGuid
,
887 &NumberBlockIoHandles
,
891 for (Index
= 0; Index
< NumberBlockIoHandles
; Index
++) {
892 Status
= gBS
->HandleProtocol (
893 BlockIoHandles
[Index
],
894 &gEfiBlockIoProtocolGuid
,
897 if (!EFI_ERROR (Status
)) {
898 if (!BlkIo
->Media
->RemovableMedia
) {
900 // skip the non-removable block devices
905 DevicePath
= DevicePathFromHandle (BlockIoHandles
[Index
]);
906 DevicePathType
= BdsGetBootTypeFromDevicePath (DevicePath
);
908 switch (DevicePathType
) {
909 case BDS_EFI_ACPI_FLOPPY_BOOT
:
910 if (FloppyNumber
== 0) {
911 UnicodeSPrint (Buffer
, sizeof (Buffer
), L
"EFI Floppy");
913 UnicodeSPrint (Buffer
, sizeof (Buffer
), L
"EFI Floppy %d", FloppyNumber
);
915 BdsLibBuildOptionFromHandle (BlockIoHandles
[Index
], BdsBootOptionList
, Buffer
);
919 case BDS_EFI_MESSAGE_ATAPI_BOOT
:
920 if (CdromNumber
== 0) {
921 UnicodeSPrint (Buffer
, sizeof (Buffer
), L
"EFI DVD/CDROM");
923 UnicodeSPrint (Buffer
, sizeof (Buffer
), L
"EFI DVD/CDROM %d", CdromNumber
);
925 BdsLibBuildOptionFromHandle (BlockIoHandles
[Index
], BdsBootOptionList
, Buffer
);
929 case BDS_EFI_MESSAGE_USB_DEVICE_BOOT
:
930 if (UsbNumber
== 0) {
931 UnicodeSPrint (Buffer
, sizeof (Buffer
), L
"EFI USB Device");
933 UnicodeSPrint (Buffer
, sizeof (Buffer
), L
"EFI USB Device %d", UsbNumber
);
935 BdsLibBuildOptionFromHandle (BlockIoHandles
[Index
], BdsBootOptionList
, Buffer
);
939 case BDS_EFI_MESSAGE_SCSI_BOOT
:
940 if (UsbNumber
== 0) {
941 UnicodeSPrint (Buffer
, sizeof (Buffer
), L
"EFI SCSI Device");
943 UnicodeSPrint (Buffer
, sizeof (Buffer
), L
"EFI SCSI Device %d", UsbNumber
);
945 BdsLibBuildOptionFromHandle (BlockIoHandles
[Index
], BdsBootOptionList
, Buffer
);
949 case BDS_EFI_MESSAGE_MISC_BOOT
:
950 if (MiscNumber
== 0) {
951 UnicodeSPrint (Buffer
, sizeof (Buffer
), L
"EFI Misc Device");
953 UnicodeSPrint (Buffer
, sizeof (Buffer
), L
"EFI Misc Device %d", MiscNumber
);
955 BdsLibBuildOptionFromHandle (BlockIoHandles
[Index
], BdsBootOptionList
, Buffer
);
964 if (NumberBlockIoHandles
!= 0) {
965 FreePool (BlockIoHandles
);
969 // If there is simple file protocol which does not consume block Io protocol, create a boot option for it here.
972 gBS
->LocateHandleBuffer (
974 &gEfiSimpleFileSystemProtocolGuid
,
976 &NumberFileSystemHandles
,
979 for (Index
= 0; Index
< NumberFileSystemHandles
; Index
++) {
980 Status
= gBS
->HandleProtocol (
981 FileSystemHandles
[Index
],
982 &gEfiBlockIoProtocolGuid
,
985 if (!EFI_ERROR (Status
)) {
987 // Skip if the file system handle supports a BlkIo protocol,
993 // Do the removable Media thing. \EFI\BOOT\boot{machinename}.EFI
994 // machinename is ia32, ia64, x64, ...
996 Hdr
.Union
= &HdrData
;
998 Status
= BdsLibGetImageHeader (
999 FileSystemHandles
[Index
],
1000 (CHAR16
*)PcdGetPtr (PcdDefaultBootFileName
),
1004 if (!EFI_ERROR (Status
) &&
1005 EFI_IMAGE_MACHINE_TYPE_SUPPORTED (Hdr
.Pe32
->FileHeader
.Machine
) &&
1006 Hdr
.Pe32
->OptionalHeader
.Subsystem
== EFI_IMAGE_SUBSYSTEM_EFI_APPLICATION
) {
1012 // No such file or the file is not a EFI application, delete this boot option
1014 BdsLibDeleteOptionFromHandle (FileSystemHandles
[Index
]);
1016 if (NonBlockNumber
== 0) {
1017 UnicodeSPrint (Buffer
, sizeof (Buffer
), L
"EFI Non-Block Boot Device");
1019 UnicodeSPrint (Buffer
, sizeof (Buffer
), L
"EFI Non-Block Boot Device %d", NonBlockNumber
);
1021 BdsLibBuildOptionFromHandle (FileSystemHandles
[Index
], BdsBootOptionList
, Buffer
);
1026 if (NumberFileSystemHandles
!= 0) {
1027 FreePool (FileSystemHandles
);
1031 // Parse Network Boot Device
1033 gBS
->LocateHandleBuffer (
1035 &gEfiSimpleNetworkProtocolGuid
,
1037 &NumberSimpleNetworkHandles
,
1038 &SimpleNetworkHandles
1040 for (Index
= 0; Index
< NumberSimpleNetworkHandles
; Index
++) {
1042 UnicodeSPrint (Buffer
, sizeof (Buffer
), L
"EFI Network");
1044 UnicodeSPrint (Buffer
, sizeof (Buffer
), L
"EFI Network %d", Index
);
1046 BdsLibBuildOptionFromHandle (SimpleNetworkHandles
[Index
], BdsBootOptionList
, Buffer
);
1049 if (NumberSimpleNetworkHandles
!= 0) {
1050 FreePool (SimpleNetworkHandles
);
1054 // Check if we have on flash shell
1056 gBS
->LocateHandleBuffer (
1058 &gEfiFirmwareVolume2ProtocolGuid
,
1063 for (Index
= 0; Index
< FvHandleCount
; Index
++) {
1065 // Only care the dispatched FV. If no dispatch protocol on the FV, it is not dispatched, then skip it.
1067 Status
= gBS
->HandleProtocol (
1068 FvHandleBuffer
[Index
],
1069 &gEfiFirmwareVolumeDispatchProtocolGuid
,
1072 if (EFI_ERROR (Status
)) {
1076 gBS
->HandleProtocol (
1077 FvHandleBuffer
[Index
],
1078 &gEfiFirmwareVolume2ProtocolGuid
,
1082 Status
= Fv
->ReadFile (
1089 &AuthenticationStatus
1091 if (EFI_ERROR (Status
)) {
1093 // Skip if no shell file in the FV
1098 // Build the shell boot option
1100 BdsLibBuildOptionFromShell (FvHandleBuffer
[Index
], BdsBootOptionList
);
1103 if (FvHandleCount
!= 0) {
1104 FreePool (FvHandleBuffer
);
1107 // Make sure every boot only have one time
1108 // boot device enumerate
1110 BdsLibBuildOptionFromVar (BdsBootOptionList
, L
"BootOrder");
1111 mEnumBootDevice
= TRUE
;
1117 Build the boot option with the handle parsed in.
1119 @param Handle The handle which present the device path to create
1121 @param BdsBootOptionList The header of the link list which indexed all
1122 current boot options
1123 @param String Boot option name.
1128 BdsLibBuildOptionFromHandle (
1129 IN EFI_HANDLE Handle
,
1130 IN LIST_ENTRY
*BdsBootOptionList
,
1134 EFI_DEVICE_PATH_PROTOCOL
*DevicePath
;
1136 DevicePath
= DevicePathFromHandle (Handle
);
1139 // Create and register new boot option
1141 BdsLibRegisterNewOption (BdsBootOptionList
, DevicePath
, String
, L
"BootOrder");
1146 Build the on flash shell boot option with the handle parsed in.
1148 @param Handle The handle which present the device path to create
1149 on flash shell boot option
1150 @param BdsBootOptionList The header of the link list which indexed all
1151 current boot options
1156 BdsLibBuildOptionFromShell (
1157 IN EFI_HANDLE Handle
,
1158 IN OUT LIST_ENTRY
*BdsBootOptionList
1161 EFI_DEVICE_PATH_PROTOCOL
*DevicePath
;
1162 MEDIA_FW_VOL_FILEPATH_DEVICE_PATH ShellNode
;
1164 DevicePath
= DevicePathFromHandle (Handle
);
1167 // Build the shell device path
1169 EfiInitializeFwVolDevicepathNode (&ShellNode
, &gEfiShellFileGuid
);
1171 DevicePath
= AppendDevicePathNode (DevicePath
, (EFI_DEVICE_PATH_PROTOCOL
*) &ShellNode
);
1174 // Create and register the shell boot option
1176 BdsLibRegisterNewOption (BdsBootOptionList
, DevicePath
, L
"EFI Internal Shell", L
"BootOrder");
1181 Boot from the EFI1.1 spec defined "BootNext" variable
1193 BDS_COMMON_OPTION
*BootOption
;
1194 LIST_ENTRY TempList
;
1199 // Init the boot option name buffer and temp link list
1201 InitializeListHead (&TempList
);
1202 ZeroMem (Buffer
, sizeof (Buffer
));
1204 BootNext
= BdsLibGetVariableAndSize (
1206 &gEfiGlobalVariableGuid
,
1211 // Clear the boot next variable first
1213 if (BootNext
!= NULL
) {
1216 &gEfiGlobalVariableGuid
,
1217 EFI_VARIABLE_BOOTSERVICE_ACCESS
| EFI_VARIABLE_RUNTIME_ACCESS
| EFI_VARIABLE_NON_VOLATILE
,
1223 // Start to build the boot option and try to boot
1225 UnicodeSPrint (Buffer
, sizeof (Buffer
), L
"Boot%04x", *BootNext
);
1226 BootOption
= BdsLibVariableToOption (&TempList
, Buffer
);
1227 BdsLibConnectDevicePath (BootOption
->DevicePath
);
1228 BdsLibBootViaBootOption (BootOption
, BootOption
->DevicePath
, &ExitDataSize
, &ExitData
);
1234 Return the bootable media handle.
1235 First, check the device is connected
1236 Second, check whether the device path point to a device which support SimpleFileSystemProtocol,
1237 Third, detect the the default boot file in the Media, and return the removable Media handle.
1239 @param DevicePath Device Path to a bootable device
1241 @retval NULL The device path points to an EFI bootable Media
1242 @retval NULL The media on the DevicePath is not bootable
1247 BdsLibGetBootableHandle (
1248 IN EFI_DEVICE_PATH_PROTOCOL
*DevicePath
1252 EFI_DEVICE_PATH_PROTOCOL
*UpdatedDevicePath
;
1253 EFI_DEVICE_PATH_PROTOCOL
*DupDevicePath
;
1255 EFI_BLOCK_IO_PROTOCOL
*BlockIo
;
1257 EFI_DEVICE_PATH_PROTOCOL
*TempDevicePath
;
1260 EFI_HANDLE ReturnHandle
;
1261 EFI_HANDLE
*SimpleFileSystemHandles
;
1263 UINTN NumberSimpleFileSystemHandles
;
1265 EFI_IMAGE_DOS_HEADER DosHeader
;
1266 EFI_IMAGE_OPTIONAL_HEADER_UNION HdrData
;
1267 EFI_IMAGE_OPTIONAL_HEADER_PTR_UNION Hdr
;
1269 UpdatedDevicePath
= DevicePath
;
1272 // Check whether the device is connected
1274 Status
= gBS
->LocateDevicePath (&gEfiBlockIoProtocolGuid
, &UpdatedDevicePath
, &Handle
);
1275 if (EFI_ERROR (Status
)) {
1277 // Skip the case that the boot option point to a simple file protocol which does not consume block Io protocol,
1279 Status
= gBS
->LocateDevicePath (&gEfiSimpleFileSystemProtocolGuid
, &UpdatedDevicePath
, &Handle
);
1280 if (EFI_ERROR (Status
)) {
1282 // Fail to find the proper BlockIo and simple file protocol, maybe because device not present, we need to connect it firstly
1284 UpdatedDevicePath
= DevicePath
;
1285 Status
= gBS
->LocateDevicePath (&gEfiDevicePathProtocolGuid
, &UpdatedDevicePath
, &Handle
);
1286 gBS
->ConnectController (Handle
, NULL
, NULL
, TRUE
);
1290 // Get BlockIo protocal and check removable attribute
1292 Status
= gBS
->HandleProtocol (Handle
, &gEfiBlockIoProtocolGuid
, (VOID
**)&BlockIo
);
1294 // Issue a dummy read to the device to check for media change.
1295 // When the removable media is changed, any Block IO read/write will
1296 // cause the BlockIo protocol be reinstalled and EFI_MEDIA_CHANGED is
1297 // returned. After the Block IO protocol is reinstalled, subsequent
1298 // Block IO read/write will success.
1300 Buffer
= AllocatePool (BlockIo
->Media
->BlockSize
);
1301 if (Buffer
!= NULL
) {
1302 BlockIo
->ReadBlocks (
1304 BlockIo
->Media
->MediaId
,
1306 BlockIo
->Media
->BlockSize
,
1314 // Detect the the default boot file from removable Media
1318 // If fail to get bootable handle specified by a USB boot option, the BDS should try to find other bootable device in the same USB bus
1319 // Try to locate the USB node device path first, if fail then use its previour PCI node to search
1321 DupDevicePath
= DuplicateDevicePath (DevicePath
);
1322 ASSERT (DupDevicePath
!= NULL
);
1324 UpdatedDevicePath
= DupDevicePath
;
1325 Status
= gBS
->LocateDevicePath (&gEfiDevicePathProtocolGuid
, &UpdatedDevicePath
, &Handle
);
1327 // if the resulting device path point to a usb node, and the usb node is a dummy node, should only let device path only point to the previous Pci node
1328 // Acpi()/Pci()/Usb() --> Acpi()/Pci()
1330 if ((DevicePathType (UpdatedDevicePath
) == MESSAGING_DEVICE_PATH
) &&
1331 (DevicePathSubType (UpdatedDevicePath
) == MSG_USB_DP
)) {
1333 // Remove the usb node, let the device path only point to PCI node
1335 SetDevicePathEndNode (UpdatedDevicePath
);
1336 UpdatedDevicePath
= DupDevicePath
;
1338 UpdatedDevicePath
= DevicePath
;
1342 // Get the device path size of boot option
1344 Size
= GetDevicePathSize(UpdatedDevicePath
) - sizeof (EFI_DEVICE_PATH_PROTOCOL
); // minus the end node
1345 ReturnHandle
= NULL
;
1346 gBS
->LocateHandleBuffer (
1348 &gEfiSimpleFileSystemProtocolGuid
,
1350 &NumberSimpleFileSystemHandles
,
1351 &SimpleFileSystemHandles
1353 for (Index
= 0; Index
< NumberSimpleFileSystemHandles
; Index
++) {
1355 // Get the device path size of SimpleFileSystem handle
1357 TempDevicePath
= DevicePathFromHandle (SimpleFileSystemHandles
[Index
]);
1358 TempSize
= GetDevicePathSize (TempDevicePath
)- sizeof (EFI_DEVICE_PATH_PROTOCOL
); // minus the end node
1360 // Check whether the device path of boot option is part of the SimpleFileSystem handle's device path
1362 if (Size
<= TempSize
&& CompareMem (TempDevicePath
, UpdatedDevicePath
, Size
)==0) {
1364 // Load the default boot file \EFI\BOOT\boot{machinename}.EFI from removable Media
1365 // machinename is ia32, ia64, x64, ...
1367 Hdr
.Union
= &HdrData
;
1368 Status
= BdsLibGetImageHeader (
1369 SimpleFileSystemHandles
[Index
],
1370 (CHAR16
*)PcdGetPtr(PcdDefaultBootFileName
),
1374 if (!EFI_ERROR (Status
) &&
1375 EFI_IMAGE_MACHINE_TYPE_SUPPORTED (Hdr
.Pe32
->FileHeader
.Machine
) &&
1376 Hdr
.Pe32
->OptionalHeader
.Subsystem
== EFI_IMAGE_SUBSYSTEM_EFI_APPLICATION
) {
1377 ReturnHandle
= SimpleFileSystemHandles
[Index
];
1383 FreePool(DupDevicePath
);
1385 if (SimpleFileSystemHandles
!= NULL
) {
1386 FreePool(SimpleFileSystemHandles
);
1389 return ReturnHandle
;
1393 Check to see if the network cable is plugged in. If the DevicePath is not
1394 connected it will be connected.
1396 @param DevicePath Device Path to check
1398 @retval TRUE DevicePath points to an Network that is connected
1399 @retval FALSE DevicePath does not point to a bootable network
1403 BdsLibNetworkBootWithMediaPresent (
1404 IN EFI_DEVICE_PATH_PROTOCOL
*DevicePath
1408 EFI_DEVICE_PATH_PROTOCOL
*UpdatedDevicePath
;
1410 EFI_SIMPLE_NETWORK_PROTOCOL
*Snp
;
1411 BOOLEAN MediaPresent
;
1413 MediaPresent
= FALSE
;
1415 UpdatedDevicePath
= DevicePath
;
1416 Status
= gBS
->LocateDevicePath (&gEfiSimpleNetworkProtocolGuid
, &UpdatedDevicePath
, &Handle
);
1417 if (EFI_ERROR (Status
)) {
1419 // Device not present so see if we need to connect it
1421 Status
= BdsLibConnectDevicePath (DevicePath
);
1422 if (!EFI_ERROR (Status
)) {
1424 // This one should work after we did the connect
1426 Status
= gBS
->LocateDevicePath (&gEfiSimpleNetworkProtocolGuid
, &UpdatedDevicePath
, &Handle
);
1430 if (!EFI_ERROR (Status
)) {
1431 Status
= gBS
->HandleProtocol (Handle
, &gEfiSimpleNetworkProtocolGuid
, (VOID
**)&Snp
);
1432 if (!EFI_ERROR (Status
)) {
1433 if (Snp
->Mode
->MediaPresentSupported
) {
1434 if (Snp
->Mode
->State
== EfiSimpleNetworkInitialized
) {
1436 // In case some one else is using the SNP check to see if it's connected
1438 MediaPresent
= Snp
->Mode
->MediaPresent
;
1441 // No one is using SNP so we need to Start and Initialize so
1442 // MediaPresent will be valid.
1444 Status
= Snp
->Start (Snp
);
1445 if (!EFI_ERROR (Status
)) {
1446 Status
= Snp
->Initialize (Snp
, 0, 0);
1447 if (!EFI_ERROR (Status
)) {
1448 MediaPresent
= Snp
->Mode
->MediaPresent
;
1449 Snp
->Shutdown (Snp
);
1455 MediaPresent
= TRUE
;
1460 return MediaPresent
;
1464 For a bootable Device path, return its boot type.
1466 @param DevicePath The bootable device Path to check
1468 @retval BDS_EFI_MEDIA_HD_BOOT If the device path contains any media deviec path node, it is media boot type
1469 For the floppy node, handle it as media node
1470 @retval BDS_EFI_MEDIA_CDROM_BOOT If the device path contains any media deviec path node, it is media boot type
1471 For the floppy node, handle it as media node
1472 @retval BDS_EFI_ACPI_FLOPPY_BOOT If the device path contains any media deviec path node, it is media boot type
1473 For the floppy node, handle it as media node
1474 @retval BDS_EFI_MESSAGE_ATAPI_BOOT If the device path not contains any media deviec path node, and
1475 its last device path node point to a message device path node, it is
1477 @retval BDS_EFI_MESSAGE_SCSI_BOOT If the device path not contains any media deviec path node, and
1478 its last device path node point to a message device path node, it is
1479 @retval BDS_EFI_MESSAGE_USB_DEVICE_BOOT If the device path not contains any media deviec path node, and
1480 its last device path node point to a message device path node, it is
1481 @retval BDS_EFI_MESSAGE_MISC_BOOT If the device path not contains any media deviec path node, and
1482 its last device path node point to a message device path node, it is
1483 @retval BDS_LEGACY_BBS_BOOT Legacy boot type
1484 @retval BDS_EFI_UNSUPPORT An EFI Removable BlockIO device path not point to a media and message devie,
1489 BdsGetBootTypeFromDevicePath (
1490 IN EFI_DEVICE_PATH_PROTOCOL
*DevicePath
1493 ACPI_HID_DEVICE_PATH
*Acpi
;
1494 EFI_DEVICE_PATH_PROTOCOL
*TempDevicePath
;
1495 EFI_DEVICE_PATH_PROTOCOL
*LastDeviceNode
;
1498 if (NULL
== DevicePath
) {
1499 return BDS_EFI_UNSUPPORT
;
1502 TempDevicePath
= DevicePath
;
1504 while (!IsDevicePathEndType (TempDevicePath
)) {
1505 switch (DevicePathType (TempDevicePath
)) {
1506 case BBS_DEVICE_PATH
:
1507 return BDS_LEGACY_BBS_BOOT
;
1508 case MEDIA_DEVICE_PATH
:
1509 if (DevicePathSubType (TempDevicePath
) == MEDIA_HARDDRIVE_DP
) {
1510 return BDS_EFI_MEDIA_HD_BOOT
;
1511 } else if (DevicePathSubType (TempDevicePath
) == MEDIA_CDROM_DP
) {
1512 return BDS_EFI_MEDIA_CDROM_BOOT
;
1515 case ACPI_DEVICE_PATH
:
1516 Acpi
= (ACPI_HID_DEVICE_PATH
*) TempDevicePath
;
1517 if (EISA_ID_TO_NUM (Acpi
->HID
) == 0x0604) {
1518 return BDS_EFI_ACPI_FLOPPY_BOOT
;
1521 case MESSAGING_DEVICE_PATH
:
1523 // Get the last device path node
1525 LastDeviceNode
= NextDevicePathNode (TempDevicePath
);
1526 if (DevicePathSubType(LastDeviceNode
) == MSG_DEVICE_LOGICAL_UNIT_DP
) {
1528 // if the next node type is Device Logical Unit, which specify the Logical Unit Number (LUN),
1531 LastDeviceNode
= NextDevicePathNode (LastDeviceNode
);
1534 // if the device path not only point to driver device, it is not a messaging device path,
1536 if (!IsDevicePathEndType (LastDeviceNode
)) {
1540 if (DevicePathSubType(TempDevicePath
) == MSG_ATAPI_DP
) {
1541 return BDS_EFI_MESSAGE_ATAPI_BOOT
;
1542 } else if (DevicePathSubType(TempDevicePath
) == MSG_USB_DP
) {
1543 return BDS_EFI_MESSAGE_USB_DEVICE_BOOT
;
1544 } else if (DevicePathSubType(TempDevicePath
) == MSG_SCSI_DP
) {
1545 return BDS_EFI_MESSAGE_SCSI_BOOT
;
1547 return BDS_EFI_MESSAGE_MISC_BOOT
;
1551 TempDevicePath
= NextDevicePathNode (TempDevicePath
);
1554 return BDS_EFI_UNSUPPORT
;
1558 Check whether the Device path in a boot option point to a valide bootable device,
1559 And if CheckMedia is true, check the device is ready to boot now.
1561 @param DevPath the Device path in a boot option
1562 @param CheckMedia if true, check the device is ready to boot now.
1564 @retval TRUE the Device path is valide
1565 @retval FALSE the Device path is invalide .
1570 BdsLibIsValidEFIBootOptDevicePath (
1571 IN EFI_DEVICE_PATH_PROTOCOL
*DevPath
,
1572 IN BOOLEAN CheckMedia
1577 EFI_DEVICE_PATH_PROTOCOL
*TempDevicePath
;
1578 EFI_DEVICE_PATH_PROTOCOL
*LastDeviceNode
;
1579 EFI_BLOCK_IO_PROTOCOL
*BlockIo
;
1581 TempDevicePath
= DevPath
;
1582 LastDeviceNode
= DevPath
;
1585 // Check if it's a valid boot option for network boot device
1586 // Only check if there is SimpleNetworkProtocol installed. If yes, that means
1587 // there is the network card there.
1589 Status
= gBS
->LocateDevicePath (
1590 &gEfiSimpleNetworkProtocolGuid
,
1594 if (EFI_ERROR (Status
)) {
1596 // Device not present so see if we need to connect it
1598 TempDevicePath
= DevPath
;
1599 BdsLibConnectDevicePath (TempDevicePath
);
1600 Status
= gBS
->LocateDevicePath (
1601 &gEfiSimpleNetworkProtocolGuid
,
1607 if (!EFI_ERROR (Status
)) {
1610 // Test if it is ready to boot now
1612 if (BdsLibNetworkBootWithMediaPresent(DevPath
)) {
1621 // If the boot option point to a file, it is a valid EFI boot option,
1622 // and assume it is ready to boot now
1624 while (!IsDevicePathEnd (TempDevicePath
)) {
1625 LastDeviceNode
= TempDevicePath
;
1626 TempDevicePath
= NextDevicePathNode (TempDevicePath
);
1628 if ((DevicePathType (LastDeviceNode
) == MEDIA_DEVICE_PATH
) &&
1629 (DevicePathSubType (LastDeviceNode
) == MEDIA_FILEPATH_DP
)) {
1634 // Check if it's a valid boot option for internal Shell
1636 if (EfiGetNameGuidFromFwVolDevicePathNode ((MEDIA_FW_VOL_FILEPATH_DEVICE_PATH
*) LastDeviceNode
) != NULL
) {
1638 // If the boot option point to Internal FV shell, make sure it is valid
1640 TempDevicePath
= DevPath
;
1641 Status
= BdsLibUpdateFvFileDevicePath (&TempDevicePath
, &gEfiShellFileGuid
);
1642 if (Status
== EFI_ALREADY_STARTED
) {
1645 if (Status
== EFI_SUCCESS
) {
1646 FreePool (TempDevicePath
);
1653 // If the boot option point to a blockIO device, no matter whether or not it is a removeable device, it is a valid EFI boot option
1655 TempDevicePath
= DevPath
;
1656 Status
= gBS
->LocateDevicePath (&gEfiBlockIoProtocolGuid
, &TempDevicePath
, &Handle
);
1657 if (EFI_ERROR (Status
)) {
1659 // Device not present so see if we need to connect it
1661 Status
= BdsLibConnectDevicePath (DevPath
);
1662 if (!EFI_ERROR (Status
)) {
1664 // Try again to get the Block Io protocol after we did the connect
1666 TempDevicePath
= DevPath
;
1667 Status
= gBS
->LocateDevicePath (&gEfiBlockIoProtocolGuid
, &TempDevicePath
, &Handle
);
1671 if (!EFI_ERROR (Status
)) {
1672 Status
= gBS
->HandleProtocol (Handle
, &gEfiBlockIoProtocolGuid
, (VOID
**)&BlockIo
);
1673 if (!EFI_ERROR (Status
)) {
1676 // Test if it is ready to boot now
1678 if (BdsLibGetBootableHandle (DevPath
) != NULL
) {
1687 // if the boot option point to a simple file protocol which does not consume block Io protocol, it is also a valid EFI boot option,
1689 Status
= gBS
->LocateDevicePath (&gEfiSimpleFileSystemProtocolGuid
, &TempDevicePath
, &Handle
);
1690 if (!EFI_ERROR (Status
)) {
1693 // Test if it is ready to boot now
1695 if (BdsLibGetBootableHandle (DevPath
) != NULL
) {
1709 According to a file guild, check a Fv file device path is valid. If it is invalid,
1710 try to return the valid device path.
1711 FV address maybe changes for memory layout adjust from time to time, use this funciton
1712 could promise the Fv file device path is right.
1714 @param DevicePath on input, the Fv file device path need to check on
1715 output, the updated valid Fv file device path
1716 @param FileGuid the Fv file guild
1718 @retval EFI_INVALID_PARAMETER the input DevicePath or FileGuid is invalid
1720 @retval EFI_UNSUPPORTED the input DevicePath does not contain Fv file
1722 @retval EFI_ALREADY_STARTED the input DevicePath has pointed to Fv file, it is
1724 @retval EFI_SUCCESS has successfully updated the invalid DevicePath,
1725 and return the updated device path in DevicePath
1730 BdsLibUpdateFvFileDevicePath (
1731 IN OUT EFI_DEVICE_PATH_PROTOCOL
** DevicePath
,
1732 IN EFI_GUID
*FileGuid
1735 EFI_DEVICE_PATH_PROTOCOL
*TempDevicePath
;
1736 EFI_DEVICE_PATH_PROTOCOL
*LastDeviceNode
;
1738 EFI_GUID
*GuidPoint
;
1740 UINTN FvHandleCount
;
1741 EFI_HANDLE
*FvHandleBuffer
;
1742 EFI_FV_FILETYPE Type
;
1744 EFI_FV_FILE_ATTRIBUTES Attributes
;
1745 UINT32 AuthenticationStatus
;
1747 EFI_LOADED_IMAGE_PROTOCOL
*LoadedImage
;
1748 EFI_FIRMWARE_VOLUME2_PROTOCOL
*Fv
;
1749 MEDIA_FW_VOL_FILEPATH_DEVICE_PATH FvFileNode
;
1750 EFI_HANDLE FoundFvHandle
;
1751 EFI_DEVICE_PATH_PROTOCOL
*NewDevicePath
;
1753 if ((DevicePath
== NULL
) || (*DevicePath
== NULL
)) {
1754 return EFI_INVALID_PARAMETER
;
1756 if (FileGuid
== NULL
) {
1757 return EFI_INVALID_PARAMETER
;
1761 // Check whether the device path point to the default the input Fv file
1763 TempDevicePath
= *DevicePath
;
1764 LastDeviceNode
= TempDevicePath
;
1765 while (!IsDevicePathEnd (TempDevicePath
)) {
1766 LastDeviceNode
= TempDevicePath
;
1767 TempDevicePath
= NextDevicePathNode (TempDevicePath
);
1769 GuidPoint
= EfiGetNameGuidFromFwVolDevicePathNode (
1770 (MEDIA_FW_VOL_FILEPATH_DEVICE_PATH
*) LastDeviceNode
1772 if (GuidPoint
== NULL
) {
1774 // if this option does not points to a Fv file, just return EFI_UNSUPPORTED
1776 return EFI_UNSUPPORTED
;
1778 if (!CompareGuid (GuidPoint
, FileGuid
)) {
1780 // If the Fv file is not the input file guid, just return EFI_UNSUPPORTED
1782 return EFI_UNSUPPORTED
;
1786 // Check whether the input Fv file device path is valid
1788 TempDevicePath
= *DevicePath
;
1789 FoundFvHandle
= NULL
;
1790 Status
= gBS
->LocateDevicePath (
1791 &gEfiFirmwareVolume2ProtocolGuid
,
1795 if (!EFI_ERROR (Status
)) {
1796 Status
= gBS
->HandleProtocol (
1798 &gEfiFirmwareVolume2ProtocolGuid
,
1801 if (!EFI_ERROR (Status
)) {
1803 // Set FV ReadFile Buffer as NULL, only need to check whether input Fv file exist there
1805 Status
= Fv
->ReadFile (
1812 &AuthenticationStatus
1814 if (!EFI_ERROR (Status
)) {
1815 return EFI_ALREADY_STARTED
;
1821 // Look for the input wanted FV file in current FV
1822 // First, try to look for in Bds own FV. Bds and input wanted FV file usually are in the same FV
1825 FoundFvHandle
= NULL
;
1826 Status
= gBS
->HandleProtocol (
1828 &gEfiLoadedImageProtocolGuid
,
1829 (VOID
**) &LoadedImage
1831 if (!EFI_ERROR (Status
)) {
1832 Status
= gBS
->HandleProtocol (
1833 LoadedImage
->DeviceHandle
,
1834 &gEfiFirmwareVolume2ProtocolGuid
,
1837 if (!EFI_ERROR (Status
)) {
1838 Status
= Fv
->ReadFile (
1845 &AuthenticationStatus
1847 if (!EFI_ERROR (Status
)) {
1849 FoundFvHandle
= LoadedImage
->DeviceHandle
;
1854 // Second, if fail to find, try to enumerate all FV
1857 FvHandleBuffer
= NULL
;
1858 gBS
->LocateHandleBuffer (
1860 &gEfiFirmwareVolume2ProtocolGuid
,
1865 for (Index
= 0; Index
< FvHandleCount
; Index
++) {
1866 gBS
->HandleProtocol (
1867 FvHandleBuffer
[Index
],
1868 &gEfiFirmwareVolume2ProtocolGuid
,
1872 Status
= Fv
->ReadFile (
1879 &AuthenticationStatus
1881 if (EFI_ERROR (Status
)) {
1883 // Skip if input Fv file not in the FV
1888 FoundFvHandle
= FvHandleBuffer
[Index
];
1892 if (FvHandleBuffer
!= NULL
) {
1893 FreePool (FvHandleBuffer
);
1899 // Build the shell device path
1901 NewDevicePath
= DevicePathFromHandle (FoundFvHandle
);
1902 EfiInitializeFwVolDevicepathNode (&FvFileNode
, FileGuid
);
1903 NewDevicePath
= AppendDevicePathNode (NewDevicePath
, (EFI_DEVICE_PATH_PROTOCOL
*) &FvFileNode
);
1904 *DevicePath
= NewDevicePath
;
1907 return EFI_NOT_FOUND
;