From 9e3f171d816429218b3e72341b2056d349f30d8c Mon Sep 17 00:00:00 2001 From: Ruiyu Ni Date: Wed, 6 May 2015 04:50:23 +0000 Subject: [PATCH 1/1] IntelFrameworkModulePkg: Add LegacyBootManagerLib. LegacyBootManagerLib is a NULL class library to work with UefiBootManagerLib providing legacy boot support. Contributed-under: TianoCore Contribution Agreement 1.0 Signed-off-by: Ruiyu Ni Reviewed-by: Eric Dong git-svn-id: https://svn.code.sf.net/p/edk2/code/trunk/edk2@17330 6f19259b-4bc3-4df7-8a09-765794883524 --- .../IntelFrameworkModulePkg.dsc | 3 +- .../LegacyBootManagerLib/InternalLegacyBm.h | 66 + .../Library/LegacyBootManagerLib/LegacyBm.c | 1536 +++++++++++++++++ .../LegacyBootManagerLib.inf | 65 + 4 files changed, 1669 insertions(+), 1 deletion(-) create mode 100644 IntelFrameworkModulePkg/Library/LegacyBootManagerLib/InternalLegacyBm.h create mode 100644 IntelFrameworkModulePkg/Library/LegacyBootManagerLib/LegacyBm.c create mode 100644 IntelFrameworkModulePkg/Library/LegacyBootManagerLib/LegacyBootManagerLib.inf diff --git a/IntelFrameworkModulePkg/IntelFrameworkModulePkg.dsc b/IntelFrameworkModulePkg/IntelFrameworkModulePkg.dsc index 7505301232..20e016d363 100644 --- a/IntelFrameworkModulePkg/IntelFrameworkModulePkg.dsc +++ b/IntelFrameworkModulePkg/IntelFrameworkModulePkg.dsc @@ -3,7 +3,7 @@ # # This file is used to build all modules in IntelFrameworkModulePkg. # -#Copyright (c) 2007 - 2014, Intel Corporation. All rights reserved.
+#Copyright (c) 2007 - 2015, Intel Corporation. All rights reserved.
#This program and the accompanying materials are licensed and made available under #the terms and conditions of the BSD License that accompanies this distribution. #The full text of the license may be found at @@ -139,6 +139,7 @@ IntelFrameworkModulePkg/Library/PlatformBdsLibNull/PlatformBdsLibNull.inf IntelFrameworkModulePkg/Library/GenericBdsLib/GenericBdsLib.inf IntelFrameworkModulePkg/Library/DxeCapsuleLib/DxeCapsuleLib.inf + IntelFrameworkModulePkg/Library/LegacyBootManagerLib/LegacyBootManagerLib.inf IntelFrameworkModulePkg/Bus/Pci/IdeBusDxe/IdeBusDxe.inf IntelFrameworkModulePkg/Bus/Isa/IsaBusDxe/IsaBusDxe.inf diff --git a/IntelFrameworkModulePkg/Library/LegacyBootManagerLib/InternalLegacyBm.h b/IntelFrameworkModulePkg/Library/LegacyBootManagerLib/InternalLegacyBm.h new file mode 100644 index 0000000000..e7bdde9def --- /dev/null +++ b/IntelFrameworkModulePkg/Library/LegacyBootManagerLib/InternalLegacyBm.h @@ -0,0 +1,66 @@ +/** @file + +Copyright (c) 2011 - 2015, Intel Corporation. All rights reserved.
+This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +**/ + +#ifndef _INTERNAL_LEGACY_BM_H_ +#define _INTERNAL_LEGACY_BM_H_ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#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_ \ No newline at end of file diff --git a/IntelFrameworkModulePkg/Library/LegacyBootManagerLib/LegacyBm.c b/IntelFrameworkModulePkg/Library/LegacyBootManagerLib/LegacyBm.c new file mode 100644 index 0000000000..1ed42d527a --- /dev/null +++ b/IntelFrameworkModulePkg/Library/LegacyBootManagerLib/LegacyBm.c @@ -0,0 +1,1536 @@ +/** @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 - 2015, Intel Corporation. All rights reserved.
+This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +**/ + +#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; + AsciiStrToUnicodeStr (StringBufferA, 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 + // + UnicodeStrToAsciiStr (Description, 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) ((UINT8 *) DevOrderPtr - (UINT8 *) 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/IntelFrameworkModulePkg/Library/LegacyBootManagerLib/LegacyBootManagerLib.inf b/IntelFrameworkModulePkg/Library/LegacyBootManagerLib/LegacyBootManagerLib.inf new file mode 100644 index 0000000000..2dc03a8f83 --- /dev/null +++ b/IntelFrameworkModulePkg/Library/LegacyBootManagerLib/LegacyBootManagerLib.inf @@ -0,0 +1,65 @@ +## @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 - 2015, Intel Corporation. All rights reserved.
+# This program and the accompanying materials +# are licensed and made available under the terms and conditions of the BSD License +# which accompanies this distribution. The full text of the license may be found at +# http://opensource.org/licenses/bsd-license.php +# +# THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +# WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. +# +## + +[Defines] + INF_VERSION = 0x00010005 + BASE_NAME = LegacyBootManagerLib + 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] -- 2.39.2