alder_lake_bios/Insyde/InsydeModulePkg/Library/GenericBdsLib/BdsFastBoot.c

845 lines
26 KiB
C

/** @file
BDS fast boot related functions
;******************************************************************************
;* Copyright (c) 2017 - 2021, 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 "InternalBdsLib.h"
/**
Get specific device path node from input device path.
@param[in] DevicePath The pointer of device path
@param[in] TargetDevicePathType Type of target device path node
@param[in] TargetDevicePathSubType Subtype of target device path node
@return The pointer of target device path node or NULL if not found
**/
STATIC
EFI_DEVICE_PATH_PROTOCOL *
GetDevicePathNode (
IN EFI_DEVICE_PATH_PROTOCOL *DevicePath,
IN UINT8 TargetDevicePathType,
IN UINT8 TargetDevicePathSubType
)
{
EFI_DEVICE_PATH_PROTOCOL *DevicePathNode;
if (DevicePath == NULL) {
return NULL;
}
DevicePathNode = DevicePath;
while (!IsDevicePathEnd (DevicePathNode)) {
if ((DevicePathType (DevicePathNode) == TargetDevicePathType) &&
(DevicePathSubType (DevicePathNode) == TargetDevicePathSubType)) {
return DevicePathNode;
}
DevicePathNode = NextDevicePathNode (DevicePathNode);
}
return NULL;
}
/**
Get version type resource directory
@param[in] ResourceData The pointer of resource data
@param[out] VersionDir The double pointer of version type resource directory
@param[out] VersionDirEntry The double pointer of version type resource directory entry
@retval EFI_SUCCESS Successfully get version type resource directory
@retval EFI_INVALID_PARAMETER Input pointer is NULL
@retval EFI_NOT_FOUND There is no version type resource directory
**/
STATIC
EFI_STATUS
GetVersionResourceDir (
IN UINT8 *ResourceData,
OUT EFI_IMAGE_RESOURCE_DIRECTORY **VersionDir,
OUT EFI_IMAGE_RESOURCE_DIRECTORY_ENTRY **VersionDirEntry
)
{
EFI_IMAGE_RESOURCE_DIRECTORY *Dir;
EFI_IMAGE_RESOURCE_DIRECTORY_ENTRY *DirEntry;
UINT16 Index;
UINT16 Count;
if (ResourceData == NULL || VersionDir == NULL || VersionDirEntry == NULL) {
return EFI_INVALID_PARAMETER;
}
Dir = (EFI_IMAGE_RESOURCE_DIRECTORY *) ResourceData;
DirEntry = (EFI_IMAGE_RESOURCE_DIRECTORY_ENTRY *) ((UINT8 *) Dir + sizeof (EFI_IMAGE_RESOURCE_DIRECTORY));
Count = Dir->NumberOfNamedEntries + Dir->NumberOfIdEntries;
for (Index = 0; Index < Count; Index++) {
if (DirEntry[Index].u1.Id == RESOURCE_SECTION_RESOURCE_TYPE_VERSION &&
DirEntry[Index].u2.s.DataIsDirectory) {
*VersionDir = (EFI_IMAGE_RESOURCE_DIRECTORY *) (ResourceData + DirEntry[Index].u2.s.OffsetToDirectory);
*VersionDirEntry = (EFI_IMAGE_RESOURCE_DIRECTORY_ENTRY *) ((UINT8 *) *VersionDir + sizeof (EFI_IMAGE_RESOURCE_DIRECTORY));
return EFI_SUCCESS;
}
}
return EFI_NOT_FOUND;
}
/**
Get the binary version number of Windows OS
@param[in] ResourceDir The pointer of resource directory of image
@param[in] ResourceData The pointer of resource data of image
@param[out] VersionMS The most significant 32 bits of the binary version number of Windows OS
@param[out] VersionLS The least significant 32 bits of the binary version number of Windows OS
@retval EFI_SUCCESS Successfully get binary version number
@retval EFI_INVALID_PARAMETER Input pointer is NULL or data size is zero
@retval EFI_NOT_FOUND There is no version number information in image
**/
STATIC
EFI_STATUS
GetWindowsOsVer (
IN EFI_IMAGE_DATA_DIRECTORY *ResourceDir,
IN UINT8 *ResourceData,
OUT UINT32 *VersionMS,
OUT UINT32 *VersionLS
)
{
EFI_STATUS Status;
EFI_IMAGE_RESOURCE_DIRECTORY *VersionDir;
EFI_IMAGE_RESOURCE_DIRECTORY_ENTRY *VersionDirEntry;
EFI_IMAGE_RESOURCE_DIRECTORY *Dir;
EFI_IMAGE_RESOURCE_DIRECTORY_ENTRY *DirEntry;
EFI_IMAGE_RESOURCE_DATA_ENTRY *DataEntry;
UINT16 Index;
UINT16 Count;
UINT8 *Ptr;
UINT8 *VersionInfo;
CHAR16 *KeyStr;
UINT16 MaxPaddingCount;
VS_FIXEDFILEINFO *FixedFileInfo;
if (ResourceDir == NULL || ResourceData == NULL || VersionMS == NULL || VersionLS == NULL) {
return EFI_INVALID_PARAMETER;
}
Status = GetVersionResourceDir (ResourceData, &VersionDir, &VersionDirEntry);
if (Status != EFI_SUCCESS) {
return EFI_NOT_FOUND;
}
Count = VersionDir->NumberOfNamedEntries + VersionDir->NumberOfIdEntries;
for (Index = 0; Index < Count; Index++) {
if (!VersionDirEntry[Index].u2.s.DataIsDirectory) {
continue;
}
Dir = (EFI_IMAGE_RESOURCE_DIRECTORY *) (ResourceData + VersionDirEntry[Index].u2.s.OffsetToDirectory);
DirEntry = (EFI_IMAGE_RESOURCE_DIRECTORY_ENTRY *) ((UINT8 *) Dir + sizeof (EFI_IMAGE_RESOURCE_DIRECTORY));
if (DirEntry->u2.s.DataIsDirectory) {
continue;
}
DataEntry = (EFI_IMAGE_RESOURCE_DATA_ENTRY *) (ResourceData + DirEntry->u2.OffsetToData);
if (DataEntry->OffsetToData < ResourceDir->VirtualAddress) {
continue;
}
//
// Get version info data entry VS_VERSIONINFO by comparing key string.
// Key string is located after VersionInfoSize (UINT16), ValueSize (UINT16) and Type (UINT16).
//
VersionInfo = ResourceData + (DataEntry->OffsetToData - ResourceDir->VirtualAddress);
KeyStr = (CHAR16 *) (VersionInfo + sizeof (UINT16) + sizeof (UINT16) + sizeof (UINT16));
if (StrCmp (KeyStr, L"VS_VERSION_INFO") != 0) {
continue;
}
Ptr = (UINT8 *) KeyStr;
Ptr += StrSize (KeyStr);
MaxPaddingCount = 3;
while (*Ptr == 0 && MaxPaddingCount > 0) {
Ptr++;
MaxPaddingCount--;
}
if (MaxPaddingCount == 0) {
continue;
}
FixedFileInfo = (VS_FIXEDFILEINFO *) Ptr;
if (FixedFileInfo->Signature != VS_FIXEDFILEINFO_SIGNATURE) {
continue;
}
*VersionMS = FixedFileInfo->ProductVersionMS;
*VersionLS = FixedFileInfo->ProductVersionLS;
return EFI_SUCCESS;
}
return EFI_NOT_FOUND;
}
/**
Get resource section header
@param[in] ThisFile File Handle
@param[in] DosHeader The pointer of image DOS header
@param[in] NumOfSections Number of section header in image
@param[out] ResourceSectionHeader The pointer of resouces section header
@retval EFI_SUCCESS Successfully get resource section header
@retval EFI_INVALID_PARAMETER Input pointer parameter is NULL
@retval EFI_BUFFER_TOO_SMALL Allocate pool fail
@retval EFI_NOT_FOUND Can not find resource section
@retval Other Fail to set file position or read data
**/
STATIC
EFI_STATUS
GetResourceSectionHeader (
IN EFI_FILE_HANDLE ThisFile,
IN EFI_IMAGE_DOS_HEADER *DosHeader,
IN UINT16 NumOfSections,
OUT EFI_IMAGE_SECTION_HEADER *ResourceSectionHeader
)
{
EFI_STATUS Status;
UINT8 *Buffer;
UINTN BufferSize;
UINT16 Index;
EFI_IMAGE_SECTION_HEADER *SectionHdrPtr;
EFI_IMAGE_OPTIONAL_HEADER_UNION PeHdr;
UINTN PeHdrSize;
if (ThisFile == NULL || DosHeader == NULL || ResourceSectionHeader == NULL) {
return EFI_INVALID_PARAMETER;
}
Status = ThisFile->SetPosition (ThisFile, DosHeader->e_lfanew);
if (EFI_ERROR (Status)) {
return Status;
}
BufferSize = sizeof(PeHdr);
ZeroMem (&PeHdr, BufferSize);
Status = ThisFile->Read (ThisFile, &BufferSize, &PeHdr);
if (EFI_ERROR (Status)) {
return Status;
}
if (PeHdr.Pe32.OptionalHeader.Magic == EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC) {
PeHdrSize = sizeof(EFI_IMAGE_NT_HEADERS32);
} else if (PeHdr.Pe32.OptionalHeader.Magic == EFI_IMAGE_NT_OPTIONAL_HDR64_MAGIC) {
PeHdrSize = sizeof(EFI_IMAGE_NT_HEADERS64);
} else {
return EFI_UNSUPPORTED;
}
Status = ThisFile->SetPosition (ThisFile, DosHeader->e_lfanew + PeHdrSize);
if (EFI_ERROR (Status)) {
return Status;
}
BufferSize = NumOfSections * sizeof (EFI_IMAGE_SECTION_HEADER);
Buffer = AllocatePool (BufferSize);
if (Buffer == NULL) {
return EFI_BUFFER_TOO_SMALL;
}
Status = ThisFile->Read (ThisFile, &BufferSize, Buffer);
if (EFI_ERROR (Status)) {
FreePool (Buffer);
return Status;
}
SectionHdrPtr = (EFI_IMAGE_SECTION_HEADER *) Buffer;
for (Index = 0; Index < NumOfSections; Index++) {
if (AsciiStrnCmp ((CHAR8 *) SectionHdrPtr, ".rsrc", 5) == 0) {
CopyMem (ResourceSectionHeader, SectionHdrPtr, sizeof (EFI_IMAGE_SECTION_HEADER));
break;
}
SectionHdrPtr++;
}
FreePool (Buffer);
return (Index < NumOfSections) ? EFI_SUCCESS : EFI_NOT_FOUND;
}
/**
Get raw data of resource section
@param[in] ThisFile File Handle
@param[in] SectionHeader The pointer of seaction header
@param[out] RawData The double pointer of raw data
@param[out] RawDataSize The pointer of raw data size
@retval EFI_SUCCESS Successfully get raw data
@retval EFI_INVALID_PARAMETER Input pointer parameter is NULL
@retval EFI_BUFFER_TOO_SMALL Allocate pool fail
@retval Other Fail to set file position or read data
**/
STATIC
EFI_STATUS
GetResourceSectionRawData (
IN EFI_FILE_HANDLE ThisFile,
IN EFI_IMAGE_SECTION_HEADER *SectionHeader,
OUT UINT8 **RawData,
OUT UINT32 *RawDataSize
)
{
EFI_STATUS Status;
UINT8 *Buffer;
UINTN BufferSize;
if (ThisFile == NULL || SectionHeader == NULL || RawData == NULL || RawDataSize == NULL) {
return EFI_INVALID_PARAMETER;
}
Status = ThisFile->SetPosition (ThisFile, SectionHeader->PointerToRawData);
if (EFI_ERROR (Status)) {
return Status;
}
//
// Read real file size. VirtualSize is the real file size and SizeOfRawData is the size with file alignment
//
BufferSize = SectionHeader->Misc.VirtualSize;
Buffer = AllocatePool (BufferSize);
if (Buffer == NULL) {
return EFI_OUT_OF_RESOURCES;
}
Status = ThisFile->Read (ThisFile, &BufferSize, Buffer);
if (EFI_ERROR (Status)) {
FreePool (Buffer);
return Status;
}
*RawData = Buffer;
*RawDataSize = (UINT32) BufferSize;
return EFI_SUCCESS;
}
/**
Get resource section data from image file
@param[in] Device Device handle
@param[in] FileName Target file name
@param[out] ResourceDataDir The pointer of resource data directory
@param[out] ResourceData The double pointer of resource data
@param[out] ResourceDataSize The pointer of resource data size
@retval EFI_SUCCESS Successfully get resource section data
@retval EFI_NOT_FOUND There is no resource data directory in image file
@retval EFI_INVALID_PARAMETER The pointer of input parameter is NULL
@retval Other Fail to get resource section data
**/
STATIC
EFI_STATUS
GetResourceSectionData (
IN EFI_HANDLE Device,
IN CHAR16 *FileName,
OUT EFI_IMAGE_DATA_DIRECTORY *ResourceDataDir,
OUT UINT8 **ResourceData,
OUT UINT32 *ResourceDataSize
)
{
EFI_STATUS Status;
EFI_IMAGE_DOS_HEADER DosHeader;
EFI_IMAGE_OPTIONAL_HEADER_PTR_UNION Hdr;
EFI_IMAGE_OPTIONAL_HEADER_UNION HdrData;
UINT16 Magic;
EFI_IMAGE_DATA_DIRECTORY *DataDir;
UINT16 NumOfSections;
EFI_IMAGE_SECTION_HEADER ResourceSectionHeader;
EFI_SIMPLE_FILE_SYSTEM_PROTOCOL *Volume;
EFI_FILE_HANDLE Root;
EFI_FILE_HANDLE ThisFile;
if (FileName == NULL || ResourceDataDir == NULL || ResourceData == NULL || ResourceDataSize == NULL) {
return EFI_INVALID_PARAMETER;
}
//
// Get resource data directory
//
Hdr.Union = &HdrData;
Status = BdsLibGetImageHeader (Device, FileName, &DosHeader, Hdr);
if (EFI_ERROR (Status) || !EFI_IMAGE_MACHINE_TYPE_SUPPORTED (Hdr.Pe32->FileHeader.Machine)) {
return EFI_NOT_FOUND;
}
if (Hdr.Pe32->FileHeader.Machine == EFI_IMAGE_MACHINE_IA64 && Hdr.Pe32->OptionalHeader.Magic == EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC) {
Magic = EFI_IMAGE_NT_OPTIONAL_HDR64_MAGIC;
} else {
Magic = Hdr.Pe32->OptionalHeader.Magic;
}
if (Magic == EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC) {
DataDir = (EFI_IMAGE_DATA_DIRECTORY *) &Hdr.Pe32->OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_RESOURCE];
NumOfSections = Hdr.Pe32->FileHeader.NumberOfSections;
} else {
DataDir = (EFI_IMAGE_DATA_DIRECTORY *) &Hdr.Pe32Plus->OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_RESOURCE];
NumOfSections = Hdr.Pe32Plus->FileHeader.NumberOfSections;
}
if (DataDir->Size == 0) {
return EFI_NOT_FOUND;
}
//
// Open file and read resource section data
//
Root = NULL;
ThisFile = NULL;
Status = gBS->HandleProtocol (Device, &gEfiSimpleFileSystemProtocolGuid, (VOID *) &Volume);
if (EFI_ERROR (Status)) {
goto Done;
}
Status = Volume->OpenVolume (Volume, &Root);
if (EFI_ERROR (Status)) {
Root = NULL;
goto Done;
}
Status = Root->Open (Root, &ThisFile, FileName, EFI_FILE_MODE_READ, 0);
if (EFI_ERROR (Status)) {
goto Done;
}
Status = GetResourceSectionHeader (ThisFile, &DosHeader, NumOfSections, &ResourceSectionHeader);
if (EFI_ERROR (Status)) {
goto Done;
}
Status = GetResourceSectionRawData (ThisFile, &ResourceSectionHeader, ResourceData, ResourceDataSize);
if (EFI_ERROR (Status)) {
goto Done;
}
CopyMem (ResourceDataDir, DataDir, sizeof (EFI_IMAGE_DATA_DIRECTORY));
Done:
if (ThisFile != NULL) {
ThisFile->Close (ThisFile);
}
if (Root != NULL) {
Root->Close (Root);
}
return Status;
}
/**
Indicates if the OS version of boot option device path matches, or is greater than, the Windows 8 version
@param[in] BootOptionDevicePath The device path of boot option
@retval TRUE The OS version of boot option device path matches, or is greater than, the Windows 8 version
@retval FALSE The OS version of boot option device path does not matches, or is not greater than, the Windows 8 version
**/
STATIC
BOOLEAN
IsWindows8OrGreater (
IN EFI_DEVICE_PATH_PROTOCOL *BootOptionDevicePath
)
{
EFI_STATUS Status;
EFI_DEVICE_PATH_PROTOCOL *WorkingDevicePath;
EFI_DEVICE_PATH_PROTOCOL *FullDevicePath;
EFI_IMAGE_DATA_DIRECTORY ResourceDataDir;
FILEPATH_DEVICE_PATH *FilePath;
UINT8 *ResourceData;
UINT32 ResourceDataSize;
UINT32 VersionMS;
UINT32 VersionLS;
EFI_HANDLE Handle;
if (BootOptionDevicePath == NULL) {
return FALSE;
}
//
// Get device path handle
//
FullDevicePath = NULL;
if ((DevicePathType (BootOptionDevicePath) == MEDIA_DEVICE_PATH) &&
(DevicePathSubType (BootOptionDevicePath) == MEDIA_HARDDRIVE_DP)) {
FullDevicePath = BdsExpandPartitionPartialDevicePathToFull ((HARDDRIVE_DEVICE_PATH *) BootOptionDevicePath);
if (FullDevicePath == NULL) {
return FALSE;
}
WorkingDevicePath = FullDevicePath;
} else {
WorkingDevicePath = BootOptionDevicePath;
}
Status = gBS->LocateDevicePath (
&gEfiSimpleFileSystemProtocolGuid,
&WorkingDevicePath,
&Handle
);
if (FullDevicePath != NULL) {
FreePool (FullDevicePath);
}
if (EFI_ERROR (Status)) {
return FALSE;
}
//
// Check if the OS version of boot option device path matches, or is greater than, the Windows 8 version
//
FilePath = (FILEPATH_DEVICE_PATH *) GetDevicePathNode (BootOptionDevicePath, MEDIA_DEVICE_PATH, MEDIA_FILEPATH_DP);
if (FilePath == NULL) {
return FALSE;
}
ResourceData = NULL;
Status = GetResourceSectionData (Handle, FilePath->PathName, &ResourceDataDir, &ResourceData, &ResourceDataSize);
if (Status != EFI_SUCCESS) {
return FALSE;
}
Status = GetWindowsOsVer (&ResourceDataDir, ResourceData, &VersionMS, &VersionLS);
if (Status != EFI_SUCCESS) {
return FALSE;
}
return (VersionMS >= MICROSOFT_OS_VERSION_WINDOWS_8) ? TRUE : FALSE;
}
/**
Check if the file of boot option device path belongs to fast boot UEFI OS.
@param[in] BootOptionDevicePath The device path of boot option
@retval TRUE The file of boot option device path belongs to fast boot UEFI OS
@retval FALSE The file of boot option device path does not belong to fast boot UEFI OS
**/
STATIC
BOOLEAN
IsFastBootUefiOs (
IN EFI_DEVICE_PATH_PROTOCOL *BootOptionDevicePath
)
{
BOOLEAN Result;
FILEPATH_DEVICE_PATH *FilePath;
CHAR16 *PcdFastBootOsList;
CHAR16 *FastBootOsList;
CHAR16 *FastBootOs;
CHAR16 *NextFastBootOs;
Result = FALSE;
FilePath = (FILEPATH_DEVICE_PATH *) GetDevicePathNode (BootOptionDevicePath, MEDIA_DEVICE_PATH, MEDIA_FILEPATH_DP);
if (FilePath == NULL) {
return Result;
}
PcdFastBootOsList = PcdGetPtr (PcdUefiOsFastBootList);
FastBootOsList = AllocateCopyPool (StrSize (PcdFastBootOsList), PcdFastBootOsList);
if (FastBootOsList == NULL) {
return Result;
}
NextFastBootOs = FastBootOsList;
while (NextFastBootOs != NULL) {
FastBootOs = NextFastBootOs;
//
// Skip front space characters of file path string
//
while (*FastBootOs == ' ') {
FastBootOs++;
}
if (*FastBootOs == CHAR_NULL) {
break;
}
//
// Because two files are separated by space char, modify space char to null and set NextFastBootOs pointer to next char.
//
NextFastBootOs = StrStr (FastBootOs, L" ");
if (NextFastBootOs != NULL) {
*NextFastBootOs = CHAR_NULL;
NextFastBootOs++;
}
if (StrStr (FastBootOs, FilePath->PathName) != NULL) {
if (StrStr (FilePath->PathName, L"\\EFI\\Microsoft\\Boot\\bootmgfw.efi") != NULL) {
Result = IsWindows8OrGreater (BootOptionDevicePath);
} else {
Result = TRUE;
}
break;
}
}
FreePool (FastBootOsList);
return Result;
}
/**
Update the BlockIo device path of target boot device into TargetHddDevPath variable.
Assume target boot device is HDD in the first boot option in BootOrder.
@retval EFI_SUCCESS Update target HDD variable success.
@retval EFI_NOT_FOUND BootOrder or Boot#### variable does not exist.
**/
EFI_STATUS
UpdateTargetHddVariable (
VOID
)
{
EFI_STATUS Status;
UINT16 *BootOrder;
UINTN Size;
EFI_DEVICE_PATH_PROTOCOL *OptionDevicePath;
UINTN BlockIndex;
UINTN BlockIoHandleCount;
EFI_HANDLE *BlockIoBuffer;
EFI_DEVICE_PATH_PROTOCOL *BlockIoDevicePath;
BootOrder = BdsLibGetVariableAndSize (
L"BootOrder",
&gEfiGlobalVariableGuid,
&Size
);
if (BootOrder == NULL) {
return EFI_NOT_FOUND;
}
OptionDevicePath = BdsLibGetDevicePathFromBootOption (BootOrder[0]);
if (OptionDevicePath == NULL) {
FreePool (BootOrder);
return EFI_NOT_FOUND;
}
if (((DevicePathType (OptionDevicePath) == MEDIA_DEVICE_PATH) &&
(DevicePathSubType (OptionDevicePath) == MEDIA_HARDDRIVE_DP)) &&
IsFastBootUefiOs (OptionDevicePath)) {
BlockIoBuffer = NULL;
Status = gBS->LocateHandleBuffer (
ByProtocol,
&gEfiBlockIoProtocolGuid,
NULL,
&BlockIoHandleCount,
&BlockIoBuffer
);
if (!EFI_ERROR (Status)) {
for (BlockIndex = 0; BlockIndex < BlockIoHandleCount; BlockIndex++) {
Status = gBS->HandleProtocol (
BlockIoBuffer[BlockIndex],
&gEfiDevicePathProtocolGuid,
(VOID **) &BlockIoDevicePath
);
if (EFI_ERROR (Status) || BlockIoDevicePath == NULL) {
continue;
}
if (MatchPartitionDevicePathNode (BlockIoDevicePath, (HARDDRIVE_DEVICE_PATH *) OptionDevicePath)) {
gRT->SetVariable (
L"TargetHddDevPath",
&gEfiGenericVariableGuid,
EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS,
GetDevicePathSize (BlockIoDevicePath),
BlockIoDevicePath
);
break;
}
}
if (BlockIoBuffer != NULL) {
FreePool (BlockIoBuffer);
}
}
}
FreePool (OptionDevicePath);
FreePool (BootOrder);
return EFI_SUCCESS;
}
/**
Set target HDD in boot list as connected.
**/
VOID
SetTargetHddConnected (
VOID
)
{
EFI_DEVICE_PATH_PROTOCOL *BlockIoDevicePath;
UINTN Size;
LIST_ENTRY *OptionList;
LIST_ENTRY *Link;
H2O_BDS_LOAD_OPTION *CurrentLoadOption;
EFI_STATUS Status;
BlockIoDevicePath = BdsLibGetVariableAndSize (
L"TargetHddDevPath",
&gEfiGenericVariableGuid,
&Size
);
if (BlockIoDevicePath == NULL) {
return;
}
if (GetDevicePathSizeEx (BlockIoDevicePath, Size) == 0) {
FreePool (BlockIoDevicePath);
return;
}
Status = gBdsServices->GetBootList (gBdsServices, &OptionList);
if (Status != EFI_SUCCESS) {
return;
}
for (Link = GetFirstNode (OptionList); !IsNull (OptionList, Link); Link = GetNextNode (OptionList, Link)) {
CurrentLoadOption = BDS_OPTION_FROM_LINK (Link);
if (((DevicePathType (CurrentLoadOption->DevicePath) == MEDIA_DEVICE_PATH) &&
(DevicePathSubType (CurrentLoadOption->DevicePath) == MEDIA_HARDDRIVE_DP)) &&
MatchPartitionDevicePathNode (BlockIoDevicePath, (HARDDRIVE_DEVICE_PATH *) CurrentLoadOption->DevicePath)) {
CurrentLoadOption->Connected = TRUE;
}
}
FreePool (BlockIoDevicePath);
}
/**
Check target device is valid or not by comparing device path from TargetHddDevPath variable.
@retval TRUE Target device is valid.
@retval FALSE Target device is not valid.
**/
STATIC
BOOLEAN
TargetDevIsValid (
VOID
)
{
BOOLEAN Valid;
UINT16 *BootOrder;
UINTN Size;
EFI_DEVICE_PATH_PROTOCOL *OptionDevicePath;
EFI_DEVICE_PATH_PROTOCOL *BlockIoDevicePath;
CHAR16 BootOption[BOOT_OPTION_MAX_CHAR];
EFI_LOAD_OPTION *BootOptionVar;
BootOrder = BdsLibGetVariableAndSize (
L"BootOrder",
&gEfiGlobalVariableGuid,
&Size
);
if (BootOrder == NULL) {
return FALSE;
}
OptionDevicePath = BdsLibGetDevicePathFromBootOption (BootOrder[0]);
if (OptionDevicePath == NULL) {
FreePool (BootOrder);
return FALSE;
}
UnicodeSPrint (BootOption, sizeof (BootOption), L"Boot%04x", BootOrder[0]);
BootOptionVar = (EFI_LOAD_OPTION *) BdsLibGetVariableAndSize (
BootOption,
&gEfiGlobalVariableGuid,
&Size
);
if (BootOptionVar == NULL || !IS_LOAD_OPTION_TYPE (BootOptionVar->Attributes, LOAD_OPTION_ACTIVE)) {
FreePool ((VOID*)BootOptionVar);
return FALSE;
}
Valid = FALSE;
if (((DevicePathType (OptionDevicePath) == MEDIA_DEVICE_PATH) &&
(DevicePathSubType (OptionDevicePath) == MEDIA_HARDDRIVE_DP))) {
BlockIoDevicePath = BdsLibGetVariableAndSize (
L"TargetHddDevPath",
&gEfiGenericVariableGuid,
&Size
);
if (BlockIoDevicePath != NULL &&
GetDevicePathSizeEx (BlockIoDevicePath, Size) != 0 &&
MatchPartitionDevicePathNode (BlockIoDevicePath, (HARDDRIVE_DEVICE_PATH *) OptionDevicePath)) {
Valid = TRUE;
FreePool (BlockIoDevicePath);
}
}
FreePool (OptionDevicePath);
FreePool (BootOrder);
FreePool ((VOID*)BootOptionVar);
return Valid;
}
/**
Check Win 8 Fast Boot feature is active or not.
@retval TRUE Win 8 Fast Boot feature is active.
@retval FALSE Win 8 Fast Boot feature is not active.
**/
BOOLEAN
BdsLibIsWin8FastBootActive (
VOID
)
{
EFI_STATUS Status;
KERNEL_CONFIGURATION SystemConfiguration;
UINT16 BootNext;
UINTN Size;
Size = sizeof (BootNext);
Status = gRT->GetVariable (
L"BootNext",
&gEfiGlobalVariableGuid,
NULL,
&Size,
&BootNext
);
if (!EFI_ERROR (Status)) {
return FALSE;
}
Status = GetKernelConfiguration (&SystemConfiguration);
if (EFI_ERROR (Status)) {
return FALSE;
}
if (SystemConfiguration.Win8FastBoot == 0 &&
H2OGetBootType () == EFI_BOOT_TYPE) {
switch (SystemConfiguration.NewPositionPolicy) {
case ADD_POSITION_AUTO:
if (TargetDevIsValid ()) {
return TRUE;
}
break;
case ADD_POSITION_FIRST:
case ADD_POSITION_LAST:
default:
break;
}
}
return FALSE;
}