2 BDS Lib functions which relate with create or process the boot option.
4 Copyright (c) 2004 - 2019, Intel Corporation. All rights reserved.<BR>
5 SPDX-License-Identifier: BSD-2-Clause-Patent
9 #include "InternalBdsLib.h"
11 #include <Library/NetLib.h>
12 #include "Library/DebugLib.h"
14 BOOLEAN mEnumBootDevice
= FALSE
;
15 EFI_HII_HANDLE gBdsLibStringPackHandle
= NULL
;
21 @param Event The triggered event.
22 @param Context Context for this event.
33 // Record the performance data for End of BDS
35 PERF_END(NULL
, "BDS", NULL
, 0);
41 The constructor function register UNI strings into imageHandle.
43 It will ASSERT() if that operation fails and it will always return EFI_SUCCESS.
45 @param ImageHandle The firmware allocated handle for the EFI image.
46 @param SystemTable A pointer to the EFI System Table.
48 @retval EFI_SUCCESS The constructor successfully added string package.
49 @retval Other value The constructor can't add string package.
54 GenericBdsLibConstructor (
55 IN EFI_HANDLE ImageHandle
,
56 IN EFI_SYSTEM_TABLE
*SystemTable
60 gBdsLibStringPackHandle
= HiiAddPackages (
61 &gBdsLibStringPackageGuid
,
67 ASSERT (gBdsLibStringPackHandle
!= NULL
);
73 Deletete the Boot Option from EFI Variable. The Boot Order Arrray
76 @param OptionNumber The number of Boot option want to be deleted.
77 @param BootOrder The Boot Order array.
78 @param BootOrderSize The size of the Boot Order Array.
80 @retval EFI_SUCCESS The Boot Option Variable was found and removed
81 @retval EFI_UNSUPPORTED The Boot Option Variable store was inaccessible
82 @retval EFI_NOT_FOUND The Boot Option Variable was not found
87 IN UINTN OptionNumber
,
88 IN OUT UINT16
*BootOrder
,
89 IN OUT UINTN
*BootOrderSize
96 UnicodeSPrint (BootOption
, sizeof (BootOption
), L
"Boot%04x", OptionNumber
);
97 Status
= gRT
->SetVariable (
99 &gEfiGlobalVariableGuid
,
105 // Deleting variable with existing variable implementation shouldn't fail.
107 ASSERT_EFI_ERROR (Status
);
110 // adjust boot order array
112 for (Index
= 0; Index
< *BootOrderSize
/ sizeof (UINT16
); Index
++) {
113 if (BootOrder
[Index
] == OptionNumber
) {
114 CopyMem (&BootOrder
[Index
], &BootOrder
[Index
+1], *BootOrderSize
- (Index
+1) * sizeof (UINT16
));
115 *BootOrderSize
-= sizeof (UINT16
);
124 Translate the first n characters of an Ascii string to
125 Unicode characters. The count n is indicated by parameter
126 Size. If Size is greater than the length of string, then
127 the entire string is translated.
130 @param AStr Pointer to input Ascii string.
131 @param Size The number of characters to translate.
132 @param UStr Pointer to output Unicode string buffer.
145 while (AStr
[Idx
] != 0) {
146 UStr
[Idx
] = (CHAR16
) AStr
[Idx
];
157 Build Legacy Device Name String according.
159 @param CurBBSEntry BBS Table.
161 @param BufSize The buffer size.
162 @param BootString The output string.
166 BdsBuildLegacyDevNameString (
167 IN BBS_TABLE
*CurBBSEntry
,
170 OUT CHAR16
*BootString
183 Fmt
= L
"Primary Master %s";
190 Fmt
= L
"Primary Slave %s";
197 Fmt
= L
"Secondary Master %s";
204 Fmt
= L
"Secondary Slave %s";
212 switch (CurBBSEntry
->DeviceType
) {
233 case BBS_EMBED_NETWORK
:
247 // If current BBS entry has its description then use it.
249 StringDesc
= (UINT8
*) (UINTN
) ((CurBBSEntry
->DescStringSegment
<< 4) + CurBBSEntry
->DescStringOffset
);
250 if (NULL
!= StringDesc
) {
252 // Only get fisrt 32 characters, this is suggested by BBS spec
254 AsciiToUnicodeSize (StringDesc
, 32, Temp
);
260 // BbsTable 16 entries are for onboard IDE.
261 // Set description string for SATA harddisks, Harddisk 0 ~ Harddisk 11
263 if (Index
>= 5 && Index
<= 16 && (CurBBSEntry
->DeviceType
== BBS_HARDDISK
|| CurBBSEntry
->DeviceType
== BBS_CDROM
)) {
265 UnicodeSPrint (BootString
, BufSize
, Fmt
, Type
, Index
- 5);
267 UnicodeSPrint (BootString
, BufSize
, Fmt
, Type
);
273 Create a legacy boot option for the specified entry of
274 BBS table, save it as variable, and append it to the boot
278 @param CurrentBbsEntry Pointer to current BBS table.
279 @param CurrentBbsDevPath Pointer to the Device Path Protocol instance of BBS
280 @param Index Index of the specified entry in BBS table.
281 @param BootOrderList On input, the original boot order list.
282 On output, the new boot order list attached with the
284 @param BootOrderListSize On input, the original size of boot order list.
285 On output, the size of new boot order list.
287 @retval EFI_SUCCESS Boot Option successfully created.
288 @retval EFI_OUT_OF_RESOURCES Fail to allocate necessary memory.
289 @retval Other Error occurs while setting variable.
293 BdsCreateLegacyBootOption (
294 IN BBS_TABLE
*CurrentBbsEntry
,
295 IN EFI_DEVICE_PATH_PROTOCOL
*CurrentBbsDevPath
,
297 IN OUT UINT16
**BootOrderList
,
298 IN OUT UINTN
*BootOrderListSize
302 UINT16 CurrentBootOptionNo
;
303 UINT16 BootString
[10];
304 CHAR16 BootDesc
[100];
305 CHAR8 HelpString
[100];
306 UINT16
*NewBootOrderList
;
311 UINT16 CurrentBbsDevPathSize
;
312 UINTN BootOrderIndex
;
313 UINTN BootOrderLastIndex
;
315 BOOLEAN IndexNotFound
;
316 BBS_BBS_DEVICE_PATH
*NewBbsDevPathNode
;
318 if ((*BootOrderList
) == NULL
) {
319 CurrentBootOptionNo
= 0;
321 for (ArrayIndex
= 0; ArrayIndex
< (UINTN
) (*BootOrderListSize
/ sizeof (UINT16
)); ArrayIndex
++) {
322 IndexNotFound
= TRUE
;
323 for (BootOrderIndex
= 0; BootOrderIndex
< (UINTN
) (*BootOrderListSize
/ sizeof (UINT16
)); BootOrderIndex
++) {
324 if ((*BootOrderList
)[BootOrderIndex
] == ArrayIndex
) {
325 IndexNotFound
= FALSE
;
330 if (!IndexNotFound
) {
337 CurrentBootOptionNo
= (UINT16
) ArrayIndex
;
347 BdsBuildLegacyDevNameString (CurrentBbsEntry
, Index
, sizeof (BootDesc
), BootDesc
);
350 // Create new BBS device path node with description string
352 UnicodeStrToAsciiStr (BootDesc
, HelpString
);
354 StringLen
= AsciiStrLen (HelpString
);
355 NewBbsDevPathNode
= AllocateZeroPool (sizeof (BBS_BBS_DEVICE_PATH
) + StringLen
);
356 if (NewBbsDevPathNode
== NULL
) {
357 return EFI_OUT_OF_RESOURCES
;
359 CopyMem (NewBbsDevPathNode
, CurrentBbsDevPath
, sizeof (BBS_BBS_DEVICE_PATH
));
360 CopyMem (NewBbsDevPathNode
->String
, HelpString
, StringLen
+ 1);
361 SetDevicePathNodeLength (&(NewBbsDevPathNode
->Header
), sizeof (BBS_BBS_DEVICE_PATH
) + StringLen
);
364 // Create entire new CurrentBbsDevPath with end node
366 CurrentBbsDevPath
= AppendDevicePathNode (
368 (EFI_DEVICE_PATH_PROTOCOL
*) NewBbsDevPathNode
370 if (CurrentBbsDevPath
== NULL
) {
371 FreePool (NewBbsDevPathNode
);
372 return EFI_OUT_OF_RESOURCES
;
375 CurrentBbsDevPathSize
= (UINT16
) (GetDevicePathSize (CurrentBbsDevPath
));
377 BufferSize
= sizeof (UINT32
) +
380 CurrentBbsDevPathSize
+
384 Buffer
= AllocateZeroPool (BufferSize
);
385 if (Buffer
== NULL
) {
386 FreePool (NewBbsDevPathNode
);
387 FreePool (CurrentBbsDevPath
);
388 return EFI_OUT_OF_RESOURCES
;
391 Ptr
= (UINT8
*) Buffer
;
393 *((UINT32
*) Ptr
) = LOAD_OPTION_ACTIVE
;
394 Ptr
+= sizeof (UINT32
);
396 *((UINT16
*) Ptr
) = CurrentBbsDevPathSize
;
397 Ptr
+= sizeof (UINT16
);
404 Ptr
+= StrSize (BootDesc
);
409 CurrentBbsDevPathSize
411 Ptr
+= CurrentBbsDevPathSize
;
419 Ptr
+= sizeof (BBS_TABLE
);
420 *((UINT16
*) Ptr
) = (UINT16
) Index
;
422 Status
= gRT
->SetVariable (
424 &gEfiGlobalVariableGuid
,
425 EFI_VARIABLE_BOOTSERVICE_ACCESS
| EFI_VARIABLE_RUNTIME_ACCESS
| EFI_VARIABLE_NON_VOLATILE
,
434 NewBootOrderList
= AllocateZeroPool (*BootOrderListSize
+ sizeof (UINT16
));
435 if (NULL
== NewBootOrderList
) {
436 FreePool (NewBbsDevPathNode
);
437 FreePool (CurrentBbsDevPath
);
438 return EFI_OUT_OF_RESOURCES
;
441 if (*BootOrderList
!= NULL
) {
442 CopyMem (NewBootOrderList
, *BootOrderList
, *BootOrderListSize
);
443 FreePool (*BootOrderList
);
446 BootOrderLastIndex
= (UINTN
) (*BootOrderListSize
/ sizeof (UINT16
));
447 NewBootOrderList
[BootOrderLastIndex
] = CurrentBootOptionNo
;
448 *BootOrderListSize
+= sizeof (UINT16
);
449 *BootOrderList
= NewBootOrderList
;
451 FreePool (NewBbsDevPathNode
);
452 FreePool (CurrentBbsDevPath
);
457 Check if the boot option is a legacy one.
459 @param BootOptionVar The boot option data payload.
460 @param BbsEntry The BBS Table.
461 @param BbsIndex The table index.
463 @retval TRUE It is a legacy boot option.
464 @retval FALSE It is not a legacy boot option.
468 BdsIsLegacyBootOption (
469 IN UINT8
*BootOptionVar
,
470 OUT BBS_TABLE
**BbsEntry
,
475 EFI_DEVICE_PATH_PROTOCOL
*DevicePath
;
480 Ptr
+= sizeof (UINT32
);
481 DevPathLen
= *(UINT16
*) Ptr
;
482 Ptr
+= sizeof (UINT16
);
483 Ptr
+= StrSize ((UINT16
*) Ptr
);
484 DevicePath
= (EFI_DEVICE_PATH_PROTOCOL
*) Ptr
;
485 if ((BBS_DEVICE_PATH
== DevicePath
->Type
) && (BBS_BBS_DP
== DevicePath
->SubType
)) {
487 *BbsEntry
= (BBS_TABLE
*) Ptr
;
488 Ptr
+= sizeof (BBS_TABLE
);
489 *BbsIndex
= *(UINT16
*) Ptr
;
500 Delete all the invalid legacy boot options.
502 @retval EFI_SUCCESS All invalide legacy boot options are deleted.
503 @retval EFI_OUT_OF_RESOURCES Fail to allocate necessary memory.
504 @retval EFI_NOT_FOUND Fail to retrive variable of boot order.
508 BdsDeleteAllInvalidLegacyBootOptions (
513 UINT8
*BootOptionVar
;
515 UINTN BootOptionSize
;
519 HDD_INFO
*LocalHddInfo
;
520 BBS_TABLE
*LocalBbsTable
;
523 EFI_LEGACY_BIOS_PROTOCOL
*LegacyBios
;
525 UINT16 BootOption
[10];
526 UINT16 BootDesc
[100];
527 BOOLEAN DescStringMatch
;
529 Status
= EFI_SUCCESS
;
535 LocalBbsTable
= NULL
;
538 Status
= gBS
->LocateProtocol (&gEfiLegacyBiosProtocolGuid
, NULL
, (VOID
**) &LegacyBios
);
539 if (EFI_ERROR (Status
)) {
543 BootOrder
= BdsLibGetVariableAndSize (
545 &gEfiGlobalVariableGuid
,
548 if (BootOrder
== NULL
) {
549 return EFI_NOT_FOUND
;
552 LegacyBios
->GetBbsInfo (
561 while (Index
< BootOrderSize
/ sizeof (UINT16
)) {
562 UnicodeSPrint (BootOption
, sizeof (BootOption
), L
"Boot%04x", BootOrder
[Index
]);
563 BootOptionVar
= BdsLibGetVariableAndSize (
565 &gEfiGlobalVariableGuid
,
568 if (NULL
== BootOptionVar
) {
570 Status
= gRT
->GetVariable (
572 &gEfiGlobalVariableGuid
,
577 if (Status
== EFI_NOT_FOUND
) {
581 BdsDeleteBootOption (
588 FreePool (BootOrder
);
589 return EFI_OUT_OF_RESOURCES
;
594 // Skip Non-Legacy boot option
596 if (!BdsIsLegacyBootOption (BootOptionVar
, &BbsEntry
, &BbsIndex
)) {
597 if (BootOptionVar
!= NULL
) {
598 FreePool (BootOptionVar
);
604 if (BbsIndex
< BbsCount
) {
606 // Check if BBS Description String is changed
608 DescStringMatch
= FALSE
;
609 BdsBuildLegacyDevNameString (
610 &LocalBbsTable
[BbsIndex
],
616 if (StrCmp (BootDesc
, (UINT16
*)(BootOptionVar
+ sizeof (UINT32
) + sizeof (UINT16
))) == 0) {
617 DescStringMatch
= TRUE
;
620 if (!((LocalBbsTable
[BbsIndex
].BootPriority
== BBS_IGNORE_ENTRY
) ||
621 (LocalBbsTable
[BbsIndex
].BootPriority
== BBS_DO_NOT_BOOT_FROM
)) &&
622 (LocalBbsTable
[BbsIndex
].DeviceType
== BbsEntry
->DeviceType
) &&
629 if (BootOptionVar
!= NULL
) {
630 FreePool (BootOptionVar
);
635 BdsDeleteBootOption (
643 // Adjust the number of boot options.
645 Status
= gRT
->SetVariable (
647 &gEfiGlobalVariableGuid
,
648 EFI_VARIABLE_BOOTSERVICE_ACCESS
| EFI_VARIABLE_RUNTIME_ACCESS
| EFI_VARIABLE_NON_VOLATILE
,
653 // Shrinking variable with existing variable implementation shouldn't fail.
655 ASSERT_EFI_ERROR (Status
);
656 FreePool (BootOrder
);
662 Find all legacy boot option by device type.
664 @param BootOrder The boot order array.
665 @param BootOptionNum The number of boot option.
666 @param DevType Device type.
667 @param DevName Device name.
668 @param Attribute The boot option attribute.
669 @param BbsIndex The BBS table index.
670 @param OptionNumber The boot option index.
672 @retval TRUE The Legacy boot option is found.
673 @retval FALSE The legacy boot option is not found.
677 BdsFindLegacyBootOptionByDevTypeAndName (
678 IN UINT16
*BootOrder
,
679 IN UINTN BootOptionNum
,
682 OUT UINT32
*Attribute
,
683 OUT UINT16
*BbsIndex
,
684 OUT UINT16
*OptionNumber
688 CHAR16 BootOption
[9];
689 UINTN BootOptionSize
;
690 UINT8
*BootOptionVar
;
697 if (NULL
== BootOrder
) {
702 // Loop all boot option from variable
704 for (Index
= 0; Index
< BootOptionNum
; Index
++) {
705 UnicodeSPrint (BootOption
, sizeof (BootOption
), L
"Boot%04x", (UINTN
) BootOrder
[Index
]);
706 BootOptionVar
= BdsLibGetVariableAndSize (
708 &gEfiGlobalVariableGuid
,
711 if (NULL
== BootOptionVar
) {
716 // Skip Non-legacy boot option
718 if (!BdsIsLegacyBootOption (BootOptionVar
, &BbsEntry
, BbsIndex
)) {
719 FreePool (BootOptionVar
);
724 (BbsEntry
->DeviceType
!= DevType
) ||
725 (StrCmp (DevName
, (CHAR16
*)(BootOptionVar
+ sizeof (UINT32
) + sizeof (UINT16
))) != 0)
727 FreePool (BootOptionVar
);
731 *Attribute
= *(UINT32
*) BootOptionVar
;
732 *OptionNumber
= BootOrder
[Index
];
734 FreePool (BootOptionVar
);
742 Create a legacy boot option.
744 @param BbsItem The BBS Table entry.
745 @param Index Index of the specified entry in BBS table.
746 @param BootOrderList The boot order list.
747 @param BootOrderListSize The size of boot order list.
749 @retval EFI_OUT_OF_RESOURCE No enough memory.
750 @retval EFI_SUCCESS The function complete successfully.
751 @return Other value if the legacy boot option is not created.
755 BdsCreateOneLegacyBootOption (
756 IN BBS_TABLE
*BbsItem
,
758 IN OUT UINT16
**BootOrderList
,
759 IN OUT UINTN
*BootOrderListSize
762 BBS_BBS_DEVICE_PATH BbsDevPathNode
;
764 EFI_DEVICE_PATH_PROTOCOL
*DevPath
;
769 // Create device path node.
771 BbsDevPathNode
.Header
.Type
= BBS_DEVICE_PATH
;
772 BbsDevPathNode
.Header
.SubType
= BBS_BBS_DP
;
773 SetDevicePathNodeLength (&BbsDevPathNode
.Header
, sizeof (BBS_BBS_DEVICE_PATH
));
774 BbsDevPathNode
.DeviceType
= BbsItem
->DeviceType
;
775 CopyMem (&BbsDevPathNode
.StatusFlag
, &BbsItem
->StatusFlags
, sizeof (UINT16
));
777 DevPath
= AppendDevicePathNode (
779 (EFI_DEVICE_PATH_PROTOCOL
*) &BbsDevPathNode
781 if (NULL
== DevPath
) {
782 return EFI_OUT_OF_RESOURCES
;
785 Status
= BdsCreateLegacyBootOption (
792 BbsItem
->BootPriority
= 0x00;
800 Add the legacy boot options from BBS table if they do not exist.
802 @retval EFI_SUCCESS The boot options are added successfully
803 or they are already in boot options.
804 @retval EFI_NOT_FOUND No legacy boot options is found.
805 @retval EFI_OUT_OF_RESOURCE No enough memory.
806 @return Other value LegacyBoot options are not added.
810 BdsAddNonExistingLegacyBootOptions (
820 HDD_INFO
*LocalHddInfo
;
821 BBS_TABLE
*LocalBbsTable
;
823 EFI_LEGACY_BIOS_PROTOCOL
*LegacyBios
;
832 LocalBbsTable
= NULL
;
834 Status
= gBS
->LocateProtocol (&gEfiLegacyBiosProtocolGuid
, NULL
, (VOID
**) &LegacyBios
);
835 if (EFI_ERROR (Status
)) {
839 LegacyBios
->GetBbsInfo (
847 BootOrder
= BdsLibGetVariableAndSize (
849 &gEfiGlobalVariableGuid
,
852 if (BootOrder
== NULL
) {
856 for (Index
= 0; Index
< BbsCount
; Index
++) {
857 if ((LocalBbsTable
[Index
].BootPriority
== BBS_IGNORE_ENTRY
) ||
858 (LocalBbsTable
[Index
].BootPriority
== BBS_DO_NOT_BOOT_FROM
)
863 BdsBuildLegacyDevNameString (&LocalBbsTable
[Index
], Index
, sizeof (Desc
), Desc
);
865 Exist
= BdsFindLegacyBootOptionByDevTypeAndName (
867 BootOrderSize
/ sizeof (UINT16
),
868 LocalBbsTable
[Index
].DeviceType
,
876 // Not found such type of legacy device in boot options or we found but it's disabled
877 // so we have to create one and put it to the tail of boot order list
879 Status
= BdsCreateOneLegacyBootOption (
880 &LocalBbsTable
[Index
],
885 if (!EFI_ERROR (Status
)) {
886 ASSERT (BootOrder
!= NULL
);
888 OptionNumber
= BootOrder
[BootOrderSize
/ sizeof (UINT16
) - 1];
892 ASSERT (BbsIndex
== Index
);
895 Status
= gRT
->SetVariable (
897 &gEfiGlobalVariableGuid
,
898 EFI_VARIABLE_BOOTSERVICE_ACCESS
| EFI_VARIABLE_RUNTIME_ACCESS
| EFI_VARIABLE_NON_VOLATILE
,
902 if (BootOrder
!= NULL
) {
903 FreePool (BootOrder
);
910 Fill the device order buffer.
912 @param BbsTable The BBS table.
913 @param BbsType The BBS Type.
914 @param BbsCount The BBS Count.
915 @param Buf device order buffer.
917 @return The device order buffer.
922 IN BBS_TABLE
*BbsTable
,
930 for (Index
= 0; Index
< BbsCount
; Index
++) {
931 if (BbsTable
[Index
].BootPriority
== BBS_IGNORE_ENTRY
) {
935 if (BbsTable
[Index
].DeviceType
!= BbsType
) {
939 *Buf
= (UINT16
) (Index
& 0xFF);
947 Create the device order buffer.
949 @param BbsTable The BBS table.
950 @param BbsCount The BBS Count.
952 @retval EFI_SUCCES The buffer is created and the EFI variable named
953 VAR_LEGACY_DEV_ORDER and gEfiLegacyDevOrderVariableGuid is
955 @retval EFI_OUT_OF_RESOURCES Memmory or storage is not enough.
956 @retval EFI_DEVICE_ERROR Fail to add the device order into EFI variable fail
957 because of hardware error.
961 IN BBS_TABLE
*BbsTable
,
973 LEGACY_DEV_ORDER_ENTRY
*DevOrder
;
974 LEGACY_DEV_ORDER_ENTRY
*DevOrderPtr
;
983 HeaderSize
= sizeof (BBS_TYPE
) + sizeof (UINT16
);
985 Status
= EFI_SUCCESS
;
988 // Count all boot devices
990 for (Index
= 0; Index
< BbsCount
; Index
++) {
991 if (BbsTable
[Index
].BootPriority
== BBS_IGNORE_ENTRY
) {
995 switch (BbsTable
[Index
].DeviceType
) {
1008 case BBS_EMBED_NETWORK
:
1012 case BBS_BEV_DEVICE
:
1021 TotalSize
+= (HeaderSize
+ sizeof (UINT16
) * FDCount
);
1022 TotalSize
+= (HeaderSize
+ sizeof (UINT16
) * HDCount
);
1023 TotalSize
+= (HeaderSize
+ sizeof (UINT16
) * CDCount
);
1024 TotalSize
+= (HeaderSize
+ sizeof (UINT16
) * NETCount
);
1025 TotalSize
+= (HeaderSize
+ sizeof (UINT16
) * BEVCount
);
1028 // Create buffer to hold all boot device order
1030 DevOrder
= AllocateZeroPool (TotalSize
);
1031 if (NULL
== DevOrder
) {
1032 return EFI_OUT_OF_RESOURCES
;
1034 DevOrderPtr
= DevOrder
;
1036 DevOrderPtr
->BbsType
= BBS_FLOPPY
;
1037 DevOrderPtr
->Length
= (UINT16
) (sizeof (DevOrderPtr
->Length
) + FDCount
* sizeof (UINT16
));
1038 DevOrderPtr
= (LEGACY_DEV_ORDER_ENTRY
*) BdsFillDevOrderBuf (BbsTable
, BBS_FLOPPY
, BbsCount
, DevOrderPtr
->Data
);
1040 DevOrderPtr
->BbsType
= BBS_HARDDISK
;
1041 DevOrderPtr
->Length
= (UINT16
) (sizeof (UINT16
) + HDCount
* sizeof (UINT16
));
1042 DevOrderPtr
= (LEGACY_DEV_ORDER_ENTRY
*) BdsFillDevOrderBuf (BbsTable
, BBS_HARDDISK
, BbsCount
, DevOrderPtr
->Data
);
1044 DevOrderPtr
->BbsType
= BBS_CDROM
;
1045 DevOrderPtr
->Length
= (UINT16
) (sizeof (UINT16
) + CDCount
* sizeof (UINT16
));
1046 DevOrderPtr
= (LEGACY_DEV_ORDER_ENTRY
*) BdsFillDevOrderBuf (BbsTable
, BBS_CDROM
, BbsCount
, DevOrderPtr
->Data
);
1048 DevOrderPtr
->BbsType
= BBS_EMBED_NETWORK
;
1049 DevOrderPtr
->Length
= (UINT16
) (sizeof (UINT16
) + NETCount
* sizeof (UINT16
));
1050 DevOrderPtr
= (LEGACY_DEV_ORDER_ENTRY
*) BdsFillDevOrderBuf (BbsTable
, BBS_EMBED_NETWORK
, BbsCount
, DevOrderPtr
->Data
);
1052 DevOrderPtr
->BbsType
= BBS_BEV_DEVICE
;
1053 DevOrderPtr
->Length
= (UINT16
) (sizeof (UINT16
) + BEVCount
* sizeof (UINT16
));
1054 DevOrderPtr
= (LEGACY_DEV_ORDER_ENTRY
*) BdsFillDevOrderBuf (BbsTable
, BBS_BEV_DEVICE
, BbsCount
, DevOrderPtr
->Data
);
1056 ASSERT (TotalSize
== (UINTN
) ((UINT8
*) DevOrderPtr
- (UINT8
*) DevOrder
));
1059 // Save device order for legacy boot device to variable.
1061 Status
= gRT
->SetVariable (
1062 VAR_LEGACY_DEV_ORDER
,
1063 &gEfiLegacyDevOrderVariableGuid
,
1064 EFI_VARIABLE_BOOTSERVICE_ACCESS
| EFI_VARIABLE_NON_VOLATILE
,
1068 FreePool (DevOrder
);
1074 Add the legacy boot devices from BBS table into
1075 the legacy device boot order.
1077 @retval EFI_SUCCESS The boot devices are added successfully.
1078 @retval EFI_NOT_FOUND The legacy boot devices are not found.
1079 @retval EFI_OUT_OF_RESOURCES Memmory or storage is not enough.
1080 @retval EFI_DEVICE_ERROR Fail to add the legacy device boot order into EFI variable
1081 because of hardware error.
1085 BdsUpdateLegacyDevOrder (
1089 LEGACY_DEV_ORDER_ENTRY
*DevOrder
;
1090 LEGACY_DEV_ORDER_ENTRY
*NewDevOrder
;
1091 LEGACY_DEV_ORDER_ENTRY
*Ptr
;
1092 LEGACY_DEV_ORDER_ENTRY
*NewPtr
;
1094 EFI_LEGACY_BIOS_PROTOCOL
*LegacyBios
;
1098 HDD_INFO
*LocalHddInfo
;
1099 BBS_TABLE
*LocalBbsTable
;
1129 HeaderSize
= sizeof (BBS_TYPE
) + sizeof (UINT16
);
1137 Status
= gBS
->LocateProtocol (&gEfiLegacyBiosProtocolGuid
, NULL
, (VOID
**) &LegacyBios
);
1138 if (EFI_ERROR (Status
)) {
1142 Status
= LegacyBios
->GetBbsInfo (
1149 if (EFI_ERROR (Status
)) {
1153 DevOrder
= BdsLibGetVariableAndSize (
1154 VAR_LEGACY_DEV_ORDER
,
1155 &gEfiLegacyDevOrderVariableGuid
,
1158 if (NULL
== DevOrder
) {
1159 return BdsCreateDevOrder (LocalBbsTable
, BbsCount
);
1162 // First we figure out how many boot devices with same device type respectively
1164 for (Index
= 0; Index
< BbsCount
; Index
++) {
1165 if ((LocalBbsTable
[Index
].BootPriority
== BBS_IGNORE_ENTRY
) ||
1166 (LocalBbsTable
[Index
].BootPriority
== BBS_DO_NOT_BOOT_FROM
)
1171 switch (LocalBbsTable
[Index
].DeviceType
) {
1184 case BBS_EMBED_NETWORK
:
1188 case BBS_BEV_DEVICE
:
1197 TotalSize
+= (HeaderSize
+ FDCount
* sizeof (UINT16
));
1198 TotalSize
+= (HeaderSize
+ HDCount
* sizeof (UINT16
));
1199 TotalSize
+= (HeaderSize
+ CDCount
* sizeof (UINT16
));
1200 TotalSize
+= (HeaderSize
+ NETCount
* sizeof (UINT16
));
1201 TotalSize
+= (HeaderSize
+ BEVCount
* sizeof (UINT16
));
1203 NewDevOrder
= AllocateZeroPool (TotalSize
);
1204 if (NULL
== NewDevOrder
) {
1205 return EFI_OUT_OF_RESOURCES
;
1214 NewPtr
= NewDevOrder
;
1215 NewPtr
->BbsType
= Ptr
->BbsType
;
1216 NewPtr
->Length
= (UINT16
) (sizeof (UINT16
) + FDCount
* sizeof (UINT16
));
1217 for (Index
= 0; Index
< Ptr
->Length
/ sizeof (UINT16
) - 1; Index
++) {
1218 if (LocalBbsTable
[Ptr
->Data
[Index
] & 0xFF].BootPriority
== BBS_IGNORE_ENTRY
||
1219 LocalBbsTable
[Ptr
->Data
[Index
] & 0xFF].BootPriority
== BBS_DO_NOT_BOOT_FROM
||
1220 LocalBbsTable
[Ptr
->Data
[Index
] & 0xFF].DeviceType
!= BBS_FLOPPY
1225 NewPtr
->Data
[FDIndex
] = Ptr
->Data
[Index
];
1228 NewFDPtr
= NewPtr
->Data
;
1233 Ptr
= (LEGACY_DEV_ORDER_ENTRY
*) (&Ptr
->Data
[Ptr
->Length
/ sizeof (UINT16
) - 1]);
1234 NewPtr
= (LEGACY_DEV_ORDER_ENTRY
*) (&NewPtr
->Data
[NewPtr
->Length
/ sizeof (UINT16
) -1]);
1235 NewPtr
->BbsType
= Ptr
->BbsType
;
1236 NewPtr
->Length
= (UINT16
) (sizeof (UINT16
) + HDCount
* sizeof (UINT16
));
1237 for (Index
= 0; Index
< Ptr
->Length
/ sizeof (UINT16
) - 1; Index
++) {
1238 if (LocalBbsTable
[Ptr
->Data
[Index
] & 0xFF].BootPriority
== BBS_IGNORE_ENTRY
||
1239 LocalBbsTable
[Ptr
->Data
[Index
] & 0xFF].BootPriority
== BBS_DO_NOT_BOOT_FROM
||
1240 LocalBbsTable
[Ptr
->Data
[Index
] & 0xFF].BootPriority
== BBS_LOWEST_PRIORITY
||
1241 LocalBbsTable
[Ptr
->Data
[Index
] & 0xFF].DeviceType
!= BBS_HARDDISK
1246 NewPtr
->Data
[HDIndex
] = Ptr
->Data
[Index
];
1249 NewHDPtr
= NewPtr
->Data
;
1254 Ptr
= (LEGACY_DEV_ORDER_ENTRY
*) (&Ptr
->Data
[Ptr
->Length
/ sizeof (UINT16
) - 1]);
1255 NewPtr
= (LEGACY_DEV_ORDER_ENTRY
*) (&NewPtr
->Data
[NewPtr
->Length
/ sizeof (UINT16
) -1]);
1256 NewPtr
->BbsType
= Ptr
->BbsType
;
1257 NewPtr
->Length
= (UINT16
) (sizeof (UINT16
) + CDCount
* sizeof (UINT16
));
1258 for (Index
= 0; Index
< Ptr
->Length
/ sizeof (UINT16
) - 1; Index
++) {
1259 if (LocalBbsTable
[Ptr
->Data
[Index
] & 0xFF].BootPriority
== BBS_IGNORE_ENTRY
||
1260 LocalBbsTable
[Ptr
->Data
[Index
] & 0xFF].BootPriority
== BBS_DO_NOT_BOOT_FROM
||
1261 LocalBbsTable
[Ptr
->Data
[Index
] & 0xFF].BootPriority
== BBS_LOWEST_PRIORITY
||
1262 LocalBbsTable
[Ptr
->Data
[Index
] & 0xFF].DeviceType
!= BBS_CDROM
1267 NewPtr
->Data
[CDIndex
] = Ptr
->Data
[Index
];
1270 NewCDPtr
= NewPtr
->Data
;
1275 Ptr
= (LEGACY_DEV_ORDER_ENTRY
*) (&Ptr
->Data
[Ptr
->Length
/ sizeof (UINT16
) - 1]);
1276 NewPtr
= (LEGACY_DEV_ORDER_ENTRY
*) (&NewPtr
->Data
[NewPtr
->Length
/ sizeof (UINT16
) -1]);
1277 NewPtr
->BbsType
= Ptr
->BbsType
;
1278 NewPtr
->Length
= (UINT16
) (sizeof (UINT16
) + NETCount
* sizeof (UINT16
));
1279 for (Index
= 0; Index
< Ptr
->Length
/ sizeof (UINT16
) - 1; Index
++) {
1280 if (LocalBbsTable
[Ptr
->Data
[Index
] & 0xFF].BootPriority
== BBS_IGNORE_ENTRY
||
1281 LocalBbsTable
[Ptr
->Data
[Index
] & 0xFF].BootPriority
== BBS_DO_NOT_BOOT_FROM
||
1282 LocalBbsTable
[Ptr
->Data
[Index
] & 0xFF].BootPriority
== BBS_LOWEST_PRIORITY
||
1283 LocalBbsTable
[Ptr
->Data
[Index
] & 0xFF].DeviceType
!= BBS_EMBED_NETWORK
1288 NewPtr
->Data
[NETIndex
] = Ptr
->Data
[Index
];
1291 NewNETPtr
= NewPtr
->Data
;
1296 Ptr
= (LEGACY_DEV_ORDER_ENTRY
*) (&Ptr
->Data
[Ptr
->Length
/ sizeof (UINT16
) - 1]);
1297 NewPtr
= (LEGACY_DEV_ORDER_ENTRY
*) (&NewPtr
->Data
[NewPtr
->Length
/ sizeof (UINT16
) -1]);
1298 NewPtr
->BbsType
= Ptr
->BbsType
;
1299 NewPtr
->Length
= (UINT16
) (sizeof (UINT16
) + BEVCount
* sizeof (UINT16
));
1300 for (Index
= 0; Index
< Ptr
->Length
/ sizeof (UINT16
) - 1; Index
++) {
1301 if (LocalBbsTable
[Ptr
->Data
[Index
] & 0xFF].BootPriority
== BBS_IGNORE_ENTRY
||
1302 LocalBbsTable
[Ptr
->Data
[Index
] & 0xFF].BootPriority
== BBS_DO_NOT_BOOT_FROM
||
1303 LocalBbsTable
[Ptr
->Data
[Index
] & 0xFF].BootPriority
== BBS_LOWEST_PRIORITY
||
1304 LocalBbsTable
[Ptr
->Data
[Index
] & 0xFF].DeviceType
!= BBS_BEV_DEVICE
1309 NewPtr
->Data
[BEVIndex
] = Ptr
->Data
[Index
];
1312 NewBEVPtr
= NewPtr
->Data
;
1314 for (Index
= 0; Index
< BbsCount
; Index
++) {
1315 if ((LocalBbsTable
[Index
].BootPriority
== BBS_IGNORE_ENTRY
) ||
1316 (LocalBbsTable
[Index
].BootPriority
== BBS_DO_NOT_BOOT_FROM
)
1321 switch (LocalBbsTable
[Index
].DeviceType
) {
1324 NewDevPtr
= NewFDPtr
;
1329 NewDevPtr
= NewHDPtr
;
1334 NewDevPtr
= NewCDPtr
;
1337 case BBS_EMBED_NETWORK
:
1339 NewDevPtr
= NewNETPtr
;
1342 case BBS_BEV_DEVICE
:
1344 NewDevPtr
= NewBEVPtr
;
1352 // at this point we have copied those valid indexes to new buffer
1353 // and we should check if there is any new appeared boot device
1356 for (Index2
= 0; Index2
< *Idx
; Index2
++) {
1357 if ((NewDevPtr
[Index2
] & 0xFF) == (UINT16
) Index
) {
1362 if (Index2
== *Idx
) {
1364 // Index2 == *Idx means we didn't find Index
1365 // so Index is a new appeared device's index in BBS table
1366 // insert it before disabled indexes.
1368 for (Index2
= 0; Index2
< *Idx
; Index2
++) {
1369 if ((NewDevPtr
[Index2
] & 0xFF00) == 0xFF00) {
1373 CopyMem (&NewDevPtr
[Index2
+ 1], &NewDevPtr
[Index2
], (*Idx
- Index2
) * sizeof (UINT16
));
1374 NewDevPtr
[Index2
] = (UINT16
) (Index
& 0xFF);
1380 FreePool (DevOrder
);
1382 Status
= gRT
->SetVariable (
1383 VAR_LEGACY_DEV_ORDER
,
1384 &gEfiLegacyDevOrderVariableGuid
,
1385 EFI_VARIABLE_BOOTSERVICE_ACCESS
| EFI_VARIABLE_NON_VOLATILE
,
1389 FreePool (NewDevOrder
);
1395 Set Boot Priority for specified device type.
1397 @param DeviceType The device type.
1398 @param BbsIndex The BBS index to set the highest priority. Ignore when -1.
1399 @param LocalBbsTable The BBS table.
1400 @param Priority The prority table.
1402 @retval EFI_SUCCESS The function completes successfully.
1403 @retval EFI_NOT_FOUND Failed to find device.
1404 @retval EFI_OUT_OF_RESOURCES Failed to get the efi variable of device order.
1408 BdsSetBootPriority4SameTypeDev (
1409 IN UINT16 DeviceType
,
1411 IN OUT BBS_TABLE
*LocalBbsTable
,
1412 IN OUT UINT16
*Priority
1415 LEGACY_DEV_ORDER_ENTRY
*DevOrder
;
1416 LEGACY_DEV_ORDER_ENTRY
*DevOrderPtr
;
1420 DevOrder
= BdsLibGetVariableAndSize (
1421 VAR_LEGACY_DEV_ORDER
,
1422 &gEfiLegacyDevOrderVariableGuid
,
1425 if (NULL
== DevOrder
) {
1426 return EFI_OUT_OF_RESOURCES
;
1429 DevOrderPtr
= DevOrder
;
1430 while ((UINT8
*) DevOrderPtr
< (UINT8
*) DevOrder
+ DevOrderSize
) {
1431 if (DevOrderPtr
->BbsType
== DeviceType
) {
1435 DevOrderPtr
= (LEGACY_DEV_ORDER_ENTRY
*) ((UINTN
) DevOrderPtr
+ sizeof (BBS_TYPE
) + DevOrderPtr
->Length
);
1438 if ((UINT8
*) DevOrderPtr
>= (UINT8
*) DevOrder
+ DevOrderSize
) {
1439 FreePool (DevOrder
);
1440 return EFI_NOT_FOUND
;
1443 if (BbsIndex
!= (UINTN
) -1) {
1444 LocalBbsTable
[BbsIndex
].BootPriority
= *Priority
;
1448 // If the high byte of the DevIndex is 0xFF, it indicates that this device has been disabled.
1450 for (Index
= 0; Index
< DevOrderPtr
->Length
/ sizeof (UINT16
) - 1; Index
++) {
1451 if ((DevOrderPtr
->Data
[Index
] & 0xFF00) == 0xFF00) {
1453 // LocalBbsTable[DevIndex[Index] & 0xFF].BootPriority = BBS_DISABLED_ENTRY;
1455 } else if (DevOrderPtr
->Data
[Index
] != BbsIndex
) {
1456 LocalBbsTable
[DevOrderPtr
->Data
[Index
]].BootPriority
= *Priority
;
1461 FreePool (DevOrder
);
1466 Print the BBS Table.
1468 @param LocalBbsTable The BBS table.
1469 @param BbsCount The count of entry in BBS table.
1473 IN BBS_TABLE
*LocalBbsTable
,
1479 DEBUG ((DEBUG_ERROR
, "\n"));
1480 DEBUG ((DEBUG_ERROR
, " NO Prio bb/dd/ff cl/sc Type Stat segm:offs\n"));
1481 DEBUG ((DEBUG_ERROR
, "=============================================\n"));
1482 for (Idx
= 0; Idx
< BbsCount
; Idx
++) {
1483 if ((LocalBbsTable
[Idx
].BootPriority
== BBS_IGNORE_ENTRY
) ||
1484 (LocalBbsTable
[Idx
].BootPriority
== BBS_DO_NOT_BOOT_FROM
) ||
1485 (LocalBbsTable
[Idx
].BootPriority
== BBS_LOWEST_PRIORITY
)
1492 " %02x: %04x %02x/%02x/%02x %02x/%02x %04x %04x %04x:%04x\n",
1494 (UINTN
) LocalBbsTable
[Idx
].BootPriority
,
1495 (UINTN
) LocalBbsTable
[Idx
].Bus
,
1496 (UINTN
) LocalBbsTable
[Idx
].Device
,
1497 (UINTN
) LocalBbsTable
[Idx
].Function
,
1498 (UINTN
) LocalBbsTable
[Idx
].Class
,
1499 (UINTN
) LocalBbsTable
[Idx
].SubClass
,
1500 (UINTN
) LocalBbsTable
[Idx
].DeviceType
,
1501 (UINTN
) * (UINT16
*) &LocalBbsTable
[Idx
].StatusFlags
,
1502 (UINTN
) LocalBbsTable
[Idx
].BootHandlerSegment
,
1503 (UINTN
) LocalBbsTable
[Idx
].BootHandlerOffset
,
1504 (UINTN
) ((LocalBbsTable
[Idx
].MfgStringSegment
<< 4) + LocalBbsTable
[Idx
].MfgStringOffset
),
1505 (UINTN
) ((LocalBbsTable
[Idx
].DescStringSegment
<< 4) + LocalBbsTable
[Idx
].DescStringOffset
))
1509 DEBUG ((DEBUG_ERROR
, "\n"));
1513 Set the boot priority for BBS entries based on boot option entry and boot order.
1515 @param Entry The boot option is to be checked for refresh BBS table.
1517 @retval EFI_SUCCESS The boot priority for BBS entries is refreshed successfully.
1518 @retval EFI_NOT_FOUND BBS entries can't be found.
1519 @retval EFI_OUT_OF_RESOURCES Failed to get the legacy device boot order.
1523 BdsRefreshBbsTableForBoot (
1524 IN BDS_COMMON_OPTION
*Entry
1531 HDD_INFO
*LocalHddInfo
;
1532 BBS_TABLE
*LocalBbsTable
;
1534 EFI_LEGACY_BIOS_PROTOCOL
*LegacyBios
;
1538 UINTN BootOrderSize
;
1539 UINT8
*BootOptionVar
;
1540 UINTN BootOptionSize
;
1541 CHAR16 BootOption
[9];
1544 EFI_DEVICE_PATH_PROTOCOL
*DevPath
;
1546 UINTN DeviceTypeCount
;
1547 UINTN DeviceTypeIndex
;
1551 LocalHddInfo
= NULL
;
1552 LocalBbsTable
= NULL
;
1553 DevType
= BBS_UNKNOWN
;
1555 Status
= gBS
->LocateProtocol (&gEfiLegacyBiosProtocolGuid
, NULL
, (VOID
**) &LegacyBios
);
1556 if (EFI_ERROR (Status
)) {
1560 LegacyBios
->GetBbsInfo (
1568 // First, set all the present devices' boot priority to BBS_UNPRIORITIZED_ENTRY
1569 // We will set them according to the settings setup by user
1571 for (Index
= 0; Index
< BbsCount
; Index
++) {
1572 if (!((BBS_IGNORE_ENTRY
== LocalBbsTable
[Index
].BootPriority
) ||
1573 (BBS_DO_NOT_BOOT_FROM
== LocalBbsTable
[Index
].BootPriority
) ||
1574 (BBS_LOWEST_PRIORITY
== LocalBbsTable
[Index
].BootPriority
))) {
1575 LocalBbsTable
[Index
].BootPriority
= BBS_UNPRIORITIZED_ENTRY
;
1579 // boot priority always starts at 0
1582 if (Entry
->LoadOptionsSize
== sizeof (BBS_TABLE
) + sizeof (UINT16
)) {
1584 // If Entry stands for a legacy boot option, we prioritize the devices with the same type first.
1586 DevType
= ((BBS_TABLE
*) Entry
->LoadOptions
)->DeviceType
;
1587 BbsIndex
= *(UINT16
*) ((BBS_TABLE
*) Entry
->LoadOptions
+ 1);
1588 Status
= BdsSetBootPriority4SameTypeDev (
1594 if (EFI_ERROR (Status
)) {
1599 // we have to set the boot priority for other BBS entries with different device types
1601 BootOrder
= BdsLibGetVariableAndSize (
1603 &gEfiGlobalVariableGuid
,
1606 DeviceType
= AllocatePool (BootOrderSize
+ sizeof (UINT16
));
1607 ASSERT (DeviceType
!= NULL
);
1609 DeviceType
[0] = DevType
;
1610 DeviceTypeCount
= 1;
1611 for (Index
= 0; ((BootOrder
!= NULL
) && (Index
< BootOrderSize
/ sizeof (UINT16
))); Index
++) {
1612 UnicodeSPrint (BootOption
, sizeof (BootOption
), L
"Boot%04x", BootOrder
[Index
]);
1613 BootOptionVar
= BdsLibGetVariableAndSize (
1615 &gEfiGlobalVariableGuid
,
1618 if (NULL
== BootOptionVar
) {
1622 Ptr
= BootOptionVar
;
1624 Ptr
+= sizeof (UINT32
);
1625 DevPathLen
= *(UINT16
*) Ptr
;
1626 Ptr
+= sizeof (UINT16
);
1627 Ptr
+= StrSize ((UINT16
*) Ptr
);
1628 DevPath
= (EFI_DEVICE_PATH_PROTOCOL
*) Ptr
;
1629 if (BBS_DEVICE_PATH
!= DevPath
->Type
|| BBS_BBS_DP
!= DevPath
->SubType
) {
1630 FreePool (BootOptionVar
);
1635 DevType
= ((BBS_TABLE
*) Ptr
)->DeviceType
;
1636 for (DeviceTypeIndex
= 0; DeviceTypeIndex
< DeviceTypeCount
; DeviceTypeIndex
++) {
1637 if (DeviceType
[DeviceTypeIndex
] == DevType
) {
1641 if (DeviceTypeIndex
< DeviceTypeCount
) {
1643 // We don't want to process twice for a device type
1645 FreePool (BootOptionVar
);
1649 DeviceType
[DeviceTypeCount
] = DevType
;
1652 Status
= BdsSetBootPriority4SameTypeDev (
1658 FreePool (BootOptionVar
);
1659 if (EFI_ERROR (Status
)) {
1664 FreePool (DeviceType
);
1666 if (BootOrder
!= NULL
) {
1667 FreePool (BootOrder
);
1671 PrintBbsTable (LocalBbsTable
, BbsCount
);
1678 Boot the legacy system with the boot option
1680 @param Option The legacy boot option which have BBS device path
1682 @retval EFI_UNSUPPORTED There is no legacybios protocol, do not support
1684 @retval EFI_STATUS Return the status of LegacyBios->LegacyBoot ().
1688 BdsLibDoLegacyBoot (
1689 IN BDS_COMMON_OPTION
*Option
1693 EFI_LEGACY_BIOS_PROTOCOL
*LegacyBios
;
1694 EFI_EVENT LegacyBootEvent
;
1696 Status
= gBS
->LocateProtocol (&gEfiLegacyBiosProtocolGuid
, NULL
, (VOID
**) &LegacyBios
);
1697 if (EFI_ERROR (Status
)) {
1699 // If no LegacyBios protocol we do not support legacy boot
1701 return EFI_UNSUPPORTED
;
1704 // Notes: if we separate the int 19, then we don't need to refresh BBS
1706 BdsRefreshBbsTableForBoot (Option
);
1709 // Write boot to OS performance data for legacy boot.
1713 // Create an event to be signalled when Legacy Boot occurs to write performance data.
1715 Status
= EfiCreateEventLegacyBootEx(
1721 ASSERT_EFI_ERROR (Status
);
1724 DEBUG ((DEBUG_INFO
| DEBUG_LOAD
, "Legacy Boot: %S\n", Option
->Description
));
1725 return LegacyBios
->LegacyBoot (
1727 (BBS_BBS_DEVICE_PATH
*) Option
->DevicePath
,
1728 Option
->LoadOptionsSize
,
1734 Internal function to check if the input boot option is a valid EFI NV Boot####.
1736 @param OptionToCheck Boot option to be checked.
1738 @retval TRUE This boot option matches a valid EFI NV Boot####.
1739 @retval FALSE If not.
1743 IsBootOptionValidNVVarialbe (
1744 IN BDS_COMMON_OPTION
*OptionToCheck
1747 LIST_ENTRY TempList
;
1748 BDS_COMMON_OPTION
*BootOption
;
1750 CHAR16 OptionName
[20];
1754 InitializeListHead (&TempList
);
1755 UnicodeSPrint (OptionName
, sizeof (OptionName
), L
"Boot%04x", OptionToCheck
->BootCurrent
);
1757 BootOption
= BdsLibVariableToOption (&TempList
, OptionName
);
1758 if (BootOption
== NULL
) {
1763 // If the Boot Option Number and Device Path matches, OptionToCheck matches a
1764 // valid EFI NV Boot####.
1766 if ((OptionToCheck
->BootCurrent
== BootOption
->BootCurrent
) &&
1767 (CompareMem (OptionToCheck
->DevicePath
, BootOption
->DevicePath
, GetDevicePathSize (OptionToCheck
->DevicePath
)) == 0))
1772 FreePool (BootOption
);
1778 Check whether a USB device match the specified USB Class device path. This
1779 function follows "Load Option Processing" behavior in UEFI specification.
1781 @param UsbIo USB I/O protocol associated with the USB device.
1782 @param UsbClass The USB Class device path to match.
1784 @retval TRUE The USB device match the USB Class device path.
1785 @retval FALSE The USB device does not match the USB Class device path.
1790 IN EFI_USB_IO_PROTOCOL
*UsbIo
,
1791 IN USB_CLASS_DEVICE_PATH
*UsbClass
1795 EFI_USB_DEVICE_DESCRIPTOR DevDesc
;
1796 EFI_USB_INTERFACE_DESCRIPTOR IfDesc
;
1798 UINT8 DeviceSubClass
;
1799 UINT8 DeviceProtocol
;
1801 if ((DevicePathType (UsbClass
) != MESSAGING_DEVICE_PATH
) ||
1802 (DevicePathSubType (UsbClass
) != MSG_USB_CLASS_DP
)){
1807 // Check Vendor Id and Product Id.
1809 Status
= UsbIo
->UsbGetDeviceDescriptor (UsbIo
, &DevDesc
);
1810 if (EFI_ERROR (Status
)) {
1814 if ((UsbClass
->VendorId
!= 0xffff) &&
1815 (UsbClass
->VendorId
!= DevDesc
.IdVendor
)) {
1819 if ((UsbClass
->ProductId
!= 0xffff) &&
1820 (UsbClass
->ProductId
!= DevDesc
.IdProduct
)) {
1824 DeviceClass
= DevDesc
.DeviceClass
;
1825 DeviceSubClass
= DevDesc
.DeviceSubClass
;
1826 DeviceProtocol
= DevDesc
.DeviceProtocol
;
1827 if (DeviceClass
== 0) {
1829 // If Class in Device Descriptor is set to 0, use the Class, SubClass and
1830 // Protocol in Interface Descriptor instead.
1832 Status
= UsbIo
->UsbGetInterfaceDescriptor (UsbIo
, &IfDesc
);
1833 if (EFI_ERROR (Status
)) {
1837 DeviceClass
= IfDesc
.InterfaceClass
;
1838 DeviceSubClass
= IfDesc
.InterfaceSubClass
;
1839 DeviceProtocol
= IfDesc
.InterfaceProtocol
;
1843 // Check Class, SubClass and Protocol.
1845 if ((UsbClass
->DeviceClass
!= 0xff) &&
1846 (UsbClass
->DeviceClass
!= DeviceClass
)) {
1850 if ((UsbClass
->DeviceSubClass
!= 0xff) &&
1851 (UsbClass
->DeviceSubClass
!= DeviceSubClass
)) {
1855 if ((UsbClass
->DeviceProtocol
!= 0xff) &&
1856 (UsbClass
->DeviceProtocol
!= DeviceProtocol
)) {
1864 Check whether a USB device match the specified USB WWID device path. This
1865 function follows "Load Option Processing" behavior in UEFI specification.
1867 @param UsbIo USB I/O protocol associated with the USB device.
1868 @param UsbWwid The USB WWID device path to match.
1870 @retval TRUE The USB device match the USB WWID device path.
1871 @retval FALSE The USB device does not match the USB WWID device path.
1876 IN EFI_USB_IO_PROTOCOL
*UsbIo
,
1877 IN USB_WWID_DEVICE_PATH
*UsbWwid
1881 EFI_USB_DEVICE_DESCRIPTOR DevDesc
;
1882 EFI_USB_INTERFACE_DESCRIPTOR IfDesc
;
1883 UINT16
*LangIdTable
;
1888 CHAR16
*SerialNumberStr
;
1891 if ((DevicePathType (UsbWwid
) != MESSAGING_DEVICE_PATH
) ||
1892 (DevicePathSubType (UsbWwid
) != MSG_USB_WWID_DP
)){
1897 // Check Vendor Id and Product Id.
1899 Status
= UsbIo
->UsbGetDeviceDescriptor (UsbIo
, &DevDesc
);
1900 if (EFI_ERROR (Status
)) {
1903 if ((DevDesc
.IdVendor
!= UsbWwid
->VendorId
) ||
1904 (DevDesc
.IdProduct
!= UsbWwid
->ProductId
)) {
1909 // Check Interface Number.
1911 Status
= UsbIo
->UsbGetInterfaceDescriptor (UsbIo
, &IfDesc
);
1912 if (EFI_ERROR (Status
)) {
1915 if (IfDesc
.InterfaceNumber
!= UsbWwid
->InterfaceNumber
) {
1920 // Check Serial Number.
1922 if (DevDesc
.StrSerialNumber
== 0) {
1927 // Get all supported languages.
1931 Status
= UsbIo
->UsbGetSupportedLanguages (UsbIo
, &LangIdTable
, &TableSize
);
1932 if (EFI_ERROR (Status
) || (TableSize
== 0) || (LangIdTable
== NULL
)) {
1937 // Serial number in USB WWID device path is the last 64-or-less UTF-16 characters.
1939 CompareStr
= (CHAR16
*) (UINTN
) (UsbWwid
+ 1);
1940 CompareLen
= (DevicePathNodeLength (UsbWwid
) - sizeof (USB_WWID_DEVICE_PATH
)) / sizeof (CHAR16
);
1941 if (CompareStr
[CompareLen
- 1] == L
'\0') {
1946 // Compare serial number in each supported language.
1948 for (Index
= 0; Index
< TableSize
/ sizeof (UINT16
); Index
++) {
1949 SerialNumberStr
= NULL
;
1950 Status
= UsbIo
->UsbGetStringDescriptor (
1953 DevDesc
.StrSerialNumber
,
1956 if (EFI_ERROR (Status
) || (SerialNumberStr
== NULL
)) {
1960 Length
= StrLen (SerialNumberStr
);
1961 if ((Length
>= CompareLen
) &&
1962 (CompareMem (SerialNumberStr
+ Length
- CompareLen
, CompareStr
, CompareLen
* sizeof (CHAR16
)) == 0)) {
1963 FreePool (SerialNumberStr
);
1967 FreePool (SerialNumberStr
);
1974 Find a USB device path which match the specified short-form device path start
1975 with USB Class or USB WWID device path and load the boot file then return the
1976 image handle. If ParentDevicePath is NULL, this function will search in all USB
1977 devices of the platform. If ParentDevicePath is not NULL,this function will only
1978 search in its child devices.
1980 @param ParentDevicePath The device path of the parent.
1981 @param ShortFormDevicePath The USB Class or USB WWID device path to match.
1983 @return The image Handle if find load file from specified short-form device path
1984 or NULL if not found.
1989 IN EFI_DEVICE_PATH_PROTOCOL
*ParentDevicePath
,
1990 IN EFI_DEVICE_PATH_PROTOCOL
*ShortFormDevicePath
1994 UINTN UsbIoHandleCount
;
1995 EFI_HANDLE
*UsbIoHandleBuffer
;
1996 EFI_DEVICE_PATH_PROTOCOL
*UsbIoDevicePath
;
1997 EFI_USB_IO_PROTOCOL
*UsbIo
;
2001 EFI_HANDLE ImageHandle
;
2003 EFI_DEVICE_PATH_PROTOCOL
*FullDevicePath
;
2004 EFI_DEVICE_PATH_PROTOCOL
*NextDevicePath
;
2006 FullDevicePath
= NULL
;
2010 // Get all UsbIo Handles.
2012 UsbIoHandleCount
= 0;
2013 UsbIoHandleBuffer
= NULL
;
2014 Status
= gBS
->LocateHandleBuffer (
2016 &gEfiUsbIoProtocolGuid
,
2021 if (EFI_ERROR (Status
) || (UsbIoHandleCount
== 0) || (UsbIoHandleBuffer
== NULL
)) {
2025 ParentSize
= (ParentDevicePath
== NULL
) ? 0 : GetDevicePathSize (ParentDevicePath
);
2026 for (Index
= 0; Index
< UsbIoHandleCount
; Index
++) {
2028 // Get the Usb IO interface.
2030 Status
= gBS
->HandleProtocol(
2031 UsbIoHandleBuffer
[Index
],
2032 &gEfiUsbIoProtocolGuid
,
2035 if (EFI_ERROR (Status
)) {
2039 UsbIoDevicePath
= DevicePathFromHandle (UsbIoHandleBuffer
[Index
]);
2040 if (UsbIoDevicePath
== NULL
) {
2044 if (ParentDevicePath
!= NULL
) {
2046 // Compare starting part of UsbIoHandle's device path with ParentDevicePath.
2048 Size
= GetDevicePathSize (UsbIoDevicePath
);
2049 if ((Size
< ParentSize
) ||
2050 (CompareMem (UsbIoDevicePath
, ParentDevicePath
, ParentSize
- END_DEVICE_PATH_LENGTH
) != 0)) {
2055 if (BdsMatchUsbClass (UsbIo
, (USB_CLASS_DEVICE_PATH
*) ShortFormDevicePath
) ||
2056 BdsMatchUsbWwid (UsbIo
, (USB_WWID_DEVICE_PATH
*) ShortFormDevicePath
)) {
2058 // Try to find if there is the boot file in this DevicePath
2060 NextDevicePath
= NextDevicePathNode (ShortFormDevicePath
);
2061 if (!IsDevicePathEnd (NextDevicePath
)) {
2062 FullDevicePath
= AppendDevicePath (UsbIoDevicePath
, NextDevicePath
);
2064 // Connect the full device path, so that Simple File System protocol
2065 // could be installed for this USB device.
2067 BdsLibConnectDevicePath (FullDevicePath
);
2068 REPORT_STATUS_CODE (EFI_PROGRESS_CODE
, PcdGet32 (PcdProgressCodeOsLoaderLoad
));
2069 Status
= gBS
->LoadImage (
2077 FreePool (FullDevicePath
);
2079 FullDevicePath
= UsbIoDevicePath
;
2080 Status
= EFI_NOT_FOUND
;
2084 // If we didn't find an image directly, we need to try as if it is a removable device boot option
2085 // and load the image according to the default boot behavior for removable device.
2087 if (EFI_ERROR (Status
)) {
2089 // check if there is a bootable removable media could be found in this device path ,
2090 // and get the bootable media handle
2092 Handle
= BdsLibGetBootableHandle(UsbIoDevicePath
);
2093 if (Handle
== NULL
) {
2097 // Load the default boot file \EFI\BOOT\boot{machinename}.EFI from removable Media
2098 // machinename is ia32, ia64, x64, ...
2100 FullDevicePath
= FileDevicePath (Handle
, EFI_REMOVABLE_MEDIA_FILE_NAME
);
2101 if (FullDevicePath
!= NULL
) {
2102 REPORT_STATUS_CODE (EFI_PROGRESS_CODE
, PcdGet32 (PcdProgressCodeOsLoaderLoad
));
2103 Status
= gBS
->LoadImage (
2111 if (EFI_ERROR (Status
)) {
2113 // The DevicePath failed, and it's not a valid
2114 // removable media device.
2126 FreePool (UsbIoHandleBuffer
);
2131 Expand USB Class or USB WWID device path node to be full device path of a USB
2132 device in platform then load the boot file on this full device path and return the
2135 This function support following 4 cases:
2136 1) Boot Option device path starts with a USB Class or USB WWID device path,
2137 and there is no Media FilePath device path in the end.
2138 In this case, it will follow Removable Media Boot Behavior.
2139 2) Boot Option device path starts with a USB Class or USB WWID device path,
2140 and ended with Media FilePath device path.
2141 3) Boot Option device path starts with a full device path to a USB Host Controller,
2142 contains a USB Class or USB WWID device path node, while not ended with Media
2143 FilePath device path. In this case, it will follow Removable Media Boot Behavior.
2144 4) Boot Option device path starts with a full device path to a USB Host Controller,
2145 contains a USB Class or USB WWID device path node, and ended with Media
2146 FilePath device path.
2148 @param DevicePath The Boot Option device path.
2150 @return The image handle of boot file, or NULL if there is no boot file found in
2151 the specified USB Class or USB WWID device path.
2155 BdsExpandUsbShortFormDevicePath (
2156 IN EFI_DEVICE_PATH_PROTOCOL
*DevicePath
2159 EFI_HANDLE
*ImageHandle
;
2160 EFI_DEVICE_PATH_PROTOCOL
*TempDevicePath
;
2161 EFI_DEVICE_PATH_PROTOCOL
*ShortFormDevicePath
;
2164 // Search for USB Class or USB WWID device path node.
2166 ShortFormDevicePath
= NULL
;
2168 TempDevicePath
= DevicePath
;
2169 while (!IsDevicePathEnd (TempDevicePath
)) {
2170 if ((DevicePathType (TempDevicePath
) == MESSAGING_DEVICE_PATH
) &&
2171 ((DevicePathSubType (TempDevicePath
) == MSG_USB_CLASS_DP
) ||
2172 (DevicePathSubType (TempDevicePath
) == MSG_USB_WWID_DP
))) {
2173 ShortFormDevicePath
= TempDevicePath
;
2176 TempDevicePath
= NextDevicePathNode (TempDevicePath
);
2179 if (ShortFormDevicePath
== NULL
) {
2181 // No USB Class or USB WWID device path node found, do nothing.
2186 if (ShortFormDevicePath
== DevicePath
) {
2188 // Boot Option device path starts with USB Class or USB WWID device path.
2190 ImageHandle
= BdsFindUsbDevice (NULL
, ShortFormDevicePath
);
2191 if (ImageHandle
== NULL
) {
2193 // Failed to find a match in existing devices, connect the short form USB
2194 // device path and try again.
2196 BdsLibConnectUsbDevByShortFormDP (0xff, ShortFormDevicePath
);
2197 ImageHandle
= BdsFindUsbDevice (NULL
, ShortFormDevicePath
);
2201 // Boot Option device path contains USB Class or USB WWID device path node.
2205 // Prepare the parent device path for search.
2207 TempDevicePath
= DuplicateDevicePath (DevicePath
);
2208 ASSERT (TempDevicePath
!= NULL
);
2209 SetDevicePathEndNode (((UINT8
*) TempDevicePath
) + ((UINTN
) ShortFormDevicePath
- (UINTN
) DevicePath
));
2212 // The USB Host Controller device path is already in Boot Option device path
2213 // and USB Bus driver already support RemainingDevicePath starts with USB
2214 // Class or USB WWID device path, so just search in existing USB devices and
2215 // doesn't perform ConnectController here.
2217 ImageHandle
= BdsFindUsbDevice (TempDevicePath
, ShortFormDevicePath
);
2218 FreePool (TempDevicePath
);
2225 Process the boot option follow the UEFI specification and
2226 special treat the legacy boot option with BBS_DEVICE_PATH.
2228 @param Option The boot option need to be processed
2229 @param DevicePath The device path which describe where to load the
2230 boot image or the legacy BBS device path to boot
2232 @param ExitDataSize The size of exit data.
2233 @param ExitData Data returned when Boot image failed.
2235 @retval EFI_SUCCESS Boot from the input boot option successfully.
2236 @retval EFI_NOT_FOUND If the Device Path is not found in the system
2241 BdsLibBootViaBootOption (
2242 IN BDS_COMMON_OPTION
*Option
,
2243 IN EFI_DEVICE_PATH_PROTOCOL
*DevicePath
,
2244 OUT UINTN
*ExitDataSize
,
2245 OUT CHAR16
**ExitData OPTIONAL
2249 EFI_STATUS StatusLogo
;
2251 EFI_HANDLE ImageHandle
;
2252 EFI_DEVICE_PATH_PROTOCOL
*FilePath
;
2253 EFI_LOADED_IMAGE_PROTOCOL
*ImageInfo
;
2254 EFI_DEVICE_PATH_PROTOCOL
*WorkingDevicePath
;
2255 EFI_ACPI_S3_SAVE_PROTOCOL
*AcpiS3Save
;
2256 LIST_ENTRY TempBootLists
;
2257 EFI_BOOT_LOGO_PROTOCOL
*BootLogo
;
2263 // Notes: this code can be remove after the s3 script table
2264 // hook on the event EVT_SIGNAL_READY_TO_BOOT or
2265 // EVT_SIGNAL_LEGACY_BOOT
2267 Status
= gBS
->LocateProtocol (&gEfiAcpiS3SaveProtocolGuid
, NULL
, (VOID
**) &AcpiS3Save
);
2268 if (!EFI_ERROR (Status
)) {
2269 AcpiS3Save
->S3Save (AcpiS3Save
, NULL
);
2272 // If it's Device Path that starts with a hard drive path, append it with the front part to compose a
2275 WorkingDevicePath
= NULL
;
2276 if ((DevicePathType (DevicePath
) == MEDIA_DEVICE_PATH
) &&
2277 (DevicePathSubType (DevicePath
) == MEDIA_HARDDRIVE_DP
)) {
2278 WorkingDevicePath
= BdsExpandPartitionPartialDevicePathToFull (
2279 (HARDDRIVE_DEVICE_PATH
*)DevicePath
2281 if (WorkingDevicePath
!= NULL
) {
2282 DevicePath
= WorkingDevicePath
;
2289 if (IsBootOptionValidNVVarialbe (Option
)) {
2291 // For a temporary boot (i.e. a boot by selected a EFI Shell using "Boot From File"), Boot Current is actually not valid.
2292 // In this case, "BootCurrent" is not created.
2293 // Only create the BootCurrent variable when it points to a valid Boot#### variable.
2295 SetVariableAndReportStatusCodeOnError (
2297 &gEfiGlobalVariableGuid
,
2298 EFI_VARIABLE_BOOTSERVICE_ACCESS
| EFI_VARIABLE_RUNTIME_ACCESS
,
2300 &Option
->BootCurrent
2305 // Report Status Code to indicate ReadyToBoot event will be signalled
2307 REPORT_STATUS_CODE (EFI_PROGRESS_CODE
, (EFI_SOFTWARE_DXE_BS_DRIVER
| EFI_SW_DXE_BS_PC_READY_TO_BOOT_EVENT
));
2310 // Signal the EVT_SIGNAL_READY_TO_BOOT event
2312 EfiSignalEventReadyToBoot();
2315 // Expand USB Class or USB WWID device path node to be full device path of a USB
2316 // device in platform then load the boot file on this full device path and get the
2319 ImageHandle
= BdsExpandUsbShortFormDevicePath (DevicePath
);
2322 // Adjust the different type memory page number just before booting
2323 // and save the updated info into the variable for next boot to use
2325 BdsSetMemoryTypeInformationVariable ();
2328 // By expanding the USB Class or WWID device path, the ImageHandle has returnned.
2329 // Here get the ImageHandle for the non USB class or WWID device path.
2331 if (ImageHandle
== NULL
) {
2332 ASSERT (Option
->DevicePath
!= NULL
);
2333 if ((DevicePathType (Option
->DevicePath
) == BBS_DEVICE_PATH
) &&
2334 (DevicePathSubType (Option
->DevicePath
) == BBS_BBS_DP
)
2337 // Check to see if we should legacy BOOT. If yes then do the legacy boot
2339 return BdsLibDoLegacyBoot (Option
);
2343 // If the boot option point to Internal FV shell, make sure it is valid
2345 Status
= BdsLibUpdateFvFileDevicePath (&DevicePath
, &gUefiShellFileGuid
);
2346 if (!EFI_ERROR(Status
)) {
2347 if (Option
->DevicePath
!= NULL
) {
2348 FreePool(Option
->DevicePath
);
2350 Option
->DevicePath
= AllocateZeroPool (GetDevicePathSize (DevicePath
));
2351 ASSERT(Option
->DevicePath
!= NULL
);
2352 CopyMem (Option
->DevicePath
, DevicePath
, GetDevicePathSize (DevicePath
));
2354 // Update the shell boot option
2356 InitializeListHead (&TempBootLists
);
2357 BdsLibRegisterNewOption (&TempBootLists
, DevicePath
, L
"EFI Internal Shell", L
"BootOrder");
2360 // free the temporary device path created by BdsLibUpdateFvFileDevicePath()
2362 FreePool (DevicePath
);
2363 DevicePath
= Option
->DevicePath
;
2368 if (Option
->Description
== NULL
) {
2369 DEBUG ((DEBUG_INFO
| DEBUG_LOAD
, "Booting from unknown device path\n"));
2371 DEBUG ((DEBUG_INFO
| DEBUG_LOAD
, "Booting %S\n", Option
->Description
));
2377 // Report status code for OS Loader LoadImage.
2379 REPORT_STATUS_CODE (EFI_PROGRESS_CODE
, PcdGet32 (PcdProgressCodeOsLoaderLoad
));
2380 Status
= gBS
->LoadImage (
2390 // If we didn't find an image directly, we need to try as if it is a removable device boot option
2391 // and load the image according to the default boot behavior for removable device.
2393 if (EFI_ERROR (Status
)) {
2395 // check if there is a bootable removable media could be found in this device path ,
2396 // and get the bootable media handle
2398 Handle
= BdsLibGetBootableHandle(DevicePath
);
2399 if (Handle
!= NULL
) {
2401 // Load the default boot file \EFI\BOOT\boot{machinename}.EFI from removable Media
2402 // machinename is ia32, ia64, x64, ...
2404 FilePath
= FileDevicePath (Handle
, EFI_REMOVABLE_MEDIA_FILE_NAME
);
2405 if (FilePath
!= NULL
) {
2406 REPORT_STATUS_CODE (EFI_PROGRESS_CODE
, PcdGet32 (PcdProgressCodeOsLoaderLoad
));
2407 Status
= gBS
->LoadImage (
2420 // Provide the image with it's load options
2422 if ((ImageHandle
== NULL
) || (EFI_ERROR(Status
))) {
2424 // Report Status Code to indicate that the failure to load boot option
2426 REPORT_STATUS_CODE (
2427 EFI_ERROR_CODE
| EFI_ERROR_MINOR
,
2428 (EFI_SOFTWARE_DXE_BS_DRIVER
| EFI_SW_DXE_BS_EC_BOOT_OPTION_LOAD_ERROR
)
2433 Status
= gBS
->HandleProtocol (ImageHandle
, &gEfiLoadedImageProtocolGuid
, (VOID
**) &ImageInfo
);
2434 ASSERT_EFI_ERROR (Status
);
2436 if (Option
->LoadOptionsSize
!= 0) {
2437 ImageInfo
->LoadOptionsSize
= Option
->LoadOptionsSize
;
2438 ImageInfo
->LoadOptions
= Option
->LoadOptions
;
2442 // Clean to NULL because the image is loaded directly from the firmwares boot manager.
2444 ImageInfo
->ParentHandle
= NULL
;
2447 // Before calling the image, enable the Watchdog Timer for
2448 // the 5 Minute period
2450 gBS
->SetWatchdogTimer (5 * 60, 0x0000, 0x00, NULL
);
2453 // Write boot to OS performance data for UEFI boot
2456 BmEndOfBdsPerfCode (NULL
, NULL
);
2460 // Report status code for OS Loader StartImage.
2462 REPORT_STATUS_CODE (EFI_PROGRESS_CODE
, PcdGet32 (PcdProgressCodeOsLoaderStart
));
2464 Status
= gBS
->StartImage (ImageHandle
, ExitDataSize
, ExitData
);
2465 DEBUG ((DEBUG_INFO
| DEBUG_LOAD
, "Image Return Status = %r\n", Status
));
2466 if (EFI_ERROR (Status
)) {
2468 // Report Status Code to indicate that boot failure
2470 REPORT_STATUS_CODE (
2471 EFI_ERROR_CODE
| EFI_ERROR_MINOR
,
2472 (EFI_SOFTWARE_DXE_BS_DRIVER
| EFI_SW_DXE_BS_EC_BOOT_OPTION_FAILED
)
2477 // Clear the Watchdog Timer after the image returns
2479 gBS
->SetWatchdogTimer (0x0000, 0x0000, 0x0000, NULL
);
2483 // Set Logo status invalid after trying one boot option
2486 StatusLogo
= gBS
->LocateProtocol (&gEfiBootLogoProtocolGuid
, NULL
, (VOID
**) &BootLogo
);
2487 if (!EFI_ERROR (StatusLogo
) && (BootLogo
!= NULL
)) {
2488 BootLogo
->SetBootLogo (BootLogo
, NULL
, 0, 0, 0, 0);
2492 // Clear Boot Current
2493 // Deleting variable with current implementation shouldn't fail.
2497 &gEfiGlobalVariableGuid
,
2498 EFI_VARIABLE_BOOTSERVICE_ACCESS
| EFI_VARIABLE_RUNTIME_ACCESS
,
2508 Expand a device path that starts with a hard drive media device path node to be a
2509 full device path that includes the full hardware path to the device. We need
2510 to do this so it can be booted. As an optimization the front match (the part point
2511 to the partition node. E.g. ACPI() /PCI()/ATA()/Partition() ) is saved in a variable
2512 so a connect all is not required on every boot. All successful history device path
2513 which point to partition node (the front part) will be saved.
2515 @param HardDriveDevicePath EFI Device Path to boot, if it starts with a hard
2516 drive media device path.
2517 @return A Pointer to the full device path or NULL if a valid Hard Drive devic path
2521 EFI_DEVICE_PATH_PROTOCOL
*
2523 BdsExpandPartitionPartialDevicePathToFull (
2524 IN HARDDRIVE_DEVICE_PATH
*HardDriveDevicePath
2528 UINTN BlockIoHandleCount
;
2529 EFI_HANDLE
*BlockIoBuffer
;
2530 EFI_DEVICE_PATH_PROTOCOL
*FullDevicePath
;
2531 EFI_DEVICE_PATH_PROTOCOL
*BlockIoDevicePath
;
2532 EFI_DEVICE_PATH_PROTOCOL
*DevicePath
;
2535 EFI_DEVICE_PATH_PROTOCOL
*CachedDevicePath
;
2536 EFI_DEVICE_PATH_PROTOCOL
*TempNewDevicePath
;
2537 UINTN CachedDevicePathSize
;
2538 BOOLEAN DeviceExist
;
2540 EFI_DEVICE_PATH_PROTOCOL
*Instance
;
2543 FullDevicePath
= NULL
;
2545 // Check if there is prestore HD_BOOT_DEVICE_PATH_VARIABLE_NAME variable.
2546 // If exist, search the front path which point to partition node in the variable instants.
2547 // If fail to find or HD_BOOT_DEVICE_PATH_VARIABLE_NAME not exist, reconnect all and search in all system
2550 HD_BOOT_DEVICE_PATH_VARIABLE_NAME
,
2551 &gHdBootDevicePathVariablGuid
,
2552 (VOID
**) &CachedDevicePath
,
2553 &CachedDevicePathSize
2557 // Delete the invalid HD_BOOT_DEVICE_PATH_VARIABLE_NAME variable.
2559 if ((CachedDevicePath
!= NULL
) && !IsDevicePathValid (CachedDevicePath
, CachedDevicePathSize
)) {
2560 FreePool (CachedDevicePath
);
2561 CachedDevicePath
= NULL
;
2562 Status
= gRT
->SetVariable (
2563 HD_BOOT_DEVICE_PATH_VARIABLE_NAME
,
2564 &gHdBootDevicePathVariablGuid
,
2569 ASSERT_EFI_ERROR (Status
);
2572 if (CachedDevicePath
!= NULL
) {
2573 TempNewDevicePath
= CachedDevicePath
;
2574 DeviceExist
= FALSE
;
2578 // Check every instance of the variable
2579 // First, check whether the instance contain the partition node, which is needed for distinguishing multi
2580 // partial partition boot option. Second, check whether the instance could be connected.
2582 Instance
= GetNextDevicePathInstance (&TempNewDevicePath
, &Size
);
2583 if (MatchPartitionDevicePathNode (Instance
, HardDriveDevicePath
)) {
2585 // Connect the device path instance, the device path point to hard drive media device path node
2586 // e.g. ACPI() /PCI()/ATA()/Partition()
2588 Status
= BdsLibConnectDevicePath (Instance
);
2589 if (!EFI_ERROR (Status
)) {
2595 // Come here means the first instance is not matched
2599 } while (TempNewDevicePath
!= NULL
);
2603 // Find the matched device path.
2604 // Append the file path information from the boot option and return the fully expanded device path.
2606 DevicePath
= NextDevicePathNode ((EFI_DEVICE_PATH_PROTOCOL
*) HardDriveDevicePath
);
2607 FullDevicePath
= AppendDevicePath (Instance
, DevicePath
);
2610 // Adjust the HD_BOOT_DEVICE_PATH_VARIABLE_NAME instances sequence if the matched one is not first one.
2614 // First delete the matched instance.
2616 TempNewDevicePath
= CachedDevicePath
;
2617 CachedDevicePath
= BdsLibDelPartMatchInstance (CachedDevicePath
, Instance
);
2618 FreePool (TempNewDevicePath
);
2621 // Second, append the remaining path after the matched instance
2623 TempNewDevicePath
= CachedDevicePath
;
2624 CachedDevicePath
= AppendDevicePathInstance (Instance
, CachedDevicePath
);
2625 FreePool (TempNewDevicePath
);
2627 // Save the matching Device Path so we don't need to do a connect all next time
2628 // Failure to set the variable only impacts the performance when next time expanding the short-form device path.
2630 Status
= gRT
->SetVariable (
2631 HD_BOOT_DEVICE_PATH_VARIABLE_NAME
,
2632 &gHdBootDevicePathVariablGuid
,
2633 EFI_VARIABLE_BOOTSERVICE_ACCESS
| EFI_VARIABLE_NON_VOLATILE
,
2634 GetDevicePathSize (CachedDevicePath
),
2639 FreePool (Instance
);
2640 FreePool (CachedDevicePath
);
2641 return FullDevicePath
;
2646 // If we get here we fail to find or HD_BOOT_DEVICE_PATH_VARIABLE_NAME not exist, and now we need
2647 // to search all devices in the system for a matched partition
2649 BdsLibConnectAllDriversToAllControllers ();
2650 Status
= gBS
->LocateHandleBuffer (ByProtocol
, &gEfiBlockIoProtocolGuid
, NULL
, &BlockIoHandleCount
, &BlockIoBuffer
);
2651 if (EFI_ERROR (Status
) || BlockIoHandleCount
== 0 || BlockIoBuffer
== NULL
) {
2653 // If there was an error or there are no device handles that support
2654 // the BLOCK_IO Protocol, then return.
2659 // Loop through all the device handles that support the BLOCK_IO Protocol
2661 for (Index
= 0; Index
< BlockIoHandleCount
; Index
++) {
2663 Status
= gBS
->HandleProtocol (BlockIoBuffer
[Index
], &gEfiDevicePathProtocolGuid
, (VOID
*) &BlockIoDevicePath
);
2664 if (EFI_ERROR (Status
) || BlockIoDevicePath
== NULL
) {
2668 if (MatchPartitionDevicePathNode (BlockIoDevicePath
, HardDriveDevicePath
)) {
2670 // Find the matched partition device path
2672 DevicePath
= NextDevicePathNode ((EFI_DEVICE_PATH_PROTOCOL
*) HardDriveDevicePath
);
2673 FullDevicePath
= AppendDevicePath (BlockIoDevicePath
, DevicePath
);
2676 // Save the matched partition device path in HD_BOOT_DEVICE_PATH_VARIABLE_NAME variable
2678 if (CachedDevicePath
!= NULL
) {
2680 // Save the matched partition device path as first instance of HD_BOOT_DEVICE_PATH_VARIABLE_NAME variable
2682 if (BdsLibMatchDevicePaths (CachedDevicePath
, BlockIoDevicePath
)) {
2683 TempNewDevicePath
= CachedDevicePath
;
2684 CachedDevicePath
= BdsLibDelPartMatchInstance (CachedDevicePath
, BlockIoDevicePath
);
2685 FreePool(TempNewDevicePath
);
2688 if (CachedDevicePath
!= NULL
) {
2689 TempNewDevicePath
= CachedDevicePath
;
2690 CachedDevicePath
= AppendDevicePathInstance (BlockIoDevicePath
, CachedDevicePath
);
2691 FreePool(TempNewDevicePath
);
2693 CachedDevicePath
= DuplicateDevicePath (BlockIoDevicePath
);
2697 // Here limit the device path instance number to 12, which is max number for a system support 3 IDE controller
2698 // If the user try to boot many OS in different HDs or partitions, in theory,
2699 // the HD_BOOT_DEVICE_PATH_VARIABLE_NAME variable maybe become larger and larger.
2702 ASSERT (CachedDevicePath
!= NULL
);
2703 TempNewDevicePath
= CachedDevicePath
;
2704 while (!IsDevicePathEnd (TempNewDevicePath
)) {
2705 TempNewDevicePath
= NextDevicePathNode (TempNewDevicePath
);
2707 // Parse one instance
2709 while (!IsDevicePathEndType (TempNewDevicePath
)) {
2710 TempNewDevicePath
= NextDevicePathNode (TempNewDevicePath
);
2714 // If the CachedDevicePath variable contain too much instance, only remain 12 instances.
2716 if (InstanceNum
>= 12) {
2717 SetDevicePathEndNode (TempNewDevicePath
);
2722 CachedDevicePath
= DuplicateDevicePath (BlockIoDevicePath
);
2726 // Save the matching Device Path so we don't need to do a connect all next time
2727 // Failure to set the variable only impacts the performance when next time expanding the short-form device path.
2729 Status
= gRT
->SetVariable (
2730 HD_BOOT_DEVICE_PATH_VARIABLE_NAME
,
2731 &gHdBootDevicePathVariablGuid
,
2732 EFI_VARIABLE_BOOTSERVICE_ACCESS
| EFI_VARIABLE_NON_VOLATILE
,
2733 GetDevicePathSize (CachedDevicePath
),
2741 if (CachedDevicePath
!= NULL
) {
2742 FreePool (CachedDevicePath
);
2744 if (BlockIoBuffer
!= NULL
) {
2745 FreePool (BlockIoBuffer
);
2747 return FullDevicePath
;
2751 Check whether there is a instance in BlockIoDevicePath, which contain multi device path
2752 instances, has the same partition node with HardDriveDevicePath device path
2754 @param BlockIoDevicePath Multi device path instances which need to check
2755 @param HardDriveDevicePath A device path which starts with a hard drive media
2758 @retval TRUE There is a matched device path instance.
2759 @retval FALSE There is no matched device path instance.
2764 MatchPartitionDevicePathNode (
2765 IN EFI_DEVICE_PATH_PROTOCOL
*BlockIoDevicePath
,
2766 IN HARDDRIVE_DEVICE_PATH
*HardDriveDevicePath
2769 HARDDRIVE_DEVICE_PATH
*TmpHdPath
;
2770 EFI_DEVICE_PATH_PROTOCOL
*DevicePath
;
2772 EFI_DEVICE_PATH_PROTOCOL
*BlockIoHdDevicePathNode
;
2774 if ((BlockIoDevicePath
== NULL
) || (HardDriveDevicePath
== NULL
)) {
2779 // Make PreviousDevicePath == the device path node before the end node
2781 DevicePath
= BlockIoDevicePath
;
2782 BlockIoHdDevicePathNode
= NULL
;
2785 // find the partition device path node
2787 while (!IsDevicePathEnd (DevicePath
)) {
2788 if ((DevicePathType (DevicePath
) == MEDIA_DEVICE_PATH
) &&
2789 (DevicePathSubType (DevicePath
) == MEDIA_HARDDRIVE_DP
)
2791 BlockIoHdDevicePathNode
= DevicePath
;
2795 DevicePath
= NextDevicePathNode (DevicePath
);
2798 if (BlockIoHdDevicePathNode
== NULL
) {
2802 // See if the harddrive device path in blockio matches the orig Hard Drive Node
2804 TmpHdPath
= (HARDDRIVE_DEVICE_PATH
*) BlockIoHdDevicePathNode
;
2808 // Check for the match
2810 if ((TmpHdPath
->MBRType
== HardDriveDevicePath
->MBRType
) &&
2811 (TmpHdPath
->SignatureType
== HardDriveDevicePath
->SignatureType
)) {
2812 switch (TmpHdPath
->SignatureType
) {
2813 case SIGNATURE_TYPE_GUID
:
2814 Match
= CompareGuid ((EFI_GUID
*)TmpHdPath
->Signature
, (EFI_GUID
*)HardDriveDevicePath
->Signature
);
2816 case SIGNATURE_TYPE_MBR
:
2817 Match
= (BOOLEAN
)(*((UINT32
*)(&(TmpHdPath
->Signature
[0]))) == ReadUnaligned32((UINT32
*)(&(HardDriveDevicePath
->Signature
[0]))));
2829 Delete the boot option associated with the handle passed in.
2831 @param Handle The handle which present the device path to create
2834 @retval EFI_SUCCESS Delete the boot option success
2835 @retval EFI_NOT_FOUND If the Device Path is not found in the system
2836 @retval EFI_OUT_OF_RESOURCES Lack of memory resource
2837 @retval Other Error return value from SetVariable()
2841 BdsLibDeleteOptionFromHandle (
2842 IN EFI_HANDLE Handle
2846 UINT8
*BootOptionVar
;
2847 UINTN BootOrderSize
;
2848 UINTN BootOptionSize
;
2851 UINT16 BootOption
[BOOT_OPTION_MAX_CHAR
];
2852 UINTN DevicePathSize
;
2853 UINTN OptionDevicePathSize
;
2854 EFI_DEVICE_PATH_PROTOCOL
*DevicePath
;
2855 EFI_DEVICE_PATH_PROTOCOL
*OptionDevicePath
;
2858 Status
= EFI_SUCCESS
;
2863 // Check "BootOrder" variable, if no, means there is no any boot order.
2865 BootOrder
= BdsLibGetVariableAndSize (
2867 &gEfiGlobalVariableGuid
,
2870 if (BootOrder
== NULL
) {
2871 return EFI_NOT_FOUND
;
2875 // Convert device handle to device path protocol instance
2877 DevicePath
= DevicePathFromHandle (Handle
);
2878 if (DevicePath
== NULL
) {
2879 return EFI_NOT_FOUND
;
2881 DevicePathSize
= GetDevicePathSize (DevicePath
);
2884 // Loop all boot order variable and find the matching device path
2887 while (Index
< BootOrderSize
/ sizeof (UINT16
)) {
2888 UnicodeSPrint (BootOption
, sizeof (BootOption
), L
"Boot%04x", BootOrder
[Index
]);
2889 BootOptionVar
= BdsLibGetVariableAndSize (
2891 &gEfiGlobalVariableGuid
,
2895 if (BootOptionVar
== NULL
) {
2896 FreePool (BootOrder
);
2897 return EFI_OUT_OF_RESOURCES
;
2900 if (!ValidateOption(BootOptionVar
, BootOptionSize
)) {
2901 BdsDeleteBootOption (BootOrder
[Index
], BootOrder
, &BootOrderSize
);
2902 FreePool (BootOptionVar
);
2907 TempPtr
= BootOptionVar
;
2908 TempPtr
+= sizeof (UINT32
) + sizeof (UINT16
);
2909 TempPtr
+= StrSize ((CHAR16
*) TempPtr
);
2910 OptionDevicePath
= (EFI_DEVICE_PATH_PROTOCOL
*) TempPtr
;
2911 OptionDevicePathSize
= GetDevicePathSize (OptionDevicePath
);
2914 // Check whether the device path match
2916 if ((OptionDevicePathSize
== DevicePathSize
) &&
2917 (CompareMem (DevicePath
, OptionDevicePath
, DevicePathSize
) == 0)) {
2918 BdsDeleteBootOption (BootOrder
[Index
], BootOrder
, &BootOrderSize
);
2919 FreePool (BootOptionVar
);
2923 FreePool (BootOptionVar
);
2928 // Adjust number of boot option for "BootOrder" variable.
2930 Status
= gRT
->SetVariable (
2932 &gEfiGlobalVariableGuid
,
2933 EFI_VARIABLE_BOOTSERVICE_ACCESS
| EFI_VARIABLE_RUNTIME_ACCESS
| EFI_VARIABLE_NON_VOLATILE
,
2938 // Shrinking variable with existing variable implementation shouldn't fail.
2940 ASSERT_EFI_ERROR (Status
);
2942 FreePool (BootOrder
);
2949 Delete all invalid EFI boot options.
2951 @retval EFI_SUCCESS Delete all invalid boot option success
2952 @retval EFI_NOT_FOUND Variable "BootOrder" is not found
2953 @retval EFI_OUT_OF_RESOURCES Lack of memory resource
2954 @retval Other Error return value from SetVariable()
2958 BdsDeleteAllInvalidEfiBootOption (
2963 UINT8
*BootOptionVar
;
2964 UINTN BootOrderSize
;
2965 UINTN BootOptionSize
;
2969 UINT16 BootOption
[BOOT_OPTION_MAX_CHAR
];
2970 EFI_DEVICE_PATH_PROTOCOL
*OptionDevicePath
;
2972 CHAR16
*Description
;
2975 Status
= EFI_SUCCESS
;
2978 OptionDevicePath
= NULL
;
2983 // Check "BootOrder" variable firstly, this variable hold the number of boot options
2985 BootOrder
= BdsLibGetVariableAndSize (
2987 &gEfiGlobalVariableGuid
,
2990 if (NULL
== BootOrder
) {
2991 return EFI_NOT_FOUND
;
2995 while (Index
< BootOrderSize
/ sizeof (UINT16
)) {
2996 UnicodeSPrint (BootOption
, sizeof (BootOption
), L
"Boot%04x", BootOrder
[Index
]);
2997 BootOptionVar
= BdsLibGetVariableAndSize (
2999 &gEfiGlobalVariableGuid
,
3002 if (NULL
== BootOptionVar
) {
3003 FreePool (BootOrder
);
3004 return EFI_OUT_OF_RESOURCES
;
3007 if (!ValidateOption(BootOptionVar
, BootOptionSize
)) {
3010 TempPtr
= BootOptionVar
;
3011 TempPtr
+= sizeof (UINT32
) + sizeof (UINT16
);
3012 Description
= (CHAR16
*) TempPtr
;
3013 TempPtr
+= StrSize ((CHAR16
*) TempPtr
);
3014 OptionDevicePath
= (EFI_DEVICE_PATH_PROTOCOL
*) TempPtr
;
3017 // Skip legacy boot option (BBS boot device)
3019 if ((DevicePathType (OptionDevicePath
) == BBS_DEVICE_PATH
) &&
3020 (DevicePathSubType (OptionDevicePath
) == BBS_BBS_DP
)) {
3021 FreePool (BootOptionVar
);
3027 if (Corrupted
|| !BdsLibIsValidEFIBootOptDevicePathExt (OptionDevicePath
, FALSE
, Description
)) {
3029 // Delete this invalid boot option "Boot####"
3031 Status
= gRT
->SetVariable (
3033 &gEfiGlobalVariableGuid
,
3034 EFI_VARIABLE_BOOTSERVICE_ACCESS
| EFI_VARIABLE_RUNTIME_ACCESS
| EFI_VARIABLE_NON_VOLATILE
,
3039 // Deleting variable with current variable implementation shouldn't fail.
3041 ASSERT_EFI_ERROR (Status
);
3043 // Mark this boot option in boot order as deleted
3045 BootOrder
[Index
] = 0xffff;
3049 FreePool (BootOptionVar
);
3054 // Adjust boot order array
3057 for (Index
= 0; Index
< BootOrderSize
/ sizeof (UINT16
); Index
++) {
3058 if (BootOrder
[Index
] != 0xffff) {
3059 BootOrder
[Index2
] = BootOrder
[Index
];
3063 Status
= gRT
->SetVariable (
3065 &gEfiGlobalVariableGuid
,
3066 EFI_VARIABLE_BOOTSERVICE_ACCESS
| EFI_VARIABLE_RUNTIME_ACCESS
| EFI_VARIABLE_NON_VOLATILE
,
3067 Index2
* sizeof (UINT16
),
3071 // Shrinking variable with current variable implementation shouldn't fail.
3073 ASSERT_EFI_ERROR (Status
);
3075 FreePool (BootOrder
);
3082 For EFI boot option, BDS separate them as six types:
3083 1. Network - The boot option points to the SimpleNetworkProtocol device.
3084 Bds will try to automatically create this type boot option when enumerate.
3085 2. Shell - The boot option points to internal flash shell.
3086 Bds will try to automatically create this type boot option when enumerate.
3087 3. Removable BlockIo - The boot option only points to the removable media
3088 device, like USB flash disk, DVD, Floppy etc.
3089 These device should contain a *removable* blockIo
3090 protocol in their device handle.
3091 Bds will try to automatically create this type boot option
3093 4. Fixed BlockIo - The boot option only points to a Fixed blockIo device,
3095 These device should contain a *fixed* blockIo
3096 protocol in their device handle.
3097 BDS will skip fixed blockIo devices, and NOT
3098 automatically create boot option for them. But BDS
3099 will help to delete those fixed blockIo boot option,
3100 whose description rule conflict with other auto-created
3102 5. Non-BlockIo Simplefile - The boot option points to a device whose handle
3103 has SimpleFileSystem Protocol, but has no blockio
3104 protocol. These devices do not offer blockIo
3105 protocol, but BDS still can get the
3106 \EFI\BOOT\boot{machinename}.EFI by SimpleFileSystem
3108 6. File - The boot option points to a file. These boot options are usually
3109 created by user manually or OS loader. BDS will not delete or modify
3112 This function will enumerate all possible boot device in the system, and
3113 automatically create boot options for Network, Shell, Removable BlockIo,
3114 and Non-BlockIo Simplefile devices.
3115 It will only execute once of every boot.
3117 @param BdsBootOptionList The header of the link list which indexed all
3118 current boot options
3120 @retval EFI_SUCCESS Finished all the boot device enumerate and create
3121 the boot option base on that boot device
3123 @retval EFI_OUT_OF_RESOURCES Failed to enumerate the boot device and create the boot option list
3127 BdsLibEnumerateAllBootOption (
3128 IN OUT LIST_ENTRY
*BdsBootOptionList
3132 UINT16 FloppyNumber
;
3133 UINT16 HarddriveNumber
;
3138 UINT16 NonBlockNumber
;
3139 UINTN NumberBlockIoHandles
;
3140 EFI_HANDLE
*BlockIoHandles
;
3141 EFI_BLOCK_IO_PROTOCOL
*BlkIo
;
3142 BOOLEAN Removable
[2];
3143 UINTN RemovableIndex
;
3145 UINTN NumOfLoadFileHandles
;
3146 EFI_HANDLE
*LoadFileHandles
;
3147 UINTN FvHandleCount
;
3148 EFI_HANDLE
*FvHandleBuffer
;
3149 EFI_FV_FILETYPE Type
;
3151 EFI_FV_FILE_ATTRIBUTES Attributes
;
3152 UINT32 AuthenticationStatus
;
3153 EFI_FIRMWARE_VOLUME2_PROTOCOL
*Fv
;
3154 EFI_DEVICE_PATH_PROTOCOL
*DevicePath
;
3155 UINTN DevicePathType
;
3157 EFI_HANDLE
*FileSystemHandles
;
3158 UINTN NumberFileSystemHandles
;
3160 EFI_IMAGE_DOS_HEADER DosHeader
;
3163 EFI_IMAGE_OPTIONAL_HEADER_UNION HdrData
;
3164 EFI_IMAGE_OPTIONAL_HEADER_PTR_UNION Hdr
;
3167 EFI_HANDLE
*NetworkHandles
;
3171 HarddriveNumber
= 0;
3178 ZeroMem (Buffer
, sizeof (Buffer
));
3181 // If the boot device enumerate happened, just get the boot
3182 // device from the boot order variable
3184 if (mEnumBootDevice
) {
3185 GetVariable2 (LAST_ENUM_LANGUAGE_VARIABLE_NAME
, &gLastEnumLangGuid
, (VOID
**)&LastLang
, NULL
);
3186 GetEfiGlobalVariable2 (L
"PlatformLang", (VOID
**)&PlatLang
, NULL
);
3187 ASSERT (PlatLang
!= NULL
);
3188 if ((LastLang
!= NULL
) && (AsciiStrCmp (LastLang
, PlatLang
) == 0)) {
3189 Status
= BdsLibBuildOptionFromVar (BdsBootOptionList
, L
"BootOrder");
3190 FreePool (LastLang
);
3191 FreePool (PlatLang
);
3194 Status
= gRT
->SetVariable (
3195 LAST_ENUM_LANGUAGE_VARIABLE_NAME
,
3197 EFI_VARIABLE_BOOTSERVICE_ACCESS
| EFI_VARIABLE_NON_VOLATILE
,
3198 AsciiStrSize (PlatLang
),
3202 // Failure to set the variable only impacts the performance next time enumerating the boot options.
3205 if (LastLang
!= NULL
) {
3206 FreePool (LastLang
);
3208 FreePool (PlatLang
);
3213 // Notes: this dirty code is to get the legacy boot option from the
3214 // BBS table and create to variable as the EFI boot option, it should
3215 // be removed after the CSM can provide legacy boot option directly
3217 REFRESH_LEGACY_BOOT_OPTIONS
;
3220 // Delete invalid boot option
3222 BdsDeleteAllInvalidEfiBootOption ();
3225 // Parse removable media followed by fixed media.
3226 // The Removable[] array is used by the for-loop below to create removable media boot options
3227 // at first, and then to create fixed media boot options.
3229 Removable
[0] = FALSE
;
3230 Removable
[1] = TRUE
;
3232 gBS
->LocateHandleBuffer (
3234 &gEfiBlockIoProtocolGuid
,
3236 &NumberBlockIoHandles
,
3240 for (RemovableIndex
= 0; RemovableIndex
< 2; RemovableIndex
++) {
3241 for (Index
= 0; Index
< NumberBlockIoHandles
; Index
++) {
3242 Status
= gBS
->HandleProtocol (
3243 BlockIoHandles
[Index
],
3244 &gEfiBlockIoProtocolGuid
,
3248 // skip the logical partition
3250 if (EFI_ERROR (Status
) || BlkIo
->Media
->LogicalPartition
) {
3255 // firstly fixed block io then the removable block io
3257 if (BlkIo
->Media
->RemovableMedia
== Removable
[RemovableIndex
]) {
3260 DevicePath
= DevicePathFromHandle (BlockIoHandles
[Index
]);
3261 DevicePathType
= BdsGetBootTypeFromDevicePath (DevicePath
);
3263 switch (DevicePathType
) {
3264 case BDS_EFI_ACPI_FLOPPY_BOOT
:
3265 if (FloppyNumber
!= 0) {
3266 UnicodeSPrint (Buffer
, sizeof (Buffer
), L
"%s %d", BdsLibGetStringById (STRING_TOKEN (STR_DESCRIPTION_FLOPPY
)), FloppyNumber
);
3268 UnicodeSPrint (Buffer
, sizeof (Buffer
), L
"%s", BdsLibGetStringById (STRING_TOKEN (STR_DESCRIPTION_FLOPPY
)));
3270 BdsLibBuildOptionFromHandle (BlockIoHandles
[Index
], BdsBootOptionList
, Buffer
);
3275 // Assume a removable SATA device should be the DVD/CD device, a fixed SATA device should be the Hard Drive device.
3277 case BDS_EFI_MESSAGE_ATAPI_BOOT
:
3278 case BDS_EFI_MESSAGE_SATA_BOOT
:
3279 if (BlkIo
->Media
->RemovableMedia
) {
3280 if (CdromNumber
!= 0) {
3281 UnicodeSPrint (Buffer
, sizeof (Buffer
), L
"%s %d", BdsLibGetStringById (STRING_TOKEN (STR_DESCRIPTION_CD_DVD
)), CdromNumber
);
3283 UnicodeSPrint (Buffer
, sizeof (Buffer
), L
"%s", BdsLibGetStringById (STRING_TOKEN (STR_DESCRIPTION_CD_DVD
)));
3287 if (HarddriveNumber
!= 0) {
3288 UnicodeSPrint (Buffer
, sizeof (Buffer
), L
"%s %d", BdsLibGetStringById (STRING_TOKEN (STR_DESCRIPTION_HARDDRIVE
)), HarddriveNumber
);
3290 UnicodeSPrint (Buffer
, sizeof (Buffer
), L
"%s", BdsLibGetStringById (STRING_TOKEN (STR_DESCRIPTION_HARDDRIVE
)));
3294 DEBUG ((DEBUG_INFO
| DEBUG_LOAD
, "Buffer: %S\n", Buffer
));
3295 BdsLibBuildOptionFromHandle (BlockIoHandles
[Index
], BdsBootOptionList
, Buffer
);
3298 case BDS_EFI_MESSAGE_USB_DEVICE_BOOT
:
3299 if (UsbNumber
!= 0) {
3300 UnicodeSPrint (Buffer
, sizeof (Buffer
), L
"%s %d", BdsLibGetStringById (STRING_TOKEN (STR_DESCRIPTION_USB
)), UsbNumber
);
3302 UnicodeSPrint (Buffer
, sizeof (Buffer
), L
"%s", BdsLibGetStringById (STRING_TOKEN (STR_DESCRIPTION_USB
)));
3304 BdsLibBuildOptionFromHandle (BlockIoHandles
[Index
], BdsBootOptionList
, Buffer
);
3308 case BDS_EFI_MESSAGE_SCSI_BOOT
:
3309 if (ScsiNumber
!= 0) {
3310 UnicodeSPrint (Buffer
, sizeof (Buffer
), L
"%s %d", BdsLibGetStringById (STRING_TOKEN (STR_DESCRIPTION_SCSI
)), ScsiNumber
);
3312 UnicodeSPrint (Buffer
, sizeof (Buffer
), L
"%s", BdsLibGetStringById (STRING_TOKEN (STR_DESCRIPTION_SCSI
)));
3314 BdsLibBuildOptionFromHandle (BlockIoHandles
[Index
], BdsBootOptionList
, Buffer
);
3318 case BDS_EFI_MESSAGE_MISC_BOOT
:
3320 if (MiscNumber
!= 0) {
3321 UnicodeSPrint (Buffer
, sizeof (Buffer
), L
"%s %d", BdsLibGetStringById (STRING_TOKEN (STR_DESCRIPTION_MISC
)), MiscNumber
);
3323 UnicodeSPrint (Buffer
, sizeof (Buffer
), L
"%s", BdsLibGetStringById (STRING_TOKEN (STR_DESCRIPTION_MISC
)));
3325 BdsLibBuildOptionFromHandle (BlockIoHandles
[Index
], BdsBootOptionList
, Buffer
);
3332 if (NumberBlockIoHandles
!= 0) {
3333 FreePool (BlockIoHandles
);
3337 // If there is simple file protocol which does not consume block Io protocol, create a boot option for it here.
3340 gBS
->LocateHandleBuffer (
3342 &gEfiSimpleFileSystemProtocolGuid
,
3344 &NumberFileSystemHandles
,
3347 for (Index
= 0; Index
< NumberFileSystemHandles
; Index
++) {
3348 Status
= gBS
->HandleProtocol (
3349 FileSystemHandles
[Index
],
3350 &gEfiBlockIoProtocolGuid
,
3353 if (!EFI_ERROR (Status
)) {
3355 // Skip if the file system handle supports a BlkIo protocol,
3361 // Do the removable Media thing. \EFI\BOOT\boot{machinename}.EFI
3362 // machinename is ia32, ia64, x64, ...
3364 Hdr
.Union
= &HdrData
;
3366 Status
= BdsLibGetImageHeader (
3367 FileSystemHandles
[Index
],
3368 EFI_REMOVABLE_MEDIA_FILE_NAME
,
3372 if (!EFI_ERROR (Status
) &&
3373 EFI_IMAGE_MACHINE_TYPE_SUPPORTED (Hdr
.Pe32
->FileHeader
.Machine
) &&
3374 Hdr
.Pe32
->OptionalHeader
.Subsystem
== EFI_IMAGE_SUBSYSTEM_EFI_APPLICATION
) {
3380 // No such file or the file is not a EFI application, delete this boot option
3382 BdsLibDeleteOptionFromHandle (FileSystemHandles
[Index
]);
3384 if (NonBlockNumber
!= 0) {
3385 UnicodeSPrint (Buffer
, sizeof (Buffer
), L
"%s %d", BdsLibGetStringById (STRING_TOKEN (STR_DESCRIPTION_NON_BLOCK
)), NonBlockNumber
);
3387 UnicodeSPrint (Buffer
, sizeof (Buffer
), L
"%s", BdsLibGetStringById (STRING_TOKEN (STR_DESCRIPTION_NON_BLOCK
)));
3389 BdsLibBuildOptionFromHandle (FileSystemHandles
[Index
], BdsBootOptionList
, Buffer
);
3394 if (NumberFileSystemHandles
!= 0) {
3395 FreePool (FileSystemHandles
);
3399 // Parse Network Boot Device
3401 NumOfLoadFileHandles
= 0;
3403 // Search Load File protocol for PXE boot option.
3405 gBS
->LocateHandleBuffer (
3407 &gEfiLoadFileProtocolGuid
,
3409 &NumOfLoadFileHandles
,
3413 for (Index
= 0; Index
< NumOfLoadFileHandles
; Index
++) {
3416 //Locate EFI_DEVICE_PATH_PROTOCOL to dynamically get IPv4/IPv6 protocol information.
3419 Status
= gBS
->HandleProtocol (
3420 LoadFileHandles
[Index
],
3421 &gEfiDevicePathProtocolGuid
,
3422 (VOID
**) &DevicePath
3425 ASSERT_EFI_ERROR (Status
);
3427 while (!IsDevicePathEnd (DevicePath
)) {
3428 if ((DevicePath
->Type
== MESSAGING_DEVICE_PATH
) &&
3429 (DevicePath
->SubType
== MSG_IPv4_DP
)) {
3432 //Get handle infomation
3435 NetworkHandles
= NULL
;
3436 Status
= gBS
->LocateHandle (
3438 &gEfiSimpleNetworkProtocolGuid
,
3444 if (Status
== EFI_BUFFER_TOO_SMALL
) {
3445 NetworkHandles
= AllocateZeroPool(BufferSize
);
3446 if (NetworkHandles
== NULL
) {
3447 return (EFI_OUT_OF_RESOURCES
);
3449 Status
= gBS
->LocateHandle(
3451 &gEfiSimpleNetworkProtocolGuid
,
3459 //Get the MAC string
3461 Status
= NetLibGetMacString (
3466 if (EFI_ERROR (Status
)) {
3469 IPverStr
= L
" IPv4";
3470 UnicodeSPrint (Buffer
, sizeof (Buffer
), L
"%s%s%s", BdsLibGetStringById (STRING_TOKEN (STR_DESCRIPTION_NETWORK
)),MacStr
,IPverStr
);
3473 if((DevicePath
->Type
== MESSAGING_DEVICE_PATH
) &&
3474 (DevicePath
->SubType
== MSG_IPv6_DP
)) {
3477 //Get handle infomation
3480 NetworkHandles
= NULL
;
3481 Status
= gBS
->LocateHandle (
3483 &gEfiSimpleNetworkProtocolGuid
,
3489 if (Status
== EFI_BUFFER_TOO_SMALL
) {
3490 NetworkHandles
= AllocateZeroPool(BufferSize
);
3491 if (NetworkHandles
== NULL
) {
3492 return (EFI_OUT_OF_RESOURCES
);
3494 Status
= gBS
->LocateHandle(
3496 &gEfiSimpleNetworkProtocolGuid
,
3504 //Get the MAC string
3506 Status
= NetLibGetMacString (
3511 if (EFI_ERROR (Status
)) {
3514 IPverStr
= L
" IPv6";
3515 UnicodeSPrint (Buffer
, sizeof (Buffer
), L
"%s%s%s", BdsLibGetStringById (STRING_TOKEN (STR_DESCRIPTION_NETWORK
)),MacStr
,IPverStr
);
3518 DevicePath
= NextDevicePathNode (DevicePath
);
3521 BdsLibBuildOptionFromHandle (LoadFileHandles
[Index
], BdsBootOptionList
, Buffer
);
3524 if (NumOfLoadFileHandles
!= 0) {
3525 FreePool (LoadFileHandles
);
3529 // Check if we have on flash shell
3531 gBS
->LocateHandleBuffer (
3533 &gEfiFirmwareVolume2ProtocolGuid
,
3538 for (Index
= 0; Index
< FvHandleCount
; Index
++) {
3539 gBS
->HandleProtocol (
3540 FvHandleBuffer
[Index
],
3541 &gEfiFirmwareVolume2ProtocolGuid
,
3545 Status
= Fv
->ReadFile (
3547 &gUefiShellFileGuid
,
3552 &AuthenticationStatus
3554 if (EFI_ERROR (Status
)) {
3556 // Skip if no shell file in the FV
3561 // Build the shell boot option
3563 BdsLibBuildOptionFromShell (FvHandleBuffer
[Index
], BdsBootOptionList
);
3566 if (FvHandleCount
!= 0) {
3567 FreePool (FvHandleBuffer
);
3570 // Make sure every boot only have one time
3571 // boot device enumerate
3573 Status
= BdsLibBuildOptionFromVar (BdsBootOptionList
, L
"BootOrder");
3574 mEnumBootDevice
= TRUE
;
3580 Build the boot option with the handle parsed in
3582 @param Handle The handle which present the device path to create
3584 @param BdsBootOptionList The header of the link list which indexed all
3585 current boot options
3586 @param String The description of the boot option.
3591 BdsLibBuildOptionFromHandle (
3592 IN EFI_HANDLE Handle
,
3593 IN LIST_ENTRY
*BdsBootOptionList
,
3597 EFI_DEVICE_PATH_PROTOCOL
*DevicePath
;
3599 DevicePath
= DevicePathFromHandle (Handle
);
3602 // Create and register new boot option
3604 BdsLibRegisterNewOption (BdsBootOptionList
, DevicePath
, String
, L
"BootOrder");
3609 Build the on flash shell boot option with the handle parsed in.
3611 @param Handle The handle which present the device path to create
3612 on flash shell boot option
3613 @param BdsBootOptionList The header of the link list which indexed all
3614 current boot options
3619 BdsLibBuildOptionFromShell (
3620 IN EFI_HANDLE Handle
,
3621 IN OUT LIST_ENTRY
*BdsBootOptionList
3624 EFI_DEVICE_PATH_PROTOCOL
*DevicePath
;
3625 MEDIA_FW_VOL_FILEPATH_DEVICE_PATH ShellNode
;
3627 DevicePath
= DevicePathFromHandle (Handle
);
3630 // Build the shell device path
3632 EfiInitializeFwVolDevicepathNode (&ShellNode
, &gUefiShellFileGuid
);
3634 DevicePath
= AppendDevicePathNode (DevicePath
, (EFI_DEVICE_PATH_PROTOCOL
*) &ShellNode
);
3637 // Create and register the shell boot option
3639 BdsLibRegisterNewOption (BdsBootOptionList
, DevicePath
, L
"EFI Internal Shell", L
"BootOrder");
3644 Boot from the UEFI spec defined "BootNext" variable.
3657 BDS_COMMON_OPTION
*BootOption
;
3658 LIST_ENTRY TempList
;
3663 // Init the boot option name buffer and temp link list
3665 InitializeListHead (&TempList
);
3666 ZeroMem (Buffer
, sizeof (Buffer
));
3668 BootNext
= BdsLibGetVariableAndSize (
3670 &gEfiGlobalVariableGuid
,
3675 // Clear the boot next variable first
3677 if (BootNext
!= NULL
) {
3678 Status
= gRT
->SetVariable (
3680 &gEfiGlobalVariableGuid
,
3681 EFI_VARIABLE_BOOTSERVICE_ACCESS
| EFI_VARIABLE_RUNTIME_ACCESS
| EFI_VARIABLE_NON_VOLATILE
,
3686 // Deleting variable with current variable implementation shouldn't fail.
3688 ASSERT_EFI_ERROR (Status
);
3691 // Start to build the boot option and try to boot
3693 UnicodeSPrint (Buffer
, sizeof (Buffer
), L
"Boot%04x", *BootNext
);
3694 BootOption
= BdsLibVariableToOption (&TempList
, Buffer
);
3695 ASSERT (BootOption
!= NULL
);
3696 BdsLibConnectDevicePath (BootOption
->DevicePath
);
3697 BdsLibBootViaBootOption (BootOption
, BootOption
->DevicePath
, &ExitDataSize
, &ExitData
);
3698 FreePool(BootOption
);
3705 Return the bootable media handle.
3706 First, check the device is connected
3707 Second, check whether the device path point to a device which support SimpleFileSystemProtocol,
3708 Third, detect the the default boot file in the Media, and return the removable Media handle.
3710 @param DevicePath Device Path to a bootable device
3712 @return The bootable media handle. If the media on the DevicePath is not bootable, NULL will return.
3717 BdsLibGetBootableHandle (
3718 IN EFI_DEVICE_PATH_PROTOCOL
*DevicePath
3723 EFI_DEVICE_PATH_PROTOCOL
*UpdatedDevicePath
;
3724 EFI_DEVICE_PATH_PROTOCOL
*DupDevicePath
;
3726 EFI_BLOCK_IO_PROTOCOL
*BlockIo
;
3728 EFI_DEVICE_PATH_PROTOCOL
*TempDevicePath
;
3731 EFI_HANDLE ReturnHandle
;
3732 EFI_HANDLE
*SimpleFileSystemHandles
;
3734 UINTN NumberSimpleFileSystemHandles
;
3736 EFI_IMAGE_DOS_HEADER DosHeader
;
3737 EFI_IMAGE_OPTIONAL_HEADER_UNION HdrData
;
3738 EFI_IMAGE_OPTIONAL_HEADER_PTR_UNION Hdr
;
3740 UpdatedDevicePath
= DevicePath
;
3743 // Enter to critical section to protect the acquired BlockIo instance
3744 // from getting released due to the USB mass storage hotplug event
3746 OldTpl
= gBS
->RaiseTPL (TPL_CALLBACK
);
3749 // Check whether the device is connected
3751 Status
= gBS
->LocateDevicePath (&gEfiBlockIoProtocolGuid
, &UpdatedDevicePath
, &Handle
);
3752 if (EFI_ERROR (Status
)) {
3754 // Skip the case that the boot option point to a simple file protocol which does not consume block Io protocol,
3756 Status
= gBS
->LocateDevicePath (&gEfiSimpleFileSystemProtocolGuid
, &UpdatedDevicePath
, &Handle
);
3757 if (EFI_ERROR (Status
)) {
3759 // Fail to find the proper BlockIo and simple file protocol, maybe because device not present, we need to connect it firstly
3761 UpdatedDevicePath
= DevicePath
;
3762 Status
= gBS
->LocateDevicePath (&gEfiDevicePathProtocolGuid
, &UpdatedDevicePath
, &Handle
);
3763 gBS
->ConnectController (Handle
, NULL
, NULL
, TRUE
);
3767 // For removable device boot option, its contained device path only point to the removable device handle,
3768 // should make sure all its children handles (its child partion or media handles) are created and connected.
3770 gBS
->ConnectController (Handle
, NULL
, NULL
, TRUE
);
3772 // Get BlockIo protocol and check removable attribute
3774 Status
= gBS
->HandleProtocol (Handle
, &gEfiBlockIoProtocolGuid
, (VOID
**)&BlockIo
);
3775 ASSERT_EFI_ERROR (Status
);
3778 // Issue a dummy read to the device to check for media change.
3779 // When the removable media is changed, any Block IO read/write will
3780 // cause the BlockIo protocol be reinstalled and EFI_MEDIA_CHANGED is
3781 // returned. After the Block IO protocol is reinstalled, subsequent
3782 // Block IO read/write will success.
3784 Buffer
= AllocatePool (BlockIo
->Media
->BlockSize
);
3785 if (Buffer
!= NULL
) {
3786 BlockIo
->ReadBlocks (
3788 BlockIo
->Media
->MediaId
,
3790 BlockIo
->Media
->BlockSize
,
3798 // Detect the the default boot file from removable Media
3802 // 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
3803 // Try to locate the USB node device path first, if fail then use its previous PCI node to search
3805 DupDevicePath
= DuplicateDevicePath (DevicePath
);
3806 ASSERT (DupDevicePath
!= NULL
);
3808 UpdatedDevicePath
= DupDevicePath
;
3809 Status
= gBS
->LocateDevicePath (&gEfiDevicePathProtocolGuid
, &UpdatedDevicePath
, &Handle
);
3811 // 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
3812 // Acpi()/Pci()/Usb() --> Acpi()/Pci()
3814 if ((DevicePathType (UpdatedDevicePath
) == MESSAGING_DEVICE_PATH
) &&
3815 (DevicePathSubType (UpdatedDevicePath
) == MSG_USB_DP
)) {
3817 // Remove the usb node, let the device path only point to PCI node
3819 SetDevicePathEndNode (UpdatedDevicePath
);
3820 UpdatedDevicePath
= DupDevicePath
;
3822 UpdatedDevicePath
= DevicePath
;
3826 // Get the device path size of boot option
3828 Size
= GetDevicePathSize(UpdatedDevicePath
) - sizeof (EFI_DEVICE_PATH_PROTOCOL
); // minus the end node
3829 ReturnHandle
= NULL
;
3830 gBS
->LocateHandleBuffer (
3832 &gEfiSimpleFileSystemProtocolGuid
,
3834 &NumberSimpleFileSystemHandles
,
3835 &SimpleFileSystemHandles
3837 for (Index
= 0; Index
< NumberSimpleFileSystemHandles
; Index
++) {
3839 // Get the device path size of SimpleFileSystem handle
3841 TempDevicePath
= DevicePathFromHandle (SimpleFileSystemHandles
[Index
]);
3842 TempSize
= GetDevicePathSize (TempDevicePath
)- sizeof (EFI_DEVICE_PATH_PROTOCOL
); // minus the end node
3844 // Check whether the device path of boot option is part of the SimpleFileSystem handle's device path
3846 if (Size
<= TempSize
&& CompareMem (TempDevicePath
, UpdatedDevicePath
, Size
)==0) {
3848 // Load the default boot file \EFI\BOOT\boot{machinename}.EFI from removable Media
3849 // machinename is ia32, ia64, x64, ...
3851 Hdr
.Union
= &HdrData
;
3852 Status
= BdsLibGetImageHeader (
3853 SimpleFileSystemHandles
[Index
],
3854 EFI_REMOVABLE_MEDIA_FILE_NAME
,
3858 if (!EFI_ERROR (Status
) &&
3859 EFI_IMAGE_MACHINE_TYPE_SUPPORTED (Hdr
.Pe32
->FileHeader
.Machine
) &&
3860 Hdr
.Pe32
->OptionalHeader
.Subsystem
== EFI_IMAGE_SUBSYSTEM_EFI_APPLICATION
) {
3861 ReturnHandle
= SimpleFileSystemHandles
[Index
];
3867 FreePool(DupDevicePath
);
3869 if (SimpleFileSystemHandles
!= NULL
) {
3870 FreePool(SimpleFileSystemHandles
);
3873 gBS
->RestoreTPL (OldTpl
);
3875 return ReturnHandle
;
3879 Check to see if the network cable is plugged in. If the DevicePath is not
3880 connected it will be connected.
3882 @param DevicePath Device Path to check
3884 @retval TRUE DevicePath points to an Network that is connected
3885 @retval FALSE DevicePath does not point to a bootable network
3889 BdsLibNetworkBootWithMediaPresent (
3890 IN EFI_DEVICE_PATH_PROTOCOL
*DevicePath
3894 EFI_DEVICE_PATH_PROTOCOL
*UpdatedDevicePath
;
3896 EFI_SIMPLE_NETWORK_PROTOCOL
*Snp
;
3897 BOOLEAN MediaPresent
;
3898 UINT32 InterruptStatus
;
3900 MediaPresent
= FALSE
;
3902 UpdatedDevicePath
= DevicePath
;
3904 // Locate Load File Protocol for PXE boot option first
3906 Status
= gBS
->LocateDevicePath (&gEfiLoadFileProtocolGuid
, &UpdatedDevicePath
, &Handle
);
3907 if (EFI_ERROR (Status
)) {
3909 // Device not present so see if we need to connect it
3911 Status
= BdsLibConnectDevicePath (DevicePath
);
3912 if (!EFI_ERROR (Status
)) {
3914 // This one should work after we did the connect
3916 Status
= gBS
->LocateDevicePath (&gEfiLoadFileProtocolGuid
, &UpdatedDevicePath
, &Handle
);
3920 if (!EFI_ERROR (Status
)) {
3921 Status
= gBS
->HandleProtocol (Handle
, &gEfiSimpleNetworkProtocolGuid
, (VOID
**)&Snp
);
3922 if (EFI_ERROR (Status
)) {
3924 // Failed to open SNP from this handle, try to get SNP from parent handle
3926 UpdatedDevicePath
= DevicePathFromHandle (Handle
);
3927 if (UpdatedDevicePath
!= NULL
) {
3928 Status
= gBS
->LocateDevicePath (&gEfiSimpleNetworkProtocolGuid
, &UpdatedDevicePath
, &Handle
);
3929 if (!EFI_ERROR (Status
)) {
3931 // SNP handle found, get SNP from it
3933 Status
= gBS
->HandleProtocol (Handle
, &gEfiSimpleNetworkProtocolGuid
, (VOID
**) &Snp
);
3938 if (!EFI_ERROR (Status
)) {
3939 if (Snp
->Mode
->MediaPresentSupported
) {
3940 if (Snp
->Mode
->State
== EfiSimpleNetworkInitialized
) {
3942 // Invoke Snp->GetStatus() to refresh the media status
3944 Snp
->GetStatus (Snp
, &InterruptStatus
, NULL
);
3947 // In case some one else is using the SNP check to see if it's connected
3949 MediaPresent
= Snp
->Mode
->MediaPresent
;
3952 // No one is using SNP so we need to Start and Initialize so
3953 // MediaPresent will be valid.
3955 Status
= Snp
->Start (Snp
);
3956 if (!EFI_ERROR (Status
)) {
3957 Status
= Snp
->Initialize (Snp
, 0, 0);
3958 if (!EFI_ERROR (Status
)) {
3959 MediaPresent
= Snp
->Mode
->MediaPresent
;
3960 Snp
->Shutdown (Snp
);
3966 MediaPresent
= TRUE
;
3971 return MediaPresent
;
3975 For a bootable Device path, return its boot type.
3977 @param DevicePath The bootable device Path to check
3979 @retval BDS_EFI_MEDIA_HD_BOOT If given device path contains MEDIA_DEVICE_PATH type device path node
3980 which subtype is MEDIA_HARDDRIVE_DP
3981 @retval BDS_EFI_MEDIA_CDROM_BOOT If given device path contains MEDIA_DEVICE_PATH type device path node
3982 which subtype is MEDIA_CDROM_DP
3983 @retval BDS_EFI_ACPI_FLOPPY_BOOT If given device path contains ACPI_DEVICE_PATH type device path node
3984 which HID is floppy device.
3985 @retval BDS_EFI_MESSAGE_ATAPI_BOOT If given device path contains MESSAGING_DEVICE_PATH type device path node
3986 and its last device path node's subtype is MSG_ATAPI_DP.
3987 @retval BDS_EFI_MESSAGE_SCSI_BOOT If given device path contains MESSAGING_DEVICE_PATH type device path node
3988 and its last device path node's subtype is MSG_SCSI_DP.
3989 @retval BDS_EFI_MESSAGE_USB_DEVICE_BOOT If given device path contains MESSAGING_DEVICE_PATH type device path node
3990 and its last device path node's subtype is MSG_USB_DP.
3991 @retval BDS_EFI_MESSAGE_MISC_BOOT If the device path not contains any media device path node, and
3992 its last device path node point to a message device path node.
3993 @retval BDS_LEGACY_BBS_BOOT If given device path contains BBS_DEVICE_PATH type device path node.
3994 @retval BDS_EFI_UNSUPPORT An EFI Removable BlockIO device path not point to a media and message device,
3999 BdsGetBootTypeFromDevicePath (
4000 IN EFI_DEVICE_PATH_PROTOCOL
*DevicePath
4003 ACPI_HID_DEVICE_PATH
*Acpi
;
4004 EFI_DEVICE_PATH_PROTOCOL
*TempDevicePath
;
4005 EFI_DEVICE_PATH_PROTOCOL
*LastDeviceNode
;
4008 if (NULL
== DevicePath
) {
4009 return BDS_EFI_UNSUPPORT
;
4012 TempDevicePath
= DevicePath
;
4014 while (!IsDevicePathEndType (TempDevicePath
)) {
4015 switch (DevicePathType (TempDevicePath
)) {
4016 case BBS_DEVICE_PATH
:
4017 return BDS_LEGACY_BBS_BOOT
;
4018 case MEDIA_DEVICE_PATH
:
4019 if (DevicePathSubType (TempDevicePath
) == MEDIA_HARDDRIVE_DP
) {
4020 return BDS_EFI_MEDIA_HD_BOOT
;
4021 } else if (DevicePathSubType (TempDevicePath
) == MEDIA_CDROM_DP
) {
4022 return BDS_EFI_MEDIA_CDROM_BOOT
;
4025 case ACPI_DEVICE_PATH
:
4026 Acpi
= (ACPI_HID_DEVICE_PATH
*) TempDevicePath
;
4027 if (EISA_ID_TO_NUM (Acpi
->HID
) == 0x0604) {
4028 return BDS_EFI_ACPI_FLOPPY_BOOT
;
4031 case MESSAGING_DEVICE_PATH
:
4033 // Get the last device path node
4035 LastDeviceNode
= NextDevicePathNode (TempDevicePath
);
4036 if (DevicePathSubType(LastDeviceNode
) == MSG_DEVICE_LOGICAL_UNIT_DP
) {
4038 // if the next node type is Device Logical Unit, which specify the Logical Unit Number (LUN),
4041 LastDeviceNode
= NextDevicePathNode (LastDeviceNode
);
4044 // if the device path not only point to driver device, it is not a messaging device path,
4046 if (!IsDevicePathEndType (LastDeviceNode
)) {
4050 switch (DevicePathSubType (TempDevicePath
)) {
4052 BootType
= BDS_EFI_MESSAGE_ATAPI_BOOT
;
4056 BootType
= BDS_EFI_MESSAGE_USB_DEVICE_BOOT
;
4060 BootType
= BDS_EFI_MESSAGE_SCSI_BOOT
;
4064 BootType
= BDS_EFI_MESSAGE_SATA_BOOT
;
4067 case MSG_MAC_ADDR_DP
:
4071 BootType
= BDS_EFI_MESSAGE_MAC_BOOT
;
4075 BootType
= BDS_EFI_MESSAGE_MISC_BOOT
;
4083 TempDevicePath
= NextDevicePathNode (TempDevicePath
);
4086 return BDS_EFI_UNSUPPORT
;
4090 Check whether the Device path in a boot option point to a valid bootable device,
4091 And if CheckMedia is true, check the device is ready to boot now.
4093 @param DevPath the Device path in a boot option
4094 @param CheckMedia if true, check the device is ready to boot now.
4096 @retval TRUE the Device path is valid
4097 @retval FALSE the Device path is invalid .
4102 BdsLibIsValidEFIBootOptDevicePath (
4103 IN EFI_DEVICE_PATH_PROTOCOL
*DevPath
,
4104 IN BOOLEAN CheckMedia
4107 return BdsLibIsValidEFIBootOptDevicePathExt (DevPath
, CheckMedia
, NULL
);
4111 Check whether the Device path in a boot option point to a valid bootable device,
4112 And if CheckMedia is true, check the device is ready to boot now.
4113 If Description is not NULL and the device path point to a fixed BlockIo
4114 device, check the description whether conflict with other auto-created
4117 @param DevPath the Device path in a boot option
4118 @param CheckMedia if true, check the device is ready to boot now.
4119 @param Description the description in a boot option
4121 @retval TRUE the Device path is valid
4122 @retval FALSE the Device path is invalid .
4127 BdsLibIsValidEFIBootOptDevicePathExt (
4128 IN EFI_DEVICE_PATH_PROTOCOL
*DevPath
,
4129 IN BOOLEAN CheckMedia
,
4130 IN CHAR16
*Description
4135 EFI_DEVICE_PATH_PROTOCOL
*TempDevicePath
;
4136 EFI_DEVICE_PATH_PROTOCOL
*LastDeviceNode
;
4137 EFI_BLOCK_IO_PROTOCOL
*BlockIo
;
4139 TempDevicePath
= DevPath
;
4140 LastDeviceNode
= DevPath
;
4143 // Check if it's a valid boot option for network boot device.
4144 // Check if there is EfiLoadFileProtocol installed.
4145 // If yes, that means there is a boot option for network.
4147 Status
= gBS
->LocateDevicePath (
4148 &gEfiLoadFileProtocolGuid
,
4152 if (EFI_ERROR (Status
)) {
4154 // Device not present so see if we need to connect it
4156 TempDevicePath
= DevPath
;
4157 BdsLibConnectDevicePath (TempDevicePath
);
4158 Status
= gBS
->LocateDevicePath (
4159 &gEfiLoadFileProtocolGuid
,
4165 if (!EFI_ERROR (Status
)) {
4166 if (!IsDevicePathEnd (TempDevicePath
)) {
4168 // LoadFile protocol is not installed on handle with exactly the same DevPath
4175 // Test if it is ready to boot now
4177 if (BdsLibNetworkBootWithMediaPresent(DevPath
)) {
4186 // If the boot option point to a file, it is a valid EFI boot option,
4187 // and assume it is ready to boot now
4189 while (!IsDevicePathEnd (TempDevicePath
)) {
4191 // If there is USB Class or USB WWID device path node, treat it as valid EFI
4192 // Boot Option. BdsExpandUsbShortFormDevicePath () will be used to expand it
4193 // to full device path.
4195 if ((DevicePathType (TempDevicePath
) == MESSAGING_DEVICE_PATH
) &&
4196 ((DevicePathSubType (TempDevicePath
) == MSG_USB_CLASS_DP
) ||
4197 (DevicePathSubType (TempDevicePath
) == MSG_USB_WWID_DP
))) {
4201 LastDeviceNode
= TempDevicePath
;
4202 TempDevicePath
= NextDevicePathNode (TempDevicePath
);
4204 if ((DevicePathType (LastDeviceNode
) == MEDIA_DEVICE_PATH
) &&
4205 (DevicePathSubType (LastDeviceNode
) == MEDIA_FILEPATH_DP
)) {
4210 // Check if it's a valid boot option for internal FV application
4212 if (EfiGetNameGuidFromFwVolDevicePathNode ((MEDIA_FW_VOL_FILEPATH_DEVICE_PATH
*) LastDeviceNode
) != NULL
) {
4214 // If the boot option point to internal FV application, make sure it is valid
4216 TempDevicePath
= DevPath
;
4217 Status
= BdsLibUpdateFvFileDevicePath (
4219 EfiGetNameGuidFromFwVolDevicePathNode ((MEDIA_FW_VOL_FILEPATH_DEVICE_PATH
*) LastDeviceNode
)
4221 if (Status
== EFI_ALREADY_STARTED
) {
4224 if (Status
== EFI_SUCCESS
) {
4225 FreePool (TempDevicePath
);
4232 // If the boot option point to a blockIO device:
4233 // if it is a removable blockIo device, it is valid.
4234 // if it is a fixed blockIo device, check its description confliction.
4236 TempDevicePath
= DevPath
;
4237 Status
= gBS
->LocateDevicePath (&gEfiBlockIoProtocolGuid
, &TempDevicePath
, &Handle
);
4238 if (EFI_ERROR (Status
)) {
4240 // Device not present so see if we need to connect it
4242 Status
= BdsLibConnectDevicePath (DevPath
);
4243 if (!EFI_ERROR (Status
)) {
4245 // Try again to get the Block Io protocol after we did the connect
4247 TempDevicePath
= DevPath
;
4248 Status
= gBS
->LocateDevicePath (&gEfiBlockIoProtocolGuid
, &TempDevicePath
, &Handle
);
4252 if (!EFI_ERROR (Status
)) {
4253 Status
= gBS
->HandleProtocol (Handle
, &gEfiBlockIoProtocolGuid
, (VOID
**)&BlockIo
);
4254 if (!EFI_ERROR (Status
)) {
4257 // Test if it is ready to boot now
4259 if (BdsLibGetBootableHandle (DevPath
) != NULL
) {
4268 // 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,
4270 Status
= gBS
->LocateDevicePath (&gEfiSimpleFileSystemProtocolGuid
, &TempDevicePath
, &Handle
);
4271 if (!EFI_ERROR (Status
)) {
4274 // Test if it is ready to boot now
4276 if (BdsLibGetBootableHandle (DevPath
) != NULL
) {
4290 According to a file guild, check a Fv file device path is valid. If it is invalid,
4291 try to return the valid device path.
4292 FV address maybe changes for memory layout adjust from time to time, use this function
4293 could promise the Fv file device path is right.
4295 @param DevicePath on input, the Fv file device path need to check on
4296 output, the updated valid Fv file device path
4297 @param FileGuid the Fv file guild
4299 @retval EFI_INVALID_PARAMETER the input DevicePath or FileGuid is invalid
4301 @retval EFI_UNSUPPORTED the input DevicePath does not contain Fv file
4303 @retval EFI_ALREADY_STARTED the input DevicePath has pointed to Fv file, it is
4305 @retval EFI_SUCCESS has successfully updated the invalid DevicePath,
4306 and return the updated device path in DevicePath
4311 BdsLibUpdateFvFileDevicePath (
4312 IN OUT EFI_DEVICE_PATH_PROTOCOL
** DevicePath
,
4313 IN EFI_GUID
*FileGuid
4316 EFI_DEVICE_PATH_PROTOCOL
*TempDevicePath
;
4317 EFI_DEVICE_PATH_PROTOCOL
*LastDeviceNode
;
4319 EFI_GUID
*GuidPoint
;
4321 UINTN FvHandleCount
;
4322 EFI_HANDLE
*FvHandleBuffer
;
4323 EFI_FV_FILETYPE Type
;
4325 EFI_FV_FILE_ATTRIBUTES Attributes
;
4326 UINT32 AuthenticationStatus
;
4328 EFI_LOADED_IMAGE_PROTOCOL
*LoadedImage
;
4329 EFI_FIRMWARE_VOLUME2_PROTOCOL
*Fv
;
4330 MEDIA_FW_VOL_FILEPATH_DEVICE_PATH FvFileNode
;
4331 EFI_HANDLE FoundFvHandle
;
4332 EFI_DEVICE_PATH_PROTOCOL
*NewDevicePath
;
4334 if ((DevicePath
== NULL
) || (*DevicePath
== NULL
)) {
4335 return EFI_INVALID_PARAMETER
;
4337 if (FileGuid
== NULL
) {
4338 return EFI_INVALID_PARAMETER
;
4342 // Check whether the device path point to the default the input Fv file
4344 TempDevicePath
= *DevicePath
;
4345 LastDeviceNode
= TempDevicePath
;
4346 while (!IsDevicePathEnd (TempDevicePath
)) {
4347 LastDeviceNode
= TempDevicePath
;
4348 TempDevicePath
= NextDevicePathNode (TempDevicePath
);
4350 GuidPoint
= EfiGetNameGuidFromFwVolDevicePathNode (
4351 (MEDIA_FW_VOL_FILEPATH_DEVICE_PATH
*) LastDeviceNode
4353 if (GuidPoint
== NULL
) {
4355 // if this option does not points to a Fv file, just return EFI_UNSUPPORTED
4357 return EFI_UNSUPPORTED
;
4359 if (!CompareGuid (GuidPoint
, FileGuid
)) {
4361 // If the Fv file is not the input file guid, just return EFI_UNSUPPORTED
4363 return EFI_UNSUPPORTED
;
4367 // Check whether the input Fv file device path is valid
4369 TempDevicePath
= *DevicePath
;
4370 FoundFvHandle
= NULL
;
4371 Status
= gBS
->LocateDevicePath (
4372 &gEfiFirmwareVolume2ProtocolGuid
,
4376 if (!EFI_ERROR (Status
)) {
4377 Status
= gBS
->HandleProtocol (
4379 &gEfiFirmwareVolume2ProtocolGuid
,
4382 if (!EFI_ERROR (Status
)) {
4384 // Set FV ReadFile Buffer as NULL, only need to check whether input Fv file exist there
4386 Status
= Fv
->ReadFile (
4393 &AuthenticationStatus
4395 if (!EFI_ERROR (Status
)) {
4396 return EFI_ALREADY_STARTED
;
4402 // Look for the input wanted FV file in current FV
4403 // First, try to look for in Bds own FV. Bds and input wanted FV file usually are in the same FV
4406 FoundFvHandle
= NULL
;
4407 Status
= gBS
->HandleProtocol (
4409 &gEfiLoadedImageProtocolGuid
,
4410 (VOID
**) &LoadedImage
4412 if (!EFI_ERROR (Status
)) {
4413 Status
= gBS
->HandleProtocol (
4414 LoadedImage
->DeviceHandle
,
4415 &gEfiFirmwareVolume2ProtocolGuid
,
4418 if (!EFI_ERROR (Status
)) {
4419 Status
= Fv
->ReadFile (
4426 &AuthenticationStatus
4428 if (!EFI_ERROR (Status
)) {
4430 FoundFvHandle
= LoadedImage
->DeviceHandle
;
4435 // Second, if fail to find, try to enumerate all FV
4438 FvHandleBuffer
= NULL
;
4439 gBS
->LocateHandleBuffer (
4441 &gEfiFirmwareVolume2ProtocolGuid
,
4446 for (Index
= 0; Index
< FvHandleCount
; Index
++) {
4447 gBS
->HandleProtocol (
4448 FvHandleBuffer
[Index
],
4449 &gEfiFirmwareVolume2ProtocolGuid
,
4453 Status
= Fv
->ReadFile (
4460 &AuthenticationStatus
4462 if (EFI_ERROR (Status
)) {
4464 // Skip if input Fv file not in the FV
4469 FoundFvHandle
= FvHandleBuffer
[Index
];
4473 if (FvHandleBuffer
!= NULL
) {
4474 FreePool (FvHandleBuffer
);
4480 // Build the shell device path
4482 NewDevicePath
= DevicePathFromHandle (FoundFvHandle
);
4483 EfiInitializeFwVolDevicepathNode (&FvFileNode
, FileGuid
);
4484 NewDevicePath
= AppendDevicePathNode (NewDevicePath
, (EFI_DEVICE_PATH_PROTOCOL
*) &FvFileNode
);
4485 ASSERT (NewDevicePath
!= NULL
);
4486 *DevicePath
= NewDevicePath
;
4489 return EFI_NOT_FOUND
;