--- /dev/null
+/** @file\r
+ This function deal with the legacy boot option, it create, delete\r
+ and manage the legacy boot option, all legacy boot option is getting from\r
+ the legacy BBS table.\r
+\r
+Copyright (c) 2011 - 2015, Intel Corporation. All rights reserved.<BR>\r
+This program and the accompanying materials\r
+are licensed and made available under the terms and conditions of the BSD License\r
+which accompanies this distribution. The full text of the license may be found at\r
+http://opensource.org/licenses/bsd-license.php\r
+\r
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+\r
+**/\r
+\r
+#include "InternalLegacyBm.h"\r
+\r
+#define LEGACY_BM_BOOT_DESCRIPTION_LENGTH 32\r
+\r
+/**\r
+ Initialize legacy boot manager library by call EfiBootManagerRegisterLegacyBootSupport\r
+ function to export two function pointer.\r
+\r
+ @param ImageHandle The image handle.\r
+ @param SystemTable The system table.\r
+\r
+ @retval EFI_SUCCESS The legacy boot manager library is initialized correctly.\r
+ @return Other value if failed to initialize the legacy boot manager library.\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+LegacyBootManagerLibConstructor (\r
+ IN EFI_HANDLE ImageHandle,\r
+ IN EFI_SYSTEM_TABLE *SystemTable\r
+)\r
+{\r
+ EfiBootManagerRegisterLegacyBootSupport (\r
+ LegacyBmRefreshAllBootOption,\r
+ LegacyBmBoot\r
+ );\r
+ return EFI_SUCCESS;\r
+}\r
+\r
+/**\r
+ Get the device type from the input legacy device path.\r
+\r
+ @param DevicePath The legacy device path.\r
+\r
+ @retval The legacy device type.\r
+**/\r
+UINT16\r
+LegacyBmDeviceType (\r
+ EFI_DEVICE_PATH_PROTOCOL *DevicePath\r
+ )\r
+{\r
+ ASSERT ((DevicePathType (DevicePath) == BBS_DEVICE_PATH) &&\r
+ (DevicePathSubType (DevicePath) == BBS_BBS_DP));\r
+ return ((BBS_BBS_DEVICE_PATH *) DevicePath)->DeviceType;\r
+}\r
+\r
+/**\r
+ Validate the BbsEntry base on the Boot Priority info in the BbsEntry.\r
+\r
+ @param BbsEntry The input bbs entry info.\r
+\r
+ @retval TRUE The BbsEntry is valid.\r
+ @retval FALSE The BbsEntry is invalid.\r
+**/\r
+BOOLEAN\r
+LegacyBmValidBbsEntry (\r
+ IN BBS_TABLE *BbsEntry\r
+ )\r
+{\r
+ switch (BbsEntry->BootPriority) {\r
+ case BBS_IGNORE_ENTRY:\r
+ case BBS_DO_NOT_BOOT_FROM:\r
+ case BBS_LOWEST_PRIORITY:\r
+ return FALSE;\r
+ default:\r
+ return TRUE;\r
+ }\r
+}\r
+\r
+/**\r
+ Build Legacy Device Name String according.\r
+\r
+ @param CurBBSEntry BBS Table.\r
+ @param Index Index.\r
+ @param BufSize The buffer size.\r
+ @param BootString The output string.\r
+\r
+**/\r
+VOID\r
+LegacyBmBuildLegacyDevNameString (\r
+ IN BBS_TABLE *CurBBSEntry,\r
+ IN UINTN Index,\r
+ IN UINTN BufSize,\r
+ OUT CHAR16 *BootString\r
+ )\r
+{\r
+ CHAR16 *Fmt;\r
+ CHAR16 *Type;\r
+ CHAR8 *StringDesc;\r
+ CHAR8 StringBufferA[LEGACY_BM_BOOT_DESCRIPTION_LENGTH + 1];\r
+ CHAR16 StringBufferU[LEGACY_BM_BOOT_DESCRIPTION_LENGTH + 1];\r
+\r
+ switch (Index) {\r
+ //\r
+ // Primary Master\r
+ //\r
+ case 1:\r
+ Fmt = L"Primary Master %s";\r
+ break;\r
+\r
+ //\r
+ // Primary Slave\r
+ //\r
+ case 2:\r
+ Fmt = L"Primary Slave %s";\r
+ break;\r
+\r
+ //\r
+ // Secondary Master\r
+ //\r
+ case 3:\r
+ Fmt = L"Secondary Master %s";\r
+ break;\r
+\r
+ //\r
+ // Secondary Slave\r
+ //\r
+ case 4:\r
+ Fmt = L"Secondary Slave %s";\r
+ break;\r
+\r
+ default:\r
+ Fmt = L"%s";\r
+ break;\r
+ }\r
+\r
+ switch (CurBBSEntry->DeviceType) {\r
+ case BBS_FLOPPY:\r
+ Type = L"Floppy";\r
+ break;\r
+\r
+ case BBS_HARDDISK:\r
+ Type = L"Harddisk";\r
+ break;\r
+\r
+ case BBS_CDROM:\r
+ Type = L"CDROM";\r
+ break;\r
+\r
+ case BBS_PCMCIA:\r
+ Type = L"PCMCIAe";\r
+ break;\r
+\r
+ case BBS_USB:\r
+ Type = L"USB";\r
+ break;\r
+\r
+ case BBS_EMBED_NETWORK:\r
+ Type = L"Network";\r
+ break;\r
+\r
+ case BBS_BEV_DEVICE:\r
+ Type = L"BEVe";\r
+ break;\r
+\r
+ case BBS_UNKNOWN:\r
+ default:\r
+ Type = L"Unknown";\r
+ break;\r
+ }\r
+ //\r
+ // If current BBS entry has its description then use it.\r
+ //\r
+ StringDesc = (CHAR8 *) (UINTN) ((CurBBSEntry->DescStringSegment << 4) + CurBBSEntry->DescStringOffset);\r
+ if (NULL != StringDesc) {\r
+ //\r
+ // Only get fisrt 32 characters, this is suggested by BBS spec\r
+ //\r
+ CopyMem (StringBufferA, StringDesc, LEGACY_BM_BOOT_DESCRIPTION_LENGTH);\r
+ StringBufferA[LEGACY_BM_BOOT_DESCRIPTION_LENGTH] = 0;\r
+ AsciiStrToUnicodeStr (StringBufferA, StringBufferU);\r
+ Fmt = L"%s";\r
+ Type = StringBufferU;\r
+ }\r
+\r
+ //\r
+ // BbsTable 16 entries are for onboard IDE.\r
+ // Set description string for SATA harddisks, Harddisk 0 ~ Harddisk 11\r
+ //\r
+ if (Index >= 5 && Index <= 16 && (CurBBSEntry->DeviceType == BBS_HARDDISK || CurBBSEntry->DeviceType == BBS_CDROM)) {\r
+ Fmt = L"%s %d";\r
+ UnicodeSPrint (BootString, BufSize, Fmt, Type, Index - 5);\r
+ } else {\r
+ UnicodeSPrint (BootString, BufSize, Fmt, Type);\r
+ }\r
+}\r
+\r
+/**\r
+ Get the Bbs index for the input boot option.\r
+\r
+ @param BootOption The input boot option info.\r
+ @param BbsTable The input Bbs table.\r
+ @param BbsCount The input total bbs entry number.\r
+ @param BbsIndexUsed The array shows how many BBS table indexs have been used.\r
+\r
+ @retval The index for the input boot option.\r
+**/\r
+UINT16\r
+LegacyBmFuzzyMatch (\r
+ EFI_BOOT_MANAGER_LOAD_OPTION *BootOption,\r
+ BBS_TABLE *BbsTable,\r
+ UINT16 BbsCount,\r
+ BOOLEAN *BbsIndexUsed\r
+ )\r
+{\r
+ UINT16 Index;\r
+ LEGACY_BM_BOOT_OPTION_BBS_DATA *BbsData;\r
+ CHAR16 Description[LEGACY_BM_BOOT_DESCRIPTION_LENGTH + 1];\r
+\r
+ BbsData = (LEGACY_BM_BOOT_OPTION_BBS_DATA *) BootOption->OptionalData;\r
+\r
+ //\r
+ // Directly check the BBS index stored in BootOption\r
+ //\r
+ if ((BbsData->BbsIndex < BbsCount) &&\r
+ (LegacyBmDeviceType (BootOption->FilePath) == BbsTable[BbsData->BbsIndex].DeviceType)) {\r
+ LegacyBmBuildLegacyDevNameString (\r
+ &BbsTable[BbsData->BbsIndex],\r
+ BbsData->BbsIndex,\r
+ sizeof (Description),\r
+ Description\r
+ );\r
+ if ((StrCmp (Description, BootOption->Description) == 0) && !BbsIndexUsed[BbsData->BbsIndex]) {\r
+ //\r
+ // If devices with the same description string are connected, \r
+ // the BbsIndex of the first device is returned for the other device also.\r
+ // So, check if the BbsIndex is already being used, before assigning the BbsIndex.\r
+ //\r
+ BbsIndexUsed[BbsData->BbsIndex] = TRUE;\r
+ return BbsData->BbsIndex;\r
+ }\r
+ }\r
+\r
+ //\r
+ // BBS table could be changed (entry removed/moved)\r
+ // find the correct BBS index\r
+ //\r
+ for (Index = 0; Index < BbsCount; Index++) {\r
+ if (!LegacyBmValidBbsEntry (&BbsTable[Index]) ||\r
+ (BbsTable[Index].DeviceType != LegacyBmDeviceType (BootOption->FilePath))) {\r
+ continue;\r
+ }\r
+\r
+ LegacyBmBuildLegacyDevNameString (\r
+ &BbsTable[Index],\r
+ Index,\r
+ sizeof (Description),\r
+ Description\r
+ );\r
+ if ((StrCmp (Description, BootOption->Description) == 0) && !BbsIndexUsed[Index]) {\r
+ //\r
+ // If devices with the same description string are connected, \r
+ // the BbsIndex of the first device is assigned for the other device also.\r
+ // So, check if the BbsIndex is already being used, before assigning the corrected BbsIndex.\r
+ //\r
+ break;\r
+ }\r
+ }\r
+\r
+ //\r
+ // Add the corrected BbsIndex in the UsedBbsIndex Buffer\r
+ //\r
+ if (Index != BbsCount) {\r
+ BbsIndexUsed[Index] = TRUE;\r
+ }\r
+\r
+ return Index;\r
+}\r
+\r
+/**\r
+\r
+ Update legacy device order base on the input info.\r
+\r
+ @param LegacyDevOrder Legacy device order data buffer.\r
+ @param LegacyDevOrderSize Legacy device order data buffer size.\r
+ @param DeviceType Device type which need to check.\r
+ @param OldBbsIndex Old Bds Index.\r
+ @param NewBbsIndex New Bds Index, if it is -1,means remove this option.\r
+\r
+**/\r
+VOID\r
+LegacyBmUpdateBbsIndex (\r
+ LEGACY_DEV_ORDER_ENTRY *LegacyDevOrder,\r
+ UINTN *LegacyDevOrderSize,\r
+ UINT16 DeviceType,\r
+ UINT16 OldBbsIndex,\r
+ UINT16 NewBbsIndex // Delete entry if -1\r
+ )\r
+{\r
+ LEGACY_DEV_ORDER_ENTRY *Entry;\r
+ UINTN Index;\r
+\r
+ ASSERT (((LegacyDevOrder == NULL) && (*LegacyDevOrderSize == 0)) ||\r
+ ((LegacyDevOrder != NULL) && (*LegacyDevOrderSize != 0))\r
+ );\r
+\r
+ for (Entry = LegacyDevOrder; \r
+ Entry < (LEGACY_DEV_ORDER_ENTRY *) ((UINT8 *) LegacyDevOrder + *LegacyDevOrderSize);\r
+ Entry = (LEGACY_DEV_ORDER_ENTRY *) ((UINTN) Entry + sizeof (BBS_TYPE) + Entry->Length)\r
+ ) {\r
+ if (Entry->BbsType == DeviceType) {\r
+ for (Index = 0; Index < Entry->Length / sizeof (UINT16) - 1; Index++) {\r
+ if (Entry->Data[Index] == OldBbsIndex) {\r
+ if (NewBbsIndex == (UINT16) -1) {\r
+ //\r
+ // Delete the old entry\r
+ //\r
+ CopyMem (\r
+ &Entry->Data[Index], \r
+ &Entry->Data[Index + 1], \r
+ (UINT8 *) LegacyDevOrder + *LegacyDevOrderSize - (UINT8 *) &Entry->Data[Index + 1]\r
+ );\r
+ Entry->Length -= sizeof (UINT16);\r
+ *LegacyDevOrderSize -= sizeof(UINT16);\r
+ } else {\r
+ Entry->Data[Index] = NewBbsIndex;\r
+ }\r
+ break;\r
+ }\r
+ }\r
+ break;\r
+ }\r
+ }\r
+}\r
+\r
+/**\r
+ Delete all the legacy boot options.\r
+\r
+ @retval EFI_SUCCESS All legacy boot options are deleted.\r
+**/\r
+EFI_STATUS\r
+LegacyBmDeleteAllBootOptions (\r
+ VOID\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ UINTN Index;\r
+ EFI_BOOT_MANAGER_LOAD_OPTION *BootOption;\r
+ UINTN BootOptionCount;\r
+\r
+ BootOption = EfiBootManagerGetLoadOptions (&BootOptionCount, LoadOptionTypeBoot);\r
+ for (Index = 0; Index < BootOptionCount; Index++) {\r
+ if ((DevicePathType (BootOption[Index].FilePath) == BBS_DEVICE_PATH) &&\r
+ (DevicePathSubType (BootOption[Index].FilePath) == BBS_BBS_DP)) {\r
+ Status = EfiBootManagerDeleteLoadOptionVariable (BootOption[Index].OptionNumber, BootOption[Index].OptionType);\r
+ //\r
+ // Deleting variable with current variable implementation shouldn't fail.\r
+ //\r
+ ASSERT_EFI_ERROR (Status);\r
+ }\r
+ }\r
+\r
+ Status = gRT->SetVariable (\r
+ VAR_LEGACY_DEV_ORDER,\r
+ &gEfiLegacyDevOrderVariableGuid,\r
+ 0,\r
+ 0,\r
+ NULL\r
+ );\r
+ //\r
+ // Deleting variable with current variable implementation shouldn't fail.\r
+ //\r
+ ASSERT (Status == EFI_SUCCESS || Status == EFI_NOT_FOUND);\r
+\r
+ return EFI_SUCCESS;\r
+}\r
+\r
+\r
+/**\r
+ Delete all the invalid legacy boot options.\r
+\r
+ @retval EFI_SUCCESS All invalide legacy boot options are deleted.\r
+ @retval EFI_OUT_OF_RESOURCES Fail to allocate necessary memory.\r
+ @retval EFI_NOT_FOUND Fail to retrive variable of boot order.\r
+**/\r
+EFI_STATUS\r
+LegacyBmDeleteAllInvalidBootOptions (\r
+ VOID\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ UINT16 HddCount;\r
+ UINT16 BbsCount;\r
+ HDD_INFO *HddInfo;\r
+ BBS_TABLE *BbsTable;\r
+ UINT16 BbsIndex;\r
+ EFI_LEGACY_BIOS_PROTOCOL *LegacyBios;\r
+ UINTN Index;\r
+ EFI_BOOT_MANAGER_LOAD_OPTION *BootOption;\r
+ UINTN BootOptionCount;\r
+ LEGACY_DEV_ORDER_ENTRY *LegacyDevOrder;\r
+ UINTN LegacyDevOrderSize;\r
+ BOOLEAN *BbsIndexUsed;\r
+\r
+ HddCount = 0;\r
+ BbsCount = 0;\r
+ HddInfo = NULL;\r
+ BbsTable = NULL;\r
+\r
+ Status = gBS->LocateProtocol (&gEfiLegacyBiosProtocolGuid, NULL, (VOID **) &LegacyBios);\r
+ if (EFI_ERROR (Status)) {\r
+ return Status;\r
+ }\r
+\r
+ Status = LegacyBios->GetBbsInfo (\r
+ LegacyBios,\r
+ &HddCount,\r
+ &HddInfo,\r
+ &BbsCount,\r
+ &BbsTable\r
+ );\r
+ if (EFI_ERROR (Status)) {\r
+ return Status;\r
+ }\r
+\r
+ GetVariable2 (VAR_LEGACY_DEV_ORDER, &gEfiLegacyDevOrderVariableGuid, (VOID **) &LegacyDevOrder, &LegacyDevOrderSize);\r
+\r
+ BootOption = EfiBootManagerGetLoadOptions (&BootOptionCount, LoadOptionTypeBoot);\r
+\r
+ BbsIndexUsed = AllocateZeroPool (BbsCount * sizeof (BOOLEAN));\r
+ ASSERT (BbsIndexUsed != NULL);\r
+\r
+ for (Index = 0; Index < BootOptionCount; Index++) {\r
+ //\r
+ // Skip non legacy boot option\r
+ //\r
+ if ((DevicePathType (BootOption[Index].FilePath) != BBS_DEVICE_PATH) ||\r
+ (DevicePathSubType (BootOption[Index].FilePath) != BBS_BBS_DP)) {\r
+ continue;\r
+ }\r
+\r
+ BbsIndex = LegacyBmFuzzyMatch (&BootOption[Index], BbsTable, BbsCount, BbsIndexUsed);\r
+ if (BbsIndex == BbsCount) {\r
+ DEBUG ((EFI_D_INFO, "[LegacyBds] Delete Boot Option Boot%04x: %s\n", (UINTN) BootOption[Index].OptionNumber, BootOption[Index].Description));\r
+ //\r
+ // Delete entry from LegacyDevOrder\r
+ //\r
+ LegacyBmUpdateBbsIndex (\r
+ LegacyDevOrder,\r
+ &LegacyDevOrderSize,\r
+ LegacyBmDeviceType (BootOption[Index].FilePath),\r
+ ((LEGACY_BM_BOOT_OPTION_BBS_DATA *) BootOption[Index].OptionalData)->BbsIndex,\r
+ (UINT16) -1\r
+ );\r
+ EfiBootManagerDeleteLoadOptionVariable (BootOption[Index].OptionNumber, BootOption[Index].OptionType);\r
+ } else {\r
+ if (((LEGACY_BM_BOOT_OPTION_BBS_DATA *) BootOption[Index].OptionalData)->BbsIndex != BbsIndex) {\r
+ DEBUG ((EFI_D_INFO, "[LegacyBds] Update Boot Option Boot%04x: %s Bbs0x%04x->Bbs0x%04x\n", (UINTN) BootOption[Index].OptionNumber, BootOption[Index].Description,\r
+ (UINTN) ((LEGACY_BM_BOOT_OPTION_BBS_DATA *) BootOption[Index].OptionalData)->BbsIndex, (UINTN) BbsIndex));\r
+ //\r
+ // Update the BBS index in LegacyDevOrder\r
+ //\r
+ LegacyBmUpdateBbsIndex (\r
+ LegacyDevOrder,\r
+ &LegacyDevOrderSize,\r
+ LegacyBmDeviceType (BootOption[Index].FilePath),\r
+ ((LEGACY_BM_BOOT_OPTION_BBS_DATA *) BootOption[Index].OptionalData)->BbsIndex,\r
+ BbsIndex\r
+ );\r
+\r
+ //\r
+ // Update the OptionalData in the Boot#### variable\r
+ //\r
+ ((LEGACY_BM_BOOT_OPTION_BBS_DATA *) BootOption[Index].OptionalData)->BbsIndex = BbsIndex;\r
+ EfiBootManagerLoadOptionToVariable (&BootOption[Index]);\r
+ }\r
+ }\r
+ }\r
+ EfiBootManagerFreeLoadOptions (BootOption, BootOptionCount);\r
+\r
+ if (LegacyDevOrder != NULL) {\r
+ Status = gRT->SetVariable (\r
+ VAR_LEGACY_DEV_ORDER,\r
+ &gEfiLegacyDevOrderVariableGuid,\r
+ EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_NON_VOLATILE,\r
+ LegacyDevOrderSize,\r
+ LegacyDevOrder\r
+ );\r
+ //\r
+ // Shrink variable with current variable implementation shouldn't fail.\r
+ //\r
+ ASSERT_EFI_ERROR (Status);\r
+\r
+ FreePool (LegacyDevOrder);\r
+ }\r
+ FreePool(BbsIndexUsed);\r
+ return Status;\r
+}\r
+\r
+/**\r
+ Create legacy boot option.\r
+\r
+ @param BootOption Ponter to the boot option which will be crated.\r
+ @param BbsEntry The input bbs entry info.\r
+ @param BbsIndex The BBS index.\r
+\r
+ @retval EFI_SUCCESS Create legacy boot option successfully.\r
+ @retval EFI_INVALID_PARAMETER Invalid input parameter.\r
+\r
+**/\r
+EFI_STATUS\r
+LegacyBmCreateLegacyBootOption (\r
+ IN OUT EFI_BOOT_MANAGER_LOAD_OPTION *BootOption,\r
+ IN BBS_TABLE *BbsEntry,\r
+ IN UINT16 BbsIndex\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ EFI_DEVICE_PATH_PROTOCOL *DevicePath;\r
+ CHAR16 Description[LEGACY_BM_BOOT_DESCRIPTION_LENGTH + 1];\r
+ CHAR8 HelpString[LEGACY_BM_BOOT_DESCRIPTION_LENGTH + 1];\r
+ UINTN StringLen;\r
+ LEGACY_BM_BOOT_OPTION_BBS_DATA *OptionalData;\r
+ BBS_BBS_DEVICE_PATH *BbsNode;\r
+\r
+ if ((BootOption == NULL) || (BbsEntry == NULL)) {\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+ \r
+ LegacyBmBuildLegacyDevNameString (BbsEntry, BbsIndex, sizeof (Description), Description);\r
+\r
+ //\r
+ // Create the BBS device path with description string\r
+ //\r
+ UnicodeStrToAsciiStr (Description, HelpString);\r
+ StringLen = AsciiStrLen (HelpString);\r
+ DevicePath = AllocatePool (sizeof (BBS_BBS_DEVICE_PATH) + StringLen + END_DEVICE_PATH_LENGTH);\r
+ ASSERT (DevicePath != NULL);\r
+\r
+ BbsNode = (BBS_BBS_DEVICE_PATH *) DevicePath;\r
+ SetDevicePathNodeLength (BbsNode, sizeof (BBS_BBS_DEVICE_PATH) + StringLen);\r
+ BbsNode->Header.Type = BBS_DEVICE_PATH;\r
+ BbsNode->Header.SubType = BBS_BBS_DP;\r
+ BbsNode->DeviceType = BbsEntry->DeviceType;\r
+ CopyMem (&BbsNode->StatusFlag, &BbsEntry->StatusFlags, sizeof (BBS_STATUS_FLAGS));\r
+ CopyMem (BbsNode->String, HelpString, StringLen + 1);\r
+\r
+ SetDevicePathEndNode (NextDevicePathNode (BbsNode));\r
+\r
+ //\r
+ // Create the OptionalData\r
+ //\r
+ OptionalData = AllocatePool (sizeof (LEGACY_BM_BOOT_OPTION_BBS_DATA));\r
+ ASSERT (OptionalData != NULL);\r
+ OptionalData->BbsIndex = BbsIndex;\r
+\r
+ //\r
+ // Create the BootOption\r
+ //\r
+ Status = EfiBootManagerInitializeLoadOption (\r
+ BootOption,\r
+ LoadOptionNumberUnassigned,\r
+ LoadOptionTypeBoot,\r
+ LOAD_OPTION_ACTIVE,\r
+ Description,\r
+ DevicePath,\r
+ (UINT8 *) OptionalData,\r
+ sizeof (LEGACY_BM_BOOT_OPTION_BBS_DATA)\r
+ );\r
+ FreePool (DevicePath);\r
+ FreePool (OptionalData);\r
+ \r
+ return Status;\r
+}\r
+\r
+/**\r
+ Fill the device order buffer.\r
+\r
+ @param BbsTable The BBS table.\r
+ @param BbsType The BBS Type.\r
+ @param BbsCount The BBS Count.\r
+ @param Buf device order buffer.\r
+\r
+ @return The device order buffer.\r
+\r
+**/\r
+UINT16 *\r
+LegacyBmFillDevOrderBuf (\r
+ IN BBS_TABLE *BbsTable,\r
+ IN BBS_TYPE BbsType,\r
+ IN UINTN BbsCount,\r
+ OUT UINT16 *Buf\r
+ )\r
+{\r
+ UINTN Index;\r
+\r
+ for (Index = 0; Index < BbsCount; Index++) {\r
+ if (!LegacyBmValidBbsEntry (&BbsTable[Index])) {\r
+ continue;\r
+ }\r
+\r
+ if (BbsTable[Index].DeviceType != BbsType) {\r
+ continue;\r
+ }\r
+\r
+ *Buf = (UINT16) (Index & 0xFF);\r
+ Buf++;\r
+ }\r
+\r
+ return Buf;\r
+}\r
+\r
+/**\r
+ Create the device order buffer.\r
+\r
+ @param BbsTable The BBS table.\r
+ @param BbsCount The BBS Count.\r
+\r
+ @retval EFI_SUCCES The buffer is created and the EFI variable named \r
+ VAR_LEGACY_DEV_ORDER and EfiLegacyDevOrderGuid is\r
+ set correctly.\r
+ @retval EFI_OUT_OF_RESOURCES Memmory or storage is not enough.\r
+ @retval EFI_DEVICE_ERROR Fail to add the device order into EFI variable fail\r
+ because of hardware error.\r
+**/\r
+EFI_STATUS\r
+LegacyBmCreateDevOrder (\r
+ IN BBS_TABLE *BbsTable,\r
+ IN UINT16 BbsCount\r
+ )\r
+{\r
+ UINTN Index;\r
+ UINTN FDCount;\r
+ UINTN HDCount;\r
+ UINTN CDCount;\r
+ UINTN NETCount;\r
+ UINTN BEVCount;\r
+ UINTN TotalSize;\r
+ UINTN HeaderSize;\r
+ LEGACY_DEV_ORDER_ENTRY *DevOrder;\r
+ LEGACY_DEV_ORDER_ENTRY *DevOrderPtr;\r
+ EFI_STATUS Status;\r
+\r
+ FDCount = 0;\r
+ HDCount = 0;\r
+ CDCount = 0;\r
+ NETCount = 0;\r
+ BEVCount = 0;\r
+ TotalSize = 0;\r
+ HeaderSize = sizeof (BBS_TYPE) + sizeof (UINT16);\r
+ DevOrder = NULL;\r
+ Status = EFI_SUCCESS;\r
+\r
+ //\r
+ // Count all boot devices\r
+ //\r
+ for (Index = 0; Index < BbsCount; Index++) {\r
+ if (!LegacyBmValidBbsEntry (&BbsTable[Index])) {\r
+ continue;\r
+ }\r
+\r
+ switch (BbsTable[Index].DeviceType) {\r
+ case BBS_FLOPPY:\r
+ FDCount++;\r
+ break;\r
+\r
+ case BBS_HARDDISK:\r
+ HDCount++;\r
+ break;\r
+\r
+ case BBS_CDROM:\r
+ CDCount++;\r
+ break;\r
+\r
+ case BBS_EMBED_NETWORK:\r
+ NETCount++;\r
+ break;\r
+\r
+ case BBS_BEV_DEVICE:\r
+ BEVCount++;\r
+ break;\r
+\r
+ default:\r
+ break;\r
+ }\r
+ }\r
+\r
+ TotalSize += (HeaderSize + sizeof (UINT16) * FDCount);\r
+ TotalSize += (HeaderSize + sizeof (UINT16) * HDCount);\r
+ TotalSize += (HeaderSize + sizeof (UINT16) * CDCount);\r
+ TotalSize += (HeaderSize + sizeof (UINT16) * NETCount);\r
+ TotalSize += (HeaderSize + sizeof (UINT16) * BEVCount);\r
+\r
+ //\r
+ // Create buffer to hold all boot device order\r
+ //\r
+ DevOrder = AllocateZeroPool (TotalSize);\r
+ if (NULL == DevOrder) {\r
+ return EFI_OUT_OF_RESOURCES;\r
+ }\r
+ DevOrderPtr = DevOrder;\r
+\r
+ DevOrderPtr->BbsType = BBS_FLOPPY;\r
+ DevOrderPtr->Length = (UINT16) (sizeof (DevOrderPtr->Length) + FDCount * sizeof (UINT16));\r
+ DevOrderPtr = (LEGACY_DEV_ORDER_ENTRY *) LegacyBmFillDevOrderBuf (BbsTable, BBS_FLOPPY, BbsCount, DevOrderPtr->Data);\r
+\r
+ DevOrderPtr->BbsType = BBS_HARDDISK;\r
+ DevOrderPtr->Length = (UINT16) (sizeof (UINT16) + HDCount * sizeof (UINT16));\r
+ DevOrderPtr = (LEGACY_DEV_ORDER_ENTRY *) LegacyBmFillDevOrderBuf (BbsTable, BBS_HARDDISK, BbsCount, DevOrderPtr->Data);\r
+ \r
+ DevOrderPtr->BbsType = BBS_CDROM;\r
+ DevOrderPtr->Length = (UINT16) (sizeof (UINT16) + CDCount * sizeof (UINT16));\r
+ DevOrderPtr = (LEGACY_DEV_ORDER_ENTRY *) LegacyBmFillDevOrderBuf (BbsTable, BBS_CDROM, BbsCount, DevOrderPtr->Data);\r
+ \r
+ DevOrderPtr->BbsType = BBS_EMBED_NETWORK;\r
+ DevOrderPtr->Length = (UINT16) (sizeof (UINT16) + NETCount * sizeof (UINT16));\r
+ DevOrderPtr = (LEGACY_DEV_ORDER_ENTRY *) LegacyBmFillDevOrderBuf (BbsTable, BBS_EMBED_NETWORK, BbsCount, DevOrderPtr->Data);\r
+\r
+ DevOrderPtr->BbsType = BBS_BEV_DEVICE;\r
+ DevOrderPtr->Length = (UINT16) (sizeof (UINT16) + BEVCount * sizeof (UINT16));\r
+ DevOrderPtr = (LEGACY_DEV_ORDER_ENTRY *) LegacyBmFillDevOrderBuf (BbsTable, BBS_BEV_DEVICE, BbsCount, DevOrderPtr->Data);\r
+\r
+ ASSERT (TotalSize == (UINTN) ((UINT8 *) DevOrderPtr - (UINT8 *) DevOrder));\r
+\r
+ //\r
+ // Save device order for legacy boot device to variable.\r
+ //\r
+ Status = gRT->SetVariable (\r
+ VAR_LEGACY_DEV_ORDER,\r
+ &gEfiLegacyDevOrderVariableGuid,\r
+ EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_NON_VOLATILE,\r
+ TotalSize,\r
+ DevOrder\r
+ );\r
+ FreePool (DevOrder);\r
+\r
+ return Status;\r
+}\r
+\r
+/**\r
+ Add the legacy boot devices from BBS table into \r
+ the legacy device boot order.\r
+\r
+ @retval EFI_SUCCESS The boot devices are added successfully.\r
+ @retval EFI_NOT_FOUND The legacy boot devices are not found.\r
+ @retval EFI_OUT_OF_RESOURCES Memmory or storage is not enough.\r
+ @retval EFI_DEVICE_ERROR Fail to add the legacy device boot order into EFI variable\r
+ because of hardware error.\r
+**/\r
+EFI_STATUS\r
+LegacyBmUpdateDevOrder (\r
+ VOID\r
+ )\r
+{\r
+ LEGACY_DEV_ORDER_ENTRY *DevOrder;\r
+ LEGACY_DEV_ORDER_ENTRY *NewDevOrder;\r
+ LEGACY_DEV_ORDER_ENTRY *Ptr;\r
+ LEGACY_DEV_ORDER_ENTRY *NewPtr;\r
+ EFI_LEGACY_BIOS_PROTOCOL *LegacyBios;\r
+ EFI_STATUS Status;\r
+ UINT16 HddCount;\r
+ UINT16 BbsCount;\r
+ HDD_INFO *LocalHddInfo;\r
+ BBS_TABLE *LocalBbsTable;\r
+ UINTN Index;\r
+ UINTN Index2;\r
+ UINTN *Idx;\r
+ UINTN FDCount;\r
+ UINTN HDCount;\r
+ UINTN CDCount;\r
+ UINTN NETCount;\r
+ UINTN BEVCount;\r
+ UINTN TotalSize;\r
+ UINTN HeaderSize;\r
+ UINT16 *NewFDPtr;\r
+ UINT16 *NewHDPtr;\r
+ UINT16 *NewCDPtr;\r
+ UINT16 *NewNETPtr;\r
+ UINT16 *NewBEVPtr;\r
+ UINT16 *NewDevPtr;\r
+ UINTN FDIndex;\r
+ UINTN HDIndex;\r
+ UINTN CDIndex;\r
+ UINTN NETIndex;\r
+ UINTN BEVIndex;\r
+\r
+ Idx = NULL;\r
+ FDCount = 0;\r
+ HDCount = 0;\r
+ CDCount = 0;\r
+ NETCount = 0;\r
+ BEVCount = 0;\r
+ TotalSize = 0;\r
+ HeaderSize = sizeof (BBS_TYPE) + sizeof (UINT16);\r
+ FDIndex = 0;\r
+ HDIndex = 0;\r
+ CDIndex = 0;\r
+ NETIndex = 0;\r
+ BEVIndex = 0;\r
+ NewDevPtr = NULL;\r
+\r
+ Status = gBS->LocateProtocol (&gEfiLegacyBiosProtocolGuid, NULL, (VOID **) &LegacyBios);\r
+ if (EFI_ERROR (Status)) {\r
+ return Status;\r
+ }\r
+\r
+ Status = LegacyBios->GetBbsInfo (\r
+ LegacyBios,\r
+ &HddCount,\r
+ &LocalHddInfo,\r
+ &BbsCount,\r
+ &LocalBbsTable\r
+ );\r
+ if (EFI_ERROR (Status)) {\r
+ return Status;\r
+ }\r
+\r
+ GetVariable2 (VAR_LEGACY_DEV_ORDER, &gEfiLegacyDevOrderVariableGuid, (VOID **) &DevOrder, NULL);\r
+ if (NULL == DevOrder) {\r
+ return LegacyBmCreateDevOrder (LocalBbsTable, BbsCount);\r
+ }\r
+ //\r
+ // First we figure out how many boot devices with same device type respectively\r
+ //\r
+ for (Index = 0; Index < BbsCount; Index++) {\r
+ if (!LegacyBmValidBbsEntry (&LocalBbsTable[Index])) {\r
+ continue;\r
+ }\r
+\r
+ switch (LocalBbsTable[Index].DeviceType) {\r
+ case BBS_FLOPPY:\r
+ FDCount++;\r
+ break;\r
+\r
+ case BBS_HARDDISK:\r
+ HDCount++;\r
+ break;\r
+\r
+ case BBS_CDROM:\r
+ CDCount++;\r
+ break;\r
+\r
+ case BBS_EMBED_NETWORK:\r
+ NETCount++;\r
+ break;\r
+\r
+ case BBS_BEV_DEVICE:\r
+ BEVCount++;\r
+ break;\r
+\r
+ default:\r
+ break;\r
+ }\r
+ }\r
+\r
+ TotalSize += (HeaderSize + FDCount * sizeof (UINT16));\r
+ TotalSize += (HeaderSize + HDCount * sizeof (UINT16));\r
+ TotalSize += (HeaderSize + CDCount * sizeof (UINT16));\r
+ TotalSize += (HeaderSize + NETCount * sizeof (UINT16));\r
+ TotalSize += (HeaderSize + BEVCount * sizeof (UINT16));\r
+\r
+ NewDevOrder = AllocateZeroPool (TotalSize);\r
+ if (NULL == NewDevOrder) {\r
+ return EFI_OUT_OF_RESOURCES;\r
+ }\r
+\r
+ //\r
+ // copy FD\r
+ //\r
+ Ptr = DevOrder;\r
+ NewPtr = NewDevOrder;\r
+ NewPtr->BbsType = Ptr->BbsType;\r
+ NewPtr->Length = (UINT16) (sizeof (UINT16) + FDCount * sizeof (UINT16));\r
+ for (Index = 0; Index < Ptr->Length / sizeof (UINT16) - 1; Index++) {\r
+ if (!LegacyBmValidBbsEntry (&LocalBbsTable[Ptr->Data[Index] & 0xFF]) ||\r
+ LocalBbsTable[Ptr->Data[Index] & 0xFF].DeviceType != BBS_FLOPPY\r
+ ) {\r
+ continue;\r
+ }\r
+\r
+ NewPtr->Data[FDIndex] = Ptr->Data[Index];\r
+ FDIndex++;\r
+ }\r
+ NewFDPtr = NewPtr->Data;\r
+\r
+ //\r
+ // copy HD\r
+ //\r
+ Ptr = (LEGACY_DEV_ORDER_ENTRY *) (&Ptr->Data[Ptr->Length / sizeof (UINT16) - 1]);\r
+ NewPtr = (LEGACY_DEV_ORDER_ENTRY *) (&NewPtr->Data[NewPtr->Length / sizeof (UINT16) -1]);\r
+ NewPtr->BbsType = Ptr->BbsType;\r
+ NewPtr->Length = (UINT16) (sizeof (UINT16) + HDCount * sizeof (UINT16));\r
+ for (Index = 0; Index < Ptr->Length / sizeof (UINT16) - 1; Index++) {\r
+ if (!LegacyBmValidBbsEntry (&LocalBbsTable[Ptr->Data[Index] & 0xFF]) ||\r
+ LocalBbsTable[Ptr->Data[Index] & 0xFF].DeviceType != BBS_HARDDISK\r
+ ) {\r
+ continue;\r
+ }\r
+\r
+ NewPtr->Data[HDIndex] = Ptr->Data[Index];\r
+ HDIndex++;\r
+ }\r
+ NewHDPtr = NewPtr->Data;\r
+\r
+ //\r
+ // copy CD\r
+ //\r
+ Ptr = (LEGACY_DEV_ORDER_ENTRY *) (&Ptr->Data[Ptr->Length / sizeof (UINT16) - 1]);\r
+ NewPtr = (LEGACY_DEV_ORDER_ENTRY *) (&NewPtr->Data[NewPtr->Length / sizeof (UINT16) -1]);\r
+ NewPtr->BbsType = Ptr->BbsType;\r
+ NewPtr->Length = (UINT16) (sizeof (UINT16) + CDCount * sizeof (UINT16));\r
+ for (Index = 0; Index < Ptr->Length / sizeof (UINT16) - 1; Index++) {\r
+ if (!LegacyBmValidBbsEntry (&LocalBbsTable[Ptr->Data[Index] & 0xFF]) ||\r
+ LocalBbsTable[Ptr->Data[Index] & 0xFF].DeviceType != BBS_CDROM\r
+ ) {\r
+ continue;\r
+ }\r
+\r
+ NewPtr->Data[CDIndex] = Ptr->Data[Index];\r
+ CDIndex++;\r
+ }\r
+ NewCDPtr = NewPtr->Data;\r
+\r
+ //\r
+ // copy NET\r
+ //\r
+ Ptr = (LEGACY_DEV_ORDER_ENTRY *) (&Ptr->Data[Ptr->Length / sizeof (UINT16) - 1]);\r
+ NewPtr = (LEGACY_DEV_ORDER_ENTRY *) (&NewPtr->Data[NewPtr->Length / sizeof (UINT16) -1]);\r
+ NewPtr->BbsType = Ptr->BbsType;\r
+ NewPtr->Length = (UINT16) (sizeof (UINT16) + NETCount * sizeof (UINT16));\r
+ for (Index = 0; Index < Ptr->Length / sizeof (UINT16) - 1; Index++) {\r
+ if (!LegacyBmValidBbsEntry (&LocalBbsTable[Ptr->Data[Index] & 0xFF]) ||\r
+ LocalBbsTable[Ptr->Data[Index] & 0xFF].DeviceType != BBS_EMBED_NETWORK\r
+ ) {\r
+ continue;\r
+ }\r
+\r
+ NewPtr->Data[NETIndex] = Ptr->Data[Index];\r
+ NETIndex++;\r
+ }\r
+ NewNETPtr = NewPtr->Data;\r
+ \r
+ //\r
+ // copy BEV\r
+ //\r
+ Ptr = (LEGACY_DEV_ORDER_ENTRY *) (&Ptr->Data[Ptr->Length / sizeof (UINT16) - 1]);\r
+ NewPtr = (LEGACY_DEV_ORDER_ENTRY *) (&NewPtr->Data[NewPtr->Length / sizeof (UINT16) -1]);\r
+ NewPtr->BbsType = Ptr->BbsType;\r
+ NewPtr->Length = (UINT16) (sizeof (UINT16) + BEVCount * sizeof (UINT16));\r
+ for (Index = 0; Index < Ptr->Length / sizeof (UINT16) - 1; Index++) {\r
+ if (!LegacyBmValidBbsEntry (&LocalBbsTable[Ptr->Data[Index] & 0xFF]) ||\r
+ LocalBbsTable[Ptr->Data[Index] & 0xFF].DeviceType != BBS_BEV_DEVICE\r
+ ) {\r
+ continue;\r
+ }\r
+\r
+ NewPtr->Data[BEVIndex] = Ptr->Data[Index];\r
+ BEVIndex++;\r
+ }\r
+ NewBEVPtr = NewPtr->Data;\r
+\r
+ for (Index = 0; Index < BbsCount; Index++) {\r
+ if (!LegacyBmValidBbsEntry (&LocalBbsTable[Index])) {\r
+ continue;\r
+ }\r
+\r
+ switch (LocalBbsTable[Index].DeviceType) {\r
+ case BBS_FLOPPY:\r
+ Idx = &FDIndex;\r
+ NewDevPtr = NewFDPtr;\r
+ break;\r
+\r
+ case BBS_HARDDISK:\r
+ Idx = &HDIndex;\r
+ NewDevPtr = NewHDPtr;\r
+ break;\r
+\r
+ case BBS_CDROM:\r
+ Idx = &CDIndex;\r
+ NewDevPtr = NewCDPtr;\r
+ break;\r
+\r
+ case BBS_EMBED_NETWORK:\r
+ Idx = &NETIndex;\r
+ NewDevPtr = NewNETPtr;\r
+ break;\r
+\r
+ case BBS_BEV_DEVICE:\r
+ Idx = &BEVIndex;\r
+ NewDevPtr = NewBEVPtr;\r
+ break;\r
+\r
+ default:\r
+ Idx = NULL;\r
+ break;\r
+ }\r
+ //\r
+ // at this point we have copied those valid indexes to new buffer\r
+ // and we should check if there is any new appeared boot device\r
+ //\r
+ if (Idx != NULL) {\r
+ for (Index2 = 0; Index2 < *Idx; Index2++) {\r
+ if ((NewDevPtr[Index2] & 0xFF) == (UINT16) Index) {\r
+ break;\r
+ }\r
+ }\r
+\r
+ if (Index2 == *Idx) {\r
+ //\r
+ // Index2 == *Idx means we didn't find Index\r
+ // so Index is a new appeared device's index in BBS table\r
+ // insert it before disabled indexes.\r
+ //\r
+ for (Index2 = 0; Index2 < *Idx; Index2++) {\r
+ if ((NewDevPtr[Index2] & 0xFF00) == 0xFF00) {\r
+ break;\r
+ }\r
+ }\r
+ CopyMem (&NewDevPtr[Index2 + 1], &NewDevPtr[Index2], (*Idx - Index2) * sizeof (UINT16));\r
+ NewDevPtr[Index2] = (UINT16) (Index & 0xFF);\r
+ (*Idx)++;\r
+ }\r
+ }\r
+ }\r
+\r
+ FreePool (DevOrder);\r
+\r
+ Status = gRT->SetVariable (\r
+ VAR_LEGACY_DEV_ORDER,\r
+ &gEfiLegacyDevOrderVariableGuid,\r
+ EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_NON_VOLATILE,\r
+ TotalSize,\r
+ NewDevOrder\r
+ );\r
+ FreePool (NewDevOrder);\r
+\r
+ return Status;\r
+}\r
+\r
+/**\r
+ Set Boot Priority for specified device type.\r
+\r
+ @param DeviceType The device type.\r
+ @param BbsIndex The BBS index to set the highest priority. Ignore when -1.\r
+ @param LocalBbsTable The BBS table.\r
+ @param Priority The prority table.\r
+\r
+ @retval EFI_SUCCESS The function completes successfully.\r
+ @retval EFI_NOT_FOUND Failed to find device.\r
+ @retval EFI_OUT_OF_RESOURCES Failed to get the efi variable of device order.\r
+\r
+**/\r
+EFI_STATUS\r
+LegacyBmSetPriorityForSameTypeDev (\r
+ IN UINT16 DeviceType,\r
+ IN UINTN BbsIndex,\r
+ IN OUT BBS_TABLE *LocalBbsTable,\r
+ IN OUT UINT16 *Priority\r
+ )\r
+{\r
+ LEGACY_DEV_ORDER_ENTRY *DevOrder;\r
+ LEGACY_DEV_ORDER_ENTRY *DevOrderPtr;\r
+ UINTN DevOrderSize;\r
+ UINTN Index;\r
+\r
+ GetVariable2 (VAR_LEGACY_DEV_ORDER, &gEfiLegacyDevOrderVariableGuid, (VOID **) &DevOrder, &DevOrderSize);\r
+ if (NULL == DevOrder) {\r
+ return EFI_OUT_OF_RESOURCES;\r
+ }\r
+\r
+ DevOrderPtr = DevOrder;\r
+ while ((UINT8 *) DevOrderPtr < (UINT8 *) DevOrder + DevOrderSize) {\r
+ if (DevOrderPtr->BbsType == DeviceType) {\r
+ break;\r
+ }\r
+\r
+ DevOrderPtr = (LEGACY_DEV_ORDER_ENTRY *) ((UINTN) DevOrderPtr + sizeof (BBS_TYPE) + DevOrderPtr->Length);\r
+ }\r
+\r
+ if ((UINT8 *) DevOrderPtr >= (UINT8 *) DevOrder + DevOrderSize) {\r
+ FreePool (DevOrder);\r
+ return EFI_NOT_FOUND;\r
+ }\r
+\r
+ if (BbsIndex != (UINTN) -1) {\r
+ //\r
+ // In case the BBS entry isn't valid because devices were plugged or removed.\r
+ //\r
+ if (!LegacyBmValidBbsEntry (&LocalBbsTable[BbsIndex]) || (LocalBbsTable[BbsIndex].DeviceType != DeviceType)) {\r
+ FreePool (DevOrder);\r
+ return EFI_NOT_FOUND;\r
+ }\r
+ LocalBbsTable[BbsIndex].BootPriority = *Priority;\r
+ (*Priority)++;\r
+ }\r
+ //\r
+ // If the high byte of the DevIndex is 0xFF, it indicates that this device has been disabled.\r
+ //\r
+ for (Index = 0; Index < DevOrderPtr->Length / sizeof (UINT16) - 1; Index++) {\r
+ if ((DevOrderPtr->Data[Index] & 0xFF00) == 0xFF00) {\r
+ //\r
+ // LocalBbsTable[DevIndex[Index] & 0xFF].BootPriority = BBS_DISABLED_ENTRY;\r
+ //\r
+ } else if (DevOrderPtr->Data[Index] != BbsIndex) {\r
+ LocalBbsTable[DevOrderPtr->Data[Index]].BootPriority = *Priority;\r
+ (*Priority)++;\r
+ }\r
+ }\r
+\r
+ FreePool (DevOrder);\r
+ return EFI_SUCCESS;\r
+}\r
+\r
+/**\r
+ Print the BBS Table.\r
+\r
+ @param LocalBbsTable The BBS table.\r
+ @param BbsCount The count of entry in BBS table.\r
+**/\r
+VOID\r
+LegacyBmPrintBbsTable (\r
+ IN BBS_TABLE *LocalBbsTable,\r
+ IN UINT16 BbsCount\r
+ )\r
+{\r
+ UINT16 Index;\r
+\r
+ DEBUG ((DEBUG_INFO, "\n"));\r
+ DEBUG ((DEBUG_INFO, " NO Prio bb/dd/ff cl/sc Type Stat segm:offs\n"));\r
+ DEBUG ((DEBUG_INFO, "=============================================\n"));\r
+ for (Index = 0; Index < BbsCount; Index++) {\r
+ if (!LegacyBmValidBbsEntry (&LocalBbsTable[Index])) {\r
+ continue;\r
+ }\r
+\r
+ DEBUG (\r
+ (DEBUG_INFO,\r
+ " %02x: %04x %02x/%02x/%02x %02x/%02x %04x %04x %04x:%04x\n",\r
+ (UINTN) Index,\r
+ (UINTN) LocalBbsTable[Index].BootPriority,\r
+ (UINTN) LocalBbsTable[Index].Bus,\r
+ (UINTN) LocalBbsTable[Index].Device,\r
+ (UINTN) LocalBbsTable[Index].Function,\r
+ (UINTN) LocalBbsTable[Index].Class,\r
+ (UINTN) LocalBbsTable[Index].SubClass,\r
+ (UINTN) LocalBbsTable[Index].DeviceType,\r
+ (UINTN) * (UINT16 *) &LocalBbsTable[Index].StatusFlags,\r
+ (UINTN) LocalBbsTable[Index].BootHandlerSegment,\r
+ (UINTN) LocalBbsTable[Index].BootHandlerOffset,\r
+ (UINTN) ((LocalBbsTable[Index].MfgStringSegment << 4) + LocalBbsTable[Index].MfgStringOffset),\r
+ (UINTN) ((LocalBbsTable[Index].DescStringSegment << 4) + LocalBbsTable[Index].DescStringOffset))\r
+ );\r
+ }\r
+\r
+ DEBUG ((DEBUG_INFO, "\n"));\r
+}\r
+\r
+/**\r
+ Set the boot priority for BBS entries based on boot option entry and boot order.\r
+\r
+ @param BootOption The boot option is to be checked for refresh BBS table.\r
+ \r
+ @retval EFI_SUCCESS The boot priority for BBS entries is refreshed successfully.\r
+ @retval EFI_NOT_FOUND BBS entries can't be found.\r
+ @retval EFI_OUT_OF_RESOURCES Failed to get the legacy device boot order.\r
+**/\r
+EFI_STATUS\r
+LegacyBmRefreshBbsTableForBoot (\r
+ IN EFI_BOOT_MANAGER_LOAD_OPTION *BootOption\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ UINT16 BbsIndex;\r
+ UINT16 HddCount;\r
+ UINT16 BbsCount;\r
+ HDD_INFO *LocalHddInfo;\r
+ BBS_TABLE *LocalBbsTable;\r
+ UINT16 DevType;\r
+ EFI_LEGACY_BIOS_PROTOCOL *LegacyBios;\r
+ UINTN Index;\r
+ UINT16 Priority;\r
+ UINT16 *DeviceType;\r
+ UINTN DeviceTypeCount;\r
+ UINTN DeviceTypeIndex;\r
+ EFI_BOOT_MANAGER_LOAD_OPTION *Option;\r
+ UINTN OptionCount;\r
+\r
+ HddCount = 0;\r
+ BbsCount = 0;\r
+ LocalHddInfo = NULL;\r
+ LocalBbsTable = NULL;\r
+ DevType = BBS_UNKNOWN;\r
+\r
+ Status = gBS->LocateProtocol (&gEfiLegacyBiosProtocolGuid, NULL, (VOID **) &LegacyBios);\r
+ if (EFI_ERROR (Status)) {\r
+ return Status;\r
+ }\r
+\r
+ Status = LegacyBios->GetBbsInfo (\r
+ LegacyBios,\r
+ &HddCount,\r
+ &LocalHddInfo,\r
+ &BbsCount,\r
+ &LocalBbsTable\r
+ );\r
+ if (EFI_ERROR (Status)) {\r
+ return Status;\r
+ }\r
+\r
+ //\r
+ // First, set all the present devices' boot priority to BBS_UNPRIORITIZED_ENTRY\r
+ // We will set them according to the settings setup by user\r
+ //\r
+ for (Index = 0; Index < BbsCount; Index++) {\r
+ if (LegacyBmValidBbsEntry (&LocalBbsTable[Index])) {\r
+ LocalBbsTable[Index].BootPriority = BBS_UNPRIORITIZED_ENTRY;\r
+ }\r
+ }\r
+ //\r
+ // boot priority always starts at 0\r
+ //\r
+ Priority = 0; \r
+ if ((DevicePathType (BootOption->FilePath) == BBS_DEVICE_PATH) &&\r
+ (DevicePathSubType (BootOption->FilePath) == BBS_BBS_DP)) {\r
+ //\r
+ // If BootOption stands for a legacy boot option, we prioritize the devices with the same type first.\r
+ //\r
+ DevType = LegacyBmDeviceType (BootOption->FilePath);\r
+ BbsIndex = ((LEGACY_BM_BOOT_OPTION_BBS_DATA *) BootOption->OptionalData)->BbsIndex;\r
+ Status = LegacyBmSetPriorityForSameTypeDev (\r
+ DevType,\r
+ BbsIndex,\r
+ LocalBbsTable,\r
+ &Priority\r
+ );\r
+ if (EFI_ERROR (Status)) {\r
+ return Status;\r
+ }\r
+ }\r
+ //\r
+ // we have to set the boot priority for other BBS entries with different device types\r
+ //\r
+ Option = EfiBootManagerGetLoadOptions (&OptionCount, LoadOptionTypeBoot);\r
+ DeviceType = AllocatePool (sizeof (UINT16) * OptionCount);\r
+ ASSERT (DeviceType != NULL);\r
+ DeviceType[0] = DevType;\r
+ DeviceTypeCount = 1;\r
+ for (Index = 0; Index < OptionCount; Index++) {\r
+ if ((DevicePathType (Option[Index].FilePath) != BBS_DEVICE_PATH) ||\r
+ (DevicePathSubType (Option[Index].FilePath) != BBS_BBS_DP)) {\r
+ continue;\r
+ }\r
+ \r
+ DevType = LegacyBmDeviceType (Option[Index].FilePath);\r
+ for (DeviceTypeIndex = 0; DeviceTypeIndex < DeviceTypeCount; DeviceTypeIndex++) {\r
+ if (DeviceType[DeviceTypeIndex] == DevType) {\r
+ break;\r
+ }\r
+ }\r
+ if (DeviceTypeIndex < DeviceTypeCount) {\r
+ //\r
+ // We don't want to process twice for a device type\r
+ //\r
+ continue;\r
+ }\r
+\r
+ DeviceType[DeviceTypeCount] = DevType;\r
+ DeviceTypeCount++;\r
+\r
+ Status = LegacyBmSetPriorityForSameTypeDev (\r
+ DevType,\r
+ (UINTN) -1,\r
+ LocalBbsTable,\r
+ &Priority\r
+ );\r
+ }\r
+ EfiBootManagerFreeLoadOptions (Option, OptionCount);\r
+\r
+ DEBUG_CODE_BEGIN();\r
+ LegacyBmPrintBbsTable (LocalBbsTable, BbsCount);\r
+ DEBUG_CODE_END();\r
+ \r
+ return Status;\r
+}\r
+\r
+\r
+/**\r
+ Boot the legacy system with the boot option.\r
+\r
+ @param BootOption The legacy boot option which have BBS device path\r
+ On return, BootOption->Status contains the boot status.\r
+ EFI_UNSUPPORTED There is no legacybios protocol, do not support\r
+ legacy boot.\r
+ EFI_STATUS The status of LegacyBios->LegacyBoot ().\r
+**/\r
+VOID\r
+EFIAPI\r
+LegacyBmBoot (\r
+ IN EFI_BOOT_MANAGER_LOAD_OPTION *BootOption\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ EFI_LEGACY_BIOS_PROTOCOL *LegacyBios;\r
+\r
+ Status = gBS->LocateProtocol (&gEfiLegacyBiosProtocolGuid, NULL, (VOID **) &LegacyBios);\r
+ if (EFI_ERROR (Status)) {\r
+ //\r
+ // If no LegacyBios protocol we do not support legacy boot\r
+ //\r
+ BootOption->Status = EFI_UNSUPPORTED;\r
+ return;\r
+ }\r
+ //\r
+ // Notes: if we separate the int 19, then we don't need to refresh BBS\r
+ //\r
+ Status = LegacyBmRefreshBbsTableForBoot (BootOption);\r
+ if (EFI_ERROR (Status)) {\r
+ BootOption->Status = Status;\r
+ return;\r
+ }\r
+\r
+ BootOption->Status = LegacyBios->LegacyBoot (\r
+ LegacyBios,\r
+ (BBS_BBS_DEVICE_PATH *) BootOption->FilePath,\r
+ BootOption->OptionalDataSize,\r
+ BootOption->OptionalData\r
+ );\r
+}\r
+\r
+/**\r
+ This function enumerates all the legacy boot options.\r
+\r
+ @param BootOptionCount Return the legacy boot option count.\r
+\r
+ @retval Pointer to the legacy boot option buffer.\r
+**/\r
+EFI_BOOT_MANAGER_LOAD_OPTION *\r
+LegacyBmEnumerateAllBootOptions (\r
+ UINTN *BootOptionCount\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ UINT16 HddCount;\r
+ UINT16 BbsCount;\r
+ HDD_INFO *HddInfo;\r
+ BBS_TABLE *BbsTable;\r
+ EFI_LEGACY_BIOS_PROTOCOL *LegacyBios;\r
+ UINT16 Index;\r
+ EFI_BOOT_MANAGER_LOAD_OPTION *BootOptions;\r
+\r
+ ASSERT (BootOptionCount != NULL);\r
+\r
+ BootOptions = NULL;\r
+ *BootOptionCount = 0;\r
+ BbsCount = 0;\r
+\r
+ Status = gBS->LocateProtocol (&gEfiLegacyBiosProtocolGuid, NULL, (VOID **) &LegacyBios);\r
+ if (EFI_ERROR (Status)) {\r
+ return NULL;\r
+ }\r
+\r
+ Status = LegacyBios->GetBbsInfo (\r
+ LegacyBios,\r
+ &HddCount,\r
+ &HddInfo,\r
+ &BbsCount,\r
+ &BbsTable\r
+ );\r
+ if (EFI_ERROR (Status)) {\r
+ return NULL;\r
+ }\r
+\r
+ for (Index = 0; Index < BbsCount; Index++) {\r
+ if (!LegacyBmValidBbsEntry (&BbsTable[Index])) {\r
+ continue;\r
+ }\r
+\r
+ BootOptions = ReallocatePool (\r
+ sizeof (EFI_BOOT_MANAGER_LOAD_OPTION) * (*BootOptionCount),\r
+ sizeof (EFI_BOOT_MANAGER_LOAD_OPTION) * (*BootOptionCount + 1),\r
+ BootOptions\r
+ );\r
+ ASSERT (BootOptions != NULL);\r
+\r
+ Status = LegacyBmCreateLegacyBootOption (&BootOptions[(*BootOptionCount)++], &BbsTable[Index], Index);\r
+ ASSERT_EFI_ERROR (Status);\r
+ }\r
+\r
+ return BootOptions;\r
+}\r
+\r
+/**\r
+ Return the index of the boot option in the boot option array.\r
+\r
+ The function compares the Description, FilePath, OptionalData.\r
+\r
+ @param Key The input boot option which is compared with.\r
+ @param Array The input boot option array.\r
+ @param Count The count of the input boot options.\r
+\r
+ @retval The index of the input boot option in the array.\r
+\r
+**/\r
+INTN\r
+LegacyBmFindBootOption (\r
+ IN CONST EFI_BOOT_MANAGER_LOAD_OPTION *Key,\r
+ IN CONST EFI_BOOT_MANAGER_LOAD_OPTION *Array,\r
+ IN UINTN Count\r
+ )\r
+{\r
+ UINTN Index;\r
+\r
+ for (Index = 0; Index < Count; Index++) {\r
+ if ((StrCmp (Key->Description, Array[Index].Description) == 0) &&\r
+ (CompareMem (Key->FilePath, Array[Index].FilePath, GetDevicePathSize (Key->FilePath)) == 0) &&\r
+ (Key->OptionalDataSize == Array[Index].OptionalDataSize) &&\r
+ (CompareMem (Key->OptionalData, Array[Index].OptionalData, Key->OptionalDataSize) == 0)) {\r
+ return (INTN) Index;\r
+ }\r
+ }\r
+\r
+ return -1;\r
+}\r
+\r
+/**\r
+ Refresh all legacy boot options.\r
+\r
+**/\r
+VOID\r
+EFIAPI\r
+LegacyBmRefreshAllBootOption (\r
+ VOID\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ EFI_LEGACY_BIOS_PROTOCOL *LegacyBios;\r
+ UINTN RootBridgeHandleCount;\r
+ EFI_HANDLE *RootBridgeHandleBuffer;\r
+ UINTN HandleCount;\r
+ EFI_HANDLE *HandleBuffer;\r
+ UINTN RootBridgeIndex;\r
+ UINTN Index;\r
+ UINTN Flags;\r
+ EFI_BOOT_MANAGER_LOAD_OPTION *BootOptions;\r
+ UINTN BootOptionCount;\r
+ EFI_BOOT_MANAGER_LOAD_OPTION *ExistingBootOptions;\r
+ UINTN ExistingBootOptionCount;\r
+\r
+ Status = gBS->LocateProtocol (&gEfiLegacyBiosProtocolGuid, NULL, (VOID **) &LegacyBios);\r
+ if (EFI_ERROR (Status)) {\r
+ LegacyBmDeleteAllBootOptions ();\r
+ return;\r
+ }\r
+ PERF_START (NULL, "LegacyBootOptionEnum", "BDS", 0);\r
+\r
+ //\r
+ // Before enumerating the legacy boot option, we need to dispatch all the legacy option roms \r
+ // to ensure the GetBbsInfo() counts all the legacy devices.\r
+ //\r
+ gBS->LocateHandleBuffer (\r
+ ByProtocol,\r
+ &gEfiPciRootBridgeIoProtocolGuid,\r
+ NULL,\r
+ &RootBridgeHandleCount,\r
+ &RootBridgeHandleBuffer\r
+ );\r
+ for (RootBridgeIndex = 0; RootBridgeIndex < RootBridgeHandleCount; RootBridgeIndex++) {\r
+ gBS->ConnectController (RootBridgeHandleBuffer[RootBridgeIndex], NULL, NULL, FALSE);\r
+ gBS->LocateHandleBuffer (\r
+ ByProtocol,\r
+ &gEfiPciIoProtocolGuid,\r
+ NULL,\r
+ &HandleCount,\r
+ &HandleBuffer\r
+ );\r
+ for (Index = 0; Index < HandleCount; Index++) {\r
+ //\r
+ // Start the thunk driver so that the legacy option rom gets dispatched.\r
+ // Note: We don't directly call InstallPciRom because some thunk drivers \r
+ // (e.g. BlockIo thunk driver) depend on the immediate result after dispatching\r
+ //\r
+ Status = LegacyBios->CheckPciRom (\r
+ LegacyBios,\r
+ HandleBuffer[Index],\r
+ NULL,\r
+ NULL,\r
+ &Flags\r
+ );\r
+ if (!EFI_ERROR (Status)) {\r
+ gBS->ConnectController (HandleBuffer[Index], NULL, NULL, FALSE);\r
+ }\r
+ }\r
+ }\r
+\r
+ //\r
+ // Same algorithm pattern as the EfiBootManagerRefreshAllBootOption\r
+ // Firstly delete the invalid legacy boot options,\r
+ // then enumreate and save the newly appeared legacy boot options\r
+ // the last step is legacy boot option special action to refresh the LegacyDevOrder variable\r
+ //\r
+ LegacyBmDeleteAllInvalidBootOptions ();\r
+\r
+ ExistingBootOptions = EfiBootManagerGetLoadOptions (&ExistingBootOptionCount, LoadOptionTypeBoot);\r
+ BootOptions = LegacyBmEnumerateAllBootOptions (&BootOptionCount);\r
+\r
+ for (Index = 0; Index < BootOptionCount; Index++) {\r
+ if (LegacyBmFindBootOption (&BootOptions[Index], ExistingBootOptions, ExistingBootOptionCount) == -1) {\r
+ Status = EfiBootManagerAddLoadOptionVariable (&BootOptions[Index], (UINTN) -1);\r
+ DEBUG ((\r
+ EFI_D_INFO, "[LegacyBds] New Boot Option: Boot%04x Bbs0x%04x %s %r\n",\r
+ (UINTN) BootOptions[Index].OptionNumber,\r
+ (UINTN) ((LEGACY_BM_BOOT_OPTION_BBS_DATA *) BootOptions[Index].OptionalData)->BbsIndex,\r
+ BootOptions[Index].Description,\r
+ Status\r
+ ));\r
+ //\r
+ // Continue upon failure to add boot option.\r
+ //\r
+ }\r
+ }\r
+\r
+ EfiBootManagerFreeLoadOptions (ExistingBootOptions, ExistingBootOptionCount);\r
+ EfiBootManagerFreeLoadOptions (BootOptions, BootOptionCount);\r
+\r
+ //\r
+ // Failure to create LegacyDevOrder variable only impacts the boot order.\r
+ //\r
+ LegacyBmUpdateDevOrder ();\r
+\r
+ PERF_END (NULL, "LegacyBootOptionEnum", "BDS", 0);\r
+}\r