2 BDS Lib functions which relate with create or process the boot
5 Copyright (c) 2004 - 2008, Intel Corporation. <BR>
6 All rights reserved. This program and the accompanying materials
7 are licensed and made available under the terms and conditions of the BSD License
8 which accompanies this distribution. The full text of the license may be found at
9 http://opensource.org/licenses/bsd-license.php
11 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
12 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
16 #include "InternalBdsLib.h"
18 BOOLEAN mEnumBootDevice
= FALSE
;
21 // This GUID is used for an EFI Variable that stores the front device pathes
22 // for a partial device path that starts with the HD node.
24 EFI_GUID mHdBootVariablePrivateGuid
= { 0xfab7e9e1, 0x39dd, 0x4f2b, { 0x84, 0x8, 0xe2, 0xe, 0x90, 0x6c, 0xb6, 0xde } };
29 Boot the legacy system with the boot option
31 @param Option The legacy boot option which have BBS device path
33 @retval EFI_UNSUPPORTED There is no legacybios protocol, do not support
35 @retval EFI_STATUS Return the status of LegacyBios->LegacyBoot ().
40 IN BDS_COMMON_OPTION
*Option
44 EFI_LEGACY_BIOS_PROTOCOL
*LegacyBios
;
46 Status
= gBS
->LocateProtocol (&gEfiLegacyBiosProtocolGuid
, NULL
, (VOID
**) &LegacyBios
);
47 if (EFI_ERROR (Status
)) {
49 // If no LegacyBios protocol we do not support legacy boot
51 return EFI_UNSUPPORTED
;
54 // Notes: if we seperate the int 19, then we don't need to refresh BBS
56 BdsRefreshBbsTableForBoot (Option
);
59 // Write boot to OS performance data to a file
62 WriteBootToOsPerformanceData ();
65 DEBUG ((DEBUG_INFO
| DEBUG_LOAD
, "Legacy Boot: %S\n", Option
->Description
));
66 return LegacyBios
->LegacyBoot (
68 (BBS_BBS_DEVICE_PATH
*) Option
->DevicePath
,
69 Option
->LoadOptionsSize
,
76 Process the boot option follow the EFI 1.1 specification and
77 special treat the legacy boot option with BBS_DEVICE_PATH.
79 @param Option The boot option need to be processed
80 @param DevicePath The device path which describe where to load the
81 boot image or the legcy BBS device path to boot
83 @param ExitDataSize Returned directly from gBS->StartImage ()
84 @param ExitData Returned directly from gBS->StartImage ()
86 @retval EFI_SUCCESS Status from gBS->StartImage ()
87 @retval EFI_NOT_FOUND If the Device Path is not found in the system
92 BdsLibBootViaBootOption (
93 IN BDS_COMMON_OPTION
* Option
,
94 IN EFI_DEVICE_PATH_PROTOCOL
* DevicePath
,
95 OUT UINTN
*ExitDataSize
,
96 OUT CHAR16
**ExitData OPTIONAL
101 EFI_HANDLE ImageHandle
;
102 EFI_DEVICE_PATH_PROTOCOL
*FilePath
;
103 EFI_LOADED_IMAGE_PROTOCOL
*ImageInfo
;
104 EFI_DEVICE_PATH_PROTOCOL
*WorkingDevicePath
;
105 EFI_ACPI_S3_SAVE_PROTOCOL
*AcpiS3Save
;
106 LIST_ENTRY TempBootLists
;
109 // Record the performance data for End of BDS
111 PERF_END (0, BDS_TOK
, NULL
, 0);
117 // Notes: put EFI64 ROM Shadow Solution
119 EFI64_SHADOW_ALL_LEGACY_ROM ();
122 // Notes: this code can be remove after the s3 script table
123 // hook on the event EFI_EVENT_SIGNAL_READY_TO_BOOT or
124 // EFI_EVENT_SIGNAL_LEGACY_BOOT
126 Status
= gBS
->LocateProtocol (&gEfiAcpiS3SaveProtocolGuid
, NULL
, (VOID
**) &AcpiS3Save
);
127 if (!EFI_ERROR (Status
)) {
128 AcpiS3Save
->S3Save (AcpiS3Save
, NULL
);
131 // If it's Device Path that starts with a hard drive path, append it with the front part to compose a
134 WorkingDevicePath
= NULL
;
135 if ((DevicePathType (DevicePath
) == MEDIA_DEVICE_PATH
) &&
136 (DevicePathSubType (DevicePath
) == MEDIA_HARDDRIVE_DP
)) {
137 WorkingDevicePath
= BdsExpandPartitionPartialDevicePathToFull (
138 (HARDDRIVE_DEVICE_PATH
*)DevicePath
140 if (WorkingDevicePath
!= NULL
) {
141 DevicePath
= WorkingDevicePath
;
145 // Signal the EFI_EVENT_SIGNAL_READY_TO_BOOT event
147 EfiSignalEventReadyToBoot();
155 &gEfiGlobalVariableGuid
,
156 EFI_VARIABLE_BOOTSERVICE_ACCESS
| EFI_VARIABLE_RUNTIME_ACCESS
,
161 if ((DevicePathType (Option
->DevicePath
) == BBS_DEVICE_PATH
) &&
162 (DevicePathSubType (Option
->DevicePath
) == BBS_BBS_DP
)
165 // Check to see if we should legacy BOOT. If yes then do the legacy boot
167 return BdsLibDoLegacyBoot (Option
);
171 // If the boot option point to Internal FV shell, make sure it is valid
173 Status
= BdsLibUpdateFvFileDevicePath (&DevicePath
, &gEfiShellFileGuid
);
174 if (!EFI_ERROR(Status
)) {
175 if (Option
->DevicePath
!= NULL
) {
176 SafeFreePool(Option
->DevicePath
);
178 Option
->DevicePath
= AllocateZeroPool (GetDevicePathSize (DevicePath
));
179 CopyMem (Option
->DevicePath
, DevicePath
, GetDevicePathSize (DevicePath
));
181 // Update the shell boot option
183 InitializeListHead (&TempBootLists
);
184 BdsLibRegisterNewOption (&TempBootLists
, DevicePath
, L
"EFI Internal Shell", L
"BootOrder");
186 // free the temporary device path created by BdsLibUpdateFvFileDevicePath()
188 gBS
->FreePool (DevicePath
);
189 DevicePath
= Option
->DevicePath
;
193 // Drop the TPL level from TPL_APPLICATION to TPL_APPLICATION
195 gBS
->RestoreTPL (TPL_APPLICATION
);
197 DEBUG ((DEBUG_INFO
| DEBUG_LOAD
, "Booting EFI way %S\n", Option
->Description
));
199 Status
= gBS
->LoadImage (
209 // If we didn't find an image directly, we need to try as if it is a removable device boot opotion
210 // and load the image according to the default boot behavior for removable device.
212 if (EFI_ERROR (Status
)) {
214 // check if there is a bootable removable media could be found in this device path ,
215 // and get the bootable media handle
217 Handle
= BdsLibGetBootableHandle(DevicePath
);
218 if (Handle
== NULL
) {
222 // Load the default boot file \EFI\BOOT\boot{machinename}.EFI from removable Media
223 // machinename is ia32, ia64, x64, ...
225 FilePath
= FileDevicePath (Handle
, DEFAULT_REMOVABLE_FILE_NAME
);
226 if (FilePath
!= NULL
) {
227 Status
= gBS
->LoadImage (
235 if (EFI_ERROR (Status
)) {
237 // The DevicePath failed, and it's not a valid
238 // removable media device.
245 if (EFI_ERROR (Status
)) {
247 // It there is any error from the Boot attempt exit now.
252 // Provide the image with it's load options
254 Status
= gBS
->HandleProtocol (ImageHandle
, &gEfiLoadedImageProtocolGuid
, (VOID
**) &ImageInfo
);
255 ASSERT_EFI_ERROR (Status
);
257 if (Option
->LoadOptionsSize
!= 0) {
258 ImageInfo
->LoadOptionsSize
= Option
->LoadOptionsSize
;
259 ImageInfo
->LoadOptions
= Option
->LoadOptions
;
262 // Before calling the image, enable the Watchdog Timer for
263 // the 5 Minute period
265 gBS
->SetWatchdogTimer (5 * 60, 0x0000, 0x00, NULL
);
267 Status
= gBS
->StartImage (ImageHandle
, ExitDataSize
, ExitData
);
268 DEBUG ((DEBUG_INFO
| DEBUG_LOAD
, "Image Return Status = %r\n", Status
));
271 // Clear the Watchdog Timer after the image returns
273 gBS
->SetWatchdogTimer (0x0000, 0x0000, 0x0000, NULL
);
277 // Clear Boot Current
281 &gEfiGlobalVariableGuid
,
282 EFI_VARIABLE_BOOTSERVICE_ACCESS
| EFI_VARIABLE_RUNTIME_ACCESS
,
288 // Raise the TPL level back to TPL_APPLICATION
290 gBS
->RaiseTPL (TPL_APPLICATION
);
297 Expand a device path that starts with a hard drive media device path node to be a
298 full device path that includes the full hardware path to the device. We need
299 to do this so it can be booted. As an optimizaiton the front match (the part point
300 to the partition node. E.g. ACPI() /PCI()/ATA()/Partition() ) is saved in a variable
301 so a connect all is not required on every boot. All successful history device path
302 which point to partition node (the front part) will be saved.
304 @param HardDriveDevicePath EFI Device Path to boot, if it starts with a hard
305 drive media device path.
306 @return A Pointer to the full device path or NULL if a valid Hard Drive devic path
310 EFI_DEVICE_PATH_PROTOCOL
*
312 BdsExpandPartitionPartialDevicePathToFull (
313 IN HARDDRIVE_DEVICE_PATH
*HardDriveDevicePath
317 UINTN BlockIoHandleCount
;
318 EFI_HANDLE
*BlockIoBuffer
;
319 EFI_DEVICE_PATH_PROTOCOL
*FullDevicePath
;
320 EFI_DEVICE_PATH_PROTOCOL
*BlockIoDevicePath
;
321 EFI_DEVICE_PATH_PROTOCOL
*DevicePath
;
324 EFI_DEVICE_PATH_PROTOCOL
*CachedDevicePath
;
325 EFI_DEVICE_PATH_PROTOCOL
*TempNewDevicePath
;
326 UINTN CachedDevicePathSize
;
329 EFI_DEVICE_PATH_PROTOCOL
*Instance
;
332 FullDevicePath
= NULL
;
334 // Check if there is prestore 'HDDP' variable.
335 // If exist, search the front path which point to partition node in the variable instants.
336 // If fail to find or 'HDDP' not exist, reconnect all and search in all system
338 CachedDevicePath
= BdsLibGetVariableAndSize (
340 &mHdBootVariablePrivateGuid
,
341 &CachedDevicePathSize
343 if (CachedDevicePath
!= NULL
) {
344 TempNewDevicePath
= CachedDevicePath
;
349 // Check every instance of the variable
350 // First, check wheather the instance contain the partition node, which is needed for distinguishing multi
351 // partial partition boot option. Second, check wheather the instance could be connected.
353 Instance
= GetNextDevicePathInstance (&TempNewDevicePath
, &Size
);
354 if (MatchPartitionDevicePathNode (Instance
, HardDriveDevicePath
)) {
356 // Connect the device path instance, the device path point to hard drive media device path node
357 // e.g. ACPI() /PCI()/ATA()/Partition()
359 Status
= BdsLibConnectDevicePath (Instance
);
360 if (!EFI_ERROR (Status
)) {
366 // Come here means the first instance is not matched
369 SafeFreePool(Instance
);
370 } while (TempNewDevicePath
!= NULL
);
374 // Find the matched device path.
375 // Append the file path infomration from the boot option and return the fully expanded device path.
377 DevicePath
= NextDevicePathNode ((EFI_DEVICE_PATH_PROTOCOL
*) HardDriveDevicePath
);
378 FullDevicePath
= AppendDevicePath (Instance
, DevicePath
);
381 // Adjust the 'HDDP' instances sequense if the matched one is not first one.
385 // First delete the matched instance.
387 TempNewDevicePath
= CachedDevicePath
;
388 CachedDevicePath
= BdsLibDelPartMatchInstance ( CachedDevicePath
, Instance
);
389 SafeFreePool (TempNewDevicePath
);
391 // Second, append the remaining parth after the matched instance
393 TempNewDevicePath
= CachedDevicePath
;
394 CachedDevicePath
= AppendDevicePathInstance ( Instance
, CachedDevicePath
);
395 SafeFreePool (TempNewDevicePath
);
397 // Save the matching Device Path so we don't need to do a connect all next time
399 Status
= gRT
->SetVariable (
401 &mHdBootVariablePrivateGuid
,
402 EFI_VARIABLE_BOOTSERVICE_ACCESS
| EFI_VARIABLE_RUNTIME_ACCESS
| EFI_VARIABLE_NON_VOLATILE
,
403 GetDevicePathSize (CachedDevicePath
),
407 SafeFreePool(Instance
);
408 gBS
->FreePool (CachedDevicePath
);
409 return FullDevicePath
;
414 // If we get here we fail to find or 'HDDP' not exist, and now we need
415 // to seach all devices in the system for a matched partition
417 BdsLibConnectAllDriversToAllControllers ();
418 Status
= gBS
->LocateHandleBuffer (ByProtocol
, &gEfiBlockIoProtocolGuid
, NULL
, &BlockIoHandleCount
, &BlockIoBuffer
);
419 if (EFI_ERROR (Status
) || BlockIoHandleCount
== 0) {
421 // If there was an error or there are no device handles that support
422 // the BLOCK_IO Protocol, then return.
427 // Loop through all the device handles that support the BLOCK_IO Protocol
429 for (Index
= 0; Index
< BlockIoHandleCount
; Index
++) {
431 Status
= gBS
->HandleProtocol (BlockIoBuffer
[Index
], &gEfiDevicePathProtocolGuid
, (VOID
*) &BlockIoDevicePath
);
432 if (EFI_ERROR (Status
) || BlockIoDevicePath
== NULL
) {
436 if (MatchPartitionDevicePathNode (BlockIoDevicePath
, HardDriveDevicePath
)) {
438 // Find the matched partition device path
440 DevicePath
= NextDevicePathNode ((EFI_DEVICE_PATH_PROTOCOL
*) HardDriveDevicePath
);
441 FullDevicePath
= AppendDevicePath (BlockIoDevicePath
, DevicePath
);
444 // Save the matched patition device path in 'HDDP' variable
446 if (CachedDevicePath
!= NULL
) {
448 // Save the matched patition device path as first instance of 'HDDP' variable
450 if (BdsLibMatchDevicePaths (CachedDevicePath
, BlockIoDevicePath
)) {
451 TempNewDevicePath
= CachedDevicePath
;
452 CachedDevicePath
= BdsLibDelPartMatchInstance (CachedDevicePath
, BlockIoDevicePath
);
453 SafeFreePool(TempNewDevicePath
);
455 TempNewDevicePath
= CachedDevicePath
;
456 CachedDevicePath
= AppendDevicePathInstance (BlockIoDevicePath
, CachedDevicePath
);
457 SafeFreePool(TempNewDevicePath
);
459 TempNewDevicePath
= CachedDevicePath
;
460 CachedDevicePath
= AppendDevicePathInstance (BlockIoDevicePath
, CachedDevicePath
);
461 SafeFreePool(TempNewDevicePath
);
464 // Here limit the device path instance number to 12, which is max number for a system support 3 IDE controller
465 // If the user try to boot many OS in different HDs or partitions, in theary, the 'HDDP' variable maybe become larger and larger.
468 TempNewDevicePath
= CachedDevicePath
;
469 while (!IsDevicePathEnd (TempNewDevicePath
)) {
470 TempNewDevicePath
= NextDevicePathNode (TempNewDevicePath
);
472 // Parse one instance
474 while (!IsDevicePathEndType (TempNewDevicePath
)) {
475 TempNewDevicePath
= NextDevicePathNode (TempNewDevicePath
);
479 // If the CachedDevicePath variable contain too much instance, only remain 12 instances.
481 if (InstanceNum
>= 12) {
482 SetDevicePathEndNode (TempNewDevicePath
);
487 CachedDevicePath
= DuplicateDevicePath (BlockIoDevicePath
);
491 // Save the matching Device Path so we don't need to do a connect all next time
493 Status
= gRT
->SetVariable (
495 &mHdBootVariablePrivateGuid
,
496 EFI_VARIABLE_BOOTSERVICE_ACCESS
| EFI_VARIABLE_RUNTIME_ACCESS
| EFI_VARIABLE_NON_VOLATILE
,
497 GetDevicePathSize (CachedDevicePath
),
504 gBS
->FreePool (CachedDevicePath
);
505 gBS
->FreePool (BlockIoBuffer
);
506 return FullDevicePath
;
511 Check whether there is a instance in BlockIoDevicePath, which contain multi device path
512 instances, has the same partition node with HardDriveDevicePath device path
514 @param BlockIoDevicePath Multi device path instances which need to check
515 @param HardDriveDevicePath A device path which starts with a hard drive media
518 @retval TRUE There is a matched device path instance FALSE
519 -There is no matched device path instance
524 MatchPartitionDevicePathNode (
525 IN EFI_DEVICE_PATH_PROTOCOL
*BlockIoDevicePath
,
526 IN HARDDRIVE_DEVICE_PATH
*HardDriveDevicePath
529 HARDDRIVE_DEVICE_PATH
*TmpHdPath
;
530 HARDDRIVE_DEVICE_PATH
*TempPath
;
531 EFI_DEVICE_PATH_PROTOCOL
*DevicePath
;
533 EFI_DEVICE_PATH_PROTOCOL
*BlockIoHdDevicePathNode
;
535 if ((BlockIoDevicePath
== NULL
) || (HardDriveDevicePath
== NULL
)) {
539 // Make PreviousDevicePath == the device path node before the end node
541 DevicePath
= BlockIoDevicePath
;
542 BlockIoHdDevicePathNode
= NULL
;
545 // find the partition device path node
547 while (!IsDevicePathEnd (DevicePath
)) {
548 if ((DevicePathType (DevicePath
) == MEDIA_DEVICE_PATH
) &&
549 (DevicePathSubType (DevicePath
) == MEDIA_HARDDRIVE_DP
)
551 BlockIoHdDevicePathNode
= DevicePath
;
555 DevicePath
= NextDevicePathNode (DevicePath
);
558 if (BlockIoHdDevicePathNode
== NULL
) {
562 // See if the harddrive device path in blockio matches the orig Hard Drive Node
564 TmpHdPath
= (HARDDRIVE_DEVICE_PATH
*) BlockIoHdDevicePathNode
;
565 TempPath
= (HARDDRIVE_DEVICE_PATH
*) BdsLibUnpackDevicePath ((EFI_DEVICE_PATH_PROTOCOL
*) HardDriveDevicePath
);
568 // Check for the match
570 if ((TmpHdPath
->MBRType
== TempPath
->MBRType
) &&
571 (TmpHdPath
->SignatureType
== TempPath
->SignatureType
)) {
572 switch (TmpHdPath
->SignatureType
) {
573 case SIGNATURE_TYPE_GUID
:
574 Match
= CompareGuid ((EFI_GUID
*)TmpHdPath
->Signature
, (EFI_GUID
*)TempPath
->Signature
);
576 case SIGNATURE_TYPE_MBR
:
577 Match
= (BOOLEAN
)(*((UINT32
*)(&(TmpHdPath
->Signature
[0]))) == *(UINT32
*)(&(TempPath
->Signature
[0])));
590 Delete the boot option associated with the handle passed in.
592 @param Handle The handle which present the device path to create
595 @retval EFI_SUCCESS Delete the boot option success
596 @retval EFI_NOT_FOUND If the Device Path is not found in the system
597 @retval EFI_OUT_OF_RESOURCES Lack of memory resource
598 @retval Other Error return value from SetVariable()
602 BdsLibDeleteOptionFromHandle (
607 UINT8
*BootOptionVar
;
609 UINTN BootOptionSize
;
612 UINT16 BootOption
[BOOT_OPTION_MAX_CHAR
];
613 UINTN DevicePathSize
;
614 UINTN OptionDevicePathSize
;
615 EFI_DEVICE_PATH_PROTOCOL
*DevicePath
;
616 EFI_DEVICE_PATH_PROTOCOL
*OptionDevicePath
;
619 Status
= EFI_SUCCESS
;
623 BootOrder
= BdsLibGetVariableAndSize (
625 &gEfiGlobalVariableGuid
,
628 if (NULL
== BootOrder
) {
629 return EFI_NOT_FOUND
;
632 DevicePath
= DevicePathFromHandle (Handle
);
633 if (DevicePath
== NULL
) {
634 return EFI_NOT_FOUND
;
636 DevicePathSize
= GetDevicePathSize (DevicePath
);
639 while (Index
< BootOrderSize
/ sizeof (UINT16
)) {
640 UnicodeSPrint (BootOption
, sizeof (BootOption
), L
"Boot%04x", BootOrder
[Index
]);
641 BootOptionVar
= BdsLibGetVariableAndSize (
643 &gEfiGlobalVariableGuid
,
646 if (NULL
== BootOptionVar
) {
647 gBS
->FreePool (BootOrder
);
648 return EFI_OUT_OF_RESOURCES
;
651 TempPtr
= BootOptionVar
;
652 TempPtr
+= sizeof (UINT32
) + sizeof (UINT16
);
653 TempPtr
+= StrSize ((CHAR16
*) TempPtr
);
654 OptionDevicePath
= (EFI_DEVICE_PATH_PROTOCOL
*) TempPtr
;
655 OptionDevicePathSize
= GetDevicePathSize (OptionDevicePath
);
658 // Check whether the device path match
660 if ((OptionDevicePathSize
== DevicePathSize
) &&
661 (CompareMem (DevicePath
, OptionDevicePath
, DevicePathSize
) == 0)) {
662 BdsDeleteBootOption (BootOrder
[Index
], BootOrder
, &BootOrderSize
);
663 gBS
->FreePool (BootOptionVar
);
667 gBS
->FreePool (BootOptionVar
);
671 Status
= gRT
->SetVariable (
673 &gEfiGlobalVariableGuid
,
674 EFI_VARIABLE_BOOTSERVICE_ACCESS
| EFI_VARIABLE_RUNTIME_ACCESS
| EFI_VARIABLE_NON_VOLATILE
,
679 gBS
->FreePool (BootOrder
);
686 Delete all invalid EFI boot options. The probable invalid boot option could
687 be Removable media or Network boot device.
691 @retval EFI_SUCCESS Delete all invalid boot option success
692 @retval EFI_NOT_FOUND Variable "BootOrder" is not found
693 @retval EFI_OUT_OF_RESOURCES Lack of memory resource
694 @retval Other Error return value from SetVariable()
698 BdsDeleteAllInvalidEfiBootOption (
703 UINT8
*BootOptionVar
;
705 UINTN BootOptionSize
;
709 UINT16 BootOption
[BOOT_OPTION_MAX_CHAR
];
710 EFI_DEVICE_PATH_PROTOCOL
*OptionDevicePath
;
713 Status
= EFI_SUCCESS
;
717 BootOrder
= BdsLibGetVariableAndSize (
719 &gEfiGlobalVariableGuid
,
722 if (NULL
== BootOrder
) {
723 return EFI_NOT_FOUND
;
727 while (Index
< BootOrderSize
/ sizeof (UINT16
)) {
728 UnicodeSPrint (BootOption
, sizeof (BootOption
), L
"Boot%04x", BootOrder
[Index
]);
729 BootOptionVar
= BdsLibGetVariableAndSize (
731 &gEfiGlobalVariableGuid
,
734 if (NULL
== BootOptionVar
) {
735 gBS
->FreePool (BootOrder
);
736 return EFI_OUT_OF_RESOURCES
;
739 TempPtr
= BootOptionVar
;
740 TempPtr
+= sizeof (UINT32
) + sizeof (UINT16
);
741 TempPtr
+= StrSize ((CHAR16
*) TempPtr
);
742 OptionDevicePath
= (EFI_DEVICE_PATH_PROTOCOL
*) TempPtr
;
745 // Skip legacy boot option (BBS boot device)
747 if ((DevicePathType (OptionDevicePath
) == BBS_DEVICE_PATH
) &&
748 (DevicePathSubType (OptionDevicePath
) == BBS_BBS_DP
)) {
749 gBS
->FreePool (BootOptionVar
);
754 if (!BdsLibIsValidEFIBootOptDevicePath (OptionDevicePath
, FALSE
)) {
756 // Delete this invalid boot option "Boot####"
758 Status
= gRT
->SetVariable (
760 &gEfiGlobalVariableGuid
,
761 EFI_VARIABLE_BOOTSERVICE_ACCESS
| EFI_VARIABLE_RUNTIME_ACCESS
| EFI_VARIABLE_NON_VOLATILE
,
766 // Mark this boot option in boot order as deleted
768 BootOrder
[Index
] = 0xffff;
771 gBS
->FreePool (BootOptionVar
);
776 // Adjust boot order array
779 for (Index
= 0; Index
< BootOrderSize
/ sizeof (UINT16
); Index
++) {
780 if (BootOrder
[Index
] != 0xffff) {
781 BootOrder
[Index2
] = BootOrder
[Index
];
785 Status
= gRT
->SetVariable (
787 &gEfiGlobalVariableGuid
,
788 EFI_VARIABLE_BOOTSERVICE_ACCESS
| EFI_VARIABLE_RUNTIME_ACCESS
| EFI_VARIABLE_NON_VOLATILE
,
789 Index2
* sizeof (UINT16
),
793 gBS
->FreePool (BootOrder
);
800 This function will enumerate all possible boot device in the system,
801 it will only excute once of every boot.
803 @param BdsBootOptionList The header of the link list which indexed all
806 @retval EFI_SUCCESS Finished all the boot device enumerate and create
807 the boot option base on that boot device
812 BdsLibEnumerateAllBootOption (
813 IN OUT LIST_ENTRY
*BdsBootOptionList
821 UINT16 NonBlockNumber
;
822 UINTN NumberBlockIoHandles
;
823 EFI_HANDLE
*BlockIoHandles
;
824 EFI_BLOCK_IO_PROTOCOL
*BlkIo
;
826 UINTN NumberSimpleNetworkHandles
;
827 EFI_HANDLE
*SimpleNetworkHandles
;
829 EFI_HANDLE
*FvHandleBuffer
;
830 EFI_FV_FILETYPE Type
;
832 EFI_FV_FILE_ATTRIBUTES Attributes
;
833 UINT32 AuthenticationStatus
;
834 EFI_FIRMWARE_VOLUME2_PROTOCOL
*Fv
;
835 EFI_DEVICE_PATH_PROTOCOL
*DevicePath
;
836 UINTN DevicePathType
;
838 EFI_HANDLE
*FileSystemHandles
;
839 UINTN NumberFileSystemHandles
;
841 EFI_IMAGE_DOS_HEADER DosHeader
;
842 EFI_IMAGE_OPTIONAL_HEADER_UNION HdrData
;
843 EFI_IMAGE_OPTIONAL_HEADER_PTR_UNION Hdr
;
849 ZeroMem (Buffer
, sizeof (Buffer
));
851 // If the boot device enumerate happened, just get the boot
852 // device from the boot order variable
854 if (mEnumBootDevice
) {
855 BdsLibBuildOptionFromVar (BdsBootOptionList
, L
"BootOrder");
859 // Notes: this dirty code is to get the legacy boot option from the
860 // BBS table and create to variable as the EFI boot option, it should
861 // be removed after the CSM can provide legacy boot option directly
863 REFRESH_LEGACY_BOOT_OPTIONS
;
866 // Delete invalid boot option
868 BdsDeleteAllInvalidEfiBootOption ();
870 // Parse removable media
872 gBS
->LocateHandleBuffer (
874 &gEfiBlockIoProtocolGuid
,
876 &NumberBlockIoHandles
,
879 for (Index
= 0; Index
< NumberBlockIoHandles
; Index
++) {
880 Status
= gBS
->HandleProtocol (
881 BlockIoHandles
[Index
],
882 &gEfiBlockIoProtocolGuid
,
885 if (!EFI_ERROR (Status
)) {
886 if (!BlkIo
->Media
->RemovableMedia
) {
888 // skip the non-removable block devices
893 DevicePath
= DevicePathFromHandle (BlockIoHandles
[Index
]);
894 DevicePathType
= BdsGetBootTypeFromDevicePath (DevicePath
);
896 switch (DevicePathType
) {
897 case BDS_EFI_ACPI_FLOPPY_BOOT
:
898 if (FloppyNumber
== 0) {
899 UnicodeSPrint (Buffer
, sizeof (Buffer
), L
"EFI Floppy");
901 UnicodeSPrint (Buffer
, sizeof (Buffer
), L
"EFI Floppy %d", FloppyNumber
);
903 BdsLibBuildOptionFromHandle (BlockIoHandles
[Index
], BdsBootOptionList
, Buffer
);
907 case BDS_EFI_MESSAGE_ATAPI_BOOT
:
908 if (CdromNumber
== 0) {
909 UnicodeSPrint (Buffer
, sizeof (Buffer
), L
"EFI DVD/CDROM");
911 UnicodeSPrint (Buffer
, sizeof (Buffer
), L
"EFI DVD/CDROM %d", CdromNumber
);
913 BdsLibBuildOptionFromHandle (BlockIoHandles
[Index
], BdsBootOptionList
, Buffer
);
917 case BDS_EFI_MESSAGE_USB_DEVICE_BOOT
:
918 if (UsbNumber
== 0) {
919 UnicodeSPrint (Buffer
, sizeof (Buffer
), L
"EFI USB Device");
921 UnicodeSPrint (Buffer
, sizeof (Buffer
), L
"EFI USB Device %d", UsbNumber
);
923 BdsLibBuildOptionFromHandle (BlockIoHandles
[Index
], BdsBootOptionList
, Buffer
);
927 case BDS_EFI_MESSAGE_SCSI_BOOT
:
928 if (UsbNumber
== 0) {
929 UnicodeSPrint (Buffer
, sizeof (Buffer
), L
"EFI SCSI Device");
931 UnicodeSPrint (Buffer
, sizeof (Buffer
), L
"EFI SCSI Device %d", UsbNumber
);
933 BdsLibBuildOptionFromHandle (BlockIoHandles
[Index
], BdsBootOptionList
, Buffer
);
937 case BDS_EFI_MESSAGE_MISC_BOOT
:
938 if (MiscNumber
== 0) {
939 UnicodeSPrint (Buffer
, sizeof (Buffer
), L
"EFI Misc Device");
941 UnicodeSPrint (Buffer
, sizeof (Buffer
), L
"EFI Misc Device %d", MiscNumber
);
943 BdsLibBuildOptionFromHandle (BlockIoHandles
[Index
], BdsBootOptionList
, Buffer
);
952 if (NumberBlockIoHandles
!= 0) {
953 gBS
->FreePool (BlockIoHandles
);
957 // If there is simple file protocol which does not consume block Io protocol, create a boot option for it here.
960 gBS
->LocateHandleBuffer (
962 &gEfiSimpleFileSystemProtocolGuid
,
964 &NumberFileSystemHandles
,
967 for (Index
= 0; Index
< NumberFileSystemHandles
; Index
++) {
968 Status
= gBS
->HandleProtocol (
969 FileSystemHandles
[Index
],
970 &gEfiBlockIoProtocolGuid
,
973 if (!EFI_ERROR (Status
)) {
975 // Skip if the file system handle supports a BlkIo protocol,
981 // Do the removable Media thing. \EFI\BOOT\boot{machinename}.EFI
982 // machinename is ia32, ia64, x64, ...
984 Hdr
.Union
= &HdrData
;
986 Status
= BdsLibGetImageHeader (
987 FileSystemHandles
[Index
],
988 DEFAULT_REMOVABLE_FILE_NAME
,
992 if (!EFI_ERROR (Status
) &&
993 EFI_IMAGE_MACHINE_TYPE_SUPPORTED (Hdr
.Pe32
->FileHeader
.Machine
) &&
994 Hdr
.Pe32
->OptionalHeader
.Subsystem
== EFI_IMAGE_SUBSYSTEM_EFI_APPLICATION
) {
1000 // No such file or the file is not a EFI application, delete this boot option
1002 BdsLibDeleteOptionFromHandle (FileSystemHandles
[Index
]);
1004 if (NonBlockNumber
== 0) {
1005 UnicodeSPrint (Buffer
, sizeof (Buffer
), L
"EFI Non-Block Boot Device");
1007 UnicodeSPrint (Buffer
, sizeof (Buffer
), L
"EFI Non-Block Boot Device %d", NonBlockNumber
);
1009 BdsLibBuildOptionFromHandle (FileSystemHandles
[Index
], BdsBootOptionList
, Buffer
);
1014 if (NumberFileSystemHandles
!= 0) {
1015 gBS
->FreePool (FileSystemHandles
);
1019 // Parse Network Boot Device
1021 gBS
->LocateHandleBuffer (
1023 &gEfiSimpleNetworkProtocolGuid
,
1025 &NumberSimpleNetworkHandles
,
1026 &SimpleNetworkHandles
1028 for (Index
= 0; Index
< NumberSimpleNetworkHandles
; Index
++) {
1030 UnicodeSPrint (Buffer
, sizeof (Buffer
), L
"EFI Network");
1032 UnicodeSPrint (Buffer
, sizeof (Buffer
), L
"EFI Network %d", Index
);
1034 BdsLibBuildOptionFromHandle (SimpleNetworkHandles
[Index
], BdsBootOptionList
, Buffer
);
1037 if (NumberSimpleNetworkHandles
!= 0) {
1038 gBS
->FreePool (SimpleNetworkHandles
);
1042 // Check if we have on flash shell
1044 gBS
->LocateHandleBuffer (
1046 &gEfiFirmwareVolume2ProtocolGuid
,
1051 for (Index
= 0; Index
< FvHandleCount
; Index
++) {
1053 // Only care the dispatched FV. If no dispatch protocol on the FV, it is not dispatched, then skip it.
1055 Status
= gBS
->HandleProtocol (
1056 FvHandleBuffer
[Index
],
1057 &gEfiFirmwareVolumeDispatchProtocolGuid
,
1060 if (EFI_ERROR (Status
)) {
1064 gBS
->HandleProtocol (
1065 FvHandleBuffer
[Index
],
1066 &gEfiFirmwareVolume2ProtocolGuid
,
1070 Status
= Fv
->ReadFile (
1077 &AuthenticationStatus
1079 if (EFI_ERROR (Status
)) {
1081 // Skip if no shell file in the FV
1086 // Build the shell boot option
1088 BdsLibBuildOptionFromShell (FvHandleBuffer
[Index
], BdsBootOptionList
);
1091 if (FvHandleCount
!= 0) {
1092 gBS
->FreePool (FvHandleBuffer
);
1095 // Make sure every boot only have one time
1096 // boot device enumerate
1098 BdsLibBuildOptionFromVar (BdsBootOptionList
, L
"BootOrder");
1099 mEnumBootDevice
= TRUE
;
1106 Build the boot option with the handle parsed in.
1108 @param Handle The handle which present the device path to create
1110 @param BdsBootOptionList The header of the link list which indexed all
1111 current boot options
1112 @param String Boot option name.
1117 BdsLibBuildOptionFromHandle (
1118 IN EFI_HANDLE Handle
,
1119 IN LIST_ENTRY
*BdsBootOptionList
,
1123 EFI_DEVICE_PATH_PROTOCOL
*DevicePath
;
1125 DevicePath
= DevicePathFromHandle (Handle
);
1128 // Create and register new boot option
1130 BdsLibRegisterNewOption (BdsBootOptionList
, DevicePath
, String
, L
"BootOrder");
1135 Build the on flash shell boot option with the handle parsed in.
1137 @param Handle The handle which present the device path to create
1138 on flash shell boot option
1139 @param BdsBootOptionList The header of the link list which indexed all
1140 current boot options
1145 BdsLibBuildOptionFromShell (
1146 IN EFI_HANDLE Handle
,
1147 IN OUT LIST_ENTRY
*BdsBootOptionList
1150 EFI_DEVICE_PATH_PROTOCOL
*DevicePath
;
1151 MEDIA_FW_VOL_FILEPATH_DEVICE_PATH ShellNode
;
1153 DevicePath
= DevicePathFromHandle (Handle
);
1156 // Build the shell device path
1158 EfiInitializeFwVolDevicepathNode (&ShellNode
, &gEfiShellFileGuid
);
1160 //ShellNode.Header.Type = MEDIA_DEVICE_PATH;
1161 //ShellNode.Header.SubType = MEDIA_FV_FILEPATH_DP;
1162 //SetDevicePathNodeLength (&ShellNode.Header, sizeof (MEDIA_FW_VOL_FILEPATH_DEVICE_PATH));
1163 //CopyMem (&ShellNode.NameGuid, &gEfiShellFileGuid, sizeof (EFI_GUID));
1165 DevicePath
= AppendDevicePathNode (DevicePath
, (EFI_DEVICE_PATH_PROTOCOL
*) &ShellNode
);
1168 // Create and register the shell boot option
1170 BdsLibRegisterNewOption (BdsBootOptionList
, DevicePath
, L
"EFI Internal Shell", L
"BootOrder");
1176 Boot from the EFI1.1 spec defined "BootNext" variable
1188 BDS_COMMON_OPTION
*BootOption
;
1189 LIST_ENTRY TempList
;
1194 // Init the boot option name buffer and temp link list
1196 InitializeListHead (&TempList
);
1197 ZeroMem (Buffer
, sizeof (Buffer
));
1199 BootNext
= BdsLibGetVariableAndSize (
1201 &gEfiGlobalVariableGuid
,
1206 // Clear the boot next variable first
1208 if (BootNext
!= NULL
) {
1211 &gEfiGlobalVariableGuid
,
1212 EFI_VARIABLE_BOOTSERVICE_ACCESS
| EFI_VARIABLE_RUNTIME_ACCESS
| EFI_VARIABLE_NON_VOLATILE
,
1218 // Start to build the boot option and try to boot
1220 UnicodeSPrint (Buffer
, sizeof (Buffer
), L
"Boot%04x", *BootNext
);
1221 BootOption
= BdsLibVariableToOption (&TempList
, Buffer
);
1222 BdsLibConnectDevicePath (BootOption
->DevicePath
);
1223 BdsLibBootViaBootOption (BootOption
, BootOption
->DevicePath
, &ExitDataSize
, &ExitData
);
1231 Return the bootable media handle.
1232 First, check the device is connected
1233 Second, check whether the device path point to a device which support SimpleFileSystemProtocol,
1234 Third, detect the the default boot file in the Media, and return the removable Media handle.
1236 @param DevicePath Device Path to a bootable device
1238 @retval NULL The device path points to an EFI bootable Media
1239 @retval NULL The media on the DevicePath is not bootable
1244 BdsLibGetBootableHandle (
1245 IN EFI_DEVICE_PATH_PROTOCOL
*DevicePath
1249 EFI_DEVICE_PATH_PROTOCOL
*UpdatedDevicePath
;
1250 EFI_DEVICE_PATH_PROTOCOL
*DupDevicePath
;
1252 EFI_BLOCK_IO_PROTOCOL
*BlockIo
;
1254 EFI_DEVICE_PATH_PROTOCOL
*TempDevicePath
;
1257 EFI_HANDLE ReturnHandle
;
1258 EFI_HANDLE
*SimpleFileSystemHandles
;
1260 UINTN NumberSimpleFileSystemHandles
;
1262 EFI_IMAGE_DOS_HEADER DosHeader
;
1263 EFI_IMAGE_OPTIONAL_HEADER_UNION HdrData
;
1264 EFI_IMAGE_OPTIONAL_HEADER_PTR_UNION Hdr
;
1266 UpdatedDevicePath
= DevicePath
;
1268 // Check whether the device is connected
1270 Status
= gBS
->LocateDevicePath (&gEfiBlockIoProtocolGuid
, &UpdatedDevicePath
, &Handle
);
1271 if (EFI_ERROR (Status
)) {
1273 // Skip the case that the boot option point to a simple file protocol which does not consume block Io protocol,
1275 Status
= gBS
->LocateDevicePath (&gEfiSimpleFileSystemProtocolGuid
, &UpdatedDevicePath
, &Handle
);
1276 if (EFI_ERROR (Status
)) {
1278 // Fail to find the proper BlockIo and simple file protocol, maybe because device not present, we need to connect it firstly
1280 UpdatedDevicePath
= DevicePath
;
1281 Status
= gBS
->LocateDevicePath (&gEfiDevicePathProtocolGuid
, &UpdatedDevicePath
, &Handle
);
1282 gBS
->ConnectController (Handle
, NULL
, NULL
, TRUE
);
1286 // Get BlockIo protocal and check removable attribute
1288 Status
= gBS
->HandleProtocol (Handle
, &gEfiBlockIoProtocolGuid
, (VOID
**)&BlockIo
);
1290 // Issue a dummy read to the device to check for media change.
1291 // When the removable media is changed, any Block IO read/write will
1292 // cause the BlockIo protocol be reinstalled and EFI_MEDIA_CHANGED is
1293 // returned. After the Block IO protocol is reinstalled, subsequent
1294 // Block IO read/write will success.
1296 Buffer
= AllocatePool (BlockIo
->Media
->BlockSize
);
1297 if (Buffer
!= NULL
) {
1298 BlockIo
->ReadBlocks (
1300 BlockIo
->Media
->MediaId
,
1302 BlockIo
->Media
->BlockSize
,
1305 gBS
->FreePool (Buffer
);
1310 // Detect the the default boot file from removable Media
1314 // 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
1315 // Try to locate the USB node device path first, if fail then use its previour PCI node to search
1317 DupDevicePath
= DuplicateDevicePath (DevicePath
);
1318 UpdatedDevicePath
= DupDevicePath
;
1319 Status
= gBS
->LocateDevicePath (&gEfiDevicePathProtocolGuid
, &UpdatedDevicePath
, &Handle
);
1321 // 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
1322 // Acpi()/Pci()/Usb() --> Acpi()/Pci()
1324 if ((DevicePathType (UpdatedDevicePath
) == MESSAGING_DEVICE_PATH
) &&
1325 (DevicePathSubType (UpdatedDevicePath
) == MSG_USB_DP
)) {
1327 // Remove the usb node, let the device path only point to PCI node
1329 SetDevicePathEndNode (UpdatedDevicePath
);
1330 UpdatedDevicePath
= DupDevicePath
;
1332 UpdatedDevicePath
= DevicePath
;
1336 // Get the device path size of boot option
1338 Size
= GetDevicePathSize(UpdatedDevicePath
) - sizeof (EFI_DEVICE_PATH_PROTOCOL
); // minus the end node
1339 ReturnHandle
= NULL
;
1340 gBS
->LocateHandleBuffer (
1342 &gEfiSimpleFileSystemProtocolGuid
,
1344 &NumberSimpleFileSystemHandles
,
1345 &SimpleFileSystemHandles
1347 for (Index
= 0; Index
< NumberSimpleFileSystemHandles
; Index
++) {
1349 // Get the device path size of SimpleFileSystem handle
1351 TempDevicePath
= DevicePathFromHandle (SimpleFileSystemHandles
[Index
]);
1352 TempSize
= GetDevicePathSize (TempDevicePath
)- sizeof (EFI_DEVICE_PATH_PROTOCOL
); // minus the end node
1354 // Check whether the device path of boot option is part of the SimpleFileSystem handle's device path
1356 if (Size
<= TempSize
&& CompareMem (TempDevicePath
, UpdatedDevicePath
, Size
)==0) {
1358 // Load the default boot file \EFI\BOOT\boot{machinename}.EFI from removable Media
1359 // machinename is ia32, ia64, x64, ...
1361 Hdr
.Union
= &HdrData
;
1362 Status
= BdsLibGetImageHeader (
1363 SimpleFileSystemHandles
[Index
],
1364 DEFAULT_REMOVABLE_FILE_NAME
,
1368 if (!EFI_ERROR (Status
) &&
1369 EFI_IMAGE_MACHINE_TYPE_SUPPORTED (Hdr
.Pe32
->FileHeader
.Machine
) &&
1370 Hdr
.Pe32
->OptionalHeader
.Subsystem
== EFI_IMAGE_SUBSYSTEM_EFI_APPLICATION
) {
1371 ReturnHandle
= SimpleFileSystemHandles
[Index
];
1377 if (DupDevicePath
!= NULL
) {
1378 SafeFreePool(DupDevicePath
);
1380 if (SimpleFileSystemHandles
!=NULL
) {
1381 gBS
->FreePool (SimpleFileSystemHandles
);
1384 return ReturnHandle
;
1391 Check to see if the network cable is plugged in. If the DevicePath is not
1392 connected it will be connected.
1394 @param DevicePath Device Path to check
1396 @retval TRUE DevicePath points to an Network that is connected
1397 @retval FALSE DevicePath does not point to a bootable network
1401 BdsLibNetworkBootWithMediaPresent (
1402 IN EFI_DEVICE_PATH_PROTOCOL
*DevicePath
1406 EFI_DEVICE_PATH_PROTOCOL
*UpdatedDevicePath
;
1408 EFI_SIMPLE_NETWORK_PROTOCOL
*Snp
;
1409 BOOLEAN MediaPresent
;
1411 MediaPresent
= FALSE
;
1413 UpdatedDevicePath
= DevicePath
;
1414 Status
= gBS
->LocateDevicePath (&gEfiSimpleNetworkProtocolGuid
, &UpdatedDevicePath
, &Handle
);
1415 if (EFI_ERROR (Status
)) {
1417 // Device not present so see if we need to connect it
1419 Status
= BdsLibConnectDevicePath (DevicePath
);
1420 if (!EFI_ERROR (Status
)) {
1422 // This one should work after we did the connect
1424 Status
= gBS
->LocateDevicePath (&gEfiSimpleNetworkProtocolGuid
, &UpdatedDevicePath
, &Handle
);
1428 if (!EFI_ERROR (Status
)) {
1429 Status
= gBS
->HandleProtocol (Handle
, &gEfiSimpleNetworkProtocolGuid
, (VOID
**)&Snp
);
1430 if (!EFI_ERROR (Status
)) {
1431 if (Snp
->Mode
->MediaPresentSupported
) {
1432 if (Snp
->Mode
->State
== EfiSimpleNetworkInitialized
) {
1434 // In case some one else is using the SNP check to see if it's connected
1436 MediaPresent
= Snp
->Mode
->MediaPresent
;
1439 // No one is using SNP so we need to Start and Initialize so
1440 // MediaPresent will be valid.
1442 Status
= Snp
->Start (Snp
);
1443 if (!EFI_ERROR (Status
)) {
1444 Status
= Snp
->Initialize (Snp
, 0, 0);
1445 if (!EFI_ERROR (Status
)) {
1446 MediaPresent
= Snp
->Mode
->MediaPresent
;
1447 Snp
->Shutdown (Snp
);
1453 MediaPresent
= TRUE
;
1458 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
;
1559 Check whether the Device path in a boot option point to a valide bootable device,
1560 And if CheckMedia is true, check the device is ready to boot now.
1562 @param DevPath -- the Device path in a boot option
1563 @param CheckMedia -- if true, check the device is ready to boot now.
1565 @return TRUE -- the Device path is valide
1566 @return FALSE -- the Device path is invalide .
1571 BdsLibIsValidEFIBootOptDevicePath (
1572 IN EFI_DEVICE_PATH_PROTOCOL
*DevPath
,
1573 IN BOOLEAN CheckMedia
1578 EFI_DEVICE_PATH_PROTOCOL
*TempDevicePath
;
1579 EFI_DEVICE_PATH_PROTOCOL
*LastDeviceNode
;
1580 EFI_BLOCK_IO_PROTOCOL
*BlockIo
;
1582 TempDevicePath
= DevPath
;
1583 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
,
1606 if (!EFI_ERROR (Status
)) {
1609 // Test if it is ready to boot now
1611 if (BdsLibNetworkBootWithMediaPresent(DevPath
)) {
1620 // If the boot option point to a file, it is a valid EFI boot option,
1621 // and assume it is ready to boot now
1623 while (!EfiIsDevicePathEnd (TempDevicePath
)) {
1624 LastDeviceNode
= TempDevicePath
;
1625 TempDevicePath
= EfiNextDevicePathNode (TempDevicePath
);
1627 if ((DevicePathType (LastDeviceNode
) == MEDIA_DEVICE_PATH
) &&
1628 (DevicePathSubType (LastDeviceNode
) == MEDIA_FILEPATH_DP
)) {
1633 // Check if it's a valid boot option for internal Shell
1635 if (EfiGetNameGuidFromFwVolDevicePathNode ((MEDIA_FW_VOL_FILEPATH_DEVICE_PATH
*) LastDeviceNode
) != NULL
) {
1637 // If the boot option point to Internal FV shell, make sure it is valid
1639 TempDevicePath
= DevPath
;
1640 Status
= BdsLibUpdateFvFileDevicePath (&TempDevicePath
, &gEfiShellFileGuid
);
1641 if (Status
== EFI_ALREADY_STARTED
) {
1644 if (Status
== EFI_SUCCESS
) {
1645 gBS
->FreePool (TempDevicePath
);
1652 // 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
1654 TempDevicePath
= DevPath
;
1655 Status
= gBS
->LocateDevicePath (&gEfiBlockIoProtocolGuid
, &TempDevicePath
, &Handle
);
1656 if (EFI_ERROR (Status
)) {
1658 // Device not present so see if we need to connect it
1660 Status
= BdsLibConnectDevicePath (DevPath
);
1661 if (!EFI_ERROR (Status
)) {
1663 // Try again to get the Block Io protocol after we did the connect
1665 TempDevicePath
= DevPath
;
1666 Status
= gBS
->LocateDevicePath (&gEfiBlockIoProtocolGuid
, &TempDevicePath
, &Handle
);
1669 if (!EFI_ERROR (Status
)) {
1670 Status
= gBS
->HandleProtocol (Handle
, &gEfiBlockIoProtocolGuid
, (VOID
**)&BlockIo
);
1671 if (!EFI_ERROR (Status
)) {
1674 // Test if it is ready to boot now
1676 if (BdsLibGetBootableHandle (DevPath
) != NULL
) {
1685 // 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,
1687 Status
= gBS
->LocateDevicePath (&gEfiSimpleFileSystemProtocolGuid
, &TempDevicePath
, &Handle
);
1688 if (!EFI_ERROR (Status
)) {
1691 // Test if it is ready to boot now
1693 if (BdsLibGetBootableHandle (DevPath
) != NULL
) {
1707 According to a file guild, check a Fv file device path is valid. If it is invalid,
1708 try to return the valid device path.
1709 FV address maybe changes for memory layout adjust from time to time, use this funciton
1710 could promise the Fv file device path is right.
1712 @param DevicePath on input, the Fv file device path need to check on
1713 output, the updated valid Fv file device path
1714 @param FileGuid the Fv file guild
1716 @retval EFI_INVALID_PARAMETER the input DevicePath or FileGuid is invalid
1718 @retval EFI_UNSUPPORTED the input DevicePath does not contain Fv file
1720 @retval EFI_ALREADY_STARTED the input DevicePath has pointed to Fv file, it is
1722 @retval EFI_SUCCESS has successfully updated the invalid DevicePath,
1723 and return the updated device path in DevicePath
1728 BdsLibUpdateFvFileDevicePath (
1729 IN OUT EFI_DEVICE_PATH_PROTOCOL
** DevicePath
,
1730 IN EFI_GUID
*FileGuid
1733 EFI_DEVICE_PATH_PROTOCOL
*TempDevicePath
;
1734 EFI_DEVICE_PATH_PROTOCOL
*LastDeviceNode
;
1736 EFI_GUID
*GuidPoint
;
1738 UINTN FvHandleCount
;
1739 EFI_HANDLE
*FvHandleBuffer
;
1740 EFI_FV_FILETYPE Type
;
1742 EFI_FV_FILE_ATTRIBUTES Attributes
;
1743 UINT32 AuthenticationStatus
;
1745 EFI_LOADED_IMAGE_PROTOCOL
*LoadedImage
;
1746 EFI_FIRMWARE_VOLUME2_PROTOCOL
*Fv
;
1747 MEDIA_FW_VOL_FILEPATH_DEVICE_PATH FvFileNode
;
1748 EFI_HANDLE FoundFvHandle
;
1749 EFI_DEVICE_PATH_PROTOCOL
*NewDevicePath
;
1751 if ((DevicePath
== NULL
) || (*DevicePath
== NULL
)) {
1752 return EFI_INVALID_PARAMETER
;
1754 if (FileGuid
== NULL
) {
1755 return EFI_INVALID_PARAMETER
;
1758 // Check whether the device path point to the default the input Fv file
1760 TempDevicePath
= *DevicePath
;
1761 LastDeviceNode
= TempDevicePath
;
1762 while (!EfiIsDevicePathEnd (TempDevicePath
)) {
1763 LastDeviceNode
= TempDevicePath
;
1764 TempDevicePath
= EfiNextDevicePathNode (TempDevicePath
);
1766 GuidPoint
= EfiGetNameGuidFromFwVolDevicePathNode (
1767 (MEDIA_FW_VOL_FILEPATH_DEVICE_PATH
*) LastDeviceNode
1769 if (GuidPoint
== NULL
) {
1771 // if this option does not points to a Fv file, just return EFI_UNSUPPORTED
1773 return EFI_UNSUPPORTED
;
1775 if (!CompareGuid (GuidPoint
, FileGuid
)) {
1777 // If the Fv file is not the input file guid, just return EFI_UNSUPPORTED
1779 return EFI_UNSUPPORTED
;
1783 // Check whether the input Fv file device path is valid
1785 TempDevicePath
= *DevicePath
;
1786 FoundFvHandle
= NULL
;
1787 Status
= gBS
->LocateDevicePath (
1788 &gEfiFirmwareVolume2ProtocolGuid
,
1792 if (!EFI_ERROR (Status
)) {
1793 Status
= gBS
->HandleProtocol (
1795 &gEfiFirmwareVolume2ProtocolGuid
,
1798 if (!EFI_ERROR (Status
)) {
1800 // Set FV ReadFile Buffer as NULL, only need to check whether input Fv file exist there
1802 Status
= Fv
->ReadFile (
1809 &AuthenticationStatus
1811 if (!EFI_ERROR (Status
)) {
1812 return EFI_ALREADY_STARTED
;
1818 // Look for the input wanted FV file in current FV
1819 // First, try to look for in Bds own FV. Bds and input wanted FV file usually are in the same FV
1822 FoundFvHandle
= NULL
;
1823 Status
= gBS
->HandleProtocol (
1825 &gEfiLoadedImageProtocolGuid
,
1826 (VOID
**) &LoadedImage
1828 if (!EFI_ERROR (Status
)) {
1829 Status
= gBS
->HandleProtocol (
1830 LoadedImage
->DeviceHandle
,
1831 &gEfiFirmwareVolume2ProtocolGuid
,
1834 if (!EFI_ERROR (Status
)) {
1835 Status
= Fv
->ReadFile (
1842 &AuthenticationStatus
1844 if (!EFI_ERROR (Status
)) {
1846 FoundFvHandle
= LoadedImage
->DeviceHandle
;
1851 // Second, if fail to find, try to enumerate all FV
1854 FvHandleBuffer
= NULL
;
1855 gBS
->LocateHandleBuffer (
1857 &gEfiFirmwareVolume2ProtocolGuid
,
1862 for (Index
= 0; Index
< FvHandleCount
; Index
++) {
1863 gBS
->HandleProtocol (
1864 FvHandleBuffer
[Index
],
1865 &gEfiFirmwareVolume2ProtocolGuid
,
1869 Status
= Fv
->ReadFile (
1876 &AuthenticationStatus
1878 if (EFI_ERROR (Status
)) {
1880 // Skip if input Fv file not in the FV
1885 FoundFvHandle
= FvHandleBuffer
[Index
];
1888 if (FvHandleBuffer
!=NULL
) {
1889 FreePool (FvHandleBuffer
);
1895 // Build the shell device path
1897 NewDevicePath
= DevicePathFromHandle (FoundFvHandle
);
1898 EfiInitializeFwVolDevicepathNode (&FvFileNode
, FileGuid
);
1899 NewDevicePath
= AppendDevicePathNode (NewDevicePath
, (EFI_DEVICE_PATH_PROTOCOL
*) &FvFileNode
);
1900 *DevicePath
= NewDevicePath
;
1903 return EFI_NOT_FOUND
;