summaryrefslogtreecommitdiffstats
path: root/OvmfPkg/Csm/LegacyBootManagerLib
diff options
context:
space:
mode:
authorHao A Wu <hao.a.wu@intel.com>2019-05-15 11:22:29 +0800
committerHao A Wu <hao.a.wu@intel.com>2019-06-14 13:05:33 +0800
commitb522c77bdb4538710715dd13502840a2ca8072f6 (patch)
treebddb2f23f144c6d444340916f3e934cd35ab1c6b /OvmfPkg/Csm/LegacyBootManagerLib
parentbb4485d388392c9b99aac2435ab08e3d54836f26 (diff)
downloadedk2-b522c77bdb4538710715dd13502840a2ca8072f6.tar.gz
edk2-b522c77bdb4538710715dd13502840a2ca8072f6.tar.bz2
edk2-b522c77bdb4538710715dd13502840a2ca8072f6.zip
OvmfPkg: Copy the required CSM components from framework packages
REF:https://bugzilla.tianocore.org/show_bug.cgi?id=1811 This commit copies the exact: Drivers: * VideoDxe * LegacyBiosDxe Libraries: * LegacyBootMaintUiLib * LegacyBootManagerLib Guid header files: * Legacy Bios Guid * LegacyDevOrder Guid Protocol header files: * Firmware Volume Protocol * ISA ACPI Protocol * ISA I/O Protocol * Legacy BIOS Protocol * Legacy BIOS Platform Protocol * Legacy Interrupt Protocol * VGA Mini Port Protocol Framework header files (within IntelFrameworkPkg): * FrameworkDxe.h * Framework/BootScript.h * Framework/DxeCis.h * Framework/FirmwareVolumeHeader.h * Framework/FirmwareVolumeImageFormat.h * Framework/FrameworkInternalFormRepresentation.h * Framework/Hob.h * Framework/StatusCode.h from IntelFramework[Module]Pkg to OvmfPkg/Csm/ folder. Cc: Ray Ni <ray.ni@intel.com> Cc: Jordan Justen <jordan.l.justen@intel.com> Cc: Ard Biesheuvel <ard.biesheuvel@linaro.org> Signed-off-by: Hao A Wu <hao.a.wu@intel.com> Reviewed-by: David Woodhouse <dwmw2@infradead.org> Reviewed-by: Laszlo Ersek <lersek@redhat.com>
Diffstat (limited to 'OvmfPkg/Csm/LegacyBootManagerLib')
-rw-r--r--OvmfPkg/Csm/LegacyBootManagerLib/InternalLegacyBm.h60
-rw-r--r--OvmfPkg/Csm/LegacyBootManagerLib/LegacyBm.c1530
-rw-r--r--OvmfPkg/Csm/LegacyBootManagerLib/LegacyBootManagerLib.inf58
-rw-r--r--OvmfPkg/Csm/LegacyBootManagerLib/LegacyBootManagerLib.uni20
4 files changed, 1668 insertions, 0 deletions
diff --git a/OvmfPkg/Csm/LegacyBootManagerLib/InternalLegacyBm.h b/OvmfPkg/Csm/LegacyBootManagerLib/InternalLegacyBm.h
new file mode 100644
index 0000000000..292e2c1e7a
--- /dev/null
+++ b/OvmfPkg/Csm/LegacyBootManagerLib/InternalLegacyBm.h
@@ -0,0 +1,60 @@
+/** @file
+
+Copyright (c) 2011 - 2018, Intel Corporation. All rights reserved.<BR>
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#ifndef _INTERNAL_LEGACY_BM_H_
+#define _INTERNAL_LEGACY_BM_H_
+
+#include <PiDxe.h>
+#include <Guid/LegacyDevOrder.h>
+#include <Guid/GlobalVariable.h>
+#include <Protocol/LegacyBios.h>
+#include <Protocol/PciRootBridgeIo.h>
+#include <Protocol/PciIo.h>
+#include <Library/BaseLib.h>
+#include <Library/BaseMemoryLib.h>
+#include <Library/DebugLib.h>
+#include <Library/UefiBootServicesTableLib.h>
+#include <Library/UefiRuntimeServicesTableLib.h>
+#include <Library/UefiLib.h>
+#include <Library/DevicePathLib.h>
+#include <Library/UefiBootManagerLib.h>
+#include <Library/MemoryAllocationLib.h>
+#include <Library/PrintLib.h>
+#include <Library/PerformanceLib.h>
+
+#pragma pack(1)
+typedef struct {
+ UINT16 BbsIndex;
+} LEGACY_BM_BOOT_OPTION_BBS_DATA;
+#pragma pack()
+
+/**
+ Boot the legacy system with the boot option.
+
+ @param BootOption The legacy boot option which have BBS device path
+ On return, BootOption->Status contains the boot status.
+ EFI_UNSUPPORTED There is no legacybios protocol, do not support
+ legacy boot.
+ EFI_STATUS The status of LegacyBios->LegacyBoot ().
+**/
+VOID
+EFIAPI
+LegacyBmBoot (
+ IN EFI_BOOT_MANAGER_LOAD_OPTION *BootOption
+ );
+
+/**
+ Refresh all legacy boot options.
+
+**/
+VOID
+EFIAPI
+LegacyBmRefreshAllBootOption (
+ VOID
+ );
+
+#endif // _INTERNAL_LEGACY_BM_H_
diff --git a/OvmfPkg/Csm/LegacyBootManagerLib/LegacyBm.c b/OvmfPkg/Csm/LegacyBootManagerLib/LegacyBm.c
new file mode 100644
index 0000000000..6138a32ad7
--- /dev/null
+++ b/OvmfPkg/Csm/LegacyBootManagerLib/LegacyBm.c
@@ -0,0 +1,1530 @@
+/** @file
+ This function deal with the legacy boot option, it create, delete
+ and manage the legacy boot option, all legacy boot option is getting from
+ the legacy BBS table.
+
+Copyright (c) 2011 - 2018, Intel Corporation. All rights reserved.<BR>
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include "InternalLegacyBm.h"
+
+#define LEGACY_BM_BOOT_DESCRIPTION_LENGTH 32
+
+/**
+ Initialize legacy boot manager library by call EfiBootManagerRegisterLegacyBootSupport
+ function to export two function pointer.
+
+ @param ImageHandle The image handle.
+ @param SystemTable The system table.
+
+ @retval EFI_SUCCESS The legacy boot manager library is initialized correctly.
+ @return Other value if failed to initialize the legacy boot manager library.
+**/
+EFI_STATUS
+EFIAPI
+LegacyBootManagerLibConstructor (
+ IN EFI_HANDLE ImageHandle,
+ IN EFI_SYSTEM_TABLE *SystemTable
+)
+{
+ EfiBootManagerRegisterLegacyBootSupport (
+ LegacyBmRefreshAllBootOption,
+ LegacyBmBoot
+ );
+ return EFI_SUCCESS;
+}
+
+/**
+ Get the device type from the input legacy device path.
+
+ @param DevicePath The legacy device path.
+
+ @retval The legacy device type.
+**/
+UINT16
+LegacyBmDeviceType (
+ EFI_DEVICE_PATH_PROTOCOL *DevicePath
+ )
+{
+ ASSERT ((DevicePathType (DevicePath) == BBS_DEVICE_PATH) &&
+ (DevicePathSubType (DevicePath) == BBS_BBS_DP));
+ return ((BBS_BBS_DEVICE_PATH *) DevicePath)->DeviceType;
+}
+
+/**
+ Validate the BbsEntry base on the Boot Priority info in the BbsEntry.
+
+ @param BbsEntry The input bbs entry info.
+
+ @retval TRUE The BbsEntry is valid.
+ @retval FALSE The BbsEntry is invalid.
+**/
+BOOLEAN
+LegacyBmValidBbsEntry (
+ IN BBS_TABLE *BbsEntry
+ )
+{
+ switch (BbsEntry->BootPriority) {
+ case BBS_IGNORE_ENTRY:
+ case BBS_DO_NOT_BOOT_FROM:
+ case BBS_LOWEST_PRIORITY:
+ return FALSE;
+ default:
+ return TRUE;
+ }
+}
+
+/**
+ Build Legacy Device Name String according.
+
+ @param CurBBSEntry BBS Table.
+ @param Index Index.
+ @param BufSize The buffer size.
+ @param BootString The output string.
+
+**/
+VOID
+LegacyBmBuildLegacyDevNameString (
+ IN BBS_TABLE *CurBBSEntry,
+ IN UINTN Index,
+ IN UINTN BufSize,
+ OUT CHAR16 *BootString
+ )
+{
+ CHAR16 *Fmt;
+ CHAR16 *Type;
+ CHAR8 *StringDesc;
+ CHAR8 StringBufferA[LEGACY_BM_BOOT_DESCRIPTION_LENGTH + 1];
+ CHAR16 StringBufferU[LEGACY_BM_BOOT_DESCRIPTION_LENGTH + 1];
+
+ switch (Index) {
+ //
+ // Primary Master
+ //
+ case 1:
+ Fmt = L"Primary Master %s";
+ break;
+
+ //
+ // Primary Slave
+ //
+ case 2:
+ Fmt = L"Primary Slave %s";
+ break;
+
+ //
+ // Secondary Master
+ //
+ case 3:
+ Fmt = L"Secondary Master %s";
+ break;
+
+ //
+ // Secondary Slave
+ //
+ case 4:
+ Fmt = L"Secondary Slave %s";
+ break;
+
+ default:
+ Fmt = L"%s";
+ break;
+ }
+
+ switch (CurBBSEntry->DeviceType) {
+ case BBS_FLOPPY:
+ Type = L"Floppy";
+ break;
+
+ case BBS_HARDDISK:
+ Type = L"Harddisk";
+ break;
+
+ case BBS_CDROM:
+ Type = L"CDROM";
+ break;
+
+ case BBS_PCMCIA:
+ Type = L"PCMCIAe";
+ break;
+
+ case BBS_USB:
+ Type = L"USB";
+ break;
+
+ case BBS_EMBED_NETWORK:
+ Type = L"Network";
+ break;
+
+ case BBS_BEV_DEVICE:
+ Type = L"BEVe";
+ break;
+
+ case BBS_UNKNOWN:
+ default:
+ Type = L"Unknown";
+ break;
+ }
+ //
+ // If current BBS entry has its description then use it.
+ //
+ StringDesc = (CHAR8 *) (((UINTN) CurBBSEntry->DescStringSegment << 4) + CurBBSEntry->DescStringOffset);
+ if (NULL != StringDesc) {
+ //
+ // Only get fisrt 32 characters, this is suggested by BBS spec
+ //
+ CopyMem (StringBufferA, StringDesc, LEGACY_BM_BOOT_DESCRIPTION_LENGTH);
+ StringBufferA[LEGACY_BM_BOOT_DESCRIPTION_LENGTH] = 0;
+ AsciiStrToUnicodeStrS (StringBufferA, StringBufferU, ARRAY_SIZE (StringBufferU));
+ Fmt = L"%s";
+ Type = StringBufferU;
+ }
+
+ //
+ // BbsTable 16 entries are for onboard IDE.
+ // Set description string for SATA harddisks, Harddisk 0 ~ Harddisk 11
+ //
+ if (Index >= 5 && Index <= 16 && (CurBBSEntry->DeviceType == BBS_HARDDISK || CurBBSEntry->DeviceType == BBS_CDROM)) {
+ Fmt = L"%s %d";
+ UnicodeSPrint (BootString, BufSize, Fmt, Type, Index - 5);
+ } else {
+ UnicodeSPrint (BootString, BufSize, Fmt, Type);
+ }
+}
+
+/**
+ Get the Bbs index for the input boot option.
+
+ @param BootOption The input boot option info.
+ @param BbsTable The input Bbs table.
+ @param BbsCount The input total bbs entry number.
+ @param BbsIndexUsed The array shows how many BBS table indexs have been used.
+
+ @retval The index for the input boot option.
+**/
+UINT16
+LegacyBmFuzzyMatch (
+ EFI_BOOT_MANAGER_LOAD_OPTION *BootOption,
+ BBS_TABLE *BbsTable,
+ UINT16 BbsCount,
+ BOOLEAN *BbsIndexUsed
+ )
+{
+ UINT16 Index;
+ LEGACY_BM_BOOT_OPTION_BBS_DATA *BbsData;
+ CHAR16 Description[LEGACY_BM_BOOT_DESCRIPTION_LENGTH + 1];
+
+ BbsData = (LEGACY_BM_BOOT_OPTION_BBS_DATA *) BootOption->OptionalData;
+
+ //
+ // Directly check the BBS index stored in BootOption
+ //
+ if ((BbsData->BbsIndex < BbsCount) &&
+ (LegacyBmDeviceType (BootOption->FilePath) == BbsTable[BbsData->BbsIndex].DeviceType)) {
+ LegacyBmBuildLegacyDevNameString (
+ &BbsTable[BbsData->BbsIndex],
+ BbsData->BbsIndex,
+ sizeof (Description),
+ Description
+ );
+ if ((StrCmp (Description, BootOption->Description) == 0) && !BbsIndexUsed[BbsData->BbsIndex]) {
+ //
+ // If devices with the same description string are connected,
+ // the BbsIndex of the first device is returned for the other device also.
+ // So, check if the BbsIndex is already being used, before assigning the BbsIndex.
+ //
+ BbsIndexUsed[BbsData->BbsIndex] = TRUE;
+ return BbsData->BbsIndex;
+ }
+ }
+
+ //
+ // BBS table could be changed (entry removed/moved)
+ // find the correct BBS index
+ //
+ for (Index = 0; Index < BbsCount; Index++) {
+ if (!LegacyBmValidBbsEntry (&BbsTable[Index]) ||
+ (BbsTable[Index].DeviceType != LegacyBmDeviceType (BootOption->FilePath))) {
+ continue;
+ }
+
+ LegacyBmBuildLegacyDevNameString (
+ &BbsTable[Index],
+ Index,
+ sizeof (Description),
+ Description
+ );
+ if ((StrCmp (Description, BootOption->Description) == 0) && !BbsIndexUsed[Index]) {
+ //
+ // If devices with the same description string are connected,
+ // the BbsIndex of the first device is assigned for the other device also.
+ // So, check if the BbsIndex is already being used, before assigning the corrected BbsIndex.
+ //
+ break;
+ }
+ }
+
+ //
+ // Add the corrected BbsIndex in the UsedBbsIndex Buffer
+ //
+ if (Index != BbsCount) {
+ BbsIndexUsed[Index] = TRUE;
+ }
+
+ return Index;
+}
+
+/**
+
+ Update legacy device order base on the input info.
+
+ @param LegacyDevOrder Legacy device order data buffer.
+ @param LegacyDevOrderSize Legacy device order data buffer size.
+ @param DeviceType Device type which need to check.
+ @param OldBbsIndex Old Bds Index.
+ @param NewBbsIndex New Bds Index, if it is -1,means remove this option.
+
+**/
+VOID
+LegacyBmUpdateBbsIndex (
+ LEGACY_DEV_ORDER_ENTRY *LegacyDevOrder,
+ UINTN *LegacyDevOrderSize,
+ UINT16 DeviceType,
+ UINT16 OldBbsIndex,
+ UINT16 NewBbsIndex // Delete entry if -1
+ )
+{
+ LEGACY_DEV_ORDER_ENTRY *Entry;
+ UINTN Index;
+
+ ASSERT (((LegacyDevOrder == NULL) && (*LegacyDevOrderSize == 0)) ||
+ ((LegacyDevOrder != NULL) && (*LegacyDevOrderSize != 0))
+ );
+
+ for (Entry = LegacyDevOrder;
+ Entry < (LEGACY_DEV_ORDER_ENTRY *) ((UINT8 *) LegacyDevOrder + *LegacyDevOrderSize);
+ Entry = (LEGACY_DEV_ORDER_ENTRY *) ((UINTN) Entry + sizeof (BBS_TYPE) + Entry->Length)
+ ) {
+ if (Entry->BbsType == DeviceType) {
+ for (Index = 0; Index < Entry->Length / sizeof (UINT16) - 1; Index++) {
+ if (Entry->Data[Index] == OldBbsIndex) {
+ if (NewBbsIndex == (UINT16) -1) {
+ //
+ // Delete the old entry
+ //
+ CopyMem (
+ &Entry->Data[Index],
+ &Entry->Data[Index + 1],
+ (UINT8 *) LegacyDevOrder + *LegacyDevOrderSize - (UINT8 *) &Entry->Data[Index + 1]
+ );
+ Entry->Length -= sizeof (UINT16);
+ *LegacyDevOrderSize -= sizeof(UINT16);
+ } else {
+ Entry->Data[Index] = NewBbsIndex;
+ }
+ break;
+ }
+ }
+ break;
+ }
+ }
+}
+
+/**
+ Delete all the legacy boot options.
+
+ @retval EFI_SUCCESS All legacy boot options are deleted.
+**/
+EFI_STATUS
+LegacyBmDeleteAllBootOptions (
+ VOID
+ )
+{
+ EFI_STATUS Status;
+ UINTN Index;
+ EFI_BOOT_MANAGER_LOAD_OPTION *BootOption;
+ UINTN BootOptionCount;
+
+ BootOption = EfiBootManagerGetLoadOptions (&BootOptionCount, LoadOptionTypeBoot);
+ for (Index = 0; Index < BootOptionCount; Index++) {
+ if ((DevicePathType (BootOption[Index].FilePath) == BBS_DEVICE_PATH) &&
+ (DevicePathSubType (BootOption[Index].FilePath) == BBS_BBS_DP)) {
+ Status = EfiBootManagerDeleteLoadOptionVariable (BootOption[Index].OptionNumber, BootOption[Index].OptionType);
+ //
+ // Deleting variable with current variable implementation shouldn't fail.
+ //
+ ASSERT_EFI_ERROR (Status);
+ }
+ }
+
+ Status = gRT->SetVariable (
+ VAR_LEGACY_DEV_ORDER,
+ &gEfiLegacyDevOrderVariableGuid,
+ 0,
+ 0,
+ NULL
+ );
+ //
+ // Deleting variable with current variable implementation shouldn't fail.
+ //
+ ASSERT (Status == EFI_SUCCESS || Status == EFI_NOT_FOUND);
+
+ return EFI_SUCCESS;
+}
+
+
+/**
+ Delete all the invalid legacy boot options.
+
+ @retval EFI_SUCCESS All invalide legacy boot options are deleted.
+ @retval EFI_OUT_OF_RESOURCES Fail to allocate necessary memory.
+ @retval EFI_NOT_FOUND Fail to retrive variable of boot order.
+**/
+EFI_STATUS
+LegacyBmDeleteAllInvalidBootOptions (
+ VOID
+ )
+{
+ EFI_STATUS Status;
+ UINT16 HddCount;
+ UINT16 BbsCount;
+ HDD_INFO *HddInfo;
+ BBS_TABLE *BbsTable;
+ UINT16 BbsIndex;
+ EFI_LEGACY_BIOS_PROTOCOL *LegacyBios;
+ UINTN Index;
+ EFI_BOOT_MANAGER_LOAD_OPTION *BootOption;
+ UINTN BootOptionCount;
+ LEGACY_DEV_ORDER_ENTRY *LegacyDevOrder;
+ UINTN LegacyDevOrderSize;
+ BOOLEAN *BbsIndexUsed;
+
+ HddCount = 0;
+ BbsCount = 0;
+ HddInfo = NULL;
+ BbsTable = NULL;
+
+ Status = gBS->LocateProtocol (&gEfiLegacyBiosProtocolGuid, NULL, (VOID **) &LegacyBios);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ Status = LegacyBios->GetBbsInfo (
+ LegacyBios,
+ &HddCount,
+ &HddInfo,
+ &BbsCount,
+ &BbsTable
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ GetVariable2 (VAR_LEGACY_DEV_ORDER, &gEfiLegacyDevOrderVariableGuid, (VOID **) &LegacyDevOrder, &LegacyDevOrderSize);
+
+ BootOption = EfiBootManagerGetLoadOptions (&BootOptionCount, LoadOptionTypeBoot);
+
+ BbsIndexUsed = AllocateZeroPool (BbsCount * sizeof (BOOLEAN));
+ ASSERT (BbsIndexUsed != NULL);
+
+ for (Index = 0; Index < BootOptionCount; Index++) {
+ //
+ // Skip non legacy boot option
+ //
+ if ((DevicePathType (BootOption[Index].FilePath) != BBS_DEVICE_PATH) ||
+ (DevicePathSubType (BootOption[Index].FilePath) != BBS_BBS_DP)) {
+ continue;
+ }
+
+ BbsIndex = LegacyBmFuzzyMatch (&BootOption[Index], BbsTable, BbsCount, BbsIndexUsed);
+ if (BbsIndex == BbsCount) {
+ DEBUG ((EFI_D_INFO, "[LegacyBds] Delete Boot Option Boot%04x: %s\n", (UINTN) BootOption[Index].OptionNumber, BootOption[Index].Description));
+ //
+ // Delete entry from LegacyDevOrder
+ //
+ LegacyBmUpdateBbsIndex (
+ LegacyDevOrder,
+ &LegacyDevOrderSize,
+ LegacyBmDeviceType (BootOption[Index].FilePath),
+ ((LEGACY_BM_BOOT_OPTION_BBS_DATA *) BootOption[Index].OptionalData)->BbsIndex,
+ (UINT16) -1
+ );
+ EfiBootManagerDeleteLoadOptionVariable (BootOption[Index].OptionNumber, BootOption[Index].OptionType);
+ } else {
+ if (((LEGACY_BM_BOOT_OPTION_BBS_DATA *) BootOption[Index].OptionalData)->BbsIndex != BbsIndex) {
+ DEBUG ((EFI_D_INFO, "[LegacyBds] Update Boot Option Boot%04x: %s Bbs0x%04x->Bbs0x%04x\n", (UINTN) BootOption[Index].OptionNumber, BootOption[Index].Description,
+ (UINTN) ((LEGACY_BM_BOOT_OPTION_BBS_DATA *) BootOption[Index].OptionalData)->BbsIndex, (UINTN) BbsIndex));
+ //
+ // Update the BBS index in LegacyDevOrder
+ //
+ LegacyBmUpdateBbsIndex (
+ LegacyDevOrder,
+ &LegacyDevOrderSize,
+ LegacyBmDeviceType (BootOption[Index].FilePath),
+ ((LEGACY_BM_BOOT_OPTION_BBS_DATA *) BootOption[Index].OptionalData)->BbsIndex,
+ BbsIndex
+ );
+
+ //
+ // Update the OptionalData in the Boot#### variable
+ //
+ ((LEGACY_BM_BOOT_OPTION_BBS_DATA *) BootOption[Index].OptionalData)->BbsIndex = BbsIndex;
+ EfiBootManagerLoadOptionToVariable (&BootOption[Index]);
+ }
+ }
+ }
+ EfiBootManagerFreeLoadOptions (BootOption, BootOptionCount);
+
+ if (LegacyDevOrder != NULL) {
+ Status = gRT->SetVariable (
+ VAR_LEGACY_DEV_ORDER,
+ &gEfiLegacyDevOrderVariableGuid,
+ EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_NON_VOLATILE,
+ LegacyDevOrderSize,
+ LegacyDevOrder
+ );
+ //
+ // Shrink variable with current variable implementation shouldn't fail.
+ //
+ ASSERT_EFI_ERROR (Status);
+
+ FreePool (LegacyDevOrder);
+ }
+ FreePool(BbsIndexUsed);
+ return Status;
+}
+
+/**
+ Create legacy boot option.
+
+ @param BootOption Ponter to the boot option which will be crated.
+ @param BbsEntry The input bbs entry info.
+ @param BbsIndex The BBS index.
+
+ @retval EFI_SUCCESS Create legacy boot option successfully.
+ @retval EFI_INVALID_PARAMETER Invalid input parameter.
+
+**/
+EFI_STATUS
+LegacyBmCreateLegacyBootOption (
+ IN OUT EFI_BOOT_MANAGER_LOAD_OPTION *BootOption,
+ IN BBS_TABLE *BbsEntry,
+ IN UINT16 BbsIndex
+ )
+{
+ EFI_STATUS Status;
+ EFI_DEVICE_PATH_PROTOCOL *DevicePath;
+ CHAR16 Description[LEGACY_BM_BOOT_DESCRIPTION_LENGTH + 1];
+ CHAR8 HelpString[LEGACY_BM_BOOT_DESCRIPTION_LENGTH + 1];
+ UINTN StringLen;
+ LEGACY_BM_BOOT_OPTION_BBS_DATA *OptionalData;
+ BBS_BBS_DEVICE_PATH *BbsNode;
+
+ if ((BootOption == NULL) || (BbsEntry == NULL)) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ LegacyBmBuildLegacyDevNameString (BbsEntry, BbsIndex, sizeof (Description), Description);
+
+ //
+ // Create the BBS device path with description string
+ //
+ UnicodeStrToAsciiStrS (Description, HelpString, sizeof (HelpString));
+ StringLen = AsciiStrLen (HelpString);
+ DevicePath = AllocatePool (sizeof (BBS_BBS_DEVICE_PATH) + StringLen + END_DEVICE_PATH_LENGTH);
+ ASSERT (DevicePath != NULL);
+
+ BbsNode = (BBS_BBS_DEVICE_PATH *) DevicePath;
+ SetDevicePathNodeLength (BbsNode, sizeof (BBS_BBS_DEVICE_PATH) + StringLen);
+ BbsNode->Header.Type = BBS_DEVICE_PATH;
+ BbsNode->Header.SubType = BBS_BBS_DP;
+ BbsNode->DeviceType = BbsEntry->DeviceType;
+ CopyMem (&BbsNode->StatusFlag, &BbsEntry->StatusFlags, sizeof (BBS_STATUS_FLAGS));
+ CopyMem (BbsNode->String, HelpString, StringLen + 1);
+
+ SetDevicePathEndNode (NextDevicePathNode (BbsNode));
+
+ //
+ // Create the OptionalData
+ //
+ OptionalData = AllocatePool (sizeof (LEGACY_BM_BOOT_OPTION_BBS_DATA));
+ ASSERT (OptionalData != NULL);
+ OptionalData->BbsIndex = BbsIndex;
+
+ //
+ // Create the BootOption
+ //
+ Status = EfiBootManagerInitializeLoadOption (
+ BootOption,
+ LoadOptionNumberUnassigned,
+ LoadOptionTypeBoot,
+ LOAD_OPTION_ACTIVE,
+ Description,
+ DevicePath,
+ (UINT8 *) OptionalData,
+ sizeof (LEGACY_BM_BOOT_OPTION_BBS_DATA)
+ );
+ FreePool (DevicePath);
+ FreePool (OptionalData);
+
+ return Status;
+}
+
+/**
+ Fill the device order buffer.
+
+ @param BbsTable The BBS table.
+ @param BbsType The BBS Type.
+ @param BbsCount The BBS Count.
+ @param Buf device order buffer.
+
+ @return The device order buffer.
+
+**/
+UINT16 *
+LegacyBmFillDevOrderBuf (
+ IN BBS_TABLE *BbsTable,
+ IN BBS_TYPE BbsType,
+ IN UINTN BbsCount,
+ OUT UINT16 *Buf
+ )
+{
+ UINTN Index;
+
+ for (Index = 0; Index < BbsCount; Index++) {
+ if (!LegacyBmValidBbsEntry (&BbsTable[Index])) {
+ continue;
+ }
+
+ if (BbsTable[Index].DeviceType != BbsType) {
+ continue;
+ }
+
+ *Buf = (UINT16) (Index & 0xFF);
+ Buf++;
+ }
+
+ return Buf;
+}
+
+/**
+ Create the device order buffer.
+
+ @param BbsTable The BBS table.
+ @param BbsCount The BBS Count.
+
+ @retval EFI_SUCCES The buffer is created and the EFI variable named
+ VAR_LEGACY_DEV_ORDER and EfiLegacyDevOrderGuid is
+ set correctly.
+ @retval EFI_OUT_OF_RESOURCES Memmory or storage is not enough.
+ @retval EFI_DEVICE_ERROR Fail to add the device order into EFI variable fail
+ because of hardware error.
+**/
+EFI_STATUS
+LegacyBmCreateDevOrder (
+ IN BBS_TABLE *BbsTable,
+ IN UINT16 BbsCount
+ )
+{
+ UINTN Index;
+ UINTN FDCount;
+ UINTN HDCount;
+ UINTN CDCount;
+ UINTN NETCount;
+ UINTN BEVCount;
+ UINTN TotalSize;
+ UINTN HeaderSize;
+ LEGACY_DEV_ORDER_ENTRY *DevOrder;
+ LEGACY_DEV_ORDER_ENTRY *DevOrderPtr;
+ EFI_STATUS Status;
+
+ FDCount = 0;
+ HDCount = 0;
+ CDCount = 0;
+ NETCount = 0;
+ BEVCount = 0;
+ TotalSize = 0;
+ HeaderSize = sizeof (BBS_TYPE) + sizeof (UINT16);
+ DevOrder = NULL;
+ Status = EFI_SUCCESS;
+
+ //
+ // Count all boot devices
+ //
+ for (Index = 0; Index < BbsCount; Index++) {
+ if (!LegacyBmValidBbsEntry (&BbsTable[Index])) {
+ continue;
+ }
+
+ switch (BbsTable[Index].DeviceType) {
+ case BBS_FLOPPY:
+ FDCount++;
+ break;
+
+ case BBS_HARDDISK:
+ HDCount++;
+ break;
+
+ case BBS_CDROM:
+ CDCount++;
+ break;
+
+ case BBS_EMBED_NETWORK:
+ NETCount++;
+ break;
+
+ case BBS_BEV_DEVICE:
+ BEVCount++;
+ break;
+
+ default:
+ break;
+ }
+ }
+
+ TotalSize += (HeaderSize + sizeof (UINT16) * FDCount);
+ TotalSize += (HeaderSize + sizeof (UINT16) * HDCount);
+ TotalSize += (HeaderSize + sizeof (UINT16) * CDCount);
+ TotalSize += (HeaderSize + sizeof (UINT16) * NETCount);
+ TotalSize += (HeaderSize + sizeof (UINT16) * BEVCount);
+
+ //
+ // Create buffer to hold all boot device order
+ //
+ DevOrder = AllocateZeroPool (TotalSize);
+ if (NULL == DevOrder) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+ DevOrderPtr = DevOrder;
+
+ DevOrderPtr->BbsType = BBS_FLOPPY;
+ DevOrderPtr->Length = (UINT16) (sizeof (DevOrderPtr->Length) + FDCount * sizeof (UINT16));
+ DevOrderPtr = (LEGACY_DEV_ORDER_ENTRY *) LegacyBmFillDevOrderBuf (BbsTable, BBS_FLOPPY, BbsCount, DevOrderPtr->Data);
+
+ DevOrderPtr->BbsType = BBS_HARDDISK;
+ DevOrderPtr->Length = (UINT16) (sizeof (UINT16) + HDCount * sizeof (UINT16));
+ DevOrderPtr = (LEGACY_DEV_ORDER_ENTRY *) LegacyBmFillDevOrderBuf (BbsTable, BBS_HARDDISK, BbsCount, DevOrderPtr->Data);
+
+ DevOrderPtr->BbsType = BBS_CDROM;
+ DevOrderPtr->Length = (UINT16) (sizeof (UINT16) + CDCount * sizeof (UINT16));
+ DevOrderPtr = (LEGACY_DEV_ORDER_ENTRY *) LegacyBmFillDevOrderBuf (BbsTable, BBS_CDROM, BbsCount, DevOrderPtr->Data);
+
+ DevOrderPtr->BbsType = BBS_EMBED_NETWORK;
+ DevOrderPtr->Length = (UINT16) (sizeof (UINT16) + NETCount * sizeof (UINT16));
+ DevOrderPtr = (LEGACY_DEV_ORDER_ENTRY *) LegacyBmFillDevOrderBuf (BbsTable, BBS_EMBED_NETWORK, BbsCount, DevOrderPtr->Data);
+
+ DevOrderPtr->BbsType = BBS_BEV_DEVICE;
+ DevOrderPtr->Length = (UINT16) (sizeof (UINT16) + BEVCount * sizeof (UINT16));
+ DevOrderPtr = (LEGACY_DEV_ORDER_ENTRY *) LegacyBmFillDevOrderBuf (BbsTable, BBS_BEV_DEVICE, BbsCount, DevOrderPtr->Data);
+
+ ASSERT (TotalSize == ((UINTN) DevOrderPtr - (UINTN) DevOrder));
+
+ //
+ // Save device order for legacy boot device to variable.
+ //
+ Status = gRT->SetVariable (
+ VAR_LEGACY_DEV_ORDER,
+ &gEfiLegacyDevOrderVariableGuid,
+ EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_NON_VOLATILE,
+ TotalSize,
+ DevOrder
+ );
+ FreePool (DevOrder);
+
+ return Status;
+}
+
+/**
+ Add the legacy boot devices from BBS table into
+ the legacy device boot order.
+
+ @retval EFI_SUCCESS The boot devices are added successfully.
+ @retval EFI_NOT_FOUND The legacy boot devices are not found.
+ @retval EFI_OUT_OF_RESOURCES Memmory or storage is not enough.
+ @retval EFI_DEVICE_ERROR Fail to add the legacy device boot order into EFI variable
+ because of hardware error.
+**/
+EFI_STATUS
+LegacyBmUpdateDevOrder (
+ VOID
+ )
+{
+ LEGACY_DEV_ORDER_ENTRY *DevOrder;
+ LEGACY_DEV_ORDER_ENTRY *NewDevOrder;
+ LEGACY_DEV_ORDER_ENTRY *Ptr;
+ LEGACY_DEV_ORDER_ENTRY *NewPtr;
+ EFI_LEGACY_BIOS_PROTOCOL *LegacyBios;
+ EFI_STATUS Status;
+ UINT16 HddCount;
+ UINT16 BbsCount;
+ HDD_INFO *LocalHddInfo;
+ BBS_TABLE *LocalBbsTable;
+ UINTN Index;
+ UINTN Index2;
+ UINTN *Idx;
+ UINTN FDCount;
+ UINTN HDCount;
+ UINTN CDCount;
+ UINTN NETCount;
+ UINTN BEVCount;
+ UINTN TotalSize;
+ UINTN HeaderSize;
+ UINT16 *NewFDPtr;
+ UINT16 *NewHDPtr;
+ UINT16 *NewCDPtr;
+ UINT16 *NewNETPtr;
+ UINT16 *NewBEVPtr;
+ UINT16 *NewDevPtr;
+ UINTN FDIndex;
+ UINTN HDIndex;
+ UINTN CDIndex;
+ UINTN NETIndex;
+ UINTN BEVIndex;
+
+ Idx = NULL;
+ FDCount = 0;
+ HDCount = 0;
+ CDCount = 0;
+ NETCount = 0;
+ BEVCount = 0;
+ TotalSize = 0;
+ HeaderSize = sizeof (BBS_TYPE) + sizeof (UINT16);
+ FDIndex = 0;
+ HDIndex = 0;
+ CDIndex = 0;
+ NETIndex = 0;
+ BEVIndex = 0;
+ NewDevPtr = NULL;
+
+ Status = gBS->LocateProtocol (&gEfiLegacyBiosProtocolGuid, NULL, (VOID **) &LegacyBios);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ Status = LegacyBios->GetBbsInfo (
+ LegacyBios,
+ &HddCount,
+ &LocalHddInfo,
+ &BbsCount,
+ &LocalBbsTable
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ GetVariable2 (VAR_LEGACY_DEV_ORDER, &gEfiLegacyDevOrderVariableGuid, (VOID **) &DevOrder, NULL);
+ if (NULL == DevOrder) {
+ return LegacyBmCreateDevOrder (LocalBbsTable, BbsCount);
+ }
+ //
+ // First we figure out how many boot devices with same device type respectively
+ //
+ for (Index = 0; Index < BbsCount; Index++) {
+ if (!LegacyBmValidBbsEntry (&LocalBbsTable[Index])) {
+ continue;
+ }
+
+ switch (LocalBbsTable[Index].DeviceType) {
+ case BBS_FLOPPY:
+ FDCount++;
+ break;
+
+ case BBS_HARDDISK:
+ HDCount++;
+ break;
+
+ case BBS_CDROM:
+ CDCount++;
+ break;
+
+ case BBS_EMBED_NETWORK:
+ NETCount++;
+ break;
+
+ case BBS_BEV_DEVICE:
+ BEVCount++;
+ break;
+
+ default:
+ break;
+ }
+ }
+
+ TotalSize += (HeaderSize + FDCount * sizeof (UINT16));
+ TotalSize += (HeaderSize + HDCount * sizeof (UINT16));
+ TotalSize += (HeaderSize + CDCount * sizeof (UINT16));
+ TotalSize += (HeaderSize + NETCount * sizeof (UINT16));
+ TotalSize += (HeaderSize + BEVCount * sizeof (UINT16));
+
+ NewDevOrder = AllocateZeroPool (TotalSize);
+ if (NULL == NewDevOrder) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ //
+ // copy FD
+ //
+ Ptr = DevOrder;
+ NewPtr = NewDevOrder;
+ NewPtr->BbsType = Ptr->BbsType;
+ NewPtr->Length = (UINT16) (sizeof (UINT16) + FDCount * sizeof (UINT16));
+ for (Index = 0; Index < Ptr->Length / sizeof (UINT16) - 1; Index++) {
+ if (!LegacyBmValidBbsEntry (&LocalBbsTable[Ptr->Data[Index] & 0xFF]) ||
+ LocalBbsTable[Ptr->Data[Index] & 0xFF].DeviceType != BBS_FLOPPY
+ ) {
+ continue;
+ }
+
+ NewPtr->Data[FDIndex] = Ptr->Data[Index];
+ FDIndex++;
+ }
+ NewFDPtr = NewPtr->Data;
+
+ //
+ // copy HD
+ //
+ Ptr = (LEGACY_DEV_ORDER_ENTRY *) (&Ptr->Data[Ptr->Length / sizeof (UINT16) - 1]);
+ NewPtr = (LEGACY_DEV_ORDER_ENTRY *) (&NewPtr->Data[NewPtr->Length / sizeof (UINT16) -1]);
+ NewPtr->BbsType = Ptr->BbsType;
+ NewPtr->Length = (UINT16) (sizeof (UINT16) + HDCount * sizeof (UINT16));
+ for (Index = 0; Index < Ptr->Length / sizeof (UINT16) - 1; Index++) {
+ if (!LegacyBmValidBbsEntry (&LocalBbsTable[Ptr->Data[Index] & 0xFF]) ||
+ LocalBbsTable[Ptr->Data[Index] & 0xFF].DeviceType != BBS_HARDDISK
+ ) {
+ continue;
+ }
+
+ NewPtr->Data[HDIndex] = Ptr->Data[Index];
+ HDIndex++;
+ }
+ NewHDPtr = NewPtr->Data;
+
+ //
+ // copy CD
+ //
+ Ptr = (LEGACY_DEV_ORDER_ENTRY *) (&Ptr->Data[Ptr->Length / sizeof (UINT16) - 1]);
+ NewPtr = (LEGACY_DEV_ORDER_ENTRY *) (&NewPtr->Data[NewPtr->Length / sizeof (UINT16) -1]);
+ NewPtr->BbsType = Ptr->BbsType;
+ NewPtr->Length = (UINT16) (sizeof (UINT16) + CDCount * sizeof (UINT16));
+ for (Index = 0; Index < Ptr->Length / sizeof (UINT16) - 1; Index++) {
+ if (!LegacyBmValidBbsEntry (&LocalBbsTable[Ptr->Data[Index] & 0xFF]) ||
+ LocalBbsTable[Ptr->Data[Index] & 0xFF].DeviceType != BBS_CDROM
+ ) {
+ continue;
+ }
+
+ NewPtr->Data[CDIndex] = Ptr->Data[Index];
+ CDIndex++;
+ }
+ NewCDPtr = NewPtr->Data;
+
+ //
+ // copy NET
+ //
+ Ptr = (LEGACY_DEV_ORDER_ENTRY *) (&Ptr->Data[Ptr->Length / sizeof (UINT16) - 1]);
+ NewPtr = (LEGACY_DEV_ORDER_ENTRY *) (&NewPtr->Data[NewPtr->Length / sizeof (UINT16) -1]);
+ NewPtr->BbsType = Ptr->BbsType;
+ NewPtr->Length = (UINT16) (sizeof (UINT16) + NETCount * sizeof (UINT16));
+ for (Index = 0; Index < Ptr->Length / sizeof (UINT16) - 1; Index++) {
+ if (!LegacyBmValidBbsEntry (&LocalBbsTable[Ptr->Data[Index] & 0xFF]) ||
+ LocalBbsTable[Ptr->Data[Index] & 0xFF].DeviceType != BBS_EMBED_NETWORK
+ ) {
+ continue;
+ }
+
+ NewPtr->Data[NETIndex] = Ptr->Data[Index];
+ NETIndex++;
+ }
+ NewNETPtr = NewPtr->Data;
+
+ //
+ // copy BEV
+ //
+ Ptr = (LEGACY_DEV_ORDER_ENTRY *) (&Ptr->Data[Ptr->Length / sizeof (UINT16) - 1]);
+ NewPtr = (LEGACY_DEV_ORDER_ENTRY *) (&NewPtr->Data[NewPtr->Length / sizeof (UINT16) -1]);
+ NewPtr->BbsType = Ptr->BbsType;
+ NewPtr->Length = (UINT16) (sizeof (UINT16) + BEVCount * sizeof (UINT16));
+ for (Index = 0; Index < Ptr->Length / sizeof (UINT16) - 1; Index++) {
+ if (!LegacyBmValidBbsEntry (&LocalBbsTable[Ptr->Data[Index] & 0xFF]) ||
+ LocalBbsTable[Ptr->Data[Index] & 0xFF].DeviceType != BBS_BEV_DEVICE
+ ) {
+ continue;
+ }
+
+ NewPtr->Data[BEVIndex] = Ptr->Data[Index];
+ BEVIndex++;
+ }
+ NewBEVPtr = NewPtr->Data;
+
+ for (Index = 0; Index < BbsCount; Index++) {
+ if (!LegacyBmValidBbsEntry (&LocalBbsTable[Index])) {
+ continue;
+ }
+
+ switch (LocalBbsTable[Index].DeviceType) {
+ case BBS_FLOPPY:
+ Idx = &FDIndex;
+ NewDevPtr = NewFDPtr;
+ break;
+
+ case BBS_HARDDISK:
+ Idx = &HDIndex;
+ NewDevPtr = NewHDPtr;
+ break;
+
+ case BBS_CDROM:
+ Idx = &CDIndex;
+ NewDevPtr = NewCDPtr;
+ break;
+
+ case BBS_EMBED_NETWORK:
+ Idx = &NETIndex;
+ NewDevPtr = NewNETPtr;
+ break;
+
+ case BBS_BEV_DEVICE:
+ Idx = &BEVIndex;
+ NewDevPtr = NewBEVPtr;
+ break;
+
+ default:
+ Idx = NULL;
+ break;
+ }
+ //
+ // at this point we have copied those valid indexes to new buffer
+ // and we should check if there is any new appeared boot device
+ //
+ if (Idx != NULL) {
+ for (Index2 = 0; Index2 < *Idx; Index2++) {
+ if ((NewDevPtr[Index2] & 0xFF) == (UINT16) Index) {
+ break;
+ }
+ }
+
+ if (Index2 == *Idx) {
+ //
+ // Index2 == *Idx means we didn't find Index
+ // so Index is a new appeared device's index in BBS table
+ // insert it before disabled indexes.
+ //
+ for (Index2 = 0; Index2 < *Idx; Index2++) {
+ if ((NewDevPtr[Index2] & 0xFF00) == 0xFF00) {
+ break;
+ }
+ }
+ CopyMem (&NewDevPtr[Index2 + 1], &NewDevPtr[Index2], (*Idx - Index2) * sizeof (UINT16));
+ NewDevPtr[Index2] = (UINT16) (Index & 0xFF);
+ (*Idx)++;
+ }
+ }
+ }
+
+ FreePool (DevOrder);
+
+ Status = gRT->SetVariable (
+ VAR_LEGACY_DEV_ORDER,
+ &gEfiLegacyDevOrderVariableGuid,
+ EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_NON_VOLATILE,
+ TotalSize,
+ NewDevOrder
+ );
+ FreePool (NewDevOrder);
+
+ return Status;
+}
+
+/**
+ Set Boot Priority for specified device type.
+
+ @param DeviceType The device type.
+ @param BbsIndex The BBS index to set the highest priority. Ignore when -1.
+ @param LocalBbsTable The BBS table.
+ @param Priority The prority table.
+
+ @retval EFI_SUCCESS The function completes successfully.
+ @retval EFI_NOT_FOUND Failed to find device.
+ @retval EFI_OUT_OF_RESOURCES Failed to get the efi variable of device order.
+
+**/
+EFI_STATUS
+LegacyBmSetPriorityForSameTypeDev (
+ IN UINT16 DeviceType,
+ IN UINTN BbsIndex,
+ IN OUT BBS_TABLE *LocalBbsTable,
+ IN OUT UINT16 *Priority
+ )
+{
+ LEGACY_DEV_ORDER_ENTRY *DevOrder;
+ LEGACY_DEV_ORDER_ENTRY *DevOrderPtr;
+ UINTN DevOrderSize;
+ UINTN Index;
+
+ GetVariable2 (VAR_LEGACY_DEV_ORDER, &gEfiLegacyDevOrderVariableGuid, (VOID **) &DevOrder, &DevOrderSize);
+ if (NULL == DevOrder) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ DevOrderPtr = DevOrder;
+ while ((UINT8 *) DevOrderPtr < (UINT8 *) DevOrder + DevOrderSize) {
+ if (DevOrderPtr->BbsType == DeviceType) {
+ break;
+ }
+
+ DevOrderPtr = (LEGACY_DEV_ORDER_ENTRY *) ((UINTN) DevOrderPtr + sizeof (BBS_TYPE) + DevOrderPtr->Length);
+ }
+
+ if ((UINT8 *) DevOrderPtr >= (UINT8 *) DevOrder + DevOrderSize) {
+ FreePool (DevOrder);
+ return EFI_NOT_FOUND;
+ }
+
+ if (BbsIndex != (UINTN) -1) {
+ //
+ // In case the BBS entry isn't valid because devices were plugged or removed.
+ //
+ if (!LegacyBmValidBbsEntry (&LocalBbsTable[BbsIndex]) || (LocalBbsTable[BbsIndex].DeviceType != DeviceType)) {
+ FreePool (DevOrder);
+ return EFI_NOT_FOUND;
+ }
+ LocalBbsTable[BbsIndex].BootPriority = *Priority;
+ (*Priority)++;
+ }
+ //
+ // If the high byte of the DevIndex is 0xFF, it indicates that this device has been disabled.
+ //
+ for (Index = 0; Index < DevOrderPtr->Length / sizeof (UINT16) - 1; Index++) {
+ if ((DevOrderPtr->Data[Index] & 0xFF00) == 0xFF00) {
+ //
+ // LocalBbsTable[DevIndex[Index] & 0xFF].BootPriority = BBS_DISABLED_ENTRY;
+ //
+ } else if (DevOrderPtr->Data[Index] != BbsIndex) {
+ LocalBbsTable[DevOrderPtr->Data[Index]].BootPriority = *Priority;
+ (*Priority)++;
+ }
+ }
+
+ FreePool (DevOrder);
+ return EFI_SUCCESS;
+}
+
+/**
+ Print the BBS Table.
+
+ @param LocalBbsTable The BBS table.
+ @param BbsCount The count of entry in BBS table.
+**/
+VOID
+LegacyBmPrintBbsTable (
+ IN BBS_TABLE *LocalBbsTable,
+ IN UINT16 BbsCount
+ )
+{
+ UINT16 Index;
+
+ DEBUG ((DEBUG_INFO, "\n"));
+ DEBUG ((DEBUG_INFO, " NO Prio bb/dd/ff cl/sc Type Stat segm:offs\n"));
+ DEBUG ((DEBUG_INFO, "=============================================\n"));
+ for (Index = 0; Index < BbsCount; Index++) {
+ if (!LegacyBmValidBbsEntry (&LocalBbsTable[Index])) {
+ continue;
+ }
+
+ DEBUG (
+ (DEBUG_INFO,
+ " %02x: %04x %02x/%02x/%02x %02x/%02x %04x %04x %04x:%04x\n",
+ (UINTN) Index,
+ (UINTN) LocalBbsTable[Index].BootPriority,
+ (UINTN) LocalBbsTable[Index].Bus,
+ (UINTN) LocalBbsTable[Index].Device,
+ (UINTN) LocalBbsTable[Index].Function,
+ (UINTN) LocalBbsTable[Index].Class,
+ (UINTN) LocalBbsTable[Index].SubClass,
+ (UINTN) LocalBbsTable[Index].DeviceType,
+ (UINTN) * (UINT16 *) &LocalBbsTable[Index].StatusFlags,
+ (UINTN) LocalBbsTable[Index].BootHandlerSegment,
+ (UINTN) LocalBbsTable[Index].BootHandlerOffset,
+ (UINTN) ((LocalBbsTable[Index].MfgStringSegment << 4) + LocalBbsTable[Index].MfgStringOffset),
+ (UINTN) ((LocalBbsTable[Index].DescStringSegment << 4) + LocalBbsTable[Index].DescStringOffset))
+ );
+ }
+
+ DEBUG ((DEBUG_INFO, "\n"));
+}
+
+/**
+ Set the boot priority for BBS entries based on boot option entry and boot order.
+
+ @param BootOption The boot option is to be checked for refresh BBS table.
+
+ @retval EFI_SUCCESS The boot priority for BBS entries is refreshed successfully.
+ @retval EFI_NOT_FOUND BBS entries can't be found.
+ @retval EFI_OUT_OF_RESOURCES Failed to get the legacy device boot order.
+**/
+EFI_STATUS
+LegacyBmRefreshBbsTableForBoot (
+ IN EFI_BOOT_MANAGER_LOAD_OPTION *BootOption
+ )
+{
+ EFI_STATUS Status;
+ UINT16 BbsIndex;
+ UINT16 HddCount;
+ UINT16 BbsCount;
+ HDD_INFO *LocalHddInfo;
+ BBS_TABLE *LocalBbsTable;
+ UINT16 DevType;
+ EFI_LEGACY_BIOS_PROTOCOL *LegacyBios;
+ UINTN Index;
+ UINT16 Priority;
+ UINT16 *DeviceType;
+ UINTN DeviceTypeCount;
+ UINTN DeviceTypeIndex;
+ EFI_BOOT_MANAGER_LOAD_OPTION *Option;
+ UINTN OptionCount;
+
+ HddCount = 0;
+ BbsCount = 0;
+ LocalHddInfo = NULL;
+ LocalBbsTable = NULL;
+ DevType = BBS_UNKNOWN;
+
+ Status = gBS->LocateProtocol (&gEfiLegacyBiosProtocolGuid, NULL, (VOID **) &LegacyBios);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ Status = LegacyBios->GetBbsInfo (
+ LegacyBios,
+ &HddCount,
+ &LocalHddInfo,
+ &BbsCount,
+ &LocalBbsTable
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ //
+ // First, set all the present devices' boot priority to BBS_UNPRIORITIZED_ENTRY
+ // We will set them according to the settings setup by user
+ //
+ for (Index = 0; Index < BbsCount; Index++) {
+ if (LegacyBmValidBbsEntry (&LocalBbsTable[Index])) {
+ LocalBbsTable[Index].BootPriority = BBS_UNPRIORITIZED_ENTRY;
+ }
+ }
+ //
+ // boot priority always starts at 0
+ //
+ Priority = 0;
+ if ((DevicePathType (BootOption->FilePath) == BBS_DEVICE_PATH) &&
+ (DevicePathSubType (BootOption->FilePath) == BBS_BBS_DP)) {
+ //
+ // If BootOption stands for a legacy boot option, we prioritize the devices with the same type first.
+ //
+ DevType = LegacyBmDeviceType (BootOption->FilePath);
+ BbsIndex = ((LEGACY_BM_BOOT_OPTION_BBS_DATA *) BootOption->OptionalData)->BbsIndex;
+ Status = LegacyBmSetPriorityForSameTypeDev (
+ DevType,
+ BbsIndex,
+ LocalBbsTable,
+ &Priority
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+ }
+ //
+ // we have to set the boot priority for other BBS entries with different device types
+ //
+ Option = EfiBootManagerGetLoadOptions (&OptionCount, LoadOptionTypeBoot);
+ DeviceType = AllocatePool (sizeof (UINT16) * OptionCount);
+ ASSERT (DeviceType != NULL);
+ DeviceType[0] = DevType;
+ DeviceTypeCount = 1;
+ for (Index = 0; Index < OptionCount; Index++) {
+ if ((DevicePathType (Option[Index].FilePath) != BBS_DEVICE_PATH) ||
+ (DevicePathSubType (Option[Index].FilePath) != BBS_BBS_DP)) {
+ continue;
+ }
+
+ DevType = LegacyBmDeviceType (Option[Index].FilePath);
+ for (DeviceTypeIndex = 0; DeviceTypeIndex < DeviceTypeCount; DeviceTypeIndex++) {
+ if (DeviceType[DeviceTypeIndex] == DevType) {
+ break;
+ }
+ }
+ if (DeviceTypeIndex < DeviceTypeCount) {
+ //
+ // We don't want to process twice for a device type
+ //
+ continue;
+ }
+
+ DeviceType[DeviceTypeCount] = DevType;
+ DeviceTypeCount++;
+
+ Status = LegacyBmSetPriorityForSameTypeDev (
+ DevType,
+ (UINTN) -1,
+ LocalBbsTable,
+ &Priority
+ );
+ }
+ EfiBootManagerFreeLoadOptions (Option, OptionCount);
+
+ DEBUG_CODE_BEGIN();
+ LegacyBmPrintBbsTable (LocalBbsTable, BbsCount);
+ DEBUG_CODE_END();
+
+ return Status;
+}
+
+
+/**
+ Boot the legacy system with the boot option.
+
+ @param BootOption The legacy boot option which have BBS device path
+ On return, BootOption->Status contains the boot status.
+ EFI_UNSUPPORTED There is no legacybios protocol, do not support
+ legacy boot.
+ EFI_STATUS The status of LegacyBios->LegacyBoot ().
+**/
+VOID
+EFIAPI
+LegacyBmBoot (
+ IN EFI_BOOT_MANAGER_LOAD_OPTION *BootOption
+ )
+{
+ EFI_STATUS Status;
+ EFI_LEGACY_BIOS_PROTOCOL *LegacyBios;
+
+ Status = gBS->LocateProtocol (&gEfiLegacyBiosProtocolGuid, NULL, (VOID **) &LegacyBios);
+ if (EFI_ERROR (Status)) {
+ //
+ // If no LegacyBios protocol we do not support legacy boot
+ //
+ BootOption->Status = EFI_UNSUPPORTED;
+ return;
+ }
+ //
+ // Notes: if we separate the int 19, then we don't need to refresh BBS
+ //
+ Status = LegacyBmRefreshBbsTableForBoot (BootOption);
+ if (EFI_ERROR (Status)) {
+ BootOption->Status = Status;
+ return;
+ }
+
+ BootOption->Status = LegacyBios->LegacyBoot (
+ LegacyBios,
+ (BBS_BBS_DEVICE_PATH *) BootOption->FilePath,
+ BootOption->OptionalDataSize,
+ BootOption->OptionalData
+ );
+}
+
+/**
+ This function enumerates all the legacy boot options.
+
+ @param BootOptionCount Return the legacy boot option count.
+
+ @retval Pointer to the legacy boot option buffer.
+**/
+EFI_BOOT_MANAGER_LOAD_OPTION *
+LegacyBmEnumerateAllBootOptions (
+ UINTN *BootOptionCount
+ )
+{
+ EFI_STATUS Status;
+ UINT16 HddCount;
+ UINT16 BbsCount;
+ HDD_INFO *HddInfo;
+ BBS_TABLE *BbsTable;
+ EFI_LEGACY_BIOS_PROTOCOL *LegacyBios;
+ UINT16 Index;
+ EFI_BOOT_MANAGER_LOAD_OPTION *BootOptions;
+
+ ASSERT (BootOptionCount != NULL);
+
+ BootOptions = NULL;
+ *BootOptionCount = 0;
+ BbsCount = 0;
+
+ Status = gBS->LocateProtocol (&gEfiLegacyBiosProtocolGuid, NULL, (VOID **) &LegacyBios);
+ if (EFI_ERROR (Status)) {
+ return NULL;
+ }
+
+ Status = LegacyBios->GetBbsInfo (
+ LegacyBios,
+ &HddCount,
+ &HddInfo,
+ &BbsCount,
+ &BbsTable
+ );
+ if (EFI_ERROR (Status)) {
+ return NULL;
+ }
+
+ for (Index = 0; Index < BbsCount; Index++) {
+ if (!LegacyBmValidBbsEntry (&BbsTable[Index])) {
+ continue;
+ }
+
+ BootOptions = ReallocatePool (
+ sizeof (EFI_BOOT_MANAGER_LOAD_OPTION) * (*BootOptionCount),
+ sizeof (EFI_BOOT_MANAGER_LOAD_OPTION) * (*BootOptionCount + 1),
+ BootOptions
+ );
+ ASSERT (BootOptions != NULL);
+
+ Status = LegacyBmCreateLegacyBootOption (&BootOptions[(*BootOptionCount)++], &BbsTable[Index], Index);
+ ASSERT_EFI_ERROR (Status);
+ }
+
+ return BootOptions;
+}
+
+/**
+ Return the index of the boot option in the boot option array.
+
+ The function compares the Description, FilePath, OptionalData.
+
+ @param Key The input boot option which is compared with.
+ @param Array The input boot option array.
+ @param Count The count of the input boot options.
+
+ @retval The index of the input boot option in the array.
+
+**/
+INTN
+LegacyBmFindBootOption (
+ IN CONST EFI_BOOT_MANAGER_LOAD_OPTION *Key,
+ IN CONST EFI_BOOT_MANAGER_LOAD_OPTION *Array,
+ IN UINTN Count
+ )
+{
+ UINTN Index;
+
+ for (Index = 0; Index < Count; Index++) {
+ if ((StrCmp (Key->Description, Array[Index].Description) == 0) &&
+ (CompareMem (Key->FilePath, Array[Index].FilePath, GetDevicePathSize (Key->FilePath)) == 0) &&
+ (Key->OptionalDataSize == Array[Index].OptionalDataSize) &&
+ (CompareMem (Key->OptionalData, Array[Index].OptionalData, Key->OptionalDataSize) == 0)) {
+ return (INTN) Index;
+ }
+ }
+
+ return -1;
+}
+
+/**
+ Refresh all legacy boot options.
+
+**/
+VOID
+EFIAPI
+LegacyBmRefreshAllBootOption (
+ VOID
+ )
+{
+ EFI_STATUS Status;
+ EFI_LEGACY_BIOS_PROTOCOL *LegacyBios;
+ UINTN RootBridgeHandleCount;
+ EFI_HANDLE *RootBridgeHandleBuffer;
+ UINTN HandleCount;
+ EFI_HANDLE *HandleBuffer;
+ UINTN RootBridgeIndex;
+ UINTN Index;
+ UINTN Flags;
+ EFI_BOOT_MANAGER_LOAD_OPTION *BootOptions;
+ UINTN BootOptionCount;
+ EFI_BOOT_MANAGER_LOAD_OPTION *ExistingBootOptions;
+ UINTN ExistingBootOptionCount;
+
+ Status = gBS->LocateProtocol (&gEfiLegacyBiosProtocolGuid, NULL, (VOID **) &LegacyBios);
+ if (EFI_ERROR (Status)) {
+ LegacyBmDeleteAllBootOptions ();
+ return;
+ }
+ PERF_START (NULL, "LegacyBootOptionEnum", "BDS", 0);
+
+ //
+ // Before enumerating the legacy boot option, we need to dispatch all the legacy option roms
+ // to ensure the GetBbsInfo() counts all the legacy devices.
+ //
+ gBS->LocateHandleBuffer (
+ ByProtocol,
+ &gEfiPciRootBridgeIoProtocolGuid,
+ NULL,
+ &RootBridgeHandleCount,
+ &RootBridgeHandleBuffer
+ );
+ for (RootBridgeIndex = 0; RootBridgeIndex < RootBridgeHandleCount; RootBridgeIndex++) {
+ gBS->ConnectController (RootBridgeHandleBuffer[RootBridgeIndex], NULL, NULL, FALSE);
+ gBS->LocateHandleBuffer (
+ ByProtocol,
+ &gEfiPciIoProtocolGuid,
+ NULL,
+ &HandleCount,
+ &HandleBuffer
+ );
+ for (Index = 0; Index < HandleCount; Index++) {
+ //
+ // Start the thunk driver so that the legacy option rom gets dispatched.
+ // Note: We don't directly call InstallPciRom because some thunk drivers
+ // (e.g. BlockIo thunk driver) depend on the immediate result after dispatching
+ //
+ Status = LegacyBios->CheckPciRom (
+ LegacyBios,
+ HandleBuffer[Index],
+ NULL,
+ NULL,
+ &Flags
+ );
+ if (!EFI_ERROR (Status)) {
+ gBS->ConnectController (HandleBuffer[Index], NULL, NULL, FALSE);
+ }
+ }
+ }
+
+ //
+ // Same algorithm pattern as the EfiBootManagerRefreshAllBootOption
+ // Firstly delete the invalid legacy boot options,
+ // then enumreate and save the newly appeared legacy boot options
+ // the last step is legacy boot option special action to refresh the LegacyDevOrder variable
+ //
+ LegacyBmDeleteAllInvalidBootOptions ();
+
+ ExistingBootOptions = EfiBootManagerGetLoadOptions (&ExistingBootOptionCount, LoadOptionTypeBoot);
+ BootOptions = LegacyBmEnumerateAllBootOptions (&BootOptionCount);
+
+ for (Index = 0; Index < BootOptionCount; Index++) {
+ if (LegacyBmFindBootOption (&BootOptions[Index], ExistingBootOptions, ExistingBootOptionCount) == -1) {
+ Status = EfiBootManagerAddLoadOptionVariable (&BootOptions[Index], (UINTN) -1);
+ DEBUG ((
+ EFI_D_INFO, "[LegacyBds] New Boot Option: Boot%04x Bbs0x%04x %s %r\n",
+ (UINTN) BootOptions[Index].OptionNumber,
+ (UINTN) ((LEGACY_BM_BOOT_OPTION_BBS_DATA *) BootOptions[Index].OptionalData)->BbsIndex,
+ BootOptions[Index].Description,
+ Status
+ ));
+ //
+ // Continue upon failure to add boot option.
+ //
+ }
+ }
+
+ EfiBootManagerFreeLoadOptions (ExistingBootOptions, ExistingBootOptionCount);
+ EfiBootManagerFreeLoadOptions (BootOptions, BootOptionCount);
+
+ //
+ // Failure to create LegacyDevOrder variable only impacts the boot order.
+ //
+ LegacyBmUpdateDevOrder ();
+
+ PERF_END (NULL, "LegacyBootOptionEnum", "BDS", 0);
+}
diff --git a/OvmfPkg/Csm/LegacyBootManagerLib/LegacyBootManagerLib.inf b/OvmfPkg/Csm/LegacyBootManagerLib/LegacyBootManagerLib.inf
new file mode 100644
index 0000000000..eaf7b7235d
--- /dev/null
+++ b/OvmfPkg/Csm/LegacyBootManagerLib/LegacyBootManagerLib.inf
@@ -0,0 +1,58 @@
+## @file
+# Legacy Boot Manager module is library for BDS phase.
+#
+# Copyright (c) 2011 - 2018, Intel Corporation. All rights reserved.<BR>
+# SPDX-License-Identifier: BSD-2-Clause-Patent
+#
+##
+
+[Defines]
+ INF_VERSION = 0x00010005
+ BASE_NAME = LegacyBootManagerLib
+ MODULE_UNI_FILE = LegacyBootManagerLib.uni
+ FILE_GUID = F1B87BE4-0ACC-409A-A52B-7BFFABCC96A0
+ MODULE_TYPE = DXE_DRIVER
+ VERSION_STRING = 1.0
+ LIBRARY_CLASS = NULL|DXE_DRIVER UEFI_APPLICATION
+ CONSTRUCTOR = LegacyBootManagerLibConstructor
+
+#
+# The following information is for reference only and not required by the build tools.
+#
+# VALID_ARCHITECTURES = IA32 X64 EBC
+#
+
+[Sources]
+ LegacyBm.c
+ InternalLegacyBm.h
+
+[Packages]
+ MdePkg/MdePkg.dec
+ MdeModulePkg/MdeModulePkg.dec
+ IntelFrameworkPkg/IntelFrameworkPkg.dec
+ IntelFrameworkModulePkg/IntelFrameworkModulePkg.dec
+
+[LibraryClasses]
+ BaseLib
+ BaseMemoryLib
+ UefiBootServicesTableLib
+ UefiRuntimeServicesTableLib
+ DevicePathLib
+ MemoryAllocationLib
+ UefiLib
+ DebugLib
+ PrintLib
+ PerformanceLib
+ UefiBootManagerLib
+
+[Guids]
+ gEfiGlobalVariableGuid ## SOMETIMES_PRODUCES ## Variable:L"Boot####" (Boot option variable)
+ ## SOMETIMES_CONSUMES ## Variable:L"BootOrder" (The boot option array)
+ gEfiLegacyDevOrderVariableGuid
+
+[Protocols]
+ gEfiLegacyBiosProtocolGuid ## SOMETIMES_CONSUMES
+
+[FeaturePcd]
+
+[Pcd]
diff --git a/OvmfPkg/Csm/LegacyBootManagerLib/LegacyBootManagerLib.uni b/OvmfPkg/Csm/LegacyBootManagerLib/LegacyBootManagerLib.uni
new file mode 100644
index 0000000000..da2915a9a3
--- /dev/null
+++ b/OvmfPkg/Csm/LegacyBootManagerLib/LegacyBootManagerLib.uni
@@ -0,0 +1,20 @@
+// /** @file
+// Legacy Boot Manager module is library for BDS phase.
+//
+// Legacy Boot Manager module is library for BDS phase.
+//
+// Copyright (c) 2015, Intel Corporation. All rights reserved.<BR>
+//
+// SPDX-License-Identifier: BSD-2-Clause-Patent
+//
+// **/
+
+#string STR_MODULE_ABSTRACT
+#language en-US
+"Legacy Boot Manager module is library for BDS phase."
+
+#string STR_MODULE_DESCRIPTION
+#language en-US
+"Legacy Boot Manager module is library for BDS phase."
+
+