alder_lake_bios/Insyde/InsydeModulePkg/Universal/Console/RotateScreenDxe/PeCoffLib.c

397 lines
13 KiB
C

/** @file
RotateScreen
;******************************************************************************
;* Copyright (c) 2012 - 2016, 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 <Uefi.h>
#include <Guid/DebugMask.h>
#include <Library/BaseLib.h>
#include <Library/UefiBootServicesTableLib.h>
#include <Library/DebugLib.h>
#include <Library/BaseMemoryLib.h>
#include <Library/MemoryAllocationLib.h>
#include <Protocol/SimpleTextInEx.h>
#include <Protocol/GraphicsOutput.h>
#include <Protocol/AbsolutePointer.h>
#include <Protocol/DriverBinding.h>
#include <Protocol/ComponentName2.h>
#include <Protocol/LoadedImage.h>
#include "HookLib.h"
#define RESOURCE_SECTION_RESOURCE_TYPE_VERSION 16
#define VS_FIXEDFILEINFO_SIGNATURE 0xFEEF04BD
#define MICROSOFT_OS_VERSION_WINDOWS_8 0x00060002
typedef struct {
UINT32 Signature;
UINT32 StrucVersion;
UINT32 FileVersionMS;
UINT32 FileVersionLS;
UINT32 ProductVersionMS;
UINT32 ProductVersionLS;
UINT32 FileFlagsMask;
UINT32 FileFlags;
UINT32 FileOS;
UINT32 FileType;
UINT32 FileSubtype;
UINT32 FileDateMS;
UINT32 FileDateLS;
} VS_FIXEDFILEINFO;
/**
Get the headers (dos, image, optional header) from an image
@param Device SimpleFileSystem device handle
@param FileName File name for the image
@param DosHeader Pointer to dos header
@param Hdr The buffer in which to return the PE32, PE32+, or TE header.
@retval EFI_SUCCESS Successfully get the machine type.
@retval EFI_NOT_FOUND The file is not found.
@retval EFI_LOAD_ERROR File is not a valid image file.
**/
EFI_STATUS
EFIAPI
GetImageDataDirectory (
IN UINT8 *FileBuffer,
IN UINT64 FileSize,
IN UINT8 DirectoryType,
OUT EFI_IMAGE_DATA_DIRECTORY *DirectoryEntry
)
{
EFI_IMAGE_DOS_HEADER *DosHeader;
UINT64 BufferSize;
EFI_IMAGE_OPTIONAL_HEADER_PTR_UNION Hdr;
UINT16 Magic;
UINT32 NumberOfRvaAndSizes;
EFI_IMAGE_DATA_DIRECTORY *Directory;
//
// dos header
//
BufferSize = sizeof (EFI_IMAGE_DOS_HEADER);
DosHeader = (EFI_IMAGE_DOS_HEADER *) FileBuffer;
if (FileSize < BufferSize ||
FileSize <= DosHeader->e_lfanew ||
DosHeader->e_magic != EFI_IMAGE_DOS_SIGNATURE) {
return EFI_UNSUPPORTED;
}
//
// check PE signature
//
Hdr.Pe32 = (EFI_IMAGE_NT_HEADERS32 *)(FileBuffer + DosHeader->e_lfanew);
if (Hdr.Pe32->Signature != EFI_IMAGE_NT_SIGNATURE) {
return EFI_UNSUPPORTED;
}
Magic = Hdr.Pe32->OptionalHeader.Magic;
//
// Check PE32 or PE32+ magic
//
if (Magic != EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC &&
Magic != EFI_IMAGE_NT_OPTIONAL_HDR64_MAGIC) {
return EFI_UNSUPPORTED;
}
if (Magic == EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC) {
//
// Use PE32 offset
//
NumberOfRvaAndSizes = Hdr.Pe32->OptionalHeader.NumberOfRvaAndSizes;
Directory = (EFI_IMAGE_DATA_DIRECTORY *) &Hdr.Pe32->OptionalHeader.DataDirectory[DirectoryType];
} else {
//
// Use PE32+ offset
//
NumberOfRvaAndSizes = Hdr.Pe32Plus->OptionalHeader.NumberOfRvaAndSizes;
Directory = (EFI_IMAGE_DATA_DIRECTORY *) &Hdr.Pe32Plus->OptionalHeader.DataDirectory[DirectoryType];
}
if ((DirectoryType >= NumberOfRvaAndSizes) || Directory->Size == 0) {
return EFI_NOT_FOUND;
}
CopyMem (DirectoryEntry, Directory, sizeof (EFI_IMAGE_DATA_DIRECTORY));
return EFI_SUCCESS;
}
EFI_STATUS
EFIAPI
GetImageSectionHeader (
IN UINT8 *FileBuffer,
IN UINT64 FileSize,
IN CHAR8 *SectionName,
OUT EFI_IMAGE_SECTION_HEADER *SectionHeader
)
{
EFI_IMAGE_DOS_HEADER *DosHeader;
UINT64 BufferSize;
EFI_IMAGE_OPTIONAL_HEADER_PTR_UNION Hdr;
UINT16 Magic;
EFI_IMAGE_SECTION_HEADER *SectionHdr;
UINTN Index;
UINTN NumberOfSections;
UINTN StrLength;
//
// dos header
//
BufferSize = sizeof (EFI_IMAGE_DOS_HEADER);
DosHeader = (EFI_IMAGE_DOS_HEADER *) FileBuffer;
if (FileSize < BufferSize ||
FileSize <= DosHeader->e_lfanew ||
DosHeader->e_magic != EFI_IMAGE_DOS_SIGNATURE) {
return EFI_UNSUPPORTED;
}
//
// check PE signature
//
Hdr.Pe32 = (EFI_IMAGE_NT_HEADERS32 *)(FileBuffer + DosHeader->e_lfanew);
if (Hdr.Pe32->Signature != EFI_IMAGE_NT_SIGNATURE) {
return EFI_UNSUPPORTED;
}
Magic = Hdr.Pe32->OptionalHeader.Magic;
//
// Check PE32 or PE32+ magic
//
if (Magic != EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC &&
Magic != EFI_IMAGE_NT_OPTIONAL_HDR64_MAGIC) {
return EFI_UNSUPPORTED;
}
NumberOfSections = (UINTN) (Hdr.Pe32->FileHeader.NumberOfSections);
SectionHdr = (EFI_IMAGE_SECTION_HEADER *)((UINT8 *)Hdr.Pe32 +
sizeof (UINT32) +
sizeof (EFI_IMAGE_FILE_HEADER) +
Hdr.Pe32->FileHeader.SizeOfOptionalHeader
);
StrLength = AsciiStrLen (SectionName);
for (Index = 0; Index < NumberOfSections; Index++) {
if (AsciiStrnCmp (SectionHdr[Index].Name, SectionName, StrLength) == 0) {
CopyMem (SectionHeader, &SectionHdr[Index], sizeof (EFI_IMAGE_SECTION_HEADER));
return EFI_SUCCESS;
}
}
return EFI_NOT_FOUND;
}
/**
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
**/
EFI_STATUS
EFIAPI
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
**/
EFI_STATUS
EFIAPI
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 (EFI_ERROR (Status)) {
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;
}
BOOLEAN
EFIAPI
IsWindows (
EFI_HANDLE Handle,
UINT32 *VersionMS,
UINT32 *VersionLS
)
{
EFI_STATUS Status;
EFI_LOADED_IMAGE *LoadedImage;
EFI_IMAGE_DATA_DIRECTORY ResourceEntry;
EFI_IMAGE_SECTION_HEADER SectionHeader;
*VersionMS = 0;
*VersionLS = 0;
Status = gBS->HandleProtocol (
Handle,
&gEfiLoadedImageProtocolGuid,
&LoadedImage
);
ASSERT_EFI_ERROR (Status);
if (EFI_ERROR (Status)) {
return FALSE;
}
Status = GetImageDataDirectory (
LoadedImage->ImageBase,
LoadedImage->ImageSize,
EFI_IMAGE_DIRECTORY_ENTRY_RESOURCE,
&ResourceEntry
);
if (EFI_ERROR (Status)) {
return FALSE;
}
Status = GetImageSectionHeader (
LoadedImage->ImageBase,
LoadedImage->ImageSize,
".rsrc",
&SectionHeader
);
if (EFI_ERROR (Status)) {
return FALSE;
}
Status = GetWindowsOsVer (
&ResourceEntry,
(UINT8 *) LoadedImage->ImageBase + SectionHeader.VirtualAddress,
VersionMS,
VersionLS
);
if (EFI_ERROR (Status)) {
return FALSE;
}
return TRUE;
}