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 EVT_SIGNAL_READY_TO_BOOT or
124 // EVT_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 EVT_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");
187 // free the temporary device path created by BdsLibUpdateFvFileDevicePath()
189 SafeFreePool (DevicePath
);
190 DevicePath
= Option
->DevicePath
;
193 DEBUG ((DEBUG_INFO
| DEBUG_LOAD
, "Booting %S\n", Option
->Description
));
195 Status
= gBS
->LoadImage (
205 // If we didn't find an image directly, we need to try as if it is a removable device boot opotion
206 // and load the image according to the default boot behavior for removable device.
208 if (EFI_ERROR (Status
)) {
210 // check if there is a bootable removable media could be found in this device path ,
211 // and get the bootable media handle
213 Handle
= BdsLibGetBootableHandle(DevicePath
);
214 if (Handle
== NULL
) {
218 // Load the default boot file \EFI\BOOT\boot{machinename}.EFI from removable Media
219 // machinename is ia32, ia64, x64, ...
221 FilePath
= FileDevicePath (Handle
, (CONST CHAR16
*)PcdGetPtr(PcdDefaultBootFileName
));
222 if (FilePath
!= NULL
) {
223 Status
= gBS
->LoadImage (
231 if (EFI_ERROR (Status
)) {
233 // The DevicePath failed, and it's not a valid
234 // removable media device.
241 if (EFI_ERROR (Status
)) {
243 // It there is any error from the Boot attempt exit now.
248 // Provide the image with it's load options
250 Status
= gBS
->HandleProtocol (ImageHandle
, &gEfiLoadedImageProtocolGuid
, (VOID
**) &ImageInfo
);
251 ASSERT_EFI_ERROR (Status
);
253 if (Option
->LoadOptionsSize
!= 0) {
254 ImageInfo
->LoadOptionsSize
= Option
->LoadOptionsSize
;
255 ImageInfo
->LoadOptions
= Option
->LoadOptions
;
258 // Before calling the image, enable the Watchdog Timer for
259 // the 5 Minute period
261 gBS
->SetWatchdogTimer (5 * 60, 0x0000, 0x00, NULL
);
263 Status
= gBS
->StartImage (ImageHandle
, ExitDataSize
, ExitData
);
264 DEBUG ((DEBUG_INFO
| DEBUG_LOAD
, "Image Return Status = %r\n", Status
));
267 // Clear the Watchdog Timer after the image returns
269 gBS
->SetWatchdogTimer (0x0000, 0x0000, 0x0000, NULL
);
273 // Clear Boot Current
277 &gEfiGlobalVariableGuid
,
278 EFI_VARIABLE_BOOTSERVICE_ACCESS
| EFI_VARIABLE_RUNTIME_ACCESS
,
288 Expand a device path that starts with a hard drive media device path node to be a
289 full device path that includes the full hardware path to the device. We need
290 to do this so it can be booted. As an optimizaiton the front match (the part point
291 to the partition node. E.g. ACPI() /PCI()/ATA()/Partition() ) is saved in a variable
292 so a connect all is not required on every boot. All successful history device path
293 which point to partition node (the front part) will be saved.
295 @param HardDriveDevicePath EFI Device Path to boot, if it starts with a hard
296 drive media device path.
297 @return A Pointer to the full device path or NULL if a valid Hard Drive devic path
301 EFI_DEVICE_PATH_PROTOCOL
*
303 BdsExpandPartitionPartialDevicePathToFull (
304 IN HARDDRIVE_DEVICE_PATH
*HardDriveDevicePath
308 UINTN BlockIoHandleCount
;
309 EFI_HANDLE
*BlockIoBuffer
;
310 EFI_DEVICE_PATH_PROTOCOL
*FullDevicePath
;
311 EFI_DEVICE_PATH_PROTOCOL
*BlockIoDevicePath
;
312 EFI_DEVICE_PATH_PROTOCOL
*DevicePath
;
315 EFI_DEVICE_PATH_PROTOCOL
*CachedDevicePath
;
316 EFI_DEVICE_PATH_PROTOCOL
*TempNewDevicePath
;
317 UINTN CachedDevicePathSize
;
320 EFI_DEVICE_PATH_PROTOCOL
*Instance
;
323 FullDevicePath
= NULL
;
325 // Check if there is prestore 'HDDP' variable.
326 // If exist, search the front path which point to partition node in the variable instants.
327 // If fail to find or 'HDDP' not exist, reconnect all and search in all system
329 CachedDevicePath
= BdsLibGetVariableAndSize (
331 &mHdBootVariablePrivateGuid
,
332 &CachedDevicePathSize
335 if (CachedDevicePath
!= NULL
) {
336 TempNewDevicePath
= CachedDevicePath
;
341 // Check every instance of the variable
342 // First, check wheather the instance contain the partition node, which is needed for distinguishing multi
343 // partial partition boot option. Second, check wheather the instance could be connected.
345 Instance
= GetNextDevicePathInstance (&TempNewDevicePath
, &Size
);
346 if (MatchPartitionDevicePathNode (Instance
, HardDriveDevicePath
)) {
348 // Connect the device path instance, the device path point to hard drive media device path node
349 // e.g. ACPI() /PCI()/ATA()/Partition()
351 Status
= BdsLibConnectDevicePath (Instance
);
352 if (!EFI_ERROR (Status
)) {
358 // Come here means the first instance is not matched
361 SafeFreePool(Instance
);
362 } while (TempNewDevicePath
!= NULL
);
366 // Find the matched device path.
367 // Append the file path infomration from the boot option and return the fully expanded device path.
369 DevicePath
= NextDevicePathNode ((EFI_DEVICE_PATH_PROTOCOL
*) HardDriveDevicePath
);
370 FullDevicePath
= AppendDevicePath (Instance
, DevicePath
);
373 // Adjust the 'HDDP' instances sequense if the matched one is not first one.
377 // First delete the matched instance.
379 TempNewDevicePath
= CachedDevicePath
;
380 CachedDevicePath
= BdsLibDelPartMatchInstance (CachedDevicePath
, Instance
);
381 SafeFreePool (TempNewDevicePath
);
384 // Second, append the remaining parth after the matched instance
386 TempNewDevicePath
= CachedDevicePath
;
387 CachedDevicePath
= AppendDevicePathInstance (Instance
, CachedDevicePath
);
388 SafeFreePool (TempNewDevicePath
);
390 // Save the matching Device Path so we don't need to do a connect all next time
392 Status
= gRT
->SetVariable (
394 &mHdBootVariablePrivateGuid
,
395 EFI_VARIABLE_BOOTSERVICE_ACCESS
| EFI_VARIABLE_RUNTIME_ACCESS
| EFI_VARIABLE_NON_VOLATILE
,
396 GetDevicePathSize (CachedDevicePath
),
401 SafeFreePool (Instance
);
402 SafeFreePool (CachedDevicePath
);
403 return FullDevicePath
;
408 // If we get here we fail to find or 'HDDP' not exist, and now we need
409 // to seach all devices in the system for a matched partition
411 BdsLibConnectAllDriversToAllControllers ();
412 Status
= gBS
->LocateHandleBuffer (ByProtocol
, &gEfiBlockIoProtocolGuid
, NULL
, &BlockIoHandleCount
, &BlockIoBuffer
);
413 if (EFI_ERROR (Status
) || BlockIoHandleCount
== 0) {
415 // If there was an error or there are no device handles that support
416 // the BLOCK_IO Protocol, then return.
421 // Loop through all the device handles that support the BLOCK_IO Protocol
423 for (Index
= 0; Index
< BlockIoHandleCount
; Index
++) {
425 Status
= gBS
->HandleProtocol (BlockIoBuffer
[Index
], &gEfiDevicePathProtocolGuid
, (VOID
*) &BlockIoDevicePath
);
426 if (EFI_ERROR (Status
) || BlockIoDevicePath
== NULL
) {
430 if (MatchPartitionDevicePathNode (BlockIoDevicePath
, HardDriveDevicePath
)) {
432 // Find the matched partition device path
434 DevicePath
= NextDevicePathNode ((EFI_DEVICE_PATH_PROTOCOL
*) HardDriveDevicePath
);
435 FullDevicePath
= AppendDevicePath (BlockIoDevicePath
, DevicePath
);
438 // Save the matched patition device path in 'HDDP' variable
440 if (CachedDevicePath
!= NULL
) {
442 // Save the matched patition device path as first instance of 'HDDP' variable
444 if (BdsLibMatchDevicePaths (CachedDevicePath
, BlockIoDevicePath
)) {
445 TempNewDevicePath
= CachedDevicePath
;
446 CachedDevicePath
= BdsLibDelPartMatchInstance (CachedDevicePath
, BlockIoDevicePath
);
447 SafeFreePool(TempNewDevicePath
);
449 TempNewDevicePath
= CachedDevicePath
;
450 CachedDevicePath
= AppendDevicePathInstance (BlockIoDevicePath
, CachedDevicePath
);
451 SafeFreePool(TempNewDevicePath
);
453 TempNewDevicePath
= CachedDevicePath
;
454 CachedDevicePath
= AppendDevicePathInstance (BlockIoDevicePath
, CachedDevicePath
);
455 SafeFreePool(TempNewDevicePath
);
458 // Here limit the device path instance number to 12, which is max number for a system support 3 IDE controller
459 // If the user try to boot many OS in different HDs or partitions, in theary, the 'HDDP' variable maybe become larger and larger.
462 TempNewDevicePath
= CachedDevicePath
;
463 while (!IsDevicePathEnd (TempNewDevicePath
)) {
464 TempNewDevicePath
= NextDevicePathNode (TempNewDevicePath
);
466 // Parse one instance
468 while (!IsDevicePathEndType (TempNewDevicePath
)) {
469 TempNewDevicePath
= NextDevicePathNode (TempNewDevicePath
);
473 // If the CachedDevicePath variable contain too much instance, only remain 12 instances.
475 if (InstanceNum
>= 12) {
476 SetDevicePathEndNode (TempNewDevicePath
);
481 CachedDevicePath
= DuplicateDevicePath (BlockIoDevicePath
);
485 // Save the matching Device Path so we don't need to do a connect all next time
487 Status
= gRT
->SetVariable (
489 &mHdBootVariablePrivateGuid
,
490 EFI_VARIABLE_BOOTSERVICE_ACCESS
| EFI_VARIABLE_RUNTIME_ACCESS
| EFI_VARIABLE_NON_VOLATILE
,
491 GetDevicePathSize (CachedDevicePath
),
499 SafeFreePool (CachedDevicePath
);
500 SafeFreePool (BlockIoBuffer
);
501 return FullDevicePath
;
505 Check whether there is a instance in BlockIoDevicePath, which contain multi device path
506 instances, has the same partition node with HardDriveDevicePath device path
508 @param BlockIoDevicePath Multi device path instances which need to check
509 @param HardDriveDevicePath A device path which starts with a hard drive media
512 @retval TRUE There is a matched device path instance FALSE
513 @retval FALSE There is no matched device path instance
518 MatchPartitionDevicePathNode (
519 IN EFI_DEVICE_PATH_PROTOCOL
*BlockIoDevicePath
,
520 IN HARDDRIVE_DEVICE_PATH
*HardDriveDevicePath
523 HARDDRIVE_DEVICE_PATH
*TmpHdPath
;
524 HARDDRIVE_DEVICE_PATH
*TempPath
;
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
;
560 TempPath
= (HARDDRIVE_DEVICE_PATH
*) BdsLibUnpackDevicePath ((EFI_DEVICE_PATH_PROTOCOL
*) HardDriveDevicePath
);
564 // Check for the match
566 if ((TmpHdPath
->MBRType
== TempPath
->MBRType
) &&
567 (TmpHdPath
->SignatureType
== TempPath
->SignatureType
)) {
568 switch (TmpHdPath
->SignatureType
) {
569 case SIGNATURE_TYPE_GUID
:
570 Match
= CompareGuid ((EFI_GUID
*)TmpHdPath
->Signature
, (EFI_GUID
*)TempPath
->Signature
);
572 case SIGNATURE_TYPE_MBR
:
573 Match
= (BOOLEAN
)(*((UINT32
*)(&(TmpHdPath
->Signature
[0]))) == *(UINT32
*)(&(TempPath
->Signature
[0])));
585 Delete the boot option associated with the handle passed in.
587 @param Handle The handle which present the device path to create
590 @retval EFI_SUCCESS Delete the boot option success
591 @retval EFI_NOT_FOUND If the Device Path is not found in the system
592 @retval EFI_OUT_OF_RESOURCES Lack of memory resource
593 @retval Other Error return value from SetVariable()
597 BdsLibDeleteOptionFromHandle (
602 UINT8
*BootOptionVar
;
604 UINTN BootOptionSize
;
607 UINT16 BootOption
[BOOT_OPTION_MAX_CHAR
];
608 UINTN DevicePathSize
;
609 UINTN OptionDevicePathSize
;
610 EFI_DEVICE_PATH_PROTOCOL
*DevicePath
;
611 EFI_DEVICE_PATH_PROTOCOL
*OptionDevicePath
;
614 Status
= EFI_SUCCESS
;
619 // Check "BootOrder" variable, if no, means there is no any boot order.
621 BootOrder
= BdsLibGetVariableAndSize (
623 &gEfiGlobalVariableGuid
,
626 if (BootOrder
== NULL
) {
627 return EFI_NOT_FOUND
;
631 // Convert device handle to device path protocol instance
633 DevicePath
= DevicePathFromHandle (Handle
);
634 if (DevicePath
== NULL
) {
635 return EFI_NOT_FOUND
;
637 DevicePathSize
= GetDevicePathSize (DevicePath
);
640 // Loop all boot order variable and find the matching device path
643 while (Index
< BootOrderSize
/ sizeof (UINT16
)) {
644 UnicodeSPrint (BootOption
, sizeof (BootOption
), L
"Boot%04x", BootOrder
[Index
]);
645 BootOptionVar
= BdsLibGetVariableAndSize (
647 &gEfiGlobalVariableGuid
,
651 if (BootOptionVar
== NULL
) {
652 SafeFreePool (BootOrder
);
653 return EFI_OUT_OF_RESOURCES
;
656 TempPtr
= BootOptionVar
;
657 TempPtr
+= sizeof (UINT32
) + sizeof (UINT16
);
658 TempPtr
+= StrSize ((CHAR16
*) TempPtr
);
659 OptionDevicePath
= (EFI_DEVICE_PATH_PROTOCOL
*) TempPtr
;
660 OptionDevicePathSize
= GetDevicePathSize (OptionDevicePath
);
663 // Check whether the device path match
665 if ((OptionDevicePathSize
== DevicePathSize
) &&
666 (CompareMem (DevicePath
, OptionDevicePath
, DevicePathSize
) == 0)) {
667 BdsDeleteBootOption (BootOrder
[Index
], BootOrder
, &BootOrderSize
);
668 SafeFreePool (BootOptionVar
);
672 SafeFreePool (BootOptionVar
);
677 // Adjust number of boot option for "BootOrder" variable.
679 Status
= gRT
->SetVariable (
681 &gEfiGlobalVariableGuid
,
682 EFI_VARIABLE_BOOTSERVICE_ACCESS
| EFI_VARIABLE_RUNTIME_ACCESS
| EFI_VARIABLE_NON_VOLATILE
,
687 SafeFreePool (BootOrder
);
694 Delete all invalid EFI boot options. The probable invalid boot option could
695 be Removable media or Network boot device.
697 @retval EFI_SUCCESS Delete all invalid boot option success
698 @retval EFI_NOT_FOUND Variable "BootOrder" is not found
699 @retval EFI_OUT_OF_RESOURCES Lack of memory resource
700 @retval Other Error return value from SetVariable()
704 BdsDeleteAllInvalidEfiBootOption (
709 UINT8
*BootOptionVar
;
711 UINTN BootOptionSize
;
715 UINT16 BootOption
[BOOT_OPTION_MAX_CHAR
];
716 EFI_DEVICE_PATH_PROTOCOL
*OptionDevicePath
;
719 Status
= EFI_SUCCESS
;
724 // Check "BootOrder" variable firstly, this variable hold the number of boot options
726 BootOrder
= BdsLibGetVariableAndSize (
728 &gEfiGlobalVariableGuid
,
731 if (NULL
== BootOrder
) {
732 return EFI_NOT_FOUND
;
736 while (Index
< BootOrderSize
/ sizeof (UINT16
)) {
737 UnicodeSPrint (BootOption
, sizeof (BootOption
), L
"Boot%04x", BootOrder
[Index
]);
738 BootOptionVar
= BdsLibGetVariableAndSize (
740 &gEfiGlobalVariableGuid
,
743 if (NULL
== BootOptionVar
) {
744 SafeFreePool (BootOrder
);
745 return EFI_OUT_OF_RESOURCES
;
748 TempPtr
= BootOptionVar
;
749 TempPtr
+= sizeof (UINT32
) + sizeof (UINT16
);
750 TempPtr
+= StrSize ((CHAR16
*) TempPtr
);
751 OptionDevicePath
= (EFI_DEVICE_PATH_PROTOCOL
*) TempPtr
;
754 // Skip legacy boot option (BBS boot device)
756 if ((DevicePathType (OptionDevicePath
) == BBS_DEVICE_PATH
) &&
757 (DevicePathSubType (OptionDevicePath
) == BBS_BBS_DP
)) {
758 SafeFreePool (BootOptionVar
);
763 if (!BdsLibIsValidEFIBootOptDevicePath (OptionDevicePath
, FALSE
)) {
765 // Delete this invalid boot option "Boot####"
767 Status
= gRT
->SetVariable (
769 &gEfiGlobalVariableGuid
,
770 EFI_VARIABLE_BOOTSERVICE_ACCESS
| EFI_VARIABLE_RUNTIME_ACCESS
| EFI_VARIABLE_NON_VOLATILE
,
775 // Mark this boot option in boot order as deleted
777 BootOrder
[Index
] = 0xffff;
780 SafeFreePool (BootOptionVar
);
785 // Adjust boot order array
788 for (Index
= 0; Index
< BootOrderSize
/ sizeof (UINT16
); Index
++) {
789 if (BootOrder
[Index
] != 0xffff) {
790 BootOrder
[Index2
] = BootOrder
[Index
];
794 Status
= gRT
->SetVariable (
796 &gEfiGlobalVariableGuid
,
797 EFI_VARIABLE_BOOTSERVICE_ACCESS
| EFI_VARIABLE_RUNTIME_ACCESS
| EFI_VARIABLE_NON_VOLATILE
,
798 Index2
* sizeof (UINT16
),
802 SafeFreePool (BootOrder
);
809 This function will enumerate all possible boot device in the system,
810 it will only excute once of every boot.
812 @param BdsBootOptionList The header of the link list which indexed all
815 @retval EFI_SUCCESS Finished all the boot device enumerate and create
816 the boot option base on that boot device
821 BdsLibEnumerateAllBootOption (
822 IN OUT LIST_ENTRY
*BdsBootOptionList
830 UINT16 NonBlockNumber
;
831 UINTN NumberBlockIoHandles
;
832 EFI_HANDLE
*BlockIoHandles
;
833 EFI_BLOCK_IO_PROTOCOL
*BlkIo
;
835 UINTN NumberSimpleNetworkHandles
;
836 EFI_HANDLE
*SimpleNetworkHandles
;
838 EFI_HANDLE
*FvHandleBuffer
;
839 EFI_FV_FILETYPE Type
;
841 EFI_FV_FILE_ATTRIBUTES Attributes
;
842 UINT32 AuthenticationStatus
;
843 EFI_FIRMWARE_VOLUME2_PROTOCOL
*Fv
;
844 EFI_DEVICE_PATH_PROTOCOL
*DevicePath
;
845 UINTN DevicePathType
;
847 EFI_HANDLE
*FileSystemHandles
;
848 UINTN NumberFileSystemHandles
;
850 EFI_IMAGE_DOS_HEADER DosHeader
;
851 EFI_IMAGE_OPTIONAL_HEADER_UNION HdrData
;
852 EFI_IMAGE_OPTIONAL_HEADER_PTR_UNION Hdr
;
858 ZeroMem (Buffer
, sizeof (Buffer
));
861 // If the boot device enumerate happened, just get the boot
862 // device from the boot order variable
864 if (mEnumBootDevice
) {
865 BdsLibBuildOptionFromVar (BdsBootOptionList
, L
"BootOrder");
870 // Notes: this dirty code is to get the legacy boot option from the
871 // BBS table and create to variable as the EFI boot option, it should
872 // be removed after the CSM can provide legacy boot option directly
874 REFRESH_LEGACY_BOOT_OPTIONS
;
877 // Delete invalid boot option
879 BdsDeleteAllInvalidEfiBootOption ();
882 // Parse removable media
884 gBS
->LocateHandleBuffer (
886 &gEfiBlockIoProtocolGuid
,
888 &NumberBlockIoHandles
,
892 for (Index
= 0; Index
< NumberBlockIoHandles
; Index
++) {
893 Status
= gBS
->HandleProtocol (
894 BlockIoHandles
[Index
],
895 &gEfiBlockIoProtocolGuid
,
898 if (!EFI_ERROR (Status
)) {
899 if (!BlkIo
->Media
->RemovableMedia
) {
901 // skip the non-removable block devices
906 DevicePath
= DevicePathFromHandle (BlockIoHandles
[Index
]);
907 DevicePathType
= BdsGetBootTypeFromDevicePath (DevicePath
);
909 switch (DevicePathType
) {
910 case BDS_EFI_ACPI_FLOPPY_BOOT
:
911 if (FloppyNumber
== 0) {
912 UnicodeSPrint (Buffer
, sizeof (Buffer
), L
"EFI Floppy");
914 UnicodeSPrint (Buffer
, sizeof (Buffer
), L
"EFI Floppy %d", FloppyNumber
);
916 BdsLibBuildOptionFromHandle (BlockIoHandles
[Index
], BdsBootOptionList
, Buffer
);
920 case BDS_EFI_MESSAGE_ATAPI_BOOT
:
921 if (CdromNumber
== 0) {
922 UnicodeSPrint (Buffer
, sizeof (Buffer
), L
"EFI DVD/CDROM");
924 UnicodeSPrint (Buffer
, sizeof (Buffer
), L
"EFI DVD/CDROM %d", CdromNumber
);
926 BdsLibBuildOptionFromHandle (BlockIoHandles
[Index
], BdsBootOptionList
, Buffer
);
930 case BDS_EFI_MESSAGE_USB_DEVICE_BOOT
:
931 if (UsbNumber
== 0) {
932 UnicodeSPrint (Buffer
, sizeof (Buffer
), L
"EFI USB Device");
934 UnicodeSPrint (Buffer
, sizeof (Buffer
), L
"EFI USB Device %d", UsbNumber
);
936 BdsLibBuildOptionFromHandle (BlockIoHandles
[Index
], BdsBootOptionList
, Buffer
);
940 case BDS_EFI_MESSAGE_SCSI_BOOT
:
941 if (UsbNumber
== 0) {
942 UnicodeSPrint (Buffer
, sizeof (Buffer
), L
"EFI SCSI Device");
944 UnicodeSPrint (Buffer
, sizeof (Buffer
), L
"EFI SCSI Device %d", UsbNumber
);
946 BdsLibBuildOptionFromHandle (BlockIoHandles
[Index
], BdsBootOptionList
, Buffer
);
950 case BDS_EFI_MESSAGE_MISC_BOOT
:
951 if (MiscNumber
== 0) {
952 UnicodeSPrint (Buffer
, sizeof (Buffer
), L
"EFI Misc Device");
954 UnicodeSPrint (Buffer
, sizeof (Buffer
), L
"EFI Misc Device %d", MiscNumber
);
956 BdsLibBuildOptionFromHandle (BlockIoHandles
[Index
], BdsBootOptionList
, Buffer
);
965 if (NumberBlockIoHandles
!= 0) {
966 SafeFreePool (BlockIoHandles
);
970 // If there is simple file protocol which does not consume block Io protocol, create a boot option for it here.
973 gBS
->LocateHandleBuffer (
975 &gEfiSimpleFileSystemProtocolGuid
,
977 &NumberFileSystemHandles
,
980 for (Index
= 0; Index
< NumberFileSystemHandles
; Index
++) {
981 Status
= gBS
->HandleProtocol (
982 FileSystemHandles
[Index
],
983 &gEfiBlockIoProtocolGuid
,
986 if (!EFI_ERROR (Status
)) {
988 // Skip if the file system handle supports a BlkIo protocol,
994 // Do the removable Media thing. \EFI\BOOT\boot{machinename}.EFI
995 // machinename is ia32, ia64, x64, ...
997 Hdr
.Union
= &HdrData
;
999 Status
= BdsLibGetImageHeader (
1000 FileSystemHandles
[Index
],
1001 (CHAR16
*)PcdGetPtr (PcdDefaultBootFileName
),
1005 if (!EFI_ERROR (Status
) &&
1006 EFI_IMAGE_MACHINE_TYPE_SUPPORTED (Hdr
.Pe32
->FileHeader
.Machine
) &&
1007 Hdr
.Pe32
->OptionalHeader
.Subsystem
== EFI_IMAGE_SUBSYSTEM_EFI_APPLICATION
) {
1013 // No such file or the file is not a EFI application, delete this boot option
1015 BdsLibDeleteOptionFromHandle (FileSystemHandles
[Index
]);
1017 if (NonBlockNumber
== 0) {
1018 UnicodeSPrint (Buffer
, sizeof (Buffer
), L
"EFI Non-Block Boot Device");
1020 UnicodeSPrint (Buffer
, sizeof (Buffer
), L
"EFI Non-Block Boot Device %d", NonBlockNumber
);
1022 BdsLibBuildOptionFromHandle (FileSystemHandles
[Index
], BdsBootOptionList
, Buffer
);
1027 if (NumberFileSystemHandles
!= 0) {
1028 SafeFreePool (FileSystemHandles
);
1032 // Parse Network Boot Device
1034 gBS
->LocateHandleBuffer (
1036 &gEfiSimpleNetworkProtocolGuid
,
1038 &NumberSimpleNetworkHandles
,
1039 &SimpleNetworkHandles
1041 for (Index
= 0; Index
< NumberSimpleNetworkHandles
; Index
++) {
1043 UnicodeSPrint (Buffer
, sizeof (Buffer
), L
"EFI Network");
1045 UnicodeSPrint (Buffer
, sizeof (Buffer
), L
"EFI Network %d", Index
);
1047 BdsLibBuildOptionFromHandle (SimpleNetworkHandles
[Index
], BdsBootOptionList
, Buffer
);
1050 if (NumberSimpleNetworkHandles
!= 0) {
1051 SafeFreePool (SimpleNetworkHandles
);
1055 // Check if we have on flash shell
1057 gBS
->LocateHandleBuffer (
1059 &gEfiFirmwareVolume2ProtocolGuid
,
1064 for (Index
= 0; Index
< FvHandleCount
; Index
++) {
1066 // Only care the dispatched FV. If no dispatch protocol on the FV, it is not dispatched, then skip it.
1068 Status
= gBS
->HandleProtocol (
1069 FvHandleBuffer
[Index
],
1070 &gEfiFirmwareVolumeDispatchProtocolGuid
,
1073 if (EFI_ERROR (Status
)) {
1077 gBS
->HandleProtocol (
1078 FvHandleBuffer
[Index
],
1079 &gEfiFirmwareVolume2ProtocolGuid
,
1083 Status
= Fv
->ReadFile (
1090 &AuthenticationStatus
1092 if (EFI_ERROR (Status
)) {
1094 // Skip if no shell file in the FV
1099 // Build the shell boot option
1101 BdsLibBuildOptionFromShell (FvHandleBuffer
[Index
], BdsBootOptionList
);
1104 if (FvHandleCount
!= 0) {
1105 SafeFreePool (FvHandleBuffer
);
1108 // Make sure every boot only have one time
1109 // boot device enumerate
1111 BdsLibBuildOptionFromVar (BdsBootOptionList
, L
"BootOrder");
1112 mEnumBootDevice
= TRUE
;
1118 Build the boot option with the handle parsed in.
1120 @param Handle The handle which present the device path to create
1122 @param BdsBootOptionList The header of the link list which indexed all
1123 current boot options
1124 @param String Boot option name.
1129 BdsLibBuildOptionFromHandle (
1130 IN EFI_HANDLE Handle
,
1131 IN LIST_ENTRY
*BdsBootOptionList
,
1135 EFI_DEVICE_PATH_PROTOCOL
*DevicePath
;
1137 DevicePath
= DevicePathFromHandle (Handle
);
1140 // Create and register new boot option
1142 BdsLibRegisterNewOption (BdsBootOptionList
, DevicePath
, String
, L
"BootOrder");
1147 Build the on flash shell boot option with the handle parsed in.
1149 @param Handle The handle which present the device path to create
1150 on flash shell boot option
1151 @param BdsBootOptionList The header of the link list which indexed all
1152 current boot options
1157 BdsLibBuildOptionFromShell (
1158 IN EFI_HANDLE Handle
,
1159 IN OUT LIST_ENTRY
*BdsBootOptionList
1162 EFI_DEVICE_PATH_PROTOCOL
*DevicePath
;
1163 MEDIA_FW_VOL_FILEPATH_DEVICE_PATH ShellNode
;
1165 DevicePath
= DevicePathFromHandle (Handle
);
1168 // Build the shell device path
1170 EfiInitializeFwVolDevicepathNode (&ShellNode
, &gEfiShellFileGuid
);
1172 DevicePath
= AppendDevicePathNode (DevicePath
, (EFI_DEVICE_PATH_PROTOCOL
*) &ShellNode
);
1175 // Create and register the shell boot option
1177 BdsLibRegisterNewOption (BdsBootOptionList
, DevicePath
, L
"EFI Internal Shell", L
"BootOrder");
1182 Boot from the EFI1.1 spec defined "BootNext" variable
1194 BDS_COMMON_OPTION
*BootOption
;
1195 LIST_ENTRY TempList
;
1200 // Init the boot option name buffer and temp link list
1202 InitializeListHead (&TempList
);
1203 ZeroMem (Buffer
, sizeof (Buffer
));
1205 BootNext
= BdsLibGetVariableAndSize (
1207 &gEfiGlobalVariableGuid
,
1212 // Clear the boot next variable first
1214 if (BootNext
!= NULL
) {
1217 &gEfiGlobalVariableGuid
,
1218 EFI_VARIABLE_BOOTSERVICE_ACCESS
| EFI_VARIABLE_RUNTIME_ACCESS
| EFI_VARIABLE_NON_VOLATILE
,
1224 // Start to build the boot option and try to boot
1226 UnicodeSPrint (Buffer
, sizeof (Buffer
), L
"Boot%04x", *BootNext
);
1227 BootOption
= BdsLibVariableToOption (&TempList
, Buffer
);
1228 BdsLibConnectDevicePath (BootOption
->DevicePath
);
1229 BdsLibBootViaBootOption (BootOption
, BootOption
->DevicePath
, &ExitDataSize
, &ExitData
);
1235 Return the bootable media handle.
1236 First, check the device is connected
1237 Second, check whether the device path point to a device which support SimpleFileSystemProtocol,
1238 Third, detect the the default boot file in the Media, and return the removable Media handle.
1240 @param DevicePath Device Path to a bootable device
1242 @retval NULL The device path points to an EFI bootable Media
1243 @retval NULL The media on the DevicePath is not bootable
1248 BdsLibGetBootableHandle (
1249 IN EFI_DEVICE_PATH_PROTOCOL
*DevicePath
1253 EFI_DEVICE_PATH_PROTOCOL
*UpdatedDevicePath
;
1254 EFI_DEVICE_PATH_PROTOCOL
*DupDevicePath
;
1256 EFI_BLOCK_IO_PROTOCOL
*BlockIo
;
1258 EFI_DEVICE_PATH_PROTOCOL
*TempDevicePath
;
1261 EFI_HANDLE ReturnHandle
;
1262 EFI_HANDLE
*SimpleFileSystemHandles
;
1264 UINTN NumberSimpleFileSystemHandles
;
1266 EFI_IMAGE_DOS_HEADER DosHeader
;
1267 EFI_IMAGE_OPTIONAL_HEADER_UNION HdrData
;
1268 EFI_IMAGE_OPTIONAL_HEADER_PTR_UNION Hdr
;
1270 UpdatedDevicePath
= DevicePath
;
1273 // Check whether the device is connected
1275 Status
= gBS
->LocateDevicePath (&gEfiBlockIoProtocolGuid
, &UpdatedDevicePath
, &Handle
);
1276 if (EFI_ERROR (Status
)) {
1278 // Skip the case that the boot option point to a simple file protocol which does not consume block Io protocol,
1280 Status
= gBS
->LocateDevicePath (&gEfiSimpleFileSystemProtocolGuid
, &UpdatedDevicePath
, &Handle
);
1281 if (EFI_ERROR (Status
)) {
1283 // Fail to find the proper BlockIo and simple file protocol, maybe because device not present, we need to connect it firstly
1285 UpdatedDevicePath
= DevicePath
;
1286 Status
= gBS
->LocateDevicePath (&gEfiDevicePathProtocolGuid
, &UpdatedDevicePath
, &Handle
);
1287 gBS
->ConnectController (Handle
, NULL
, NULL
, TRUE
);
1291 // Get BlockIo protocal and check removable attribute
1293 Status
= gBS
->HandleProtocol (Handle
, &gEfiBlockIoProtocolGuid
, (VOID
**)&BlockIo
);
1295 // Issue a dummy read to the device to check for media change.
1296 // When the removable media is changed, any Block IO read/write will
1297 // cause the BlockIo protocol be reinstalled and EFI_MEDIA_CHANGED is
1298 // returned. After the Block IO protocol is reinstalled, subsequent
1299 // Block IO read/write will success.
1301 Buffer
= AllocatePool (BlockIo
->Media
->BlockSize
);
1302 if (Buffer
!= NULL
) {
1303 BlockIo
->ReadBlocks (
1305 BlockIo
->Media
->MediaId
,
1307 BlockIo
->Media
->BlockSize
,
1310 SafeFreePool(Buffer
);
1315 // Detect the the default boot file from removable Media
1319 // 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
1320 // Try to locate the USB node device path first, if fail then use its previour PCI node to search
1322 DupDevicePath
= DuplicateDevicePath (DevicePath
);
1323 UpdatedDevicePath
= DupDevicePath
;
1324 Status
= gBS
->LocateDevicePath (&gEfiDevicePathProtocolGuid
, &UpdatedDevicePath
, &Handle
);
1326 // 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
1327 // Acpi()/Pci()/Usb() --> Acpi()/Pci()
1329 if ((DevicePathType (UpdatedDevicePath
) == MESSAGING_DEVICE_PATH
) &&
1330 (DevicePathSubType (UpdatedDevicePath
) == MSG_USB_DP
)) {
1332 // Remove the usb node, let the device path only point to PCI node
1334 SetDevicePathEndNode (UpdatedDevicePath
);
1335 UpdatedDevicePath
= DupDevicePath
;
1337 UpdatedDevicePath
= DevicePath
;
1341 // Get the device path size of boot option
1343 Size
= GetDevicePathSize(UpdatedDevicePath
) - sizeof (EFI_DEVICE_PATH_PROTOCOL
); // minus the end node
1344 ReturnHandle
= NULL
;
1345 gBS
->LocateHandleBuffer (
1347 &gEfiSimpleFileSystemProtocolGuid
,
1349 &NumberSimpleFileSystemHandles
,
1350 &SimpleFileSystemHandles
1352 for (Index
= 0; Index
< NumberSimpleFileSystemHandles
; Index
++) {
1354 // Get the device path size of SimpleFileSystem handle
1356 TempDevicePath
= DevicePathFromHandle (SimpleFileSystemHandles
[Index
]);
1357 TempSize
= GetDevicePathSize (TempDevicePath
)- sizeof (EFI_DEVICE_PATH_PROTOCOL
); // minus the end node
1359 // Check whether the device path of boot option is part of the SimpleFileSystem handle's device path
1361 if (Size
<= TempSize
&& CompareMem (TempDevicePath
, UpdatedDevicePath
, Size
)==0) {
1363 // Load the default boot file \EFI\BOOT\boot{machinename}.EFI from removable Media
1364 // machinename is ia32, ia64, x64, ...
1366 Hdr
.Union
= &HdrData
;
1367 Status
= BdsLibGetImageHeader (
1368 SimpleFileSystemHandles
[Index
],
1369 (CHAR16
*)PcdGetPtr(PcdDefaultBootFileName
),
1373 if (!EFI_ERROR (Status
) &&
1374 EFI_IMAGE_MACHINE_TYPE_SUPPORTED (Hdr
.Pe32
->FileHeader
.Machine
) &&
1375 Hdr
.Pe32
->OptionalHeader
.Subsystem
== EFI_IMAGE_SUBSYSTEM_EFI_APPLICATION
) {
1376 ReturnHandle
= SimpleFileSystemHandles
[Index
];
1382 SafeFreePool(DupDevicePath
);
1384 SafeFreePool(SimpleFileSystemHandles
);
1386 return ReturnHandle
;
1390 Check to see if the network cable is plugged in. If the DevicePath is not
1391 connected it will be connected.
1393 @param DevicePath Device Path to check
1395 @retval TRUE DevicePath points to an Network that is connected
1396 @retval FALSE DevicePath does not point to a bootable network
1400 BdsLibNetworkBootWithMediaPresent (
1401 IN EFI_DEVICE_PATH_PROTOCOL
*DevicePath
1405 EFI_DEVICE_PATH_PROTOCOL
*UpdatedDevicePath
;
1407 EFI_SIMPLE_NETWORK_PROTOCOL
*Snp
;
1408 BOOLEAN MediaPresent
;
1410 MediaPresent
= FALSE
;
1412 UpdatedDevicePath
= DevicePath
;
1413 Status
= gBS
->LocateDevicePath (&gEfiSimpleNetworkProtocolGuid
, &UpdatedDevicePath
, &Handle
);
1414 if (EFI_ERROR (Status
)) {
1416 // Device not present so see if we need to connect it
1418 Status
= BdsLibConnectDevicePath (DevicePath
);
1419 if (!EFI_ERROR (Status
)) {
1421 // This one should work after we did the connect
1423 Status
= gBS
->LocateDevicePath (&gEfiSimpleNetworkProtocolGuid
, &UpdatedDevicePath
, &Handle
);
1427 if (!EFI_ERROR (Status
)) {
1428 Status
= gBS
->HandleProtocol (Handle
, &gEfiSimpleNetworkProtocolGuid
, (VOID
**)&Snp
);
1429 if (!EFI_ERROR (Status
)) {
1430 if (Snp
->Mode
->MediaPresentSupported
) {
1431 if (Snp
->Mode
->State
== EfiSimpleNetworkInitialized
) {
1433 // In case some one else is using the SNP check to see if it's connected
1435 MediaPresent
= Snp
->Mode
->MediaPresent
;
1438 // No one is using SNP so we need to Start and Initialize so
1439 // MediaPresent will be valid.
1441 Status
= Snp
->Start (Snp
);
1442 if (!EFI_ERROR (Status
)) {
1443 Status
= Snp
->Initialize (Snp
, 0, 0);
1444 if (!EFI_ERROR (Status
)) {
1445 MediaPresent
= Snp
->Mode
->MediaPresent
;
1446 Snp
->Shutdown (Snp
);
1452 MediaPresent
= TRUE
;
1457 return MediaPresent
;
1461 For a bootable Device path, return its boot type.
1463 @param DevicePath The bootable device Path to check
1465 @retval BDS_EFI_MEDIA_HD_BOOT If the device path contains any media deviec path node, it is media boot type
1466 For the floppy node, handle it as media node
1467 @retval BDS_EFI_MEDIA_CDROM_BOOT If the device path contains any media deviec path node, it is media boot type
1468 For the floppy node, handle it as media node
1469 @retval BDS_EFI_ACPI_FLOPPY_BOOT If the device path contains any media deviec path node, it is media boot type
1470 For the floppy node, handle it as media node
1471 @retval BDS_EFI_MESSAGE_ATAPI_BOOT If the device path not contains any media deviec path node, and
1472 its last device path node point to a message device path node, it is
1474 @retval BDS_EFI_MESSAGE_SCSI_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
1476 @retval BDS_EFI_MESSAGE_USB_DEVICE_BOOT If the device path not contains any media deviec path node, and
1477 its last device path node point to a message device path node, it is
1478 @retval BDS_EFI_MESSAGE_MISC_BOOT If the device path not contains any media deviec path node, and
1479 its last device path node point to a message device path node, it is
1480 @retval BDS_LEGACY_BBS_BOOT Legacy boot type
1481 @retval BDS_EFI_UNSUPPORT An EFI Removable BlockIO device path not point to a media and message devie,
1486 BdsGetBootTypeFromDevicePath (
1487 IN EFI_DEVICE_PATH_PROTOCOL
*DevicePath
1490 ACPI_HID_DEVICE_PATH
*Acpi
;
1491 EFI_DEVICE_PATH_PROTOCOL
*TempDevicePath
;
1492 EFI_DEVICE_PATH_PROTOCOL
*LastDeviceNode
;
1495 if (NULL
== DevicePath
) {
1496 return BDS_EFI_UNSUPPORT
;
1499 TempDevicePath
= DevicePath
;
1501 while (!IsDevicePathEndType (TempDevicePath
)) {
1502 switch (DevicePathType (TempDevicePath
)) {
1503 case BBS_DEVICE_PATH
:
1504 return BDS_LEGACY_BBS_BOOT
;
1505 case MEDIA_DEVICE_PATH
:
1506 if (DevicePathSubType (TempDevicePath
) == MEDIA_HARDDRIVE_DP
) {
1507 return BDS_EFI_MEDIA_HD_BOOT
;
1508 } else if (DevicePathSubType (TempDevicePath
) == MEDIA_CDROM_DP
) {
1509 return BDS_EFI_MEDIA_CDROM_BOOT
;
1512 case ACPI_DEVICE_PATH
:
1513 Acpi
= (ACPI_HID_DEVICE_PATH
*) TempDevicePath
;
1514 if (EISA_ID_TO_NUM (Acpi
->HID
) == 0x0604) {
1515 return BDS_EFI_ACPI_FLOPPY_BOOT
;
1518 case MESSAGING_DEVICE_PATH
:
1520 // Get the last device path node
1522 LastDeviceNode
= NextDevicePathNode (TempDevicePath
);
1523 if (DevicePathSubType(LastDeviceNode
) == MSG_DEVICE_LOGICAL_UNIT_DP
) {
1525 // if the next node type is Device Logical Unit, which specify the Logical Unit Number (LUN),
1528 LastDeviceNode
= NextDevicePathNode (LastDeviceNode
);
1531 // if the device path not only point to driver device, it is not a messaging device path,
1533 if (!IsDevicePathEndType (LastDeviceNode
)) {
1537 if (DevicePathSubType(TempDevicePath
) == MSG_ATAPI_DP
) {
1538 return BDS_EFI_MESSAGE_ATAPI_BOOT
;
1539 } else if (DevicePathSubType(TempDevicePath
) == MSG_USB_DP
) {
1540 return BDS_EFI_MESSAGE_USB_DEVICE_BOOT
;
1541 } else if (DevicePathSubType(TempDevicePath
) == MSG_SCSI_DP
) {
1542 return BDS_EFI_MESSAGE_SCSI_BOOT
;
1544 return BDS_EFI_MESSAGE_MISC_BOOT
;
1548 TempDevicePath
= NextDevicePathNode (TempDevicePath
);
1551 return BDS_EFI_UNSUPPORT
;
1555 Check whether the Device path in a boot option point to a valide bootable device,
1556 And if CheckMedia is true, check the device is ready to boot now.
1558 @param DevPath the Device path in a boot option
1559 @param CheckMedia if true, check the device is ready to boot now.
1561 @retval TRUE the Device path is valide
1562 @retval FALSE the Device path is invalide .
1567 BdsLibIsValidEFIBootOptDevicePath (
1568 IN EFI_DEVICE_PATH_PROTOCOL
*DevPath
,
1569 IN BOOLEAN CheckMedia
1574 EFI_DEVICE_PATH_PROTOCOL
*TempDevicePath
;
1575 EFI_DEVICE_PATH_PROTOCOL
*LastDeviceNode
;
1576 EFI_BLOCK_IO_PROTOCOL
*BlockIo
;
1578 TempDevicePath
= DevPath
;
1579 LastDeviceNode
= DevPath
;
1582 // Check if it's a valid boot option for network boot device
1583 // Only check if there is SimpleNetworkProtocol installed. If yes, that means
1584 // there is the network card there.
1586 Status
= gBS
->LocateDevicePath (
1587 &gEfiSimpleNetworkProtocolGuid
,
1591 if (EFI_ERROR (Status
)) {
1593 // Device not present so see if we need to connect it
1595 TempDevicePath
= DevPath
;
1596 BdsLibConnectDevicePath (TempDevicePath
);
1597 Status
= gBS
->LocateDevicePath (
1598 &gEfiSimpleNetworkProtocolGuid
,
1604 if (!EFI_ERROR (Status
)) {
1607 // Test if it is ready to boot now
1609 if (BdsLibNetworkBootWithMediaPresent(DevPath
)) {
1618 // If the boot option point to a file, it is a valid EFI boot option,
1619 // and assume it is ready to boot now
1621 while (!EfiIsDevicePathEnd (TempDevicePath
)) {
1622 LastDeviceNode
= TempDevicePath
;
1623 TempDevicePath
= EfiNextDevicePathNode (TempDevicePath
);
1625 if ((DevicePathType (LastDeviceNode
) == MEDIA_DEVICE_PATH
) &&
1626 (DevicePathSubType (LastDeviceNode
) == MEDIA_FILEPATH_DP
)) {
1631 // Check if it's a valid boot option for internal Shell
1633 if (EfiGetNameGuidFromFwVolDevicePathNode ((MEDIA_FW_VOL_FILEPATH_DEVICE_PATH
*) LastDeviceNode
) != NULL
) {
1635 // If the boot option point to Internal FV shell, make sure it is valid
1637 TempDevicePath
= DevPath
;
1638 Status
= BdsLibUpdateFvFileDevicePath (&TempDevicePath
, &gEfiShellFileGuid
);
1639 if (Status
== EFI_ALREADY_STARTED
) {
1642 if (Status
== EFI_SUCCESS
) {
1643 SafeFreePool (TempDevicePath
);
1650 // 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
1652 TempDevicePath
= DevPath
;
1653 Status
= gBS
->LocateDevicePath (&gEfiBlockIoProtocolGuid
, &TempDevicePath
, &Handle
);
1654 if (EFI_ERROR (Status
)) {
1656 // Device not present so see if we need to connect it
1658 Status
= BdsLibConnectDevicePath (DevPath
);
1659 if (!EFI_ERROR (Status
)) {
1661 // Try again to get the Block Io protocol after we did the connect
1663 TempDevicePath
= DevPath
;
1664 Status
= gBS
->LocateDevicePath (&gEfiBlockIoProtocolGuid
, &TempDevicePath
, &Handle
);
1668 if (!EFI_ERROR (Status
)) {
1669 Status
= gBS
->HandleProtocol (Handle
, &gEfiBlockIoProtocolGuid
, (VOID
**)&BlockIo
);
1670 if (!EFI_ERROR (Status
)) {
1673 // Test if it is ready to boot now
1675 if (BdsLibGetBootableHandle (DevPath
) != NULL
) {
1684 // 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,
1686 Status
= gBS
->LocateDevicePath (&gEfiSimpleFileSystemProtocolGuid
, &TempDevicePath
, &Handle
);
1687 if (!EFI_ERROR (Status
)) {
1690 // Test if it is ready to boot now
1692 if (BdsLibGetBootableHandle (DevPath
) != NULL
) {
1706 According to a file guild, check a Fv file device path is valid. If it is invalid,
1707 try to return the valid device path.
1708 FV address maybe changes for memory layout adjust from time to time, use this funciton
1709 could promise the Fv file device path is right.
1711 @param DevicePath on input, the Fv file device path need to check on
1712 output, the updated valid Fv file device path
1713 @param FileGuid the Fv file guild
1715 @retval EFI_INVALID_PARAMETER the input DevicePath or FileGuid is invalid
1717 @retval EFI_UNSUPPORTED the input DevicePath does not contain Fv file
1719 @retval EFI_ALREADY_STARTED the input DevicePath has pointed to Fv file, it is
1721 @retval EFI_SUCCESS has successfully updated the invalid DevicePath,
1722 and return the updated device path in DevicePath
1727 BdsLibUpdateFvFileDevicePath (
1728 IN OUT EFI_DEVICE_PATH_PROTOCOL
** DevicePath
,
1729 IN EFI_GUID
*FileGuid
1732 EFI_DEVICE_PATH_PROTOCOL
*TempDevicePath
;
1733 EFI_DEVICE_PATH_PROTOCOL
*LastDeviceNode
;
1735 EFI_GUID
*GuidPoint
;
1737 UINTN FvHandleCount
;
1738 EFI_HANDLE
*FvHandleBuffer
;
1739 EFI_FV_FILETYPE Type
;
1741 EFI_FV_FILE_ATTRIBUTES Attributes
;
1742 UINT32 AuthenticationStatus
;
1744 EFI_LOADED_IMAGE_PROTOCOL
*LoadedImage
;
1745 EFI_FIRMWARE_VOLUME2_PROTOCOL
*Fv
;
1746 MEDIA_FW_VOL_FILEPATH_DEVICE_PATH FvFileNode
;
1747 EFI_HANDLE FoundFvHandle
;
1748 EFI_DEVICE_PATH_PROTOCOL
*NewDevicePath
;
1750 if ((DevicePath
== NULL
) || (*DevicePath
== NULL
)) {
1751 return EFI_INVALID_PARAMETER
;
1753 if (FileGuid
== NULL
) {
1754 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
];
1889 SafeFreePool (FvHandleBuffer
);
1894 // Build the shell device path
1896 NewDevicePath
= DevicePathFromHandle (FoundFvHandle
);
1897 EfiInitializeFwVolDevicepathNode (&FvFileNode
, FileGuid
);
1898 NewDevicePath
= AppendDevicePathNode (NewDevicePath
, (EFI_DEVICE_PATH_PROTOCOL
*) &FvFileNode
);
1899 *DevicePath
= NewDevicePath
;
1902 return EFI_NOT_FOUND
;