2 BDS Lib functions which relate with create or process the boot option.
4 Copyright (c) 2004 - 2014, Intel Corporation. All rights reserved.<BR>
5 This program and the accompanying materials
6 are licensed and made available under the terms and conditions of the BSD License
7 which accompanies this distribution. The full text of the license may be found at
8 http://opensource.org/licenses/bsd-license.php
10 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
11 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
15 #include "InternalBdsLib.h"
18 BOOLEAN mEnumBootDevice
= FALSE
;
19 EFI_HII_HANDLE gBdsLibStringPackHandle
= NULL
;
22 The constructor function register UNI strings into imageHandle.
24 It will ASSERT() if that operation fails and it will always return EFI_SUCCESS.
26 @param ImageHandle The firmware allocated handle for the EFI image.
27 @param SystemTable A pointer to the EFI System Table.
29 @retval EFI_SUCCESS The constructor successfully added string package.
30 @retval Other value The constructor can't add string package.
35 GenericBdsLibConstructor (
36 IN EFI_HANDLE ImageHandle
,
37 IN EFI_SYSTEM_TABLE
*SystemTable
41 gBdsLibStringPackHandle
= HiiAddPackages (
42 &gBdsLibStringPackageGuid
,
48 ASSERT (gBdsLibStringPackHandle
!= NULL
);
54 Deletete the Boot Option from EFI Variable. The Boot Order Arrray
57 @param OptionNumber The number of Boot option want to be deleted.
58 @param BootOrder The Boot Order array.
59 @param BootOrderSize The size of the Boot Order Array.
61 @retval EFI_SUCCESS The Boot Option Variable was found and removed
62 @retval EFI_UNSUPPORTED The Boot Option Variable store was inaccessible
63 @retval EFI_NOT_FOUND The Boot Option Variable was not found
68 IN UINTN OptionNumber
,
69 IN OUT UINT16
*BootOrder
,
70 IN OUT UINTN
*BootOrderSize
77 UnicodeSPrint (BootOption
, sizeof (BootOption
), L
"Boot%04x", OptionNumber
);
78 Status
= gRT
->SetVariable (
80 &gEfiGlobalVariableGuid
,
86 // Deleting variable with existing variable implementation shouldn't fail.
88 ASSERT_EFI_ERROR (Status
);
91 // adjust boot order array
93 for (Index
= 0; Index
< *BootOrderSize
/ sizeof (UINT16
); Index
++) {
94 if (BootOrder
[Index
] == OptionNumber
) {
95 CopyMem (&BootOrder
[Index
], &BootOrder
[Index
+1], *BootOrderSize
- (Index
+1) * sizeof (UINT16
));
96 *BootOrderSize
-= sizeof (UINT16
);
105 Translate the first n characters of an Ascii string to
106 Unicode characters. The count n is indicated by parameter
107 Size. If Size is greater than the length of string, then
108 the entire string is translated.
111 @param AStr Pointer to input Ascii string.
112 @param Size The number of characters to translate.
113 @param UStr Pointer to output Unicode string buffer.
126 while (AStr
[Idx
] != 0) {
127 UStr
[Idx
] = (CHAR16
) AStr
[Idx
];
138 Build Legacy Device Name String according.
140 @param CurBBSEntry BBS Table.
142 @param BufSize The buffer size.
143 @param BootString The output string.
147 BdsBuildLegacyDevNameString (
148 IN BBS_TABLE
*CurBBSEntry
,
151 OUT CHAR16
*BootString
164 Fmt
= L
"Primary Master %s";
171 Fmt
= L
"Primary Slave %s";
178 Fmt
= L
"Secondary Master %s";
185 Fmt
= L
"Secondary Slave %s";
193 switch (CurBBSEntry
->DeviceType
) {
214 case BBS_EMBED_NETWORK
:
228 // If current BBS entry has its description then use it.
230 StringDesc
= (UINT8
*) (UINTN
) ((CurBBSEntry
->DescStringSegment
<< 4) + CurBBSEntry
->DescStringOffset
);
231 if (NULL
!= StringDesc
) {
233 // Only get fisrt 32 characters, this is suggested by BBS spec
235 AsciiToUnicodeSize (StringDesc
, 32, Temp
);
241 // BbsTable 16 entries are for onboard IDE.
242 // Set description string for SATA harddisks, Harddisk 0 ~ Harddisk 11
244 if (Index
>= 5 && Index
<= 16 && (CurBBSEntry
->DeviceType
== BBS_HARDDISK
|| CurBBSEntry
->DeviceType
== BBS_CDROM
)) {
246 UnicodeSPrint (BootString
, BufSize
, Fmt
, Type
, Index
- 5);
248 UnicodeSPrint (BootString
, BufSize
, Fmt
, Type
);
254 Create a legacy boot option for the specified entry of
255 BBS table, save it as variable, and append it to the boot
259 @param CurrentBbsEntry Pointer to current BBS table.
260 @param CurrentBbsDevPath Pointer to the Device Path Protocol instance of BBS
261 @param Index Index of the specified entry in BBS table.
262 @param BootOrderList On input, the original boot order list.
263 On output, the new boot order list attached with the
265 @param BootOrderListSize On input, the original size of boot order list.
266 On output, the size of new boot order list.
268 @retval EFI_SUCCESS Boot Option successfully created.
269 @retval EFI_OUT_OF_RESOURCES Fail to allocate necessary memory.
270 @retval Other Error occurs while setting variable.
274 BdsCreateLegacyBootOption (
275 IN BBS_TABLE
*CurrentBbsEntry
,
276 IN EFI_DEVICE_PATH_PROTOCOL
*CurrentBbsDevPath
,
278 IN OUT UINT16
**BootOrderList
,
279 IN OUT UINTN
*BootOrderListSize
283 UINT16 CurrentBootOptionNo
;
284 UINT16 BootString
[10];
285 CHAR16 BootDesc
[100];
286 CHAR8 HelpString
[100];
287 UINT16
*NewBootOrderList
;
292 UINT16 CurrentBbsDevPathSize
;
293 UINTN BootOrderIndex
;
294 UINTN BootOrderLastIndex
;
296 BOOLEAN IndexNotFound
;
297 BBS_BBS_DEVICE_PATH
*NewBbsDevPathNode
;
299 if ((*BootOrderList
) == NULL
) {
300 CurrentBootOptionNo
= 0;
302 for (ArrayIndex
= 0; ArrayIndex
< (UINTN
) (*BootOrderListSize
/ sizeof (UINT16
)); ArrayIndex
++) {
303 IndexNotFound
= TRUE
;
304 for (BootOrderIndex
= 0; BootOrderIndex
< (UINTN
) (*BootOrderListSize
/ sizeof (UINT16
)); BootOrderIndex
++) {
305 if ((*BootOrderList
)[BootOrderIndex
] == ArrayIndex
) {
306 IndexNotFound
= FALSE
;
311 if (!IndexNotFound
) {
318 CurrentBootOptionNo
= (UINT16
) ArrayIndex
;
328 BdsBuildLegacyDevNameString (CurrentBbsEntry
, Index
, sizeof (BootDesc
), BootDesc
);
331 // Create new BBS device path node with description string
333 UnicodeStrToAsciiStr (BootDesc
, HelpString
);
335 StringLen
= AsciiStrLen (HelpString
);
336 NewBbsDevPathNode
= AllocateZeroPool (sizeof (BBS_BBS_DEVICE_PATH
) + StringLen
);
337 if (NewBbsDevPathNode
== NULL
) {
338 return EFI_OUT_OF_RESOURCES
;
340 CopyMem (NewBbsDevPathNode
, CurrentBbsDevPath
, sizeof (BBS_BBS_DEVICE_PATH
));
341 CopyMem (NewBbsDevPathNode
->String
, HelpString
, StringLen
+ 1);
342 SetDevicePathNodeLength (&(NewBbsDevPathNode
->Header
), sizeof (BBS_BBS_DEVICE_PATH
) + StringLen
);
345 // Create entire new CurrentBbsDevPath with end node
347 CurrentBbsDevPath
= AppendDevicePathNode (
349 (EFI_DEVICE_PATH_PROTOCOL
*) NewBbsDevPathNode
351 if (CurrentBbsDevPath
== NULL
) {
352 FreePool (NewBbsDevPathNode
);
353 return EFI_OUT_OF_RESOURCES
;
356 CurrentBbsDevPathSize
= (UINT16
) (GetDevicePathSize (CurrentBbsDevPath
));
358 BufferSize
= sizeof (UINT32
) +
361 CurrentBbsDevPathSize
+
365 Buffer
= AllocateZeroPool (BufferSize
);
366 if (Buffer
== NULL
) {
367 FreePool (NewBbsDevPathNode
);
368 FreePool (CurrentBbsDevPath
);
369 return EFI_OUT_OF_RESOURCES
;
372 Ptr
= (UINT8
*) Buffer
;
374 *((UINT32
*) Ptr
) = LOAD_OPTION_ACTIVE
;
375 Ptr
+= sizeof (UINT32
);
377 *((UINT16
*) Ptr
) = CurrentBbsDevPathSize
;
378 Ptr
+= sizeof (UINT16
);
385 Ptr
+= StrSize (BootDesc
);
390 CurrentBbsDevPathSize
392 Ptr
+= CurrentBbsDevPathSize
;
400 Ptr
+= sizeof (BBS_TABLE
);
401 *((UINT16
*) Ptr
) = (UINT16
) Index
;
403 Status
= gRT
->SetVariable (
405 &gEfiGlobalVariableGuid
,
406 EFI_VARIABLE_BOOTSERVICE_ACCESS
| EFI_VARIABLE_RUNTIME_ACCESS
| EFI_VARIABLE_NON_VOLATILE
,
415 NewBootOrderList
= AllocateZeroPool (*BootOrderListSize
+ sizeof (UINT16
));
416 if (NULL
== NewBootOrderList
) {
417 FreePool (NewBbsDevPathNode
);
418 FreePool (CurrentBbsDevPath
);
419 return EFI_OUT_OF_RESOURCES
;
422 if (*BootOrderList
!= NULL
) {
423 CopyMem (NewBootOrderList
, *BootOrderList
, *BootOrderListSize
);
424 FreePool (*BootOrderList
);
427 BootOrderLastIndex
= (UINTN
) (*BootOrderListSize
/ sizeof (UINT16
));
428 NewBootOrderList
[BootOrderLastIndex
] = CurrentBootOptionNo
;
429 *BootOrderListSize
+= sizeof (UINT16
);
430 *BootOrderList
= NewBootOrderList
;
432 FreePool (NewBbsDevPathNode
);
433 FreePool (CurrentBbsDevPath
);
438 Check if the boot option is a legacy one.
440 @param BootOptionVar The boot option data payload.
441 @param BbsEntry The BBS Table.
442 @param BbsIndex The table index.
444 @retval TRUE It is a legacy boot option.
445 @retval FALSE It is not a legacy boot option.
449 BdsIsLegacyBootOption (
450 IN UINT8
*BootOptionVar
,
451 OUT BBS_TABLE
**BbsEntry
,
456 EFI_DEVICE_PATH_PROTOCOL
*DevicePath
;
461 Ptr
+= sizeof (UINT32
);
462 DevPathLen
= *(UINT16
*) Ptr
;
463 Ptr
+= sizeof (UINT16
);
464 Ptr
+= StrSize ((UINT16
*) Ptr
);
465 DevicePath
= (EFI_DEVICE_PATH_PROTOCOL
*) Ptr
;
466 if ((BBS_DEVICE_PATH
== DevicePath
->Type
) && (BBS_BBS_DP
== DevicePath
->SubType
)) {
468 *BbsEntry
= (BBS_TABLE
*) Ptr
;
469 Ptr
+= sizeof (BBS_TABLE
);
470 *BbsIndex
= *(UINT16
*) Ptr
;
481 Delete all the invalid legacy boot options.
483 @retval EFI_SUCCESS All invalide legacy boot options are deleted.
484 @retval EFI_OUT_OF_RESOURCES Fail to allocate necessary memory.
485 @retval EFI_NOT_FOUND Fail to retrive variable of boot order.
489 BdsDeleteAllInvalidLegacyBootOptions (
494 UINT8
*BootOptionVar
;
496 UINTN BootOptionSize
;
500 HDD_INFO
*LocalHddInfo
;
501 BBS_TABLE
*LocalBbsTable
;
504 EFI_LEGACY_BIOS_PROTOCOL
*LegacyBios
;
506 UINT16 BootOption
[10];
507 UINT16 BootDesc
[100];
508 BOOLEAN DescStringMatch
;
510 Status
= EFI_SUCCESS
;
516 LocalBbsTable
= NULL
;
519 Status
= gBS
->LocateProtocol (&gEfiLegacyBiosProtocolGuid
, NULL
, (VOID
**) &LegacyBios
);
520 if (EFI_ERROR (Status
)) {
524 BootOrder
= BdsLibGetVariableAndSize (
526 &gEfiGlobalVariableGuid
,
529 if (BootOrder
== NULL
) {
530 return EFI_NOT_FOUND
;
533 LegacyBios
->GetBbsInfo (
542 while (Index
< BootOrderSize
/ sizeof (UINT16
)) {
543 UnicodeSPrint (BootOption
, sizeof (BootOption
), L
"Boot%04x", BootOrder
[Index
]);
544 BootOptionVar
= BdsLibGetVariableAndSize (
546 &gEfiGlobalVariableGuid
,
549 if (NULL
== BootOptionVar
) {
551 Status
= gRT
->GetVariable (
553 &gEfiGlobalVariableGuid
,
558 if (Status
== EFI_NOT_FOUND
) {
562 BdsDeleteBootOption (
569 FreePool (BootOrder
);
570 return EFI_OUT_OF_RESOURCES
;
575 // Skip Non-Legacy boot option
577 if (!BdsIsLegacyBootOption (BootOptionVar
, &BbsEntry
, &BbsIndex
)) {
578 if (BootOptionVar
!= NULL
) {
579 FreePool (BootOptionVar
);
585 if (BbsIndex
< BbsCount
) {
587 // Check if BBS Description String is changed
589 DescStringMatch
= FALSE
;
590 BdsBuildLegacyDevNameString (
591 &LocalBbsTable
[BbsIndex
],
597 if (StrCmp (BootDesc
, (UINT16
*)(BootOptionVar
+ sizeof (UINT32
) + sizeof (UINT16
))) == 0) {
598 DescStringMatch
= TRUE
;
601 if (!((LocalBbsTable
[BbsIndex
].BootPriority
== BBS_IGNORE_ENTRY
) ||
602 (LocalBbsTable
[BbsIndex
].BootPriority
== BBS_DO_NOT_BOOT_FROM
)) &&
603 (LocalBbsTable
[BbsIndex
].DeviceType
== BbsEntry
->DeviceType
) &&
610 if (BootOptionVar
!= NULL
) {
611 FreePool (BootOptionVar
);
616 BdsDeleteBootOption (
624 // Adjust the number of boot options.
626 Status
= gRT
->SetVariable (
628 &gEfiGlobalVariableGuid
,
629 EFI_VARIABLE_BOOTSERVICE_ACCESS
| EFI_VARIABLE_RUNTIME_ACCESS
| EFI_VARIABLE_NON_VOLATILE
,
634 // Shrinking variable with existing variable implementation shouldn't fail.
636 ASSERT_EFI_ERROR (Status
);
637 FreePool (BootOrder
);
643 Find all legacy boot option by device type.
645 @param BootOrder The boot order array.
646 @param BootOptionNum The number of boot option.
647 @param DevType Device type.
648 @param DevName Device name.
649 @param Attribute The boot option attribute.
650 @param BbsIndex The BBS table index.
651 @param OptionNumber The boot option index.
653 @retval TRUE The Legacy boot option is found.
654 @retval FALSE The legacy boot option is not found.
658 BdsFindLegacyBootOptionByDevTypeAndName (
659 IN UINT16
*BootOrder
,
660 IN UINTN BootOptionNum
,
663 OUT UINT32
*Attribute
,
664 OUT UINT16
*BbsIndex
,
665 OUT UINT16
*OptionNumber
669 CHAR16 BootOption
[9];
670 UINTN BootOptionSize
;
671 UINT8
*BootOptionVar
;
678 if (NULL
== BootOrder
) {
683 // Loop all boot option from variable
685 for (Index
= 0; Index
< BootOptionNum
; Index
++) {
686 UnicodeSPrint (BootOption
, sizeof (BootOption
), L
"Boot%04x", (UINTN
) BootOrder
[Index
]);
687 BootOptionVar
= BdsLibGetVariableAndSize (
689 &gEfiGlobalVariableGuid
,
692 if (NULL
== BootOptionVar
) {
697 // Skip Non-legacy boot option
699 if (!BdsIsLegacyBootOption (BootOptionVar
, &BbsEntry
, BbsIndex
)) {
700 FreePool (BootOptionVar
);
705 (BbsEntry
->DeviceType
!= DevType
) ||
706 (StrCmp (DevName
, (CHAR16
*)(BootOptionVar
+ sizeof (UINT32
) + sizeof (UINT16
))) != 0)
708 FreePool (BootOptionVar
);
712 *Attribute
= *(UINT32
*) BootOptionVar
;
713 *OptionNumber
= BootOrder
[Index
];
715 FreePool (BootOptionVar
);
723 Create a legacy boot option.
725 @param BbsItem The BBS Table entry.
726 @param Index Index of the specified entry in BBS table.
727 @param BootOrderList The boot order list.
728 @param BootOrderListSize The size of boot order list.
730 @retval EFI_OUT_OF_RESOURCE No enough memory.
731 @retval EFI_SUCCESS The function complete successfully.
732 @return Other value if the legacy boot option is not created.
736 BdsCreateOneLegacyBootOption (
737 IN BBS_TABLE
*BbsItem
,
739 IN OUT UINT16
**BootOrderList
,
740 IN OUT UINTN
*BootOrderListSize
743 BBS_BBS_DEVICE_PATH BbsDevPathNode
;
745 EFI_DEVICE_PATH_PROTOCOL
*DevPath
;
750 // Create device path node.
752 BbsDevPathNode
.Header
.Type
= BBS_DEVICE_PATH
;
753 BbsDevPathNode
.Header
.SubType
= BBS_BBS_DP
;
754 SetDevicePathNodeLength (&BbsDevPathNode
.Header
, sizeof (BBS_BBS_DEVICE_PATH
));
755 BbsDevPathNode
.DeviceType
= BbsItem
->DeviceType
;
756 CopyMem (&BbsDevPathNode
.StatusFlag
, &BbsItem
->StatusFlags
, sizeof (UINT16
));
758 DevPath
= AppendDevicePathNode (
760 (EFI_DEVICE_PATH_PROTOCOL
*) &BbsDevPathNode
762 if (NULL
== DevPath
) {
763 return EFI_OUT_OF_RESOURCES
;
766 Status
= BdsCreateLegacyBootOption (
773 BbsItem
->BootPriority
= 0x00;
781 Add the legacy boot options from BBS table if they do not exist.
783 @retval EFI_SUCCESS The boot options are added successfully
784 or they are already in boot options.
785 @retval EFI_NOT_FOUND No legacy boot options is found.
786 @retval EFI_OUT_OF_RESOURCE No enough memory.
787 @return Other value LegacyBoot options are not added.
791 BdsAddNonExistingLegacyBootOptions (
801 HDD_INFO
*LocalHddInfo
;
802 BBS_TABLE
*LocalBbsTable
;
804 EFI_LEGACY_BIOS_PROTOCOL
*LegacyBios
;
813 LocalBbsTable
= NULL
;
815 Status
= gBS
->LocateProtocol (&gEfiLegacyBiosProtocolGuid
, NULL
, (VOID
**) &LegacyBios
);
816 if (EFI_ERROR (Status
)) {
820 LegacyBios
->GetBbsInfo (
828 BootOrder
= BdsLibGetVariableAndSize (
830 &gEfiGlobalVariableGuid
,
833 if (BootOrder
== NULL
) {
837 for (Index
= 0; Index
< BbsCount
; Index
++) {
838 if ((LocalBbsTable
[Index
].BootPriority
== BBS_IGNORE_ENTRY
) ||
839 (LocalBbsTable
[Index
].BootPriority
== BBS_DO_NOT_BOOT_FROM
)
844 BdsBuildLegacyDevNameString (&LocalBbsTable
[Index
], Index
, sizeof (Desc
), Desc
);
846 Exist
= BdsFindLegacyBootOptionByDevTypeAndName (
848 BootOrderSize
/ sizeof (UINT16
),
849 LocalBbsTable
[Index
].DeviceType
,
857 // Not found such type of legacy device in boot options or we found but it's disabled
858 // so we have to create one and put it to the tail of boot order list
860 Status
= BdsCreateOneLegacyBootOption (
861 &LocalBbsTable
[Index
],
866 if (!EFI_ERROR (Status
)) {
867 ASSERT (BootOrder
!= NULL
);
869 OptionNumber
= BootOrder
[BootOrderSize
/ sizeof (UINT16
) - 1];
873 ASSERT (BbsIndex
== Index
);
876 Status
= gRT
->SetVariable (
878 &gEfiGlobalVariableGuid
,
879 EFI_VARIABLE_BOOTSERVICE_ACCESS
| EFI_VARIABLE_RUNTIME_ACCESS
| EFI_VARIABLE_NON_VOLATILE
,
883 if (BootOrder
!= NULL
) {
884 FreePool (BootOrder
);
891 Fill the device order buffer.
893 @param BbsTable The BBS table.
894 @param BbsType The BBS Type.
895 @param BbsCount The BBS Count.
896 @param Buf device order buffer.
898 @return The device order buffer.
903 IN BBS_TABLE
*BbsTable
,
911 for (Index
= 0; Index
< BbsCount
; Index
++) {
912 if (BbsTable
[Index
].BootPriority
== BBS_IGNORE_ENTRY
) {
916 if (BbsTable
[Index
].DeviceType
!= BbsType
) {
920 *Buf
= (UINT16
) (Index
& 0xFF);
928 Create the device order buffer.
930 @param BbsTable The BBS table.
931 @param BbsCount The BBS Count.
933 @retval EFI_SUCCES The buffer is created and the EFI variable named
934 VAR_LEGACY_DEV_ORDER and gEfiLegacyDevOrderVariableGuid is
936 @retval EFI_OUT_OF_RESOURCES Memmory or storage is not enough.
937 @retval EFI_DEVICE_ERROR Fail to add the device order into EFI variable fail
938 because of hardware error.
942 IN BBS_TABLE
*BbsTable
,
954 LEGACY_DEV_ORDER_ENTRY
*DevOrder
;
955 LEGACY_DEV_ORDER_ENTRY
*DevOrderPtr
;
964 HeaderSize
= sizeof (BBS_TYPE
) + sizeof (UINT16
);
966 Status
= EFI_SUCCESS
;
969 // Count all boot devices
971 for (Index
= 0; Index
< BbsCount
; Index
++) {
972 if (BbsTable
[Index
].BootPriority
== BBS_IGNORE_ENTRY
) {
976 switch (BbsTable
[Index
].DeviceType
) {
989 case BBS_EMBED_NETWORK
:
1002 TotalSize
+= (HeaderSize
+ sizeof (UINT16
) * FDCount
);
1003 TotalSize
+= (HeaderSize
+ sizeof (UINT16
) * HDCount
);
1004 TotalSize
+= (HeaderSize
+ sizeof (UINT16
) * CDCount
);
1005 TotalSize
+= (HeaderSize
+ sizeof (UINT16
) * NETCount
);
1006 TotalSize
+= (HeaderSize
+ sizeof (UINT16
) * BEVCount
);
1009 // Create buffer to hold all boot device order
1011 DevOrder
= AllocateZeroPool (TotalSize
);
1012 if (NULL
== DevOrder
) {
1013 return EFI_OUT_OF_RESOURCES
;
1015 DevOrderPtr
= DevOrder
;
1017 DevOrderPtr
->BbsType
= BBS_FLOPPY
;
1018 DevOrderPtr
->Length
= (UINT16
) (sizeof (DevOrderPtr
->Length
) + FDCount
* sizeof (UINT16
));
1019 DevOrderPtr
= (LEGACY_DEV_ORDER_ENTRY
*) BdsFillDevOrderBuf (BbsTable
, BBS_FLOPPY
, BbsCount
, DevOrderPtr
->Data
);
1021 DevOrderPtr
->BbsType
= BBS_HARDDISK
;
1022 DevOrderPtr
->Length
= (UINT16
) (sizeof (UINT16
) + HDCount
* sizeof (UINT16
));
1023 DevOrderPtr
= (LEGACY_DEV_ORDER_ENTRY
*) BdsFillDevOrderBuf (BbsTable
, BBS_HARDDISK
, BbsCount
, DevOrderPtr
->Data
);
1025 DevOrderPtr
->BbsType
= BBS_CDROM
;
1026 DevOrderPtr
->Length
= (UINT16
) (sizeof (UINT16
) + CDCount
* sizeof (UINT16
));
1027 DevOrderPtr
= (LEGACY_DEV_ORDER_ENTRY
*) BdsFillDevOrderBuf (BbsTable
, BBS_CDROM
, BbsCount
, DevOrderPtr
->Data
);
1029 DevOrderPtr
->BbsType
= BBS_EMBED_NETWORK
;
1030 DevOrderPtr
->Length
= (UINT16
) (sizeof (UINT16
) + NETCount
* sizeof (UINT16
));
1031 DevOrderPtr
= (LEGACY_DEV_ORDER_ENTRY
*) BdsFillDevOrderBuf (BbsTable
, BBS_EMBED_NETWORK
, BbsCount
, DevOrderPtr
->Data
);
1033 DevOrderPtr
->BbsType
= BBS_BEV_DEVICE
;
1034 DevOrderPtr
->Length
= (UINT16
) (sizeof (UINT16
) + BEVCount
* sizeof (UINT16
));
1035 DevOrderPtr
= (LEGACY_DEV_ORDER_ENTRY
*) BdsFillDevOrderBuf (BbsTable
, BBS_BEV_DEVICE
, BbsCount
, DevOrderPtr
->Data
);
1037 ASSERT (TotalSize
== (UINTN
) ((UINT8
*) DevOrderPtr
- (UINT8
*) DevOrder
));
1040 // Save device order for legacy boot device to variable.
1042 Status
= gRT
->SetVariable (
1043 VAR_LEGACY_DEV_ORDER
,
1044 &gEfiLegacyDevOrderVariableGuid
,
1045 EFI_VARIABLE_BOOTSERVICE_ACCESS
| EFI_VARIABLE_RUNTIME_ACCESS
| EFI_VARIABLE_NON_VOLATILE
,
1049 FreePool (DevOrder
);
1055 Add the legacy boot devices from BBS table into
1056 the legacy device boot order.
1058 @retval EFI_SUCCESS The boot devices are added successfully.
1059 @retval EFI_NOT_FOUND The legacy boot devices are not found.
1060 @retval EFI_OUT_OF_RESOURCES Memmory or storage is not enough.
1061 @retval EFI_DEVICE_ERROR Fail to add the legacy device boot order into EFI variable
1062 because of hardware error.
1066 BdsUpdateLegacyDevOrder (
1070 LEGACY_DEV_ORDER_ENTRY
*DevOrder
;
1071 LEGACY_DEV_ORDER_ENTRY
*NewDevOrder
;
1072 LEGACY_DEV_ORDER_ENTRY
*Ptr
;
1073 LEGACY_DEV_ORDER_ENTRY
*NewPtr
;
1075 EFI_LEGACY_BIOS_PROTOCOL
*LegacyBios
;
1079 HDD_INFO
*LocalHddInfo
;
1080 BBS_TABLE
*LocalBbsTable
;
1110 HeaderSize
= sizeof (BBS_TYPE
) + sizeof (UINT16
);
1118 Status
= gBS
->LocateProtocol (&gEfiLegacyBiosProtocolGuid
, NULL
, (VOID
**) &LegacyBios
);
1119 if (EFI_ERROR (Status
)) {
1123 Status
= LegacyBios
->GetBbsInfo (
1130 if (EFI_ERROR (Status
)) {
1134 DevOrder
= BdsLibGetVariableAndSize (
1135 VAR_LEGACY_DEV_ORDER
,
1136 &gEfiLegacyDevOrderVariableGuid
,
1139 if (NULL
== DevOrder
) {
1140 return BdsCreateDevOrder (LocalBbsTable
, BbsCount
);
1143 // First we figure out how many boot devices with same device type respectively
1145 for (Index
= 0; Index
< BbsCount
; Index
++) {
1146 if ((LocalBbsTable
[Index
].BootPriority
== BBS_IGNORE_ENTRY
) ||
1147 (LocalBbsTable
[Index
].BootPriority
== BBS_DO_NOT_BOOT_FROM
)
1152 switch (LocalBbsTable
[Index
].DeviceType
) {
1165 case BBS_EMBED_NETWORK
:
1169 case BBS_BEV_DEVICE
:
1178 TotalSize
+= (HeaderSize
+ FDCount
* sizeof (UINT16
));
1179 TotalSize
+= (HeaderSize
+ HDCount
* sizeof (UINT16
));
1180 TotalSize
+= (HeaderSize
+ CDCount
* sizeof (UINT16
));
1181 TotalSize
+= (HeaderSize
+ NETCount
* sizeof (UINT16
));
1182 TotalSize
+= (HeaderSize
+ BEVCount
* sizeof (UINT16
));
1184 NewDevOrder
= AllocateZeroPool (TotalSize
);
1185 if (NULL
== NewDevOrder
) {
1186 return EFI_OUT_OF_RESOURCES
;
1195 NewPtr
= NewDevOrder
;
1196 NewPtr
->BbsType
= Ptr
->BbsType
;
1197 NewPtr
->Length
= (UINT16
) (sizeof (UINT16
) + FDCount
* sizeof (UINT16
));
1198 for (Index
= 0; Index
< Ptr
->Length
/ sizeof (UINT16
) - 1; Index
++) {
1199 if (LocalBbsTable
[Ptr
->Data
[Index
] & 0xFF].BootPriority
== BBS_IGNORE_ENTRY
||
1200 LocalBbsTable
[Ptr
->Data
[Index
] & 0xFF].BootPriority
== BBS_DO_NOT_BOOT_FROM
||
1201 LocalBbsTable
[Ptr
->Data
[Index
] & 0xFF].DeviceType
!= BBS_FLOPPY
1206 NewPtr
->Data
[FDIndex
] = Ptr
->Data
[Index
];
1209 NewFDPtr
= NewPtr
->Data
;
1214 Ptr
= (LEGACY_DEV_ORDER_ENTRY
*) (&Ptr
->Data
[Ptr
->Length
/ sizeof (UINT16
) - 1]);
1215 NewPtr
= (LEGACY_DEV_ORDER_ENTRY
*) (&NewPtr
->Data
[NewPtr
->Length
/ sizeof (UINT16
) -1]);
1216 NewPtr
->BbsType
= Ptr
->BbsType
;
1217 NewPtr
->Length
= (UINT16
) (sizeof (UINT16
) + HDCount
* sizeof (UINT16
));
1218 for (Index
= 0; Index
< Ptr
->Length
/ sizeof (UINT16
) - 1; Index
++) {
1219 if (LocalBbsTable
[Ptr
->Data
[Index
] & 0xFF].BootPriority
== BBS_IGNORE_ENTRY
||
1220 LocalBbsTable
[Ptr
->Data
[Index
] & 0xFF].BootPriority
== BBS_DO_NOT_BOOT_FROM
||
1221 LocalBbsTable
[Ptr
->Data
[Index
] & 0xFF].BootPriority
== BBS_LOWEST_PRIORITY
||
1222 LocalBbsTable
[Ptr
->Data
[Index
] & 0xFF].DeviceType
!= BBS_HARDDISK
1227 NewPtr
->Data
[HDIndex
] = Ptr
->Data
[Index
];
1230 NewHDPtr
= NewPtr
->Data
;
1235 Ptr
= (LEGACY_DEV_ORDER_ENTRY
*) (&Ptr
->Data
[Ptr
->Length
/ sizeof (UINT16
) - 1]);
1236 NewPtr
= (LEGACY_DEV_ORDER_ENTRY
*) (&NewPtr
->Data
[NewPtr
->Length
/ sizeof (UINT16
) -1]);
1237 NewPtr
->BbsType
= Ptr
->BbsType
;
1238 NewPtr
->Length
= (UINT16
) (sizeof (UINT16
) + CDCount
* sizeof (UINT16
));
1239 for (Index
= 0; Index
< Ptr
->Length
/ sizeof (UINT16
) - 1; Index
++) {
1240 if (LocalBbsTable
[Ptr
->Data
[Index
] & 0xFF].BootPriority
== BBS_IGNORE_ENTRY
||
1241 LocalBbsTable
[Ptr
->Data
[Index
] & 0xFF].BootPriority
== BBS_DO_NOT_BOOT_FROM
||
1242 LocalBbsTable
[Ptr
->Data
[Index
] & 0xFF].BootPriority
== BBS_LOWEST_PRIORITY
||
1243 LocalBbsTable
[Ptr
->Data
[Index
] & 0xFF].DeviceType
!= BBS_CDROM
1248 NewPtr
->Data
[CDIndex
] = Ptr
->Data
[Index
];
1251 NewCDPtr
= NewPtr
->Data
;
1256 Ptr
= (LEGACY_DEV_ORDER_ENTRY
*) (&Ptr
->Data
[Ptr
->Length
/ sizeof (UINT16
) - 1]);
1257 NewPtr
= (LEGACY_DEV_ORDER_ENTRY
*) (&NewPtr
->Data
[NewPtr
->Length
/ sizeof (UINT16
) -1]);
1258 NewPtr
->BbsType
= Ptr
->BbsType
;
1259 NewPtr
->Length
= (UINT16
) (sizeof (UINT16
) + NETCount
* sizeof (UINT16
));
1260 for (Index
= 0; Index
< Ptr
->Length
/ sizeof (UINT16
) - 1; Index
++) {
1261 if (LocalBbsTable
[Ptr
->Data
[Index
] & 0xFF].BootPriority
== BBS_IGNORE_ENTRY
||
1262 LocalBbsTable
[Ptr
->Data
[Index
] & 0xFF].BootPriority
== BBS_DO_NOT_BOOT_FROM
||
1263 LocalBbsTable
[Ptr
->Data
[Index
] & 0xFF].BootPriority
== BBS_LOWEST_PRIORITY
||
1264 LocalBbsTable
[Ptr
->Data
[Index
] & 0xFF].DeviceType
!= BBS_EMBED_NETWORK
1269 NewPtr
->Data
[NETIndex
] = Ptr
->Data
[Index
];
1272 NewNETPtr
= NewPtr
->Data
;
1277 Ptr
= (LEGACY_DEV_ORDER_ENTRY
*) (&Ptr
->Data
[Ptr
->Length
/ sizeof (UINT16
) - 1]);
1278 NewPtr
= (LEGACY_DEV_ORDER_ENTRY
*) (&NewPtr
->Data
[NewPtr
->Length
/ sizeof (UINT16
) -1]);
1279 NewPtr
->BbsType
= Ptr
->BbsType
;
1280 NewPtr
->Length
= (UINT16
) (sizeof (UINT16
) + BEVCount
* sizeof (UINT16
));
1281 for (Index
= 0; Index
< Ptr
->Length
/ sizeof (UINT16
) - 1; Index
++) {
1282 if (LocalBbsTable
[Ptr
->Data
[Index
] & 0xFF].BootPriority
== BBS_IGNORE_ENTRY
||
1283 LocalBbsTable
[Ptr
->Data
[Index
] & 0xFF].BootPriority
== BBS_DO_NOT_BOOT_FROM
||
1284 LocalBbsTable
[Ptr
->Data
[Index
] & 0xFF].BootPriority
== BBS_LOWEST_PRIORITY
||
1285 LocalBbsTable
[Ptr
->Data
[Index
] & 0xFF].DeviceType
!= BBS_BEV_DEVICE
1290 NewPtr
->Data
[BEVIndex
] = Ptr
->Data
[Index
];
1293 NewBEVPtr
= NewPtr
->Data
;
1295 for (Index
= 0; Index
< BbsCount
; Index
++) {
1296 if ((LocalBbsTable
[Index
].BootPriority
== BBS_IGNORE_ENTRY
) ||
1297 (LocalBbsTable
[Index
].BootPriority
== BBS_DO_NOT_BOOT_FROM
)
1302 switch (LocalBbsTable
[Index
].DeviceType
) {
1305 NewDevPtr
= NewFDPtr
;
1310 NewDevPtr
= NewHDPtr
;
1315 NewDevPtr
= NewCDPtr
;
1318 case BBS_EMBED_NETWORK
:
1320 NewDevPtr
= NewNETPtr
;
1323 case BBS_BEV_DEVICE
:
1325 NewDevPtr
= NewBEVPtr
;
1333 // at this point we have copied those valid indexes to new buffer
1334 // and we should check if there is any new appeared boot device
1337 for (Index2
= 0; Index2
< *Idx
; Index2
++) {
1338 if ((NewDevPtr
[Index2
] & 0xFF) == (UINT16
) Index
) {
1343 if (Index2
== *Idx
) {
1345 // Index2 == *Idx means we didn't find Index
1346 // so Index is a new appeared device's index in BBS table
1347 // insert it before disabled indexes.
1349 for (Index2
= 0; Index2
< *Idx
; Index2
++) {
1350 if ((NewDevPtr
[Index2
] & 0xFF00) == 0xFF00) {
1354 CopyMem (&NewDevPtr
[Index2
+ 1], &NewDevPtr
[Index2
], (*Idx
- Index2
) * sizeof (UINT16
));
1355 NewDevPtr
[Index2
] = (UINT16
) (Index
& 0xFF);
1361 FreePool (DevOrder
);
1363 Status
= gRT
->SetVariable (
1364 VAR_LEGACY_DEV_ORDER
,
1365 &gEfiLegacyDevOrderVariableGuid
,
1366 EFI_VARIABLE_BOOTSERVICE_ACCESS
| EFI_VARIABLE_RUNTIME_ACCESS
| EFI_VARIABLE_NON_VOLATILE
,
1370 FreePool (NewDevOrder
);
1376 Set Boot Priority for specified device type.
1378 @param DeviceType The device type.
1379 @param BbsIndex The BBS index to set the highest priority. Ignore when -1.
1380 @param LocalBbsTable The BBS table.
1381 @param Priority The prority table.
1383 @retval EFI_SUCCESS The function completes successfully.
1384 @retval EFI_NOT_FOUND Failed to find device.
1385 @retval EFI_OUT_OF_RESOURCES Failed to get the efi variable of device order.
1389 BdsSetBootPriority4SameTypeDev (
1390 IN UINT16 DeviceType
,
1392 IN OUT BBS_TABLE
*LocalBbsTable
,
1393 IN OUT UINT16
*Priority
1396 LEGACY_DEV_ORDER_ENTRY
*DevOrder
;
1397 LEGACY_DEV_ORDER_ENTRY
*DevOrderPtr
;
1401 DevOrder
= BdsLibGetVariableAndSize (
1402 VAR_LEGACY_DEV_ORDER
,
1403 &gEfiLegacyDevOrderVariableGuid
,
1406 if (NULL
== DevOrder
) {
1407 return EFI_OUT_OF_RESOURCES
;
1410 DevOrderPtr
= DevOrder
;
1411 while ((UINT8
*) DevOrderPtr
< (UINT8
*) DevOrder
+ DevOrderSize
) {
1412 if (DevOrderPtr
->BbsType
== DeviceType
) {
1416 DevOrderPtr
= (LEGACY_DEV_ORDER_ENTRY
*) ((UINT8
*) DevOrderPtr
+ sizeof (BBS_TYPE
) + DevOrderPtr
->Length
);
1419 if ((UINT8
*) DevOrderPtr
>= (UINT8
*) DevOrder
+ DevOrderSize
) {
1420 FreePool (DevOrder
);
1421 return EFI_NOT_FOUND
;
1424 if (BbsIndex
!= (UINTN
) -1) {
1425 LocalBbsTable
[BbsIndex
].BootPriority
= *Priority
;
1429 // If the high byte of the DevIndex is 0xFF, it indicates that this device has been disabled.
1431 for (Index
= 0; Index
< DevOrderPtr
->Length
/ sizeof (UINT16
) - 1; Index
++) {
1432 if ((DevOrderPtr
->Data
[Index
] & 0xFF00) == 0xFF00) {
1434 // LocalBbsTable[DevIndex[Index] & 0xFF].BootPriority = BBS_DISABLED_ENTRY;
1436 } else if (DevOrderPtr
->Data
[Index
] != BbsIndex
) {
1437 LocalBbsTable
[DevOrderPtr
->Data
[Index
]].BootPriority
= *Priority
;
1442 FreePool (DevOrder
);
1447 Print the BBS Table.
1449 @param LocalBbsTable The BBS table.
1450 @param BbsCount The count of entry in BBS table.
1454 IN BBS_TABLE
*LocalBbsTable
,
1460 DEBUG ((DEBUG_ERROR
, "\n"));
1461 DEBUG ((DEBUG_ERROR
, " NO Prio bb/dd/ff cl/sc Type Stat segm:offs\n"));
1462 DEBUG ((DEBUG_ERROR
, "=============================================\n"));
1463 for (Idx
= 0; Idx
< BbsCount
; Idx
++) {
1464 if ((LocalBbsTable
[Idx
].BootPriority
== BBS_IGNORE_ENTRY
) ||
1465 (LocalBbsTable
[Idx
].BootPriority
== BBS_DO_NOT_BOOT_FROM
) ||
1466 (LocalBbsTable
[Idx
].BootPriority
== BBS_LOWEST_PRIORITY
)
1473 " %02x: %04x %02x/%02x/%02x %02x/%02x %04x %04x %04x:%04x\n",
1475 (UINTN
) LocalBbsTable
[Idx
].BootPriority
,
1476 (UINTN
) LocalBbsTable
[Idx
].Bus
,
1477 (UINTN
) LocalBbsTable
[Idx
].Device
,
1478 (UINTN
) LocalBbsTable
[Idx
].Function
,
1479 (UINTN
) LocalBbsTable
[Idx
].Class
,
1480 (UINTN
) LocalBbsTable
[Idx
].SubClass
,
1481 (UINTN
) LocalBbsTable
[Idx
].DeviceType
,
1482 (UINTN
) * (UINT16
*) &LocalBbsTable
[Idx
].StatusFlags
,
1483 (UINTN
) LocalBbsTable
[Idx
].BootHandlerSegment
,
1484 (UINTN
) LocalBbsTable
[Idx
].BootHandlerOffset
,
1485 (UINTN
) ((LocalBbsTable
[Idx
].MfgStringSegment
<< 4) + LocalBbsTable
[Idx
].MfgStringOffset
),
1486 (UINTN
) ((LocalBbsTable
[Idx
].DescStringSegment
<< 4) + LocalBbsTable
[Idx
].DescStringOffset
))
1490 DEBUG ((DEBUG_ERROR
, "\n"));
1494 Set the boot priority for BBS entries based on boot option entry and boot order.
1496 @param Entry The boot option is to be checked for refresh BBS table.
1498 @retval EFI_SUCCESS The boot priority for BBS entries is refreshed successfully.
1499 @retval EFI_NOT_FOUND BBS entries can't be found.
1500 @retval EFI_OUT_OF_RESOURCES Failed to get the legacy device boot order.
1504 BdsRefreshBbsTableForBoot (
1505 IN BDS_COMMON_OPTION
*Entry
1512 HDD_INFO
*LocalHddInfo
;
1513 BBS_TABLE
*LocalBbsTable
;
1515 EFI_LEGACY_BIOS_PROTOCOL
*LegacyBios
;
1519 UINTN BootOrderSize
;
1520 UINT8
*BootOptionVar
;
1521 UINTN BootOptionSize
;
1522 CHAR16 BootOption
[9];
1525 EFI_DEVICE_PATH_PROTOCOL
*DevPath
;
1527 UINTN DeviceTypeCount
;
1528 UINTN DeviceTypeIndex
;
1532 LocalHddInfo
= NULL
;
1533 LocalBbsTable
= NULL
;
1534 DevType
= BBS_UNKNOWN
;
1536 Status
= gBS
->LocateProtocol (&gEfiLegacyBiosProtocolGuid
, NULL
, (VOID
**) &LegacyBios
);
1537 if (EFI_ERROR (Status
)) {
1541 LegacyBios
->GetBbsInfo (
1549 // First, set all the present devices' boot priority to BBS_UNPRIORITIZED_ENTRY
1550 // We will set them according to the settings setup by user
1552 for (Index
= 0; Index
< BbsCount
; Index
++) {
1553 if (!((BBS_IGNORE_ENTRY
== LocalBbsTable
[Index
].BootPriority
) ||
1554 (BBS_DO_NOT_BOOT_FROM
== LocalBbsTable
[Index
].BootPriority
) ||
1555 (BBS_LOWEST_PRIORITY
== LocalBbsTable
[Index
].BootPriority
))) {
1556 LocalBbsTable
[Index
].BootPriority
= BBS_UNPRIORITIZED_ENTRY
;
1560 // boot priority always starts at 0
1563 if (Entry
->LoadOptionsSize
== sizeof (BBS_TABLE
) + sizeof (UINT16
)) {
1565 // If Entry stands for a legacy boot option, we prioritize the devices with the same type first.
1567 DevType
= ((BBS_TABLE
*) Entry
->LoadOptions
)->DeviceType
;
1568 BbsIndex
= *(UINT16
*) ((BBS_TABLE
*) Entry
->LoadOptions
+ 1);
1569 Status
= BdsSetBootPriority4SameTypeDev (
1575 if (EFI_ERROR (Status
)) {
1580 // we have to set the boot priority for other BBS entries with different device types
1582 BootOrder
= BdsLibGetVariableAndSize (
1584 &gEfiGlobalVariableGuid
,
1587 DeviceType
= AllocatePool (BootOrderSize
+ sizeof (UINT16
));
1588 ASSERT (DeviceType
!= NULL
);
1590 DeviceType
[0] = DevType
;
1591 DeviceTypeCount
= 1;
1592 for (Index
= 0; ((BootOrder
!= NULL
) && (Index
< BootOrderSize
/ sizeof (UINT16
))); Index
++) {
1593 UnicodeSPrint (BootOption
, sizeof (BootOption
), L
"Boot%04x", BootOrder
[Index
]);
1594 BootOptionVar
= BdsLibGetVariableAndSize (
1596 &gEfiGlobalVariableGuid
,
1599 if (NULL
== BootOptionVar
) {
1603 Ptr
= BootOptionVar
;
1605 Ptr
+= sizeof (UINT32
);
1606 DevPathLen
= *(UINT16
*) Ptr
;
1607 Ptr
+= sizeof (UINT16
);
1608 Ptr
+= StrSize ((UINT16
*) Ptr
);
1609 DevPath
= (EFI_DEVICE_PATH_PROTOCOL
*) Ptr
;
1610 if (BBS_DEVICE_PATH
!= DevPath
->Type
|| BBS_BBS_DP
!= DevPath
->SubType
) {
1611 FreePool (BootOptionVar
);
1616 DevType
= ((BBS_TABLE
*) Ptr
)->DeviceType
;
1617 for (DeviceTypeIndex
= 0; DeviceTypeIndex
< DeviceTypeCount
; DeviceTypeIndex
++) {
1618 if (DeviceType
[DeviceTypeIndex
] == DevType
) {
1622 if (DeviceTypeIndex
< DeviceTypeCount
) {
1624 // We don't want to process twice for a device type
1626 FreePool (BootOptionVar
);
1630 DeviceType
[DeviceTypeCount
] = DevType
;
1633 Status
= BdsSetBootPriority4SameTypeDev (
1639 FreePool (BootOptionVar
);
1640 if (EFI_ERROR (Status
)) {
1645 if (BootOrder
!= NULL
) {
1646 FreePool (BootOrder
);
1650 PrintBbsTable (LocalBbsTable
, BbsCount
);
1657 Boot the legacy system with the boot option
1659 @param Option The legacy boot option which have BBS device path
1661 @retval EFI_UNSUPPORTED There is no legacybios protocol, do not support
1663 @retval EFI_STATUS Return the status of LegacyBios->LegacyBoot ().
1667 BdsLibDoLegacyBoot (
1668 IN BDS_COMMON_OPTION
*Option
1672 EFI_LEGACY_BIOS_PROTOCOL
*LegacyBios
;
1673 EFI_EVENT LegacyBootEvent
;
1675 Status
= gBS
->LocateProtocol (&gEfiLegacyBiosProtocolGuid
, NULL
, (VOID
**) &LegacyBios
);
1676 if (EFI_ERROR (Status
)) {
1678 // If no LegacyBios protocol we do not support legacy boot
1680 return EFI_UNSUPPORTED
;
1683 // Notes: if we separate the int 19, then we don't need to refresh BBS
1685 BdsRefreshBbsTableForBoot (Option
);
1688 // Write boot to OS performance data for legacy boot.
1692 // Create an event to be signalled when Legacy Boot occurs to write performance data.
1694 Status
= EfiCreateEventLegacyBootEx(
1696 WriteBootToOsPerformanceData
,
1700 ASSERT_EFI_ERROR (Status
);
1703 DEBUG ((DEBUG_INFO
| DEBUG_LOAD
, "Legacy Boot: %S\n", Option
->Description
));
1704 return LegacyBios
->LegacyBoot (
1706 (BBS_BBS_DEVICE_PATH
*) Option
->DevicePath
,
1707 Option
->LoadOptionsSize
,
1713 Internal function to check if the input boot option is a valid EFI NV Boot####.
1715 @param OptionToCheck Boot option to be checked.
1717 @retval TRUE This boot option matches a valid EFI NV Boot####.
1718 @retval FALSE If not.
1722 IsBootOptionValidNVVarialbe (
1723 IN BDS_COMMON_OPTION
*OptionToCheck
1726 LIST_ENTRY TempList
;
1727 BDS_COMMON_OPTION
*BootOption
;
1729 CHAR16 OptionName
[20];
1733 InitializeListHead (&TempList
);
1734 UnicodeSPrint (OptionName
, sizeof (OptionName
), L
"Boot%04x", OptionToCheck
->BootCurrent
);
1736 BootOption
= BdsLibVariableToOption (&TempList
, OptionName
);
1737 if (BootOption
== NULL
) {
1742 // If the Boot Option Number and Device Path matches, OptionToCheck matches a
1743 // valid EFI NV Boot####.
1745 if ((OptionToCheck
->BootCurrent
== BootOption
->BootCurrent
) &&
1746 (CompareMem (OptionToCheck
->DevicePath
, BootOption
->DevicePath
, GetDevicePathSize (OptionToCheck
->DevicePath
)) == 0))
1751 FreePool (BootOption
);
1757 Check whether a USB device match the specified USB Class device path. This
1758 function follows "Load Option Processing" behavior in UEFI specification.
1760 @param UsbIo USB I/O protocol associated with the USB device.
1761 @param UsbClass The USB Class device path to match.
1763 @retval TRUE The USB device match the USB Class device path.
1764 @retval FALSE The USB device does not match the USB Class device path.
1769 IN EFI_USB_IO_PROTOCOL
*UsbIo
,
1770 IN USB_CLASS_DEVICE_PATH
*UsbClass
1774 EFI_USB_DEVICE_DESCRIPTOR DevDesc
;
1775 EFI_USB_INTERFACE_DESCRIPTOR IfDesc
;
1777 UINT8 DeviceSubClass
;
1778 UINT8 DeviceProtocol
;
1780 if ((DevicePathType (UsbClass
) != MESSAGING_DEVICE_PATH
) ||
1781 (DevicePathSubType (UsbClass
) != MSG_USB_CLASS_DP
)){
1786 // Check Vendor Id and Product Id.
1788 Status
= UsbIo
->UsbGetDeviceDescriptor (UsbIo
, &DevDesc
);
1789 if (EFI_ERROR (Status
)) {
1793 if ((UsbClass
->VendorId
!= 0xffff) &&
1794 (UsbClass
->VendorId
!= DevDesc
.IdVendor
)) {
1798 if ((UsbClass
->ProductId
!= 0xffff) &&
1799 (UsbClass
->ProductId
!= DevDesc
.IdProduct
)) {
1803 DeviceClass
= DevDesc
.DeviceClass
;
1804 DeviceSubClass
= DevDesc
.DeviceSubClass
;
1805 DeviceProtocol
= DevDesc
.DeviceProtocol
;
1806 if (DeviceClass
== 0) {
1808 // If Class in Device Descriptor is set to 0, use the Class, SubClass and
1809 // Protocol in Interface Descriptor instead.
1811 Status
= UsbIo
->UsbGetInterfaceDescriptor (UsbIo
, &IfDesc
);
1812 if (EFI_ERROR (Status
)) {
1816 DeviceClass
= IfDesc
.InterfaceClass
;
1817 DeviceSubClass
= IfDesc
.InterfaceSubClass
;
1818 DeviceProtocol
= IfDesc
.InterfaceProtocol
;
1822 // Check Class, SubClass and Protocol.
1824 if ((UsbClass
->DeviceClass
!= 0xff) &&
1825 (UsbClass
->DeviceClass
!= DeviceClass
)) {
1829 if ((UsbClass
->DeviceSubClass
!= 0xff) &&
1830 (UsbClass
->DeviceSubClass
!= DeviceSubClass
)) {
1834 if ((UsbClass
->DeviceProtocol
!= 0xff) &&
1835 (UsbClass
->DeviceProtocol
!= DeviceProtocol
)) {
1843 Check whether a USB device match the specified USB WWID device path. This
1844 function follows "Load Option Processing" behavior in UEFI specification.
1846 @param UsbIo USB I/O protocol associated with the USB device.
1847 @param UsbWwid The USB WWID device path to match.
1849 @retval TRUE The USB device match the USB WWID device path.
1850 @retval FALSE The USB device does not match the USB WWID device path.
1855 IN EFI_USB_IO_PROTOCOL
*UsbIo
,
1856 IN USB_WWID_DEVICE_PATH
*UsbWwid
1860 EFI_USB_DEVICE_DESCRIPTOR DevDesc
;
1861 EFI_USB_INTERFACE_DESCRIPTOR IfDesc
;
1862 UINT16
*LangIdTable
;
1867 CHAR16
*SerialNumberStr
;
1870 if ((DevicePathType (UsbWwid
) != MESSAGING_DEVICE_PATH
) ||
1871 (DevicePathSubType (UsbWwid
) != MSG_USB_WWID_DP
)){
1876 // Check Vendor Id and Product Id.
1878 Status
= UsbIo
->UsbGetDeviceDescriptor (UsbIo
, &DevDesc
);
1879 if (EFI_ERROR (Status
)) {
1882 if ((DevDesc
.IdVendor
!= UsbWwid
->VendorId
) ||
1883 (DevDesc
.IdProduct
!= UsbWwid
->ProductId
)) {
1888 // Check Interface Number.
1890 Status
= UsbIo
->UsbGetInterfaceDescriptor (UsbIo
, &IfDesc
);
1891 if (EFI_ERROR (Status
)) {
1894 if (IfDesc
.InterfaceNumber
!= UsbWwid
->InterfaceNumber
) {
1899 // Check Serial Number.
1901 if (DevDesc
.StrSerialNumber
== 0) {
1906 // Get all supported languages.
1910 Status
= UsbIo
->UsbGetSupportedLanguages (UsbIo
, &LangIdTable
, &TableSize
);
1911 if (EFI_ERROR (Status
) || (TableSize
== 0) || (LangIdTable
== NULL
)) {
1916 // Serial number in USB WWID device path is the last 64-or-less UTF-16 characters.
1918 CompareStr
= (CHAR16
*) (UINTN
) (UsbWwid
+ 1);
1919 CompareLen
= (DevicePathNodeLength (UsbWwid
) - sizeof (USB_WWID_DEVICE_PATH
)) / sizeof (CHAR16
);
1920 if (CompareStr
[CompareLen
- 1] == L
'\0') {
1925 // Compare serial number in each supported language.
1927 for (Index
= 0; Index
< TableSize
/ sizeof (UINT16
); Index
++) {
1928 SerialNumberStr
= NULL
;
1929 Status
= UsbIo
->UsbGetStringDescriptor (
1932 DevDesc
.StrSerialNumber
,
1935 if (EFI_ERROR (Status
) || (SerialNumberStr
== NULL
)) {
1939 Length
= StrLen (SerialNumberStr
);
1940 if ((Length
>= CompareLen
) &&
1941 (CompareMem (SerialNumberStr
+ Length
- CompareLen
, CompareStr
, CompareLen
* sizeof (CHAR16
)) == 0)) {
1942 FreePool (SerialNumberStr
);
1946 FreePool (SerialNumberStr
);
1953 Find a USB device path which match the specified short-form device path start
1954 with USB Class or USB WWID device path and load the boot file then return the
1955 image handle. If ParentDevicePath is NULL, this function will search in all USB
1956 devices of the platform. If ParentDevicePath is not NULL,this function will only
1957 search in its child devices.
1959 @param ParentDevicePath The device path of the parent.
1960 @param ShortFormDevicePath The USB Class or USB WWID device path to match.
1962 @return The image Handle if find load file from specified short-form device path
1963 or NULL if not found.
1968 IN EFI_DEVICE_PATH_PROTOCOL
*ParentDevicePath
,
1969 IN EFI_DEVICE_PATH_PROTOCOL
*ShortFormDevicePath
1973 UINTN UsbIoHandleCount
;
1974 EFI_HANDLE
*UsbIoHandleBuffer
;
1975 EFI_DEVICE_PATH_PROTOCOL
*UsbIoDevicePath
;
1976 EFI_USB_IO_PROTOCOL
*UsbIo
;
1980 EFI_HANDLE ImageHandle
;
1982 EFI_DEVICE_PATH_PROTOCOL
*FullDevicePath
;
1983 EFI_DEVICE_PATH_PROTOCOL
*NextDevicePath
;
1985 FullDevicePath
= NULL
;
1989 // Get all UsbIo Handles.
1991 UsbIoHandleCount
= 0;
1992 UsbIoHandleBuffer
= NULL
;
1993 Status
= gBS
->LocateHandleBuffer (
1995 &gEfiUsbIoProtocolGuid
,
2000 if (EFI_ERROR (Status
) || (UsbIoHandleCount
== 0) || (UsbIoHandleBuffer
== NULL
)) {
2004 ParentSize
= (ParentDevicePath
== NULL
) ? 0 : GetDevicePathSize (ParentDevicePath
);
2005 for (Index
= 0; Index
< UsbIoHandleCount
; Index
++) {
2007 // Get the Usb IO interface.
2009 Status
= gBS
->HandleProtocol(
2010 UsbIoHandleBuffer
[Index
],
2011 &gEfiUsbIoProtocolGuid
,
2014 if (EFI_ERROR (Status
)) {
2018 UsbIoDevicePath
= DevicePathFromHandle (UsbIoHandleBuffer
[Index
]);
2019 if (UsbIoDevicePath
== NULL
) {
2023 if (ParentDevicePath
!= NULL
) {
2025 // Compare starting part of UsbIoHandle's device path with ParentDevicePath.
2027 Size
= GetDevicePathSize (UsbIoDevicePath
);
2028 if ((Size
< ParentSize
) ||
2029 (CompareMem (UsbIoDevicePath
, ParentDevicePath
, ParentSize
- END_DEVICE_PATH_LENGTH
) != 0)) {
2034 if (BdsMatchUsbClass (UsbIo
, (USB_CLASS_DEVICE_PATH
*) ShortFormDevicePath
) ||
2035 BdsMatchUsbWwid (UsbIo
, (USB_WWID_DEVICE_PATH
*) ShortFormDevicePath
)) {
2037 // Try to find if there is the boot file in this DevicePath
2039 NextDevicePath
= NextDevicePathNode (ShortFormDevicePath
);
2040 if (!IsDevicePathEnd (NextDevicePath
)) {
2041 FullDevicePath
= AppendDevicePath (UsbIoDevicePath
, NextDevicePath
);
2043 // Connect the full device path, so that Simple File System protocol
2044 // could be installed for this USB device.
2046 BdsLibConnectDevicePath (FullDevicePath
);
2047 REPORT_STATUS_CODE (EFI_PROGRESS_CODE
, PcdGet32 (PcdProgressCodeOsLoaderLoad
));
2048 Status
= gBS
->LoadImage (
2056 FreePool (FullDevicePath
);
2058 FullDevicePath
= UsbIoDevicePath
;
2059 Status
= EFI_NOT_FOUND
;
2063 // If we didn't find an image directly, we need to try as if it is a removable device boot option
2064 // and load the image according to the default boot behavior for removable device.
2066 if (EFI_ERROR (Status
)) {
2068 // check if there is a bootable removable media could be found in this device path ,
2069 // and get the bootable media handle
2071 Handle
= BdsLibGetBootableHandle(UsbIoDevicePath
);
2072 if (Handle
== NULL
) {
2076 // Load the default boot file \EFI\BOOT\boot{machinename}.EFI from removable Media
2077 // machinename is ia32, ia64, x64, ...
2079 FullDevicePath
= FileDevicePath (Handle
, EFI_REMOVABLE_MEDIA_FILE_NAME
);
2080 if (FullDevicePath
!= NULL
) {
2081 REPORT_STATUS_CODE (EFI_PROGRESS_CODE
, PcdGet32 (PcdProgressCodeOsLoaderLoad
));
2082 Status
= gBS
->LoadImage (
2090 if (EFI_ERROR (Status
)) {
2092 // The DevicePath failed, and it's not a valid
2093 // removable media device.
2105 FreePool (UsbIoHandleBuffer
);
2110 Expand USB Class or USB WWID device path node to be full device path of a USB
2111 device in platform then load the boot file on this full device path and return the
2114 This function support following 4 cases:
2115 1) Boot Option device path starts with a USB Class or USB WWID device path,
2116 and there is no Media FilePath device path in the end.
2117 In this case, it will follow Removable Media Boot Behavior.
2118 2) Boot Option device path starts with a USB Class or USB WWID device path,
2119 and ended with Media FilePath device path.
2120 3) Boot Option device path starts with a full device path to a USB Host Controller,
2121 contains a USB Class or USB WWID device path node, while not ended with Media
2122 FilePath device path. In this case, it will follow Removable Media Boot Behavior.
2123 4) Boot Option device path starts with a full device path to a USB Host Controller,
2124 contains a USB Class or USB WWID device path node, and ended with Media
2125 FilePath device path.
2127 @param DevicePath The Boot Option device path.
2129 @return The image handle of boot file, or NULL if there is no boot file found in
2130 the specified USB Class or USB WWID device path.
2134 BdsExpandUsbShortFormDevicePath (
2135 IN EFI_DEVICE_PATH_PROTOCOL
*DevicePath
2138 EFI_HANDLE
*ImageHandle
;
2139 EFI_DEVICE_PATH_PROTOCOL
*TempDevicePath
;
2140 EFI_DEVICE_PATH_PROTOCOL
*ShortFormDevicePath
;
2143 // Search for USB Class or USB WWID device path node.
2145 ShortFormDevicePath
= NULL
;
2147 TempDevicePath
= DevicePath
;
2148 while (!IsDevicePathEnd (TempDevicePath
)) {
2149 if ((DevicePathType (TempDevicePath
) == MESSAGING_DEVICE_PATH
) &&
2150 ((DevicePathSubType (TempDevicePath
) == MSG_USB_CLASS_DP
) ||
2151 (DevicePathSubType (TempDevicePath
) == MSG_USB_WWID_DP
))) {
2152 ShortFormDevicePath
= TempDevicePath
;
2155 TempDevicePath
= NextDevicePathNode (TempDevicePath
);
2158 if (ShortFormDevicePath
== NULL
) {
2160 // No USB Class or USB WWID device path node found, do nothing.
2165 if (ShortFormDevicePath
== DevicePath
) {
2167 // Boot Option device path starts with USB Class or USB WWID device path.
2169 ImageHandle
= BdsFindUsbDevice (NULL
, ShortFormDevicePath
);
2170 if (ImageHandle
== NULL
) {
2172 // Failed to find a match in existing devices, connect the short form USB
2173 // device path and try again.
2175 BdsLibConnectUsbDevByShortFormDP (0xff, ShortFormDevicePath
);
2176 ImageHandle
= BdsFindUsbDevice (NULL
, ShortFormDevicePath
);
2180 // Boot Option device path contains USB Class or USB WWID device path node.
2184 // Prepare the parent device path for search.
2186 TempDevicePath
= DuplicateDevicePath (DevicePath
);
2187 ASSERT (TempDevicePath
!= NULL
);
2188 SetDevicePathEndNode (((UINT8
*) TempDevicePath
) + ((UINTN
) ShortFormDevicePath
- (UINTN
) DevicePath
));
2191 // The USB Host Controller device path is already in Boot Option device path
2192 // and USB Bus driver already support RemainingDevicePath starts with USB
2193 // Class or USB WWID device path, so just search in existing USB devices and
2194 // doesn't perform ConnectController here.
2196 ImageHandle
= BdsFindUsbDevice (TempDevicePath
, ShortFormDevicePath
);
2197 FreePool (TempDevicePath
);
2204 Process the boot option follow the UEFI specification and
2205 special treat the legacy boot option with BBS_DEVICE_PATH.
2207 @param Option The boot option need to be processed
2208 @param DevicePath The device path which describe where to load the
2209 boot image or the legacy BBS device path to boot
2211 @param ExitDataSize The size of exit data.
2212 @param ExitData Data returned when Boot image failed.
2214 @retval EFI_SUCCESS Boot from the input boot option successfully.
2215 @retval EFI_NOT_FOUND If the Device Path is not found in the system
2220 BdsLibBootViaBootOption (
2221 IN BDS_COMMON_OPTION
*Option
,
2222 IN EFI_DEVICE_PATH_PROTOCOL
*DevicePath
,
2223 OUT UINTN
*ExitDataSize
,
2224 OUT CHAR16
**ExitData OPTIONAL
2228 EFI_STATUS StatusLogo
;
2230 EFI_HANDLE ImageHandle
;
2231 EFI_DEVICE_PATH_PROTOCOL
*FilePath
;
2232 EFI_LOADED_IMAGE_PROTOCOL
*ImageInfo
;
2233 EFI_DEVICE_PATH_PROTOCOL
*WorkingDevicePath
;
2234 EFI_ACPI_S3_SAVE_PROTOCOL
*AcpiS3Save
;
2235 LIST_ENTRY TempBootLists
;
2236 EFI_BOOT_LOGO_PROTOCOL
*BootLogo
;
2242 // Notes: this code can be remove after the s3 script table
2243 // hook on the event EVT_SIGNAL_READY_TO_BOOT or
2244 // EVT_SIGNAL_LEGACY_BOOT
2246 Status
= gBS
->LocateProtocol (&gEfiAcpiS3SaveProtocolGuid
, NULL
, (VOID
**) &AcpiS3Save
);
2247 if (!EFI_ERROR (Status
)) {
2248 AcpiS3Save
->S3Save (AcpiS3Save
, NULL
);
2251 // If it's Device Path that starts with a hard drive path, append it with the front part to compose a
2254 WorkingDevicePath
= NULL
;
2255 if ((DevicePathType (DevicePath
) == MEDIA_DEVICE_PATH
) &&
2256 (DevicePathSubType (DevicePath
) == MEDIA_HARDDRIVE_DP
)) {
2257 WorkingDevicePath
= BdsExpandPartitionPartialDevicePathToFull (
2258 (HARDDRIVE_DEVICE_PATH
*)DevicePath
2260 if (WorkingDevicePath
!= NULL
) {
2261 DevicePath
= WorkingDevicePath
;
2268 if (IsBootOptionValidNVVarialbe (Option
)) {
2270 // For a temporary boot (i.e. a boot by selected a EFI Shell using "Boot From File"), Boot Current is actually not valid.
2271 // In this case, "BootCurrent" is not created.
2272 // Only create the BootCurrent variable when it points to a valid Boot#### variable.
2274 SetVariableAndReportStatusCodeOnError (
2276 &gEfiGlobalVariableGuid
,
2277 EFI_VARIABLE_BOOTSERVICE_ACCESS
| EFI_VARIABLE_RUNTIME_ACCESS
,
2279 &Option
->BootCurrent
2284 // Report Status Code to indicate ReadyToBoot event will be signalled
2286 REPORT_STATUS_CODE (EFI_PROGRESS_CODE
, (EFI_SOFTWARE_DXE_BS_DRIVER
| EFI_SW_DXE_BS_PC_READY_TO_BOOT_EVENT
));
2289 // Signal the EVT_SIGNAL_READY_TO_BOOT event
2291 EfiSignalEventReadyToBoot();
2294 // Expand USB Class or USB WWID device path node to be full device path of a USB
2295 // device in platform then load the boot file on this full device path and get the
2298 ImageHandle
= BdsExpandUsbShortFormDevicePath (DevicePath
);
2301 // Adjust the different type memory page number just before booting
2302 // and save the updated info into the variable for next boot to use
2304 BdsSetMemoryTypeInformationVariable ();
2307 // By expanding the USB Class or WWID device path, the ImageHandle has returnned.
2308 // Here get the ImageHandle for the non USB class or WWID device path.
2310 if (ImageHandle
== NULL
) {
2311 ASSERT (Option
->DevicePath
!= NULL
);
2312 if ((DevicePathType (Option
->DevicePath
) == BBS_DEVICE_PATH
) &&
2313 (DevicePathSubType (Option
->DevicePath
) == BBS_BBS_DP
)
2316 // Check to see if we should legacy BOOT. If yes then do the legacy boot
2318 return BdsLibDoLegacyBoot (Option
);
2322 // If the boot option point to Internal FV shell, make sure it is valid
2324 Status
= BdsLibUpdateFvFileDevicePath (&DevicePath
, PcdGetPtr(PcdShellFile
));
2325 if (!EFI_ERROR(Status
)) {
2326 if (Option
->DevicePath
!= NULL
) {
2327 FreePool(Option
->DevicePath
);
2329 Option
->DevicePath
= AllocateZeroPool (GetDevicePathSize (DevicePath
));
2330 ASSERT(Option
->DevicePath
!= NULL
);
2331 CopyMem (Option
->DevicePath
, DevicePath
, GetDevicePathSize (DevicePath
));
2333 // Update the shell boot option
2335 InitializeListHead (&TempBootLists
);
2336 BdsLibRegisterNewOption (&TempBootLists
, DevicePath
, L
"EFI Internal Shell", L
"BootOrder");
2339 // free the temporary device path created by BdsLibUpdateFvFileDevicePath()
2341 FreePool (DevicePath
);
2342 DevicePath
= Option
->DevicePath
;
2347 if (Option
->Description
== NULL
) {
2348 DEBUG ((DEBUG_INFO
| DEBUG_LOAD
, "Booting from unknown device path\n"));
2350 DEBUG ((DEBUG_INFO
| DEBUG_LOAD
, "Booting %S\n", Option
->Description
));
2356 // Report status code for OS Loader LoadImage.
2358 REPORT_STATUS_CODE (EFI_PROGRESS_CODE
, PcdGet32 (PcdProgressCodeOsLoaderLoad
));
2359 Status
= gBS
->LoadImage (
2369 // If we didn't find an image directly, we need to try as if it is a removable device boot option
2370 // and load the image according to the default boot behavior for removable device.
2372 if (EFI_ERROR (Status
)) {
2374 // check if there is a bootable removable media could be found in this device path ,
2375 // and get the bootable media handle
2377 Handle
= BdsLibGetBootableHandle(DevicePath
);
2378 if (Handle
!= NULL
) {
2380 // Load the default boot file \EFI\BOOT\boot{machinename}.EFI from removable Media
2381 // machinename is ia32, ia64, x64, ...
2383 FilePath
= FileDevicePath (Handle
, EFI_REMOVABLE_MEDIA_FILE_NAME
);
2384 if (FilePath
!= NULL
) {
2385 REPORT_STATUS_CODE (EFI_PROGRESS_CODE
, PcdGet32 (PcdProgressCodeOsLoaderLoad
));
2386 Status
= gBS
->LoadImage (
2399 // Provide the image with it's load options
2401 if ((ImageHandle
== NULL
) || (EFI_ERROR(Status
))) {
2403 // Report Status Code to indicate that the failure to load boot option
2405 REPORT_STATUS_CODE (
2406 EFI_ERROR_CODE
| EFI_ERROR_MINOR
,
2407 (EFI_SOFTWARE_DXE_BS_DRIVER
| EFI_SW_DXE_BS_EC_BOOT_OPTION_LOAD_ERROR
)
2412 Status
= gBS
->HandleProtocol (ImageHandle
, &gEfiLoadedImageProtocolGuid
, (VOID
**) &ImageInfo
);
2413 ASSERT_EFI_ERROR (Status
);
2415 if (Option
->LoadOptionsSize
!= 0) {
2416 ImageInfo
->LoadOptionsSize
= Option
->LoadOptionsSize
;
2417 ImageInfo
->LoadOptions
= Option
->LoadOptions
;
2421 // Clean to NULL because the image is loaded directly from the firmwares boot manager.
2423 ImageInfo
->ParentHandle
= NULL
;
2426 // Before calling the image, enable the Watchdog Timer for
2427 // the 5 Minute period
2429 gBS
->SetWatchdogTimer (5 * 60, 0x0000, 0x00, NULL
);
2432 // Write boot to OS performance data for UEFI boot
2435 WriteBootToOsPerformanceData (NULL
, NULL
);
2439 // Report status code for OS Loader StartImage.
2441 REPORT_STATUS_CODE (EFI_PROGRESS_CODE
, PcdGet32 (PcdProgressCodeOsLoaderStart
));
2443 Status
= gBS
->StartImage (ImageHandle
, ExitDataSize
, ExitData
);
2444 DEBUG ((DEBUG_INFO
| DEBUG_LOAD
, "Image Return Status = %r\n", Status
));
2445 if (EFI_ERROR (Status
)) {
2447 // Report Status Code to indicate that boot failure
2449 REPORT_STATUS_CODE (
2450 EFI_ERROR_CODE
| EFI_ERROR_MINOR
,
2451 (EFI_SOFTWARE_DXE_BS_DRIVER
| EFI_SW_DXE_BS_EC_BOOT_OPTION_FAILED
)
2456 // Clear the Watchdog Timer after the image returns
2458 gBS
->SetWatchdogTimer (0x0000, 0x0000, 0x0000, NULL
);
2462 // Set Logo status invalid after trying one boot option
2465 StatusLogo
= gBS
->LocateProtocol (&gEfiBootLogoProtocolGuid
, NULL
, (VOID
**) &BootLogo
);
2466 if (!EFI_ERROR (StatusLogo
) && (BootLogo
!= NULL
)) {
2467 BootLogo
->SetBootLogo (BootLogo
, NULL
, 0, 0, 0, 0);
2471 // Clear Boot Current
2472 // Deleting variable with current implementation shouldn't fail.
2476 &gEfiGlobalVariableGuid
,
2477 EFI_VARIABLE_BOOTSERVICE_ACCESS
| EFI_VARIABLE_RUNTIME_ACCESS
,
2487 Expand a device path that starts with a hard drive media device path node to be a
2488 full device path that includes the full hardware path to the device. We need
2489 to do this so it can be booted. As an optimization the front match (the part point
2490 to the partition node. E.g. ACPI() /PCI()/ATA()/Partition() ) is saved in a variable
2491 so a connect all is not required on every boot. All successful history device path
2492 which point to partition node (the front part) will be saved.
2494 @param HardDriveDevicePath EFI Device Path to boot, if it starts with a hard
2495 drive media device path.
2496 @return A Pointer to the full device path or NULL if a valid Hard Drive devic path
2500 EFI_DEVICE_PATH_PROTOCOL
*
2502 BdsExpandPartitionPartialDevicePathToFull (
2503 IN HARDDRIVE_DEVICE_PATH
*HardDriveDevicePath
2507 UINTN BlockIoHandleCount
;
2508 EFI_HANDLE
*BlockIoBuffer
;
2509 EFI_DEVICE_PATH_PROTOCOL
*FullDevicePath
;
2510 EFI_DEVICE_PATH_PROTOCOL
*BlockIoDevicePath
;
2511 EFI_DEVICE_PATH_PROTOCOL
*DevicePath
;
2514 EFI_DEVICE_PATH_PROTOCOL
*CachedDevicePath
;
2515 EFI_DEVICE_PATH_PROTOCOL
*TempNewDevicePath
;
2516 UINTN CachedDevicePathSize
;
2517 BOOLEAN DeviceExist
;
2519 EFI_DEVICE_PATH_PROTOCOL
*Instance
;
2522 FullDevicePath
= NULL
;
2524 // Check if there is prestore HD_BOOT_DEVICE_PATH_VARIABLE_NAME variable.
2525 // If exist, search the front path which point to partition node in the variable instants.
2526 // If fail to find or HD_BOOT_DEVICE_PATH_VARIABLE_NAME not exist, reconnect all and search in all system
2529 HD_BOOT_DEVICE_PATH_VARIABLE_NAME
,
2530 &gHdBootDevicePathVariablGuid
,
2531 (VOID
**) &CachedDevicePath
,
2532 &CachedDevicePathSize
2536 // Delete the invalid HD_BOOT_DEVICE_PATH_VARIABLE_NAME variable.
2538 if ((CachedDevicePath
!= NULL
) && !IsDevicePathValid (CachedDevicePath
, CachedDevicePathSize
)) {
2539 FreePool (CachedDevicePath
);
2540 CachedDevicePath
= NULL
;
2541 Status
= gRT
->SetVariable (
2542 HD_BOOT_DEVICE_PATH_VARIABLE_NAME
,
2543 &gHdBootDevicePathVariablGuid
,
2548 ASSERT_EFI_ERROR (Status
);
2551 if (CachedDevicePath
!= NULL
) {
2552 TempNewDevicePath
= CachedDevicePath
;
2553 DeviceExist
= FALSE
;
2557 // Check every instance of the variable
2558 // First, check whether the instance contain the partition node, which is needed for distinguishing multi
2559 // partial partition boot option. Second, check whether the instance could be connected.
2561 Instance
= GetNextDevicePathInstance (&TempNewDevicePath
, &Size
);
2562 if (MatchPartitionDevicePathNode (Instance
, HardDriveDevicePath
)) {
2564 // Connect the device path instance, the device path point to hard drive media device path node
2565 // e.g. ACPI() /PCI()/ATA()/Partition()
2567 Status
= BdsLibConnectDevicePath (Instance
);
2568 if (!EFI_ERROR (Status
)) {
2574 // Come here means the first instance is not matched
2578 } while (TempNewDevicePath
!= NULL
);
2582 // Find the matched device path.
2583 // Append the file path information from the boot option and return the fully expanded device path.
2585 DevicePath
= NextDevicePathNode ((EFI_DEVICE_PATH_PROTOCOL
*) HardDriveDevicePath
);
2586 FullDevicePath
= AppendDevicePath (Instance
, DevicePath
);
2589 // Adjust the HD_BOOT_DEVICE_PATH_VARIABLE_NAME instances sequence if the matched one is not first one.
2593 // First delete the matched instance.
2595 TempNewDevicePath
= CachedDevicePath
;
2596 CachedDevicePath
= BdsLibDelPartMatchInstance (CachedDevicePath
, Instance
);
2597 FreePool (TempNewDevicePath
);
2600 // Second, append the remaining path after the matched instance
2602 TempNewDevicePath
= CachedDevicePath
;
2603 CachedDevicePath
= AppendDevicePathInstance (Instance
, CachedDevicePath
);
2604 FreePool (TempNewDevicePath
);
2606 // Save the matching Device Path so we don't need to do a connect all next time
2607 // Failure to set the variable only impacts the performance when next time expanding the short-form device path.
2609 Status
= gRT
->SetVariable (
2610 HD_BOOT_DEVICE_PATH_VARIABLE_NAME
,
2611 &gHdBootDevicePathVariablGuid
,
2612 EFI_VARIABLE_BOOTSERVICE_ACCESS
| EFI_VARIABLE_NON_VOLATILE
,
2613 GetDevicePathSize (CachedDevicePath
),
2618 FreePool (Instance
);
2619 FreePool (CachedDevicePath
);
2620 return FullDevicePath
;
2625 // If we get here we fail to find or HD_BOOT_DEVICE_PATH_VARIABLE_NAME not exist, and now we need
2626 // to search all devices in the system for a matched partition
2628 BdsLibConnectAllDriversToAllControllers ();
2629 Status
= gBS
->LocateHandleBuffer (ByProtocol
, &gEfiBlockIoProtocolGuid
, NULL
, &BlockIoHandleCount
, &BlockIoBuffer
);
2630 if (EFI_ERROR (Status
) || BlockIoHandleCount
== 0 || BlockIoBuffer
== NULL
) {
2632 // If there was an error or there are no device handles that support
2633 // the BLOCK_IO Protocol, then return.
2638 // Loop through all the device handles that support the BLOCK_IO Protocol
2640 for (Index
= 0; Index
< BlockIoHandleCount
; Index
++) {
2642 Status
= gBS
->HandleProtocol (BlockIoBuffer
[Index
], &gEfiDevicePathProtocolGuid
, (VOID
*) &BlockIoDevicePath
);
2643 if (EFI_ERROR (Status
) || BlockIoDevicePath
== NULL
) {
2647 if (MatchPartitionDevicePathNode (BlockIoDevicePath
, HardDriveDevicePath
)) {
2649 // Find the matched partition device path
2651 DevicePath
= NextDevicePathNode ((EFI_DEVICE_PATH_PROTOCOL
*) HardDriveDevicePath
);
2652 FullDevicePath
= AppendDevicePath (BlockIoDevicePath
, DevicePath
);
2655 // Save the matched partition device path in HD_BOOT_DEVICE_PATH_VARIABLE_NAME variable
2657 if (CachedDevicePath
!= NULL
) {
2659 // Save the matched partition device path as first instance of HD_BOOT_DEVICE_PATH_VARIABLE_NAME variable
2661 if (BdsLibMatchDevicePaths (CachedDevicePath
, BlockIoDevicePath
)) {
2662 TempNewDevicePath
= CachedDevicePath
;
2663 CachedDevicePath
= BdsLibDelPartMatchInstance (CachedDevicePath
, BlockIoDevicePath
);
2664 FreePool(TempNewDevicePath
);
2667 if (CachedDevicePath
!= NULL
) {
2668 TempNewDevicePath
= CachedDevicePath
;
2669 CachedDevicePath
= AppendDevicePathInstance (BlockIoDevicePath
, CachedDevicePath
);
2670 FreePool(TempNewDevicePath
);
2672 CachedDevicePath
= DuplicateDevicePath (BlockIoDevicePath
);
2676 // Here limit the device path instance number to 12, which is max number for a system support 3 IDE controller
2677 // If the user try to boot many OS in different HDs or partitions, in theory,
2678 // the HD_BOOT_DEVICE_PATH_VARIABLE_NAME variable maybe become larger and larger.
2681 ASSERT (CachedDevicePath
!= NULL
);
2682 TempNewDevicePath
= CachedDevicePath
;
2683 while (!IsDevicePathEnd (TempNewDevicePath
)) {
2684 TempNewDevicePath
= NextDevicePathNode (TempNewDevicePath
);
2686 // Parse one instance
2688 while (!IsDevicePathEndType (TempNewDevicePath
)) {
2689 TempNewDevicePath
= NextDevicePathNode (TempNewDevicePath
);
2693 // If the CachedDevicePath variable contain too much instance, only remain 12 instances.
2695 if (InstanceNum
>= 12) {
2696 SetDevicePathEndNode (TempNewDevicePath
);
2701 CachedDevicePath
= DuplicateDevicePath (BlockIoDevicePath
);
2705 // Save the matching Device Path so we don't need to do a connect all next time
2706 // Failure to set the variable only impacts the performance when next time expanding the short-form device path.
2708 Status
= gRT
->SetVariable (
2709 HD_BOOT_DEVICE_PATH_VARIABLE_NAME
,
2710 &gHdBootDevicePathVariablGuid
,
2711 EFI_VARIABLE_BOOTSERVICE_ACCESS
| EFI_VARIABLE_NON_VOLATILE
,
2712 GetDevicePathSize (CachedDevicePath
),
2720 if (CachedDevicePath
!= NULL
) {
2721 FreePool (CachedDevicePath
);
2723 if (BlockIoBuffer
!= NULL
) {
2724 FreePool (BlockIoBuffer
);
2726 return FullDevicePath
;
2730 Check whether there is a instance in BlockIoDevicePath, which contain multi device path
2731 instances, has the same partition node with HardDriveDevicePath device path
2733 @param BlockIoDevicePath Multi device path instances which need to check
2734 @param HardDriveDevicePath A device path which starts with a hard drive media
2737 @retval TRUE There is a matched device path instance.
2738 @retval FALSE There is no matched device path instance.
2743 MatchPartitionDevicePathNode (
2744 IN EFI_DEVICE_PATH_PROTOCOL
*BlockIoDevicePath
,
2745 IN HARDDRIVE_DEVICE_PATH
*HardDriveDevicePath
2748 HARDDRIVE_DEVICE_PATH
*TmpHdPath
;
2749 EFI_DEVICE_PATH_PROTOCOL
*DevicePath
;
2751 EFI_DEVICE_PATH_PROTOCOL
*BlockIoHdDevicePathNode
;
2753 if ((BlockIoDevicePath
== NULL
) || (HardDriveDevicePath
== NULL
)) {
2758 // Make PreviousDevicePath == the device path node before the end node
2760 DevicePath
= BlockIoDevicePath
;
2761 BlockIoHdDevicePathNode
= NULL
;
2764 // find the partition device path node
2766 while (!IsDevicePathEnd (DevicePath
)) {
2767 if ((DevicePathType (DevicePath
) == MEDIA_DEVICE_PATH
) &&
2768 (DevicePathSubType (DevicePath
) == MEDIA_HARDDRIVE_DP
)
2770 BlockIoHdDevicePathNode
= DevicePath
;
2774 DevicePath
= NextDevicePathNode (DevicePath
);
2777 if (BlockIoHdDevicePathNode
== NULL
) {
2781 // See if the harddrive device path in blockio matches the orig Hard Drive Node
2783 TmpHdPath
= (HARDDRIVE_DEVICE_PATH
*) BlockIoHdDevicePathNode
;
2787 // Check for the match
2789 if ((TmpHdPath
->MBRType
== HardDriveDevicePath
->MBRType
) &&
2790 (TmpHdPath
->SignatureType
== HardDriveDevicePath
->SignatureType
)) {
2791 switch (TmpHdPath
->SignatureType
) {
2792 case SIGNATURE_TYPE_GUID
:
2793 Match
= CompareGuid ((EFI_GUID
*)TmpHdPath
->Signature
, (EFI_GUID
*)HardDriveDevicePath
->Signature
);
2795 case SIGNATURE_TYPE_MBR
:
2796 Match
= (BOOLEAN
)(*((UINT32
*)(&(TmpHdPath
->Signature
[0]))) == ReadUnaligned32((UINT32
*)(&(HardDriveDevicePath
->Signature
[0]))));
2808 Delete the boot option associated with the handle passed in.
2810 @param Handle The handle which present the device path to create
2813 @retval EFI_SUCCESS Delete the boot option success
2814 @retval EFI_NOT_FOUND If the Device Path is not found in the system
2815 @retval EFI_OUT_OF_RESOURCES Lack of memory resource
2816 @retval Other Error return value from SetVariable()
2820 BdsLibDeleteOptionFromHandle (
2821 IN EFI_HANDLE Handle
2825 UINT8
*BootOptionVar
;
2826 UINTN BootOrderSize
;
2827 UINTN BootOptionSize
;
2830 UINT16 BootOption
[BOOT_OPTION_MAX_CHAR
];
2831 UINTN DevicePathSize
;
2832 UINTN OptionDevicePathSize
;
2833 EFI_DEVICE_PATH_PROTOCOL
*DevicePath
;
2834 EFI_DEVICE_PATH_PROTOCOL
*OptionDevicePath
;
2837 Status
= EFI_SUCCESS
;
2842 // Check "BootOrder" variable, if no, means there is no any boot order.
2844 BootOrder
= BdsLibGetVariableAndSize (
2846 &gEfiGlobalVariableGuid
,
2849 if (BootOrder
== NULL
) {
2850 return EFI_NOT_FOUND
;
2854 // Convert device handle to device path protocol instance
2856 DevicePath
= DevicePathFromHandle (Handle
);
2857 if (DevicePath
== NULL
) {
2858 return EFI_NOT_FOUND
;
2860 DevicePathSize
= GetDevicePathSize (DevicePath
);
2863 // Loop all boot order variable and find the matching device path
2866 while (Index
< BootOrderSize
/ sizeof (UINT16
)) {
2867 UnicodeSPrint (BootOption
, sizeof (BootOption
), L
"Boot%04x", BootOrder
[Index
]);
2868 BootOptionVar
= BdsLibGetVariableAndSize (
2870 &gEfiGlobalVariableGuid
,
2874 if (BootOptionVar
== NULL
) {
2875 FreePool (BootOrder
);
2876 return EFI_OUT_OF_RESOURCES
;
2879 if (!ValidateOption(BootOptionVar
, BootOptionSize
)) {
2880 BdsDeleteBootOption (BootOrder
[Index
], BootOrder
, &BootOrderSize
);
2881 FreePool (BootOptionVar
);
2886 TempPtr
= BootOptionVar
;
2887 TempPtr
+= sizeof (UINT32
) + sizeof (UINT16
);
2888 TempPtr
+= StrSize ((CHAR16
*) TempPtr
);
2889 OptionDevicePath
= (EFI_DEVICE_PATH_PROTOCOL
*) TempPtr
;
2890 OptionDevicePathSize
= GetDevicePathSize (OptionDevicePath
);
2893 // Check whether the device path match
2895 if ((OptionDevicePathSize
== DevicePathSize
) &&
2896 (CompareMem (DevicePath
, OptionDevicePath
, DevicePathSize
) == 0)) {
2897 BdsDeleteBootOption (BootOrder
[Index
], BootOrder
, &BootOrderSize
);
2898 FreePool (BootOptionVar
);
2902 FreePool (BootOptionVar
);
2907 // Adjust number of boot option for "BootOrder" variable.
2909 Status
= gRT
->SetVariable (
2911 &gEfiGlobalVariableGuid
,
2912 EFI_VARIABLE_BOOTSERVICE_ACCESS
| EFI_VARIABLE_RUNTIME_ACCESS
| EFI_VARIABLE_NON_VOLATILE
,
2917 // Shrinking variable with existing variable implementation shouldn't fail.
2919 ASSERT_EFI_ERROR (Status
);
2921 FreePool (BootOrder
);
2928 Delete all invalid EFI boot options.
2930 @retval EFI_SUCCESS Delete all invalid boot option success
2931 @retval EFI_NOT_FOUND Variable "BootOrder" is not found
2932 @retval EFI_OUT_OF_RESOURCES Lack of memory resource
2933 @retval Other Error return value from SetVariable()
2937 BdsDeleteAllInvalidEfiBootOption (
2942 UINT8
*BootOptionVar
;
2943 UINTN BootOrderSize
;
2944 UINTN BootOptionSize
;
2948 UINT16 BootOption
[BOOT_OPTION_MAX_CHAR
];
2949 EFI_DEVICE_PATH_PROTOCOL
*OptionDevicePath
;
2951 CHAR16
*Description
;
2954 Status
= EFI_SUCCESS
;
2957 OptionDevicePath
= NULL
;
2962 // Check "BootOrder" variable firstly, this variable hold the number of boot options
2964 BootOrder
= BdsLibGetVariableAndSize (
2966 &gEfiGlobalVariableGuid
,
2969 if (NULL
== BootOrder
) {
2970 return EFI_NOT_FOUND
;
2974 while (Index
< BootOrderSize
/ sizeof (UINT16
)) {
2975 UnicodeSPrint (BootOption
, sizeof (BootOption
), L
"Boot%04x", BootOrder
[Index
]);
2976 BootOptionVar
= BdsLibGetVariableAndSize (
2978 &gEfiGlobalVariableGuid
,
2981 if (NULL
== BootOptionVar
) {
2982 FreePool (BootOrder
);
2983 return EFI_OUT_OF_RESOURCES
;
2986 if (!ValidateOption(BootOptionVar
, BootOptionSize
)) {
2989 TempPtr
= BootOptionVar
;
2990 TempPtr
+= sizeof (UINT32
) + sizeof (UINT16
);
2991 Description
= (CHAR16
*) TempPtr
;
2992 TempPtr
+= StrSize ((CHAR16
*) TempPtr
);
2993 OptionDevicePath
= (EFI_DEVICE_PATH_PROTOCOL
*) TempPtr
;
2996 // Skip legacy boot option (BBS boot device)
2998 if ((DevicePathType (OptionDevicePath
) == BBS_DEVICE_PATH
) &&
2999 (DevicePathSubType (OptionDevicePath
) == BBS_BBS_DP
)) {
3000 FreePool (BootOptionVar
);
3006 if (Corrupted
|| !BdsLibIsValidEFIBootOptDevicePathExt (OptionDevicePath
, FALSE
, Description
)) {
3008 // Delete this invalid boot option "Boot####"
3010 Status
= gRT
->SetVariable (
3012 &gEfiGlobalVariableGuid
,
3013 EFI_VARIABLE_BOOTSERVICE_ACCESS
| EFI_VARIABLE_RUNTIME_ACCESS
| EFI_VARIABLE_NON_VOLATILE
,
3018 // Deleting variable with current variable implementation shouldn't fail.
3020 ASSERT_EFI_ERROR (Status
);
3022 // Mark this boot option in boot order as deleted
3024 BootOrder
[Index
] = 0xffff;
3028 FreePool (BootOptionVar
);
3033 // Adjust boot order array
3036 for (Index
= 0; Index
< BootOrderSize
/ sizeof (UINT16
); Index
++) {
3037 if (BootOrder
[Index
] != 0xffff) {
3038 BootOrder
[Index2
] = BootOrder
[Index
];
3042 Status
= gRT
->SetVariable (
3044 &gEfiGlobalVariableGuid
,
3045 EFI_VARIABLE_BOOTSERVICE_ACCESS
| EFI_VARIABLE_RUNTIME_ACCESS
| EFI_VARIABLE_NON_VOLATILE
,
3046 Index2
* sizeof (UINT16
),
3050 // Shrinking variable with current variable implementation shouldn't fail.
3052 ASSERT_EFI_ERROR (Status
);
3054 FreePool (BootOrder
);
3061 For EFI boot option, BDS separate them as six types:
3062 1. Network - The boot option points to the SimpleNetworkProtocol device.
3063 Bds will try to automatically create this type boot option when enumerate.
3064 2. Shell - The boot option points to internal flash shell.
3065 Bds will try to automatically create this type boot option when enumerate.
3066 3. Removable BlockIo - The boot option only points to the removable media
3067 device, like USB flash disk, DVD, Floppy etc.
3068 These device should contain a *removable* blockIo
3069 protocol in their device handle.
3070 Bds will try to automatically create this type boot option
3072 4. Fixed BlockIo - The boot option only points to a Fixed blockIo device,
3074 These device should contain a *fixed* blockIo
3075 protocol in their device handle.
3076 BDS will skip fixed blockIo devices, and NOT
3077 automatically create boot option for them. But BDS
3078 will help to delete those fixed blockIo boot option,
3079 whose description rule conflict with other auto-created
3081 5. Non-BlockIo Simplefile - The boot option points to a device whose handle
3082 has SimpleFileSystem Protocol, but has no blockio
3083 protocol. These devices do not offer blockIo
3084 protocol, but BDS still can get the
3085 \EFI\BOOT\boot{machinename}.EFI by SimpleFileSystem
3087 6. File - The boot option points to a file. These boot options are usually
3088 created by user manually or OS loader. BDS will not delete or modify
3091 This function will enumerate all possible boot device in the system, and
3092 automatically create boot options for Network, Shell, Removable BlockIo,
3093 and Non-BlockIo Simplefile devices.
3094 It will only execute once of every boot.
3096 @param BdsBootOptionList The header of the link list which indexed all
3097 current boot options
3099 @retval EFI_SUCCESS Finished all the boot device enumerate and create
3100 the boot option base on that boot device
3102 @retval EFI_OUT_OF_RESOURCES Failed to enumerate the boot device and create the boot option list
3106 BdsLibEnumerateAllBootOption (
3107 IN OUT LIST_ENTRY
*BdsBootOptionList
3111 UINT16 FloppyNumber
;
3112 UINT16 HarddriveNumber
;
3117 UINT16 NonBlockNumber
;
3118 UINTN NumberBlockIoHandles
;
3119 EFI_HANDLE
*BlockIoHandles
;
3120 EFI_BLOCK_IO_PROTOCOL
*BlkIo
;
3121 BOOLEAN Removable
[2];
3122 UINTN RemovableIndex
;
3124 UINTN NumOfLoadFileHandles
;
3125 EFI_HANDLE
*LoadFileHandles
;
3126 UINTN FvHandleCount
;
3127 EFI_HANDLE
*FvHandleBuffer
;
3128 EFI_FV_FILETYPE Type
;
3130 EFI_FV_FILE_ATTRIBUTES Attributes
;
3131 UINT32 AuthenticationStatus
;
3132 EFI_FIRMWARE_VOLUME2_PROTOCOL
*Fv
;
3133 EFI_DEVICE_PATH_PROTOCOL
*DevicePath
;
3134 UINTN DevicePathType
;
3136 EFI_HANDLE
*FileSystemHandles
;
3137 UINTN NumberFileSystemHandles
;
3139 EFI_IMAGE_DOS_HEADER DosHeader
;
3142 EFI_IMAGE_OPTIONAL_HEADER_UNION HdrData
;
3143 EFI_IMAGE_OPTIONAL_HEADER_PTR_UNION Hdr
;
3146 HarddriveNumber
= 0;
3153 ZeroMem (Buffer
, sizeof (Buffer
));
3156 // If the boot device enumerate happened, just get the boot
3157 // device from the boot order variable
3159 if (mEnumBootDevice
) {
3160 GetVariable2 (LAST_ENUM_LANGUAGE_VARIABLE_NAME
, &gLastEnumLangGuid
, (VOID
**)&LastLang
, NULL
);
3161 GetEfiGlobalVariable2 (L
"PlatformLang", (VOID
**)&PlatLang
, NULL
);
3162 ASSERT (PlatLang
!= NULL
);
3163 if ((LastLang
!= NULL
) && (AsciiStrCmp (LastLang
, PlatLang
) == 0)) {
3164 Status
= BdsLibBuildOptionFromVar (BdsBootOptionList
, L
"BootOrder");
3165 FreePool (LastLang
);
3166 FreePool (PlatLang
);
3169 Status
= gRT
->SetVariable (
3170 LAST_ENUM_LANGUAGE_VARIABLE_NAME
,
3172 EFI_VARIABLE_BOOTSERVICE_ACCESS
| EFI_VARIABLE_NON_VOLATILE
,
3173 AsciiStrSize (PlatLang
),
3177 // Failure to set the variable only impacts the performance next time enumerating the boot options.
3180 if (LastLang
!= NULL
) {
3181 FreePool (LastLang
);
3183 FreePool (PlatLang
);
3188 // Notes: this dirty code is to get the legacy boot option from the
3189 // BBS table and create to variable as the EFI boot option, it should
3190 // be removed after the CSM can provide legacy boot option directly
3192 REFRESH_LEGACY_BOOT_OPTIONS
;
3195 // Delete invalid boot option
3197 BdsDeleteAllInvalidEfiBootOption ();
3200 // Parse removable media followed by fixed media.
3201 // The Removable[] array is used by the for-loop below to create removable media boot options
3202 // at first, and then to create fixed media boot options.
3204 Removable
[0] = FALSE
;
3205 Removable
[1] = TRUE
;
3207 gBS
->LocateHandleBuffer (
3209 &gEfiBlockIoProtocolGuid
,
3211 &NumberBlockIoHandles
,
3215 for (RemovableIndex
= 0; RemovableIndex
< 2; RemovableIndex
++) {
3216 for (Index
= 0; Index
< NumberBlockIoHandles
; Index
++) {
3217 Status
= gBS
->HandleProtocol (
3218 BlockIoHandles
[Index
],
3219 &gEfiBlockIoProtocolGuid
,
3223 // skip the logical partition
3225 if (EFI_ERROR (Status
) || BlkIo
->Media
->LogicalPartition
) {
3230 // firstly fixed block io then the removable block io
3232 if (BlkIo
->Media
->RemovableMedia
== Removable
[RemovableIndex
]) {
3235 DevicePath
= DevicePathFromHandle (BlockIoHandles
[Index
]);
3236 DevicePathType
= BdsGetBootTypeFromDevicePath (DevicePath
);
3238 switch (DevicePathType
) {
3239 case BDS_EFI_ACPI_FLOPPY_BOOT
:
3240 if (FloppyNumber
!= 0) {
3241 UnicodeSPrint (Buffer
, sizeof (Buffer
), L
"%s %d", BdsLibGetStringById (STRING_TOKEN (STR_DESCRIPTION_FLOPPY
)), FloppyNumber
);
3243 UnicodeSPrint (Buffer
, sizeof (Buffer
), L
"%s", BdsLibGetStringById (STRING_TOKEN (STR_DESCRIPTION_FLOPPY
)));
3245 BdsLibBuildOptionFromHandle (BlockIoHandles
[Index
], BdsBootOptionList
, Buffer
);
3250 // Assume a removable SATA device should be the DVD/CD device, a fixed SATA device should be the Hard Drive device.
3252 case BDS_EFI_MESSAGE_ATAPI_BOOT
:
3253 case BDS_EFI_MESSAGE_SATA_BOOT
:
3254 if (BlkIo
->Media
->RemovableMedia
) {
3255 if (CdromNumber
!= 0) {
3256 UnicodeSPrint (Buffer
, sizeof (Buffer
), L
"%s %d", BdsLibGetStringById (STRING_TOKEN (STR_DESCRIPTION_CD_DVD
)), CdromNumber
);
3258 UnicodeSPrint (Buffer
, sizeof (Buffer
), L
"%s", BdsLibGetStringById (STRING_TOKEN (STR_DESCRIPTION_CD_DVD
)));
3262 if (HarddriveNumber
!= 0) {
3263 UnicodeSPrint (Buffer
, sizeof (Buffer
), L
"%s %d", BdsLibGetStringById (STRING_TOKEN (STR_DESCRIPTION_HARDDRIVE
)), HarddriveNumber
);
3265 UnicodeSPrint (Buffer
, sizeof (Buffer
), L
"%s", BdsLibGetStringById (STRING_TOKEN (STR_DESCRIPTION_HARDDRIVE
)));
3269 DEBUG ((DEBUG_INFO
| DEBUG_LOAD
, "Buffer: %S\n", Buffer
));
3270 BdsLibBuildOptionFromHandle (BlockIoHandles
[Index
], BdsBootOptionList
, Buffer
);
3273 case BDS_EFI_MESSAGE_USB_DEVICE_BOOT
:
3274 if (UsbNumber
!= 0) {
3275 UnicodeSPrint (Buffer
, sizeof (Buffer
), L
"%s %d", BdsLibGetStringById (STRING_TOKEN (STR_DESCRIPTION_USB
)), UsbNumber
);
3277 UnicodeSPrint (Buffer
, sizeof (Buffer
), L
"%s", BdsLibGetStringById (STRING_TOKEN (STR_DESCRIPTION_USB
)));
3279 BdsLibBuildOptionFromHandle (BlockIoHandles
[Index
], BdsBootOptionList
, Buffer
);
3283 case BDS_EFI_MESSAGE_SCSI_BOOT
:
3284 if (ScsiNumber
!= 0) {
3285 UnicodeSPrint (Buffer
, sizeof (Buffer
), L
"%s %d", BdsLibGetStringById (STRING_TOKEN (STR_DESCRIPTION_SCSI
)), ScsiNumber
);
3287 UnicodeSPrint (Buffer
, sizeof (Buffer
), L
"%s", BdsLibGetStringById (STRING_TOKEN (STR_DESCRIPTION_SCSI
)));
3289 BdsLibBuildOptionFromHandle (BlockIoHandles
[Index
], BdsBootOptionList
, Buffer
);
3293 case BDS_EFI_MESSAGE_MISC_BOOT
:
3295 if (MiscNumber
!= 0) {
3296 UnicodeSPrint (Buffer
, sizeof (Buffer
), L
"%s %d", BdsLibGetStringById (STRING_TOKEN (STR_DESCRIPTION_MISC
)), MiscNumber
);
3298 UnicodeSPrint (Buffer
, sizeof (Buffer
), L
"%s", BdsLibGetStringById (STRING_TOKEN (STR_DESCRIPTION_MISC
)));
3300 BdsLibBuildOptionFromHandle (BlockIoHandles
[Index
], BdsBootOptionList
, Buffer
);
3307 if (NumberBlockIoHandles
!= 0) {
3308 FreePool (BlockIoHandles
);
3312 // If there is simple file protocol which does not consume block Io protocol, create a boot option for it here.
3315 gBS
->LocateHandleBuffer (
3317 &gEfiSimpleFileSystemProtocolGuid
,
3319 &NumberFileSystemHandles
,
3322 for (Index
= 0; Index
< NumberFileSystemHandles
; Index
++) {
3323 Status
= gBS
->HandleProtocol (
3324 FileSystemHandles
[Index
],
3325 &gEfiBlockIoProtocolGuid
,
3328 if (!EFI_ERROR (Status
)) {
3330 // Skip if the file system handle supports a BlkIo protocol,
3336 // Do the removable Media thing. \EFI\BOOT\boot{machinename}.EFI
3337 // machinename is ia32, ia64, x64, ...
3339 Hdr
.Union
= &HdrData
;
3341 Status
= BdsLibGetImageHeader (
3342 FileSystemHandles
[Index
],
3343 EFI_REMOVABLE_MEDIA_FILE_NAME
,
3347 if (!EFI_ERROR (Status
) &&
3348 EFI_IMAGE_MACHINE_TYPE_SUPPORTED (Hdr
.Pe32
->FileHeader
.Machine
) &&
3349 Hdr
.Pe32
->OptionalHeader
.Subsystem
== EFI_IMAGE_SUBSYSTEM_EFI_APPLICATION
) {
3355 // No such file or the file is not a EFI application, delete this boot option
3357 BdsLibDeleteOptionFromHandle (FileSystemHandles
[Index
]);
3359 if (NonBlockNumber
!= 0) {
3360 UnicodeSPrint (Buffer
, sizeof (Buffer
), L
"%s %d", BdsLibGetStringById (STRING_TOKEN (STR_DESCRIPTION_NON_BLOCK
)), NonBlockNumber
);
3362 UnicodeSPrint (Buffer
, sizeof (Buffer
), L
"%s", BdsLibGetStringById (STRING_TOKEN (STR_DESCRIPTION_NON_BLOCK
)));
3364 BdsLibBuildOptionFromHandle (FileSystemHandles
[Index
], BdsBootOptionList
, Buffer
);
3369 if (NumberFileSystemHandles
!= 0) {
3370 FreePool (FileSystemHandles
);
3374 // Parse Network Boot Device
3376 NumOfLoadFileHandles
= 0;
3378 // Search Load File protocol for PXE boot option.
3380 gBS
->LocateHandleBuffer (
3382 &gEfiLoadFileProtocolGuid
,
3384 &NumOfLoadFileHandles
,
3388 for (Index
= 0; Index
< NumOfLoadFileHandles
; Index
++) {
3390 UnicodeSPrint (Buffer
, sizeof (Buffer
), L
"%s %d", BdsLibGetStringById (STRING_TOKEN (STR_DESCRIPTION_NETWORK
)), Index
);
3392 UnicodeSPrint (Buffer
, sizeof (Buffer
), L
"%s", BdsLibGetStringById (STRING_TOKEN (STR_DESCRIPTION_NETWORK
)));
3394 BdsLibBuildOptionFromHandle (LoadFileHandles
[Index
], BdsBootOptionList
, Buffer
);
3397 if (NumOfLoadFileHandles
!= 0) {
3398 FreePool (LoadFileHandles
);
3402 // Check if we have on flash shell
3404 gBS
->LocateHandleBuffer (
3406 &gEfiFirmwareVolume2ProtocolGuid
,
3411 for (Index
= 0; Index
< FvHandleCount
; Index
++) {
3412 gBS
->HandleProtocol (
3413 FvHandleBuffer
[Index
],
3414 &gEfiFirmwareVolume2ProtocolGuid
,
3418 Status
= Fv
->ReadFile (
3420 PcdGetPtr(PcdShellFile
),
3425 &AuthenticationStatus
3427 if (EFI_ERROR (Status
)) {
3429 // Skip if no shell file in the FV
3434 // Build the shell boot option
3436 BdsLibBuildOptionFromShell (FvHandleBuffer
[Index
], BdsBootOptionList
);
3439 if (FvHandleCount
!= 0) {
3440 FreePool (FvHandleBuffer
);
3443 // Make sure every boot only have one time
3444 // boot device enumerate
3446 Status
= BdsLibBuildOptionFromVar (BdsBootOptionList
, L
"BootOrder");
3447 mEnumBootDevice
= TRUE
;
3453 Build the boot option with the handle parsed in
3455 @param Handle The handle which present the device path to create
3457 @param BdsBootOptionList The header of the link list which indexed all
3458 current boot options
3459 @param String The description of the boot option.
3464 BdsLibBuildOptionFromHandle (
3465 IN EFI_HANDLE Handle
,
3466 IN LIST_ENTRY
*BdsBootOptionList
,
3470 EFI_DEVICE_PATH_PROTOCOL
*DevicePath
;
3472 DevicePath
= DevicePathFromHandle (Handle
);
3475 // Create and register new boot option
3477 BdsLibRegisterNewOption (BdsBootOptionList
, DevicePath
, String
, L
"BootOrder");
3482 Build the on flash shell boot option with the handle parsed in.
3484 @param Handle The handle which present the device path to create
3485 on flash shell boot option
3486 @param BdsBootOptionList The header of the link list which indexed all
3487 current boot options
3492 BdsLibBuildOptionFromShell (
3493 IN EFI_HANDLE Handle
,
3494 IN OUT LIST_ENTRY
*BdsBootOptionList
3497 EFI_DEVICE_PATH_PROTOCOL
*DevicePath
;
3498 MEDIA_FW_VOL_FILEPATH_DEVICE_PATH ShellNode
;
3500 DevicePath
= DevicePathFromHandle (Handle
);
3503 // Build the shell device path
3505 EfiInitializeFwVolDevicepathNode (&ShellNode
, PcdGetPtr(PcdShellFile
));
3507 DevicePath
= AppendDevicePathNode (DevicePath
, (EFI_DEVICE_PATH_PROTOCOL
*) &ShellNode
);
3510 // Create and register the shell boot option
3512 BdsLibRegisterNewOption (BdsBootOptionList
, DevicePath
, L
"EFI Internal Shell", L
"BootOrder");
3517 Boot from the UEFI spec defined "BootNext" variable.
3530 BDS_COMMON_OPTION
*BootOption
;
3531 LIST_ENTRY TempList
;
3536 // Init the boot option name buffer and temp link list
3538 InitializeListHead (&TempList
);
3539 ZeroMem (Buffer
, sizeof (Buffer
));
3541 BootNext
= BdsLibGetVariableAndSize (
3543 &gEfiGlobalVariableGuid
,
3548 // Clear the boot next variable first
3550 if (BootNext
!= NULL
) {
3551 Status
= gRT
->SetVariable (
3553 &gEfiGlobalVariableGuid
,
3554 EFI_VARIABLE_BOOTSERVICE_ACCESS
| EFI_VARIABLE_RUNTIME_ACCESS
| EFI_VARIABLE_NON_VOLATILE
,
3559 // Deleting variable with current variable implementation shouldn't fail.
3561 ASSERT_EFI_ERROR (Status
);
3564 // Start to build the boot option and try to boot
3566 UnicodeSPrint (Buffer
, sizeof (Buffer
), L
"Boot%04x", *BootNext
);
3567 BootOption
= BdsLibVariableToOption (&TempList
, Buffer
);
3568 ASSERT (BootOption
!= NULL
);
3569 BdsLibConnectDevicePath (BootOption
->DevicePath
);
3570 BdsLibBootViaBootOption (BootOption
, BootOption
->DevicePath
, &ExitDataSize
, &ExitData
);
3576 Return the bootable media handle.
3577 First, check the device is connected
3578 Second, check whether the device path point to a device which support SimpleFileSystemProtocol,
3579 Third, detect the the default boot file in the Media, and return the removable Media handle.
3581 @param DevicePath Device Path to a bootable device
3583 @return The bootable media handle. If the media on the DevicePath is not bootable, NULL will return.
3588 BdsLibGetBootableHandle (
3589 IN EFI_DEVICE_PATH_PROTOCOL
*DevicePath
3594 EFI_DEVICE_PATH_PROTOCOL
*UpdatedDevicePath
;
3595 EFI_DEVICE_PATH_PROTOCOL
*DupDevicePath
;
3597 EFI_BLOCK_IO_PROTOCOL
*BlockIo
;
3599 EFI_DEVICE_PATH_PROTOCOL
*TempDevicePath
;
3602 EFI_HANDLE ReturnHandle
;
3603 EFI_HANDLE
*SimpleFileSystemHandles
;
3605 UINTN NumberSimpleFileSystemHandles
;
3607 EFI_IMAGE_DOS_HEADER DosHeader
;
3608 EFI_IMAGE_OPTIONAL_HEADER_UNION HdrData
;
3609 EFI_IMAGE_OPTIONAL_HEADER_PTR_UNION Hdr
;
3611 UpdatedDevicePath
= DevicePath
;
3614 // Enter to critical section to protect the acquired BlockIo instance
3615 // from getting released due to the USB mass storage hotplug event
3617 OldTpl
= gBS
->RaiseTPL (TPL_CALLBACK
);
3620 // Check whether the device is connected
3622 Status
= gBS
->LocateDevicePath (&gEfiBlockIoProtocolGuid
, &UpdatedDevicePath
, &Handle
);
3623 if (EFI_ERROR (Status
)) {
3625 // Skip the case that the boot option point to a simple file protocol which does not consume block Io protocol,
3627 Status
= gBS
->LocateDevicePath (&gEfiSimpleFileSystemProtocolGuid
, &UpdatedDevicePath
, &Handle
);
3628 if (EFI_ERROR (Status
)) {
3630 // Fail to find the proper BlockIo and simple file protocol, maybe because device not present, we need to connect it firstly
3632 UpdatedDevicePath
= DevicePath
;
3633 Status
= gBS
->LocateDevicePath (&gEfiDevicePathProtocolGuid
, &UpdatedDevicePath
, &Handle
);
3634 gBS
->ConnectController (Handle
, NULL
, NULL
, TRUE
);
3638 // For removable device boot option, its contained device path only point to the removable device handle,
3639 // should make sure all its children handles (its child partion or media handles) are created and connected.
3641 gBS
->ConnectController (Handle
, NULL
, NULL
, TRUE
);
3643 // Get BlockIo protocol and check removable attribute
3645 Status
= gBS
->HandleProtocol (Handle
, &gEfiBlockIoProtocolGuid
, (VOID
**)&BlockIo
);
3646 ASSERT_EFI_ERROR (Status
);
3649 // Issue a dummy read to the device to check for media change.
3650 // When the removable media is changed, any Block IO read/write will
3651 // cause the BlockIo protocol be reinstalled and EFI_MEDIA_CHANGED is
3652 // returned. After the Block IO protocol is reinstalled, subsequent
3653 // Block IO read/write will success.
3655 Buffer
= AllocatePool (BlockIo
->Media
->BlockSize
);
3656 if (Buffer
!= NULL
) {
3657 BlockIo
->ReadBlocks (
3659 BlockIo
->Media
->MediaId
,
3661 BlockIo
->Media
->BlockSize
,
3669 // Detect the the default boot file from removable Media
3673 // 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
3674 // Try to locate the USB node device path first, if fail then use its previous PCI node to search
3676 DupDevicePath
= DuplicateDevicePath (DevicePath
);
3677 ASSERT (DupDevicePath
!= NULL
);
3679 UpdatedDevicePath
= DupDevicePath
;
3680 Status
= gBS
->LocateDevicePath (&gEfiDevicePathProtocolGuid
, &UpdatedDevicePath
, &Handle
);
3682 // 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
3683 // Acpi()/Pci()/Usb() --> Acpi()/Pci()
3685 if ((DevicePathType (UpdatedDevicePath
) == MESSAGING_DEVICE_PATH
) &&
3686 (DevicePathSubType (UpdatedDevicePath
) == MSG_USB_DP
)) {
3688 // Remove the usb node, let the device path only point to PCI node
3690 SetDevicePathEndNode (UpdatedDevicePath
);
3691 UpdatedDevicePath
= DupDevicePath
;
3693 UpdatedDevicePath
= DevicePath
;
3697 // Get the device path size of boot option
3699 Size
= GetDevicePathSize(UpdatedDevicePath
) - sizeof (EFI_DEVICE_PATH_PROTOCOL
); // minus the end node
3700 ReturnHandle
= NULL
;
3701 gBS
->LocateHandleBuffer (
3703 &gEfiSimpleFileSystemProtocolGuid
,
3705 &NumberSimpleFileSystemHandles
,
3706 &SimpleFileSystemHandles
3708 for (Index
= 0; Index
< NumberSimpleFileSystemHandles
; Index
++) {
3710 // Get the device path size of SimpleFileSystem handle
3712 TempDevicePath
= DevicePathFromHandle (SimpleFileSystemHandles
[Index
]);
3713 TempSize
= GetDevicePathSize (TempDevicePath
)- sizeof (EFI_DEVICE_PATH_PROTOCOL
); // minus the end node
3715 // Check whether the device path of boot option is part of the SimpleFileSystem handle's device path
3717 if (Size
<= TempSize
&& CompareMem (TempDevicePath
, UpdatedDevicePath
, Size
)==0) {
3719 // Load the default boot file \EFI\BOOT\boot{machinename}.EFI from removable Media
3720 // machinename is ia32, ia64, x64, ...
3722 Hdr
.Union
= &HdrData
;
3723 Status
= BdsLibGetImageHeader (
3724 SimpleFileSystemHandles
[Index
],
3725 EFI_REMOVABLE_MEDIA_FILE_NAME
,
3729 if (!EFI_ERROR (Status
) &&
3730 EFI_IMAGE_MACHINE_TYPE_SUPPORTED (Hdr
.Pe32
->FileHeader
.Machine
) &&
3731 Hdr
.Pe32
->OptionalHeader
.Subsystem
== EFI_IMAGE_SUBSYSTEM_EFI_APPLICATION
) {
3732 ReturnHandle
= SimpleFileSystemHandles
[Index
];
3738 FreePool(DupDevicePath
);
3740 if (SimpleFileSystemHandles
!= NULL
) {
3741 FreePool(SimpleFileSystemHandles
);
3744 gBS
->RestoreTPL (OldTpl
);
3746 return ReturnHandle
;
3750 Check to see if the network cable is plugged in. If the DevicePath is not
3751 connected it will be connected.
3753 @param DevicePath Device Path to check
3755 @retval TRUE DevicePath points to an Network that is connected
3756 @retval FALSE DevicePath does not point to a bootable network
3760 BdsLibNetworkBootWithMediaPresent (
3761 IN EFI_DEVICE_PATH_PROTOCOL
*DevicePath
3765 EFI_DEVICE_PATH_PROTOCOL
*UpdatedDevicePath
;
3767 EFI_SIMPLE_NETWORK_PROTOCOL
*Snp
;
3768 BOOLEAN MediaPresent
;
3769 UINT32 InterruptStatus
;
3771 MediaPresent
= FALSE
;
3773 UpdatedDevicePath
= DevicePath
;
3775 // Locate Load File Protocol for PXE boot option first
3777 Status
= gBS
->LocateDevicePath (&gEfiLoadFileProtocolGuid
, &UpdatedDevicePath
, &Handle
);
3778 if (EFI_ERROR (Status
)) {
3780 // Device not present so see if we need to connect it
3782 Status
= BdsLibConnectDevicePath (DevicePath
);
3783 if (!EFI_ERROR (Status
)) {
3785 // This one should work after we did the connect
3787 Status
= gBS
->LocateDevicePath (&gEfiLoadFileProtocolGuid
, &UpdatedDevicePath
, &Handle
);
3791 if (!EFI_ERROR (Status
)) {
3792 Status
= gBS
->HandleProtocol (Handle
, &gEfiSimpleNetworkProtocolGuid
, (VOID
**)&Snp
);
3793 if (EFI_ERROR (Status
)) {
3795 // Failed to open SNP from this handle, try to get SNP from parent handle
3797 UpdatedDevicePath
= DevicePathFromHandle (Handle
);
3798 if (UpdatedDevicePath
!= NULL
) {
3799 Status
= gBS
->LocateDevicePath (&gEfiSimpleNetworkProtocolGuid
, &UpdatedDevicePath
, &Handle
);
3800 if (!EFI_ERROR (Status
)) {
3802 // SNP handle found, get SNP from it
3804 Status
= gBS
->HandleProtocol (Handle
, &gEfiSimpleNetworkProtocolGuid
, (VOID
**) &Snp
);
3809 if (!EFI_ERROR (Status
)) {
3810 if (Snp
->Mode
->MediaPresentSupported
) {
3811 if (Snp
->Mode
->State
== EfiSimpleNetworkInitialized
) {
3813 // Invoke Snp->GetStatus() to refresh the media status
3815 Snp
->GetStatus (Snp
, &InterruptStatus
, NULL
);
3818 // In case some one else is using the SNP check to see if it's connected
3820 MediaPresent
= Snp
->Mode
->MediaPresent
;
3823 // No one is using SNP so we need to Start and Initialize so
3824 // MediaPresent will be valid.
3826 Status
= Snp
->Start (Snp
);
3827 if (!EFI_ERROR (Status
)) {
3828 Status
= Snp
->Initialize (Snp
, 0, 0);
3829 if (!EFI_ERROR (Status
)) {
3830 MediaPresent
= Snp
->Mode
->MediaPresent
;
3831 Snp
->Shutdown (Snp
);
3837 MediaPresent
= TRUE
;
3842 return MediaPresent
;
3846 For a bootable Device path, return its boot type.
3848 @param DevicePath The bootable device Path to check
3850 @retval BDS_EFI_MEDIA_HD_BOOT If given device path contains MEDIA_DEVICE_PATH type device path node
3851 which subtype is MEDIA_HARDDRIVE_DP
3852 @retval BDS_EFI_MEDIA_CDROM_BOOT If given device path contains MEDIA_DEVICE_PATH type device path node
3853 which subtype is MEDIA_CDROM_DP
3854 @retval BDS_EFI_ACPI_FLOPPY_BOOT If given device path contains ACPI_DEVICE_PATH type device path node
3855 which HID is floppy device.
3856 @retval BDS_EFI_MESSAGE_ATAPI_BOOT If given device path contains MESSAGING_DEVICE_PATH type device path node
3857 and its last device path node's subtype is MSG_ATAPI_DP.
3858 @retval BDS_EFI_MESSAGE_SCSI_BOOT If given device path contains MESSAGING_DEVICE_PATH type device path node
3859 and its last device path node's subtype is MSG_SCSI_DP.
3860 @retval BDS_EFI_MESSAGE_USB_DEVICE_BOOT If given device path contains MESSAGING_DEVICE_PATH type device path node
3861 and its last device path node's subtype is MSG_USB_DP.
3862 @retval BDS_EFI_MESSAGE_MISC_BOOT If the device path not contains any media device path node, and
3863 its last device path node point to a message device path node.
3864 @retval BDS_LEGACY_BBS_BOOT If given device path contains BBS_DEVICE_PATH type device path node.
3865 @retval BDS_EFI_UNSUPPORT An EFI Removable BlockIO device path not point to a media and message device,
3870 BdsGetBootTypeFromDevicePath (
3871 IN EFI_DEVICE_PATH_PROTOCOL
*DevicePath
3874 ACPI_HID_DEVICE_PATH
*Acpi
;
3875 EFI_DEVICE_PATH_PROTOCOL
*TempDevicePath
;
3876 EFI_DEVICE_PATH_PROTOCOL
*LastDeviceNode
;
3879 if (NULL
== DevicePath
) {
3880 return BDS_EFI_UNSUPPORT
;
3883 TempDevicePath
= DevicePath
;
3885 while (!IsDevicePathEndType (TempDevicePath
)) {
3886 switch (DevicePathType (TempDevicePath
)) {
3887 case BBS_DEVICE_PATH
:
3888 return BDS_LEGACY_BBS_BOOT
;
3889 case MEDIA_DEVICE_PATH
:
3890 if (DevicePathSubType (TempDevicePath
) == MEDIA_HARDDRIVE_DP
) {
3891 return BDS_EFI_MEDIA_HD_BOOT
;
3892 } else if (DevicePathSubType (TempDevicePath
) == MEDIA_CDROM_DP
) {
3893 return BDS_EFI_MEDIA_CDROM_BOOT
;
3896 case ACPI_DEVICE_PATH
:
3897 Acpi
= (ACPI_HID_DEVICE_PATH
*) TempDevicePath
;
3898 if (EISA_ID_TO_NUM (Acpi
->HID
) == 0x0604) {
3899 return BDS_EFI_ACPI_FLOPPY_BOOT
;
3902 case MESSAGING_DEVICE_PATH
:
3904 // Get the last device path node
3906 LastDeviceNode
= NextDevicePathNode (TempDevicePath
);
3907 if (DevicePathSubType(LastDeviceNode
) == MSG_DEVICE_LOGICAL_UNIT_DP
) {
3909 // if the next node type is Device Logical Unit, which specify the Logical Unit Number (LUN),
3912 LastDeviceNode
= NextDevicePathNode (LastDeviceNode
);
3915 // if the device path not only point to driver device, it is not a messaging device path,
3917 if (!IsDevicePathEndType (LastDeviceNode
)) {
3921 switch (DevicePathSubType (TempDevicePath
)) {
3923 BootType
= BDS_EFI_MESSAGE_ATAPI_BOOT
;
3927 BootType
= BDS_EFI_MESSAGE_USB_DEVICE_BOOT
;
3931 BootType
= BDS_EFI_MESSAGE_SCSI_BOOT
;
3935 BootType
= BDS_EFI_MESSAGE_SATA_BOOT
;
3938 case MSG_MAC_ADDR_DP
:
3942 BootType
= BDS_EFI_MESSAGE_MAC_BOOT
;
3946 BootType
= BDS_EFI_MESSAGE_MISC_BOOT
;
3954 TempDevicePath
= NextDevicePathNode (TempDevicePath
);
3957 return BDS_EFI_UNSUPPORT
;
3961 Check whether the Device path in a boot option point to a valid bootable device,
3962 And if CheckMedia is true, check the device is ready to boot now.
3964 @param DevPath the Device path in a boot option
3965 @param CheckMedia if true, check the device is ready to boot now.
3967 @retval TRUE the Device path is valid
3968 @retval FALSE the Device path is invalid .
3973 BdsLibIsValidEFIBootOptDevicePath (
3974 IN EFI_DEVICE_PATH_PROTOCOL
*DevPath
,
3975 IN BOOLEAN CheckMedia
3978 return BdsLibIsValidEFIBootOptDevicePathExt (DevPath
, CheckMedia
, NULL
);
3982 Check whether the Device path in a boot option point to a valid bootable device,
3983 And if CheckMedia is true, check the device is ready to boot now.
3984 If Description is not NULL and the device path point to a fixed BlockIo
3985 device, check the description whether conflict with other auto-created
3988 @param DevPath the Device path in a boot option
3989 @param CheckMedia if true, check the device is ready to boot now.
3990 @param Description the description in a boot option
3992 @retval TRUE the Device path is valid
3993 @retval FALSE the Device path is invalid .
3998 BdsLibIsValidEFIBootOptDevicePathExt (
3999 IN EFI_DEVICE_PATH_PROTOCOL
*DevPath
,
4000 IN BOOLEAN CheckMedia
,
4001 IN CHAR16
*Description
4006 EFI_DEVICE_PATH_PROTOCOL
*TempDevicePath
;
4007 EFI_DEVICE_PATH_PROTOCOL
*LastDeviceNode
;
4008 EFI_BLOCK_IO_PROTOCOL
*BlockIo
;
4010 TempDevicePath
= DevPath
;
4011 LastDeviceNode
= DevPath
;
4014 // Check if it's a valid boot option for network boot device.
4015 // Check if there is EfiLoadFileProtocol installed.
4016 // If yes, that means there is a boot option for network.
4018 Status
= gBS
->LocateDevicePath (
4019 &gEfiLoadFileProtocolGuid
,
4023 if (EFI_ERROR (Status
)) {
4025 // Device not present so see if we need to connect it
4027 TempDevicePath
= DevPath
;
4028 BdsLibConnectDevicePath (TempDevicePath
);
4029 Status
= gBS
->LocateDevicePath (
4030 &gEfiLoadFileProtocolGuid
,
4036 if (!EFI_ERROR (Status
)) {
4037 if (!IsDevicePathEnd (TempDevicePath
)) {
4039 // LoadFile protocol is not installed on handle with exactly the same DevPath
4046 // Test if it is ready to boot now
4048 if (BdsLibNetworkBootWithMediaPresent(DevPath
)) {
4057 // If the boot option point to a file, it is a valid EFI boot option,
4058 // and assume it is ready to boot now
4060 while (!IsDevicePathEnd (TempDevicePath
)) {
4062 // If there is USB Class or USB WWID device path node, treat it as valid EFI
4063 // Boot Option. BdsExpandUsbShortFormDevicePath () will be used to expand it
4064 // to full device path.
4066 if ((DevicePathType (TempDevicePath
) == MESSAGING_DEVICE_PATH
) &&
4067 ((DevicePathSubType (TempDevicePath
) == MSG_USB_CLASS_DP
) ||
4068 (DevicePathSubType (TempDevicePath
) == MSG_USB_WWID_DP
))) {
4072 LastDeviceNode
= TempDevicePath
;
4073 TempDevicePath
= NextDevicePathNode (TempDevicePath
);
4075 if ((DevicePathType (LastDeviceNode
) == MEDIA_DEVICE_PATH
) &&
4076 (DevicePathSubType (LastDeviceNode
) == MEDIA_FILEPATH_DP
)) {
4081 // Check if it's a valid boot option for internal FV application
4083 if (EfiGetNameGuidFromFwVolDevicePathNode ((MEDIA_FW_VOL_FILEPATH_DEVICE_PATH
*) LastDeviceNode
) != NULL
) {
4085 // If the boot option point to internal FV application, make sure it is valid
4087 TempDevicePath
= DevPath
;
4088 Status
= BdsLibUpdateFvFileDevicePath (
4090 EfiGetNameGuidFromFwVolDevicePathNode ((MEDIA_FW_VOL_FILEPATH_DEVICE_PATH
*) LastDeviceNode
)
4092 if (Status
== EFI_ALREADY_STARTED
) {
4095 if (Status
== EFI_SUCCESS
) {
4096 FreePool (TempDevicePath
);
4103 // If the boot option point to a blockIO device:
4104 // if it is a removable blockIo device, it is valid.
4105 // if it is a fixed blockIo device, check its description confliction.
4107 TempDevicePath
= DevPath
;
4108 Status
= gBS
->LocateDevicePath (&gEfiBlockIoProtocolGuid
, &TempDevicePath
, &Handle
);
4109 if (EFI_ERROR (Status
)) {
4111 // Device not present so see if we need to connect it
4113 Status
= BdsLibConnectDevicePath (DevPath
);
4114 if (!EFI_ERROR (Status
)) {
4116 // Try again to get the Block Io protocol after we did the connect
4118 TempDevicePath
= DevPath
;
4119 Status
= gBS
->LocateDevicePath (&gEfiBlockIoProtocolGuid
, &TempDevicePath
, &Handle
);
4123 if (!EFI_ERROR (Status
)) {
4124 Status
= gBS
->HandleProtocol (Handle
, &gEfiBlockIoProtocolGuid
, (VOID
**)&BlockIo
);
4125 if (!EFI_ERROR (Status
)) {
4128 // Test if it is ready to boot now
4130 if (BdsLibGetBootableHandle (DevPath
) != NULL
) {
4139 // 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,
4141 Status
= gBS
->LocateDevicePath (&gEfiSimpleFileSystemProtocolGuid
, &TempDevicePath
, &Handle
);
4142 if (!EFI_ERROR (Status
)) {
4145 // Test if it is ready to boot now
4147 if (BdsLibGetBootableHandle (DevPath
) != NULL
) {
4161 According to a file guild, check a Fv file device path is valid. If it is invalid,
4162 try to return the valid device path.
4163 FV address maybe changes for memory layout adjust from time to time, use this function
4164 could promise the Fv file device path is right.
4166 @param DevicePath on input, the Fv file device path need to check on
4167 output, the updated valid Fv file device path
4168 @param FileGuid the Fv file guild
4170 @retval EFI_INVALID_PARAMETER the input DevicePath or FileGuid is invalid
4172 @retval EFI_UNSUPPORTED the input DevicePath does not contain Fv file
4174 @retval EFI_ALREADY_STARTED the input DevicePath has pointed to Fv file, it is
4176 @retval EFI_SUCCESS has successfully updated the invalid DevicePath,
4177 and return the updated device path in DevicePath
4182 BdsLibUpdateFvFileDevicePath (
4183 IN OUT EFI_DEVICE_PATH_PROTOCOL
** DevicePath
,
4184 IN EFI_GUID
*FileGuid
4187 EFI_DEVICE_PATH_PROTOCOL
*TempDevicePath
;
4188 EFI_DEVICE_PATH_PROTOCOL
*LastDeviceNode
;
4190 EFI_GUID
*GuidPoint
;
4192 UINTN FvHandleCount
;
4193 EFI_HANDLE
*FvHandleBuffer
;
4194 EFI_FV_FILETYPE Type
;
4196 EFI_FV_FILE_ATTRIBUTES Attributes
;
4197 UINT32 AuthenticationStatus
;
4199 EFI_LOADED_IMAGE_PROTOCOL
*LoadedImage
;
4200 EFI_FIRMWARE_VOLUME2_PROTOCOL
*Fv
;
4201 MEDIA_FW_VOL_FILEPATH_DEVICE_PATH FvFileNode
;
4202 EFI_HANDLE FoundFvHandle
;
4203 EFI_DEVICE_PATH_PROTOCOL
*NewDevicePath
;
4205 if ((DevicePath
== NULL
) || (*DevicePath
== NULL
)) {
4206 return EFI_INVALID_PARAMETER
;
4208 if (FileGuid
== NULL
) {
4209 return EFI_INVALID_PARAMETER
;
4213 // Check whether the device path point to the default the input Fv file
4215 TempDevicePath
= *DevicePath
;
4216 LastDeviceNode
= TempDevicePath
;
4217 while (!IsDevicePathEnd (TempDevicePath
)) {
4218 LastDeviceNode
= TempDevicePath
;
4219 TempDevicePath
= NextDevicePathNode (TempDevicePath
);
4221 GuidPoint
= EfiGetNameGuidFromFwVolDevicePathNode (
4222 (MEDIA_FW_VOL_FILEPATH_DEVICE_PATH
*) LastDeviceNode
4224 if (GuidPoint
== NULL
) {
4226 // if this option does not points to a Fv file, just return EFI_UNSUPPORTED
4228 return EFI_UNSUPPORTED
;
4230 if (!CompareGuid (GuidPoint
, FileGuid
)) {
4232 // If the Fv file is not the input file guid, just return EFI_UNSUPPORTED
4234 return EFI_UNSUPPORTED
;
4238 // Check whether the input Fv file device path is valid
4240 TempDevicePath
= *DevicePath
;
4241 FoundFvHandle
= NULL
;
4242 Status
= gBS
->LocateDevicePath (
4243 &gEfiFirmwareVolume2ProtocolGuid
,
4247 if (!EFI_ERROR (Status
)) {
4248 Status
= gBS
->HandleProtocol (
4250 &gEfiFirmwareVolume2ProtocolGuid
,
4253 if (!EFI_ERROR (Status
)) {
4255 // Set FV ReadFile Buffer as NULL, only need to check whether input Fv file exist there
4257 Status
= Fv
->ReadFile (
4264 &AuthenticationStatus
4266 if (!EFI_ERROR (Status
)) {
4267 return EFI_ALREADY_STARTED
;
4273 // Look for the input wanted FV file in current FV
4274 // First, try to look for in Bds own FV. Bds and input wanted FV file usually are in the same FV
4277 FoundFvHandle
= NULL
;
4278 Status
= gBS
->HandleProtocol (
4280 &gEfiLoadedImageProtocolGuid
,
4281 (VOID
**) &LoadedImage
4283 if (!EFI_ERROR (Status
)) {
4284 Status
= gBS
->HandleProtocol (
4285 LoadedImage
->DeviceHandle
,
4286 &gEfiFirmwareVolume2ProtocolGuid
,
4289 if (!EFI_ERROR (Status
)) {
4290 Status
= Fv
->ReadFile (
4297 &AuthenticationStatus
4299 if (!EFI_ERROR (Status
)) {
4301 FoundFvHandle
= LoadedImage
->DeviceHandle
;
4306 // Second, if fail to find, try to enumerate all FV
4309 FvHandleBuffer
= NULL
;
4310 gBS
->LocateHandleBuffer (
4312 &gEfiFirmwareVolume2ProtocolGuid
,
4317 for (Index
= 0; Index
< FvHandleCount
; Index
++) {
4318 gBS
->HandleProtocol (
4319 FvHandleBuffer
[Index
],
4320 &gEfiFirmwareVolume2ProtocolGuid
,
4324 Status
= Fv
->ReadFile (
4331 &AuthenticationStatus
4333 if (EFI_ERROR (Status
)) {
4335 // Skip if input Fv file not in the FV
4340 FoundFvHandle
= FvHandleBuffer
[Index
];
4344 if (FvHandleBuffer
!= NULL
) {
4345 FreePool (FvHandleBuffer
);
4351 // Build the shell device path
4353 NewDevicePath
= DevicePathFromHandle (FoundFvHandle
);
4354 EfiInitializeFwVolDevicepathNode (&FvFileNode
, FileGuid
);
4355 NewDevicePath
= AppendDevicePathNode (NewDevicePath
, (EFI_DEVICE_PATH_PROTOCOL
*) &FvFileNode
);
4356 ASSERT (NewDevicePath
!= NULL
);
4357 *DevicePath
= NewDevicePath
;
4360 return EFI_NOT_FOUND
;