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