From a10fb70c1b106f4c816c010c5161b3d6566de95a Mon Sep 17 00:00:00 2001 From: srs5694 Date: Wed, 28 Aug 2013 04:00:20 -0400 Subject: [PATCH] New CSM/BIOS/legacy support code for UEFI PCs. --- EfiLib/legacy.c | 1363 +++++++++++++++++++++++++++++++++++++++++++++++ EfiLib/legacy.h | 70 +++ 2 files changed, 1433 insertions(+) create mode 100644 EfiLib/legacy.c create mode 100644 EfiLib/legacy.h diff --git a/EfiLib/legacy.c b/EfiLib/legacy.c new file mode 100644 index 0000000..3aae71d --- /dev/null +++ b/EfiLib/legacy.c @@ -0,0 +1,1363 @@ +/* + * EfiLib/legacy.c + * CSM/legacy boot support functions + * + * Taken from Tianocore source code (mostly IntelFrameworkModulePkg/Universal/BdsDxe/BootMaint/BBSsupport.c) + * + * Copyright (c) 2004 - 2011, 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 "../include/tiano_includes.h" +#include "legacy.h" + +BOOT_OPTION_BBS_MAPPING *mBootOptionBbsMapping = NULL; +UINTN mBootOptionBbsMappingCount = 0; + +extern EFI_DEVICE_PATH EndDevicePath[]; + +/** + + Translate the first n characters of an Ascii string to + Unicode characters. The count n is indicated by parameter + Size. If Size is greater than the length of string, then + the entire string is translated. + + + @param AStr Pointer to input Ascii string. + @param Size The number of characters to translate. + @param UStr Pointer to output Unicode string buffer. + +**/ +VOID +AsciiToUnicodeSize ( + IN UINT8 *AStr, + IN UINTN Size, + OUT UINT16 *UStr + ) +{ + UINTN Idx; + + Idx = 0; + while (AStr[Idx] != 0) { + UStr[Idx] = (CHAR16) AStr[Idx]; + if (Idx == Size) { + break; + } + + Idx++; + } + UStr[Idx] = 0; +} + +/** + Build Legacy Device Name String according. + + @param CurBBSEntry BBS Table. + @param Index Index. + @param BufSize The buffer size. + @param BootString The output string. + +**/ +VOID +BdsBuildLegacyDevNameString ( + IN BBS_TABLE *CurBBSEntry, + IN UINTN Index, + IN UINTN BufSize, + OUT CHAR16 *BootString + ) +{ + CHAR16 *Fmt; + CHAR16 *Type; + UINT8 *StringDesc; + CHAR16 Temp[80]; + + 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 = (UINT8 *) (UINTN) ((CurBBSEntry->DescStringSegment << 4) + CurBBSEntry->DescStringOffset); + if (NULL != StringDesc) { + // + // Only get fisrt 32 characters, this is suggested by BBS spec + // + AsciiToUnicodeSize (StringDesc, 32, Temp); + Fmt = L"%s"; + Type = Temp; + } + + // + // 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); + } +} + +/** + Check if the boot option is a legacy one. + + @param BootOptionVar The boot option data payload. + @param BbsEntry The BBS Table. + @param BbsIndex The table index. + + @retval TRUE It is a legacy boot option. + @retval FALSE It is not a legacy boot option. + +**/ +BOOLEAN +BdsIsLegacyBootOption ( + IN UINT8 *BootOptionVar, + OUT BBS_TABLE **BbsEntry, + OUT UINT16 *BbsIndex + ) +{ + UINT8 *Ptr; + EFI_DEVICE_PATH_PROTOCOL *DevicePath; + BOOLEAN Ret; + UINT16 DevPathLen; + + Ptr = BootOptionVar; + Ptr += sizeof (UINT32); + DevPathLen = *(UINT16 *) Ptr; + Ptr += sizeof (UINT16); + Ptr += StrSize ((UINT16 *) Ptr); + DevicePath = (EFI_DEVICE_PATH_PROTOCOL *) Ptr; + if ((BBS_DEVICE_PATH == DevicePath->Type) && (BBS_BBS_DP == DevicePath->SubType)) { + Ptr += DevPathLen; + *BbsEntry = (BBS_TABLE *) Ptr; + Ptr += sizeof (BBS_TABLE); + *BbsIndex = *(UINT16 *) Ptr; + Ret = TRUE; + } else { + *BbsEntry = NULL; + Ret = FALSE; + } + + return Ret; +} + +/** + Find all legacy boot option by device type. + + @param BootOrder The boot order array. + @param BootOptionNum The number of boot option. + @param DevType Device type. + @param DevName Device name. + @param Attribute The boot option attribute. + @param BbsIndex The BBS table index. + @param OptionNumber The boot option index. + + @retval TRUE The Legacy boot option is found. + @retval FALSE The legacy boot option is not found. + +**/ +BOOLEAN +BdsFindLegacyBootOptionByDevTypeAndName ( + IN UINT16 *BootOrder, + IN UINTN BootOptionNum, + IN UINT16 DevType, + IN CHAR16 *DevName, + OUT UINT32 *Attribute, + OUT UINT16 *BbsIndex, + OUT UINT16 *OptionNumber + ) +{ + UINTN Index; + CHAR16 BootOption[9]; + UINTN BootOptionSize; + UINT8 *BootOptionVar; + BBS_TABLE *BbsEntry; + BOOLEAN Found; + + BbsEntry = NULL; + Found = FALSE; + + if (NULL == BootOrder) { + return Found; + } + + // + // Loop all boot option from variable + // + for (Index = 0; Index < BootOptionNum; Index++) { + UnicodeSPrint (BootOption, sizeof (BootOption), L"Boot%04x", (UINTN) BootOrder[Index]); + BootOptionVar = BdsLibGetVariableAndSize ( + BootOption, + &gEfiGlobalVariableGuid, + &BootOptionSize + ); + if (NULL == BootOptionVar) { + continue; + } + + // + // Skip Non-legacy boot option + // + if (!BdsIsLegacyBootOption (BootOptionVar, &BbsEntry, BbsIndex)) { + FreePool (BootOptionVar); + continue; + } + + if ( + (BbsEntry->DeviceType != DevType) || + (StrCmp (DevName, (CHAR16*)(BootOptionVar + sizeof (UINT32) + sizeof (UINT16))) != 0) + ) { + FreePool (BootOptionVar); + continue; + } + + *Attribute = *(UINT32 *) BootOptionVar; + *OptionNumber = BootOrder[Index]; + Found = TRUE; + FreePool (BootOptionVar); + break; + } + + return Found; +} + +/** + + Create a legacy boot option for the specified entry of + BBS table, save it as variable, and append it to the boot + order list. + + + @param CurrentBbsEntry Pointer to current BBS table. + @param CurrentBbsDevPath Pointer to the Device Path Protocol instance of BBS + @param Index Index of the specified entry in BBS table. + @param BootOrderList On input, the original boot order list. + On output, the new boot order list attached with the + created node. + @param BootOrderListSize On input, the original size of boot order list. + On output, the size of new boot order list. + + @retval EFI_SUCCESS Boot Option successfully created. + @retval EFI_OUT_OF_RESOURCES Fail to allocate necessary memory. + @retval Other Error occurs while setting variable. + +**/ +EFI_STATUS +BdsCreateLegacyBootOption ( + IN BBS_TABLE *CurrentBbsEntry, + IN EFI_DEVICE_PATH_PROTOCOL *CurrentBbsDevPath, + IN UINTN Index, + IN OUT UINT16 **BootOrderList, + IN OUT UINTN *BootOrderListSize + ) +{ + EFI_STATUS Status; + UINT16 CurrentBootOptionNo; + UINT16 BootString[10]; + CHAR16 BootDesc[100]; + CHAR8 HelpString[100]; + UINT16 *NewBootOrderList; + UINTN BufferSize; + UINTN StringLen; + VOID *Buffer; + UINT8 *Ptr; + UINT16 CurrentBbsDevPathSize; + UINTN BootOrderIndex; + UINTN BootOrderLastIndex; + UINTN ArrayIndex; + BOOLEAN IndexNotFound; + BBS_BBS_DEVICE_PATH *NewBbsDevPathNode; + + if ((*BootOrderList) == NULL) { + CurrentBootOptionNo = 0; + } else { + for (ArrayIndex = 0; ArrayIndex < (UINTN) (*BootOrderListSize / sizeof (UINT16)); ArrayIndex++) { + IndexNotFound = TRUE; + for (BootOrderIndex = 0; BootOrderIndex < (UINTN) (*BootOrderListSize / sizeof (UINT16)); BootOrderIndex++) { + if ((*BootOrderList)[BootOrderIndex] == ArrayIndex) { + IndexNotFound = FALSE; + break; + } + } + + if (!IndexNotFound) { + continue; + } else { + break; + } + } + + CurrentBootOptionNo = (UINT16) ArrayIndex; + } + + UnicodeSPrint ( + BootString, + sizeof (BootString), + L"Boot%04x", + CurrentBootOptionNo + ); + + BdsBuildLegacyDevNameString (CurrentBbsEntry, Index, sizeof (BootDesc), BootDesc); + + // + // Create new BBS device path node with description string + // + UnicodeStrToAsciiStr (BootDesc, HelpString); + + StringLen = AsciiStrLen (HelpString); + NewBbsDevPathNode = AllocateZeroPool (sizeof (BBS_BBS_DEVICE_PATH) + StringLen); + if (NewBbsDevPathNode == NULL) { + return EFI_OUT_OF_RESOURCES; + } + CopyMem (NewBbsDevPathNode, CurrentBbsDevPath, sizeof (BBS_BBS_DEVICE_PATH)); + CopyMem (NewBbsDevPathNode->String, HelpString, StringLen + 1); + SetDevicePathNodeLength (&(NewBbsDevPathNode->Header), sizeof (BBS_BBS_DEVICE_PATH) + StringLen); + + // + // Create entire new CurrentBbsDevPath with end node + // + CurrentBbsDevPath = AppendDevicePathNode ( + EndDevicePath, + (EFI_DEVICE_PATH_PROTOCOL *) NewBbsDevPathNode + ); + if (CurrentBbsDevPath == NULL) { + FreePool (NewBbsDevPathNode); + return EFI_OUT_OF_RESOURCES; + } + + CurrentBbsDevPathSize = (UINT16) (GetDevicePathSize (CurrentBbsDevPath)); + + BufferSize = sizeof (UINT32) + + sizeof (UINT16) + + StrSize (BootDesc) + + CurrentBbsDevPathSize + + sizeof (BBS_TABLE) + + sizeof (UINT16); + + Buffer = AllocateZeroPool (BufferSize); + if (Buffer == NULL) { + FreePool (NewBbsDevPathNode); + FreePool (CurrentBbsDevPath); + return EFI_OUT_OF_RESOURCES; + } + + Ptr = (UINT8 *) Buffer; + + *((UINT32 *) Ptr) = LOAD_OPTION_ACTIVE; + Ptr += sizeof (UINT32); + + *((UINT16 *) Ptr) = CurrentBbsDevPathSize; + Ptr += sizeof (UINT16); + + CopyMem ( + Ptr, + BootDesc, + StrSize (BootDesc) + ); + Ptr += StrSize (BootDesc); + + CopyMem ( + Ptr, + CurrentBbsDevPath, + CurrentBbsDevPathSize + ); + Ptr += CurrentBbsDevPathSize; + + CopyMem ( + Ptr, + CurrentBbsEntry, + sizeof (BBS_TABLE) + ); + + Ptr += sizeof (BBS_TABLE); + *((UINT16 *) Ptr) = (UINT16) Index; + + Status = gRT->SetVariable ( + BootString, + &gEfiGlobalVariableGuid, + VAR_FLAG, + BufferSize, + Buffer + ); + + FreePool (Buffer); + + Buffer = NULL; + + NewBootOrderList = AllocateZeroPool (*BootOrderListSize + sizeof (UINT16)); + if (NULL == NewBootOrderList) { + FreePool (NewBbsDevPathNode); + FreePool (CurrentBbsDevPath); + return EFI_OUT_OF_RESOURCES; + } + + if (*BootOrderList != NULL) { + CopyMem (NewBootOrderList, *BootOrderList, *BootOrderListSize); + FreePool (*BootOrderList); + } + + BootOrderLastIndex = (UINTN) (*BootOrderListSize / sizeof (UINT16)); + NewBootOrderList[BootOrderLastIndex] = CurrentBootOptionNo; + *BootOrderListSize += sizeof (UINT16); + *BootOrderList = NewBootOrderList; + + FreePool (NewBbsDevPathNode); + FreePool (CurrentBbsDevPath); + return Status; +} + +/** + Create a legacy boot option. + + @param BbsItem The BBS Table entry. + @param Index Index of the specified entry in BBS table. + @param BootOrderList The boot order list. + @param BootOrderListSize The size of boot order list. + + @retval EFI_OUT_OF_RESOURCE No enough memory. + @retval EFI_SUCCESS The function complete successfully. + @return Other value if the legacy boot option is not created. + +**/ +EFI_STATUS +BdsCreateOneLegacyBootOption ( + IN BBS_TABLE *BbsItem, + IN UINTN Index, + IN OUT UINT16 **BootOrderList, + IN OUT UINTN *BootOrderListSize + ) +{ + BBS_BBS_DEVICE_PATH BbsDevPathNode; + EFI_STATUS Status; + EFI_DEVICE_PATH_PROTOCOL *DevPath; + + DevPath = NULL; + + // + // Create device path node. + // + BbsDevPathNode.Header.Type = BBS_DEVICE_PATH; + BbsDevPathNode.Header.SubType = BBS_BBS_DP; + SetDevicePathNodeLength (&BbsDevPathNode.Header, sizeof (BBS_BBS_DEVICE_PATH)); + BbsDevPathNode.DeviceType = BbsItem->DeviceType; + CopyMem (&BbsDevPathNode.StatusFlag, &BbsItem->StatusFlags, sizeof (UINT16)); + + DevPath = AppendDevicePathNode ( + EndDevicePath, + (EFI_DEVICE_PATH_PROTOCOL *) &BbsDevPathNode + ); + if (NULL == DevPath) { + return EFI_OUT_OF_RESOURCES; + } + + Status = BdsCreateLegacyBootOption ( + BbsItem, + DevPath, + Index, + BootOrderList, + BootOrderListSize + ); + BbsItem->BootPriority = 0x00; + + FreePool (DevPath); + + return Status; +} + +/** + Group the legacy boot options in the BootOption. + + The routine assumes the boot options in the beginning that covers all the device + types are ordered properly and re-position the following boot options just after + the corresponding boot options with the same device type. + For example: + 1. Input = [Harddisk1 CdRom2 Efi1 Harddisk0 CdRom0 CdRom1 Harddisk2 Efi0] + Assuming [Harddisk1 CdRom2 Efi1] is ordered properly + Output = [Harddisk1 Harddisk0 Harddisk2 CdRom2 CdRom0 CdRom1 Efi1 Efi0] + + 2. Input = [Efi1 Efi0 CdRom1 Harddisk0 Harddisk1 Harddisk2 CdRom0 CdRom2] + Assuming [Efi1 Efi0 CdRom1 Harddisk0] is ordered properly + Output = [Efi1 Efi0 CdRom1 CdRom0 CdRom2 Harddisk0 Harddisk1 Harddisk2] + + @param BootOption Pointer to buffer containing Boot Option Numbers + @param BootOptionCount Count of the Boot Option Numbers +**/ +VOID +GroupMultipleLegacyBootOption4SameType ( + UINT16 *BootOption, + UINTN BootOptionCount + ) +{ + UINTN DeviceTypeIndex[7]; + UINTN Index; + UINTN MappingIndex; + UINTN *NextIndex; + UINT16 OptionNumber; + UINTN DeviceIndex; + + SetMem (DeviceTypeIndex, sizeof (DeviceTypeIndex), 0xFF); + + for (Index = 0; Index < BootOptionCount; Index++) { + + // + // Find the DeviceType + // + for (MappingIndex = 0; MappingIndex < mBootOptionBbsMappingCount; MappingIndex++) { + if (mBootOptionBbsMapping[MappingIndex].BootOptionNumber == BootOption[Index]) { + break; + } + } + if (MappingIndex == mBootOptionBbsMappingCount) { + // + // Is not a legacy boot option + // + continue; + } + + ASSERT ((mBootOptionBbsMapping[MappingIndex].BbsType & 0xF) < + sizeof (DeviceTypeIndex) / sizeof (DeviceTypeIndex[0])); + NextIndex = &DeviceTypeIndex[mBootOptionBbsMapping[MappingIndex].BbsType & 0xF]; + if (*NextIndex == (UINTN) -1) { + // + // *NextIndex is the index in BootOption to put the next Option Number for the same type + // + *NextIndex = Index + 1; + } else { + // + // insert the current boot option before *NextIndex, causing [*Next .. Index] shift right one position + // + OptionNumber = BootOption[Index]; + CopyMem (&BootOption[*NextIndex + 1], &BootOption[*NextIndex], (Index - *NextIndex) * sizeof (UINT16)); + BootOption[*NextIndex] = OptionNumber; + + // + // Update the DeviceTypeIndex array to reflect the right shift operation + // + for (DeviceIndex = 0; DeviceIndex < sizeof (DeviceTypeIndex) / sizeof (DeviceTypeIndex[0]); DeviceIndex++) { + if (DeviceTypeIndex[DeviceIndex] != (UINTN) -1 && DeviceTypeIndex[DeviceIndex] >= *NextIndex) { + DeviceTypeIndex[DeviceIndex]++; + } + } + } + } +} + +/** + Function returns the value of the specified variable. + + + @param Name A Null-terminated Unicode string that is + the name of the vendor's variable. + @param VendorGuid A unique identifier for the vendor. + + @return The payload of the variable. + @retval NULL If the variable can't be read. + +**/ +VOID * +EfiLibGetVariable ( + IN CHAR16 *Name, + IN EFI_GUID *VendorGuid + ) +{ + UINTN VarSize; + + return BdsLibGetVariableAndSize (Name, VendorGuid, &VarSize); +} + +/** + Function deletes the variable specified by VarName and VarGuid. + + @param VarName A Null-terminated Unicode string that is + the name of the vendor's variable. + + @param VarGuid A unique identifier for the vendor. + + @retval EFI_SUCCESS The variable was found and removed + @retval EFI_UNSUPPORTED The variable store was inaccessible + @retval EFI_OUT_OF_RESOURCES The temporary buffer was not available + @retval EFI_NOT_FOUND The variable was not found + +**/ +EFI_STATUS +EfiLibDeleteVariable ( + IN CHAR16 *VarName, + IN EFI_GUID *VarGuid + ) +{ + VOID *VarBuf; + EFI_STATUS Status; + + VarBuf = EfiLibGetVariable (VarName, VarGuid); + Status = EFI_NOT_FOUND; + + if (VarBuf != NULL) { + // + // Delete variable from Storage + // + Status = gRT->SetVariable (VarName, VarGuid, VAR_FLAG, 0, NULL); + ASSERT (!EFI_ERROR (Status)); + FreePool (VarBuf); + } + + return Status; +} + +/** + Add the legacy boot options from BBS table if they do not exist. + + @retval EFI_SUCCESS The boot options are added successfully + or they are already in boot options. + @retval EFI_NOT_FOUND No legacy boot options is found. + @retval EFI_OUT_OF_RESOURCE No enough memory. + @return Other value LegacyBoot options are not added. +**/ +EFI_STATUS +EFIAPI +BdsAddNonExistingLegacyBootOptions ( + VOID + ) +{ + UINT16 *BootOrder; + UINTN BootOrderSize; + EFI_STATUS Status; + CHAR16 Desc[100]; + UINT16 HddCount; + UINT16 BbsCount; + HDD_INFO *LocalHddInfo; + BBS_TABLE *LocalBbsTable; + UINT16 BbsIndex; + EFI_LEGACY_BIOS_PROTOCOL *LegacyBios; + UINT16 Index; + UINT32 Attribute; + UINT16 OptionNumber; + BOOLEAN Exist; + + HddCount = 0; + BbsCount = 0; + LocalHddInfo = NULL; + LocalBbsTable = NULL; + + Status = EfiLibLocateProtocol (&gEfiLegacyBiosProtocolGuid, (VOID **) &LegacyBios); + if (EFI_ERROR (Status)) { + return Status; + } + + if (mBootOptionBbsMapping != NULL) { + FreePool (mBootOptionBbsMapping); + + mBootOptionBbsMapping = NULL; + mBootOptionBbsMappingCount = 0; + } + + LegacyBios->GetBbsInfo ( + LegacyBios, + &HddCount, + &LocalHddInfo, + &BbsCount, + &LocalBbsTable + ); + + BootOrder = BdsLibGetVariableAndSize ( + L"BootOrder", + &gEfiGlobalVariableGuid, + &BootOrderSize + ); + if (BootOrder == NULL) { + BootOrderSize = 0; + } + + for (Index = 0; Index < BbsCount; Index++) { + if ((LocalBbsTable[Index].BootPriority == BBS_IGNORE_ENTRY) || + (LocalBbsTable[Index].BootPriority == BBS_DO_NOT_BOOT_FROM) + ) { + continue; + } + + BdsBuildLegacyDevNameString (&LocalBbsTable[Index], Index, sizeof (Desc), Desc); + + Exist = BdsFindLegacyBootOptionByDevTypeAndName ( + BootOrder, + BootOrderSize / sizeof (UINT16), + LocalBbsTable[Index].DeviceType, + Desc, + &Attribute, + &BbsIndex, + &OptionNumber + ); + if (!Exist) { + // + // Not found such type of legacy device in boot options or we found but it's disabled + // so we have to create one and put it to the tail of boot order list + // + Status = BdsCreateOneLegacyBootOption ( + &LocalBbsTable[Index], + Index, + &BootOrder, + &BootOrderSize + ); + if (EFI_ERROR (Status)) { + break; + } + BbsIndex = Index; + OptionNumber = BootOrder[BootOrderSize / sizeof (UINT16) - 1]; + } + + ASSERT (BbsIndex == Index); + // + // Save the BbsIndex + // + mBootOptionBbsMapping = ReallocatePool ( + mBootOptionBbsMappingCount * sizeof (BOOT_OPTION_BBS_MAPPING), + (mBootOptionBbsMappingCount + 1) * sizeof (BOOT_OPTION_BBS_MAPPING), + mBootOptionBbsMapping + ); + ASSERT (mBootOptionBbsMapping != NULL); + mBootOptionBbsMapping[mBootOptionBbsMappingCount].BootOptionNumber = OptionNumber; + mBootOptionBbsMapping[mBootOptionBbsMappingCount].BbsIndex = Index; + mBootOptionBbsMapping[mBootOptionBbsMappingCount].BbsType = LocalBbsTable[Index].DeviceType; + mBootOptionBbsMappingCount ++; + } + + // + // Group the Boot Option Number in BootOrder for the same type devices + // + GroupMultipleLegacyBootOption4SameType ( + BootOrder, + BootOrderSize / sizeof (UINT16) + ); + + if (BootOrderSize > 0) { + Status = gRT->SetVariable ( + L"BootOrder", + &gEfiGlobalVariableGuid, + VAR_FLAG, + BootOrderSize, + BootOrder + ); + } else { + EfiLibDeleteVariable (L"BootOrder", &gEfiGlobalVariableGuid); + } + + if (BootOrder != NULL) { + FreePool (BootOrder); + } + + return Status; +} + +/** + Deletete the Boot Option from EFI Variable. The Boot Order Arrray + is also updated. + + @param OptionNumber The number of Boot option want to be deleted. + @param BootOrder The Boot Order array. + @param BootOrderSize The size of the Boot Order Array. + + @retval EFI_SUCCESS The Boot Option Variable was found and removed + @retval EFI_UNSUPPORTED The Boot Option Variable store was inaccessible + @retval EFI_NOT_FOUND The Boot Option Variable was not found +**/ +EFI_STATUS +EFIAPI +BdsDeleteBootOption ( + IN UINTN OptionNumber, + IN OUT UINT16 *BootOrder, + IN OUT UINTN *BootOrderSize + ) +{ + UINT16 BootOption[100]; + UINTN Index; + EFI_STATUS Status; + UINTN Index2Del; + + Status = EFI_SUCCESS; + Index2Del = 0; + + UnicodeSPrint (BootOption, sizeof (BootOption), L"Boot%04x", OptionNumber); + Status = EfiLibDeleteVariable (BootOption, &gEfiGlobalVariableGuid); + + // + // adjust boot order array + // + for (Index = 0; Index < *BootOrderSize / sizeof (UINT16); Index++) { + if (BootOrder[Index] == OptionNumber) { + Index2Del = Index; + break; + } + } + + if (Index != *BootOrderSize / sizeof (UINT16)) { + for (Index = 0; Index < *BootOrderSize / sizeof (UINT16) - 1; Index++) { + if (Index >= Index2Del) { + BootOrder[Index] = BootOrder[Index + 1]; + } + } + + *BootOrderSize -= sizeof (UINT16); + } + + return Status; + +} + +/** + 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 +EFIAPI +BdsDeleteAllInvalidLegacyBootOptions ( + VOID + ) +{ + UINT16 *BootOrder; + UINT8 *BootOptionVar; + UINTN BootOrderSize; + UINTN BootOptionSize; + EFI_STATUS Status; + UINT16 HddCount; + UINT16 BbsCount; + HDD_INFO *LocalHddInfo; + BBS_TABLE *LocalBbsTable; + BBS_TABLE *BbsEntry; + UINT16 BbsIndex; + EFI_LEGACY_BIOS_PROTOCOL *LegacyBios; + UINTN Index; + UINT16 BootOption[10]; + UINT16 BootDesc[100]; + BOOLEAN DescStringMatch; + + Status = EFI_SUCCESS; + BootOrder = NULL; + BootOrderSize = 0; + HddCount = 0; + BbsCount = 0; + LocalHddInfo = NULL; + LocalBbsTable = NULL; + BbsEntry = NULL; + + Status = EfiLibLocateProtocol (&gEfiLegacyBiosProtocolGuid, (VOID **) &LegacyBios); + if (EFI_ERROR (Status)) { + return Status; + } + + LegacyBios->GetBbsInfo ( + LegacyBios, + &HddCount, + &LocalHddInfo, + &BbsCount, + &LocalBbsTable + ); + + BootOrder = BdsLibGetVariableAndSize ( + L"BootOrder", + &gEfiGlobalVariableGuid, + &BootOrderSize + ); + if (BootOrder == NULL) { + BootOrderSize = 0; + } + + Index = 0; + while (Index < BootOrderSize / sizeof (UINT16)) { + UnicodeSPrint (BootOption, sizeof (BootOption), L"Boot%04x", BootOrder[Index]); + BootOptionVar = BdsLibGetVariableAndSize ( + BootOption, + &gEfiGlobalVariableGuid, + &BootOptionSize + ); + if (NULL == BootOptionVar) { + BootOptionSize = 0; + Status = gRT->GetVariable ( + BootOption, + &gEfiGlobalVariableGuid, + NULL, + &BootOptionSize, + BootOptionVar + ); + if (Status == EFI_NOT_FOUND) { + // + // Update BootOrder + // + BdsDeleteBootOption ( + BootOrder[Index], + BootOrder, + &BootOrderSize + ); + continue; + } else { + FreePool (BootOrder); + return EFI_OUT_OF_RESOURCES; + } + } + + // + // Skip Non-Legacy boot option + // + if (!BdsIsLegacyBootOption (BootOptionVar, &BbsEntry, &BbsIndex)) { + if (BootOptionVar!= NULL) { + FreePool (BootOptionVar); + } + Index++; + continue; + } + + if (BbsIndex < BbsCount) { + // + // Check if BBS Description String is changed + // + DescStringMatch = FALSE; + BdsBuildLegacyDevNameString ( + &LocalBbsTable[BbsIndex], + BbsIndex, + sizeof (BootDesc), + BootDesc + ); + + if (StrCmp (BootDesc, (UINT16*)(BootOptionVar + sizeof (UINT32) + sizeof (UINT16))) == 0) { + DescStringMatch = TRUE; + } + + if (!((LocalBbsTable[BbsIndex].BootPriority == BBS_IGNORE_ENTRY) || + (LocalBbsTable[BbsIndex].BootPriority == BBS_DO_NOT_BOOT_FROM)) && + (LocalBbsTable[BbsIndex].DeviceType == BbsEntry->DeviceType) && + DescStringMatch) { + Index++; + continue; + } + } + + if (BootOptionVar != NULL) { + FreePool (BootOptionVar); + } + // + // should delete + // + BdsDeleteBootOption ( + BootOrder[Index], + BootOrder, + &BootOrderSize + ); + } + + // + // Adjust the number of boot options. + // + if (BootOrderSize != 0) { + Status = gRT->SetVariable ( + L"BootOrder", + &gEfiGlobalVariableGuid, + VAR_FLAG, + BootOrderSize, + BootOrder + ); + } else { + EfiLibDeleteVariable (L"BootOrder", &gEfiGlobalVariableGuid); + } + + if (BootOrder != NULL) { + FreePool (BootOrder); + } + + 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 +// EFIAPI +// BdsUpdateLegacyDevOrder ( +// VOID +// ) +// { +// LEGACY_DEV_ORDER_ENTRY *DevOrder; +// LEGACY_DEV_ORDER_ENTRY *NewDevOrder; +// LEGACY_DEV_ORDER_ENTRY *Ptr; +// LEGACY_DEV_ORDER_ENTRY *NewPtr; +// UINTN DevOrderSize; +// 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 = EfiLibLocateProtocol (&gEfiLegacyBiosProtocolGuid, (VOID **) &LegacyBios); +// if (EFI_ERROR (Status)) { +// return Status; +// } +// +// Status = LegacyBios->GetBbsInfo ( +// LegacyBios, +// &HddCount, +// &LocalHddInfo, +// &BbsCount, +// &LocalBbsTable +// ); +// if (EFI_ERROR (Status)) { +// return Status; +// } +// +// DevOrder = BdsLibGetVariableAndSize ( +// VAR_LEGACY_DEV_ORDER, +// &gEfiLegacyDevOrderVariableGuid, +// &DevOrderSize +// ); +// if (NULL == DevOrder) { +// return BdsCreateDevOrder (LocalBbsTable, BbsCount); +// } +// // +// // First we figure out how many boot devices with same device type respectively +// // +// for (Index = 0; Index < BbsCount; Index++) { +// if ((LocalBbsTable[Index].BootPriority == BBS_IGNORE_ENTRY) || +// (LocalBbsTable[Index].BootPriority == BBS_DO_NOT_BOOT_FROM) +// ) { +// 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 (LocalBbsTable[Ptr->Data[Index] & 0xFF].BootPriority == BBS_IGNORE_ENTRY || +// LocalBbsTable[Ptr->Data[Index] & 0xFF].BootPriority == BBS_DO_NOT_BOOT_FROM || +// 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 (LocalBbsTable[Ptr->Data[Index] & 0xFF].BootPriority == BBS_IGNORE_ENTRY || +// LocalBbsTable[Ptr->Data[Index] & 0xFF].BootPriority == BBS_DO_NOT_BOOT_FROM || +// LocalBbsTable[Ptr->Data[Index] & 0xFF].BootPriority == BBS_LOWEST_PRIORITY || +// 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 (LocalBbsTable[Ptr->Data[Index] & 0xFF].BootPriority == BBS_IGNORE_ENTRY || +// LocalBbsTable[Ptr->Data[Index] & 0xFF].BootPriority == BBS_DO_NOT_BOOT_FROM || +// LocalBbsTable[Ptr->Data[Index] & 0xFF].BootPriority == BBS_LOWEST_PRIORITY || +// 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 (LocalBbsTable[Ptr->Data[Index] & 0xFF].BootPriority == BBS_IGNORE_ENTRY || +// LocalBbsTable[Ptr->Data[Index] & 0xFF].BootPriority == BBS_DO_NOT_BOOT_FROM || +// LocalBbsTable[Ptr->Data[Index] & 0xFF].BootPriority == BBS_LOWEST_PRIORITY || +// 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 (LocalBbsTable[Ptr->Data[Index] & 0xFF].BootPriority == BBS_IGNORE_ENTRY || +// LocalBbsTable[Ptr->Data[Index] & 0xFF].BootPriority == BBS_DO_NOT_BOOT_FROM || +// LocalBbsTable[Ptr->Data[Index] & 0xFF].BootPriority == BBS_LOWEST_PRIORITY || +// 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 ((LocalBbsTable[Index].BootPriority == BBS_IGNORE_ENTRY) || +// (LocalBbsTable[Index].BootPriority == BBS_DO_NOT_BOOT_FROM) +// ) { +// 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, +// VAR_FLAG, +// TotalSize, +// NewDevOrder +// ); +// FreePool (NewDevOrder); +// +// return Status; +// } + diff --git a/EfiLib/legacy.h b/EfiLib/legacy.h new file mode 100644 index 0000000..61dba38 --- /dev/null +++ b/EfiLib/legacy.h @@ -0,0 +1,70 @@ +/* + * EfiLib/legacy.h + * CSM/legacy boot support functions + * + * Taken from Tianocore source code (mostly IntelFrameworkModulePkg/Universal/BdsDxe/BootMaint/BBSsupport.c) + * + * Copyright (c) 2004 - 2011, 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 __LEGACY_H_ +#define __LEGACY_H_ + +#define VAR_FLAG EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_NON_VOLATILE + +#pragma pack(1) +/// +/// For each legacy boot option in BBS table, a corresponding Boot#### variables is created. +/// The structure saves the mapping relationship between #### and the index in the BBS table. +/// +typedef struct { + UINT16 BootOptionNumber; + UINT16 BbsIndex; + UINT16 BbsType; +} BOOT_OPTION_BBS_MAPPING; +#pragma pack() + +EFI_STATUS +EFIAPI +BdsAddNonExistingLegacyBootOptions ( + VOID +); + +/** + 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 +EFIAPI +BdsDeleteAllInvalidLegacyBootOptions ( + VOID + ); + +/** + 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 +// EFIAPI +// BdsUpdateLegacyDevOrder ( +// VOID +// ); + +#endif \ No newline at end of file -- 2.39.2