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 - 2018, Intel Corporation. All rights reserved.<BR>
7 SPDX-License-Identifier: BSD-2-Clause-Patent
11 #include "InternalLegacyBm.h"
13 #define LEGACY_BM_BOOT_DESCRIPTION_LENGTH 32
16 Initialize legacy boot manager library by call EfiBootManagerRegisterLegacyBootSupport
17 function to export two function pointer.
19 @param ImageHandle The image handle.
20 @param SystemTable The system table.
22 @retval EFI_SUCCESS The legacy boot manager library is initialized correctly.
23 @return Other value if failed to initialize the legacy boot manager library.
27 LegacyBootManagerLibConstructor (
28 IN EFI_HANDLE ImageHandle
,
29 IN EFI_SYSTEM_TABLE
*SystemTable
32 EfiBootManagerRegisterLegacyBootSupport (
33 LegacyBmRefreshAllBootOption
,
40 Get the device type from the input legacy device path.
42 @param DevicePath The legacy device path.
44 @retval The legacy device type.
48 EFI_DEVICE_PATH_PROTOCOL
*DevicePath
52 (DevicePathType (DevicePath
) == BBS_DEVICE_PATH
) &&
53 (DevicePathSubType (DevicePath
) == BBS_BBS_DP
)
55 return ((BBS_BBS_DEVICE_PATH
*)DevicePath
)->DeviceType
;
59 Validate the BbsEntry base on the Boot Priority info in the BbsEntry.
61 @param BbsEntry The input bbs entry info.
63 @retval TRUE The BbsEntry is valid.
64 @retval FALSE The BbsEntry is invalid.
67 LegacyBmValidBbsEntry (
68 IN BBS_TABLE
*BbsEntry
71 switch (BbsEntry
->BootPriority
) {
72 case BBS_IGNORE_ENTRY
:
73 case BBS_DO_NOT_BOOT_FROM
:
74 case BBS_LOWEST_PRIORITY
:
82 Build Legacy Device Name String according.
84 @param CurBBSEntry BBS Table.
86 @param BufSize The buffer size.
87 @param BootString The output string.
91 LegacyBmBuildLegacyDevNameString (
92 IN BBS_TABLE
*CurBBSEntry
,
95 OUT CHAR16
*BootString
101 CHAR8 StringBufferA
[LEGACY_BM_BOOT_DESCRIPTION_LENGTH
+ 1];
102 CHAR16 StringBufferU
[LEGACY_BM_BOOT_DESCRIPTION_LENGTH
+ 1];
109 Fmt
= L
"Primary Master %s";
116 Fmt
= L
"Primary Slave %s";
123 Fmt
= L
"Secondary Master %s";
130 Fmt
= L
"Secondary Slave %s";
138 switch (CurBBSEntry
->DeviceType
) {
159 case BBS_EMBED_NETWORK
:
174 // If current BBS entry has its description then use it.
176 StringDesc
= (CHAR8
*)(((UINTN
)CurBBSEntry
->DescStringSegment
<< 4) + CurBBSEntry
->DescStringOffset
);
177 if (NULL
!= StringDesc
) {
179 // Only get first 32 characters, this is suggested by BBS spec
181 CopyMem (StringBufferA
, StringDesc
, LEGACY_BM_BOOT_DESCRIPTION_LENGTH
);
182 StringBufferA
[LEGACY_BM_BOOT_DESCRIPTION_LENGTH
] = 0;
183 AsciiStrToUnicodeStrS (StringBufferA
, StringBufferU
, ARRAY_SIZE (StringBufferU
));
185 Type
= StringBufferU
;
189 // BbsTable 16 entries are for onboard IDE.
190 // Set description string for SATA harddisks, Harddisk 0 ~ Harddisk 11
192 if ((Index
>= 5) && (Index
<= 16) && ((CurBBSEntry
->DeviceType
== BBS_HARDDISK
) || (CurBBSEntry
->DeviceType
== BBS_CDROM
))) {
194 UnicodeSPrint (BootString
, BufSize
, Fmt
, Type
, Index
- 5);
196 UnicodeSPrint (BootString
, BufSize
, Fmt
, Type
);
201 Get the Bbs index for the input boot option.
203 @param BootOption The input boot option info.
204 @param BbsTable The input Bbs table.
205 @param BbsCount The input total bbs entry number.
206 @param BbsIndexUsed The array shows how many BBS table indexs have been used.
208 @retval The index for the input boot option.
212 EFI_BOOT_MANAGER_LOAD_OPTION
*BootOption
,
215 BOOLEAN
*BbsIndexUsed
219 LEGACY_BM_BOOT_OPTION_BBS_DATA
*BbsData
;
220 CHAR16 Description
[LEGACY_BM_BOOT_DESCRIPTION_LENGTH
+ 1];
222 BbsData
= (LEGACY_BM_BOOT_OPTION_BBS_DATA
*)BootOption
->OptionalData
;
225 // Directly check the BBS index stored in BootOption
227 if ((BbsData
->BbsIndex
< BbsCount
) &&
228 (LegacyBmDeviceType (BootOption
->FilePath
) == BbsTable
[BbsData
->BbsIndex
].DeviceType
))
230 LegacyBmBuildLegacyDevNameString (
231 &BbsTable
[BbsData
->BbsIndex
],
233 sizeof (Description
),
236 if ((StrCmp (Description
, BootOption
->Description
) == 0) && !BbsIndexUsed
[BbsData
->BbsIndex
]) {
238 // If devices with the same description string are connected,
239 // the BbsIndex of the first device is returned for the other device also.
240 // So, check if the BbsIndex is already being used, before assigning the BbsIndex.
242 BbsIndexUsed
[BbsData
->BbsIndex
] = TRUE
;
243 return BbsData
->BbsIndex
;
248 // BBS table could be changed (entry removed/moved)
249 // find the correct BBS index
251 for (Index
= 0; Index
< BbsCount
; Index
++) {
252 if (!LegacyBmValidBbsEntry (&BbsTable
[Index
]) ||
253 (BbsTable
[Index
].DeviceType
!= LegacyBmDeviceType (BootOption
->FilePath
)))
258 LegacyBmBuildLegacyDevNameString (
261 sizeof (Description
),
264 if ((StrCmp (Description
, BootOption
->Description
) == 0) && !BbsIndexUsed
[Index
]) {
266 // If devices with the same description string are connected,
267 // the BbsIndex of the first device is assigned for the other device also.
268 // So, check if the BbsIndex is already being used, before assigning the corrected BbsIndex.
275 // Add the corrected BbsIndex in the UsedBbsIndex Buffer
277 if (Index
!= BbsCount
) {
278 BbsIndexUsed
[Index
] = TRUE
;
286 Update legacy device order base on the input info.
288 @param LegacyDevOrder Legacy device order data buffer.
289 @param LegacyDevOrderSize Legacy device order data buffer size.
290 @param DeviceType Device type which need to check.
291 @param OldBbsIndex Old Bds Index.
292 @param NewBbsIndex New Bds Index, if it is -1,means remove this option.
296 LegacyBmUpdateBbsIndex (
297 LEGACY_DEV_ORDER_ENTRY
*LegacyDevOrder
,
298 UINTN
*LegacyDevOrderSize
,
301 UINT16 NewBbsIndex
// Delete entry if -1
304 LEGACY_DEV_ORDER_ENTRY
*Entry
;
308 ((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
)
317 if (Entry
->BbsType
== DeviceType
) {
318 for (Index
= 0; Index
< Entry
->Length
/ sizeof (UINT16
) - 1; Index
++) {
319 if (Entry
->Data
[Index
] == OldBbsIndex
) {
320 if (NewBbsIndex
== (UINT16
)-1) {
322 // Delete the old entry
326 &Entry
->Data
[Index
+ 1],
327 (UINT8
*)LegacyDevOrder
+ *LegacyDevOrderSize
- (UINT8
*)&Entry
->Data
[Index
+ 1]
329 Entry
->Length
-= sizeof (UINT16
);
330 *LegacyDevOrderSize
-= sizeof (UINT16
);
332 Entry
->Data
[Index
] = NewBbsIndex
;
345 Delete all the legacy boot options.
347 @retval EFI_SUCCESS All legacy boot options are deleted.
350 LegacyBmDeleteAllBootOptions (
356 EFI_BOOT_MANAGER_LOAD_OPTION
*BootOption
;
357 UINTN BootOptionCount
;
359 BootOption
= EfiBootManagerGetLoadOptions (&BootOptionCount
, LoadOptionTypeBoot
);
360 for (Index
= 0; Index
< BootOptionCount
; Index
++) {
361 if ((DevicePathType (BootOption
[Index
].FilePath
) == BBS_DEVICE_PATH
) &&
362 (DevicePathSubType (BootOption
[Index
].FilePath
) == BBS_BBS_DP
))
364 Status
= EfiBootManagerDeleteLoadOptionVariable (BootOption
[Index
].OptionNumber
, BootOption
[Index
].OptionType
);
366 // Deleting variable with current variable implementation shouldn't fail.
368 ASSERT_EFI_ERROR (Status
);
372 Status
= gRT
->SetVariable (
373 VAR_LEGACY_DEV_ORDER
,
374 &gEfiLegacyDevOrderVariableGuid
,
380 // Deleting variable with current variable implementation shouldn't fail.
382 ASSERT (Status
== EFI_SUCCESS
|| Status
== EFI_NOT_FOUND
);
388 Delete all the invalid legacy boot options.
390 @retval EFI_SUCCESS All invalid legacy boot options are deleted.
391 @retval EFI_OUT_OF_RESOURCES Fail to allocate necessary memory.
392 @retval EFI_NOT_FOUND Fail to retrieve variable of boot order.
395 LegacyBmDeleteAllInvalidBootOptions (
405 EFI_LEGACY_BIOS_PROTOCOL
*LegacyBios
;
407 EFI_BOOT_MANAGER_LOAD_OPTION
*BootOption
;
408 UINTN BootOptionCount
;
409 LEGACY_DEV_ORDER_ENTRY
*LegacyDevOrder
;
410 UINTN LegacyDevOrderSize
;
411 BOOLEAN
*BbsIndexUsed
;
418 Status
= gBS
->LocateProtocol (&gEfiLegacyBiosProtocolGuid
, NULL
, (VOID
**)&LegacyBios
);
419 if (EFI_ERROR (Status
)) {
423 Status
= LegacyBios
->GetBbsInfo (
430 if (EFI_ERROR (Status
)) {
434 GetVariable2 (VAR_LEGACY_DEV_ORDER
, &gEfiLegacyDevOrderVariableGuid
, (VOID
**)&LegacyDevOrder
, &LegacyDevOrderSize
);
436 BootOption
= EfiBootManagerGetLoadOptions (&BootOptionCount
, LoadOptionTypeBoot
);
438 BbsIndexUsed
= AllocateZeroPool (BbsCount
* sizeof (BOOLEAN
));
439 ASSERT (BbsIndexUsed
!= NULL
);
441 for (Index
= 0; Index
< BootOptionCount
; Index
++) {
443 // Skip non legacy boot option
445 if ((DevicePathType (BootOption
[Index
].FilePath
) != BBS_DEVICE_PATH
) ||
446 (DevicePathSubType (BootOption
[Index
].FilePath
) != BBS_BBS_DP
))
451 BbsIndex
= LegacyBmFuzzyMatch (&BootOption
[Index
], BbsTable
, BbsCount
, BbsIndexUsed
);
452 if (BbsIndex
== BbsCount
) {
453 DEBUG ((DEBUG_INFO
, "[LegacyBds] Delete Boot Option Boot%04x: %s\n", (UINTN
)BootOption
[Index
].OptionNumber
, BootOption
[Index
].Description
));
455 // Delete entry from LegacyDevOrder
457 LegacyBmUpdateBbsIndex (
460 LegacyBmDeviceType (BootOption
[Index
].FilePath
),
461 ((LEGACY_BM_BOOT_OPTION_BBS_DATA
*)BootOption
[Index
].OptionalData
)->BbsIndex
,
464 EfiBootManagerDeleteLoadOptionVariable (BootOption
[Index
].OptionNumber
, BootOption
[Index
].OptionType
);
466 if (((LEGACY_BM_BOOT_OPTION_BBS_DATA
*)BootOption
[Index
].OptionalData
)->BbsIndex
!= BbsIndex
) {
469 "[LegacyBds] Update Boot Option Boot%04x: %s Bbs0x%04x->Bbs0x%04x\n",
470 (UINTN
)BootOption
[Index
].OptionNumber
,
471 BootOption
[Index
].Description
,
472 (UINTN
)((LEGACY_BM_BOOT_OPTION_BBS_DATA
*)BootOption
[Index
].OptionalData
)->BbsIndex
,
476 // Update the BBS index in LegacyDevOrder
478 LegacyBmUpdateBbsIndex (
481 LegacyBmDeviceType (BootOption
[Index
].FilePath
),
482 ((LEGACY_BM_BOOT_OPTION_BBS_DATA
*)BootOption
[Index
].OptionalData
)->BbsIndex
,
487 // Update the OptionalData in the Boot#### variable
489 ((LEGACY_BM_BOOT_OPTION_BBS_DATA
*)BootOption
[Index
].OptionalData
)->BbsIndex
= BbsIndex
;
490 EfiBootManagerLoadOptionToVariable (&BootOption
[Index
]);
495 EfiBootManagerFreeLoadOptions (BootOption
, BootOptionCount
);
497 if (LegacyDevOrder
!= NULL
) {
498 Status
= gRT
->SetVariable (
499 VAR_LEGACY_DEV_ORDER
,
500 &gEfiLegacyDevOrderVariableGuid
,
501 EFI_VARIABLE_BOOTSERVICE_ACCESS
| EFI_VARIABLE_NON_VOLATILE
,
506 // Shrink variable with current variable implementation shouldn't fail.
508 ASSERT_EFI_ERROR (Status
);
510 FreePool (LegacyDevOrder
);
513 FreePool (BbsIndexUsed
);
518 Create legacy boot option.
520 @param BootOption Pointer to the boot option which will be crated.
521 @param BbsEntry The input bbs entry info.
522 @param BbsIndex The BBS index.
524 @retval EFI_SUCCESS Create legacy boot option successfully.
525 @retval EFI_INVALID_PARAMETER Invalid input parameter.
529 LegacyBmCreateLegacyBootOption (
530 IN OUT EFI_BOOT_MANAGER_LOAD_OPTION
*BootOption
,
531 IN BBS_TABLE
*BbsEntry
,
536 EFI_DEVICE_PATH_PROTOCOL
*DevicePath
;
537 CHAR16 Description
[LEGACY_BM_BOOT_DESCRIPTION_LENGTH
+ 1];
538 CHAR8 HelpString
[LEGACY_BM_BOOT_DESCRIPTION_LENGTH
+ 1];
540 LEGACY_BM_BOOT_OPTION_BBS_DATA
*OptionalData
;
541 BBS_BBS_DEVICE_PATH
*BbsNode
;
543 if ((BootOption
== NULL
) || (BbsEntry
== NULL
)) {
544 return EFI_INVALID_PARAMETER
;
547 LegacyBmBuildLegacyDevNameString (BbsEntry
, BbsIndex
, sizeof (Description
), Description
);
550 // Create the BBS device path with description string
552 UnicodeStrToAsciiStrS (Description
, HelpString
, sizeof (HelpString
));
553 StringLen
= AsciiStrLen (HelpString
);
554 DevicePath
= AllocatePool (sizeof (BBS_BBS_DEVICE_PATH
) + StringLen
+ END_DEVICE_PATH_LENGTH
);
555 ASSERT (DevicePath
!= NULL
);
557 BbsNode
= (BBS_BBS_DEVICE_PATH
*)DevicePath
;
558 SetDevicePathNodeLength (BbsNode
, sizeof (BBS_BBS_DEVICE_PATH
) + StringLen
);
559 BbsNode
->Header
.Type
= BBS_DEVICE_PATH
;
560 BbsNode
->Header
.SubType
= BBS_BBS_DP
;
561 BbsNode
->DeviceType
= BbsEntry
->DeviceType
;
562 CopyMem (&BbsNode
->StatusFlag
, &BbsEntry
->StatusFlags
, sizeof (BBS_STATUS_FLAGS
));
563 CopyMem (BbsNode
->String
, HelpString
, StringLen
+ 1);
565 SetDevicePathEndNode (NextDevicePathNode (BbsNode
));
568 // Create the OptionalData
570 OptionalData
= AllocatePool (sizeof (LEGACY_BM_BOOT_OPTION_BBS_DATA
));
571 ASSERT (OptionalData
!= NULL
);
572 OptionalData
->BbsIndex
= BbsIndex
;
575 // Create the BootOption
577 Status
= EfiBootManagerInitializeLoadOption (
579 LoadOptionNumberUnassigned
,
584 (UINT8
*)OptionalData
,
585 sizeof (LEGACY_BM_BOOT_OPTION_BBS_DATA
)
587 FreePool (DevicePath
);
588 FreePool (OptionalData
);
594 Fill the device order buffer.
596 @param BbsTable The BBS table.
597 @param BbsType The BBS Type.
598 @param BbsCount The BBS Count.
599 @param Buf device order buffer.
601 @return The device order buffer.
605 LegacyBmFillDevOrderBuf (
606 IN BBS_TABLE
*BbsTable
,
614 for (Index
= 0; Index
< BbsCount
; Index
++) {
615 if (!LegacyBmValidBbsEntry (&BbsTable
[Index
])) {
619 if (BbsTable
[Index
].DeviceType
!= BbsType
) {
623 *Buf
= (UINT16
)(Index
& 0xFF);
631 Create the device order buffer.
633 @param BbsTable The BBS table.
634 @param BbsCount The BBS Count.
636 @retval EFI_SUCCESS The buffer is created and the EFI variable named
637 VAR_LEGACY_DEV_ORDER and EfiLegacyDevOrderGuid is
639 @retval EFI_OUT_OF_RESOURCES Memory or storage is not enough.
640 @retval EFI_DEVICE_ERROR Fail to add the device order into EFI variable fail
641 because of hardware error.
644 LegacyBmCreateDevOrder (
645 IN BBS_TABLE
*BbsTable
,
657 LEGACY_DEV_ORDER_ENTRY
*DevOrder
;
658 LEGACY_DEV_ORDER_ENTRY
*DevOrderPtr
;
667 HeaderSize
= sizeof (BBS_TYPE
) + sizeof (UINT16
);
669 Status
= EFI_SUCCESS
;
672 // Count all boot devices
674 for (Index
= 0; Index
< BbsCount
; Index
++) {
675 if (!LegacyBmValidBbsEntry (&BbsTable
[Index
])) {
679 switch (BbsTable
[Index
].DeviceType
) {
692 case BBS_EMBED_NETWORK
:
705 TotalSize
+= (HeaderSize
+ sizeof (UINT16
) * FDCount
);
706 TotalSize
+= (HeaderSize
+ sizeof (UINT16
) * HDCount
);
707 TotalSize
+= (HeaderSize
+ sizeof (UINT16
) * CDCount
);
708 TotalSize
+= (HeaderSize
+ sizeof (UINT16
) * NETCount
);
709 TotalSize
+= (HeaderSize
+ sizeof (UINT16
) * BEVCount
);
712 // Create buffer to hold all boot device order
714 DevOrder
= AllocateZeroPool (TotalSize
);
715 if (NULL
== DevOrder
) {
716 return EFI_OUT_OF_RESOURCES
;
719 DevOrderPtr
= DevOrder
;
721 DevOrderPtr
->BbsType
= BBS_FLOPPY
;
722 DevOrderPtr
->Length
= (UINT16
)(sizeof (DevOrderPtr
->Length
) + FDCount
* sizeof (UINT16
));
723 DevOrderPtr
= (LEGACY_DEV_ORDER_ENTRY
*)LegacyBmFillDevOrderBuf (BbsTable
, BBS_FLOPPY
, BbsCount
, DevOrderPtr
->Data
);
725 DevOrderPtr
->BbsType
= BBS_HARDDISK
;
726 DevOrderPtr
->Length
= (UINT16
)(sizeof (UINT16
) + HDCount
* sizeof (UINT16
));
727 DevOrderPtr
= (LEGACY_DEV_ORDER_ENTRY
*)LegacyBmFillDevOrderBuf (BbsTable
, BBS_HARDDISK
, BbsCount
, DevOrderPtr
->Data
);
729 DevOrderPtr
->BbsType
= BBS_CDROM
;
730 DevOrderPtr
->Length
= (UINT16
)(sizeof (UINT16
) + CDCount
* sizeof (UINT16
));
731 DevOrderPtr
= (LEGACY_DEV_ORDER_ENTRY
*)LegacyBmFillDevOrderBuf (BbsTable
, BBS_CDROM
, BbsCount
, DevOrderPtr
->Data
);
733 DevOrderPtr
->BbsType
= BBS_EMBED_NETWORK
;
734 DevOrderPtr
->Length
= (UINT16
)(sizeof (UINT16
) + NETCount
* sizeof (UINT16
));
735 DevOrderPtr
= (LEGACY_DEV_ORDER_ENTRY
*)LegacyBmFillDevOrderBuf (BbsTable
, BBS_EMBED_NETWORK
, BbsCount
, DevOrderPtr
->Data
);
737 DevOrderPtr
->BbsType
= BBS_BEV_DEVICE
;
738 DevOrderPtr
->Length
= (UINT16
)(sizeof (UINT16
) + BEVCount
* sizeof (UINT16
));
739 DevOrderPtr
= (LEGACY_DEV_ORDER_ENTRY
*)LegacyBmFillDevOrderBuf (BbsTable
, BBS_BEV_DEVICE
, BbsCount
, DevOrderPtr
->Data
);
741 ASSERT (TotalSize
== ((UINTN
)DevOrderPtr
- (UINTN
)DevOrder
));
744 // Save device order for legacy boot device to variable.
746 Status
= gRT
->SetVariable (
747 VAR_LEGACY_DEV_ORDER
,
748 &gEfiLegacyDevOrderVariableGuid
,
749 EFI_VARIABLE_BOOTSERVICE_ACCESS
| EFI_VARIABLE_NON_VOLATILE
,
759 Add the legacy boot devices from BBS table into
760 the legacy device boot order.
762 @retval EFI_SUCCESS The boot devices are added successfully.
763 @retval EFI_NOT_FOUND The legacy boot devices are not found.
764 @retval EFI_OUT_OF_RESOURCES Memory or storage is not enough.
765 @retval EFI_DEVICE_ERROR Fail to add the legacy device boot order into EFI variable
766 because of hardware error.
769 LegacyBmUpdateDevOrder (
773 LEGACY_DEV_ORDER_ENTRY
*DevOrder
;
774 LEGACY_DEV_ORDER_ENTRY
*NewDevOrder
;
775 LEGACY_DEV_ORDER_ENTRY
*Ptr
;
776 LEGACY_DEV_ORDER_ENTRY
*NewPtr
;
777 EFI_LEGACY_BIOS_PROTOCOL
*LegacyBios
;
781 HDD_INFO
*LocalHddInfo
;
782 BBS_TABLE
*LocalBbsTable
;
812 HeaderSize
= sizeof (BBS_TYPE
) + sizeof (UINT16
);
820 Status
= gBS
->LocateProtocol (&gEfiLegacyBiosProtocolGuid
, NULL
, (VOID
**)&LegacyBios
);
821 if (EFI_ERROR (Status
)) {
825 Status
= LegacyBios
->GetBbsInfo (
832 if (EFI_ERROR (Status
)) {
836 GetVariable2 (VAR_LEGACY_DEV_ORDER
, &gEfiLegacyDevOrderVariableGuid
, (VOID
**)&DevOrder
, NULL
);
837 if (NULL
== DevOrder
) {
838 return LegacyBmCreateDevOrder (LocalBbsTable
, BbsCount
);
842 // First we figure out how many boot devices with same device type respectively
844 for (Index
= 0; Index
< BbsCount
; Index
++) {
845 if (!LegacyBmValidBbsEntry (&LocalBbsTable
[Index
])) {
849 switch (LocalBbsTable
[Index
].DeviceType
) {
862 case BBS_EMBED_NETWORK
:
875 TotalSize
+= (HeaderSize
+ FDCount
* sizeof (UINT16
));
876 TotalSize
+= (HeaderSize
+ HDCount
* sizeof (UINT16
));
877 TotalSize
+= (HeaderSize
+ CDCount
* sizeof (UINT16
));
878 TotalSize
+= (HeaderSize
+ NETCount
* sizeof (UINT16
));
879 TotalSize
+= (HeaderSize
+ BEVCount
* sizeof (UINT16
));
881 NewDevOrder
= AllocateZeroPool (TotalSize
);
882 if (NULL
== NewDevOrder
) {
883 return EFI_OUT_OF_RESOURCES
;
890 NewPtr
= NewDevOrder
;
891 NewPtr
->BbsType
= Ptr
->BbsType
;
892 NewPtr
->Length
= (UINT16
)(sizeof (UINT16
) + FDCount
* sizeof (UINT16
));
893 for (Index
= 0; Index
< Ptr
->Length
/ sizeof (UINT16
) - 1; Index
++) {
894 if (!LegacyBmValidBbsEntry (&LocalBbsTable
[Ptr
->Data
[Index
] & 0xFF]) ||
895 (LocalBbsTable
[Ptr
->Data
[Index
] & 0xFF].DeviceType
!= BBS_FLOPPY
)
901 NewPtr
->Data
[FDIndex
] = Ptr
->Data
[Index
];
905 NewFDPtr
= NewPtr
->Data
;
910 Ptr
= (LEGACY_DEV_ORDER_ENTRY
*)(&Ptr
->Data
[Ptr
->Length
/ sizeof (UINT16
) - 1]);
911 NewPtr
= (LEGACY_DEV_ORDER_ENTRY
*)(&NewPtr
->Data
[NewPtr
->Length
/ sizeof (UINT16
) -1]);
912 NewPtr
->BbsType
= Ptr
->BbsType
;
913 NewPtr
->Length
= (UINT16
)(sizeof (UINT16
) + HDCount
* sizeof (UINT16
));
914 for (Index
= 0; Index
< Ptr
->Length
/ sizeof (UINT16
) - 1; Index
++) {
915 if (!LegacyBmValidBbsEntry (&LocalBbsTable
[Ptr
->Data
[Index
] & 0xFF]) ||
916 (LocalBbsTable
[Ptr
->Data
[Index
] & 0xFF].DeviceType
!= BBS_HARDDISK
)
922 NewPtr
->Data
[HDIndex
] = Ptr
->Data
[Index
];
926 NewHDPtr
= NewPtr
->Data
;
931 Ptr
= (LEGACY_DEV_ORDER_ENTRY
*)(&Ptr
->Data
[Ptr
->Length
/ sizeof (UINT16
) - 1]);
932 NewPtr
= (LEGACY_DEV_ORDER_ENTRY
*)(&NewPtr
->Data
[NewPtr
->Length
/ sizeof (UINT16
) -1]);
933 NewPtr
->BbsType
= Ptr
->BbsType
;
934 NewPtr
->Length
= (UINT16
)(sizeof (UINT16
) + CDCount
* sizeof (UINT16
));
935 for (Index
= 0; Index
< Ptr
->Length
/ sizeof (UINT16
) - 1; Index
++) {
936 if (!LegacyBmValidBbsEntry (&LocalBbsTable
[Ptr
->Data
[Index
] & 0xFF]) ||
937 (LocalBbsTable
[Ptr
->Data
[Index
] & 0xFF].DeviceType
!= BBS_CDROM
)
943 NewPtr
->Data
[CDIndex
] = Ptr
->Data
[Index
];
947 NewCDPtr
= NewPtr
->Data
;
952 Ptr
= (LEGACY_DEV_ORDER_ENTRY
*)(&Ptr
->Data
[Ptr
->Length
/ sizeof (UINT16
) - 1]);
953 NewPtr
= (LEGACY_DEV_ORDER_ENTRY
*)(&NewPtr
->Data
[NewPtr
->Length
/ sizeof (UINT16
) -1]);
954 NewPtr
->BbsType
= Ptr
->BbsType
;
955 NewPtr
->Length
= (UINT16
)(sizeof (UINT16
) + NETCount
* sizeof (UINT16
));
956 for (Index
= 0; Index
< Ptr
->Length
/ sizeof (UINT16
) - 1; Index
++) {
957 if (!LegacyBmValidBbsEntry (&LocalBbsTable
[Ptr
->Data
[Index
] & 0xFF]) ||
958 (LocalBbsTable
[Ptr
->Data
[Index
] & 0xFF].DeviceType
!= BBS_EMBED_NETWORK
)
964 NewPtr
->Data
[NETIndex
] = Ptr
->Data
[Index
];
968 NewNETPtr
= NewPtr
->Data
;
973 Ptr
= (LEGACY_DEV_ORDER_ENTRY
*)(&Ptr
->Data
[Ptr
->Length
/ sizeof (UINT16
) - 1]);
974 NewPtr
= (LEGACY_DEV_ORDER_ENTRY
*)(&NewPtr
->Data
[NewPtr
->Length
/ sizeof (UINT16
) -1]);
975 NewPtr
->BbsType
= Ptr
->BbsType
;
976 NewPtr
->Length
= (UINT16
)(sizeof (UINT16
) + BEVCount
* sizeof (UINT16
));
977 for (Index
= 0; Index
< Ptr
->Length
/ sizeof (UINT16
) - 1; Index
++) {
978 if (!LegacyBmValidBbsEntry (&LocalBbsTable
[Ptr
->Data
[Index
] & 0xFF]) ||
979 (LocalBbsTable
[Ptr
->Data
[Index
] & 0xFF].DeviceType
!= BBS_BEV_DEVICE
)
985 NewPtr
->Data
[BEVIndex
] = Ptr
->Data
[Index
];
989 NewBEVPtr
= NewPtr
->Data
;
991 for (Index
= 0; Index
< BbsCount
; Index
++) {
992 if (!LegacyBmValidBbsEntry (&LocalBbsTable
[Index
])) {
996 switch (LocalBbsTable
[Index
].DeviceType
) {
999 NewDevPtr
= NewFDPtr
;
1004 NewDevPtr
= NewHDPtr
;
1009 NewDevPtr
= NewCDPtr
;
1012 case BBS_EMBED_NETWORK
:
1014 NewDevPtr
= NewNETPtr
;
1017 case BBS_BEV_DEVICE
:
1019 NewDevPtr
= NewBEVPtr
;
1028 // at this point we have copied those valid indexes to new buffer
1029 // and we should check if there is any new appeared boot device
1032 for (Index2
= 0; Index2
< *Idx
; Index2
++) {
1033 if ((NewDevPtr
[Index2
] & 0xFF) == (UINT16
)Index
) {
1038 if (Index2
== *Idx
) {
1040 // Index2 == *Idx means we didn't find Index
1041 // so Index is a new appeared device's index in BBS table
1042 // insert it before disabled indexes.
1044 for (Index2
= 0; Index2
< *Idx
; Index2
++) {
1045 if ((NewDevPtr
[Index2
] & 0xFF00) == 0xFF00) {
1050 CopyMem (&NewDevPtr
[Index2
+ 1], &NewDevPtr
[Index2
], (*Idx
- Index2
) * sizeof (UINT16
));
1051 NewDevPtr
[Index2
] = (UINT16
)(Index
& 0xFF);
1057 FreePool (DevOrder
);
1059 Status
= gRT
->SetVariable (
1060 VAR_LEGACY_DEV_ORDER
,
1061 &gEfiLegacyDevOrderVariableGuid
,
1062 EFI_VARIABLE_BOOTSERVICE_ACCESS
| EFI_VARIABLE_NON_VOLATILE
,
1066 FreePool (NewDevOrder
);
1072 Set Boot Priority for specified device type.
1074 @param DeviceType The device type.
1075 @param BbsIndex The BBS index to set the highest priority. Ignore when -1.
1076 @param LocalBbsTable The BBS table.
1077 @param Priority The priority table.
1079 @retval EFI_SUCCESS The function completes successfully.
1080 @retval EFI_NOT_FOUND Failed to find device.
1081 @retval EFI_OUT_OF_RESOURCES Failed to get the efi variable of device order.
1085 LegacyBmSetPriorityForSameTypeDev (
1086 IN UINT16 DeviceType
,
1088 IN OUT BBS_TABLE
*LocalBbsTable
,
1089 IN OUT UINT16
*Priority
1092 LEGACY_DEV_ORDER_ENTRY
*DevOrder
;
1093 LEGACY_DEV_ORDER_ENTRY
*DevOrderPtr
;
1097 GetVariable2 (VAR_LEGACY_DEV_ORDER
, &gEfiLegacyDevOrderVariableGuid
, (VOID
**)&DevOrder
, &DevOrderSize
);
1098 if (NULL
== DevOrder
) {
1099 return EFI_OUT_OF_RESOURCES
;
1102 DevOrderPtr
= DevOrder
;
1103 while ((UINT8
*)DevOrderPtr
< (UINT8
*)DevOrder
+ DevOrderSize
) {
1104 if (DevOrderPtr
->BbsType
== DeviceType
) {
1108 DevOrderPtr
= (LEGACY_DEV_ORDER_ENTRY
*)((UINTN
)DevOrderPtr
+ sizeof (BBS_TYPE
) + DevOrderPtr
->Length
);
1111 if ((UINT8
*)DevOrderPtr
>= (UINT8
*)DevOrder
+ DevOrderSize
) {
1112 FreePool (DevOrder
);
1113 return EFI_NOT_FOUND
;
1116 if (BbsIndex
!= (UINTN
)-1) {
1118 // In case the BBS entry isn't valid because devices were plugged or removed.
1120 if (!LegacyBmValidBbsEntry (&LocalBbsTable
[BbsIndex
]) || (LocalBbsTable
[BbsIndex
].DeviceType
!= DeviceType
)) {
1121 FreePool (DevOrder
);
1122 return EFI_NOT_FOUND
;
1125 LocalBbsTable
[BbsIndex
].BootPriority
= *Priority
;
1130 // If the high byte of the DevIndex is 0xFF, it indicates that this device has been disabled.
1132 for (Index
= 0; Index
< DevOrderPtr
->Length
/ sizeof (UINT16
) - 1; Index
++) {
1133 if ((DevOrderPtr
->Data
[Index
] & 0xFF00) == 0xFF00) {
1135 // LocalBbsTable[DevIndex[Index] & 0xFF].BootPriority = BBS_DISABLED_ENTRY;
1137 } else if (DevOrderPtr
->Data
[Index
] != BbsIndex
) {
1138 LocalBbsTable
[DevOrderPtr
->Data
[Index
]].BootPriority
= *Priority
;
1143 FreePool (DevOrder
);
1148 Print the BBS Table.
1150 @param LocalBbsTable The BBS table.
1151 @param BbsCount The count of entry in BBS table.
1154 LegacyBmPrintBbsTable (
1155 IN BBS_TABLE
*LocalBbsTable
,
1161 DEBUG ((DEBUG_INFO
, "\n"));
1162 DEBUG ((DEBUG_INFO
, " NO Prio bb/dd/ff cl/sc Type Stat segm:offs\n"));
1163 DEBUG ((DEBUG_INFO
, "=============================================\n"));
1164 for (Index
= 0; Index
< BbsCount
; Index
++) {
1165 if (!LegacyBmValidBbsEntry (&LocalBbsTable
[Index
])) {
1171 " %02x: %04x %02x/%02x/%02x %02x/%02x %04x %04x %04x:%04x\n",
1173 (UINTN
)LocalBbsTable
[Index
].BootPriority
,
1174 (UINTN
)LocalBbsTable
[Index
].Bus
,
1175 (UINTN
)LocalBbsTable
[Index
].Device
,
1176 (UINTN
)LocalBbsTable
[Index
].Function
,
1177 (UINTN
)LocalBbsTable
[Index
].Class
,
1178 (UINTN
)LocalBbsTable
[Index
].SubClass
,
1179 (UINTN
)LocalBbsTable
[Index
].DeviceType
,
1180 (UINTN
)*(UINT16
*)&LocalBbsTable
[Index
].StatusFlags
,
1181 (UINTN
)LocalBbsTable
[Index
].BootHandlerSegment
,
1182 (UINTN
)LocalBbsTable
[Index
].BootHandlerOffset
,
1183 (UINTN
)((LocalBbsTable
[Index
].MfgStringSegment
<< 4) + LocalBbsTable
[Index
].MfgStringOffset
),
1184 (UINTN
)((LocalBbsTable
[Index
].DescStringSegment
<< 4) + LocalBbsTable
[Index
].DescStringOffset
))
1188 DEBUG ((DEBUG_INFO
, "\n"));
1192 Set the boot priority for BBS entries based on boot option entry and boot order.
1194 @param BootOption The boot option is to be checked for refresh BBS table.
1196 @retval EFI_SUCCESS The boot priority for BBS entries is refreshed successfully.
1197 @retval EFI_NOT_FOUND BBS entries can't be found.
1198 @retval EFI_OUT_OF_RESOURCES Failed to get the legacy device boot order.
1201 LegacyBmRefreshBbsTableForBoot (
1202 IN EFI_BOOT_MANAGER_LOAD_OPTION
*BootOption
1209 HDD_INFO
*LocalHddInfo
;
1210 BBS_TABLE
*LocalBbsTable
;
1212 EFI_LEGACY_BIOS_PROTOCOL
*LegacyBios
;
1216 UINTN DeviceTypeCount
;
1217 UINTN DeviceTypeIndex
;
1218 EFI_BOOT_MANAGER_LOAD_OPTION
*Option
;
1223 LocalHddInfo
= NULL
;
1224 LocalBbsTable
= NULL
;
1225 DevType
= BBS_UNKNOWN
;
1227 Status
= gBS
->LocateProtocol (&gEfiLegacyBiosProtocolGuid
, NULL
, (VOID
**)&LegacyBios
);
1228 if (EFI_ERROR (Status
)) {
1232 Status
= LegacyBios
->GetBbsInfo (
1239 if (EFI_ERROR (Status
)) {
1244 // First, set all the present devices' boot priority to BBS_UNPRIORITIZED_ENTRY
1245 // We will set them according to the settings setup by user
1247 for (Index
= 0; Index
< BbsCount
; Index
++) {
1248 if (LegacyBmValidBbsEntry (&LocalBbsTable
[Index
])) {
1249 LocalBbsTable
[Index
].BootPriority
= BBS_UNPRIORITIZED_ENTRY
;
1254 // boot priority always starts at 0
1257 if ((DevicePathType (BootOption
->FilePath
) == BBS_DEVICE_PATH
) &&
1258 (DevicePathSubType (BootOption
->FilePath
) == BBS_BBS_DP
))
1261 // If BootOption stands for a legacy boot option, we prioritize the devices with the same type first.
1263 DevType
= LegacyBmDeviceType (BootOption
->FilePath
);
1264 BbsIndex
= ((LEGACY_BM_BOOT_OPTION_BBS_DATA
*)BootOption
->OptionalData
)->BbsIndex
;
1265 Status
= LegacyBmSetPriorityForSameTypeDev (
1271 if (EFI_ERROR (Status
)) {
1277 // we have to set the boot priority for other BBS entries with different device types
1279 Option
= EfiBootManagerGetLoadOptions (&OptionCount
, LoadOptionTypeBoot
);
1280 DeviceType
= AllocatePool (sizeof (UINT16
) * OptionCount
);
1281 ASSERT (DeviceType
!= NULL
);
1282 DeviceType
[0] = DevType
;
1283 DeviceTypeCount
= 1;
1284 for (Index
= 0; Index
< OptionCount
; Index
++) {
1285 if ((DevicePathType (Option
[Index
].FilePath
) != BBS_DEVICE_PATH
) ||
1286 (DevicePathSubType (Option
[Index
].FilePath
) != BBS_BBS_DP
))
1291 DevType
= LegacyBmDeviceType (Option
[Index
].FilePath
);
1292 for (DeviceTypeIndex
= 0; DeviceTypeIndex
< DeviceTypeCount
; DeviceTypeIndex
++) {
1293 if (DeviceType
[DeviceTypeIndex
] == DevType
) {
1298 if (DeviceTypeIndex
< DeviceTypeCount
) {
1300 // We don't want to process twice for a device type
1305 DeviceType
[DeviceTypeCount
] = DevType
;
1308 Status
= LegacyBmSetPriorityForSameTypeDev (
1316 EfiBootManagerFreeLoadOptions (Option
, OptionCount
);
1318 DEBUG_CODE_BEGIN ();
1319 LegacyBmPrintBbsTable (LocalBbsTable
, BbsCount
);
1326 Boot the legacy system with the boot option.
1328 @param BootOption The legacy boot option which have BBS device path
1329 On return, BootOption->Status contains the boot status.
1330 EFI_UNSUPPORTED There is no legacybios protocol, do not support
1332 EFI_STATUS The status of LegacyBios->LegacyBoot ().
1337 IN EFI_BOOT_MANAGER_LOAD_OPTION
*BootOption
1341 EFI_LEGACY_BIOS_PROTOCOL
*LegacyBios
;
1343 Status
= gBS
->LocateProtocol (&gEfiLegacyBiosProtocolGuid
, NULL
, (VOID
**)&LegacyBios
);
1344 if (EFI_ERROR (Status
)) {
1346 // If no LegacyBios protocol we do not support legacy boot
1348 BootOption
->Status
= EFI_UNSUPPORTED
;
1353 // Notes: if we separate the int 19, then we don't need to refresh BBS
1355 Status
= LegacyBmRefreshBbsTableForBoot (BootOption
);
1356 if (EFI_ERROR (Status
)) {
1357 BootOption
->Status
= Status
;
1361 BootOption
->Status
= LegacyBios
->LegacyBoot (
1363 (BBS_BBS_DEVICE_PATH
*)BootOption
->FilePath
,
1364 BootOption
->OptionalDataSize
,
1365 BootOption
->OptionalData
1370 This function enumerates all the legacy boot options.
1372 @param BootOptionCount Return the legacy boot option count.
1374 @retval Pointer to the legacy boot option buffer.
1376 EFI_BOOT_MANAGER_LOAD_OPTION
*
1377 LegacyBmEnumerateAllBootOptions (
1378 UINTN
*BootOptionCount
1385 BBS_TABLE
*BbsTable
;
1386 EFI_LEGACY_BIOS_PROTOCOL
*LegacyBios
;
1388 EFI_BOOT_MANAGER_LOAD_OPTION
*BootOptions
;
1390 ASSERT (BootOptionCount
!= NULL
);
1393 *BootOptionCount
= 0;
1396 Status
= gBS
->LocateProtocol (&gEfiLegacyBiosProtocolGuid
, NULL
, (VOID
**)&LegacyBios
);
1397 if (EFI_ERROR (Status
)) {
1401 Status
= LegacyBios
->GetBbsInfo (
1408 if (EFI_ERROR (Status
)) {
1412 for (Index
= 0; Index
< BbsCount
; Index
++) {
1413 if (!LegacyBmValidBbsEntry (&BbsTable
[Index
])) {
1417 BootOptions
= ReallocatePool (
1418 sizeof (EFI_BOOT_MANAGER_LOAD_OPTION
) * (*BootOptionCount
),
1419 sizeof (EFI_BOOT_MANAGER_LOAD_OPTION
) * (*BootOptionCount
+ 1),
1422 ASSERT (BootOptions
!= NULL
);
1424 Status
= LegacyBmCreateLegacyBootOption (&BootOptions
[(*BootOptionCount
)++], &BbsTable
[Index
], Index
);
1425 ASSERT_EFI_ERROR (Status
);
1432 Return the index of the boot option in the boot option array.
1434 The function compares the Description, FilePath, OptionalData.
1436 @param Key The input boot option which is compared with.
1437 @param Array The input boot option array.
1438 @param Count The count of the input boot options.
1440 @retval The index of the input boot option in the array.
1444 LegacyBmFindBootOption (
1445 IN CONST EFI_BOOT_MANAGER_LOAD_OPTION
*Key
,
1446 IN CONST EFI_BOOT_MANAGER_LOAD_OPTION
*Array
,
1452 for (Index
= 0; Index
< Count
; Index
++) {
1453 if ((StrCmp (Key
->Description
, Array
[Index
].Description
) == 0) &&
1454 (CompareMem (Key
->FilePath
, Array
[Index
].FilePath
, GetDevicePathSize (Key
->FilePath
)) == 0) &&
1455 (Key
->OptionalDataSize
== Array
[Index
].OptionalDataSize
) &&
1456 (CompareMem (Key
->OptionalData
, Array
[Index
].OptionalData
, Key
->OptionalDataSize
) == 0))
1466 Refresh all legacy boot options.
1471 LegacyBmRefreshAllBootOption (
1476 EFI_LEGACY_BIOS_PROTOCOL
*LegacyBios
;
1477 UINTN RootBridgeHandleCount
;
1478 EFI_HANDLE
*RootBridgeHandleBuffer
;
1480 EFI_HANDLE
*HandleBuffer
;
1481 UINTN RootBridgeIndex
;
1484 EFI_BOOT_MANAGER_LOAD_OPTION
*BootOptions
;
1485 UINTN BootOptionCount
;
1486 EFI_BOOT_MANAGER_LOAD_OPTION
*ExistingBootOptions
;
1487 UINTN ExistingBootOptionCount
;
1489 Status
= gBS
->LocateProtocol (&gEfiLegacyBiosProtocolGuid
, NULL
, (VOID
**)&LegacyBios
);
1490 if (EFI_ERROR (Status
)) {
1491 LegacyBmDeleteAllBootOptions ();
1495 PERF_START (NULL
, "LegacyBootOptionEnum", "BDS", 0);
1498 // Before enumerating the legacy boot option, we need to dispatch all the legacy option roms
1499 // to ensure the GetBbsInfo() counts all the legacy devices.
1501 gBS
->LocateHandleBuffer (
1503 &gEfiPciRootBridgeIoProtocolGuid
,
1505 &RootBridgeHandleCount
,
1506 &RootBridgeHandleBuffer
1508 for (RootBridgeIndex
= 0; RootBridgeIndex
< RootBridgeHandleCount
; RootBridgeIndex
++) {
1509 gBS
->ConnectController (RootBridgeHandleBuffer
[RootBridgeIndex
], NULL
, NULL
, FALSE
);
1510 gBS
->LocateHandleBuffer (
1512 &gEfiPciIoProtocolGuid
,
1517 for (Index
= 0; Index
< HandleCount
; Index
++) {
1519 // Start the thunk driver so that the legacy option rom gets dispatched.
1520 // Note: We don't directly call InstallPciRom because some thunk drivers
1521 // (e.g. BlockIo thunk driver) depend on the immediate result after dispatching
1523 Status
= LegacyBios
->CheckPciRom (
1525 HandleBuffer
[Index
],
1530 if (!EFI_ERROR (Status
)) {
1531 gBS
->ConnectController (HandleBuffer
[Index
], NULL
, NULL
, FALSE
);
1537 // Same algorithm pattern as the EfiBootManagerRefreshAllBootOption
1538 // Firstly delete the invalid legacy boot options,
1539 // then enumerate and save the newly appeared legacy boot options
1540 // the last step is legacy boot option special action to refresh the LegacyDevOrder variable
1542 LegacyBmDeleteAllInvalidBootOptions ();
1544 ExistingBootOptions
= EfiBootManagerGetLoadOptions (&ExistingBootOptionCount
, LoadOptionTypeBoot
);
1545 BootOptions
= LegacyBmEnumerateAllBootOptions (&BootOptionCount
);
1547 for (Index
= 0; Index
< BootOptionCount
; Index
++) {
1548 if (LegacyBmFindBootOption (&BootOptions
[Index
], ExistingBootOptions
, ExistingBootOptionCount
) == -1) {
1549 Status
= EfiBootManagerAddLoadOptionVariable (&BootOptions
[Index
], (UINTN
)-1);
1552 "[LegacyBds] New Boot Option: Boot%04x Bbs0x%04x %s %r\n",
1553 (UINTN
)BootOptions
[Index
].OptionNumber
,
1554 (UINTN
)((LEGACY_BM_BOOT_OPTION_BBS_DATA
*)BootOptions
[Index
].OptionalData
)->BbsIndex
,
1555 BootOptions
[Index
].Description
,
1559 // Continue upon failure to add boot option.
1564 EfiBootManagerFreeLoadOptions (ExistingBootOptions
, ExistingBootOptionCount
);
1565 EfiBootManagerFreeLoadOptions (BootOptions
, BootOptionCount
);
1568 // Failure to create LegacyDevOrder variable only impacts the boot order.
1570 LegacyBmUpdateDevOrder ();
1572 PERF_END (NULL
, "LegacyBootOptionEnum", "BDS", 0);