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
51 ASSERT ((DevicePathType (DevicePath
) == BBS_DEVICE_PATH
) &&
52 (DevicePathSubType (DevicePath
) == BBS_BBS_DP
));
53 return ((BBS_BBS_DEVICE_PATH
*) DevicePath
)->DeviceType
;
57 Validate the BbsEntry base on the Boot Priority info in the BbsEntry.
59 @param BbsEntry The input bbs entry info.
61 @retval TRUE The BbsEntry is valid.
62 @retval FALSE The BbsEntry is invalid.
65 LegacyBmValidBbsEntry (
66 IN BBS_TABLE
*BbsEntry
69 switch (BbsEntry
->BootPriority
) {
70 case BBS_IGNORE_ENTRY
:
71 case BBS_DO_NOT_BOOT_FROM
:
72 case BBS_LOWEST_PRIORITY
:
80 Build Legacy Device Name String according.
82 @param CurBBSEntry BBS Table.
84 @param BufSize The buffer size.
85 @param BootString The output string.
89 LegacyBmBuildLegacyDevNameString (
90 IN BBS_TABLE
*CurBBSEntry
,
93 OUT CHAR16
*BootString
99 CHAR8 StringBufferA
[LEGACY_BM_BOOT_DESCRIPTION_LENGTH
+ 1];
100 CHAR16 StringBufferU
[LEGACY_BM_BOOT_DESCRIPTION_LENGTH
+ 1];
107 Fmt
= L
"Primary Master %s";
114 Fmt
= L
"Primary Slave %s";
121 Fmt
= L
"Secondary Master %s";
128 Fmt
= L
"Secondary Slave %s";
136 switch (CurBBSEntry
->DeviceType
) {
157 case BBS_EMBED_NETWORK
:
171 // If current BBS entry has its description then use it.
173 StringDesc
= (CHAR8
*) (((UINTN
) CurBBSEntry
->DescStringSegment
<< 4) + CurBBSEntry
->DescStringOffset
);
174 if (NULL
!= StringDesc
) {
176 // Only get fisrt 32 characters, this is suggested by BBS spec
178 CopyMem (StringBufferA
, StringDesc
, LEGACY_BM_BOOT_DESCRIPTION_LENGTH
);
179 StringBufferA
[LEGACY_BM_BOOT_DESCRIPTION_LENGTH
] = 0;
180 AsciiStrToUnicodeStrS (StringBufferA
, StringBufferU
, ARRAY_SIZE (StringBufferU
));
182 Type
= StringBufferU
;
186 // BbsTable 16 entries are for onboard IDE.
187 // Set description string for SATA harddisks, Harddisk 0 ~ Harddisk 11
189 if (Index
>= 5 && Index
<= 16 && (CurBBSEntry
->DeviceType
== BBS_HARDDISK
|| CurBBSEntry
->DeviceType
== BBS_CDROM
)) {
191 UnicodeSPrint (BootString
, BufSize
, Fmt
, Type
, Index
- 5);
193 UnicodeSPrint (BootString
, BufSize
, Fmt
, Type
);
198 Get the Bbs index for the input boot option.
200 @param BootOption The input boot option info.
201 @param BbsTable The input Bbs table.
202 @param BbsCount The input total bbs entry number.
203 @param BbsIndexUsed The array shows how many BBS table indexs have been used.
205 @retval The index for the input boot option.
209 EFI_BOOT_MANAGER_LOAD_OPTION
*BootOption
,
212 BOOLEAN
*BbsIndexUsed
216 LEGACY_BM_BOOT_OPTION_BBS_DATA
*BbsData
;
217 CHAR16 Description
[LEGACY_BM_BOOT_DESCRIPTION_LENGTH
+ 1];
219 BbsData
= (LEGACY_BM_BOOT_OPTION_BBS_DATA
*) BootOption
->OptionalData
;
222 // Directly check the BBS index stored in BootOption
224 if ((BbsData
->BbsIndex
< BbsCount
) &&
225 (LegacyBmDeviceType (BootOption
->FilePath
) == BbsTable
[BbsData
->BbsIndex
].DeviceType
)) {
226 LegacyBmBuildLegacyDevNameString (
227 &BbsTable
[BbsData
->BbsIndex
],
229 sizeof (Description
),
232 if ((StrCmp (Description
, BootOption
->Description
) == 0) && !BbsIndexUsed
[BbsData
->BbsIndex
]) {
234 // If devices with the same description string are connected,
235 // the BbsIndex of the first device is returned for the other device also.
236 // So, check if the BbsIndex is already being used, before assigning the BbsIndex.
238 BbsIndexUsed
[BbsData
->BbsIndex
] = TRUE
;
239 return BbsData
->BbsIndex
;
244 // BBS table could be changed (entry removed/moved)
245 // find the correct BBS index
247 for (Index
= 0; Index
< BbsCount
; Index
++) {
248 if (!LegacyBmValidBbsEntry (&BbsTable
[Index
]) ||
249 (BbsTable
[Index
].DeviceType
!= LegacyBmDeviceType (BootOption
->FilePath
))) {
253 LegacyBmBuildLegacyDevNameString (
256 sizeof (Description
),
259 if ((StrCmp (Description
, BootOption
->Description
) == 0) && !BbsIndexUsed
[Index
]) {
261 // If devices with the same description string are connected,
262 // the BbsIndex of the first device is assigned for the other device also.
263 // So, check if the BbsIndex is already being used, before assigning the corrected BbsIndex.
270 // Add the corrected BbsIndex in the UsedBbsIndex Buffer
272 if (Index
!= BbsCount
) {
273 BbsIndexUsed
[Index
] = TRUE
;
281 Update legacy device order base on the input info.
283 @param LegacyDevOrder Legacy device order data buffer.
284 @param LegacyDevOrderSize Legacy device order data buffer size.
285 @param DeviceType Device type which need to check.
286 @param OldBbsIndex Old Bds Index.
287 @param NewBbsIndex New Bds Index, if it is -1,means remove this option.
291 LegacyBmUpdateBbsIndex (
292 LEGACY_DEV_ORDER_ENTRY
*LegacyDevOrder
,
293 UINTN
*LegacyDevOrderSize
,
296 UINT16 NewBbsIndex
// Delete entry if -1
299 LEGACY_DEV_ORDER_ENTRY
*Entry
;
302 ASSERT (((LegacyDevOrder
== NULL
) && (*LegacyDevOrderSize
== 0)) ||
303 ((LegacyDevOrder
!= NULL
) && (*LegacyDevOrderSize
!= 0))
306 for (Entry
= LegacyDevOrder
;
307 Entry
< (LEGACY_DEV_ORDER_ENTRY
*) ((UINT8
*) LegacyDevOrder
+ *LegacyDevOrderSize
);
308 Entry
= (LEGACY_DEV_ORDER_ENTRY
*) ((UINTN
) Entry
+ sizeof (BBS_TYPE
) + Entry
->Length
)
310 if (Entry
->BbsType
== DeviceType
) {
311 for (Index
= 0; Index
< Entry
->Length
/ sizeof (UINT16
) - 1; Index
++) {
312 if (Entry
->Data
[Index
] == OldBbsIndex
) {
313 if (NewBbsIndex
== (UINT16
) -1) {
315 // Delete the old entry
319 &Entry
->Data
[Index
+ 1],
320 (UINT8
*) LegacyDevOrder
+ *LegacyDevOrderSize
- (UINT8
*) &Entry
->Data
[Index
+ 1]
322 Entry
->Length
-= sizeof (UINT16
);
323 *LegacyDevOrderSize
-= sizeof(UINT16
);
325 Entry
->Data
[Index
] = NewBbsIndex
;
336 Delete all the legacy boot options.
338 @retval EFI_SUCCESS All legacy boot options are deleted.
341 LegacyBmDeleteAllBootOptions (
347 EFI_BOOT_MANAGER_LOAD_OPTION
*BootOption
;
348 UINTN BootOptionCount
;
350 BootOption
= EfiBootManagerGetLoadOptions (&BootOptionCount
, LoadOptionTypeBoot
);
351 for (Index
= 0; Index
< BootOptionCount
; Index
++) {
352 if ((DevicePathType (BootOption
[Index
].FilePath
) == BBS_DEVICE_PATH
) &&
353 (DevicePathSubType (BootOption
[Index
].FilePath
) == BBS_BBS_DP
)) {
354 Status
= EfiBootManagerDeleteLoadOptionVariable (BootOption
[Index
].OptionNumber
, BootOption
[Index
].OptionType
);
356 // Deleting variable with current variable implementation shouldn't fail.
358 ASSERT_EFI_ERROR (Status
);
362 Status
= gRT
->SetVariable (
363 VAR_LEGACY_DEV_ORDER
,
364 &gEfiLegacyDevOrderVariableGuid
,
370 // Deleting variable with current variable implementation shouldn't fail.
372 ASSERT (Status
== EFI_SUCCESS
|| Status
== EFI_NOT_FOUND
);
379 Delete all the invalid legacy boot options.
381 @retval EFI_SUCCESS All invalide legacy boot options are deleted.
382 @retval EFI_OUT_OF_RESOURCES Fail to allocate necessary memory.
383 @retval EFI_NOT_FOUND Fail to retrive variable of boot order.
386 LegacyBmDeleteAllInvalidBootOptions (
396 EFI_LEGACY_BIOS_PROTOCOL
*LegacyBios
;
398 EFI_BOOT_MANAGER_LOAD_OPTION
*BootOption
;
399 UINTN BootOptionCount
;
400 LEGACY_DEV_ORDER_ENTRY
*LegacyDevOrder
;
401 UINTN LegacyDevOrderSize
;
402 BOOLEAN
*BbsIndexUsed
;
409 Status
= gBS
->LocateProtocol (&gEfiLegacyBiosProtocolGuid
, NULL
, (VOID
**) &LegacyBios
);
410 if (EFI_ERROR (Status
)) {
414 Status
= LegacyBios
->GetBbsInfo (
421 if (EFI_ERROR (Status
)) {
425 GetVariable2 (VAR_LEGACY_DEV_ORDER
, &gEfiLegacyDevOrderVariableGuid
, (VOID
**) &LegacyDevOrder
, &LegacyDevOrderSize
);
427 BootOption
= EfiBootManagerGetLoadOptions (&BootOptionCount
, LoadOptionTypeBoot
);
429 BbsIndexUsed
= AllocateZeroPool (BbsCount
* sizeof (BOOLEAN
));
430 ASSERT (BbsIndexUsed
!= NULL
);
432 for (Index
= 0; Index
< BootOptionCount
; Index
++) {
434 // Skip non legacy boot option
436 if ((DevicePathType (BootOption
[Index
].FilePath
) != BBS_DEVICE_PATH
) ||
437 (DevicePathSubType (BootOption
[Index
].FilePath
) != BBS_BBS_DP
)) {
441 BbsIndex
= LegacyBmFuzzyMatch (&BootOption
[Index
], BbsTable
, BbsCount
, BbsIndexUsed
);
442 if (BbsIndex
== BbsCount
) {
443 DEBUG ((EFI_D_INFO
, "[LegacyBds] Delete Boot Option Boot%04x: %s\n", (UINTN
) BootOption
[Index
].OptionNumber
, BootOption
[Index
].Description
));
445 // Delete entry from LegacyDevOrder
447 LegacyBmUpdateBbsIndex (
450 LegacyBmDeviceType (BootOption
[Index
].FilePath
),
451 ((LEGACY_BM_BOOT_OPTION_BBS_DATA
*) BootOption
[Index
].OptionalData
)->BbsIndex
,
454 EfiBootManagerDeleteLoadOptionVariable (BootOption
[Index
].OptionNumber
, BootOption
[Index
].OptionType
);
456 if (((LEGACY_BM_BOOT_OPTION_BBS_DATA
*) BootOption
[Index
].OptionalData
)->BbsIndex
!= BbsIndex
) {
457 DEBUG ((EFI_D_INFO
, "[LegacyBds] Update Boot Option Boot%04x: %s Bbs0x%04x->Bbs0x%04x\n", (UINTN
) BootOption
[Index
].OptionNumber
, BootOption
[Index
].Description
,
458 (UINTN
) ((LEGACY_BM_BOOT_OPTION_BBS_DATA
*) BootOption
[Index
].OptionalData
)->BbsIndex
, (UINTN
) BbsIndex
));
460 // Update the BBS index in LegacyDevOrder
462 LegacyBmUpdateBbsIndex (
465 LegacyBmDeviceType (BootOption
[Index
].FilePath
),
466 ((LEGACY_BM_BOOT_OPTION_BBS_DATA
*) BootOption
[Index
].OptionalData
)->BbsIndex
,
471 // Update the OptionalData in the Boot#### variable
473 ((LEGACY_BM_BOOT_OPTION_BBS_DATA
*) BootOption
[Index
].OptionalData
)->BbsIndex
= BbsIndex
;
474 EfiBootManagerLoadOptionToVariable (&BootOption
[Index
]);
478 EfiBootManagerFreeLoadOptions (BootOption
, BootOptionCount
);
480 if (LegacyDevOrder
!= NULL
) {
481 Status
= gRT
->SetVariable (
482 VAR_LEGACY_DEV_ORDER
,
483 &gEfiLegacyDevOrderVariableGuid
,
484 EFI_VARIABLE_BOOTSERVICE_ACCESS
| EFI_VARIABLE_NON_VOLATILE
,
489 // Shrink variable with current variable implementation shouldn't fail.
491 ASSERT_EFI_ERROR (Status
);
493 FreePool (LegacyDevOrder
);
495 FreePool(BbsIndexUsed
);
500 Create legacy boot option.
502 @param BootOption Ponter to the boot option which will be crated.
503 @param BbsEntry The input bbs entry info.
504 @param BbsIndex The BBS index.
506 @retval EFI_SUCCESS Create legacy boot option successfully.
507 @retval EFI_INVALID_PARAMETER Invalid input parameter.
511 LegacyBmCreateLegacyBootOption (
512 IN OUT EFI_BOOT_MANAGER_LOAD_OPTION
*BootOption
,
513 IN BBS_TABLE
*BbsEntry
,
518 EFI_DEVICE_PATH_PROTOCOL
*DevicePath
;
519 CHAR16 Description
[LEGACY_BM_BOOT_DESCRIPTION_LENGTH
+ 1];
520 CHAR8 HelpString
[LEGACY_BM_BOOT_DESCRIPTION_LENGTH
+ 1];
522 LEGACY_BM_BOOT_OPTION_BBS_DATA
*OptionalData
;
523 BBS_BBS_DEVICE_PATH
*BbsNode
;
525 if ((BootOption
== NULL
) || (BbsEntry
== NULL
)) {
526 return EFI_INVALID_PARAMETER
;
529 LegacyBmBuildLegacyDevNameString (BbsEntry
, BbsIndex
, sizeof (Description
), Description
);
532 // Create the BBS device path with description string
534 UnicodeStrToAsciiStrS (Description
, HelpString
, sizeof (HelpString
));
535 StringLen
= AsciiStrLen (HelpString
);
536 DevicePath
= AllocatePool (sizeof (BBS_BBS_DEVICE_PATH
) + StringLen
+ END_DEVICE_PATH_LENGTH
);
537 ASSERT (DevicePath
!= NULL
);
539 BbsNode
= (BBS_BBS_DEVICE_PATH
*) DevicePath
;
540 SetDevicePathNodeLength (BbsNode
, sizeof (BBS_BBS_DEVICE_PATH
) + StringLen
);
541 BbsNode
->Header
.Type
= BBS_DEVICE_PATH
;
542 BbsNode
->Header
.SubType
= BBS_BBS_DP
;
543 BbsNode
->DeviceType
= BbsEntry
->DeviceType
;
544 CopyMem (&BbsNode
->StatusFlag
, &BbsEntry
->StatusFlags
, sizeof (BBS_STATUS_FLAGS
));
545 CopyMem (BbsNode
->String
, HelpString
, StringLen
+ 1);
547 SetDevicePathEndNode (NextDevicePathNode (BbsNode
));
550 // Create the OptionalData
552 OptionalData
= AllocatePool (sizeof (LEGACY_BM_BOOT_OPTION_BBS_DATA
));
553 ASSERT (OptionalData
!= NULL
);
554 OptionalData
->BbsIndex
= BbsIndex
;
557 // Create the BootOption
559 Status
= EfiBootManagerInitializeLoadOption (
561 LoadOptionNumberUnassigned
,
566 (UINT8
*) OptionalData
,
567 sizeof (LEGACY_BM_BOOT_OPTION_BBS_DATA
)
569 FreePool (DevicePath
);
570 FreePool (OptionalData
);
576 Fill the device order buffer.
578 @param BbsTable The BBS table.
579 @param BbsType The BBS Type.
580 @param BbsCount The BBS Count.
581 @param Buf device order buffer.
583 @return The device order buffer.
587 LegacyBmFillDevOrderBuf (
588 IN BBS_TABLE
*BbsTable
,
596 for (Index
= 0; Index
< BbsCount
; Index
++) {
597 if (!LegacyBmValidBbsEntry (&BbsTable
[Index
])) {
601 if (BbsTable
[Index
].DeviceType
!= BbsType
) {
605 *Buf
= (UINT16
) (Index
& 0xFF);
613 Create the device order buffer.
615 @param BbsTable The BBS table.
616 @param BbsCount The BBS Count.
618 @retval EFI_SUCCES The buffer is created and the EFI variable named
619 VAR_LEGACY_DEV_ORDER and EfiLegacyDevOrderGuid is
621 @retval EFI_OUT_OF_RESOURCES Memmory or storage is not enough.
622 @retval EFI_DEVICE_ERROR Fail to add the device order into EFI variable fail
623 because of hardware error.
626 LegacyBmCreateDevOrder (
627 IN BBS_TABLE
*BbsTable
,
639 LEGACY_DEV_ORDER_ENTRY
*DevOrder
;
640 LEGACY_DEV_ORDER_ENTRY
*DevOrderPtr
;
649 HeaderSize
= sizeof (BBS_TYPE
) + sizeof (UINT16
);
651 Status
= EFI_SUCCESS
;
654 // Count all boot devices
656 for (Index
= 0; Index
< BbsCount
; Index
++) {
657 if (!LegacyBmValidBbsEntry (&BbsTable
[Index
])) {
661 switch (BbsTable
[Index
].DeviceType
) {
674 case BBS_EMBED_NETWORK
:
687 TotalSize
+= (HeaderSize
+ sizeof (UINT16
) * FDCount
);
688 TotalSize
+= (HeaderSize
+ sizeof (UINT16
) * HDCount
);
689 TotalSize
+= (HeaderSize
+ sizeof (UINT16
) * CDCount
);
690 TotalSize
+= (HeaderSize
+ sizeof (UINT16
) * NETCount
);
691 TotalSize
+= (HeaderSize
+ sizeof (UINT16
) * BEVCount
);
694 // Create buffer to hold all boot device order
696 DevOrder
= AllocateZeroPool (TotalSize
);
697 if (NULL
== DevOrder
) {
698 return EFI_OUT_OF_RESOURCES
;
700 DevOrderPtr
= DevOrder
;
702 DevOrderPtr
->BbsType
= BBS_FLOPPY
;
703 DevOrderPtr
->Length
= (UINT16
) (sizeof (DevOrderPtr
->Length
) + FDCount
* sizeof (UINT16
));
704 DevOrderPtr
= (LEGACY_DEV_ORDER_ENTRY
*) LegacyBmFillDevOrderBuf (BbsTable
, BBS_FLOPPY
, BbsCount
, DevOrderPtr
->Data
);
706 DevOrderPtr
->BbsType
= BBS_HARDDISK
;
707 DevOrderPtr
->Length
= (UINT16
) (sizeof (UINT16
) + HDCount
* sizeof (UINT16
));
708 DevOrderPtr
= (LEGACY_DEV_ORDER_ENTRY
*) LegacyBmFillDevOrderBuf (BbsTable
, BBS_HARDDISK
, BbsCount
, DevOrderPtr
->Data
);
710 DevOrderPtr
->BbsType
= BBS_CDROM
;
711 DevOrderPtr
->Length
= (UINT16
) (sizeof (UINT16
) + CDCount
* sizeof (UINT16
));
712 DevOrderPtr
= (LEGACY_DEV_ORDER_ENTRY
*) LegacyBmFillDevOrderBuf (BbsTable
, BBS_CDROM
, BbsCount
, DevOrderPtr
->Data
);
714 DevOrderPtr
->BbsType
= BBS_EMBED_NETWORK
;
715 DevOrderPtr
->Length
= (UINT16
) (sizeof (UINT16
) + NETCount
* sizeof (UINT16
));
716 DevOrderPtr
= (LEGACY_DEV_ORDER_ENTRY
*) LegacyBmFillDevOrderBuf (BbsTable
, BBS_EMBED_NETWORK
, BbsCount
, DevOrderPtr
->Data
);
718 DevOrderPtr
->BbsType
= BBS_BEV_DEVICE
;
719 DevOrderPtr
->Length
= (UINT16
) (sizeof (UINT16
) + BEVCount
* sizeof (UINT16
));
720 DevOrderPtr
= (LEGACY_DEV_ORDER_ENTRY
*) LegacyBmFillDevOrderBuf (BbsTable
, BBS_BEV_DEVICE
, BbsCount
, DevOrderPtr
->Data
);
722 ASSERT (TotalSize
== ((UINTN
) DevOrderPtr
- (UINTN
) DevOrder
));
725 // Save device order for legacy boot device to variable.
727 Status
= gRT
->SetVariable (
728 VAR_LEGACY_DEV_ORDER
,
729 &gEfiLegacyDevOrderVariableGuid
,
730 EFI_VARIABLE_BOOTSERVICE_ACCESS
| EFI_VARIABLE_NON_VOLATILE
,
740 Add the legacy boot devices from BBS table into
741 the legacy device boot order.
743 @retval EFI_SUCCESS The boot devices are added successfully.
744 @retval EFI_NOT_FOUND The legacy boot devices are not found.
745 @retval EFI_OUT_OF_RESOURCES Memmory or storage is not enough.
746 @retval EFI_DEVICE_ERROR Fail to add the legacy device boot order into EFI variable
747 because of hardware error.
750 LegacyBmUpdateDevOrder (
754 LEGACY_DEV_ORDER_ENTRY
*DevOrder
;
755 LEGACY_DEV_ORDER_ENTRY
*NewDevOrder
;
756 LEGACY_DEV_ORDER_ENTRY
*Ptr
;
757 LEGACY_DEV_ORDER_ENTRY
*NewPtr
;
758 EFI_LEGACY_BIOS_PROTOCOL
*LegacyBios
;
762 HDD_INFO
*LocalHddInfo
;
763 BBS_TABLE
*LocalBbsTable
;
793 HeaderSize
= sizeof (BBS_TYPE
) + sizeof (UINT16
);
801 Status
= gBS
->LocateProtocol (&gEfiLegacyBiosProtocolGuid
, NULL
, (VOID
**) &LegacyBios
);
802 if (EFI_ERROR (Status
)) {
806 Status
= LegacyBios
->GetBbsInfo (
813 if (EFI_ERROR (Status
)) {
817 GetVariable2 (VAR_LEGACY_DEV_ORDER
, &gEfiLegacyDevOrderVariableGuid
, (VOID
**) &DevOrder
, NULL
);
818 if (NULL
== DevOrder
) {
819 return LegacyBmCreateDevOrder (LocalBbsTable
, BbsCount
);
822 // First we figure out how many boot devices with same device type respectively
824 for (Index
= 0; Index
< BbsCount
; Index
++) {
825 if (!LegacyBmValidBbsEntry (&LocalBbsTable
[Index
])) {
829 switch (LocalBbsTable
[Index
].DeviceType
) {
842 case BBS_EMBED_NETWORK
:
855 TotalSize
+= (HeaderSize
+ FDCount
* sizeof (UINT16
));
856 TotalSize
+= (HeaderSize
+ HDCount
* sizeof (UINT16
));
857 TotalSize
+= (HeaderSize
+ CDCount
* sizeof (UINT16
));
858 TotalSize
+= (HeaderSize
+ NETCount
* sizeof (UINT16
));
859 TotalSize
+= (HeaderSize
+ BEVCount
* sizeof (UINT16
));
861 NewDevOrder
= AllocateZeroPool (TotalSize
);
862 if (NULL
== NewDevOrder
) {
863 return EFI_OUT_OF_RESOURCES
;
870 NewPtr
= NewDevOrder
;
871 NewPtr
->BbsType
= Ptr
->BbsType
;
872 NewPtr
->Length
= (UINT16
) (sizeof (UINT16
) + FDCount
* sizeof (UINT16
));
873 for (Index
= 0; Index
< Ptr
->Length
/ sizeof (UINT16
) - 1; Index
++) {
874 if (!LegacyBmValidBbsEntry (&LocalBbsTable
[Ptr
->Data
[Index
] & 0xFF]) ||
875 LocalBbsTable
[Ptr
->Data
[Index
] & 0xFF].DeviceType
!= BBS_FLOPPY
880 NewPtr
->Data
[FDIndex
] = Ptr
->Data
[Index
];
883 NewFDPtr
= NewPtr
->Data
;
888 Ptr
= (LEGACY_DEV_ORDER_ENTRY
*) (&Ptr
->Data
[Ptr
->Length
/ sizeof (UINT16
) - 1]);
889 NewPtr
= (LEGACY_DEV_ORDER_ENTRY
*) (&NewPtr
->Data
[NewPtr
->Length
/ sizeof (UINT16
) -1]);
890 NewPtr
->BbsType
= Ptr
->BbsType
;
891 NewPtr
->Length
= (UINT16
) (sizeof (UINT16
) + HDCount
* sizeof (UINT16
));
892 for (Index
= 0; Index
< Ptr
->Length
/ sizeof (UINT16
) - 1; Index
++) {
893 if (!LegacyBmValidBbsEntry (&LocalBbsTable
[Ptr
->Data
[Index
] & 0xFF]) ||
894 LocalBbsTable
[Ptr
->Data
[Index
] & 0xFF].DeviceType
!= BBS_HARDDISK
899 NewPtr
->Data
[HDIndex
] = Ptr
->Data
[Index
];
902 NewHDPtr
= NewPtr
->Data
;
907 Ptr
= (LEGACY_DEV_ORDER_ENTRY
*) (&Ptr
->Data
[Ptr
->Length
/ sizeof (UINT16
) - 1]);
908 NewPtr
= (LEGACY_DEV_ORDER_ENTRY
*) (&NewPtr
->Data
[NewPtr
->Length
/ sizeof (UINT16
) -1]);
909 NewPtr
->BbsType
= Ptr
->BbsType
;
910 NewPtr
->Length
= (UINT16
) (sizeof (UINT16
) + CDCount
* sizeof (UINT16
));
911 for (Index
= 0; Index
< Ptr
->Length
/ sizeof (UINT16
) - 1; Index
++) {
912 if (!LegacyBmValidBbsEntry (&LocalBbsTable
[Ptr
->Data
[Index
] & 0xFF]) ||
913 LocalBbsTable
[Ptr
->Data
[Index
] & 0xFF].DeviceType
!= BBS_CDROM
918 NewPtr
->Data
[CDIndex
] = Ptr
->Data
[Index
];
921 NewCDPtr
= NewPtr
->Data
;
926 Ptr
= (LEGACY_DEV_ORDER_ENTRY
*) (&Ptr
->Data
[Ptr
->Length
/ sizeof (UINT16
) - 1]);
927 NewPtr
= (LEGACY_DEV_ORDER_ENTRY
*) (&NewPtr
->Data
[NewPtr
->Length
/ sizeof (UINT16
) -1]);
928 NewPtr
->BbsType
= Ptr
->BbsType
;
929 NewPtr
->Length
= (UINT16
) (sizeof (UINT16
) + NETCount
* sizeof (UINT16
));
930 for (Index
= 0; Index
< Ptr
->Length
/ sizeof (UINT16
) - 1; Index
++) {
931 if (!LegacyBmValidBbsEntry (&LocalBbsTable
[Ptr
->Data
[Index
] & 0xFF]) ||
932 LocalBbsTable
[Ptr
->Data
[Index
] & 0xFF].DeviceType
!= BBS_EMBED_NETWORK
937 NewPtr
->Data
[NETIndex
] = Ptr
->Data
[Index
];
940 NewNETPtr
= NewPtr
->Data
;
945 Ptr
= (LEGACY_DEV_ORDER_ENTRY
*) (&Ptr
->Data
[Ptr
->Length
/ sizeof (UINT16
) - 1]);
946 NewPtr
= (LEGACY_DEV_ORDER_ENTRY
*) (&NewPtr
->Data
[NewPtr
->Length
/ sizeof (UINT16
) -1]);
947 NewPtr
->BbsType
= Ptr
->BbsType
;
948 NewPtr
->Length
= (UINT16
) (sizeof (UINT16
) + BEVCount
* sizeof (UINT16
));
949 for (Index
= 0; Index
< Ptr
->Length
/ sizeof (UINT16
) - 1; Index
++) {
950 if (!LegacyBmValidBbsEntry (&LocalBbsTable
[Ptr
->Data
[Index
] & 0xFF]) ||
951 LocalBbsTable
[Ptr
->Data
[Index
] & 0xFF].DeviceType
!= BBS_BEV_DEVICE
956 NewPtr
->Data
[BEVIndex
] = Ptr
->Data
[Index
];
959 NewBEVPtr
= NewPtr
->Data
;
961 for (Index
= 0; Index
< BbsCount
; Index
++) {
962 if (!LegacyBmValidBbsEntry (&LocalBbsTable
[Index
])) {
966 switch (LocalBbsTable
[Index
].DeviceType
) {
969 NewDevPtr
= NewFDPtr
;
974 NewDevPtr
= NewHDPtr
;
979 NewDevPtr
= NewCDPtr
;
982 case BBS_EMBED_NETWORK
:
984 NewDevPtr
= NewNETPtr
;
989 NewDevPtr
= NewBEVPtr
;
997 // at this point we have copied those valid indexes to new buffer
998 // and we should check if there is any new appeared boot device
1001 for (Index2
= 0; Index2
< *Idx
; Index2
++) {
1002 if ((NewDevPtr
[Index2
] & 0xFF) == (UINT16
) Index
) {
1007 if (Index2
== *Idx
) {
1009 // Index2 == *Idx means we didn't find Index
1010 // so Index is a new appeared device's index in BBS table
1011 // insert it before disabled indexes.
1013 for (Index2
= 0; Index2
< *Idx
; Index2
++) {
1014 if ((NewDevPtr
[Index2
] & 0xFF00) == 0xFF00) {
1018 CopyMem (&NewDevPtr
[Index2
+ 1], &NewDevPtr
[Index2
], (*Idx
- Index2
) * sizeof (UINT16
));
1019 NewDevPtr
[Index2
] = (UINT16
) (Index
& 0xFF);
1025 FreePool (DevOrder
);
1027 Status
= gRT
->SetVariable (
1028 VAR_LEGACY_DEV_ORDER
,
1029 &gEfiLegacyDevOrderVariableGuid
,
1030 EFI_VARIABLE_BOOTSERVICE_ACCESS
| EFI_VARIABLE_NON_VOLATILE
,
1034 FreePool (NewDevOrder
);
1040 Set Boot Priority for specified device type.
1042 @param DeviceType The device type.
1043 @param BbsIndex The BBS index to set the highest priority. Ignore when -1.
1044 @param LocalBbsTable The BBS table.
1045 @param Priority The prority table.
1047 @retval EFI_SUCCESS The function completes successfully.
1048 @retval EFI_NOT_FOUND Failed to find device.
1049 @retval EFI_OUT_OF_RESOURCES Failed to get the efi variable of device order.
1053 LegacyBmSetPriorityForSameTypeDev (
1054 IN UINT16 DeviceType
,
1056 IN OUT BBS_TABLE
*LocalBbsTable
,
1057 IN OUT UINT16
*Priority
1060 LEGACY_DEV_ORDER_ENTRY
*DevOrder
;
1061 LEGACY_DEV_ORDER_ENTRY
*DevOrderPtr
;
1065 GetVariable2 (VAR_LEGACY_DEV_ORDER
, &gEfiLegacyDevOrderVariableGuid
, (VOID
**) &DevOrder
, &DevOrderSize
);
1066 if (NULL
== DevOrder
) {
1067 return EFI_OUT_OF_RESOURCES
;
1070 DevOrderPtr
= DevOrder
;
1071 while ((UINT8
*) DevOrderPtr
< (UINT8
*) DevOrder
+ DevOrderSize
) {
1072 if (DevOrderPtr
->BbsType
== DeviceType
) {
1076 DevOrderPtr
= (LEGACY_DEV_ORDER_ENTRY
*) ((UINTN
) DevOrderPtr
+ sizeof (BBS_TYPE
) + DevOrderPtr
->Length
);
1079 if ((UINT8
*) DevOrderPtr
>= (UINT8
*) DevOrder
+ DevOrderSize
) {
1080 FreePool (DevOrder
);
1081 return EFI_NOT_FOUND
;
1084 if (BbsIndex
!= (UINTN
) -1) {
1086 // In case the BBS entry isn't valid because devices were plugged or removed.
1088 if (!LegacyBmValidBbsEntry (&LocalBbsTable
[BbsIndex
]) || (LocalBbsTable
[BbsIndex
].DeviceType
!= DeviceType
)) {
1089 FreePool (DevOrder
);
1090 return EFI_NOT_FOUND
;
1092 LocalBbsTable
[BbsIndex
].BootPriority
= *Priority
;
1096 // If the high byte of the DevIndex is 0xFF, it indicates that this device has been disabled.
1098 for (Index
= 0; Index
< DevOrderPtr
->Length
/ sizeof (UINT16
) - 1; Index
++) {
1099 if ((DevOrderPtr
->Data
[Index
] & 0xFF00) == 0xFF00) {
1101 // LocalBbsTable[DevIndex[Index] & 0xFF].BootPriority = BBS_DISABLED_ENTRY;
1103 } else if (DevOrderPtr
->Data
[Index
] != BbsIndex
) {
1104 LocalBbsTable
[DevOrderPtr
->Data
[Index
]].BootPriority
= *Priority
;
1109 FreePool (DevOrder
);
1114 Print the BBS Table.
1116 @param LocalBbsTable The BBS table.
1117 @param BbsCount The count of entry in BBS table.
1120 LegacyBmPrintBbsTable (
1121 IN BBS_TABLE
*LocalBbsTable
,
1127 DEBUG ((DEBUG_INFO
, "\n"));
1128 DEBUG ((DEBUG_INFO
, " NO Prio bb/dd/ff cl/sc Type Stat segm:offs\n"));
1129 DEBUG ((DEBUG_INFO
, "=============================================\n"));
1130 for (Index
= 0; Index
< BbsCount
; Index
++) {
1131 if (!LegacyBmValidBbsEntry (&LocalBbsTable
[Index
])) {
1137 " %02x: %04x %02x/%02x/%02x %02x/%02x %04x %04x %04x:%04x\n",
1139 (UINTN
) LocalBbsTable
[Index
].BootPriority
,
1140 (UINTN
) LocalBbsTable
[Index
].Bus
,
1141 (UINTN
) LocalBbsTable
[Index
].Device
,
1142 (UINTN
) LocalBbsTable
[Index
].Function
,
1143 (UINTN
) LocalBbsTable
[Index
].Class
,
1144 (UINTN
) LocalBbsTable
[Index
].SubClass
,
1145 (UINTN
) LocalBbsTable
[Index
].DeviceType
,
1146 (UINTN
) * (UINT16
*) &LocalBbsTable
[Index
].StatusFlags
,
1147 (UINTN
) LocalBbsTable
[Index
].BootHandlerSegment
,
1148 (UINTN
) LocalBbsTable
[Index
].BootHandlerOffset
,
1149 (UINTN
) ((LocalBbsTable
[Index
].MfgStringSegment
<< 4) + LocalBbsTable
[Index
].MfgStringOffset
),
1150 (UINTN
) ((LocalBbsTable
[Index
].DescStringSegment
<< 4) + LocalBbsTable
[Index
].DescStringOffset
))
1154 DEBUG ((DEBUG_INFO
, "\n"));
1158 Set the boot priority for BBS entries based on boot option entry and boot order.
1160 @param BootOption The boot option is to be checked for refresh BBS table.
1162 @retval EFI_SUCCESS The boot priority for BBS entries is refreshed successfully.
1163 @retval EFI_NOT_FOUND BBS entries can't be found.
1164 @retval EFI_OUT_OF_RESOURCES Failed to get the legacy device boot order.
1167 LegacyBmRefreshBbsTableForBoot (
1168 IN EFI_BOOT_MANAGER_LOAD_OPTION
*BootOption
1175 HDD_INFO
*LocalHddInfo
;
1176 BBS_TABLE
*LocalBbsTable
;
1178 EFI_LEGACY_BIOS_PROTOCOL
*LegacyBios
;
1182 UINTN DeviceTypeCount
;
1183 UINTN DeviceTypeIndex
;
1184 EFI_BOOT_MANAGER_LOAD_OPTION
*Option
;
1189 LocalHddInfo
= NULL
;
1190 LocalBbsTable
= NULL
;
1191 DevType
= BBS_UNKNOWN
;
1193 Status
= gBS
->LocateProtocol (&gEfiLegacyBiosProtocolGuid
, NULL
, (VOID
**) &LegacyBios
);
1194 if (EFI_ERROR (Status
)) {
1198 Status
= LegacyBios
->GetBbsInfo (
1205 if (EFI_ERROR (Status
)) {
1210 // First, set all the present devices' boot priority to BBS_UNPRIORITIZED_ENTRY
1211 // We will set them according to the settings setup by user
1213 for (Index
= 0; Index
< BbsCount
; Index
++) {
1214 if (LegacyBmValidBbsEntry (&LocalBbsTable
[Index
])) {
1215 LocalBbsTable
[Index
].BootPriority
= BBS_UNPRIORITIZED_ENTRY
;
1219 // boot priority always starts at 0
1222 if ((DevicePathType (BootOption
->FilePath
) == BBS_DEVICE_PATH
) &&
1223 (DevicePathSubType (BootOption
->FilePath
) == BBS_BBS_DP
)) {
1225 // If BootOption stands for a legacy boot option, we prioritize the devices with the same type first.
1227 DevType
= LegacyBmDeviceType (BootOption
->FilePath
);
1228 BbsIndex
= ((LEGACY_BM_BOOT_OPTION_BBS_DATA
*) BootOption
->OptionalData
)->BbsIndex
;
1229 Status
= LegacyBmSetPriorityForSameTypeDev (
1235 if (EFI_ERROR (Status
)) {
1240 // we have to set the boot priority for other BBS entries with different device types
1242 Option
= EfiBootManagerGetLoadOptions (&OptionCount
, LoadOptionTypeBoot
);
1243 DeviceType
= AllocatePool (sizeof (UINT16
) * OptionCount
);
1244 ASSERT (DeviceType
!= NULL
);
1245 DeviceType
[0] = DevType
;
1246 DeviceTypeCount
= 1;
1247 for (Index
= 0; Index
< OptionCount
; Index
++) {
1248 if ((DevicePathType (Option
[Index
].FilePath
) != BBS_DEVICE_PATH
) ||
1249 (DevicePathSubType (Option
[Index
].FilePath
) != BBS_BBS_DP
)) {
1253 DevType
= LegacyBmDeviceType (Option
[Index
].FilePath
);
1254 for (DeviceTypeIndex
= 0; DeviceTypeIndex
< DeviceTypeCount
; DeviceTypeIndex
++) {
1255 if (DeviceType
[DeviceTypeIndex
] == DevType
) {
1259 if (DeviceTypeIndex
< DeviceTypeCount
) {
1261 // We don't want to process twice for a device type
1266 DeviceType
[DeviceTypeCount
] = DevType
;
1269 Status
= LegacyBmSetPriorityForSameTypeDev (
1276 EfiBootManagerFreeLoadOptions (Option
, OptionCount
);
1279 LegacyBmPrintBbsTable (LocalBbsTable
, BbsCount
);
1287 Boot the legacy system with the boot option.
1289 @param BootOption The legacy boot option which have BBS device path
1290 On return, BootOption->Status contains the boot status.
1291 EFI_UNSUPPORTED There is no legacybios protocol, do not support
1293 EFI_STATUS The status of LegacyBios->LegacyBoot ().
1298 IN EFI_BOOT_MANAGER_LOAD_OPTION
*BootOption
1302 EFI_LEGACY_BIOS_PROTOCOL
*LegacyBios
;
1304 Status
= gBS
->LocateProtocol (&gEfiLegacyBiosProtocolGuid
, NULL
, (VOID
**) &LegacyBios
);
1305 if (EFI_ERROR (Status
)) {
1307 // If no LegacyBios protocol we do not support legacy boot
1309 BootOption
->Status
= EFI_UNSUPPORTED
;
1313 // Notes: if we separate the int 19, then we don't need to refresh BBS
1315 Status
= LegacyBmRefreshBbsTableForBoot (BootOption
);
1316 if (EFI_ERROR (Status
)) {
1317 BootOption
->Status
= Status
;
1321 BootOption
->Status
= LegacyBios
->LegacyBoot (
1323 (BBS_BBS_DEVICE_PATH
*) BootOption
->FilePath
,
1324 BootOption
->OptionalDataSize
,
1325 BootOption
->OptionalData
1330 This function enumerates all the legacy boot options.
1332 @param BootOptionCount Return the legacy boot option count.
1334 @retval Pointer to the legacy boot option buffer.
1336 EFI_BOOT_MANAGER_LOAD_OPTION
*
1337 LegacyBmEnumerateAllBootOptions (
1338 UINTN
*BootOptionCount
1345 BBS_TABLE
*BbsTable
;
1346 EFI_LEGACY_BIOS_PROTOCOL
*LegacyBios
;
1348 EFI_BOOT_MANAGER_LOAD_OPTION
*BootOptions
;
1350 ASSERT (BootOptionCount
!= NULL
);
1353 *BootOptionCount
= 0;
1356 Status
= gBS
->LocateProtocol (&gEfiLegacyBiosProtocolGuid
, NULL
, (VOID
**) &LegacyBios
);
1357 if (EFI_ERROR (Status
)) {
1361 Status
= LegacyBios
->GetBbsInfo (
1368 if (EFI_ERROR (Status
)) {
1372 for (Index
= 0; Index
< BbsCount
; Index
++) {
1373 if (!LegacyBmValidBbsEntry (&BbsTable
[Index
])) {
1377 BootOptions
= ReallocatePool (
1378 sizeof (EFI_BOOT_MANAGER_LOAD_OPTION
) * (*BootOptionCount
),
1379 sizeof (EFI_BOOT_MANAGER_LOAD_OPTION
) * (*BootOptionCount
+ 1),
1382 ASSERT (BootOptions
!= NULL
);
1384 Status
= LegacyBmCreateLegacyBootOption (&BootOptions
[(*BootOptionCount
)++], &BbsTable
[Index
], Index
);
1385 ASSERT_EFI_ERROR (Status
);
1392 Return the index of the boot option in the boot option array.
1394 The function compares the Description, FilePath, OptionalData.
1396 @param Key The input boot option which is compared with.
1397 @param Array The input boot option array.
1398 @param Count The count of the input boot options.
1400 @retval The index of the input boot option in the array.
1404 LegacyBmFindBootOption (
1405 IN CONST EFI_BOOT_MANAGER_LOAD_OPTION
*Key
,
1406 IN CONST EFI_BOOT_MANAGER_LOAD_OPTION
*Array
,
1412 for (Index
= 0; Index
< Count
; Index
++) {
1413 if ((StrCmp (Key
->Description
, Array
[Index
].Description
) == 0) &&
1414 (CompareMem (Key
->FilePath
, Array
[Index
].FilePath
, GetDevicePathSize (Key
->FilePath
)) == 0) &&
1415 (Key
->OptionalDataSize
== Array
[Index
].OptionalDataSize
) &&
1416 (CompareMem (Key
->OptionalData
, Array
[Index
].OptionalData
, Key
->OptionalDataSize
) == 0)) {
1417 return (INTN
) Index
;
1425 Refresh all legacy boot options.
1430 LegacyBmRefreshAllBootOption (
1435 EFI_LEGACY_BIOS_PROTOCOL
*LegacyBios
;
1436 UINTN RootBridgeHandleCount
;
1437 EFI_HANDLE
*RootBridgeHandleBuffer
;
1439 EFI_HANDLE
*HandleBuffer
;
1440 UINTN RootBridgeIndex
;
1443 EFI_BOOT_MANAGER_LOAD_OPTION
*BootOptions
;
1444 UINTN BootOptionCount
;
1445 EFI_BOOT_MANAGER_LOAD_OPTION
*ExistingBootOptions
;
1446 UINTN ExistingBootOptionCount
;
1448 Status
= gBS
->LocateProtocol (&gEfiLegacyBiosProtocolGuid
, NULL
, (VOID
**) &LegacyBios
);
1449 if (EFI_ERROR (Status
)) {
1450 LegacyBmDeleteAllBootOptions ();
1453 PERF_START (NULL
, "LegacyBootOptionEnum", "BDS", 0);
1456 // Before enumerating the legacy boot option, we need to dispatch all the legacy option roms
1457 // to ensure the GetBbsInfo() counts all the legacy devices.
1459 gBS
->LocateHandleBuffer (
1461 &gEfiPciRootBridgeIoProtocolGuid
,
1463 &RootBridgeHandleCount
,
1464 &RootBridgeHandleBuffer
1466 for (RootBridgeIndex
= 0; RootBridgeIndex
< RootBridgeHandleCount
; RootBridgeIndex
++) {
1467 gBS
->ConnectController (RootBridgeHandleBuffer
[RootBridgeIndex
], NULL
, NULL
, FALSE
);
1468 gBS
->LocateHandleBuffer (
1470 &gEfiPciIoProtocolGuid
,
1475 for (Index
= 0; Index
< HandleCount
; Index
++) {
1477 // Start the thunk driver so that the legacy option rom gets dispatched.
1478 // Note: We don't directly call InstallPciRom because some thunk drivers
1479 // (e.g. BlockIo thunk driver) depend on the immediate result after dispatching
1481 Status
= LegacyBios
->CheckPciRom (
1483 HandleBuffer
[Index
],
1488 if (!EFI_ERROR (Status
)) {
1489 gBS
->ConnectController (HandleBuffer
[Index
], NULL
, NULL
, FALSE
);
1495 // Same algorithm pattern as the EfiBootManagerRefreshAllBootOption
1496 // Firstly delete the invalid legacy boot options,
1497 // then enumreate and save the newly appeared legacy boot options
1498 // the last step is legacy boot option special action to refresh the LegacyDevOrder variable
1500 LegacyBmDeleteAllInvalidBootOptions ();
1502 ExistingBootOptions
= EfiBootManagerGetLoadOptions (&ExistingBootOptionCount
, LoadOptionTypeBoot
);
1503 BootOptions
= LegacyBmEnumerateAllBootOptions (&BootOptionCount
);
1505 for (Index
= 0; Index
< BootOptionCount
; Index
++) {
1506 if (LegacyBmFindBootOption (&BootOptions
[Index
], ExistingBootOptions
, ExistingBootOptionCount
) == -1) {
1507 Status
= EfiBootManagerAddLoadOptionVariable (&BootOptions
[Index
], (UINTN
) -1);
1509 EFI_D_INFO
, "[LegacyBds] New Boot Option: Boot%04x Bbs0x%04x %s %r\n",
1510 (UINTN
) BootOptions
[Index
].OptionNumber
,
1511 (UINTN
) ((LEGACY_BM_BOOT_OPTION_BBS_DATA
*) BootOptions
[Index
].OptionalData
)->BbsIndex
,
1512 BootOptions
[Index
].Description
,
1516 // Continue upon failure to add boot option.
1521 EfiBootManagerFreeLoadOptions (ExistingBootOptions
, ExistingBootOptionCount
);
1522 EfiBootManagerFreeLoadOptions (BootOptions
, BootOptionCount
);
1525 // Failure to create LegacyDevOrder variable only impacts the boot order.
1527 LegacyBmUpdateDevOrder ();
1529 PERF_END (NULL
, "LegacyBootOptionEnum", "BDS", 0);