2 This function deal with the legacy boot option, it create, delete
3 and manage the legacy boot option, all legacy boot option is getting from
6 Copyright (c) 2011 - 2017, Intel Corporation. All rights reserved.<BR>
7 This program and the accompanying materials
8 are licensed and made available under the terms and conditions of the BSD License
9 which accompanies this distribution. The full text of the license may be found at
10 http://opensource.org/licenses/bsd-license.php
12 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
13 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
17 #include "InternalLegacyBm.h"
19 #define LEGACY_BM_BOOT_DESCRIPTION_LENGTH 32
22 Initialize legacy boot manager library by call EfiBootManagerRegisterLegacyBootSupport
23 function to export two function pointer.
25 @param ImageHandle The image handle.
26 @param SystemTable The system table.
28 @retval EFI_SUCCESS The legacy boot manager library is initialized correctly.
29 @return Other value if failed to initialize the legacy boot manager library.
33 LegacyBootManagerLibConstructor (
34 IN EFI_HANDLE ImageHandle
,
35 IN EFI_SYSTEM_TABLE
*SystemTable
38 EfiBootManagerRegisterLegacyBootSupport (
39 LegacyBmRefreshAllBootOption
,
46 Get the device type from the input legacy device path.
48 @param DevicePath The legacy device path.
50 @retval The legacy device type.
54 EFI_DEVICE_PATH_PROTOCOL
*DevicePath
57 ASSERT ((DevicePathType (DevicePath
) == BBS_DEVICE_PATH
) &&
58 (DevicePathSubType (DevicePath
) == BBS_BBS_DP
));
59 return ((BBS_BBS_DEVICE_PATH
*) DevicePath
)->DeviceType
;
63 Validate the BbsEntry base on the Boot Priority info in the BbsEntry.
65 @param BbsEntry The input bbs entry info.
67 @retval TRUE The BbsEntry is valid.
68 @retval FALSE The BbsEntry is invalid.
71 LegacyBmValidBbsEntry (
72 IN BBS_TABLE
*BbsEntry
75 switch (BbsEntry
->BootPriority
) {
76 case BBS_IGNORE_ENTRY
:
77 case BBS_DO_NOT_BOOT_FROM
:
78 case BBS_LOWEST_PRIORITY
:
86 Build Legacy Device Name String according.
88 @param CurBBSEntry BBS Table.
90 @param BufSize The buffer size.
91 @param BootString The output string.
95 LegacyBmBuildLegacyDevNameString (
96 IN BBS_TABLE
*CurBBSEntry
,
99 OUT CHAR16
*BootString
105 CHAR8 StringBufferA
[LEGACY_BM_BOOT_DESCRIPTION_LENGTH
+ 1];
106 CHAR16 StringBufferU
[LEGACY_BM_BOOT_DESCRIPTION_LENGTH
+ 1];
113 Fmt
= L
"Primary Master %s";
120 Fmt
= L
"Primary Slave %s";
127 Fmt
= L
"Secondary Master %s";
134 Fmt
= L
"Secondary Slave %s";
142 switch (CurBBSEntry
->DeviceType
) {
163 case BBS_EMBED_NETWORK
:
177 // If current BBS entry has its description then use it.
179 StringDesc
= (CHAR8
*) (((UINTN
) CurBBSEntry
->DescStringSegment
<< 4) + CurBBSEntry
->DescStringOffset
);
180 if (NULL
!= StringDesc
) {
182 // Only get fisrt 32 characters, this is suggested by BBS spec
184 CopyMem (StringBufferA
, StringDesc
, LEGACY_BM_BOOT_DESCRIPTION_LENGTH
);
185 StringBufferA
[LEGACY_BM_BOOT_DESCRIPTION_LENGTH
] = 0;
186 AsciiStrToUnicodeStrS (StringBufferA
, StringBufferU
, ARRAY_SIZE (StringBufferU
));
188 Type
= StringBufferU
;
192 // BbsTable 16 entries are for onboard IDE.
193 // Set description string for SATA harddisks, Harddisk 0 ~ Harddisk 11
195 if (Index
>= 5 && Index
<= 16 && (CurBBSEntry
->DeviceType
== BBS_HARDDISK
|| CurBBSEntry
->DeviceType
== BBS_CDROM
)) {
197 UnicodeSPrint (BootString
, BufSize
, Fmt
, Type
, Index
- 5);
199 UnicodeSPrint (BootString
, BufSize
, Fmt
, Type
);
204 Get the Bbs index for the input boot option.
206 @param BootOption The input boot option info.
207 @param BbsTable The input Bbs table.
208 @param BbsCount The input total bbs entry number.
209 @param BbsIndexUsed The array shows how many BBS table indexs have been used.
211 @retval The index for the input boot option.
215 EFI_BOOT_MANAGER_LOAD_OPTION
*BootOption
,
218 BOOLEAN
*BbsIndexUsed
222 LEGACY_BM_BOOT_OPTION_BBS_DATA
*BbsData
;
223 CHAR16 Description
[LEGACY_BM_BOOT_DESCRIPTION_LENGTH
+ 1];
225 BbsData
= (LEGACY_BM_BOOT_OPTION_BBS_DATA
*) BootOption
->OptionalData
;
228 // Directly check the BBS index stored in BootOption
230 if ((BbsData
->BbsIndex
< BbsCount
) &&
231 (LegacyBmDeviceType (BootOption
->FilePath
) == BbsTable
[BbsData
->BbsIndex
].DeviceType
)) {
232 LegacyBmBuildLegacyDevNameString (
233 &BbsTable
[BbsData
->BbsIndex
],
235 sizeof (Description
),
238 if ((StrCmp (Description
, BootOption
->Description
) == 0) && !BbsIndexUsed
[BbsData
->BbsIndex
]) {
240 // If devices with the same description string are connected,
241 // the BbsIndex of the first device is returned for the other device also.
242 // So, check if the BbsIndex is already being used, before assigning the BbsIndex.
244 BbsIndexUsed
[BbsData
->BbsIndex
] = TRUE
;
245 return BbsData
->BbsIndex
;
250 // BBS table could be changed (entry removed/moved)
251 // find the correct BBS index
253 for (Index
= 0; Index
< BbsCount
; Index
++) {
254 if (!LegacyBmValidBbsEntry (&BbsTable
[Index
]) ||
255 (BbsTable
[Index
].DeviceType
!= LegacyBmDeviceType (BootOption
->FilePath
))) {
259 LegacyBmBuildLegacyDevNameString (
262 sizeof (Description
),
265 if ((StrCmp (Description
, BootOption
->Description
) == 0) && !BbsIndexUsed
[Index
]) {
267 // If devices with the same description string are connected,
268 // the BbsIndex of the first device is assigned for the other device also.
269 // So, check if the BbsIndex is already being used, before assigning the corrected BbsIndex.
276 // Add the corrected BbsIndex in the UsedBbsIndex Buffer
278 if (Index
!= BbsCount
) {
279 BbsIndexUsed
[Index
] = TRUE
;
287 Update legacy device order base on the input info.
289 @param LegacyDevOrder Legacy device order data buffer.
290 @param LegacyDevOrderSize Legacy device order data buffer size.
291 @param DeviceType Device type which need to check.
292 @param OldBbsIndex Old Bds Index.
293 @param NewBbsIndex New Bds Index, if it is -1,means remove this option.
297 LegacyBmUpdateBbsIndex (
298 LEGACY_DEV_ORDER_ENTRY
*LegacyDevOrder
,
299 UINTN
*LegacyDevOrderSize
,
302 UINT16 NewBbsIndex
// Delete entry if -1
305 LEGACY_DEV_ORDER_ENTRY
*Entry
;
308 ASSERT (((LegacyDevOrder
== NULL
) && (*LegacyDevOrderSize
== 0)) ||
309 ((LegacyDevOrder
!= NULL
) && (*LegacyDevOrderSize
!= 0))
312 for (Entry
= LegacyDevOrder
;
313 Entry
< (LEGACY_DEV_ORDER_ENTRY
*) ((UINT8
*) LegacyDevOrder
+ *LegacyDevOrderSize
);
314 Entry
= (LEGACY_DEV_ORDER_ENTRY
*) ((UINTN
) Entry
+ sizeof (BBS_TYPE
) + Entry
->Length
)
316 if (Entry
->BbsType
== DeviceType
) {
317 for (Index
= 0; Index
< Entry
->Length
/ sizeof (UINT16
) - 1; Index
++) {
318 if (Entry
->Data
[Index
] == OldBbsIndex
) {
319 if (NewBbsIndex
== (UINT16
) -1) {
321 // Delete the old entry
325 &Entry
->Data
[Index
+ 1],
326 (UINT8
*) LegacyDevOrder
+ *LegacyDevOrderSize
- (UINT8
*) &Entry
->Data
[Index
+ 1]
328 Entry
->Length
-= sizeof (UINT16
);
329 *LegacyDevOrderSize
-= sizeof(UINT16
);
331 Entry
->Data
[Index
] = NewBbsIndex
;
342 Delete all the legacy boot options.
344 @retval EFI_SUCCESS All legacy boot options are deleted.
347 LegacyBmDeleteAllBootOptions (
353 EFI_BOOT_MANAGER_LOAD_OPTION
*BootOption
;
354 UINTN BootOptionCount
;
356 BootOption
= EfiBootManagerGetLoadOptions (&BootOptionCount
, LoadOptionTypeBoot
);
357 for (Index
= 0; Index
< BootOptionCount
; Index
++) {
358 if ((DevicePathType (BootOption
[Index
].FilePath
) == BBS_DEVICE_PATH
) &&
359 (DevicePathSubType (BootOption
[Index
].FilePath
) == BBS_BBS_DP
)) {
360 Status
= EfiBootManagerDeleteLoadOptionVariable (BootOption
[Index
].OptionNumber
, BootOption
[Index
].OptionType
);
362 // Deleting variable with current variable implementation shouldn't fail.
364 ASSERT_EFI_ERROR (Status
);
368 Status
= gRT
->SetVariable (
369 VAR_LEGACY_DEV_ORDER
,
370 &gEfiLegacyDevOrderVariableGuid
,
376 // Deleting variable with current variable implementation shouldn't fail.
378 ASSERT (Status
== EFI_SUCCESS
|| Status
== EFI_NOT_FOUND
);
385 Delete all the invalid legacy boot options.
387 @retval EFI_SUCCESS All invalide legacy boot options are deleted.
388 @retval EFI_OUT_OF_RESOURCES Fail to allocate necessary memory.
389 @retval EFI_NOT_FOUND Fail to retrive variable of boot order.
392 LegacyBmDeleteAllInvalidBootOptions (
402 EFI_LEGACY_BIOS_PROTOCOL
*LegacyBios
;
404 EFI_BOOT_MANAGER_LOAD_OPTION
*BootOption
;
405 UINTN BootOptionCount
;
406 LEGACY_DEV_ORDER_ENTRY
*LegacyDevOrder
;
407 UINTN LegacyDevOrderSize
;
408 BOOLEAN
*BbsIndexUsed
;
415 Status
= gBS
->LocateProtocol (&gEfiLegacyBiosProtocolGuid
, NULL
, (VOID
**) &LegacyBios
);
416 if (EFI_ERROR (Status
)) {
420 Status
= LegacyBios
->GetBbsInfo (
427 if (EFI_ERROR (Status
)) {
431 GetVariable2 (VAR_LEGACY_DEV_ORDER
, &gEfiLegacyDevOrderVariableGuid
, (VOID
**) &LegacyDevOrder
, &LegacyDevOrderSize
);
433 BootOption
= EfiBootManagerGetLoadOptions (&BootOptionCount
, LoadOptionTypeBoot
);
435 BbsIndexUsed
= AllocateZeroPool (BbsCount
* sizeof (BOOLEAN
));
436 ASSERT (BbsIndexUsed
!= NULL
);
438 for (Index
= 0; Index
< BootOptionCount
; Index
++) {
440 // Skip non legacy boot option
442 if ((DevicePathType (BootOption
[Index
].FilePath
) != BBS_DEVICE_PATH
) ||
443 (DevicePathSubType (BootOption
[Index
].FilePath
) != BBS_BBS_DP
)) {
447 BbsIndex
= LegacyBmFuzzyMatch (&BootOption
[Index
], BbsTable
, BbsCount
, BbsIndexUsed
);
448 if (BbsIndex
== BbsCount
) {
449 DEBUG ((EFI_D_INFO
, "[LegacyBds] Delete Boot Option Boot%04x: %s\n", (UINTN
) BootOption
[Index
].OptionNumber
, BootOption
[Index
].Description
));
451 // Delete entry from LegacyDevOrder
453 LegacyBmUpdateBbsIndex (
456 LegacyBmDeviceType (BootOption
[Index
].FilePath
),
457 ((LEGACY_BM_BOOT_OPTION_BBS_DATA
*) BootOption
[Index
].OptionalData
)->BbsIndex
,
460 EfiBootManagerDeleteLoadOptionVariable (BootOption
[Index
].OptionNumber
, BootOption
[Index
].OptionType
);
462 if (((LEGACY_BM_BOOT_OPTION_BBS_DATA
*) BootOption
[Index
].OptionalData
)->BbsIndex
!= BbsIndex
) {
463 DEBUG ((EFI_D_INFO
, "[LegacyBds] Update Boot Option Boot%04x: %s Bbs0x%04x->Bbs0x%04x\n", (UINTN
) BootOption
[Index
].OptionNumber
, BootOption
[Index
].Description
,
464 (UINTN
) ((LEGACY_BM_BOOT_OPTION_BBS_DATA
*) BootOption
[Index
].OptionalData
)->BbsIndex
, (UINTN
) BbsIndex
));
466 // Update the BBS index in LegacyDevOrder
468 LegacyBmUpdateBbsIndex (
471 LegacyBmDeviceType (BootOption
[Index
].FilePath
),
472 ((LEGACY_BM_BOOT_OPTION_BBS_DATA
*) BootOption
[Index
].OptionalData
)->BbsIndex
,
477 // Update the OptionalData in the Boot#### variable
479 ((LEGACY_BM_BOOT_OPTION_BBS_DATA
*) BootOption
[Index
].OptionalData
)->BbsIndex
= BbsIndex
;
480 EfiBootManagerLoadOptionToVariable (&BootOption
[Index
]);
484 EfiBootManagerFreeLoadOptions (BootOption
, BootOptionCount
);
486 if (LegacyDevOrder
!= NULL
) {
487 Status
= gRT
->SetVariable (
488 VAR_LEGACY_DEV_ORDER
,
489 &gEfiLegacyDevOrderVariableGuid
,
490 EFI_VARIABLE_BOOTSERVICE_ACCESS
| EFI_VARIABLE_NON_VOLATILE
,
495 // Shrink variable with current variable implementation shouldn't fail.
497 ASSERT_EFI_ERROR (Status
);
499 FreePool (LegacyDevOrder
);
501 FreePool(BbsIndexUsed
);
506 Create legacy boot option.
508 @param BootOption Ponter to the boot option which will be crated.
509 @param BbsEntry The input bbs entry info.
510 @param BbsIndex The BBS index.
512 @retval EFI_SUCCESS Create legacy boot option successfully.
513 @retval EFI_INVALID_PARAMETER Invalid input parameter.
517 LegacyBmCreateLegacyBootOption (
518 IN OUT EFI_BOOT_MANAGER_LOAD_OPTION
*BootOption
,
519 IN BBS_TABLE
*BbsEntry
,
524 EFI_DEVICE_PATH_PROTOCOL
*DevicePath
;
525 CHAR16 Description
[LEGACY_BM_BOOT_DESCRIPTION_LENGTH
+ 1];
526 CHAR8 HelpString
[LEGACY_BM_BOOT_DESCRIPTION_LENGTH
+ 1];
528 LEGACY_BM_BOOT_OPTION_BBS_DATA
*OptionalData
;
529 BBS_BBS_DEVICE_PATH
*BbsNode
;
531 if ((BootOption
== NULL
) || (BbsEntry
== NULL
)) {
532 return EFI_INVALID_PARAMETER
;
535 LegacyBmBuildLegacyDevNameString (BbsEntry
, BbsIndex
, sizeof (Description
), Description
);
538 // Create the BBS device path with description string
540 UnicodeStrToAsciiStrS (Description
, HelpString
, sizeof (HelpString
));
541 StringLen
= AsciiStrLen (HelpString
);
542 DevicePath
= AllocatePool (sizeof (BBS_BBS_DEVICE_PATH
) + StringLen
+ END_DEVICE_PATH_LENGTH
);
543 ASSERT (DevicePath
!= NULL
);
545 BbsNode
= (BBS_BBS_DEVICE_PATH
*) DevicePath
;
546 SetDevicePathNodeLength (BbsNode
, sizeof (BBS_BBS_DEVICE_PATH
) + StringLen
);
547 BbsNode
->Header
.Type
= BBS_DEVICE_PATH
;
548 BbsNode
->Header
.SubType
= BBS_BBS_DP
;
549 BbsNode
->DeviceType
= BbsEntry
->DeviceType
;
550 CopyMem (&BbsNode
->StatusFlag
, &BbsEntry
->StatusFlags
, sizeof (BBS_STATUS_FLAGS
));
551 CopyMem (BbsNode
->String
, HelpString
, StringLen
+ 1);
553 SetDevicePathEndNode (NextDevicePathNode (BbsNode
));
556 // Create the OptionalData
558 OptionalData
= AllocatePool (sizeof (LEGACY_BM_BOOT_OPTION_BBS_DATA
));
559 ASSERT (OptionalData
!= NULL
);
560 OptionalData
->BbsIndex
= BbsIndex
;
563 // Create the BootOption
565 Status
= EfiBootManagerInitializeLoadOption (
567 LoadOptionNumberUnassigned
,
572 (UINT8
*) OptionalData
,
573 sizeof (LEGACY_BM_BOOT_OPTION_BBS_DATA
)
575 FreePool (DevicePath
);
576 FreePool (OptionalData
);
582 Fill the device order buffer.
584 @param BbsTable The BBS table.
585 @param BbsType The BBS Type.
586 @param BbsCount The BBS Count.
587 @param Buf device order buffer.
589 @return The device order buffer.
593 LegacyBmFillDevOrderBuf (
594 IN BBS_TABLE
*BbsTable
,
602 for (Index
= 0; Index
< BbsCount
; Index
++) {
603 if (!LegacyBmValidBbsEntry (&BbsTable
[Index
])) {
607 if (BbsTable
[Index
].DeviceType
!= BbsType
) {
611 *Buf
= (UINT16
) (Index
& 0xFF);
619 Create the device order buffer.
621 @param BbsTable The BBS table.
622 @param BbsCount The BBS Count.
624 @retval EFI_SUCCES The buffer is created and the EFI variable named
625 VAR_LEGACY_DEV_ORDER and EfiLegacyDevOrderGuid is
627 @retval EFI_OUT_OF_RESOURCES Memmory or storage is not enough.
628 @retval EFI_DEVICE_ERROR Fail to add the device order into EFI variable fail
629 because of hardware error.
632 LegacyBmCreateDevOrder (
633 IN BBS_TABLE
*BbsTable
,
645 LEGACY_DEV_ORDER_ENTRY
*DevOrder
;
646 LEGACY_DEV_ORDER_ENTRY
*DevOrderPtr
;
655 HeaderSize
= sizeof (BBS_TYPE
) + sizeof (UINT16
);
657 Status
= EFI_SUCCESS
;
660 // Count all boot devices
662 for (Index
= 0; Index
< BbsCount
; Index
++) {
663 if (!LegacyBmValidBbsEntry (&BbsTable
[Index
])) {
667 switch (BbsTable
[Index
].DeviceType
) {
680 case BBS_EMBED_NETWORK
:
693 TotalSize
+= (HeaderSize
+ sizeof (UINT16
) * FDCount
);
694 TotalSize
+= (HeaderSize
+ sizeof (UINT16
) * HDCount
);
695 TotalSize
+= (HeaderSize
+ sizeof (UINT16
) * CDCount
);
696 TotalSize
+= (HeaderSize
+ sizeof (UINT16
) * NETCount
);
697 TotalSize
+= (HeaderSize
+ sizeof (UINT16
) * BEVCount
);
700 // Create buffer to hold all boot device order
702 DevOrder
= AllocateZeroPool (TotalSize
);
703 if (NULL
== DevOrder
) {
704 return EFI_OUT_OF_RESOURCES
;
706 DevOrderPtr
= DevOrder
;
708 DevOrderPtr
->BbsType
= BBS_FLOPPY
;
709 DevOrderPtr
->Length
= (UINT16
) (sizeof (DevOrderPtr
->Length
) + FDCount
* sizeof (UINT16
));
710 DevOrderPtr
= (LEGACY_DEV_ORDER_ENTRY
*) LegacyBmFillDevOrderBuf (BbsTable
, BBS_FLOPPY
, BbsCount
, DevOrderPtr
->Data
);
712 DevOrderPtr
->BbsType
= BBS_HARDDISK
;
713 DevOrderPtr
->Length
= (UINT16
) (sizeof (UINT16
) + HDCount
* sizeof (UINT16
));
714 DevOrderPtr
= (LEGACY_DEV_ORDER_ENTRY
*) LegacyBmFillDevOrderBuf (BbsTable
, BBS_HARDDISK
, BbsCount
, DevOrderPtr
->Data
);
716 DevOrderPtr
->BbsType
= BBS_CDROM
;
717 DevOrderPtr
->Length
= (UINT16
) (sizeof (UINT16
) + CDCount
* sizeof (UINT16
));
718 DevOrderPtr
= (LEGACY_DEV_ORDER_ENTRY
*) LegacyBmFillDevOrderBuf (BbsTable
, BBS_CDROM
, BbsCount
, DevOrderPtr
->Data
);
720 DevOrderPtr
->BbsType
= BBS_EMBED_NETWORK
;
721 DevOrderPtr
->Length
= (UINT16
) (sizeof (UINT16
) + NETCount
* sizeof (UINT16
));
722 DevOrderPtr
= (LEGACY_DEV_ORDER_ENTRY
*) LegacyBmFillDevOrderBuf (BbsTable
, BBS_EMBED_NETWORK
, BbsCount
, DevOrderPtr
->Data
);
724 DevOrderPtr
->BbsType
= BBS_BEV_DEVICE
;
725 DevOrderPtr
->Length
= (UINT16
) (sizeof (UINT16
) + BEVCount
* sizeof (UINT16
));
726 DevOrderPtr
= (LEGACY_DEV_ORDER_ENTRY
*) LegacyBmFillDevOrderBuf (BbsTable
, BBS_BEV_DEVICE
, BbsCount
, DevOrderPtr
->Data
);
728 ASSERT (TotalSize
== ((UINTN
) DevOrderPtr
- (UINTN
) DevOrder
));
731 // Save device order for legacy boot device to variable.
733 Status
= gRT
->SetVariable (
734 VAR_LEGACY_DEV_ORDER
,
735 &gEfiLegacyDevOrderVariableGuid
,
736 EFI_VARIABLE_BOOTSERVICE_ACCESS
| EFI_VARIABLE_NON_VOLATILE
,
746 Add the legacy boot devices from BBS table into
747 the legacy device boot order.
749 @retval EFI_SUCCESS The boot devices are added successfully.
750 @retval EFI_NOT_FOUND The legacy boot devices are not found.
751 @retval EFI_OUT_OF_RESOURCES Memmory or storage is not enough.
752 @retval EFI_DEVICE_ERROR Fail to add the legacy device boot order into EFI variable
753 because of hardware error.
756 LegacyBmUpdateDevOrder (
760 LEGACY_DEV_ORDER_ENTRY
*DevOrder
;
761 LEGACY_DEV_ORDER_ENTRY
*NewDevOrder
;
762 LEGACY_DEV_ORDER_ENTRY
*Ptr
;
763 LEGACY_DEV_ORDER_ENTRY
*NewPtr
;
764 EFI_LEGACY_BIOS_PROTOCOL
*LegacyBios
;
768 HDD_INFO
*LocalHddInfo
;
769 BBS_TABLE
*LocalBbsTable
;
799 HeaderSize
= sizeof (BBS_TYPE
) + sizeof (UINT16
);
807 Status
= gBS
->LocateProtocol (&gEfiLegacyBiosProtocolGuid
, NULL
, (VOID
**) &LegacyBios
);
808 if (EFI_ERROR (Status
)) {
812 Status
= LegacyBios
->GetBbsInfo (
819 if (EFI_ERROR (Status
)) {
823 GetVariable2 (VAR_LEGACY_DEV_ORDER
, &gEfiLegacyDevOrderVariableGuid
, (VOID
**) &DevOrder
, NULL
);
824 if (NULL
== DevOrder
) {
825 return LegacyBmCreateDevOrder (LocalBbsTable
, BbsCount
);
828 // First we figure out how many boot devices with same device type respectively
830 for (Index
= 0; Index
< BbsCount
; Index
++) {
831 if (!LegacyBmValidBbsEntry (&LocalBbsTable
[Index
])) {
835 switch (LocalBbsTable
[Index
].DeviceType
) {
848 case BBS_EMBED_NETWORK
:
861 TotalSize
+= (HeaderSize
+ FDCount
* sizeof (UINT16
));
862 TotalSize
+= (HeaderSize
+ HDCount
* sizeof (UINT16
));
863 TotalSize
+= (HeaderSize
+ CDCount
* sizeof (UINT16
));
864 TotalSize
+= (HeaderSize
+ NETCount
* sizeof (UINT16
));
865 TotalSize
+= (HeaderSize
+ BEVCount
* sizeof (UINT16
));
867 NewDevOrder
= AllocateZeroPool (TotalSize
);
868 if (NULL
== NewDevOrder
) {
869 return EFI_OUT_OF_RESOURCES
;
876 NewPtr
= NewDevOrder
;
877 NewPtr
->BbsType
= Ptr
->BbsType
;
878 NewPtr
->Length
= (UINT16
) (sizeof (UINT16
) + FDCount
* sizeof (UINT16
));
879 for (Index
= 0; Index
< Ptr
->Length
/ sizeof (UINT16
) - 1; Index
++) {
880 if (!LegacyBmValidBbsEntry (&LocalBbsTable
[Ptr
->Data
[Index
] & 0xFF]) ||
881 LocalBbsTable
[Ptr
->Data
[Index
] & 0xFF].DeviceType
!= BBS_FLOPPY
886 NewPtr
->Data
[FDIndex
] = Ptr
->Data
[Index
];
889 NewFDPtr
= NewPtr
->Data
;
894 Ptr
= (LEGACY_DEV_ORDER_ENTRY
*) (&Ptr
->Data
[Ptr
->Length
/ sizeof (UINT16
) - 1]);
895 NewPtr
= (LEGACY_DEV_ORDER_ENTRY
*) (&NewPtr
->Data
[NewPtr
->Length
/ sizeof (UINT16
) -1]);
896 NewPtr
->BbsType
= Ptr
->BbsType
;
897 NewPtr
->Length
= (UINT16
) (sizeof (UINT16
) + HDCount
* sizeof (UINT16
));
898 for (Index
= 0; Index
< Ptr
->Length
/ sizeof (UINT16
) - 1; Index
++) {
899 if (!LegacyBmValidBbsEntry (&LocalBbsTable
[Ptr
->Data
[Index
] & 0xFF]) ||
900 LocalBbsTable
[Ptr
->Data
[Index
] & 0xFF].DeviceType
!= BBS_HARDDISK
905 NewPtr
->Data
[HDIndex
] = Ptr
->Data
[Index
];
908 NewHDPtr
= NewPtr
->Data
;
913 Ptr
= (LEGACY_DEV_ORDER_ENTRY
*) (&Ptr
->Data
[Ptr
->Length
/ sizeof (UINT16
) - 1]);
914 NewPtr
= (LEGACY_DEV_ORDER_ENTRY
*) (&NewPtr
->Data
[NewPtr
->Length
/ sizeof (UINT16
) -1]);
915 NewPtr
->BbsType
= Ptr
->BbsType
;
916 NewPtr
->Length
= (UINT16
) (sizeof (UINT16
) + CDCount
* sizeof (UINT16
));
917 for (Index
= 0; Index
< Ptr
->Length
/ sizeof (UINT16
) - 1; Index
++) {
918 if (!LegacyBmValidBbsEntry (&LocalBbsTable
[Ptr
->Data
[Index
] & 0xFF]) ||
919 LocalBbsTable
[Ptr
->Data
[Index
] & 0xFF].DeviceType
!= BBS_CDROM
924 NewPtr
->Data
[CDIndex
] = Ptr
->Data
[Index
];
927 NewCDPtr
= NewPtr
->Data
;
932 Ptr
= (LEGACY_DEV_ORDER_ENTRY
*) (&Ptr
->Data
[Ptr
->Length
/ sizeof (UINT16
) - 1]);
933 NewPtr
= (LEGACY_DEV_ORDER_ENTRY
*) (&NewPtr
->Data
[NewPtr
->Length
/ sizeof (UINT16
) -1]);
934 NewPtr
->BbsType
= Ptr
->BbsType
;
935 NewPtr
->Length
= (UINT16
) (sizeof (UINT16
) + NETCount
* sizeof (UINT16
));
936 for (Index
= 0; Index
< Ptr
->Length
/ sizeof (UINT16
) - 1; Index
++) {
937 if (!LegacyBmValidBbsEntry (&LocalBbsTable
[Ptr
->Data
[Index
] & 0xFF]) ||
938 LocalBbsTable
[Ptr
->Data
[Index
] & 0xFF].DeviceType
!= BBS_EMBED_NETWORK
943 NewPtr
->Data
[NETIndex
] = Ptr
->Data
[Index
];
946 NewNETPtr
= NewPtr
->Data
;
951 Ptr
= (LEGACY_DEV_ORDER_ENTRY
*) (&Ptr
->Data
[Ptr
->Length
/ sizeof (UINT16
) - 1]);
952 NewPtr
= (LEGACY_DEV_ORDER_ENTRY
*) (&NewPtr
->Data
[NewPtr
->Length
/ sizeof (UINT16
) -1]);
953 NewPtr
->BbsType
= Ptr
->BbsType
;
954 NewPtr
->Length
= (UINT16
) (sizeof (UINT16
) + BEVCount
* sizeof (UINT16
));
955 for (Index
= 0; Index
< Ptr
->Length
/ sizeof (UINT16
) - 1; Index
++) {
956 if (!LegacyBmValidBbsEntry (&LocalBbsTable
[Ptr
->Data
[Index
] & 0xFF]) ||
957 LocalBbsTable
[Ptr
->Data
[Index
] & 0xFF].DeviceType
!= BBS_BEV_DEVICE
962 NewPtr
->Data
[BEVIndex
] = Ptr
->Data
[Index
];
965 NewBEVPtr
= NewPtr
->Data
;
967 for (Index
= 0; Index
< BbsCount
; Index
++) {
968 if (!LegacyBmValidBbsEntry (&LocalBbsTable
[Index
])) {
972 switch (LocalBbsTable
[Index
].DeviceType
) {
975 NewDevPtr
= NewFDPtr
;
980 NewDevPtr
= NewHDPtr
;
985 NewDevPtr
= NewCDPtr
;
988 case BBS_EMBED_NETWORK
:
990 NewDevPtr
= NewNETPtr
;
995 NewDevPtr
= NewBEVPtr
;
1003 // at this point we have copied those valid indexes to new buffer
1004 // and we should check if there is any new appeared boot device
1007 for (Index2
= 0; Index2
< *Idx
; Index2
++) {
1008 if ((NewDevPtr
[Index2
] & 0xFF) == (UINT16
) Index
) {
1013 if (Index2
== *Idx
) {
1015 // Index2 == *Idx means we didn't find Index
1016 // so Index is a new appeared device's index in BBS table
1017 // insert it before disabled indexes.
1019 for (Index2
= 0; Index2
< *Idx
; Index2
++) {
1020 if ((NewDevPtr
[Index2
] & 0xFF00) == 0xFF00) {
1024 CopyMem (&NewDevPtr
[Index2
+ 1], &NewDevPtr
[Index2
], (*Idx
- Index2
) * sizeof (UINT16
));
1025 NewDevPtr
[Index2
] = (UINT16
) (Index
& 0xFF);
1031 FreePool (DevOrder
);
1033 Status
= gRT
->SetVariable (
1034 VAR_LEGACY_DEV_ORDER
,
1035 &gEfiLegacyDevOrderVariableGuid
,
1036 EFI_VARIABLE_BOOTSERVICE_ACCESS
| EFI_VARIABLE_NON_VOLATILE
,
1040 FreePool (NewDevOrder
);
1046 Set Boot Priority for specified device type.
1048 @param DeviceType The device type.
1049 @param BbsIndex The BBS index to set the highest priority. Ignore when -1.
1050 @param LocalBbsTable The BBS table.
1051 @param Priority The prority table.
1053 @retval EFI_SUCCESS The function completes successfully.
1054 @retval EFI_NOT_FOUND Failed to find device.
1055 @retval EFI_OUT_OF_RESOURCES Failed to get the efi variable of device order.
1059 LegacyBmSetPriorityForSameTypeDev (
1060 IN UINT16 DeviceType
,
1062 IN OUT BBS_TABLE
*LocalBbsTable
,
1063 IN OUT UINT16
*Priority
1066 LEGACY_DEV_ORDER_ENTRY
*DevOrder
;
1067 LEGACY_DEV_ORDER_ENTRY
*DevOrderPtr
;
1071 GetVariable2 (VAR_LEGACY_DEV_ORDER
, &gEfiLegacyDevOrderVariableGuid
, (VOID
**) &DevOrder
, &DevOrderSize
);
1072 if (NULL
== DevOrder
) {
1073 return EFI_OUT_OF_RESOURCES
;
1076 DevOrderPtr
= DevOrder
;
1077 while ((UINT8
*) DevOrderPtr
< (UINT8
*) DevOrder
+ DevOrderSize
) {
1078 if (DevOrderPtr
->BbsType
== DeviceType
) {
1082 DevOrderPtr
= (LEGACY_DEV_ORDER_ENTRY
*) ((UINTN
) DevOrderPtr
+ sizeof (BBS_TYPE
) + DevOrderPtr
->Length
);
1085 if ((UINT8
*) DevOrderPtr
>= (UINT8
*) DevOrder
+ DevOrderSize
) {
1086 FreePool (DevOrder
);
1087 return EFI_NOT_FOUND
;
1090 if (BbsIndex
!= (UINTN
) -1) {
1092 // In case the BBS entry isn't valid because devices were plugged or removed.
1094 if (!LegacyBmValidBbsEntry (&LocalBbsTable
[BbsIndex
]) || (LocalBbsTable
[BbsIndex
].DeviceType
!= DeviceType
)) {
1095 FreePool (DevOrder
);
1096 return EFI_NOT_FOUND
;
1098 LocalBbsTable
[BbsIndex
].BootPriority
= *Priority
;
1102 // If the high byte of the DevIndex is 0xFF, it indicates that this device has been disabled.
1104 for (Index
= 0; Index
< DevOrderPtr
->Length
/ sizeof (UINT16
) - 1; Index
++) {
1105 if ((DevOrderPtr
->Data
[Index
] & 0xFF00) == 0xFF00) {
1107 // LocalBbsTable[DevIndex[Index] & 0xFF].BootPriority = BBS_DISABLED_ENTRY;
1109 } else if (DevOrderPtr
->Data
[Index
] != BbsIndex
) {
1110 LocalBbsTable
[DevOrderPtr
->Data
[Index
]].BootPriority
= *Priority
;
1115 FreePool (DevOrder
);
1120 Print the BBS Table.
1122 @param LocalBbsTable The BBS table.
1123 @param BbsCount The count of entry in BBS table.
1126 LegacyBmPrintBbsTable (
1127 IN BBS_TABLE
*LocalBbsTable
,
1133 DEBUG ((DEBUG_INFO
, "\n"));
1134 DEBUG ((DEBUG_INFO
, " NO Prio bb/dd/ff cl/sc Type Stat segm:offs\n"));
1135 DEBUG ((DEBUG_INFO
, "=============================================\n"));
1136 for (Index
= 0; Index
< BbsCount
; Index
++) {
1137 if (!LegacyBmValidBbsEntry (&LocalBbsTable
[Index
])) {
1143 " %02x: %04x %02x/%02x/%02x %02x/%02x %04x %04x %04x:%04x\n",
1145 (UINTN
) LocalBbsTable
[Index
].BootPriority
,
1146 (UINTN
) LocalBbsTable
[Index
].Bus
,
1147 (UINTN
) LocalBbsTable
[Index
].Device
,
1148 (UINTN
) LocalBbsTable
[Index
].Function
,
1149 (UINTN
) LocalBbsTable
[Index
].Class
,
1150 (UINTN
) LocalBbsTable
[Index
].SubClass
,
1151 (UINTN
) LocalBbsTable
[Index
].DeviceType
,
1152 (UINTN
) * (UINT16
*) &LocalBbsTable
[Index
].StatusFlags
,
1153 (UINTN
) LocalBbsTable
[Index
].BootHandlerSegment
,
1154 (UINTN
) LocalBbsTable
[Index
].BootHandlerOffset
,
1155 (UINTN
) ((LocalBbsTable
[Index
].MfgStringSegment
<< 4) + LocalBbsTable
[Index
].MfgStringOffset
),
1156 (UINTN
) ((LocalBbsTable
[Index
].DescStringSegment
<< 4) + LocalBbsTable
[Index
].DescStringOffset
))
1160 DEBUG ((DEBUG_INFO
, "\n"));
1164 Set the boot priority for BBS entries based on boot option entry and boot order.
1166 @param BootOption The boot option is to be checked for refresh BBS table.
1168 @retval EFI_SUCCESS The boot priority for BBS entries is refreshed successfully.
1169 @retval EFI_NOT_FOUND BBS entries can't be found.
1170 @retval EFI_OUT_OF_RESOURCES Failed to get the legacy device boot order.
1173 LegacyBmRefreshBbsTableForBoot (
1174 IN EFI_BOOT_MANAGER_LOAD_OPTION
*BootOption
1181 HDD_INFO
*LocalHddInfo
;
1182 BBS_TABLE
*LocalBbsTable
;
1184 EFI_LEGACY_BIOS_PROTOCOL
*LegacyBios
;
1188 UINTN DeviceTypeCount
;
1189 UINTN DeviceTypeIndex
;
1190 EFI_BOOT_MANAGER_LOAD_OPTION
*Option
;
1195 LocalHddInfo
= NULL
;
1196 LocalBbsTable
= NULL
;
1197 DevType
= BBS_UNKNOWN
;
1199 Status
= gBS
->LocateProtocol (&gEfiLegacyBiosProtocolGuid
, NULL
, (VOID
**) &LegacyBios
);
1200 if (EFI_ERROR (Status
)) {
1204 Status
= LegacyBios
->GetBbsInfo (
1211 if (EFI_ERROR (Status
)) {
1216 // First, set all the present devices' boot priority to BBS_UNPRIORITIZED_ENTRY
1217 // We will set them according to the settings setup by user
1219 for (Index
= 0; Index
< BbsCount
; Index
++) {
1220 if (LegacyBmValidBbsEntry (&LocalBbsTable
[Index
])) {
1221 LocalBbsTable
[Index
].BootPriority
= BBS_UNPRIORITIZED_ENTRY
;
1225 // boot priority always starts at 0
1228 if ((DevicePathType (BootOption
->FilePath
) == BBS_DEVICE_PATH
) &&
1229 (DevicePathSubType (BootOption
->FilePath
) == BBS_BBS_DP
)) {
1231 // If BootOption stands for a legacy boot option, we prioritize the devices with the same type first.
1233 DevType
= LegacyBmDeviceType (BootOption
->FilePath
);
1234 BbsIndex
= ((LEGACY_BM_BOOT_OPTION_BBS_DATA
*) BootOption
->OptionalData
)->BbsIndex
;
1235 Status
= LegacyBmSetPriorityForSameTypeDev (
1241 if (EFI_ERROR (Status
)) {
1246 // we have to set the boot priority for other BBS entries with different device types
1248 Option
= EfiBootManagerGetLoadOptions (&OptionCount
, LoadOptionTypeBoot
);
1249 DeviceType
= AllocatePool (sizeof (UINT16
) * OptionCount
);
1250 ASSERT (DeviceType
!= NULL
);
1251 DeviceType
[0] = DevType
;
1252 DeviceTypeCount
= 1;
1253 for (Index
= 0; Index
< OptionCount
; Index
++) {
1254 if ((DevicePathType (Option
[Index
].FilePath
) != BBS_DEVICE_PATH
) ||
1255 (DevicePathSubType (Option
[Index
].FilePath
) != BBS_BBS_DP
)) {
1259 DevType
= LegacyBmDeviceType (Option
[Index
].FilePath
);
1260 for (DeviceTypeIndex
= 0; DeviceTypeIndex
< DeviceTypeCount
; DeviceTypeIndex
++) {
1261 if (DeviceType
[DeviceTypeIndex
] == DevType
) {
1265 if (DeviceTypeIndex
< DeviceTypeCount
) {
1267 // We don't want to process twice for a device type
1272 DeviceType
[DeviceTypeCount
] = DevType
;
1275 Status
= LegacyBmSetPriorityForSameTypeDev (
1282 EfiBootManagerFreeLoadOptions (Option
, OptionCount
);
1285 LegacyBmPrintBbsTable (LocalBbsTable
, BbsCount
);
1293 Boot the legacy system with the boot option.
1295 @param BootOption The legacy boot option which have BBS device path
1296 On return, BootOption->Status contains the boot status.
1297 EFI_UNSUPPORTED There is no legacybios protocol, do not support
1299 EFI_STATUS The status of LegacyBios->LegacyBoot ().
1304 IN EFI_BOOT_MANAGER_LOAD_OPTION
*BootOption
1308 EFI_LEGACY_BIOS_PROTOCOL
*LegacyBios
;
1310 Status
= gBS
->LocateProtocol (&gEfiLegacyBiosProtocolGuid
, NULL
, (VOID
**) &LegacyBios
);
1311 if (EFI_ERROR (Status
)) {
1313 // If no LegacyBios protocol we do not support legacy boot
1315 BootOption
->Status
= EFI_UNSUPPORTED
;
1319 // Notes: if we separate the int 19, then we don't need to refresh BBS
1321 Status
= LegacyBmRefreshBbsTableForBoot (BootOption
);
1322 if (EFI_ERROR (Status
)) {
1323 BootOption
->Status
= Status
;
1327 BootOption
->Status
= LegacyBios
->LegacyBoot (
1329 (BBS_BBS_DEVICE_PATH
*) BootOption
->FilePath
,
1330 BootOption
->OptionalDataSize
,
1331 BootOption
->OptionalData
1336 This function enumerates all the legacy boot options.
1338 @param BootOptionCount Return the legacy boot option count.
1340 @retval Pointer to the legacy boot option buffer.
1342 EFI_BOOT_MANAGER_LOAD_OPTION
*
1343 LegacyBmEnumerateAllBootOptions (
1344 UINTN
*BootOptionCount
1351 BBS_TABLE
*BbsTable
;
1352 EFI_LEGACY_BIOS_PROTOCOL
*LegacyBios
;
1354 EFI_BOOT_MANAGER_LOAD_OPTION
*BootOptions
;
1356 ASSERT (BootOptionCount
!= NULL
);
1359 *BootOptionCount
= 0;
1362 Status
= gBS
->LocateProtocol (&gEfiLegacyBiosProtocolGuid
, NULL
, (VOID
**) &LegacyBios
);
1363 if (EFI_ERROR (Status
)) {
1367 Status
= LegacyBios
->GetBbsInfo (
1374 if (EFI_ERROR (Status
)) {
1378 for (Index
= 0; Index
< BbsCount
; Index
++) {
1379 if (!LegacyBmValidBbsEntry (&BbsTable
[Index
])) {
1383 BootOptions
= ReallocatePool (
1384 sizeof (EFI_BOOT_MANAGER_LOAD_OPTION
) * (*BootOptionCount
),
1385 sizeof (EFI_BOOT_MANAGER_LOAD_OPTION
) * (*BootOptionCount
+ 1),
1388 ASSERT (BootOptions
!= NULL
);
1390 Status
= LegacyBmCreateLegacyBootOption (&BootOptions
[(*BootOptionCount
)++], &BbsTable
[Index
], Index
);
1391 ASSERT_EFI_ERROR (Status
);
1398 Return the index of the boot option in the boot option array.
1400 The function compares the Description, FilePath, OptionalData.
1402 @param Key The input boot option which is compared with.
1403 @param Array The input boot option array.
1404 @param Count The count of the input boot options.
1406 @retval The index of the input boot option in the array.
1410 LegacyBmFindBootOption (
1411 IN CONST EFI_BOOT_MANAGER_LOAD_OPTION
*Key
,
1412 IN CONST EFI_BOOT_MANAGER_LOAD_OPTION
*Array
,
1418 for (Index
= 0; Index
< Count
; Index
++) {
1419 if ((StrCmp (Key
->Description
, Array
[Index
].Description
) == 0) &&
1420 (CompareMem (Key
->FilePath
, Array
[Index
].FilePath
, GetDevicePathSize (Key
->FilePath
)) == 0) &&
1421 (Key
->OptionalDataSize
== Array
[Index
].OptionalDataSize
) &&
1422 (CompareMem (Key
->OptionalData
, Array
[Index
].OptionalData
, Key
->OptionalDataSize
) == 0)) {
1423 return (INTN
) Index
;
1431 Refresh all legacy boot options.
1436 LegacyBmRefreshAllBootOption (
1441 EFI_LEGACY_BIOS_PROTOCOL
*LegacyBios
;
1442 UINTN RootBridgeHandleCount
;
1443 EFI_HANDLE
*RootBridgeHandleBuffer
;
1445 EFI_HANDLE
*HandleBuffer
;
1446 UINTN RootBridgeIndex
;
1449 EFI_BOOT_MANAGER_LOAD_OPTION
*BootOptions
;
1450 UINTN BootOptionCount
;
1451 EFI_BOOT_MANAGER_LOAD_OPTION
*ExistingBootOptions
;
1452 UINTN ExistingBootOptionCount
;
1454 Status
= gBS
->LocateProtocol (&gEfiLegacyBiosProtocolGuid
, NULL
, (VOID
**) &LegacyBios
);
1455 if (EFI_ERROR (Status
)) {
1456 LegacyBmDeleteAllBootOptions ();
1459 PERF_START (NULL
, "LegacyBootOptionEnum", "BDS", 0);
1462 // Before enumerating the legacy boot option, we need to dispatch all the legacy option roms
1463 // to ensure the GetBbsInfo() counts all the legacy devices.
1465 gBS
->LocateHandleBuffer (
1467 &gEfiPciRootBridgeIoProtocolGuid
,
1469 &RootBridgeHandleCount
,
1470 &RootBridgeHandleBuffer
1472 for (RootBridgeIndex
= 0; RootBridgeIndex
< RootBridgeHandleCount
; RootBridgeIndex
++) {
1473 gBS
->ConnectController (RootBridgeHandleBuffer
[RootBridgeIndex
], NULL
, NULL
, FALSE
);
1474 gBS
->LocateHandleBuffer (
1476 &gEfiPciIoProtocolGuid
,
1481 for (Index
= 0; Index
< HandleCount
; Index
++) {
1483 // Start the thunk driver so that the legacy option rom gets dispatched.
1484 // Note: We don't directly call InstallPciRom because some thunk drivers
1485 // (e.g. BlockIo thunk driver) depend on the immediate result after dispatching
1487 Status
= LegacyBios
->CheckPciRom (
1489 HandleBuffer
[Index
],
1494 if (!EFI_ERROR (Status
)) {
1495 gBS
->ConnectController (HandleBuffer
[Index
], NULL
, NULL
, FALSE
);
1501 // Same algorithm pattern as the EfiBootManagerRefreshAllBootOption
1502 // Firstly delete the invalid legacy boot options,
1503 // then enumreate and save the newly appeared legacy boot options
1504 // the last step is legacy boot option special action to refresh the LegacyDevOrder variable
1506 LegacyBmDeleteAllInvalidBootOptions ();
1508 ExistingBootOptions
= EfiBootManagerGetLoadOptions (&ExistingBootOptionCount
, LoadOptionTypeBoot
);
1509 BootOptions
= LegacyBmEnumerateAllBootOptions (&BootOptionCount
);
1511 for (Index
= 0; Index
< BootOptionCount
; Index
++) {
1512 if (LegacyBmFindBootOption (&BootOptions
[Index
], ExistingBootOptions
, ExistingBootOptionCount
) == -1) {
1513 Status
= EfiBootManagerAddLoadOptionVariable (&BootOptions
[Index
], (UINTN
) -1);
1515 EFI_D_INFO
, "[LegacyBds] New Boot Option: Boot%04x Bbs0x%04x %s %r\n",
1516 (UINTN
) BootOptions
[Index
].OptionNumber
,
1517 (UINTN
) ((LEGACY_BM_BOOT_OPTION_BBS_DATA
*) BootOptions
[Index
].OptionalData
)->BbsIndex
,
1518 BootOptions
[Index
].Description
,
1522 // Continue upon failure to add boot option.
1527 EfiBootManagerFreeLoadOptions (ExistingBootOptions
, ExistingBootOptionCount
);
1528 EfiBootManagerFreeLoadOptions (BootOptions
, BootOptionCount
);
1531 // Failure to create LegacyDevOrder variable only impacts the boot order.
1533 LegacyBmUpdateDevOrder ();
1535 PERF_END (NULL
, "LegacyBootOptionEnum", "BDS", 0);