mirror of
https://github.com/CloverHackyColor/CloverBootloader.git
synced 2024-12-02 13:03:28 +01:00
680 lines
14 KiB
C
680 lines
14 KiB
C
/** @file
|
|
UEFI Image Loader library implementation.
|
|
|
|
Copyright (c) 2023, Marvin Häuser. All rights reserved.<BR>
|
|
|
|
SPDX-License-Identifier: BSD-3-Clause
|
|
**/
|
|
|
|
#include <Base.h>
|
|
#include <Uefi/UefiBaseType.h>
|
|
#include <Uefi/UefiSpec.h>
|
|
|
|
#include <Library/BaseLib.h>
|
|
#include <Library/BaseMemoryLib.h>
|
|
#include <Library/BaseOverflowLib.h>
|
|
#include <Library/CacheMaintenanceLib.h>
|
|
#include <Library/DebugLib.h>
|
|
#include <Library/MemoryAllocationLib.h>
|
|
#include <Library/PcdLib.h>
|
|
#include <Library/UefiImageLib.h>
|
|
#include <Library/UefiImageExtraActionLib.h>
|
|
|
|
#include "UeSupport.h"
|
|
#include "PeSupport.h"
|
|
|
|
STATIC_ASSERT (
|
|
UEFI_IMAGE_FORMAT_SUPPORT_SOURCES != 0,
|
|
"At least one UEFI image format support source must be enabled."
|
|
);
|
|
|
|
#if (UEFI_IMAGE_FORMAT_SUPPORT_SOURCES & (1 << UEFI_IMAGE_SOURCE_NON_FV)) != 0
|
|
#define UEFI_IMAGE_FORMAT_SUPPORT_NON_FV PcdGet8 (PcdUefiImageFormatSupportNonFv)
|
|
#else
|
|
#define UEFI_IMAGE_FORMAT_SUPPORT_NON_FV 0
|
|
#endif
|
|
|
|
#if (UEFI_IMAGE_FORMAT_SUPPORT_SOURCES & (1 << UEFI_IMAGE_SOURCE_FV)) != 0
|
|
#define UEFI_IMAGE_FORMAT_SUPPORT_FV PcdGet8 (PcdUefiImageFormatSupportFv)
|
|
#else
|
|
#define UEFI_IMAGE_FORMAT_SUPPORT_FV 0
|
|
#endif
|
|
|
|
#define UEFI_IMAGE_FORMAT_SUPPORT \
|
|
(UEFI_IMAGE_FORMAT_SUPPORT_NON_FV | UEFI_IMAGE_FORMAT_SUPPORT_FV)
|
|
|
|
#define FORMAT_EQ(FormatIndex, Format) \
|
|
(UEFI_IMAGE_FORMAT_SUPPORT == (1U << (Format)) || \
|
|
((UEFI_IMAGE_FORMAT_SUPPORT & (1U << (Format))) != 0 && \
|
|
(FormatIndex) == (Format)))
|
|
|
|
#define UEFI_IMAGE_EXEC(Result, FormatIndex, Func, ...) \
|
|
do { \
|
|
if (FORMAT_EQ ((FormatIndex), UefiImageFormatUe)) { \
|
|
ASSERT ((FormatIndex) == UefiImageFormatUe); \
|
|
Result = mUeSupport.Func (__VA_ARGS__); \
|
|
} else { \
|
|
ASSERT ((FormatIndex) == UefiImageFormatPe); \
|
|
Result = mPeSupport.Func (__VA_ARGS__); \
|
|
} \
|
|
} while (FALSE)
|
|
|
|
#define UEFI_IMAGE_EXEC_VOID(FormatIndex, Func, ...) \
|
|
do { \
|
|
if (FORMAT_EQ ((FormatIndex), UefiImageFormatUe)) { \
|
|
ASSERT ((FormatIndex) == UefiImageFormatUe); \
|
|
mUeSupport.Func (__VA_ARGS__); \
|
|
} else { \
|
|
ASSERT ((FormatIndex) == UefiImageFormatPe); \
|
|
mPeSupport.Func (__VA_ARGS__); \
|
|
} \
|
|
} while (FALSE)
|
|
|
|
STATIC_ASSERT (
|
|
UefiImageFormatMax == 2,
|
|
"Support for more formats needs to be added above."
|
|
);
|
|
|
|
#define FORMAT_SUPPORTED(Format, Source) \
|
|
((UEFI_IMAGE_FORMAT_SUPPORT & (1U << (Format))) != 0 && \
|
|
(((Source) == UEFI_IMAGE_SOURCE_NON_FV && (UEFI_IMAGE_FORMAT_SUPPORT_NON_FV & (1U << (Format))) != 0) || \
|
|
((Source) == UEFI_IMAGE_SOURCE_FV && (UEFI_IMAGE_FORMAT_SUPPORT_FV & (1U << (Format))) != 0)))
|
|
|
|
STATIC_ASSERT (
|
|
UEFI_IMAGE_SOURCE_MAX == 3,
|
|
"Support for more sources needs to be added above."
|
|
);
|
|
|
|
STATIC
|
|
RETURN_STATUS
|
|
InternalInitializeContextPreHash (
|
|
OUT UEFI_IMAGE_LOADER_IMAGE_CONTEXT *Context,
|
|
IN CONST VOID *FileBuffer,
|
|
IN UINT32 FileSize,
|
|
IN UINT8 FormatIndex,
|
|
IN UINT8 ImageOrigin
|
|
)
|
|
{
|
|
RETURN_STATUS Status;
|
|
|
|
UEFI_IMAGE_EXEC (
|
|
Status,
|
|
FormatIndex,
|
|
InitializeContextPreHash,
|
|
Context,
|
|
FileBuffer,
|
|
FileSize,
|
|
ImageOrigin
|
|
);
|
|
|
|
return Status;
|
|
}
|
|
|
|
RETURN_STATUS
|
|
UefiImageInitializeContextPreHash (
|
|
OUT UEFI_IMAGE_LOADER_IMAGE_CONTEXT *Context,
|
|
IN CONST VOID *FileBuffer,
|
|
IN UINT32 FileSize,
|
|
IN UEFI_IMAGE_SOURCE Source,
|
|
IN UINT8 ImageOrigin
|
|
)
|
|
{
|
|
RETURN_STATUS Status;
|
|
|
|
#if (UEFI_IMAGE_FORMAT_SUPPORT_SOURCES & (1U << UEFI_IMAGE_SOURCE_NON_FV)) != 0
|
|
ASSERT ((PcdGet8 (PcdUefiImageFormatSupportNonFv) & ~((1ULL << UefiImageFormatMax) - 1ULL)) == 0);
|
|
ASSERT (PcdGet8 (PcdUefiImageFormatSupportNonFv) != 0);
|
|
#else
|
|
ASSERT (Source != UEFI_IMAGE_SOURCE_NON_FV);
|
|
#endif
|
|
|
|
#if (UEFI_IMAGE_FORMAT_SUPPORT_SOURCES & (1U << UEFI_IMAGE_SOURCE_FV)) != 0
|
|
ASSERT ((PcdGet8 (PcdUefiImageFormatSupportFv) & ~((1ULL << UefiImageFormatMax) - 1ULL)) == 0);
|
|
ASSERT (PcdGet8 (PcdUefiImageFormatSupportFv) != 0);
|
|
#else
|
|
ASSERT (Source != UEFI_IMAGE_SOURCE_FV);
|
|
#endif
|
|
|
|
Status = RETURN_UNSUPPORTED;
|
|
|
|
STATIC_ASSERT (
|
|
UefiImageFormatUe == UefiImageFormatMax - 1,
|
|
"Support for more formats needs to be added above."
|
|
);
|
|
|
|
if (FORMAT_SUPPORTED (UefiImageFormatUe, Source)) {
|
|
Status = InternalInitializeContextPreHash (
|
|
Context,
|
|
FileBuffer,
|
|
FileSize,
|
|
UefiImageFormatUe,
|
|
ImageOrigin
|
|
);
|
|
if (!RETURN_ERROR (Status)) {
|
|
Context->FormatIndex = UefiImageFormatUe;
|
|
}
|
|
}
|
|
|
|
if (RETURN_ERROR (Status) && FORMAT_SUPPORTED (UefiImageFormatPe, Source)) {
|
|
Status = InternalInitializeContextPreHash (
|
|
Context,
|
|
FileBuffer,
|
|
FileSize,
|
|
UefiImageFormatPe,
|
|
ImageOrigin
|
|
);
|
|
if (!RETURN_ERROR (Status)) {
|
|
Context->FormatIndex = UefiImageFormatPe;
|
|
}
|
|
}
|
|
|
|
return Status;
|
|
}
|
|
|
|
BOOLEAN
|
|
UefiImageHashImageDefault (
|
|
IN OUT UEFI_IMAGE_LOADER_IMAGE_CONTEXT *Context,
|
|
IN OUT VOID *HashContext,
|
|
IN UEFI_IMAGE_LOADER_HASH_UPDATE HashUpdate
|
|
)
|
|
{
|
|
BOOLEAN Success;
|
|
|
|
UEFI_IMAGE_EXEC (
|
|
Success,
|
|
Context->FormatIndex,
|
|
HashImageDefault,
|
|
Context,
|
|
HashContext,
|
|
HashUpdate
|
|
);
|
|
|
|
return Success;
|
|
}
|
|
|
|
RETURN_STATUS
|
|
UefiImageInitializeContextPostHash (
|
|
IN OUT UEFI_IMAGE_LOADER_IMAGE_CONTEXT *Context
|
|
)
|
|
{
|
|
RETURN_STATUS Status;
|
|
|
|
UEFI_IMAGE_EXEC (
|
|
Status,
|
|
Context->FormatIndex,
|
|
InitializeContextPostHash,
|
|
Context
|
|
);
|
|
|
|
return Status;
|
|
}
|
|
|
|
RETURN_STATUS
|
|
UefiImageLoadImage (
|
|
IN OUT UEFI_IMAGE_LOADER_IMAGE_CONTEXT *Context,
|
|
OUT VOID *Destination,
|
|
IN UINT32 DestinationSize
|
|
)
|
|
{
|
|
RETURN_STATUS Status;
|
|
|
|
UEFI_IMAGE_EXEC (
|
|
Status,
|
|
Context->FormatIndex,
|
|
LoadImage,
|
|
Context,
|
|
Destination,
|
|
DestinationSize
|
|
);
|
|
|
|
return Status;
|
|
}
|
|
|
|
BOOLEAN
|
|
UefiImageImageIsInplace (
|
|
IN OUT UEFI_IMAGE_LOADER_IMAGE_CONTEXT *Context
|
|
)
|
|
{
|
|
BOOLEAN Result;
|
|
|
|
UEFI_IMAGE_EXEC (
|
|
Result,
|
|
Context->FormatIndex,
|
|
ImageIsInplace,
|
|
Context
|
|
);
|
|
|
|
return Result;
|
|
}
|
|
|
|
RETURN_STATUS
|
|
UefiImageLoadImageInplace (
|
|
IN OUT UEFI_IMAGE_LOADER_IMAGE_CONTEXT *Context
|
|
)
|
|
{
|
|
RETURN_STATUS Status;
|
|
|
|
UEFI_IMAGE_EXEC (
|
|
Status,
|
|
Context->FormatIndex,
|
|
LoadImageInplace,
|
|
Context
|
|
);
|
|
|
|
return Status;
|
|
}
|
|
|
|
RETURN_STATUS
|
|
UefiImageRelocateImageInplace (
|
|
IN OUT UEFI_IMAGE_LOADER_IMAGE_CONTEXT *Context
|
|
)
|
|
{
|
|
RETURN_STATUS Status;
|
|
|
|
UEFI_IMAGE_EXEC (
|
|
Status,
|
|
Context->FormatIndex,
|
|
RelocateImageInplace,
|
|
Context
|
|
);
|
|
|
|
return Status;
|
|
}
|
|
|
|
RETURN_STATUS
|
|
UefiImageLoaderGetRuntimeContextSize (
|
|
IN OUT UEFI_IMAGE_LOADER_IMAGE_CONTEXT *Context,
|
|
OUT UINT32 *Size
|
|
)
|
|
{
|
|
RETURN_STATUS Status;
|
|
|
|
UEFI_IMAGE_EXEC (
|
|
Status,
|
|
Context->FormatIndex,
|
|
LoaderGetRuntimeContextSize,
|
|
Context,
|
|
Size
|
|
);
|
|
if (!RETURN_ERROR (Status)) {
|
|
*Size += 8;
|
|
}
|
|
|
|
return Status;
|
|
}
|
|
|
|
RETURN_STATUS
|
|
UefiImageRelocateImage (
|
|
IN OUT UEFI_IMAGE_LOADER_IMAGE_CONTEXT *Context,
|
|
IN UINT64 BaseAddress,
|
|
OUT UEFI_IMAGE_LOADER_RUNTIME_CONTEXT *RuntimeContext OPTIONAL,
|
|
IN UINT32 RuntimeContextSize
|
|
)
|
|
{
|
|
RETURN_STATUS Status;
|
|
VOID *FormatContext;
|
|
UINT32 FormatContextSize;
|
|
|
|
FormatContext = RuntimeContext;
|
|
FormatContextSize = RuntimeContextSize;
|
|
if (RuntimeContext != NULL) {
|
|
*(UINT64 *)RuntimeContext = Context->FormatIndex;
|
|
FormatContext = (VOID *)((UINT64 *)RuntimeContext + 1);
|
|
ASSERT (FormatContextSize >= 8);
|
|
FormatContextSize -= 8;
|
|
}
|
|
|
|
UEFI_IMAGE_EXEC (
|
|
Status,
|
|
Context->FormatIndex,
|
|
RelocateImage,
|
|
Context,
|
|
BaseAddress,
|
|
FormatContext,
|
|
FormatContextSize
|
|
);
|
|
|
|
if (!RETURN_ERROR (Status)) {
|
|
UefiImageLoaderRelocateImageExtraAction (Context);
|
|
}
|
|
|
|
return Status;
|
|
}
|
|
|
|
RETURN_STATUS
|
|
UefiImageRuntimeRelocateImage (
|
|
IN OUT VOID *Image,
|
|
IN UINT32 ImageSize,
|
|
IN UINT64 BaseAddress,
|
|
IN CONST UEFI_IMAGE_LOADER_RUNTIME_CONTEXT *RuntimeContext
|
|
)
|
|
{
|
|
RETURN_STATUS Status;
|
|
|
|
UEFI_IMAGE_EXEC (
|
|
Status,
|
|
*(UINT8 *)RuntimeContext,
|
|
RuntimeRelocateImage,
|
|
Image,
|
|
ImageSize,
|
|
BaseAddress,
|
|
((UINT64 *)RuntimeContext + 1)
|
|
);
|
|
|
|
return Status;
|
|
}
|
|
|
|
VOID
|
|
UefiImageDiscardSegments (
|
|
IN OUT UEFI_IMAGE_LOADER_IMAGE_CONTEXT *Context
|
|
)
|
|
{
|
|
UEFI_IMAGE_EXEC_VOID (
|
|
Context->FormatIndex,
|
|
DiscardSegments,
|
|
Context
|
|
);
|
|
}
|
|
|
|
RETURN_STATUS
|
|
UefiImageGetSymbolsPath (
|
|
IN CONST UEFI_IMAGE_LOADER_IMAGE_CONTEXT *Context,
|
|
OUT CONST CHAR8 **SymbolsPath,
|
|
OUT UINT32 *SymbolsPathSize
|
|
)
|
|
{
|
|
RETURN_STATUS Status;
|
|
|
|
UEFI_IMAGE_EXEC (
|
|
Status,
|
|
Context->FormatIndex,
|
|
GetSymbolsPath,
|
|
Context,
|
|
SymbolsPath,
|
|
SymbolsPathSize
|
|
);
|
|
|
|
return Status;
|
|
}
|
|
|
|
RETURN_STATUS
|
|
UefiImageGetFirstCertificate (
|
|
IN OUT UEFI_IMAGE_LOADER_IMAGE_CONTEXT *Context,
|
|
OUT CONST WIN_CERTIFICATE **Certificate
|
|
)
|
|
{
|
|
RETURN_STATUS Status;
|
|
|
|
UEFI_IMAGE_EXEC (
|
|
Status,
|
|
Context->FormatIndex,
|
|
GetFirstCertificate,
|
|
Context,
|
|
Certificate
|
|
);
|
|
|
|
return Status;
|
|
}
|
|
|
|
RETURN_STATUS
|
|
UefiImageGetNextCertificate (
|
|
IN OUT UEFI_IMAGE_LOADER_IMAGE_CONTEXT *Context,
|
|
IN OUT CONST WIN_CERTIFICATE **Certificate
|
|
)
|
|
{
|
|
RETURN_STATUS Status;
|
|
|
|
UEFI_IMAGE_EXEC (
|
|
Status,
|
|
Context->FormatIndex,
|
|
GetNextCertificate,
|
|
Context,
|
|
Certificate
|
|
);
|
|
|
|
return Status;
|
|
}
|
|
|
|
RETURN_STATUS
|
|
UefiImageGetHiiDataRva (
|
|
IN OUT UEFI_IMAGE_LOADER_IMAGE_CONTEXT *Context,
|
|
OUT UINT32 *HiiRva,
|
|
OUT UINT32 *HiiSize
|
|
)
|
|
{
|
|
RETURN_STATUS Status;
|
|
|
|
UEFI_IMAGE_EXEC (
|
|
Status,
|
|
Context->FormatIndex,
|
|
GetHiiDataRva,
|
|
Context,
|
|
HiiRva,
|
|
HiiSize
|
|
);
|
|
|
|
return Status;
|
|
}
|
|
|
|
UINT32
|
|
UefiImageGetEntryPointAddress (
|
|
IN CONST UEFI_IMAGE_LOADER_IMAGE_CONTEXT *Context
|
|
)
|
|
{
|
|
UINT32 Result;
|
|
|
|
UEFI_IMAGE_EXEC (
|
|
Result,
|
|
Context->FormatIndex,
|
|
GetEntryPointAddress,
|
|
Context
|
|
);
|
|
|
|
return Result;
|
|
}
|
|
|
|
UINT16
|
|
UefiImageGetMachine (
|
|
IN OUT UEFI_IMAGE_LOADER_IMAGE_CONTEXT *Context
|
|
)
|
|
{
|
|
UINT16 Result;
|
|
|
|
UEFI_IMAGE_EXEC (
|
|
Result,
|
|
Context->FormatIndex,
|
|
GetMachine,
|
|
Context
|
|
);
|
|
|
|
return Result;
|
|
}
|
|
|
|
UINT16
|
|
UefiImageGetSubsystem (
|
|
IN OUT UEFI_IMAGE_LOADER_IMAGE_CONTEXT *Context
|
|
)
|
|
{
|
|
UINT16 Result;
|
|
|
|
UEFI_IMAGE_EXEC (
|
|
Result,
|
|
Context->FormatIndex,
|
|
GetSubsystem,
|
|
Context
|
|
);
|
|
|
|
return Result;
|
|
}
|
|
|
|
UINT32
|
|
UefiImageGetSegmentAlignment (
|
|
IN OUT UEFI_IMAGE_LOADER_IMAGE_CONTEXT *Context
|
|
)
|
|
{
|
|
UINT32 Result;
|
|
|
|
UEFI_IMAGE_EXEC (
|
|
Result,
|
|
Context->FormatIndex,
|
|
GetSegmentAlignment,
|
|
Context
|
|
);
|
|
|
|
return Result;
|
|
}
|
|
|
|
UINT32
|
|
UefiImageGetImageSize (
|
|
IN OUT UEFI_IMAGE_LOADER_IMAGE_CONTEXT *Context
|
|
)
|
|
{
|
|
UINT32 Result;
|
|
|
|
UEFI_IMAGE_EXEC (
|
|
Result,
|
|
Context->FormatIndex,
|
|
GetImageSize,
|
|
Context
|
|
);
|
|
|
|
return Result;
|
|
}
|
|
|
|
UINT64
|
|
UefiImageGetBaseAddress (
|
|
IN OUT UEFI_IMAGE_LOADER_IMAGE_CONTEXT *Context
|
|
)
|
|
{
|
|
UINT64 Result;
|
|
|
|
UEFI_IMAGE_EXEC (
|
|
Result,
|
|
Context->FormatIndex,
|
|
GetBaseAddress,
|
|
Context
|
|
);
|
|
|
|
return Result;
|
|
}
|
|
|
|
BOOLEAN
|
|
UefiImageGetRelocsStripped (
|
|
IN OUT UEFI_IMAGE_LOADER_IMAGE_CONTEXT *Context
|
|
)
|
|
{
|
|
BOOLEAN Result;
|
|
|
|
UEFI_IMAGE_EXEC (
|
|
Result,
|
|
Context->FormatIndex,
|
|
GetRelocsStripped,
|
|
Context
|
|
);
|
|
|
|
return Result;
|
|
}
|
|
|
|
UINTN
|
|
UefiImageLoaderGetImageAddress (
|
|
IN CONST UEFI_IMAGE_LOADER_IMAGE_CONTEXT *Context
|
|
)
|
|
{
|
|
UINTN Result;
|
|
|
|
UEFI_IMAGE_EXEC (
|
|
Result,
|
|
Context->FormatIndex,
|
|
LoaderGetImageAddress,
|
|
Context
|
|
);
|
|
|
|
return Result;
|
|
}
|
|
|
|
UINTN
|
|
UefiImageLoaderGetDebugAddress (
|
|
IN CONST UEFI_IMAGE_LOADER_IMAGE_CONTEXT *Context
|
|
)
|
|
{
|
|
UINTN Result;
|
|
|
|
UEFI_IMAGE_EXEC (
|
|
Result,
|
|
Context->FormatIndex,
|
|
LoaderGetDebugAddress,
|
|
Context
|
|
);
|
|
|
|
return Result;
|
|
}
|
|
|
|
UEFI_IMAGE_RECORD *
|
|
UefiImageLoaderGetImageRecord (
|
|
IN OUT UEFI_IMAGE_LOADER_IMAGE_CONTEXT *Context
|
|
)
|
|
{
|
|
UEFI_IMAGE_RECORD *Result;
|
|
|
|
UEFI_IMAGE_EXEC (
|
|
Result,
|
|
Context->FormatIndex,
|
|
LoaderGetImageRecord,
|
|
Context
|
|
);
|
|
|
|
return Result;
|
|
}
|
|
|
|
RETURN_STATUS
|
|
UefiImageDebugLocateImage (
|
|
OUT UEFI_IMAGE_LOADER_IMAGE_CONTEXT *Context,
|
|
IN UINTN Address,
|
|
IN UINT8 ImageOrigin
|
|
)
|
|
{
|
|
RETURN_STATUS Status;
|
|
|
|
UEFI_IMAGE_EXEC (
|
|
Status,
|
|
Context->FormatIndex,
|
|
DebugLocateImage,
|
|
Context,
|
|
Address,
|
|
ImageOrigin
|
|
);
|
|
|
|
return Status;
|
|
}
|
|
|
|
RETURN_STATUS
|
|
UefiImageGetFixedAddress (
|
|
IN OUT UEFI_IMAGE_LOADER_IMAGE_CONTEXT *Context,
|
|
OUT UINT64 *Address
|
|
)
|
|
{
|
|
RETURN_STATUS Status;
|
|
|
|
UEFI_IMAGE_EXEC (
|
|
Status,
|
|
Context->FormatIndex,
|
|
GetFixedAddress,
|
|
Context,
|
|
Address
|
|
);
|
|
|
|
return Status;
|
|
}
|
|
|
|
VOID
|
|
UefiImageDebugPrintSegments (
|
|
IN OUT UEFI_IMAGE_LOADER_IMAGE_CONTEXT *Context
|
|
)
|
|
{
|
|
UEFI_IMAGE_EXEC_VOID (
|
|
Context->FormatIndex,
|
|
DebugPrintSegments,
|
|
Context
|
|
);
|
|
}
|