alder_lake_bios/Insyde/InsydeModulePkg/Universal/CommonPolicy/BootOptionPolicyDxe/BootOptionPolicy.c

888 lines
28 KiB
C

/** @file
Entry and initial functions for BootOptionPolicy driver
;******************************************************************************
;* Copyright (c) 2012 - 2020, Insyde Software Corp. All Rights Reserved.
;*
;* You may not reproduce, distribute, publish, display, perform, modify, adapt,
;* transmit, broadcast, present, recite, release, license or otherwise exploit
;* any part of this publication in any form, by any means, without the prior
;* written permission of Insyde Software Corporation.
;*
;******************************************************************************
*/
#include "BootOptionPolicy.h"
STATIC
BOOLEAN
IsUsbDevice (
IN BBS_TABLE *CurrentBbsTable
);
STATIC
EFI_STATUS
ConvertDeviceType (
IN OUT UINT8 *DevType,
IN BOOT_OPTION_POLICY_DATA *BootOptionPolicyData
);
STATIC
EFI_STATUS
GetNormalTypeBootPosition (
IN BOOT_OPTION_POLICY_DATA *BootOptionPolicyData,
IN UINT16 *BootOrderList,
IN UINTN RegisterOptionNumber,
IN UINTN BootOptionNum,
IN OUT UINTN *NewPosition
);
STATIC
BOOLEAN
IsEfiShellBootOption (
IN EFI_DEVICE_PATH_PROTOCOL *DevicePath
);
/**
Initialize BootOptionPolicy driver.
@param ImageHandle The image handle.
@param SystemTable The system table.
@retval EFI_SUCCESS The BootOptionPolicy module is initialized correctly..
@return Other value if failed to initialize the BootOptionPolicy module.
**/
EFI_STATUS
EFIAPI
InitBootOptionPolicy (
IN EFI_HANDLE ImageHandle,
IN EFI_SYSTEM_TABLE *SystemTable
)
{
EFI_STATUS Status;
BOOT_OPTION_POLICY_DATA *BootOptionPolicyData;
KERNEL_CONFIGURATION KernelConfiguration;
Status = GetKernelConfiguration (&KernelConfiguration);
if (EFI_ERROR (Status)) {
return Status;
}
//
// implement worker function
//
BootOptionPolicyData = AllocateZeroPool (sizeof(BOOT_OPTION_POLICY_DATA));
if (BootOptionPolicyData == NULL) {
return EFI_OUT_OF_RESOURCES;
}
BootOptionPolicyData->Signature = EFI_BOOT_OPTION_POLICY_SIGNATURE;
BootOptionPolicyData->NewPositionPolicy = KernelConfiguration.NewPositionPolicy;
BootOptionPolicyData->BootNormalPriority = KernelConfiguration.BootNormalPriority;
BootOptionPolicyData->LegacyNormalMenuType = KernelConfiguration.LegacyNormalMenuType;
CopyMem (BootOptionPolicyData->BootTypeOrder, KernelConfiguration.BootTypeOrder, MAX_BOOT_ORDER_NUMBER);
BootOptionPolicyData->BootOptionPolicy.FindPositionOfNewBootOption = FindPositionOfNewBootOption;
BootOptionPolicyData->BootOptionPolicy.GetEfiOptionPriority = GetEfiOptionPriority;
//
// Install Setup Utility
//
BootOptionPolicyData->Handle = NULL;
Status = gBS->InstallProtocolInterface (
&BootOptionPolicyData->Handle,
&gEfiBootOptionPolicyProtocolGuid,
EFI_NATIVE_INTERFACE,
&BootOptionPolicyData->BootOptionPolicy
);
if (EFI_ERROR (Status)) {
FreePool (BootOptionPolicyData);
return Status;
}
return EFI_SUCCESS;
}
EFI_STATUS
EFIAPI
FindPositionOfNewBootOption (
IN EFI_BOOT_OPTION_POLICY_PROTOCOL * This,
IN EFI_DEVICE_PATH_PROTOCOL *DevicePath,
IN UINT16 *BootOrder,
IN UINTN BootOptionType,
IN UINTN BootOptionNum,
IN UINTN RegisterOptionNumber,
IN OUT UINTN *NewPosition
)
{
BOOT_OPTION_POLICY_DATA *BootOptionPolicyData;
UINTN Index;
UINTN BootOption;
CHAR16 BootOptionString[20];
UINTN BootOptionSize;
VOID *BootOptionVar;
UINTN NewPositionPolicy;
BOOLEAN FindFlag;
UINTN BootOptionTypePolicy = 1;
UINTN CurrentBootOptionType;
EFI_DEVICE_PATH_PROTOCOL *OptionDevicePath;
UINT8 *TempPtr;
UINTN LegacyNormalMenuType;
EFI_STATUS Status;
EFI_BOOT_ORDER_PRIORITY WorkBootPriority;
EFI_BOOT_ORDER_PRIORITY CurrentBootPriority;
UINTN LastEfiBootIndex;
BOOLEAN CreateByOS;
UINTN Size;
BootOptionPolicyData = EFI_BOOT_OPTION_POLICY_FROM_THIS (This);
NewPositionPolicy = BootOptionPolicyData->NewPositionPolicy;
BootOptionTypePolicy = BootOptionPolicyData->BootNormalPriority;
LegacyNormalMenuType = BootOptionPolicyData->LegacyNormalMenuType;
//
// find the first Legacy BootOPtion in BootOrder
//
BootOption = 0;
FindFlag = FALSE;
CurrentBootPriority = OtherEfiBootOption;
LastEfiBootIndex = 0xFFFFFFFF;
if (BootOptionType == EFI_BOOT_DEV && NewPositionPolicy == IN_AUTO) {
Status = GetEfiOptionPriority (
This,
FALSE,
DevicePath,
&CurrentBootPriority
);
ASSERT_EFI_ERROR (Status);
if (EFI_ERROR (Status)) {
return Status;
}
}
for (Index = 0; Index < BootOptionNum; Index++) {
BootOption = BootOrder[Index];
UnicodeSPrint (
BootOptionString,
sizeof (BootOptionString),
L"Boot%04x",
BootOption
);
BootOptionSize = 0;
BootOptionVar = NULL;
Status = CommonGetVariableDataAndSize (
BootOptionString,
&gEfiGlobalVariableGuid,
&BootOptionSize,
(VOID**) &BootOptionVar
);
if (EFI_ERROR (Status)) {
return EFI_NOT_FOUND;
}
Size = 0;
TempPtr = BootOptionVar;
TempPtr += sizeof (UINT32);
Size += sizeof (UINT32) + (UINT16) (*TempPtr);
TempPtr += sizeof (UINT16);
Size += sizeof (UINT16) + (UINT16) StrSize ((UINT16 *) TempPtr);
TempPtr += StrSize ((CHAR16 *) TempPtr);
OptionDevicePath = (EFI_DEVICE_PATH_PROTOCOL *) TempPtr;
TempPtr += GetDevicePathSize (OptionDevicePath);
if ((BBS_DEVICE_PATH == OptionDevicePath->Type) && (BBS_BBS_DP == OptionDevicePath->SubType)) {
CurrentBootOptionType = LEGACY_BOOT_DEV;
} else {
CurrentBootOptionType = EFI_BOOT_DEV;
}
if (CurrentBootOptionType == BootOptionType) {
//
// if the Legacy Normal menu type is set and BootOptionType is legacy boot device
// ,get the boot order new position according device type
//
if ((LegacyNormalMenuType == 0) && (BootOptionType == LEGACY_BOOT_DEV)) {
Status = GetNormalTypeBootPosition (
BootOptionPolicyData,
BootOrder,
RegisterOptionNumber,
BootOptionNum,
NewPosition
);
if (!EFI_ERROR (Status)) {
Index = BootOptionNum;
FindFlag = TRUE;
}
} else {
switch (NewPositionPolicy) {
case IN_FIRST :
if (BootOptionType == BootOptionTypePolicy) {
*NewPosition = 0;
} else {
*NewPosition = Index;
}
Index = BootOptionNum;
FindFlag = TRUE;
break;
case IN_LAST :
*NewPosition = Index + 1;
FindFlag = TRUE;
break;
case IN_AUTO:
if (BootOptionType == LEGACY_BOOT_DEV) {
//
// Legacy devices boot order is same as IN_FIRST
//
if (BootOptionType == BootOptionTypePolicy) {
*NewPosition = 0;
} else {
*NewPosition = Index;
}
Index = BootOptionNum;
FindFlag = TRUE;
} else {
CreateByOS = TRUE;
if (((BootOptionSize - Size == 2) && (AsciiStrnCmp ((CHAR8 *)TempPtr, "RC", 2) == 0)) ||
(IsEfiShellBootOption (DevicePath) && (BootOptionSize - Size >= 2) && (AsciiStrnCmp ((CHAR8 *)TempPtr, "RC", 2) == 0))) {
CreateByOS = FALSE;
}
Status = GetEfiOptionPriority (
This,
CreateByOS,
OptionDevicePath,
&WorkBootPriority
);
ASSERT_EFI_ERROR (Status);
LastEfiBootIndex = Index;
if (CurrentBootPriority <= WorkBootPriority) {
*NewPosition = Index;
Index = BootOptionNum;
FindFlag = TRUE;
}
}
break;
default :
break;
}
}
}
FreePool (BootOptionVar);
}
if (!FindFlag) {
if (BootOptionType == BootOptionTypePolicy) {
*NewPosition = (LastEfiBootIndex == 0xFFFFFFFF) ? 0 : LastEfiBootIndex + 1;
} else {
*NewPosition = BootOptionNum;
}
}
return EFI_SUCCESS;
}
/**
Check the specific BBS Table entry is USB device
@param CurrentBbsTable Pointer to current BBS table start address
@retval TRUE It is USB device
@retval FALSE It isn't USB device
**/
STATIC
BOOLEAN
IsUsbDevice (
IN BBS_TABLE *CurrentBbsTable
)
{
if ((CurrentBbsTable->Class == PCI_CLASS_SERIAL) &&
(CurrentBbsTable->SubClass == PCI_CLASS_SERIAL_USB)) {
return TRUE;
}
return FALSE;
}
/**
convert the device the device type according supported device type.
if the device type isn't in supported Boot type order, change this
type to BOOT_POLICY_OTHER_DEVICE
@param DevType IN : a pointer point to original device type
OUT: a pointer point to converted device type
@param BootOptionPolicyData a pointer point to BOOT_OPTION_POLICY_DATA
@retval EFI_SUCCESS Convert device type successfully.
@retval EFI_INVALID_PARAMETER Invalid input parameter.
**/
STATIC
EFI_STATUS
ConvertDeviceType (
IN OUT UINT8 *DevType,
IN BOOT_OPTION_POLICY_DATA *BootOptionPolicyData
)
{
UINT8 DevTypeOrder[MAX_BOOT_ORDER_NUMBER];
UINTN DeviceTypeCount;
UINTN Index;
BOOLEAN SupportedType;
if ((DevType == NULL) || (BootOptionPolicyData == NULL)) {
return EFI_INVALID_PARAMETER;
}
//
//calculate the supported device type count
//
for (DeviceTypeCount = 0; DeviceTypeCount < MAX_BOOT_ORDER_NUMBER; DeviceTypeCount++) {
if (BootOptionPolicyData->BootTypeOrder[DeviceTypeCount] == 0) {
break;
}
}
ZeroMem (DevTypeOrder, MAX_BOOT_ORDER_NUMBER);
CopyMem (DevTypeOrder, BootOptionPolicyData->BootTypeOrder, DeviceTypeCount);
SupportedType = FALSE;
for (Index = 0; Index < DeviceTypeCount; Index++) {
if (*DevType == DevTypeOrder[Index]) {
SupportedType = TRUE;
}
}
if (!SupportedType) {
*DevType = BOOT_POLICY_OTHER_DEVICE;
}
return EFI_SUCCESS;
}
/**
Get the new postion for new register option number in boot order according
boot type and new position policy (IN_FIRST or IN_LAST)
@param BootOptionPolicyData a pointer point to BOOT_OPTION_POLICY_DATA
@param BootOrderList a pointer point to boot order list
@param RegisterOptionNumber the new boot option number which want to insert to boot order
@param BootOptionNum the total boot option count
@param NewPosition IN : a valid pointer which doesn't point to NULL
OUT: a pointer point to the position which want to insert to boot order
@retval EFI_SUCCESS get new boot position is success
@retval EFI_INVALID_PARAMETER input parameter is invalid
@retval EFI_UNSUPPORTED 1. the new register boot option is not legacy device
2. the NewPositionPolicy is invalid
**/
STATIC
EFI_STATUS
GetNormalTypeBootPosition (
IN BOOT_OPTION_POLICY_DATA *BootOptionPolicyData,
IN UINT16 *BootOrderList,
IN UINTN RegisterOptionNumber,
IN UINTN BootOptionNum,
IN OUT UINTN *NewPosition
)
{
EFI_STATUS Status;
UINT16 BootOption[100];
UINT8 *BootOptionVar;
UINT8 *Ptr;
UINT16 DevPathLen;
UINT8 DevType;
UINTN Index;
UINTN Index2;
UINT8 DevTypeOrder[MAX_BOOT_ORDER_NUMBER];
UINTN DeviceTypeCount;
UINTN BehindCurrentDevTypeCount;
UINTN LastLegacyBootOptionNum;
EFI_DEVICE_PATH_PROTOCOL *DevPath;
if ((BootOptionPolicyData == NULL) ||
(BootOptionPolicyData->LegacyNormalMenuType != 0)) {
return EFI_INVALID_PARAMETER;
}
if ((BootOrderList == NULL) || (NewPosition == NULL)) {
return EFI_INVALID_PARAMETER;
}
BehindCurrentDevTypeCount = 0;
LastLegacyBootOptionNum = 0;
//
//Calculate the supported device type count
//
for (DeviceTypeCount = 0; DeviceTypeCount < MAX_BOOT_ORDER_NUMBER; DeviceTypeCount++) {
if (BootOptionPolicyData->BootTypeOrder[DeviceTypeCount] == 0) {
break;
}
}
ZeroMem (DevTypeOrder, MAX_BOOT_ORDER_NUMBER);
//
//Get the device type from this new boot option
//
UnicodeSPrint (BootOption, sizeof (BootOption), L"Boot%04x", RegisterOptionNumber);
BootOptionVar = CommonGetVariableData (
BootOption,
&gEfiGlobalVariableGuid
);
if (BootOptionVar == NULL) {
return EFI_NOT_FOUND;
}
Ptr = BootOptionVar;
Ptr += sizeof (UINT32);
DevPathLen = *(UINT16 *) Ptr;
Ptr += sizeof (UINT16);
Ptr += StrSize ((UINT16 *) Ptr);
DevPath = (EFI_DEVICE_PATH_PROTOCOL *) Ptr;
//
//Check is legacy boot device?
//
if (BBS_DEVICE_PATH != DevPath->Type || BBS_BBS_DP != DevPath->SubType) {
FreePool (BootOptionVar);
return EFI_UNSUPPORTED;
}
Ptr += DevPathLen;
if (IsUsbDevice ((BBS_TABLE *) Ptr)) {
DevType = BBS_USB;
} else {
DevType = (UINT8) (((BBS_TABLE *) Ptr)->DeviceType);
}
Status = ConvertDeviceType (&DevType, BootOptionPolicyData);
//
//Get all the devices type which behind the device type of new register boot option
//if the boot policy is IN_FIRST, the Saved devices type includes the boot type
//of new register boot option. if the boot policy is IN_LAST, the Saved devices type
//doesn't include the boot type
//
for (Index = 0; Index < DeviceTypeCount; Index++) {
if (DevType == BootOptionPolicyData->BootTypeOrder[Index]) {
switch (BootOptionPolicyData->NewPositionPolicy) {
case IN_FIRST:
case IN_AUTO:
BehindCurrentDevTypeCount = DeviceTypeCount - Index;
CopyMem (
DevTypeOrder,
&(BootOptionPolicyData->BootTypeOrder[Index]),
DeviceTypeCount - Index
);
break;
case IN_LAST:
if ((DeviceTypeCount - (Index + 1)) != 0) {
BehindCurrentDevTypeCount = DeviceTypeCount - (Index + 1);
CopyMem (
DevTypeOrder,
&(BootOptionPolicyData->BootTypeOrder[Index + 1]),
DeviceTypeCount - (Index + 1)
);
}
break;
default:
FreePool (BootOptionVar);
return EFI_UNSUPPORTED;;
}
break;
}
}
FreePool (BootOptionVar);
//
//Find the first boot option which match the any saved devices type
//
for (Index = 0; Index < BootOptionNum; Index++) {
UnicodeSPrint (BootOption, sizeof (BootOption), L"Boot%04x", BootOrderList[Index]);
BootOptionVar = CommonGetVariableData (
BootOption,
&gEfiGlobalVariableGuid
);
if (BootOptionVar == NULL) {
continue;
}
Ptr = BootOptionVar;
Ptr += sizeof (UINT32);
DevPathLen = *(UINT16 *) Ptr;
Ptr += sizeof (UINT16);
Ptr += StrSize ((UINT16 *) Ptr);
DevPath = (EFI_DEVICE_PATH_PROTOCOL *) Ptr;
//
//Check is legacy boot device? skip check EFI device
//
if (BBS_DEVICE_PATH != DevPath->Type || BBS_BBS_DP != DevPath->SubType) {
FreePool (BootOptionVar);
BootOptionVar = NULL;
continue;
}
LastLegacyBootOptionNum = Index + 1;
Ptr += DevPathLen;
if (IsUsbDevice ((BBS_TABLE *) Ptr)) {
DevType = BBS_USB;
} else {
DevType = (UINT8) (((BBS_TABLE *) Ptr)->DeviceType);
}
Status = ConvertDeviceType (&DevType, BootOptionPolicyData);
//
//search the match devices type
//
for (Index2 = 0; Index2 < BehindCurrentDevTypeCount; Index2++) {
if (DevType == DevTypeOrder[Index2]) {
*NewPosition = Index;
FreePool (BootOptionVar);
BootOptionVar = NULL;
return EFI_SUCCESS;
}
}
FreePool (BootOptionVar);
BootOptionVar = NULL;
}
//
//if not find any boot option to match saved boot devices type, insert the
//boot option in the last of the list of legacy boot device
//
*NewPosition = LastLegacyBootOptionNum;
return EFI_SUCCESS;
}
/**
Check whether there is a instance in BlockIoDevicePath, which contain multi device path
instances, has the same partition node with HardDriveDevicePath device path
@param BlockIoDevicePath Multi device path instances which need to check
@param HardDriveDevicePath A device path which starts with a hard drive media device path.
@retval TRUE There is a matched device path instance
@retval FALSE There is no matched device path instance
**/
STATIC
BOOLEAN
MatchPartitionDevicePathNode (
IN EFI_DEVICE_PATH_PROTOCOL *BlockIoDevicePath,
IN HARDDRIVE_DEVICE_PATH *HardDriveDevicePath
)
{
HARDDRIVE_DEVICE_PATH *Node;
if ((BlockIoDevicePath == NULL) || (HardDriveDevicePath == NULL)) {
return FALSE;
}
//
// Match all the partition device path nodes including the nested partition nodes
//
while (!IsDevicePathEnd (BlockIoDevicePath)) {
if ((DevicePathType (BlockIoDevicePath) == MEDIA_DEVICE_PATH) &&
(DevicePathSubType (BlockIoDevicePath) == MEDIA_HARDDRIVE_DP)
) {
//
// See if the harddrive device path in blockio matches the orig Hard Drive Node
//
Node = (HARDDRIVE_DEVICE_PATH *) BlockIoDevicePath;
//
// Match Signature and PartitionNumber.
// Unused bytes in Signature are initiaized with zeros.
//
if ((Node->PartitionNumber == HardDriveDevicePath->PartitionNumber) &&
(Node->MBRType == HardDriveDevicePath->MBRType) &&
(Node->SignatureType == HardDriveDevicePath->SignatureType) &&
(CompareMem (Node->Signature, HardDriveDevicePath->Signature, sizeof (Node->Signature)) == 0)) {
return TRUE;
}
}
BlockIoDevicePath = NextDevicePathNode (BlockIoDevicePath);
}
return FALSE;
}
/**
If input is a hard drive device path, append it to corresponding BlockIo device path.
If input is not a hard drive device path, output NULL.
@param HardDriveDevicePath Input device path
@return Pointer to device path which combines BlockIo and hard drive device path
or NULL if input is not hard disk device.
**/
STATIC
EFI_DEVICE_PATH_PROTOCOL *
AppendHardDrivePathToBlkIoDevicePath (
IN HARDDRIVE_DEVICE_PATH *HardDriveDevicePath
)
{
EFI_STATUS Status;
UINTN BlockIoHandleCount;
EFI_HANDLE *BlockIoBuffer;
EFI_DEVICE_PATH_PROTOCOL *BlockIoDevicePath;
EFI_DEVICE_PATH_PROTOCOL *DevicePath;
EFI_DEVICE_PATH_PROTOCOL *NewDevicePath;
UINTN Index;
if (HardDriveDevicePath == NULL) {
return NULL;
}
if (!((DevicePathType (&HardDriveDevicePath->Header) == MEDIA_DEVICE_PATH) &&
(DevicePathSubType (&HardDriveDevicePath->Header) == MEDIA_HARDDRIVE_DP))) {
return NULL;
}
Status = gBS->LocateHandleBuffer (ByProtocol, &gEfiBlockIoProtocolGuid, NULL, &BlockIoHandleCount, &BlockIoBuffer);
if (EFI_ERROR (Status) || BlockIoHandleCount == 0) {
return NULL;
}
for (Index = 0; Index < BlockIoHandleCount; Index++) {
Status = gBS->HandleProtocol (BlockIoBuffer[Index], &gEfiDevicePathProtocolGuid, (VOID *) &BlockIoDevicePath);
if (EFI_ERROR (Status) || BlockIoDevicePath == NULL) {
continue;
}
if (MatchPartitionDevicePathNode (BlockIoDevicePath, HardDriveDevicePath)) {
//
// Combine the Block IO and Hard Drive Device path together.
//
DevicePath = NextDevicePathNode ((EFI_DEVICE_PATH_PROTOCOL *) HardDriveDevicePath);
NewDevicePath = AppendDevicePath (BlockIoDevicePath, DevicePath);
FreePool (BlockIoBuffer);
return NewDevicePath;
}
}
FreePool (BlockIoBuffer);
return NULL;
}
/**
Check if the boot option is a EFI shell boot option which is put in ROM image.
@param DevicePath The device path need to be processed.
@retval TRUE It is a EFI shell boot option in ROM image.
@retval FALSE It is not a EFI shell boot option in ROM image.
**/
STATIC
BOOLEAN
IsEfiShellBootOption (
IN EFI_DEVICE_PATH_PROTOCOL *DevicePath
)
{
EFI_DEVICE_PATH_PROTOCOL *LastDeviceNode;
EFI_DEVICE_PATH_PROTOCOL *WorkDevicePath;
BOOLEAN IsEfiShell;
EFI_GUID *FileGuid;
IsEfiShell = FALSE;
WorkDevicePath = DevicePath;
LastDeviceNode = DevicePath;
while (!IsDevicePathEnd (WorkDevicePath)) {
LastDeviceNode = WorkDevicePath;
WorkDevicePath = NextDevicePathNode (WorkDevicePath);
}
FileGuid = EfiGetNameGuidFromFwVolDevicePathNode ((MEDIA_FW_VOL_FILEPATH_DEVICE_PATH *) LastDeviceNode);
if (FileGuid != NULL && (CompareGuid (FileGuid, PcdGetPtr(PcdShellFile)) || CompareGuid (FileGuid, PcdGetPtr(PcdMiniShellFile)))) {
IsEfiShell = TRUE;
}
return IsEfiShell;
}
/**
Check if the boot option is a EFI network boot option.
@param DevicePath The device path need to be processed.
@retval TRUE It is a EFI network boot option.
@retval FALSE It is not a EFI network boot option.
**/
STATIC
BOOLEAN
IsEfiNetWorkBootOption (
IN EFI_DEVICE_PATH_PROTOCOL *DevicePath
)
{
EFI_DEVICE_PATH_PROTOCOL *Node;
for (Node = DevicePath; !IsDevicePathEndType (Node); Node = NextDevicePathNode (Node)) {
if (DevicePathType (Node) == MESSAGING_DEVICE_PATH) {
switch (DevicePathSubType (Node)) {
case MSG_MAC_ADDR_DP:
case MSG_IPv4_DP:
case MSG_IPv6_DP:
return TRUE;
}
}
}
return FALSE;
}
/**
Check if the boot option is a EFI hard drive boot option.
@param DevicePath The device path need to be processed.
@retval TRUE It is a EFI hard drive boot option.
@retval FALSE It is not a EFI hard drive boot option.
**/
STATIC
BOOLEAN
IsEfiHarddriveBootOption (
IN EFI_DEVICE_PATH_PROTOCOL *DevicePath
)
{
EFI_DEVICE_PATH_PROTOCOL *Node;
for (Node = DevicePath; !IsDevicePathEndType (Node); Node = NextDevicePathNode (Node)) {
if (DevicePathType (Node) == MEDIA_DEVICE_PATH &&
DevicePathSubType (Node) == MEDIA_HARDDRIVE_DP) {
return TRUE;
}
}
return FALSE;
}
/**
Check if the boot option is a EFI USB boot option.
@param DevicePath The device path need to be processed.
@retval TRUE It is a EFI USB boot option.
@retval FALSE It is not a EFI USB boot option.
**/
STATIC
BOOLEAN
IsEfiUsbBootOption (
IN EFI_DEVICE_PATH_PROTOCOL *DevicePath
)
{
EFI_DEVICE_PATH_PROTOCOL *Node;
for (Node = DevicePath; !IsDevicePathEndType (Node); Node = NextDevicePathNode (Node)) {
if (DevicePathType (Node) == MESSAGING_DEVICE_PATH &&
DevicePathSubType (Node) == MSG_USB_DP) {
return TRUE;
}
}
return FALSE;
}
/**
Use device path to get the boot priority of EFI boot option. The priority policy as below
1. permanent OS created Boot Variables
2. Firmware created "Widnows Boot Loader" for recovery when OS hard disk boot item is missing.
3. Removable media with EFI spec boot \EFI\Boot\BootX64.efi or \EFI\Boot\BootIA32.efi
4. Network load image items when EFI Network Boot is enabled.
5. EFI Shell if found in ROM image
@param This A pointer to the EFI_BOOT_OPTION_POLICY_PROTOCOL instance.
@param CreateByOS A Flag to indicate this boot otpion is create by OS or not.
@param DevicePath A pointer to the EFI_DEVICE_PATH_PROTOCOL instance.
@param OptionPriority A pointer to save boot option prioriy.
@retval EFI_SUCCESS Get option priority successful.
@retval EFI_UNSUPPORTED Input device path isn't valid or is a BBS device path.
@retval EFI_INVALID_PARAMETER Input parameter is invalid.
**/
EFI_STATUS
EFIAPI
GetEfiOptionPriority (
IN EFI_BOOT_OPTION_POLICY_PROTOCOL *This,
IN BOOLEAN CreateByOS,
IN EFI_DEVICE_PATH_PROTOCOL *DevicePath,
OUT EFI_BOOT_ORDER_PRIORITY *OptionPriority
)
{
EFI_STATUS Status;
EFI_DEVICE_PATH_PROTOCOL *NewDevicePath;
EFI_DEVICE_PATH_PROTOCOL *TempDevicePath;
EFI_HANDLE Handle;
EFI_BLOCK_IO_PROTOCOL *BlkIo;
if (This == NULL || DevicePath == NULL || OptionPriority == NULL) {
return EFI_INVALID_PARAMETER;
}
if (BBS_DEVICE_PATH == DevicePathType (DevicePath) && BBS_BBS_DP == DevicePathSubType (DevicePath)) {
return EFI_UNSUPPORTED;
}
*OptionPriority = OtherEfiBootOption;
//
// Check USB Entry for Portable Workspace first
//
if (DevicePathType (DevicePath) == MESSAGING_DEVICE_PATH && DevicePathSubType (DevicePath) == MSG_USB_CLASS_DP) {
*OptionPriority = CreateByOS ? OsCreateEfiBootOption : RecoveryCreateEfiBootOption;
} else if (DevicePathType (DevicePath) == MESSAGING_DEVICE_PATH && DevicePathSubType (DevicePath) == MSG_USB_WWID_DP) {
*OptionPriority = RemovableEfiBootOption;
} else {
//
// Get hard Driver Full device path
//
NewDevicePath = AppendHardDrivePathToBlkIoDevicePath ((HARDDRIVE_DEVICE_PATH *) DevicePath);
if (NewDevicePath == NULL) {
NewDevicePath = DevicePath;
}
TempDevicePath = NewDevicePath;
Status = gBS->LocateDevicePath (
&gEfiSimpleFileSystemProtocolGuid,
&TempDevicePath,
&Handle
);
if (!EFI_ERROR (Status)) {
Status = gBS->HandleProtocol (
Handle,
&gEfiBlockIoProtocolGuid,
(VOID **) &BlkIo
);
if (!EFI_ERROR (Status)) {
if (!BlkIo->Media->RemovableMedia &&
!IsEfiUsbBootOption (NewDevicePath) &&
IsEfiHarddriveBootOption (NewDevicePath)) {
*OptionPriority = CreateByOS ? OsCreateEfiBootOption : RecoveryCreateEfiBootOption;
} else {
*OptionPriority = RemovableEfiBootOption;
}
}
} else if (IsEfiNetWorkBootOption (DevicePath)) {
//
// Check this boot option is whether EFI network boot option
//
*OptionPriority = NetWorkEfiBootOption;
} else if (IsEfiShellBootOption (DevicePath)) {
//
// Check this boot option is wheter shell found in ROM image
//
*OptionPriority = ShellEfiBootOption;
}
if (NewDevicePath != DevicePath) {
FreePool (NewDevicePath);
}
}
return EFI_SUCCESS;
}