BaseTools: Replaced GenFw with ImageTool and MicroTool.

This commit is contained in:
Mikhail Krichanov 2022-12-28 17:21:20 +03:00
parent ef68b89fbc
commit cf92e9f7d7
65 changed files with 8751 additions and 428 deletions

6
.gitmodules vendored
View File

@ -16,10 +16,14 @@
[submodule "BaseTools/Source/C/BrotliCompress/brotli"]
path = BaseTools/Source/C/BrotliCompress/brotli
url = https://github.com/google/brotli
ignore = untracked
ignore = untracked
[submodule "RedfishPkg/Library/JsonLib/jansson"]
path = RedfishPkg/Library/JsonLib/jansson
url = https://github.com/akheron/jansson
[submodule "UnitTestFrameworkPkg/Library/GoogleTestLib/googletest"]
path = UnitTestFrameworkPkg/Library/GoogleTestLib/googletest
url = https://github.com/google/googletest.git
[submodule "OpenCorePkg"]
path = OpenCorePkg
url = https://github.com/acidanthera/OpenCorePkg.git
branch = SecurePeAndImageTool-202211-rebase

View File

@ -18,4 +18,8 @@ Source/C/bin/
Source/C/libs/
Bin/Win32
Lib
BaseToolsBuild/
BaseToolsBuild/
ImageTool/ImageTool
ImageTool/ImageTool32
ImageTool/ImageTool64
MicroTool/MicroTool

View File

@ -0,0 +1,43 @@
#!/usr/bin/env bash
#
# Copyright (c) 2022, Mikhail Krichanov. All rights reserved.
# SPDX-License-Identifier: BSD-3-Clause
#
full_cmd=${BASH_SOURCE:-$0} # see http://mywiki.wooledge.org/BashFAQ/028 for a discussion of why $0 is not a good choice here
dir=$(dirname "$full_cmd")
cmd=${full_cmd##*/}
if [ -n "$WORKSPACE" ] && [ -e "$EDK_TOOLS_PATH/ImageTool" ]
then
if [ $1 == 'IA32' ]
then
if [ ! -e "$EDK_TOOLS_PATH/ImageTool/ImageTool32" ]
then
echo "BaseTools C Tool binary was not found (ImageTool32)"
echo "You may need to run:"
echo " make -C $EDK_TOOLS_PATH/ImageTool"
else
shift
exec "$EDK_TOOLS_PATH/ImageTool/ImageTool32" "$@"
fi
elif [ $1 == 'X64' ]
then
if [ ! -e "$EDK_TOOLS_PATH/ImageTool/ImageTool64" ]
then
echo "BaseTools C Tool binary was not found (ImageTool64)"
echo "You may need to run:"
echo " make -C $EDK_TOOLS_PATH/ImageTool"
else
shift
exec "$EDK_TOOLS_PATH/ImageTool/ImageTool64" "$@"
fi
else
echo "ImageTool for $1 is not supported"
exit 127
fi
else
echo "Unable to find the real '$cmd' to run"
echo "This message was printed by"
echo " $0"
exit 127
fi

View File

@ -0,0 +1,25 @@
#!/usr/bin/env bash
#
# Copyright (c) 2022, Mikhail Krichanov. All rights reserved.
# SPDX-License-Identifier: BSD-3-Clause
#
full_cmd=${BASH_SOURCE:-$0} # see http://mywiki.wooledge.org/BashFAQ/028 for a discussion of why $0 is not a good choice here
dir=$(dirname "$full_cmd")
cmd=${full_cmd##*/}
if [ -n "$WORKSPACE" ] && [ -e "$EDK_TOOLS_PATH/MicroTool" ]
then
if [ ! -e "$EDK_TOOLS_PATH/MicroTool/MicroTool" ]
then
echo "BaseTools C Tool binary was not found (MicroTool)"
echo "You may need to run:"
echo " make -C $EDK_TOOLS_PATH/MicroTool"
else
exec "$EDK_TOOLS_PATH/MicroTool/MicroTool" "$@"
fi
else
echo "Unable to find the real '$cmd' to run"
echo "This message was printed by"
echo " $0"
exit 127
fi

View File

@ -0,0 +1,22 @@
::
:: Copyright (c) 2022, Mikhail Krichanov. All rights reserved.
:: SPDX-License-Identifier: BSD-3-Clause
::
@echo off
set args=%2
:start
shift /2
if "%2"=="" goto done
set args=%args% %2
goto start
:done
if "%1%"=="IA32" (
call ImageTool32.exe %args%
) else (
if "%1%"=="X64" (
call ImageTool64.exe %args%
) else (
echo Unable to find the command to run!
)
)

View File

@ -0,0 +1,6 @@
::
:: Copyright (c) 2022, Mikhail Krichanov. All rights reserved.
:: SPDX-License-Identifier: BSD-3-Clause
::
@echo off
call MicroTool.exe %*

View File

@ -272,7 +272,14 @@
<Command.GCC>
$(RM) ${dst}
"$(SLINK)" cr ${dst} $(SLINK_FLAGS) @$(OBJECT_FILES_LIST)
<Command.RVCT>
"$(SLINK)" $(SLINK_FLAGS) ${dst} --via $(OBJECT_FILES_LIST)
<Command.RVCTCYGWIN>
# $(OBJECT_FILES_LIST) has wrong paths for cygwin
"$(SLINK)" $(SLINK_FLAGS) ${dst} $(OBJECT_FILES)
<Command.XCODE>
"$(SLINK)" $(SLINK_FLAGS) ${dst} -filelist $(OBJECT_FILES_LIST)
@ -299,8 +306,8 @@
<Command.XCODE>
"$(DLINK)" $(DLINK_FLAGS) -o ${dst} $(DLINK_SPATH) -filelist $(STATIC_LIBRARY_FILES_LIST) $(DLINK2_FLAGS)
[Static-Library-File.SEC.AARCH64, Static-Library-File.PEI_CORE.AARCH64, Static-Library-File.PEIM.AARCH64,Static-Library-File.SEC.ARM, Static-Library-File.PEI_CORE.ARM, Static-Library-File.PEIM.ARM]
<InputFile>
*.lib
@ -334,8 +341,8 @@
<Command.XCODE>
"$(DLINK)" -o ${dst} $(DLINK_FLAGS) $(DLINK_SPATH) -filelist $(STATIC_LIBRARY_FILES_LIST) $(DLINK2_FLAGS)
[Dynamic-Library-File]
<InputFile>
?.dll
@ -346,32 +353,33 @@
$(OUTPUT_DIR)(+)$(MODULE_NAME).map
<Command.MSFT, Command.INTEL, Command.CLANGPDB>
"$(GENFW)" -e $(MODULE_TYPE) -o ${dst} ${src} $(GENFW_FLAGS)
ImageTool $(ARCH) PeXip ${src} ${dst} $(MODULE_TYPE)
$(CP) ${dst} $(DEBUG_DIR)
$(CP) ${dst} $(BIN_DIR)(+)$(MODULE_NAME_GUID).efi
-$(CP) $(DEBUG_DIR)(+)*.map $(OUTPUT_DIR)
-$(CP) $(DEBUG_DIR)(+)*.pdb $(OUTPUT_DIR)
<Command.GCC>
-$(CP) $(DEBUG_DIR)(+)*.pdb $(OUTPUT_DIR)
<Command.GCC, Command.CLANGGCC>
$(CP) ${src} $(DEBUG_DIR)(+)$(MODULE_NAME).debug
$(OBJCOPY) $(OBJCOPY_STRIPFLAG) ${src}
#
#The below 2 lines are only needed for UNIXGCC tool chain, which generates PE image directly
# The below 2 lines are only needed for UNIXGCC tool chain, which generates PE image directly
#
-$(OBJCOPY) $(OBJCOPY_ADDDEBUGFLAG) ${src}
-$(CP) $(DEBUG_DIR)(+)$(MODULE_NAME).debug $(BIN_DIR)(+)$(MODULE_NAME_GUID).debug
ImageTool $(ARCH) ElfToPe ${src} ${dst} $(MODULE_TYPE)
"$(GENFW)" -e $(MODULE_TYPE) -o ${dst} ${src} $(GENFW_FLAGS)
$(CP) ${dst} $(DEBUG_DIR)
$(CP) ${dst} $(BIN_DIR)(+)$(MODULE_NAME_GUID).efi
-$(CP) $(DEBUG_DIR)(+)*.map $(OUTPUT_DIR)
<Command.XCODE>
# tool to convert Mach-O to PE/COFF
"$(MTOC)" -subsystem $(MODULE_TYPE) $(MTOC_FLAGS) ${src} $(DEBUG_DIR)(+)$(MODULE_NAME).pecoff
# create symbol file for GDB debug
-$(DSYMUTIL) ${src}
"$(GENFW)" -e $(MODULE_TYPE) -o ${dst} $(DEBUG_DIR)(+)$(MODULE_NAME).pecoff $(GENFW_FLAGS)
ImageTool $(ARCH) PeXip $(DEBUG_DIR)(+)$(MODULE_NAME).pecoff ${dst} $(MODULE_TYPE)
$(CP) ${dst} $(DEBUG_DIR)
$(CP) ${dst} $(BIN_DIR)(+)$(MODULE_NAME_GUID).efi
-$(CP) $(DEBUG_DIR)(+)*.map $(OUTPUT_DIR)
@ -405,14 +413,14 @@
<Command.MSFT, Command.INTEL>
Trim --asl-file --asl-deps -o $(OUTPUT_DIR)(+)${s_dir}(+)${s_base}.i -i $(INC_LIST) ${src}
"$(ASLPP)" $(DEPS_FLAGS) $(ASLPP_FLAGS) $(INC) /I${s_path} $(OUTPUT_DIR)(+)${s_dir}(+)${s_base}.i > $(OUTPUT_DIR)(+)${s_dir}(+)${s_base}.iii
Trim --source-code -l -o $(OUTPUT_DIR)(+)${s_dir}(+)${s_base}.iiii $(OUTPUT_DIR)(+)${s_dir}(+)${s_base}.iii
Trim --source-code -l -o $(OUTPUT_DIR)(+)${s_dir}(+)${s_base}.iiii $(OUTPUT_DIR)(+)${s_dir}(+)${s_base}.iii
"$(ASL)" $(ASL_FLAGS) $(ASL_OUTFLAGS)${dst} $(OUTPUT_DIR)(+)${s_dir}(+)${s_base}.iiii
$(CP) $(OUTPUT_DIR)(+)${s_dir}(+)${s_base}.aml $(OUTPUT_DIR)(+)${s_dir}(+)${s_base}.amli
<Command.GCC>
Trim --asl-file --asl-deps -o $(OUTPUT_DIR)(+)${s_dir}(+)${s_base}.i -i $(INC_LIST) ${src}
"$(ASLPP)" $(DEPS_FLAGS) $(ASLPP_FLAGS) $(INC) -I${s_path} $(OUTPUT_DIR)(+)${s_dir}(+)${s_base}.i > $(OUTPUT_DIR)(+)${s_dir}(+)${s_base}.iii
Trim --source-code -l -o $(OUTPUT_DIR)(+)${s_dir}(+)${s_base}.iiii $(OUTPUT_DIR)(+)${s_dir}(+)${s_base}.iii
Trim --source-code -l -o $(OUTPUT_DIR)(+)${s_dir}(+)${s_base}.iiii $(OUTPUT_DIR)(+)${s_dir}(+)${s_base}.iii
"$(ASL)" $(ASL_FLAGS) $(ASL_OUTFLAGS)${dst} $(OUTPUT_DIR)(+)${s_dir}(+)${s_base}.iiii
$(CP) $(OUTPUT_DIR)(+)${s_dir}(+)${s_base}.aml $(OUTPUT_DIR)(+)${s_dir}(+)${s_base}.amli
@ -439,12 +447,12 @@
<Command.MSFT, Command.INTEL>
"$(ASLCC)" $(DEPS_FLAGS) /Fo$(OUTPUT_DIR)(+)${s_dir}(+)${s_base}.obj $(ASLCC_FLAGS) $(DEPS_FLAGS) $(INC) ${src}
"$(ASLDLINK)" /OUT:$(OUTPUT_DIR)(+)${s_dir}(+)${s_base}.dll $(ASLDLINK_FLAGS) $(OUTPUT_DIR)(+)${s_dir}(+)${s_base}.obj
"$(GENFW)" -o ${dst} -c $(OUTPUT_DIR)(+)${s_dir}(+)${s_base}.dll $(GENFW_FLAGS)
ImageTool $(ARCH) GetAcpi $(OUTPUT_DIR)(+)${s_dir}(+)${s_base}.dll ${dst}
<Command.GCC>
"$(ASLCC)" $(DEPS_FLAGS) -c -o $(OUTPUT_DIR)(+)${s_dir}(+)${s_base}.obj $(CC_FLAGS) $(ASLCC_FLAGS) $(DEPS_FLAGS) $(INC) ${src}
"$(ASLDLINK)" -o $(OUTPUT_DIR)(+)${s_dir}(+)${s_base}.dll $(ASLDLINK_FLAGS) $(OUTPUT_DIR)(+)${s_dir}(+)${s_base}.obj
"$(GENFW)" -o ${dst} -c $(OUTPUT_DIR)(+)${s_dir}(+)${s_base}.dll $(GENFW_FLAGS)
ImageTool $(ARCH) GetAcpi $(OUTPUT_DIR)(+)${s_dir}(+)${s_base}.dll ${dst}
[Acpi-Table-Code-File]
<InputFile>
@ -459,25 +467,24 @@
<Command.MSFT, Command.INTEL>
"$(ASLCC)" $(DEPS_FLAGS) /Fo$(OUTPUT_DIR)(+)${s_dir}(+)${s_base}.obj $(ASLCC_FLAGS) $(DEPS_FLAGS) $(INC) ${src}
"$(ASLDLINK)" /OUT:$(OUTPUT_DIR)(+)${s_dir}(+)${s_base}.dll $(ASLDLINK_FLAGS) $(OUTPUT_DIR)(+)${s_dir}(+)${s_base}.obj
"$(GENFW)" -o ${dst} -c $(OUTPUT_DIR)(+)${s_dir}(+)${s_base}.dll $(GENFW_FLAGS)
ImageTool $(ARCH) GetAcpi $(OUTPUT_DIR)(+)${s_dir}(+)${s_base}.dll ${dst}
<Command.GCC>
"$(ASLCC)" $(DEPS_FLAGS) -c -o $(OUTPUT_DIR)(+)${s_dir}(+)${s_base}.obj $(CC_FLAGS) $(ASLCC_FLAGS) $(DEPS_FLAGS) $(INC) ${src}
"$(ASLDLINK)" -o $(OUTPUT_DIR)(+)${s_dir}(+)${s_base}.dll $(ASLDLINK_FLAGS) $(OUTPUT_DIR)(+)${s_dir}(+)${s_base}.obj
"$(GENFW)" -o ${dst} -c $(OUTPUT_DIR)(+)${s_dir}(+)${s_base}.dll $(GENFW_FLAGS)
"$(ASLDLINK)" -o $(OUTPUT_DIR)(+)${s_dir}(+)${s_base}.dll $(ASLDLINK_FLAGS) $(OUTPUT_DIR)(+)${s_dir}(+)${s_base}.obj $(CC_FLAGS) $(ASLCC_FLAGS)
ImageTool $(ARCH) GetAcpi $(OUTPUT_DIR)(+)${s_dir}(+)${s_base}.dll ${dst}
<Command.CLANGPDB>
"$(ASLCC)" $(DEPS_FLAGS) -c -o $(OUTPUT_DIR)(+)${s_dir}(+)${s_base}.obj $(CC_FLAGS) $(ASLCC_FLAGS) $(DEPS_FLAGS) $(INC) ${src}
"$(ASLDLINK)" /OUT:$(OUTPUT_DIR)(+)${s_dir}(+)${s_base}.dll $(ASLDLINK_FLAGS) $(OUTPUT_DIR)(+)${s_dir}(+)${s_base}.obj
"$(GENFW)" -o ${dst} -c $(OUTPUT_DIR)(+)${s_dir}(+)${s_base}.dll $(GENFW_FLAGS)
ImageTool $(ARCH) GetAcpi $(OUTPUT_DIR)(+)${s_dir}(+)${s_base}.dll ${dst}
<Command.XCODE>
<Command.XCODE>
"$(ASLCC)" $(DEPS_FLAGS) -o $(OUTPUT_DIR)(+)${s_dir}(+)${s_base}.obj $(ASLCC_FLAGS) $(DEPS_FLAGS) $(INC) ${src}
"$(ASLDLINK)" -o $(OUTPUT_DIR)(+)${s_dir}(+)${s_base}.dll $(ASLDLINK_FLAGS) $(OUTPUT_DIR)(+)${s_dir}(+)${s_base}.obj
"$(MTOC)" -subsystem $(MODULE_TYPE) $(MTOC_FLAGS) $(OUTPUT_DIR)(+)${s_dir}(+)${s_base}.dll $(OUTPUT_DIR)(+)${s_dir}(+)${s_base}.pecoff
"$(GENFW)" -o ${dst} -c $(OUTPUT_DIR)(+)${s_dir}(+)${s_base}.pecoff $(GENFW_FLAGS)
ImageTool $(ARCH) GetAcpi $(OUTPUT_DIR)(+)${s_dir}(+)${s_base}.pecoff ${dst}
[Masm16-Code-File]
<InputFile>
?.asm16, ?.Asm16, ?.ASM16, ?.s16, ?.S16
@ -502,7 +509,7 @@
Trim --source-code -o ${d_path}(+)${s_base}.iii ${d_path}(+)${s_base}.ii
"$(ASM)" -o $(OUTPUT_DIR)(+)${s_dir}(+)${s_base}.obj $(ASM_FLAGS) $(INC) ${d_path}(+)${s_base}.iii
"$(DLINK)" -o ${dst} $(DLINK_FLAGS) --start-group $(DLINK_SPATH) $(LIBS) $(OUTPUT_DIR)(+)${s_dir}(+)${s_base}.obj --end-group
<Command.XCODE>
Trim --asm-file -o ${d_path}(+)${s_base}.i -i $(INC_LIST) ${src}
"$(PP)" $(DEPS_FLAGS) $(PP_FLAGS) $(INC) ${src} > ${d_path}(+)${s_base}.ii
@ -510,7 +517,7 @@
"$(ASM)" -o $(OUTPUT_DIR)(+)${s_dir}(+)${s_base}.obj $(ASM_FLAGS) $(INC) ${d_path}(+)${s_base}.iii
"$(SLINK)" $(SLINK_FLAGS) $(OUTPUT_DIR)(+)${s_dir}(+)${s_base}.slib $(OUTPUT_DIR)(+)${s_dir}(+)${s_base}.obj
otool -t $(OUTPUT_DIR)(+)${s_dir}(+)${s_base}.slib | hex2bin.py ${dst}
[Nasm-to-Binary-Code-File]
<InputFile>
@ -538,7 +545,7 @@
$(OUTPUT_DIR)(+)${s_base}.mcb
<Command>
"$(GENFW)" -o ${dst} -m ${src} $(GENFW_FLAGS)
MicroTool TxtToBin ${src} ${dst}
[Microcode-Binary-File]
<InputFile>
@ -551,7 +558,7 @@
$(OUTPUT_DIR)(+)$(MODULE_NAME).bin
<Command>
"$(GENFW)" -o ${dst} -j $(MICROCODE_BINARY_FILES) $(GENFW_FLAGS)
MicroTool Merge ${dst} $(MICROCODE_BINARY_FILES)
-$(CP) ${dst} $(BIN_DIR)(+)$(MODULE_NAME_GUID).bin
[EFI-Image-File]
@ -641,12 +648,12 @@
$(OUTPUT_DIR)(+)$(MODULE_NAME)hii.rc
<Command.MSFT, Command.INTEL, Command.CLANGPDB>
"$(GENFW)" -o $(OUTPUT_DIR)(+)$(MODULE_NAME)hii.rc -g $(MODULE_GUID) --hiipackage $(HII_BINARY_PACKAGES) $(GENFW_FLAGS)
ImageTool $(ARCH) HiiBinPe $(OUTPUT_DIR)(+)$(MODULE_NAME)hii.rc $(MODULE_GUID) $(HII_BINARY_PACKAGES)
"$(RC)" /Fo${dst} $(OUTPUT_DIR)(+)$(MODULE_NAME)hii.rc
<Command.GCC, Command.CLANGGCC>
"$(GENFW)" -o $(OUTPUT_DIR)(+)$(MODULE_NAME)hii.rc -g $(MODULE_GUID) --hiibinpackage $(HII_BINARY_PACKAGES) $(GENFW_FLAGS)
ImageTool $(ARCH) HiiBinElf $(OUTPUT_DIR)(+)$(MODULE_NAME)hii.rc $(MODULE_GUID) $(HII_BINARY_PACKAGES)
"$(RC)" $(RC_FLAGS) $(OUTPUT_DIR)(+)$(MODULE_NAME)hii.rc ${dst}
<Command.XCODE>
"$(GENFW)" -o $(OUTPUT_DIR)(+)$(MODULE_NAME)hii.rc -g $(MODULE_GUID) --hiibinpackage $(HII_BINARY_PACKAGES) $(GENFW_FLAGS)
ImageTool $(ARCH) HiiBinElf $(OUTPUT_DIR)(+)$(MODULE_NAME)hii.rc $(MODULE_GUID) $(HII_BINARY_PACKAGES)

View File

@ -2907,15 +2907,15 @@ DEFINE CLANGDWARF_X64_DLINK2_FLAGS = -Wl,--defsym=PECOFF_HEADER_SIZE=0x22
*_CLANGDWARF_IA32_ASLPP_FLAGS = DEF(GCC_ASLPP_FLAGS) DEF(CLANG38_IA32_TARGET)
*_CLANGDWARF_IA32_VFRPP_FLAGS = DEF(GCC_VFRPP_FLAGS) DEF(CLANG38_IA32_TARGET)
DEBUG_CLANGDWARF_IA32_CC_FLAGS = DEF(CLANG38_ALL_CC_FLAGS) -m32 -Oz -flto -march=i586 DEF(CLANG38_IA32_TARGET) -g -fno-pic -fno-pie
DEBUG_CLANGDWARF_IA32_CC_FLAGS = DEF(CLANG38_ALL_CC_FLAGS) -m32 -malign-double -Oz -flto -march=i586 DEF(CLANG38_IA32_TARGET) -g -fno-pic -fno-pie
DEBUG_CLANGDWARF_IA32_DLINK_FLAGS = DEF(CLANGDWARF_IA32_X64_DLINK_FLAGS) -flto -Wl,-O3 -Wl,-melf_i386 -Wl,--oformat,elf32-i386
DEBUG_CLANGDWARF_IA32_DLINK2_FLAGS = DEF(CLANGDWARF_IA32_DLINK2_FLAGS) -O3 -fuse-ld=lld
RELEASE_CLANGDWARF_IA32_CC_FLAGS = DEF(CLANG38_ALL_CC_FLAGS) -m32 -Oz -flto -march=i586 DEF(CLANG38_IA32_TARGET) -fno-pic -fno-pie
RELEASE_CLANGDWARF_IA32_CC_FLAGS = DEF(CLANG38_ALL_CC_FLAGS) -m32 -malign-double -Oz -flto -march=i586 DEF(CLANG38_IA32_TARGET) -fno-pic -fno-pie
RELEASE_CLANGDWARF_IA32_DLINK_FLAGS = DEF(CLANGDWARF_IA32_X64_DLINK_FLAGS) -flto -Wl,-O3 -Wl,-melf_i386 -Wl,--oformat,elf32-i386
RELEASE_CLANGDWARF_IA32_DLINK2_FLAGS = DEF(CLANGDWARF_IA32_DLINK2_FLAGS) -O3 -fuse-ld=lld
NOOPT_CLANGDWARF_IA32_CC_FLAGS = DEF(CLANG38_ALL_CC_FLAGS) -m32 -O0 -march=i586 DEF(CLANG38_IA32_TARGET) -g -fno-pic -fno-pie
NOOPT_CLANGDWARF_IA32_CC_FLAGS = DEF(CLANG38_ALL_CC_FLAGS) -m32 -malign-double -O0 -march=i586 DEF(CLANG38_IA32_TARGET) -g -fno-pic -fno-pie
NOOPT_CLANGDWARF_IA32_DLINK_FLAGS = DEF(CLANGDWARF_IA32_X64_DLINK_FLAGS) -Wl,-O0 -Wl,-melf_i386 -Wl,--oformat,elf32-i386
NOOPT_CLANGDWARF_IA32_DLINK2_FLAGS = DEF(CLANGDWARF_IA32_DLINK2_FLAGS) -O0 -fuse-ld=lld

View File

@ -10,7 +10,7 @@ all: subdirs
LANGUAGES = C Python
SOURCE_SUBDIRS := $(patsubst %,Source/%,$(sort $(LANGUAGES)))
SUBDIRS := $(SOURCE_SUBDIRS) Tests
SUBDIRS := $(SOURCE_SUBDIRS) Tests ImageTool MicroTool
CLEAN_SUBDIRS := $(patsubst %,%-clean,$(sort $(SUBDIRS)))
.PHONY: subdirs $(SUBDIRS)

View File

@ -0,0 +1,301 @@
/** @file
Copyright (c) 2022, Mikhail Krichanov. All rights reserved.
SPDX-License-Identifier: BSD-3-Clause
**/
#include "ImageTool.h"
static
EFI_IMAGE_RESOURCE_DIRECTORY_ENTRY *
CreateEntry (
IN UINT8 *HiiSectionHeader,
IN OUT UINT32 *HiiSectionOffset,
IN BOOLEAN DataIsDirectory
)
{
EFI_IMAGE_RESOURCE_DIRECTORY *RDir;
EFI_IMAGE_RESOURCE_DIRECTORY_ENTRY *Entry;
assert (HiiSectionHeader != NULL);
assert (HiiSectionOffset != NULL);
RDir = (EFI_IMAGE_RESOURCE_DIRECTORY *)(HiiSectionHeader + *HiiSectionOffset);
*HiiSectionOffset += sizeof (EFI_IMAGE_RESOURCE_DIRECTORY);
RDir->NumberOfNamedEntries = 1;
Entry = (EFI_IMAGE_RESOURCE_DIRECTORY_ENTRY *)(HiiSectionHeader + *HiiSectionOffset);
*HiiSectionOffset += sizeof (EFI_IMAGE_RESOURCE_DIRECTORY_ENTRY);
Entry->u1.s.NameIsString = 1;
if (DataIsDirectory) {
Entry->u2.s.DataIsDirectory = 1;
Entry->u2.s.OffsetToDirectory = *HiiSectionOffset;
}
return Entry;
}
static
void
CreateStringEntry (
IN OUT EFI_IMAGE_RESOURCE_DIRECTORY_ENTRY *Entry,
IN UINT8 *HiiSectionHeader,
IN OUT UINT32 *HiiSectionOffset,
IN CHAR16 *String
)
{
EFI_IMAGE_RESOURCE_DIRECTORY_STRING *RDStr;
assert (Entry != NULL);
assert (HiiSectionHeader != NULL);
assert (HiiSectionOffset != NULL);
assert (String != NULL);
Entry->u1.s.NameOffset = *HiiSectionOffset;
RDStr = (EFI_IMAGE_RESOURCE_DIRECTORY_STRING *)(HiiSectionHeader + *HiiSectionOffset);
RDStr->Length = (UINT16)StrLen (String);
memcpy (RDStr->String, String, RDStr->Length * sizeof (RDStr->String[0]));
*HiiSectionOffset += sizeof (*RDStr) + RDStr->Length * sizeof (RDStr->String[0]);
}
static
UINT8 *
CreateHiiResouceSectionHeader (
OUT UINT32 *HiiHeaderSize,
IN UINT32 HiiDataSize
)
{
UINT32 HiiSectionHeaderSize;
UINT32 HiiSectionOffset;
UINT8 *HiiSectionHeader;
EFI_IMAGE_RESOURCE_DIRECTORY_ENTRY *TypeRDirEntry;
EFI_IMAGE_RESOURCE_DIRECTORY_ENTRY *NameRDirEntry;
EFI_IMAGE_RESOURCE_DIRECTORY_ENTRY *LangRDirEntry;
EFI_IMAGE_RESOURCE_DATA_ENTRY *ResourceDataEntry;
assert (HiiHeaderSize != NULL);
//
// Calculate the total size for the resource header (include Type, Name and Language)
// then allocate memory for whole Hii file.
//
HiiSectionHeaderSize = 3 * (sizeof (EFI_IMAGE_RESOURCE_DIRECTORY) + sizeof (EFI_IMAGE_RESOURCE_DIRECTORY_ENTRY)
+ sizeof (EFI_IMAGE_RESOURCE_DIRECTORY_STRING) + 3 * sizeof (CHAR16)) + sizeof (EFI_IMAGE_RESOURCE_DATA_ENTRY);
HiiSectionHeader = calloc (1, HiiSectionHeaderSize + HiiDataSize);
if (HiiSectionHeader == NULL) {
fprintf (stderr, "ImageTool: Could not allocate memory for Hii\n");
return NULL;
}
HiiSectionOffset = 0;
//
// Create Type, Name, Language entries
//
TypeRDirEntry = CreateEntry (HiiSectionHeader, &HiiSectionOffset, TRUE);
NameRDirEntry = CreateEntry (HiiSectionHeader, &HiiSectionOffset, TRUE);
LangRDirEntry = CreateEntry (HiiSectionHeader, &HiiSectionOffset, FALSE);
//
// Create string entry for Type, Name, Language
//
CreateStringEntry (TypeRDirEntry, HiiSectionHeader, &HiiSectionOffset, L"HII");
CreateStringEntry (NameRDirEntry, HiiSectionHeader, &HiiSectionOffset, L"EFI");
CreateStringEntry (LangRDirEntry, HiiSectionHeader, &HiiSectionOffset, L"BIN");
//
// Create Leaf data
//
LangRDirEntry->u2.OffsetToData = HiiSectionOffset;
ResourceDataEntry = (EFI_IMAGE_RESOURCE_DATA_ENTRY *)(HiiSectionHeader + HiiSectionOffset);
HiiSectionOffset += sizeof (EFI_IMAGE_RESOURCE_DATA_ENTRY);
ResourceDataEntry->OffsetToData = HiiSectionOffset;
ResourceDataEntry->Size = HiiDataSize;
*HiiHeaderSize = HiiSectionHeaderSize;
return HiiSectionHeader;
}
RETURN_STATUS
ConstructHii (
IN const char *FileNames[],
IN UINT32 NumOfFiles,
IN GUID *HiiGuid,
OUT void **Hii,
OUT UINT32 *HiiSize,
IN BOOLEAN IsElf
)
{
UINT8 *HiiPackageDataPointer;
EFI_HII_PACKAGE_LIST_HEADER HiiPackageListHeader;
EFI_HII_PACKAGE_HEADER *HiiPackageHeader;
EFI_IFR_FORM_SET *IfrFormSet;
EFI_HII_PACKAGE_HEADER EndPackage;
UINT32 HiiSectionHeaderSize;
UINT8 *HiiSectionHeader;
const char *HiiPackageRCFileHeader;
UINT32 Index;
UINT32 Total;
UINT8 *Buffer;
UINT8 *BufferStart;
UINT32 Step;
void *File;
UINT32 FileSize;
UINT8 NumberOfFormPackages;
UINT32 TempSize;
assert (Hii != NULL);
assert (HiiGuid != NULL);
assert (FileNames != NULL);
NumberOfFormPackages = 0;
EndPackage.Length = sizeof (EFI_HII_PACKAGE_HEADER);
EndPackage.Type = EFI_HII_PACKAGE_END;
HiiPackageListHeader.PackageLength = sizeof (EFI_HII_PACKAGE_LIST_HEADER) + sizeof (EndPackage);
for (Index = 0; Index < NumOfFiles; ++Index) {
File = UserReadFile (FileNames[Index], &FileSize);
if (File == NULL) {
fprintf (stderr, "ImageTool: Could not open %s: %s\n", FileNames[Index], strerror (errno));
return RETURN_ABORTED;
}
HiiPackageHeader = (EFI_HII_PACKAGE_HEADER *)File;
if (HiiPackageHeader->Type == EFI_HII_PACKAGE_FORMS) {
if (HiiPackageHeader->Length != FileSize) {
fprintf (stderr, "ImageTool: Wrong package size in HII package file %s\n", FileNames[Index]);
free (File);
return RETURN_ABORTED;
}
if (IsZeroGuid (HiiGuid)) {
IfrFormSet = (EFI_IFR_FORM_SET *)(HiiPackageHeader + 1);
CopyGuid (HiiGuid, &IfrFormSet->Guid);
}
++NumberOfFormPackages;
}
HiiPackageListHeader.PackageLength += FileSize;
free (File);
}
if (NumberOfFormPackages > 1) {
fprintf (stderr, "ImageTool: The input HII packages contain more than one HII Form package\n");
return RETURN_INVALID_PARAMETER;
}
if (IsZeroGuid (HiiGuid)) {
fprintf (stderr, "ImageTool: HII package list guid is not specified\n");
return RETURN_ABORTED;
}
CopyGuid (&HiiPackageListHeader.PackageListGuid, HiiGuid);
if (IsElf) {
HiiSectionHeader = CreateHiiResouceSectionHeader (&HiiSectionHeaderSize, HiiPackageListHeader.PackageLength);
if (HiiSectionHeader == NULL) {
return RETURN_OUT_OF_RESOURCES;
}
HiiPackageDataPointer = HiiSectionHeader + HiiSectionHeaderSize;
memcpy (HiiPackageDataPointer, &HiiPackageListHeader, sizeof (HiiPackageListHeader));
HiiPackageDataPointer += sizeof (HiiPackageListHeader);
for (Index = 0; Index < NumOfFiles; ++Index) {
File = UserReadFile (FileNames[Index], &FileSize);
if (File == NULL) {
fprintf (stderr, "ImageTool: Could not open %s: %s\n", FileNames[Index], strerror (errno));
free (HiiSectionHeader);
return RETURN_ABORTED;
}
memcpy (HiiPackageDataPointer, File, FileSize);
HiiPackageDataPointer += FileSize;
free (File);
}
memcpy (HiiPackageDataPointer, &EndPackage, sizeof (EndPackage));
*Hii = HiiSectionHeader;
*HiiSize = HiiSectionHeaderSize + HiiPackageListHeader.PackageLength;
return RETURN_SUCCESS;
}
HiiPackageRCFileHeader = "//\n// DO NOT EDIT -- auto-generated file\n//\n\n1 HII\n{";
HiiSectionHeaderSize = (UINT32)AsciiStrLen (HiiPackageRCFileHeader);
TempSize = HiiSectionHeaderSize + 5 * HiiPackageListHeader.PackageLength;
HiiSectionHeader = calloc (1, TempSize);
if (HiiSectionHeader == NULL) {
fprintf (stderr, "ImageTool: Could not allocate memory for HiiRC\n");
return RETURN_OUT_OF_RESOURCES;
}
Buffer = calloc (1, HiiPackageListHeader.PackageLength);
if (Buffer == NULL) {
fprintf (stderr, "ImageTool: Could not allocate memory for Buffer\n");
free (HiiSectionHeader);
return RETURN_OUT_OF_RESOURCES;
}
BufferStart = Buffer;
memcpy (Buffer, &HiiPackageListHeader, sizeof (HiiPackageListHeader));
Buffer += sizeof (HiiPackageListHeader);
for (Index = 0; Index < NumOfFiles; ++Index) {
File = UserReadFile (FileNames[Index], &FileSize);
if (File == NULL) {
fprintf (stderr, "ImageTool: Could not open %s: %s\n", FileNames[Index], strerror (errno));
free (HiiSectionHeader);
free (BufferStart);
return RETURN_ABORTED;
}
memcpy (Buffer, File, FileSize);
Buffer += FileSize;
free (File);
}
memcpy (Buffer, &EndPackage, sizeof (EndPackage));
memcpy (HiiSectionHeader, HiiPackageRCFileHeader, HiiSectionHeaderSize);
HiiPackageDataPointer = HiiSectionHeader + HiiSectionHeaderSize;
Total = HiiSectionHeaderSize;
Buffer = BufferStart;
for (Index = 0; Index + 2 < HiiPackageListHeader.PackageLength; Index += 2) {
if (Index % 16 == 0) {
Step = snprintf ((char *)HiiPackageDataPointer, TempSize - Total, "\n ");
HiiPackageDataPointer += Step;
Total += Step;
}
Step = snprintf ((char *)HiiPackageDataPointer, TempSize - Total, " 0x%04X,", *(UINT16 *)Buffer);
HiiPackageDataPointer += Step;
Total += Step;
Buffer += 2;
}
if (Index % 16 == 0) {
Step = snprintf ((char *)HiiPackageDataPointer, TempSize - Total, "\n ");
HiiPackageDataPointer += Step;
Total += Step;
}
if ((Index + 2) == HiiPackageListHeader.PackageLength) {
Total += snprintf ((char *)HiiPackageDataPointer, TempSize - Total, " 0x%04X\n}\n", *(UINT16 *)Buffer);
} else if ((Index + 1) == HiiPackageListHeader.PackageLength) {
Total += snprintf ((char *)HiiPackageDataPointer, TempSize - Total, " 0x%04X\n}\n", *(UINT8 *)Buffer);
}
*Hii = HiiSectionHeader;
*HiiSize = Total;
free (BufferStart);
return RETURN_SUCCESS;
}

View File

@ -0,0 +1,962 @@
/** @file
Copyright (c) 2022, Mikhail Krichanov. All rights reserved.
SPDX-License-Identifier: BSD-3-Clause
**/
#include "ImageTool.h"
static Elf_Ehdr *mEhdr = NULL;
static Elf_Size mPeAlignment = DEFAULT_PE_ALIGNMENT;
static UINT64 mSizeOfHeaders = 0x0;
#if defined(EFI_TARGET64)
static UINT8 *mGotData = NULL;
static UINT32 mWGotOffset = 0x0;
static const Elf_Shdr *mGOTShdr = NULL;
static UINT32 *mGOTPeEntries = NULL;
static UINT32 mGOTMaxEntries = 0;
static UINT32 mGOTNumEntries = 0;
#endif
#if defined (_MSC_EXTENSIONS)
#define EFI_IMAGE_MACHINE_IA32 0x014C
#define EFI_IMAGE_MACHINE_X64 0x8664
#define EFI_IMAGE_MACHINE_ARMTHUMB_MIXED 0x01C2
#define EFI_IMAGE_MACHINE_AARCH64 0xAA64
#endif
extern image_tool_image_info_t mImageInfo;
static
Elf_Shdr *
GetShdrByIndex (
IN UINT32 Index
)
{
UINTN Offset;
assert (Index < mEhdr->e_shnum);
Offset = (UINTN)mEhdr->e_shoff + Index * mEhdr->e_shentsize;
return (Elf_Shdr *)((UINT8 *)mEhdr + Offset);
}
static
Elf_Sym *
GetSymbol (
IN UINT32 TableIndex,
IN UINT32 SymbolIndex
)
{
const Elf_Shdr *TableShdr;
UINT8 *Symtab;
TableShdr = GetShdrByIndex (TableIndex);
Symtab = (UINT8 *)mEhdr + TableShdr->sh_offset;
return (Elf_Sym *)(Symtab + SymbolIndex * TableShdr->sh_entsize);
}
static
char *
GetString (
IN UINT32 Offset
)
{
const Elf_Shdr *Shdr;
char *String;
Shdr = GetShdrByIndex (mEhdr->e_shstrndx);
if (Offset >= Shdr->sh_size) {
fprintf (stderr, "ImageTool: Invalid ELF string offset\n");
return NULL;
}
String = (char *)((UINT8 *)mEhdr + Shdr->sh_offset + Offset);
return String;
}
static
BOOLEAN
IsTextShdr (
IN const Elf_Shdr *Shdr
)
{
assert (Shdr != NULL);
return ((((Shdr->sh_flags & (SHF_EXECINSTR | SHF_ALLOC)) == (SHF_EXECINSTR | SHF_ALLOC)) ||
((Shdr->sh_flags & (SHF_WRITE | SHF_ALLOC)) == SHF_ALLOC))
&& (Shdr->sh_type == SHT_PROGBITS));
}
static
BOOLEAN
IsHiiRsrcShdr (
IN const Elf_Shdr *Shdr
)
{
assert (Shdr != NULL);
Elf_Shdr *Namedr = GetShdrByIndex (mEhdr->e_shstrndx);
return (BOOLEAN) (strcmp ((CHAR8*)mEhdr + Namedr->sh_offset + Shdr->sh_name, ELF_HII_SECTION_NAME) == 0);
}
static
BOOLEAN
IsDataShdr (
IN const Elf_Shdr *Shdr
)
{
assert (Shdr != NULL);
if (IsHiiRsrcShdr (Shdr)) {
return FALSE;
}
return (((Shdr->sh_flags & (SHF_EXECINSTR | SHF_WRITE | SHF_ALLOC)) == (SHF_ALLOC | SHF_WRITE))
&& ((Shdr->sh_type == SHT_PROGBITS) || (Shdr->sh_type == SHT_NOBITS)));
}
static
BOOLEAN
IsRelocShdr (
IN const Elf_Shdr *Shdr
)
{
const Elf_Shdr *SecShdr;
const Elf_Rel *Rel;
UINTN Index;
assert (Shdr != NULL);
if ((Shdr->sh_type != SHT_REL) && (Shdr->sh_type != SHT_RELA)) {
return FALSE;
}
SecShdr = GetShdrByIndex (Shdr->sh_info);
if ((!IsTextShdr (SecShdr)) && (!IsDataShdr (SecShdr))) {
return FALSE;
}
for (Index = 0; Index < Shdr->sh_size; Index += (UINTN)Shdr->sh_entsize) {
Rel = (Elf_Rel *)((UINT8 *)mEhdr + Shdr->sh_offset + Index);
#if defined(EFI_TARGET64)
if ((ELF_R_TYPE(Rel->r_info) == R_X86_64_64)
|| (ELF_R_TYPE(Rel->r_info) == R_X86_64_32)) {
return TRUE;
}
#elif defined(EFI_TARGET32)
if (ELF_R_TYPE(Rel->r_info) == R_386_32) {
return TRUE;
}
#endif
}
return FALSE;
}
VOID
SetHiiResourceHeader (
IN OUT UINT8 *Hii,
IN UINT32 Offset
)
{
UINT32 Index;
EFI_IMAGE_RESOURCE_DIRECTORY *RDir;
EFI_IMAGE_RESOURCE_DIRECTORY_ENTRY *RDirEntry;
EFI_IMAGE_RESOURCE_DIRECTORY_STRING *RDirString;
EFI_IMAGE_RESOURCE_DATA_ENTRY *RDataEntry;
assert (Hii != NULL);
//
// Fill Resource section entry
//
RDir = (EFI_IMAGE_RESOURCE_DIRECTORY *)Hii;
RDirEntry = (EFI_IMAGE_RESOURCE_DIRECTORY_ENTRY *)(RDir + 1);
for (Index = 0; Index < RDir->NumberOfNamedEntries; ++Index) {
if (RDirEntry->u1.s.NameIsString) {
RDirString = (EFI_IMAGE_RESOURCE_DIRECTORY_STRING *)(Hii + RDirEntry->u1.s.NameOffset);
if ((RDirString->Length == 3)
&& (RDirString->String[0] == L'H')
&& (RDirString->String[1] == L'I')
&& (RDirString->String[2] == L'I')) {
//
// Resource Type "HII" found
//
if (RDirEntry->u2.s.DataIsDirectory) {
//
// Move to next level - resource Name
//
RDir = (EFI_IMAGE_RESOURCE_DIRECTORY *)(Hii + RDirEntry->u2.s.OffsetToDirectory);
RDirEntry = (EFI_IMAGE_RESOURCE_DIRECTORY_ENTRY *)(RDir + 1);
if (RDirEntry->u2.s.DataIsDirectory) {
//
// Move to next level - resource Language
//
RDir = (EFI_IMAGE_RESOURCE_DIRECTORY *)(Hii + RDirEntry->u2.s.OffsetToDirectory);
RDirEntry = (EFI_IMAGE_RESOURCE_DIRECTORY_ENTRY *)(RDir + 1);
}
}
//
// Now it ought to be resource Data. Update its OffsetToData value
//
if (!RDirEntry->u2.s.DataIsDirectory) {
RDataEntry = (EFI_IMAGE_RESOURCE_DATA_ENTRY *)(Hii + RDirEntry->u2.OffsetToData);
RDataEntry->OffsetToData = RDataEntry->OffsetToData + Offset;
break;
}
}
}
RDirEntry++;
}
return;
}
static
VOID
FindAddress (
IN UINT32 ElfIndex,
OUT UINT8 **SectionData,
OUT UINT32 *WOffset
)
{
UINT32 Index;
assert (SectionData != NULL);
assert (WOffset != NULL);
*WOffset = (UINT32)mSizeOfHeaders;
for (Index = 0; Index < mImageInfo.SegmentInfo.NumSegments; ++Index) {
if (mImageInfo.SegmentInfo.Segments[Index].ImageSize == ElfIndex) {
*SectionData = mImageInfo.SegmentInfo.Segments[Index].Data;
break;
}
*WOffset += mImageInfo.SegmentInfo.Segments[Index].DataSize;
}
return;
}
#if defined(EFI_TARGET64)
static
RETURN_STATUS
FindElfGOTSectionFromGOTEntryElfRva (
IN Elf_Addr GOTEntryElfRva
)
{
UINT32 Index;
const Elf_Shdr *Shdr;
if (mGOTShdr != NULL) {
if ((GOTEntryElfRva >= mGOTShdr->sh_addr)
&& (GOTEntryElfRva < (mGOTShdr->sh_addr + mGOTShdr->sh_size))) {
return RETURN_SUCCESS;
}
fprintf (stderr, "ImageTool: GOT entries found in multiple sections\n");
return RETURN_UNSUPPORTED;
}
for (Index = 0; Index < mEhdr->e_shnum; ++Index) {
Shdr = GetShdrByIndex(Index);
if ((GOTEntryElfRva >= Shdr->sh_addr)
&& (GOTEntryElfRva < (Shdr->sh_addr + Shdr->sh_size))) {
mGOTShdr = Shdr;
FindAddress (Index, &mGotData, &mWGotOffset);
return RETURN_SUCCESS;
}
}
fprintf (stderr, "ImageTool: ElfRva 0x%016llx for GOT entry not found in any section\n", GOTEntryElfRva);
return RETURN_VOLUME_CORRUPTED;
}
static
RETURN_STATUS
AccumulatePeGOTEntries (
IN UINT32 GOTPeEntry,
OUT BOOLEAN *IsNew
)
{
UINT32 Index;
assert (IsNew != NULL);
if (mGOTPeEntries != NULL) {
for (Index = 0; Index < mGOTNumEntries; ++Index) {
if (mGOTPeEntries[Index] == GOTPeEntry) {
*IsNew = FALSE;
return RETURN_SUCCESS;
}
}
}
if (mGOTPeEntries == NULL) {
mGOTMaxEntries = 5;
mGOTNumEntries = 0;
mGOTPeEntries = calloc (1, mGOTMaxEntries * sizeof (*mGOTPeEntries));
if (mGOTPeEntries == NULL) {
fprintf (stderr, "ImageTool: Could not allocate memory for mGOTPeEntries\n");
return RETURN_OUT_OF_RESOURCES;
}
} else if (mGOTNumEntries == mGOTMaxEntries) {
mGOTMaxEntries *= 2;
mGOTPeEntries = realloc (mGOTPeEntries, mGOTMaxEntries * sizeof (*mGOTPeEntries));
if (mGOTPeEntries == NULL) {
fprintf (stderr, "ImageTool: Could not reallocate memory for mGOTPeEntries\n");
return RETURN_OUT_OF_RESOURCES;
}
}
mGOTPeEntries[mGOTNumEntries] = mWGotOffset + GOTPeEntry;
++mGOTNumEntries;
*IsNew = TRUE;
return RETURN_SUCCESS;
}
#endif
static
RETURN_STATUS
ReadElfFile (
IN const char *Name
)
{
static const unsigned char Ident[] = {
ELFMAG0, ELFMAG1, ELFMAG2, ELFMAG3, ELFCLASS, ELFDATA2LSB
};
const Elf_Shdr *Shdr;
UINTN Offset;
UINT32 Index;
UINT32 FileSize;
char *Last;
assert (Name != NULL);
mEhdr = (Elf_Ehdr *)UserReadFile (Name, &FileSize);
if (mEhdr == NULL) {
fprintf (stderr, "ImageTool: Could not open %s: %s\n", Name, strerror (errno));
return RETURN_VOLUME_CORRUPTED;
}
//
// Check header
//
if ((FileSize < sizeof (*mEhdr))
|| (memcmp (Ident, mEhdr->e_ident, sizeof (Ident)) != 0)) {
fprintf (stderr, "ImageTool: Invalid ELF header in file %s\n", Name);
fprintf (stderr, "ImageTool: mEhdr->e_ident[0] = 0x%x expected 0x%x\n", mEhdr->e_ident[0], Ident[0]);
fprintf (stderr, "ImageTool: mEhdr->e_ident[1] = 0x%x expected 0x%x\n", mEhdr->e_ident[1], Ident[1]);
fprintf (stderr, "ImageTool: mEhdr->e_ident[2] = 0x%x expected 0x%x\n", mEhdr->e_ident[2], Ident[2]);
fprintf (stderr, "ImageTool: mEhdr->e_ident[3] = 0x%x expected 0x%x\n", mEhdr->e_ident[3], Ident[3]);
fprintf (stderr, "ImageTool: mEhdr->e_ident[4] = 0x%x expected 0x%x\n", mEhdr->e_ident[4], Ident[4]);
fprintf (stderr, "ImageTool: mEhdr->e_ident[5] = 0x%x expected 0x%x\n", mEhdr->e_ident[5], Ident[5]);
fprintf (stderr, "ImageTool: FileSize = 0x%x sizeof(*mEhdr) = 0x%lx\n", FileSize, sizeof (*mEhdr));
return RETURN_VOLUME_CORRUPTED;
}
if ((mEhdr->e_type != ET_EXEC) && (mEhdr->e_type != ET_DYN)) {
fprintf (stderr, "ImageTool: ELF e_type not ET_EXEC or ET_DYN\n");
return RETURN_UNSUPPORTED;
}
#if defined(EFI_TARGET64)
if (mEhdr->e_machine != EM_X86_64) {
fprintf (stderr, "ImageTool: Unsupported ELF e_machine\n");
return RETURN_UNSUPPORTED;
}
#elif defined(EFI_TARGET32)
if (mEhdr->e_machine != EM_386) {
fprintf (stderr, "ImageTool: Unsupported ELF e_machine\n");
return RETURN_UNSUPPORTED;
}
#endif
//
// Check section headers
//
for (Index = 0; Index < mEhdr->e_shnum; ++Index) {
Offset = (UINTN)mEhdr->e_shoff + Index * mEhdr->e_shentsize;
if (FileSize < (Offset + sizeof (*Shdr))) {
fprintf (stderr, "ImageTool: ELF section header is outside file %s\n", Name);
return RETURN_VOLUME_CORRUPTED;
}
Shdr = (Elf_Shdr *)((UINT8 *)mEhdr + Offset);
if ((Shdr->sh_type != SHT_NOBITS)
&& ((FileSize < Shdr->sh_offset) || ((FileSize - Shdr->sh_offset) < Shdr->sh_size))) {
fprintf (stderr, "ImageTool: ELF section %d points outside file %s\n", Index, Name);
return RETURN_VOLUME_CORRUPTED;
}
if (Shdr->sh_link >= mEhdr->e_shnum) {
fprintf (stderr, "ImageTool: ELF %d-th section's sh_link is out of range\n", Index);
return RETURN_VOLUME_CORRUPTED;
}
if (((Shdr->sh_type == SHT_RELA) || (Shdr->sh_type == SHT_REL))
&& (Shdr->sh_info >= mEhdr->e_shnum)) {
fprintf (stderr, "ImageTool: ELF %d-th section's sh_info is out of range\n", Index);
return RETURN_VOLUME_CORRUPTED;
}
if (Shdr->sh_addralign <= mPeAlignment) {
continue;
}
if ((IsTextShdr (Shdr)) || (IsDataShdr (Shdr)) || (IsHiiRsrcShdr (Shdr))) {
mPeAlignment = Shdr->sh_addralign;
}
}
if (mEhdr->e_shstrndx >= mEhdr->e_shnum) {
fprintf (stderr, "ImageTool: Invalid section name string table\n");
return RETURN_VOLUME_CORRUPTED;
}
Shdr = GetShdrByIndex (mEhdr->e_shstrndx);
if (Shdr->sh_type != SHT_STRTAB) {
fprintf (stderr, "ImageTool: ELF string table section has wrong type\n");
return RETURN_VOLUME_CORRUPTED;
}
Last = (char *)((UINT8 *)mEhdr + Shdr->sh_offset + Shdr->sh_size - 1);
if (*Last != '\0') {
fprintf (stderr, "ImageTool: ELF string table section is not NUL-terminated\n");
return RETURN_VOLUME_CORRUPTED;
}
if ((!IS_POW2(mPeAlignment)) || (mPeAlignment > MAX_PE_ALIGNMENT)) {
fprintf (stderr, "ImageTool: Invalid section alignment\n");
return RETURN_VOLUME_CORRUPTED;
}
return RETURN_SUCCESS;
}
static
RETURN_STATUS
FixSegmentsSetRelocs (
VOID
)
{
UINT32 Index;
const Elf_Shdr *RelShdr;
const Elf_Shdr *SecShdr;
UINT8 *SecData;
UINT32 WSecOffset;
UINTN RelIdx;
const Elf_Rela *Rel;
const Elf_Sym *Sym;
const Elf_Shdr *SymShdr;
UINT8 *SymData;
UINT32 WSymOffset;
UINT8 *Targ;
UINT32 RelNum;
UINTN Offset;
#if defined(EFI_TARGET64)
Elf_Addr GOTEntryRva;
RETURN_STATUS Status;
BOOLEAN IsNew;
#endif
RelNum = 0;
for (Index = 0; Index < mEhdr->e_shnum; Index++) {
RelShdr = GetShdrByIndex (Index);
if ((RelShdr->sh_type != SHT_REL) && (RelShdr->sh_type != SHT_RELA)) {
continue;
}
if (RelShdr->sh_info == 0) {
continue;
}
SecShdr = GetShdrByIndex (RelShdr->sh_info);
FindAddress (RelShdr->sh_info, &SecData, &WSecOffset);
#if defined(EFI_TARGET64)
if ((RelShdr->sh_type != SHT_RELA) || (!((IsTextShdr (SecShdr)) || (IsDataShdr (SecShdr))))) {
continue;
}
#elif defined(EFI_TARGET32)
if ((RelShdr->sh_type != SHT_REL) || (!((IsTextShdr (SecShdr)) || (IsDataShdr (SecShdr))))) {
continue;
}
#endif
//
// Process all relocation entries for this section.
//
for (RelIdx = 0; RelIdx < RelShdr->sh_size; RelIdx += (UINTN)RelShdr->sh_entsize) {
Rel = (Elf_Rela *)((UINT8 *)mEhdr + RelShdr->sh_offset + RelIdx);
Offset = (UINTN)((Elf_Addr)WSecOffset + (Rel->r_offset - SecShdr->sh_addr));
//
// Set pointer to symbol table entry associated with the relocation entry.
//
Sym = GetSymbol (RelShdr->sh_link, ELF_R_SYM(Rel->r_info));
if ((Sym->st_shndx == SHN_UNDEF) || (Sym->st_shndx >= mEhdr->e_shnum)) {
continue;
}
SymShdr = GetShdrByIndex (Sym->st_shndx);
FindAddress (Sym->st_shndx, &SymData, &WSymOffset);
Targ = SecData + (Rel->r_offset - SecShdr->sh_addr);
#if defined(EFI_TARGET64)
switch (ELF_R_TYPE(Rel->r_info)) {
case R_X86_64_NONE:
break;
case R_X86_64_64:
WriteUnaligned64 ((UINT64 *)Targ, ReadUnaligned64((UINT64 *)Targ) - SymShdr->sh_addr + WSymOffset);
mImageInfo.RelocInfo.Relocs[RelNum].Type = EFI_IMAGE_REL_BASED_DIR64;
mImageInfo.RelocInfo.Relocs[RelNum].Target = (uint32_t)Offset;
++RelNum;
break;
case R_X86_64_32:
WriteUnaligned32 ((UINT32 *)Targ, (UINT32)((UINT64)ReadUnaligned32((UINT32 *)Targ) - SymShdr->sh_addr + WSymOffset));
mImageInfo.RelocInfo.Relocs[RelNum].Type = EFI_IMAGE_REL_BASED_HIGHLOW;
mImageInfo.RelocInfo.Relocs[RelNum].Target = (uint32_t)Offset;
++RelNum;
break;
case R_X86_64_32S:
*(INT32 *)Targ = (INT32)((INT64)(*(INT32 *)Targ) - SymShdr->sh_addr + WSymOffset);
break;
case R_X86_64_PLT32:
case R_X86_64_PC32:
WriteUnaligned32 ((UINT32 *)Targ, (UINT32)(ReadUnaligned32((UINT32 *)Targ) + (WSymOffset - WSecOffset) - (SymShdr->sh_addr - SecShdr->sh_addr)));
break;
case R_X86_64_GOTPCREL:
case R_X86_64_GOTPCRELX:
case R_X86_64_REX_GOTPCRELX:
GOTEntryRva = Rel->r_offset - Rel->r_addend + *(INT32 *)Targ;
Status = FindElfGOTSectionFromGOTEntryElfRva (GOTEntryRva);
if (RETURN_ERROR (Status)) {
return Status;
}
WriteUnaligned32 ((UINT32 *)Targ, (UINT32)(ReadUnaligned32((UINT32 *)Targ) + (mWGotOffset - mGOTShdr->sh_addr) - (WSecOffset - SecShdr->sh_addr)));
//
// ELF Rva -> Offset in PE GOT
//
GOTEntryRva -= mGOTShdr->sh_addr;
Status = AccumulatePeGOTEntries ((UINT32)GOTEntryRva, &IsNew);
if (RETURN_ERROR (Status)) {
return Status;
}
if (IsNew) {
//
// Relocate GOT entry if it's the first time we run into it
//
Targ = mGotData + GOTEntryRva;
WriteUnaligned64 ((UINT64 *)Targ, ReadUnaligned64((UINT64 *)Targ) - SymShdr->sh_addr + WSymOffset);
}
break;
default:
fprintf (stderr, "ImageTool: Unsupported ELF EM_X86_64 relocation 0x%llx\n", ELF_R_TYPE(Rel->r_info));
return RETURN_UNSUPPORTED;
}
#elif defined(EFI_TARGET32)
switch (ELF_R_TYPE(Rel->r_info)) {
case R_386_NONE:
break;
case R_386_32:
WriteUnaligned32 ((UINT32 *)Targ, ReadUnaligned32((UINT32 *)Targ) - SymShdr->sh_addr + WSymOffset);
mImageInfo.RelocInfo.Relocs[RelNum].Type = EFI_IMAGE_REL_BASED_HIGHLOW;
mImageInfo.RelocInfo.Relocs[RelNum].Target = Offset;
++RelNum;
break;
case R_386_PLT32:
case R_386_PC32:
WriteUnaligned32 ((UINT32 *)Targ, (UINT32)(ReadUnaligned32((UINT32 *)Targ) + (WSymOffset - WSecOffset) - (SymShdr->sh_addr - SecShdr->sh_addr)));
break;
default:
fprintf (stderr, "ImageTool: Unsupported ELF EM_386 relocation 0x%x\n", ELF_R_TYPE(Rel->r_info));
return RETURN_UNSUPPORTED;
}
#endif
}
}
assert (RelNum == mImageInfo.RelocInfo.NumRelocs);
return RETURN_SUCCESS;
}
static
RETURN_STATUS
FixAddresses (
VOID
)
{
RETURN_STATUS Status;
UINT32 Index;
const Elf_Shdr *Shdr;
UINT64 Pointer;
#if defined(EFI_TARGET64)
UINT32 NewSize;
#endif
mSizeOfHeaders = sizeof (EFI_IMAGE_DOS_HEADER) + sizeof (EFI_IMAGE_NT_HEADERS) +
EFI_IMAGE_NUMBER_OF_DIRECTORY_ENTRIES * sizeof (EFI_IMAGE_DATA_DIRECTORY) +
mImageInfo.SegmentInfo.NumSegments * sizeof (EFI_IMAGE_SECTION_HEADER);
if (mImageInfo.RelocInfo.Relocs != NULL) {
mSizeOfHeaders += sizeof (EFI_IMAGE_SECTION_HEADER);
}
if (mImageInfo.DebugInfo.SymbolsPath != NULL) {
mSizeOfHeaders += sizeof (EFI_IMAGE_SECTION_HEADER);
}
if (mImageInfo.HiiInfo.Data != NULL) {
mSizeOfHeaders += sizeof (EFI_IMAGE_SECTION_HEADER);
}
mSizeOfHeaders = ALIGN_VALUE (mSizeOfHeaders, mPeAlignment);
Status = FixSegmentsSetRelocs ();
if (RETURN_ERROR (Status)) {
return Status;
}
Pointer = mSizeOfHeaders;
for (Index = 0; Index < mImageInfo.SegmentInfo.NumSegments; ++Index) {
Shdr = GetShdrByIndex (mImageInfo.SegmentInfo.Segments[Index].ImageSize);
if ((mEhdr->e_entry >= Shdr->sh_addr)
&& ((mEhdr->e_entry - Shdr->sh_addr) < Shdr->sh_size)) {
mImageInfo.HeaderInfo.EntryPointAddress = (uint32_t)Pointer + (uint32_t)(mEhdr->e_entry - Shdr->sh_addr);
}
mImageInfo.SegmentInfo.Segments[Index].ImageAddress = Pointer;
mImageInfo.SegmentInfo.Segments[Index].ImageSize = mImageInfo.SegmentInfo.Segments[Index].DataSize;
Pointer += mImageInfo.SegmentInfo.Segments[Index].DataSize;
}
if (mImageInfo.HiiInfo.Data != NULL) {
SetHiiResourceHeader (mImageInfo.HiiInfo.Data, (UINT32)Pointer);
}
#if defined(EFI_TARGET64)
if (mGOTPeEntries != NULL) {
NewSize = (mImageInfo.RelocInfo.NumRelocs + mGOTNumEntries) * sizeof (*mImageInfo.RelocInfo.Relocs);
mImageInfo.RelocInfo.Relocs = realloc (mImageInfo.RelocInfo.Relocs, NewSize);
if (mImageInfo.RelocInfo.Relocs == NULL) {
fprintf (stderr, "ImageTool: Could not reallocate memory for Relocs\n");
return RETURN_OUT_OF_RESOURCES;
}
for (Index = 0; Index < mGOTNumEntries; ++Index) {
mImageInfo.RelocInfo.Relocs[mImageInfo.RelocInfo.NumRelocs + Index].Type = EFI_IMAGE_REL_BASED_DIR64;
mImageInfo.RelocInfo.Relocs[mImageInfo.RelocInfo.NumRelocs + Index].Target = mGOTPeEntries[Index];
}
}
#endif
return RETURN_SUCCESS;
}
static
RETURN_STATUS
CreateIntermediate (
VOID
)
{
const Elf_Shdr *Shdr;
UINT32 Index;
image_tool_segment_t *Segments;
image_tool_reloc_t *Relocs;
UINT32 SIndex;
const Elf_Rel *Rel;
UINTN RIndex;
char *Name;
Segments = NULL;
SIndex = 0;
Relocs = NULL;
for (Index = 0; Index < mEhdr->e_shnum; ++Index) {
Shdr = GetShdrByIndex (Index);
if ((IsTextShdr (Shdr)) || (IsDataShdr (Shdr)) || (IsHiiRsrcShdr (Shdr))) {
if ((Shdr->sh_addralign == 0) || (Shdr->sh_addralign == 1)) {
fprintf (stderr, "ImageTool: Alignment field is invalid\n");
return RETURN_VOLUME_CORRUPTED;
}
if (!IS_ALIGNED(Shdr->sh_addr, Shdr->sh_addralign)) {
fprintf (stderr, "ImageTool: Section address not aligned to its own alignment\n");
return RETURN_VOLUME_CORRUPTED;
}
}
if ((IsTextShdr (Shdr)) || (IsDataShdr (Shdr))) {
++mImageInfo.SegmentInfo.NumSegments;
}
if (IsRelocShdr (Shdr)) {
for (RIndex = 0; RIndex < Shdr->sh_size; RIndex += (UINTN)Shdr->sh_entsize) {
Rel = (Elf_Rel *)((UINT8 *)mEhdr + Shdr->sh_offset + RIndex);
#if defined(EFI_TARGET64)
if ((ELF_R_TYPE(Rel->r_info) == R_X86_64_64)
|| (ELF_R_TYPE(Rel->r_info) == R_X86_64_32)) {
++mImageInfo.RelocInfo.NumRelocs;
}
#elif defined(EFI_TARGET32)
if (ELF_R_TYPE(Rel->r_info) == R_386_32) {
++mImageInfo.RelocInfo.NumRelocs;
}
#endif
}
}
}
if (mImageInfo.SegmentInfo.NumSegments == 0) {
fprintf (stderr, "ImageTool: No .text or .data sections\n");
return RETURN_VOLUME_CORRUPTED;
}
Segments = calloc (1, sizeof (*Segments) * mImageInfo.SegmentInfo.NumSegments);
if (Segments == NULL) {
fprintf (stderr, "ImageTool: Could not allocate memory for Segments\n");
return RETURN_OUT_OF_RESOURCES;
};
mImageInfo.SegmentInfo.Segments = Segments;
if (mImageInfo.RelocInfo.NumRelocs != 0) {
Relocs = calloc (1, sizeof (*Relocs) * mImageInfo.RelocInfo.NumRelocs);
if (Relocs == NULL) {
fprintf (stderr, "ImageTool: Could not allocate memory for Relocs\n");
return RETURN_OUT_OF_RESOURCES;
};
mImageInfo.RelocInfo.Relocs = Relocs;
}
for (Index = 0; Index < mEhdr->e_shnum; ++Index) {
Shdr = GetShdrByIndex (Index);
if (IsTextShdr (Shdr)) {
Name = GetString (Shdr->sh_name);
if (Name == NULL) {
return RETURN_VOLUME_CORRUPTED;
}
Segments[SIndex].Name = calloc (1, strlen (Name) + 1);
if (Segments[SIndex].Name == NULL) {
fprintf (stderr, "ImageTool: Could not allocate memory for Segment #%d Name\n", SIndex);
return RETURN_OUT_OF_RESOURCES;
};
memcpy (Segments[SIndex].Name, Name, strlen (Name));
Segments[SIndex].DataSize = (uint32_t)ALIGN_VALUE (Shdr->sh_size, mPeAlignment);
Segments[SIndex].Data = calloc (1, Segments[SIndex].DataSize);
if (Segments[SIndex].Data == NULL) {
fprintf (stderr, "ImageTool: Could not allocate memory for Segment #%d Data\n", SIndex);
return RETURN_OUT_OF_RESOURCES;
};
memcpy (Segments[SIndex].Data, (UINT8 *)mEhdr + Shdr->sh_offset, (size_t)Shdr->sh_size);
Segments[SIndex].ImageAddress = 0;
Segments[SIndex].ImageSize = Index; // Will be needed by FindAddress()
Segments[SIndex].Read = true;
Segments[SIndex].Write = false;
Segments[SIndex].Execute = true;
Segments[SIndex].Type = ToolImageSectionTypeCode;
++SIndex;
continue;
}
if (IsDataShdr (Shdr)) {
Name = GetString (Shdr->sh_name);
if (Name == NULL) {
return RETURN_VOLUME_CORRUPTED;
}
Segments[SIndex].Name = calloc (1, strlen (Name) + 1);
if (Segments[SIndex].Name == NULL) {
fprintf (stderr, "ImageTool: Could not allocate memory for Segment #%d Name\n", SIndex);
return RETURN_OUT_OF_RESOURCES;
};
memcpy (Segments[SIndex].Name, Name, strlen (Name));
Segments[SIndex].DataSize = (uint32_t)ALIGN_VALUE (Shdr->sh_size, mPeAlignment);
Segments[SIndex].Data = calloc (1, Segments[SIndex].DataSize);
if (Segments[SIndex].Data == NULL) {
fprintf (stderr, "ImageTool: Could not allocate memory for Segment #%d Data\n", SIndex);
return RETURN_OUT_OF_RESOURCES;
};
if (Shdr->sh_type == SHT_PROGBITS) {
memcpy (Segments[SIndex].Data, (UINT8 *)mEhdr + Shdr->sh_offset, (size_t)Shdr->sh_size);
}
Segments[SIndex].ImageAddress = 0;
Segments[SIndex].ImageSize = Index; // Will be needed by FindAddress()
Segments[SIndex].Read = true;
Segments[SIndex].Write = true;
Segments[SIndex].Execute = false;
Segments[SIndex].Type = ToolImageSectionTypeInitialisedData;
++SIndex;
continue;
}
if (IsHiiRsrcShdr (Shdr)) {
mImageInfo.HiiInfo.DataSize = (uint32_t)ALIGN_VALUE (Shdr->sh_size, mPeAlignment);
mImageInfo.HiiInfo.Data = calloc (1, mImageInfo.HiiInfo.DataSize);
if (mImageInfo.HiiInfo.Data == NULL) {
fprintf (stderr, "ImageTool: Could not allocate memory for Hii Data\n");
return RETURN_OUT_OF_RESOURCES;
};
if (Shdr->sh_type == SHT_PROGBITS) {
memcpy (mImageInfo.HiiInfo.Data, (UINT8 *)mEhdr + Shdr->sh_offset, (size_t)Shdr->sh_size);
}
}
}
assert (SIndex == mImageInfo.SegmentInfo.NumSegments);
return FixAddresses();
}
RETURN_STATUS
ScanElf (
IN const char *ElfName,
IN const char *ModuleType
)
{
RETURN_STATUS Status;
assert (ElfName != NULL);
assert (ModuleType != NULL);
Status = ReadElfFile (ElfName);
if (RETURN_ERROR (Status)) {
if (mEhdr != NULL) {
free (mEhdr);
}
return Status;
}
memset (&mImageInfo, 0, sizeof (mImageInfo));
mImageInfo.HeaderInfo.PreferredAddress = 0;
mImageInfo.HeaderInfo.EntryPointAddress = 0;
mImageInfo.HeaderInfo.IsXip = true;
mImageInfo.SegmentInfo.SegmentAlignment = (uint32_t)mPeAlignment;
mImageInfo.RelocInfo.RelocsStripped = false;
mImageInfo.DebugInfo.SymbolsPathLen = strlen (ElfName) + 1;
switch (mEhdr->e_machine) {
case EM_386:
mImageInfo.HeaderInfo.Machine = EFI_IMAGE_MACHINE_IA32;
break;
case EM_X86_64:
mImageInfo.HeaderInfo.Machine = EFI_IMAGE_MACHINE_X64;
break;
case EM_ARM:
mImageInfo.HeaderInfo.Machine = EFI_IMAGE_MACHINE_ARMTHUMB_MIXED;
break;
case EM_AARCH64:
mImageInfo.HeaderInfo.Machine = EFI_IMAGE_MACHINE_AARCH64;
break;
default:
fprintf (stderr, "ImageTool: Unknown ELF architecture %d\n", mEhdr->e_machine);
free (mEhdr);
return RETURN_UNSUPPORTED;
}
mImageInfo.DebugInfo.SymbolsPath = calloc (1, mImageInfo.DebugInfo.SymbolsPathLen);
if (mImageInfo.DebugInfo.SymbolsPath == NULL) {
fprintf (stderr, "ImageTool: Could not allocate memory for Debug Data\n");
free (mEhdr);
return RETURN_OUT_OF_RESOURCES;
};
memcpy (mImageInfo.DebugInfo.SymbolsPath, ElfName, mImageInfo.DebugInfo.SymbolsPathLen);
if ((strcmp (ModuleType, "BASE") == 0)
|| (strcmp (ModuleType, "SEC") == 0)
|| (strcmp (ModuleType, "SECURITY_CORE") == 0)
|| (strcmp (ModuleType, "PEI_CORE") == 0)
|| (strcmp (ModuleType, "PEIM") == 0)
|| (strcmp (ModuleType, "COMBINED_PEIM_DRIVER") == 0)
|| (strcmp (ModuleType, "PIC_PEIM") == 0)
|| (strcmp (ModuleType, "RELOCATABLE_PEIM") == 0)
|| (strcmp (ModuleType, "DXE_CORE") == 0)
|| (strcmp (ModuleType, "BS_DRIVER") == 0)
|| (strcmp (ModuleType, "DXE_DRIVER") == 0)
|| (strcmp (ModuleType, "DXE_SMM_DRIVER") == 0)
|| (strcmp (ModuleType, "UEFI_DRIVER") == 0)
|| (strcmp (ModuleType, "SMM_CORE") == 0)
|| (strcmp (ModuleType, "MM_STANDALONE") == 0)
|| (strcmp (ModuleType, "MM_CORE_STANDALONE") == 0)) {
mImageInfo.HeaderInfo.Subsystem = EFI_IMAGE_SUBSYSTEM_EFI_BOOT_SERVICE_DRIVER;
} else if ((strcmp (ModuleType, "UEFI_APPLICATION") == 0)
|| (strcmp (ModuleType, "APPLICATION") == 0)) {
mImageInfo.HeaderInfo.Subsystem = EFI_IMAGE_SUBSYSTEM_EFI_APPLICATION;
} else if ((strcmp (ModuleType, "DXE_RUNTIME_DRIVER") == 0)
|| (strcmp (ModuleType, "RT_DRIVER") == 0)) {
mImageInfo.HeaderInfo.Subsystem = EFI_IMAGE_SUBSYSTEM_EFI_RUNTIME_DRIVER;
} else if ((strcmp (ModuleType, "DXE_SAL_DRIVER") == 0)
|| (strcmp (ModuleType, "SAL_RT_DRIVER") == 0)) {
mImageInfo.HeaderInfo.Subsystem = EFI_IMAGE_SUBSYSTEM_SAL_RUNTIME_DRIVER;
} else {
fprintf (stderr, "ImageTool: Unknown EFI_FILETYPE = %s\n", ModuleType);
free (mImageInfo.DebugInfo.SymbolsPath);
free (mEhdr);
return RETURN_UNSUPPORTED;
}
Status = CreateIntermediate ();
if (RETURN_ERROR (Status)) {
ToolImageDestruct (&mImageInfo);
}
#if defined(EFI_TARGET64)
if (mGOTPeEntries != NULL) {
free (mGOTPeEntries);
}
#endif
free (mEhdr);
return Status;
}

View File

@ -0,0 +1,35 @@
## @file
# Copyright (c) 2021, Marvin Häuser. All rights reserved.
# Copyright (c) 2022, Mikhail Krichanov. All rights reserved.
# SPDX-License-Identifier: BSD-3-Clause
##
PROJECT = ImageTool
OBJS = $(PROJECT).o
OBJS += Image.o PeEmit.o PeScan.o UeEmit.o ElfScan.o BinEmit.o
OBJS += BaseAlignment.o BaseBitOverflow.o UeImageLib.o UefiImageExtraActionLib.o
OBJS += PeCoffInit.o PeCoffInfo.o PeCoffLoad.o PeCoffRelocate.o PeCoffHii.o PeCoffDebug.o
DEBUG = 1
SANITIZE = 0
OC_USER = ../../OpenCorePkg
UDK_PATH = ../..
include $(OC_USER)/User/Makefile
.DEFAULT_GOAL := Tools
CFLAGS += -include Pcds.h -Werror
VPATH += ../../MdePkg/Library/BaseOverflowLib:$\
../../MdePkg/Library/BasePeCoffLib2:$\
../../MdePkg/Library/BaseUefiImageExtraActionLibNull:$\
../../MdePkg/Library/BaseUeImageLib
Tools: Tool32 Tool64
Tool32:
$(MAKE) all CFLAGS="$(CFLAGS) -DEFI_TARGET32" PRODUCT=ImageTool32 INFIX=_Tool32
Tool64:
$(MAKE) all CFLAGS="$(CFLAGS) -DEFI_TARGET64" PRODUCT=ImageTool64 INFIX=_Tool64

312
BaseTools/ImageTool/Image.c Normal file
View File

@ -0,0 +1,312 @@
/** @file
Copyright (c) 2021, Marvin Häuser. All rights reserved.
Copyright (c) 2022, Mikhail Krichanov. All rights reserved.
SPDX-License-Identifier: BSD-3-Clause
**/
#include "ImageTool.h"
static
bool
CheckToolImageSegment (
image_tool_segment_info_t *SegmentInfo,
image_tool_segment_t *Segment,
uint32_t *PreviousEndAddress
)
{
bool Overflow;
assert (Segment != NULL);
assert (PreviousEndAddress != NULL);
Overflow = BaseOverflowAlignUpU32 (
Segment->ImageSize,
SegmentInfo->SegmentAlignment,
&Segment->ImageSize
);
if (Overflow) {
raise ();
return false;
}
if (Segment->Write && Segment->Execute) {
raise ();
return false;
}
//
// Shrink segment.
//
if (Segment->ImageSize < Segment->DataSize) {
Segment->DataSize = Segment->ImageSize;
}
for (; Segment->DataSize > 0; --Segment->DataSize) {
if (Segment->Data[Segment->DataSize - 1] != 0) {
break;
}
}
// FIXME: Expand prior segment
if (Segment->ImageAddress != *PreviousEndAddress) {
raise ();
return false;
}
Overflow = BaseOverflowAddU32 (
(uint32_t)Segment->ImageAddress,
Segment->ImageSize,
PreviousEndAddress
);
if (Overflow) {
raise ();
return false;
}
return true;
}
static
bool
CheckToolImageSegmentInfo (
image_tool_segment_info_t *SegmentInfo,
uint32_t *ImageSize
)
{
uint64_t Index;
bool Result;
assert (SegmentInfo != NULL);
assert (ImageSize != NULL);
if (!IS_POW2 (SegmentInfo->SegmentAlignment)) {
raise ();
return false;
}
if (SegmentInfo->NumSegments == 0) {
raise ();
return false;
}
*ImageSize = (uint32_t)SegmentInfo->Segments[0].ImageAddress;
for (Index = 0; Index < SegmentInfo->NumSegments; ++Index) {
Result = CheckToolImageSegment (
SegmentInfo,
&SegmentInfo->Segments[Index],
ImageSize
);
if (!Result) {
raise ();
return false;
}
}
return true;
}
static
const image_tool_segment_t *
ImageGetSegmentByAddress (
const image_tool_segment_info_t *SegmentInfo,
uint64_t Address
)
{
uint64_t Index;
assert (SegmentInfo != NULL);
for (Index = 0; Index < SegmentInfo->NumSegments; ++Index) {
if ((SegmentInfo->Segments[Index].ImageAddress <= Address)
&& (Address < SegmentInfo->Segments[Index].ImageAddress + SegmentInfo->Segments[Index].ImageSize)) {
return &SegmentInfo->Segments[Index];
}
}
return NULL;
}
static
bool
CheckToolImageReloc (
const image_tool_image_info_t *Image,
const image_tool_reloc_t *Reloc
)
{
const image_tool_segment_t *Segment;
assert (Image != NULL);
assert (Reloc != NULL);
Segment = ImageGetSegmentByAddress (&Image->SegmentInfo, Reloc->Target);
if (Segment == NULL) {
raise ();
return false;
}
/*if (Segment->Write) {
printf("!!! writable reloc at %x !!!\n", Reloc->Target);
}*/
return true;
}
static
bool
CheckToolImageRelocInfo (
const image_tool_image_info_t *Image
)
{
const image_tool_reloc_info_t *RelocInfo;
uint32_t Index;
bool Result;
assert (Image != NULL);
RelocInfo = &Image->RelocInfo;
if (RelocInfo->RelocsStripped && (RelocInfo->NumRelocs > 0)) {
raise ();
return false;
}
if (RelocInfo->NumRelocs > (MAX_UINT32 / sizeof (UINT16))) {
raise ();
return false;
}
for (Index = 0; Index < RelocInfo->NumRelocs; ++Index) {
Result = CheckToolImageReloc (Image, &RelocInfo->Relocs[Index]);
if (!Result) {
raise ();
return false;
}
}
return true;
}
static
bool
CheckToolImageDebugInfo (
image_tool_debug_info_t *DebugInfo
)
{
assert (DebugInfo != NULL);
if (DebugInfo->SymbolsPath != NULL) {
// FIXME: UE-only?
if (DebugInfo->SymbolsPathLen > MAX_UINT8) {
raise ();
return false;
}
}
return true;
}
bool
CheckToolImage (
image_tool_image_info_t *Image
)
{
bool Result;
uint32_t ImageSize;
assert (Image != NULL);
Result = CheckToolImageSegmentInfo (&Image->SegmentInfo, &ImageSize);
if (!Result) {
raise ();
return false;
}
Result = CheckToolImageRelocInfo (Image);
if (!Result) {
raise ();
return false;
}
Result = CheckToolImageDebugInfo (&Image->DebugInfo);
if (!Result) {
raise ();
return false;
}
return true;
}
bool
ImageConvertToXip (
image_tool_image_info_t *Image
)
{
image_tool_segment_info_t *SegmentInfo;
uint64_t Index;
image_tool_segment_t *Segment;
void *Data;
void *Memory;
assert (Image != NULL);
SegmentInfo = &Image->SegmentInfo;
for (Index = 0; Index < SegmentInfo->NumSegments; ++Index) {
Segment = &SegmentInfo->Segments[Index];
assert (Segment->DataSize <= Segment->ImageSize);
Data = calloc (Segment->ImageSize, 1);
if (Data == NULL) {
return false;
}
memmove (Data, Segment->Data, Segment->DataSize);
Memory = Segment->Data;
Segment->Data = Data;
Segment->DataSize = Segment->ImageSize;
free (Memory);
}
Image->HeaderInfo.IsXip = true;
return true;
}
void
ToolImageDestruct (
image_tool_image_info_t *Image
)
{
uint8_t Index;
assert (Image != NULL);
if (Image->SegmentInfo.Segments != NULL) {
for (Index = 0; Index < Image->SegmentInfo.NumSegments; ++Index) {
if (Image->SegmentInfo.Segments[Index].Name != NULL) {
free (Image->SegmentInfo.Segments[Index].Name);
}
if (Image->SegmentInfo.Segments[Index].DataSize != 0) {
free (Image->SegmentInfo.Segments[Index].Data);
}
}
free (Image->SegmentInfo.Segments);
}
if (Image->HiiInfo.Data != NULL) {
free (Image->HiiInfo.Data);
}
if (Image->RelocInfo.Relocs != NULL) {
free (Image->RelocInfo.Relocs);
}
if (Image->DebugInfo.SymbolsPath != NULL) {
free (Image->DebugInfo.SymbolsPath);
}
memset (Image, 0, sizeof (*Image));
}

View File

@ -0,0 +1,552 @@
/** @file
Copyright (c) 2021, Marvin Häuser. All rights reserved.
Copyright (c) 2022, Mikhail Krichanov. All rights reserved.
SPDX-License-Identifier: BSD-3-Clause
**/
#include "ImageTool.h"
#include <IndustryStandard/Acpi10.h>
#include <IndustryStandard/Acpi30.h>
#include <IndustryStandard/MemoryMappedConfigurationSpaceAccessTable.h>
#define EFI_ACPI_1_0_FIRMWARE_ACPI_CONTROL_STRUCTURE_VERSION 0x0
image_tool_image_info_t mImageInfo;
static
RETURN_STATUS
PeToUe (
IN const char *PeName,
IN const char *UeName
)
{
void *Pe;
uint32_t PeSize;
void *Ue;
uint32_t UeSize;
bool Result;
image_tool_image_info_t Image;
assert (PeName != NULL);
assert (UeName != NULL);
Pe = UserReadFile (PeName, &PeSize);
if (Pe == NULL) {
return RETURN_ABORTED;
}
Result = ToolContextConstructPe (&Image, Pe, PeSize, NULL);
free (Pe);
Pe = NULL;
if (!Result) {
return RETURN_ABORTED;
}
Result = CheckToolImage (&Image);
if (!Result) {
ToolImageDestruct (&Image);
return RETURN_ABORTED;
}
Result = ImageConvertToXip (&Image);
if (!Result) {
ToolImageDestruct (&Image);
return RETURN_ABORTED;
}
Ue = ToolImageEmitUe (&Image, &UeSize);
if (Ue == NULL) {
ToolImageDestruct (&Image);
return RETURN_ABORTED;
}
ToolImageDestruct (&Image);
/*UE_LOADER_IMAGE_CONTEXT UeContext;
RETURN_STATUS Status = UeInitializeContext(&UeContext, Ue, UeSize);
printf("UE status - %llu\n", Status);*/
UserWriteFile (UeName, Ue, UeSize);
free (Ue);
Ue = NULL;
return RETURN_SUCCESS;
}
static
RETURN_STATUS
PeXip (
IN const char *OldName,
IN const char *NewName,
IN const char *ModuleType
)
{
void *Pe;
uint32_t PeSize;
bool Result;
image_tool_image_info_t Image;
assert (OldName != NULL);
assert (NewName != NULL);
assert (ModuleType != NULL);
Pe = UserReadFile (OldName, &PeSize);
if (Pe == NULL) {
fprintf (stderr, "ImageTool: Could not open %s: %s\n", OldName, strerror (errno));
return RETURN_ABORTED;
}
Result = ToolContextConstructPe (&Image, Pe, PeSize, ModuleType);
free (Pe);
Pe = NULL;
if (!Result) {
ToolImageDestruct (&Image);
return RETURN_ABORTED;
}
Pe = ToolImageEmitPe (&Image, &PeSize);
if (Pe == NULL) {
ToolImageDestruct (&Image);
return RETURN_ABORTED;
}
ToolImageDestruct (&Image);
UserWriteFile (NewName, Pe, PeSize);
free (Pe);
return RETURN_SUCCESS;
}
static
RETURN_STATUS
HiiBin (
IN const char *HiiName,
IN const char *Guid,
IN const char *FileNames[],
IN UINT32 NumOfFiles,
IN BOOLEAN IsElf
)
{
RETURN_STATUS Status;
void *Hii;
UINT32 HiiSize;
GUID HiiGuid;
assert (FileNames != NULL);
assert (HiiName != NULL);
assert (Guid != NULL);
Status = AsciiStrToGuid (Guid, &HiiGuid);
if (RETURN_ERROR (Status)) {
fprintf (stderr, "ImageTool: Invalid GUID - %s\n", Guid);
return Status;
}
Status = ConstructHii (FileNames, NumOfFiles, &HiiGuid, &Hii, &HiiSize, IsElf);
if (RETURN_ERROR (Status)) {
fprintf (stderr, "ImageTool: Could not construct HiiBin\n");
return Status;
}
UserWriteFile (HiiName, Hii, HiiSize);
free (Hii);
return RETURN_SUCCESS;
}
static
RETURN_STATUS
Rebase (
IN const char *BaseAddress,
IN const char *OldName,
IN const char *NewName
)
{
RETURN_STATUS Status;
void *Pe;
uint32_t PeSize;
UINT64 NewBaseAddress;
PE_COFF_LOADER_IMAGE_CONTEXT Context;
EFI_IMAGE_NT_HEADERS *PeHdr;
assert (BaseAddress != NULL);
assert (OldName != NULL);
assert (NewName != NULL);
Status = AsciiStrHexToUint64S (BaseAddress, NULL, &NewBaseAddress);
if (RETURN_ERROR (Status)) {
fprintf (stderr, "ImageTool: Could not convert ASCII string to UINT64\n");
return Status;
}
#ifdef EFI_TARGET32
if (NewBaseAddress > MAX_UINT32) {
fprintf (stderr, "ImageTool: New Base Address exceeds MAX value\n");
return RETURN_INVALID_PARAMETER;
}
#endif
Pe = UserReadFile (OldName, &PeSize);
if (Pe == NULL) {
fprintf (stderr, "ImageTool: Could not open %s: %s\n", OldName, strerror (errno));
return RETURN_ABORTED;
}
Status = PeCoffInitializeContext (&Context, Pe, (UINT32)PeSize);
if (RETURN_ERROR (Status)) {
fprintf (stderr, "ImageTool: Could not initialise Context\n");
free (Pe);
return Status;
}
Context.ImageBuffer = (void *)Context.FileBuffer;
Status = PeCoffRelocateImage (&Context, NewBaseAddress, NULL, 0);
if (EFI_ERROR (Status)) {
fprintf (stderr, "ImageTool: Could not relocate image\n");
free (Pe);
return Status;
}
PeHdr = (EFI_IMAGE_NT_HEADERS *)(void *)((char *)Context.ImageBuffer + Context.ExeHdrOffset);
#ifdef EFI_TARGET32
PeHdr->ImageBase = (UINT32)NewBaseAddress;
#else
PeHdr->ImageBase = NewBaseAddress;
#endif
UserWriteFile (NewName, Pe, PeSize);
free (Pe);
return RETURN_SUCCESS;
}
static
RETURN_STATUS
CheckAcpiTable (
IN const void *AcpiTable,
IN UINT32 Length
)
{
const EFI_ACPI_DESCRIPTION_HEADER *AcpiHeader;
const EFI_ACPI_3_0_FIRMWARE_ACPI_CONTROL_STRUCTURE *Facs;
UINT32 ExpectedLength;
AcpiHeader = (const EFI_ACPI_DESCRIPTION_HEADER *)AcpiTable;
if (AcpiHeader->Length > Length) {
fprintf (stderr, "ImageTool: AcpiTable length section size\n");
return RETURN_VOLUME_CORRUPTED;
}
switch (AcpiHeader->Signature) {
case EFI_ACPI_3_0_FIXED_ACPI_DESCRIPTION_TABLE_SIGNATURE:
switch (AcpiHeader->Revision) {
case EFI_ACPI_1_0_FIXED_ACPI_DESCRIPTION_TABLE_REVISION:
ExpectedLength = sizeof(EFI_ACPI_1_0_FIXED_ACPI_DESCRIPTION_TABLE);
break;
case EFI_ACPI_2_0_FIXED_ACPI_DESCRIPTION_TABLE_REVISION:
ExpectedLength = sizeof(EFI_ACPI_2_0_FIXED_ACPI_DESCRIPTION_TABLE);
break;
case EFI_ACPI_3_0_FIXED_ACPI_DESCRIPTION_TABLE_REVISION:
ExpectedLength = sizeof(EFI_ACPI_3_0_FIXED_ACPI_DESCRIPTION_TABLE);
break;
default:
if (AcpiHeader->Revision > EFI_ACPI_3_0_FIXED_ACPI_DESCRIPTION_TABLE_REVISION) {
ExpectedLength = AcpiHeader->Length;
break;
}
fprintf (stderr, "ImageTool: FACP revision check failed\n");
return RETURN_VOLUME_CORRUPTED;
}
if (ExpectedLength != AcpiHeader->Length) {
fprintf (stderr, "ImageTool: FACP length check failed\n");
return RETURN_VOLUME_CORRUPTED;
}
break;
case EFI_ACPI_3_0_FIRMWARE_ACPI_CONTROL_STRUCTURE_SIGNATURE:
Facs = (const EFI_ACPI_3_0_FIRMWARE_ACPI_CONTROL_STRUCTURE *)AcpiTable;
if (Facs->Version > EFI_ACPI_3_0_FIRMWARE_ACPI_CONTROL_STRUCTURE_VERSION) {
break;
}
if ((Facs->Version != EFI_ACPI_1_0_FIRMWARE_ACPI_CONTROL_STRUCTURE_VERSION)
&& (Facs->Version != EFI_ACPI_2_0_FIRMWARE_ACPI_CONTROL_STRUCTURE_VERSION)
&& (Facs->Version != EFI_ACPI_3_0_FIRMWARE_ACPI_CONTROL_STRUCTURE_VERSION)) {
fprintf (stderr, "ImageTool: FACS version check failed\n");
return RETURN_VOLUME_CORRUPTED;
}
if ((Facs->Length != sizeof(EFI_ACPI_1_0_FIRMWARE_ACPI_CONTROL_STRUCTURE))
&& (Facs->Length != sizeof(EFI_ACPI_2_0_FIRMWARE_ACPI_CONTROL_STRUCTURE))
&& (Facs->Length != sizeof(EFI_ACPI_3_0_FIRMWARE_ACPI_CONTROL_STRUCTURE))) {
fprintf (stderr, "ImageTool: FACS length check failed\n");
return RETURN_VOLUME_CORRUPTED;
}
break;
case EFI_ACPI_3_0_DIFFERENTIATED_SYSTEM_DESCRIPTION_TABLE_SIGNATURE:
if (AcpiHeader->Revision > EFI_ACPI_3_0_DIFFERENTIATED_SYSTEM_DESCRIPTION_TABLE_REVISION) {
break;
}
if (AcpiHeader->Length <= sizeof(EFI_ACPI_DESCRIPTION_HEADER)) {
fprintf (stderr, "ImageTool: DSDT length check failed\n");
return RETURN_VOLUME_CORRUPTED;
}
break;
case EFI_ACPI_3_0_MULTIPLE_APIC_DESCRIPTION_TABLE_SIGNATURE:
if (AcpiHeader->Revision > EFI_ACPI_3_0_MULTIPLE_APIC_DESCRIPTION_TABLE_REVISION) {
break;
}
if ((AcpiHeader->Revision != EFI_ACPI_1_0_MULTIPLE_APIC_DESCRIPTION_TABLE_REVISION)
&& (AcpiHeader->Revision != EFI_ACPI_2_0_MULTIPLE_APIC_DESCRIPTION_TABLE_REVISION)
&& (AcpiHeader->Revision != EFI_ACPI_3_0_MULTIPLE_APIC_DESCRIPTION_TABLE_REVISION)) {
fprintf (stderr, "ImageTool: APIC revision check failed\n");
return RETURN_VOLUME_CORRUPTED;
}
if (AcpiHeader->Length <= (sizeof(EFI_ACPI_DESCRIPTION_HEADER) + sizeof(UINT32) + sizeof(UINT32))) {
fprintf (stderr, "ImageTool: APIC length check failed\n");
return RETURN_VOLUME_CORRUPTED;
}
break;
case EFI_ACPI_3_0_PCI_EXPRESS_MEMORY_MAPPED_CONFIGURATION_SPACE_BASE_ADDRESS_DESCRIPTION_TABLE_SIGNATURE:
if (AcpiHeader->Revision > EFI_ACPI_MEMORY_MAPPED_CONFIGURATION_SPACE_ACCESS_TABLE_REVISION) {
break;
}
if (AcpiHeader->Revision != EFI_ACPI_MEMORY_MAPPED_CONFIGURATION_SPACE_ACCESS_TABLE_REVISION) {
fprintf (stderr, "ImageTool: MCFG revision check failed\n");
return RETURN_VOLUME_CORRUPTED;
}
if (AcpiHeader->Length <= (sizeof(EFI_ACPI_DESCRIPTION_HEADER) + sizeof(UINT64))) {
fprintf (stderr, "ImageTool: MCFG length check failed\n");
return RETURN_VOLUME_CORRUPTED;
}
break;
default:
break;
}
return RETURN_SUCCESS;
}
static
RETURN_STATUS
GetAcpi (
IN const char *PeName,
IN const char *AcpiName
)
{
RETURN_STATUS Status;
void *Pe;
uint32_t PeSize;
PE_COFF_LOADER_IMAGE_CONTEXT Context;
UINT16 NumberOfSections;
const EFI_IMAGE_SECTION_HEADER *Sections;
UINT16 Index;
UINT32 FileLength;
assert (PeName != NULL);
assert (AcpiName != NULL);
Pe = UserReadFile (PeName, &PeSize);
if (Pe == NULL) {
fprintf (stderr, "ImageTool: Could not open %s: %s\n", PeName, strerror (errno));
return RETURN_ABORTED;
}
Status = PeCoffInitializeContext (&Context, Pe, (UINT32)PeSize);
if (RETURN_ERROR (Status)) {
fprintf (stderr, "ImageTool: Could not initialise Context\n");
free (Pe);
return Status;
}
NumberOfSections = PeCoffGetSectionTable (&Context, &Sections);
for (Index = 0; Index < NumberOfSections; ++Index) {
if ((strcmp ((char *)Sections[Index].Name, ".data") == 0)
|| (strcmp ((char *)Sections[Index].Name, ".sdata") == 0)) {
if (Sections[Index].VirtualSize < Sections[Index].SizeOfRawData) {
FileLength = Sections[Index].VirtualSize;
} else {
FileLength = Sections[Index].SizeOfRawData;
}
Status = CheckAcpiTable ((char *)Context.FileBuffer + Sections[Index].PointerToRawData, FileLength);
if (RETURN_ERROR (Status)) {
free (Pe);
return Status;
}
UserWriteFile (AcpiName, (char *)Context.FileBuffer + Sections[Index].PointerToRawData, FileLength);
free (Pe);
return RETURN_SUCCESS;
}
}
return RETURN_NOT_FOUND;
}
static
RETURN_STATUS
ElfToPe (
IN const char *ElfName,
IN const char *PeName,
IN const char *ModuleType
)
{
RETURN_STATUS Status;
void *Pe;
uint32_t PeSize;
assert (ElfName != NULL);
assert (PeName != NULL);
assert (ModuleType != NULL);
Status = ScanElf (ElfName, ModuleType);
if (RETURN_ERROR (Status)) {
return Status;
}
Pe = ToolImageEmitPe (&mImageInfo, &PeSize);
if (Pe == NULL) {
ToolImageDestruct (&mImageInfo);
return RETURN_ABORTED;
}
ToolImageDestruct (&mImageInfo);
UserWriteFile (PeName, Pe, PeSize);
free (Pe);
return RETURN_SUCCESS;
}
int main (int argc, const char *argv[])
{
RETURN_STATUS Status;
UINT32 NumOfFiles;
if (argc < 2) {
fprintf (stderr, "ImageTool: No command is specified\n");
raise ();
return -1;
}
if (strcmp (argv[1], "ElfToPe") == 0) {
if (argc < 5) {
fprintf (stderr, "ImageTool: Command arguments are missing\n");
fprintf (stderr, " Usage: ImageTool ElfToPe InputFile OutputFile ModuleType\n");
raise ();
return -1;
}
Status = ElfToPe (argv[2], argv [3], argv[4]);
if (RETURN_ERROR (Status)) {
raise ();
return -1;
}
} else if (strcmp (argv[1], "PeXip") == 0) {
if (argc < 5) {
fprintf (stderr, "ImageTool: Command arguments are missing\n");
fprintf (stderr, " Usage: ImageTool PeXip InputFile OutputFile ModuleType\n");
raise ();
return -1;
}
Status = PeXip (argv[2], argv[3], argv[4]);
if (RETURN_ERROR (Status)) {
raise ();
return -1;
}
} else if (strcmp (argv[1], "HiiBinElf") == 0) {
if (argc < 5) {
fprintf (stderr, "ImageTool: Command arguments are missing\n");
fprintf (stderr, " Usage: ImageTool HiiBinElf OutputFile GUID InputFile1 InputFile2 ...\n");
raise ();
return -1;
}
NumOfFiles = (UINT32)argc - 4U;
Status = HiiBin (argv[2], argv[3], &argv[4], NumOfFiles, TRUE);
if (RETURN_ERROR (Status)) {
raise ();
return -1;
}
} else if (strcmp (argv[1], "HiiBinPe") == 0) {
if (argc < 5) {
fprintf (stderr, "ImageTool: Command arguments are missing\n");
fprintf (stderr, " Usage: ImageTool HiiBinPe OutputFile GUID InputFile1 InputFile2 ...\n");
raise ();
return -1;
}
NumOfFiles = (UINT32)argc - 4U;
Status = HiiBin (argv[2], argv[3], &argv[4], NumOfFiles, FALSE);
if (RETURN_ERROR (Status)) {
raise ();
return -1;
}
} else if (strcmp (argv[1], "Rebase") == 0) {
if (argc < 5) {
fprintf (stderr, "ImageTool: Command arguments are missing\n");
fprintf (stderr, " Usage: ImageTool Rebase Address InputFile OutputFile\n");
raise ();
return -1;
}
Status = Rebase (argv[2], argv[3], argv[4]);
if (RETURN_ERROR (Status)) {
raise ();
return -1;
}
} else if (strcmp (argv[1], "GetAcpi") == 0) {
if (argc < 4) {
fprintf (stderr, "ImageTool: Command arguments are missing\n");
fprintf (stderr, " Usage: ImageTool GetAcpi InputFile OutputFile\n");
raise ();
return -1;
}
Status = GetAcpi (argv[2], argv[3]);
if (RETURN_ERROR (Status)) {
raise ();
return -1;
}
} else if (strcmp (argv[1], "PeToUe") == 0) {
if (argc < 4) {
fprintf (stderr, "ImageTool: Command arguments are missing\n");
fprintf (stderr, " Usage: ImageTool PeToUe InputFile OutputFile\n");
raise ();
return -1;
}
Status = PeToUe (argv[2], argv[3]);
if (RETURN_ERROR (Status)) {
raise ();
return -1;
}
}
return 0;
}

View File

@ -0,0 +1,200 @@
/** @file
Copyright (c) 2021, Marvin Häuser. All rights reserved.
Copyright (c) 2022, Mikhail Krichanov. All rights reserved.
SPDX-License-Identifier: BSD-3-Clause
**/
#ifndef IMAGE_TOOL_H
#define IMAGE_TOOL_H
#include <stdbool.h>
#include <errno.h>
#include <assert.h>
#include <IndustryStandard/PeImage2.h>
#include <IndustryStandard/UeImage.h>
#include <Library/PeCoffLib2.h>
#include <Library/UeImageLib.h>
#include <Library/BaseLib.h>
#include <Library/BaseMemoryLib.h>
#include <Library/BaseOverflowLib.h>
#include <UserFile.h>
#include "../../UefiPayloadPkg/PayloadLoaderPeim/ElfLib/ElfCommon.h"
#undef ELF_R_TYPE
#undef ELF_R_SYM
#ifdef EFI_TARGET32
#include "../../UefiPayloadPkg/PayloadLoaderPeim/ElfLib/Elf32.h"
#define EFI_IMAGE_NT_HEADERS EFI_IMAGE_NT_HEADERS32
#define EFI_IMAGE_NT_OPTIONAL_HDR_MAGIC EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC
#define EFI_IMAGE_FILE_MACHINE EFI_IMAGE_FILE_32BIT_MACHINE
#define ELFCLASS ELFCLASS32
#define Elf_Ehdr Elf32_Ehdr
#define Elf_Shdr Elf32_Shdr
#define Elf_Sym Elf32_Sym
#define Elf_Rel Elf32_Rel
#define Elf_Rela Elf32_Rela
#define Elf_Size Elf32_Size
#define Elf_Addr Elf32_Addr
#define ELF_R_TYPE ELF32_R_TYPE
#define ELF_R_SYM ELF32_R_SYM
#elif defined(EFI_TARGET64)
#include "../../UefiPayloadPkg/PayloadLoaderPeim/ElfLib/Elf64.h"
#define EFI_IMAGE_NT_HEADERS EFI_IMAGE_NT_HEADERS64
#define EFI_IMAGE_NT_OPTIONAL_HDR_MAGIC EFI_IMAGE_NT_OPTIONAL_HDR64_MAGIC
#define EFI_IMAGE_FILE_MACHINE 0
#define ELFCLASS ELFCLASS64
#define Elf_Ehdr Elf64_Ehdr
#define Elf_Shdr Elf64_Shdr
#define Elf_Sym Elf64_Sym
#define Elf_Rel Elf64_Rel
#define Elf_Rela Elf64_Rela
#define Elf_Size Elf64_Size
#define Elf_Addr Elf64_Addr
#define ELF_R_TYPE ELF64_R_TYPE
#define ELF_R_SYM ELF64_R_SYM
#endif
#define ELF_HII_SECTION_NAME ".hii"
#define MAX_PE_ALIGNMENT 0x10000
#define DEFAULT_PE_ALIGNMENT 0x1000
#define raise() assert(false)
typedef struct {
EFI_IMAGE_DEBUG_DIRECTORY_ENTRY Dir;
EFI_IMAGE_DEBUG_CODEVIEW_NB10_ENTRY Nb10;
char Name[];
} DebugData;
#define PAGE(x) ((x) & ~4095U)
#define PAGE_OFF(x) ((x) & 4095U)
typedef struct {
uint64_t PreferredAddress;
uint32_t EntryPointAddress;
uint16_t Machine;
uint16_t Subsystem;
bool IsXip;
} image_tool_header_info_t;
typedef enum {
ToolImageSectionTypeCode,
ToolImageSectionTypeInitialisedData,
ToolImageSectionTypeUninitialisedData
} image_tool_type_t;
typedef struct {
char *Name;
uint8_t *Data;
uint32_t DataSize;
uint64_t ImageAddress;
uint32_t ImageSize;
bool Read;
bool Write;
bool Execute;
image_tool_type_t Type;
} image_tool_segment_t;
typedef struct {
uint32_t SegmentAlignment;
uint32_t NumSegments;
image_tool_segment_t *Segments;
} image_tool_segment_info_t;
typedef struct {
uint8_t Type;
uint32_t Target;
} image_tool_reloc_t;
typedef struct {
uint32_t NumRelocs;
bool RelocsStripped;
image_tool_reloc_t *Relocs;
} image_tool_reloc_info_t;
typedef struct {
char *SymbolsPath;
uint32_t SymbolsPathLen;
} image_tool_debug_info_t;
typedef struct {
uint32_t DebugDirAddress;
uint32_t DebugDirSize;
} image_tool_pe_datadir_info_t;
typedef struct {
void *Data;
uint32_t DataSize;
} image_tool_hii_info_t;
typedef struct {
image_tool_header_info_t HeaderInfo;
image_tool_segment_info_t SegmentInfo;
image_tool_reloc_info_t RelocInfo;
image_tool_hii_info_t HiiInfo;
image_tool_debug_info_t DebugInfo;
} image_tool_image_info_t;
void
ToolImageDestruct (
image_tool_image_info_t *Image
);
bool
ImageConvertToXip (
image_tool_image_info_t *Image
);
void *
ToolImageEmitUe (
const image_tool_image_info_t *Image,
uint32_t *FileSize
);
bool
ToolContextConstructPe (
OUT image_tool_image_info_t *Image,
IN const void *File,
IN size_t FileSize,
IN const char *ModuleType OPTIONAL
);
bool
CheckToolImage (
image_tool_image_info_t *Image
);
void *
ToolImageEmitPe (
const image_tool_image_info_t *Image,
uint32_t *FileSize
);
RETURN_STATUS
ScanElf (
IN const char *ElfName,
IN const char *ModuleType
);
VOID
SetHiiResourceHeader (
IN OUT UINT8 *Hii,
IN UINT32 Offset
);
RETURN_STATUS
ConstructHii (
IN const char *FileNames[],
IN UINT32 NumOfFiles,
IN GUID *HiiGuid,
OUT void **Hii,
OUT UINT32 *HiiSize,
IN BOOLEAN IsElf
);
#endif // IMAGE_TOOL_H

View File

@ -0,0 +1,98 @@
## @file
# Windows makefile for 'ImageTool' module build.
#
# Copyright (c) 2022, Mikhail Krichanov. All rights reserved.
# SPDX-License-Identifier: BSD-3-Clause
#
!INCLUDE ..\Source\C\Makefiles\ms.common
APP = ImageTool
OC_USER = ..\..\OpenCorePkg
UDK_PATH = ..\..
UDK_ARCH = $(HOST_ARCH)
OUT_DIR = .\Windows_$(INFIX)
OV = $(UDK_PATH)\MdePkg\Library\BaseOverflowLib
PE = $(UDK_PATH)\MdePkg\Library\BasePeCoffLib2
UE = $(UDK_PATH)\MdePkg\Library\BaseUeImageLib
UA = $(UDK_PATH)\MdePkg\Library\BaseUefiImageExtraActionLibNull
OBJECTS = ImageTool.obj Image.obj PeEmit.obj PeScan.obj UeEmit.obj ElfScan.obj BinEmit.obj
OBJECTS = $(OBJECTS) {$(OV)}BaseAlignment.obj BaseBitOverflow.obj {$(UE)}UeImageLib.obj {$(UA)}UefiImageExtraActionLib.obj
OBJECTS = $(OBJECTS) {$(PE)}PeCoffInit.obj PeCoffInfo.obj PeCoffRelocate.obj PeCoffLoad.obj PeCoffHii.obj PeCoffDebug.obj
BASE = $(UDK_PATH)\MdePkg\Library\BaseLib
OUT = $(UDK_PATH)\MdePkg\Library\UefiDebugLibConOut
PRIN = $(UDK_PATH)\MdePkg\Library\BasePrintLib
ERRO = $(UDK_PATH)\MdePkg\Library\BaseDebugPrintErrorLevelLib
USER = $(OC_USER)\User\Library
OBJECTS = $(OBJECTS) {$(BASE)}SafeString.obj String.obj SwapBytes16.obj SwapBytes32.obj CpuDeadLoop.obj
OBJECTS = $(OBJECTS) {$(OUT)}DebugLib.obj {$(PRIN)}PrintLib.obj PrintLibInternal.obj {$(ERRO)}BaseDebugPrintErrorLevelLib.obj
OBJECTS = $(OBJECTS) {$(USER)}UserFile.obj UserBaseMemoryLib.obj UserMath.obj UserPcd.obj UserMisc.obj UserGlobalVar.obj UserBootServices.obj
INC = -I . -I $(OC_USER)\User\Include -I $(OC_USER)\Include\Acidanthera
INC = $(INC) -I $(UDK_PATH)\MdePkg\Include -I $(UDK_PATH)\MdePkg\Include\Library -I $(UDK_PATH)\MdePkg\Include\$(UDK_ARCH)
INC = $(INC) -I $(UDK_PATH)\MdePkg\Library\BaseLib -I $(UDK_PATH)\MdeModulePkg\Include -I $(UDK_PATH)\UefiCpuPkg\Include
INC = $(INC) /FI $(OC_USER)\User\Include\UserPcd.h /FI $(UDK_PATH)\MdePkg\Include\Base.h /FI $(OC_USER)\User\Include\UserGlobalVar.h
all:
-if not exist $(OUT_DIR)64 mkdir $(OUT_DIR)64
$(MAKE) $(APP)64 CFLAGS="$(CFLAGS) /D EFI_TARGET64" INFIX=64
-if not exist $(OUT_DIR)32 mkdir $(OUT_DIR)32
$(MAKE) $(APP)32 CFLAGS="$(CFLAGS) /D EFI_TARGET32" INFIX=32
$(APP)$(INFIX) : $(OBJECTS)
-@if not exist $(BIN_PATH) mkdir $(BIN_PATH)
@cd $(OUT_DIR)
$(LD) /nologo /debug /OPT:REF /OPT:ICF=10 /incremental:no /nodefaultlib:libc.lib /out:..\$@ $(LIBS) $**
@copy /y ..\$@ $(BIN_PATH)\$@.exe
.PHONY:clean
.PHONY:cleanall
clean:
del /f /q $(OUT_DIR)32 $(OUT_DIR)64 $(APP)32 $(APP)64 *.pdb > nul
cleanall:
del /f /q $(OUT_DIR)32 $(OUT_DIR)64 *.pdb $(BIN_PATH)\$(APP)64.exe $(BIN_PATH)\$(APP)32.exe > nul
.c.obj :
$(CC) -c $(CFLAGS) $(INC) $< -Fo$@
@move $@ $(OUT_DIR)\
{$(OV)}.c.obj :
$(CC) -c $(CFLAGS) $(INC) $< -Fo$@
@move $@ $(OUT_DIR)\
{$(PE)}.c.obj :
$(CC) -c $(CFLAGS) $(INC) /FI Pcds.h $< -Fo$@
@move $@ $(OUT_DIR)\
{$(UE)}.c.obj :
$(CC) -c $(CFLAGS) $(INC) /FI Pcds.h $< -Fo$@
@move $@ $(OUT_DIR)\
{$(UA)}.c.obj :
$(CC) -c $(CFLAGS) $(INC) $< -Fo$@
@move $@ $(OUT_DIR)\
{$(BASE)}.c.obj :
$(CC) -c $(CFLAGS) $(INC) /wd 4005 $< -Fo$@
@move $@ $(OUT_DIR)\
{$(OUT)}.c.obj :
$(CC) -c $(CFLAGS) $(INC) $< -Fo$@
@move $@ $(OUT_DIR)\
{$(PRIN)}.c.obj :
$(CC) -c $(CFLAGS) $(INC) /wd 4005 $< -Fo$@
@move $@ $(OUT_DIR)\
{$(ERRO)}.c.obj :
$(CC) -c $(CFLAGS) $(INC) $< -Fo$@
@move $@ $(OUT_DIR)\
{$(USER)}.c.obj :
$(CC) -c $(CFLAGS) $(INC) /D WIN32 /wd 4754 $< -Fo$@
@move $@ $(OUT_DIR)\

View File

@ -0,0 +1,11 @@
/** @file
Copyright (c) 2021, Marvin Häuser. All rights reserved.
SPDX-License-Identifier: BSD-3-Clause
**/
#define _PCD_GET_MODE_BOOL_PcdImageLoaderProhibitTe TRUE
#define _PCD_GET_MODE_32_PcdImageLoaderAlignmentPolicy 0xFFFFFFFFU
#define _PCD_GET_MODE_BOOL_PcdImageLoaderWXorX TRUE
#define _PCD_GET_MODE_32_PcdImageLoaderRelocTypePolicy 0x00
#define _PCD_GET_MODE_BOOL_PcdImageLoaderDebugSupport TRUE
#define _PCD_GET_MODE_BOOL_PcdImageLoaderAllowMisalignedOffset FALSE

View File

@ -0,0 +1,985 @@
/** @file
Copyright (c) 2021, Marvin Häuser. All rights reserved.
Copyright (c) 2022, Mikhail Krichanov. All rights reserved.
SPDX-License-Identifier: BSD-3-Clause
**/
#include "ImageTool.h"
typedef struct {
uint8_t NumExtraSections;
uint32_t SizeOfHeaders;
uint8_t NumberOfRvaAndSizes;
uint16_t SizeOfOptionalHeader;
uint32_t SectionHeadersSize;
uint32_t ExtraSectionHeadersSize;
} image_tool_emit_pe_hdr_info_t;
typedef struct {
const image_tool_image_info_t *Image;
EFI_IMAGE_NT_HEADERS *PeHdr;
image_tool_emit_pe_hdr_info_t HdrInfo;
uint32_t SectionsSize;
uint32_t ExtraSectionsSize;
uint32_t UnsignedFileSize;
uint32_t RelocTableSize;
uint32_t HiiTableSize;
uint32_t DebugTableSize;
uint16_t FileAlignment;
} image_tool_pe_emit_context_t;
static
bool
EmitPeGetHeaderSizes (
const image_tool_image_info_t *Image,
image_tool_emit_pe_hdr_info_t *HdrInfo
)
{
assert (Image != NULL);
assert (HdrInfo != NULL);
if (Image->RelocInfo.NumRelocs > 0) {
HdrInfo->ExtraSectionHeadersSize += sizeof (EFI_IMAGE_SECTION_HEADER);
}
if (Image->HiiInfo.DataSize > 0) {
HdrInfo->ExtraSectionHeadersSize += sizeof (EFI_IMAGE_SECTION_HEADER);
}
if (Image->DebugInfo.SymbolsPath != NULL) {
HdrInfo->ExtraSectionHeadersSize += sizeof (EFI_IMAGE_SECTION_HEADER);
}
HdrInfo->SectionHeadersSize = (uint32_t)Image->SegmentInfo.NumSegments * sizeof (EFI_IMAGE_SECTION_HEADER);
HdrInfo->NumberOfRvaAndSizes = EFI_IMAGE_NUMBER_OF_DIRECTORY_ENTRIES;
HdrInfo->SizeOfOptionalHeader = sizeof (EFI_IMAGE_NT_HEADERS) - sizeof (EFI_IMAGE_NT_HEADERS_COMMON_HDR)
+ HdrInfo->NumberOfRvaAndSizes * sizeof (EFI_IMAGE_DATA_DIRECTORY);
HdrInfo->SizeOfHeaders = sizeof (EFI_IMAGE_DOS_HEADER) + sizeof (EFI_IMAGE_NT_HEADERS)
+ HdrInfo->NumberOfRvaAndSizes * sizeof (EFI_IMAGE_DATA_DIRECTORY)
+ HdrInfo->SectionHeadersSize + HdrInfo->ExtraSectionHeadersSize;
return true;
}
static
bool
EmitPeGetSectionsSize (
const image_tool_pe_emit_context_t *Context,
uint32_t *SectionsSize
)
{
const image_tool_image_info_t *Image;
uint8_t Index;
uint32_t DataSize;
bool Overflow;
assert (Context != NULL);
assert (SectionsSize != NULL);
Image = Context->Image;
*SectionsSize = 0;
for (Index = 0; Index < Image->SegmentInfo.NumSegments; ++Index) {
Overflow = BaseOverflowAlignUpU32 (
Image->SegmentInfo.Segments[Index].DataSize,
Context->FileAlignment,
&DataSize
);
if (Overflow) {
raise ();
return false;
}
Overflow = BaseOverflowAddU32 (*SectionsSize, DataSize, SectionsSize);
if (Overflow) {
raise ();
return false;
}
}
return true;
}
static
bool
EmitPeGetRelocSectionSize (
const image_tool_image_info_t *Image,
uint32_t *RelocsSize
)
{
uint32_t RelocTableSize;
uint32_t BlockAddress;
uint32_t BlockSize;
uint32_t Index;
uint32_t RelocAddress;
assert (Image != NULL);
assert (RelocsSize != NULL);
if (Image->RelocInfo.NumRelocs == 0) {
*RelocsSize = 0;
return true;
}
assert (Image->RelocInfo.NumRelocs <= MAX_UINT32);
RelocTableSize = 0;
BlockAddress = PAGE(Image->RelocInfo.Relocs[0].Target);
BlockSize = sizeof (EFI_IMAGE_BASE_RELOCATION_BLOCK);
for (Index = 0; Index < Image->RelocInfo.NumRelocs; ++Index) {
RelocAddress = PAGE(Image->RelocInfo.Relocs[Index].Target);
if (RelocAddress != BlockAddress) {
BlockSize = ALIGN_VALUE (BlockSize, 4);
RelocTableSize += BlockSize;
BlockAddress = RelocAddress;
BlockSize = sizeof (EFI_IMAGE_BASE_RELOCATION_BLOCK);
}
BlockSize += sizeof (UINT16);
}
BlockSize = ALIGN_VALUE (BlockSize, 4);
RelocTableSize += BlockSize;
*RelocsSize = RelocTableSize;
return true;
}
static
bool
EmitPeGetHiiSectionSize (
const image_tool_pe_emit_context_t *Context,
uint32_t *HiiSize
)
{
assert (Context != NULL);
assert (HiiSize != NULL);
return !BaseOverflowAlignUpU32 (
Context->Image->HiiInfo.DataSize,
Context->FileAlignment,
HiiSize
);
}
static
bool
EmitPeGetDebugSectionSize (
const image_tool_image_info_t *Image,
uint32_t *DebugSize
)
{
assert (Image != NULL);
assert (DebugSize != NULL);
*DebugSize = 0;
if (Image->DebugInfo.SymbolsPath != NULL) {
return !BaseOverflowAlignUpU32 (
sizeof (DebugData) + Image->DebugInfo.SymbolsPathLen,
Image->SegmentInfo.SegmentAlignment,
DebugSize
);
}
return true;
}
static
bool
EmitPeGetExtraSectionsSize (
image_tool_pe_emit_context_t *Context,
uint32_t *SectionsSize
)
{
const image_tool_image_info_t *Image;
bool Result;
uint32_t AlignedRelocTableSize;
bool Overflow;
uint32_t AlignedDebugTableSize;
uint32_t AlignedHiiTableSize;
assert (Context != NULL);
assert (SectionsSize != NULL);
Image = Context->Image;
Result = EmitPeGetRelocSectionSize (Image, &Context->RelocTableSize);
if (!Result) {
raise ();
return false;
}
Result = EmitPeGetDebugSectionSize (Image, &Context->DebugTableSize);
if (!Result) {
raise ();
return false;
}
Result = EmitPeGetHiiSectionSize (Context, &Context->HiiTableSize);
if (!Result) {
raise ();
return false;
}
Overflow = BaseOverflowAlignUpU32 (
Context->RelocTableSize,
Context->FileAlignment,
&AlignedRelocTableSize
);
if (Overflow) {
raise ();
return false;
}
Overflow = BaseOverflowAlignUpU32 (
Context->DebugTableSize,
Context->FileAlignment,
&AlignedDebugTableSize
);
if (Overflow) {
raise ();
return false;
}
Overflow = BaseOverflowAlignUpU32 (
Context->HiiTableSize,
Context->FileAlignment,
&AlignedHiiTableSize
);
if (Overflow) {
raise ();
return false;
}
Overflow = BaseOverflowAddU32 (
AlignedRelocTableSize,
AlignedDebugTableSize,
SectionsSize
);
if (Overflow) {
raise ();
return false;
}
Overflow = BaseOverflowAddU32 (
*SectionsSize,
AlignedHiiTableSize,
SectionsSize
);
if (Overflow) {
raise ();
return false;
}
return true;
}
static
bool
ToolImageEmitPeSectionHeaders (
const image_tool_pe_emit_context_t *Context,
uint8_t **Buffer,
uint32_t *BufferSize
)
{
const image_tool_image_info_t *Image;
uint16_t SectionHeadersSize;
uint32_t SectionOffset;
EFI_IMAGE_SECTION_HEADER *Sections;
uint8_t Index;
assert (Context != NULL);
assert (Buffer != NULL);
assert (BufferSize != NULL);
Image = Context->Image;
SectionHeadersSize = (uint16_t) (Image->SegmentInfo.NumSegments * sizeof (EFI_IMAGE_SECTION_HEADER));
SectionOffset = ALIGN_VALUE (Context->HdrInfo.SizeOfHeaders, Context->FileAlignment);
Sections = (void *) *Buffer;
assert (SectionHeadersSize <= *BufferSize);
for (Index = 0; Index < Image->SegmentInfo.NumSegments; ++Index) {
switch (Image->SegmentInfo.Segments[Index].Type) {
case ToolImageSectionTypeCode:
Sections[Index].Characteristics = EFI_IMAGE_SCN_CNT_CODE;
break;
case ToolImageSectionTypeInitialisedData:
Sections[Index].Characteristics = EFI_IMAGE_SCN_CNT_INITIALIZED_DATA;
break;
case ToolImageSectionTypeUninitialisedData:
Sections[Index].Characteristics = EFI_IMAGE_SCN_CNT_UNINITIALIZED_DATA;
break;
default:
assert (false);
break;
}
if (Image->SegmentInfo.Segments[Index].Read) {
Sections[Index].Characteristics |= EFI_IMAGE_SCN_MEM_READ;
}
if (Image->SegmentInfo.Segments[Index].Write) {
Sections[Index].Characteristics |= EFI_IMAGE_SCN_MEM_WRITE;
}
if (Image->SegmentInfo.Segments[Index].Execute) {
Sections[Index].Characteristics |= EFI_IMAGE_SCN_MEM_EXECUTE;
}
Sections[Index].PointerToRawData = SectionOffset;
Sections[Index].VirtualAddress = SectionOffset;
Sections[Index].SizeOfRawData = ALIGN_VALUE (Image->SegmentInfo.Segments[Index].DataSize, Context->FileAlignment);
Sections[Index].VirtualSize = Sections[Index].SizeOfRawData;
strncpy (
(char *) Sections[Index].Name,
Image->SegmentInfo.Segments[Index].Name,
sizeof (Sections[Index].Name)
);
SectionOffset += Sections[Index].SizeOfRawData;
}
*BufferSize -= SectionHeadersSize;
*Buffer += SectionHeadersSize;
assert (SectionHeadersSize == Context->HdrInfo.SectionHeadersSize);
return true;
}
static
bool
ToolImageEmitPeExtraSectionHeaders (
image_tool_pe_emit_context_t *Context,
uint8_t **Buffer,
uint32_t *BufferSize
)
{
uint32_t SectionHeadersSize;
EFI_IMAGE_SECTION_HEADER *Section;
assert (Context != NULL);
assert (Buffer != NULL);
assert (BufferSize != NULL);
SectionHeadersSize = 0;
if (Context->HiiTableSize > 0) {
++Context->PeHdr->CommonHeader.FileHeader.NumberOfSections;
assert (sizeof (EFI_IMAGE_SECTION_HEADER) <= *BufferSize);
Section = (void *) *Buffer;
strncpy ((char *)Section->Name, ".rsrc", sizeof (Section->Name));
Section->SizeOfRawData = Context->HiiTableSize;
Section->VirtualSize = Context->HiiTableSize;
Section->Characteristics = EFI_IMAGE_SCN_CNT_INITIALIZED_DATA | EFI_IMAGE_SCN_MEM_READ;
Section->PointerToRawData = ALIGN_VALUE (Context->HdrInfo.SizeOfHeaders, Context->FileAlignment) + Context->SectionsSize;
Section->VirtualAddress = Section->PointerToRawData;
Context->PeHdr->DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_RESOURCE].Size = Context->HiiTableSize;
Context->PeHdr->DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_RESOURCE].VirtualAddress = Section->PointerToRawData;
*BufferSize -= sizeof (EFI_IMAGE_SECTION_HEADER);
*Buffer += sizeof (EFI_IMAGE_SECTION_HEADER);
SectionHeadersSize += sizeof (EFI_IMAGE_SECTION_HEADER);
}
if (Context->RelocTableSize > 0) {
++Context->PeHdr->CommonHeader.FileHeader.NumberOfSections;
assert (sizeof (EFI_IMAGE_SECTION_HEADER) <= *BufferSize);
Section = (void *) *Buffer;
strncpy ((char *)Section->Name, ".reloc", sizeof (Section->Name));
Section->SizeOfRawData = ALIGN_VALUE (Context->RelocTableSize, Context->FileAlignment);
Section->VirtualSize = ALIGN_VALUE (Context->RelocTableSize, Context->FileAlignment);
Section->Characteristics = EFI_IMAGE_SCN_CNT_INITIALIZED_DATA
| EFI_IMAGE_SCN_MEM_DISCARDABLE | EFI_IMAGE_SCN_MEM_READ;
Section->PointerToRawData = ALIGN_VALUE (Context->HdrInfo.SizeOfHeaders, Context->FileAlignment)
+ Context->SectionsSize + Context->HiiTableSize;
Section->VirtualAddress = Section->PointerToRawData;
Context->PeHdr->DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_BASERELOC].Size = Context->RelocTableSize;
Context->PeHdr->DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_BASERELOC].VirtualAddress = Section->PointerToRawData;
*BufferSize -= sizeof (EFI_IMAGE_SECTION_HEADER);
*Buffer += sizeof (EFI_IMAGE_SECTION_HEADER);
SectionHeadersSize += sizeof (EFI_IMAGE_SECTION_HEADER);
}
if (Context->DebugTableSize > 0) {
++Context->PeHdr->CommonHeader.FileHeader.NumberOfSections;
assert (sizeof (EFI_IMAGE_SECTION_HEADER) <= *BufferSize);
Section = (void *) *Buffer;
strncpy ((char *)Section->Name, ".debug", sizeof (Section->Name));
Section->SizeOfRawData = Context->DebugTableSize;
Section->VirtualSize = Context->DebugTableSize;
Section->Characteristics = EFI_IMAGE_SCN_CNT_INITIALIZED_DATA | EFI_IMAGE_SCN_MEM_READ;
Section->PointerToRawData = Context->UnsignedFileSize - Context->DebugTableSize;
Section->VirtualAddress = Section->PointerToRawData;
Context->PeHdr->DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_DEBUG].Size = sizeof (EFI_IMAGE_DEBUG_DIRECTORY_ENTRY);
Context->PeHdr->DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_DEBUG].VirtualAddress = Section->PointerToRawData;
*BufferSize -= sizeof (EFI_IMAGE_SECTION_HEADER);
*Buffer += sizeof (EFI_IMAGE_SECTION_HEADER);
SectionHeadersSize += sizeof (EFI_IMAGE_SECTION_HEADER);
}
assert (Context->HdrInfo.ExtraSectionHeadersSize == SectionHeadersSize);
return true;
}
static
bool
ToolImageEmitPeHeaders (
image_tool_pe_emit_context_t *Context,
uint8_t **Buffer,
uint32_t *BufferSize
)
{
const image_tool_image_info_t *Image;
EFI_IMAGE_DOS_HEADER *DosHdr;
EFI_IMAGE_NT_HEADERS *PePlusHdr;
bool Result;
uint32_t HeaderPadding;
assert (Context != NULL);
assert (Buffer != NULL);
assert (BufferSize != NULL);
assert (sizeof (EFI_IMAGE_DOS_HEADER) <= *BufferSize);
Image = Context->Image;
DosHdr = (void *) *Buffer;
DosHdr->e_magic = EFI_IMAGE_DOS_SIGNATURE;
DosHdr->e_lfanew = sizeof (EFI_IMAGE_DOS_HEADER);
*BufferSize -= sizeof (EFI_IMAGE_DOS_HEADER);
*Buffer += sizeof (EFI_IMAGE_DOS_HEADER);
assert (sizeof (EFI_IMAGE_NT_HEADERS) <= *BufferSize);
PePlusHdr = (EFI_IMAGE_NT_HEADERS *)(VOID *) *Buffer;
PePlusHdr->CommonHeader.Signature = EFI_IMAGE_NT_SIGNATURE;
PePlusHdr->CommonHeader.FileHeader.Machine = Image->HeaderInfo.Machine;
PePlusHdr->CommonHeader.FileHeader.NumberOfSections = (UINT16)Image->SegmentInfo.NumSegments;
PePlusHdr->CommonHeader.FileHeader.SizeOfOptionalHeader = Context->HdrInfo.SizeOfOptionalHeader;
PePlusHdr->CommonHeader.FileHeader.Characteristics =
EFI_IMAGE_FILE_EXECUTABLE_IMAGE | EFI_IMAGE_FILE_LINE_NUMS_STRIPPED |
EFI_IMAGE_FILE_LOCAL_SYMS_STRIPPED | EFI_IMAGE_FILE_LARGE_ADDRESS_AWARE;
if (Image->RelocInfo.RelocsStripped) {
PePlusHdr->CommonHeader.FileHeader.Characteristics |= EFI_IMAGE_FILE_RELOCS_STRIPPED;
}
PePlusHdr->Magic = EFI_IMAGE_NT_OPTIONAL_HDR_MAGIC;
PePlusHdr->AddressOfEntryPoint = Image->HeaderInfo.EntryPointAddress;
PePlusHdr->SectionAlignment = Image->SegmentInfo.SegmentAlignment;
PePlusHdr->FileAlignment = Context->FileAlignment;
PePlusHdr->SizeOfHeaders = Context->HdrInfo.SizeOfHeaders;
PePlusHdr->ImageBase = (UINTN)Image->HeaderInfo.PreferredAddress;
PePlusHdr->Subsystem = Image->HeaderInfo.Subsystem;
PePlusHdr->NumberOfRvaAndSizes = Context->HdrInfo.NumberOfRvaAndSizes;
STATIC_ASSERT(
OFFSET_OF(EFI_IMAGE_NT_HEADERS, DataDirectory) == sizeof (EFI_IMAGE_NT_HEADERS),
"The following code needs to be updated to consider padding."
);
Context->PeHdr = PePlusHdr;
*BufferSize -= sizeof (EFI_IMAGE_NT_HEADERS) + PePlusHdr->NumberOfRvaAndSizes * sizeof (EFI_IMAGE_DATA_DIRECTORY);
*Buffer += sizeof (EFI_IMAGE_NT_HEADERS) + PePlusHdr->NumberOfRvaAndSizes * sizeof (EFI_IMAGE_DATA_DIRECTORY);
Result = ToolImageEmitPeSectionHeaders (Context, Buffer, BufferSize);
if (!Result) {
return false;
}
Result = ToolImageEmitPeExtraSectionHeaders (Context, Buffer, BufferSize);
if (!Result) {
return false;
}
HeaderPadding = ALIGN_VALUE_ADDEND(
Context->HdrInfo.SizeOfHeaders,
Context->FileAlignment
);
assert (HeaderPadding <= *BufferSize);
*BufferSize -= HeaderPadding;
*Buffer += HeaderPadding;
return true;
}
static
bool
ToolImageEmitPeSections (
const image_tool_pe_emit_context_t *Context,
uint8_t **Buffer,
uint32_t *BufferSize
)
{
const image_tool_image_info_t *Image;
uint32_t SectionsSize;
uint8_t Index;
const image_tool_segment_t *Segment;
uint32_t SectionPadding;
bool FirstCode;
#if defined(EFI_TARGET32)
bool FirstData;
#endif
assert (Context != NULL);
assert (Buffer != NULL);
assert (BufferSize != NULL);
assert (Context->SectionsSize <= *BufferSize);
Image = Context->Image;
SectionsSize = 0;
FirstCode = true;
#if defined(EFI_TARGET32)
FirstData = true;
#endif
for (Index = 0; Index < Image->SegmentInfo.NumSegments; ++Index) {
Segment = &Image->SegmentInfo.Segments[Index];
if (FirstCode && (Segment->Type == ToolImageSectionTypeCode)) {
Context->PeHdr->BaseOfCode = (UINT32)Segment->ImageAddress;
FirstCode = false;
}
#if defined(EFI_TARGET32)
if (FirstData && (Segment->Type == ToolImageSectionTypeInitialisedData)) {
Context->PeHdr->BaseOfData = (UINT32)Segment->ImageAddress;
FirstData = false;
}
#endif
assert (Segment->DataSize <= *BufferSize);
memmove (*Buffer, Segment->Data, Segment->DataSize);
*BufferSize -= Segment->DataSize;
*Buffer += Segment->DataSize;
SectionsSize += Segment->DataSize;
SectionPadding = ALIGN_VALUE_ADDEND (
Segment->DataSize,
Context->FileAlignment
);
assert (SectionPadding <= *BufferSize);
*BufferSize -= SectionPadding;
*Buffer += SectionPadding;
SectionsSize += SectionPadding;
switch (Segment->Type) {
case ToolImageSectionTypeCode:
Context->PeHdr->BaseOfCode = MIN(Context->PeHdr->BaseOfCode, (UINT32)Segment->ImageAddress);
Context->PeHdr->SizeOfCode += Segment->ImageSize;
break;
case ToolImageSectionTypeInitialisedData:
#if defined(EFI_TARGET32)
Context->PeHdr->BaseOfData = MIN(Context->PeHdr->BaseOfData, (UINT32)Segment->ImageAddress);
#endif
Context->PeHdr->SizeOfInitializedData += Segment->ImageSize;
break;
case ToolImageSectionTypeUninitialisedData:
Context->PeHdr->SizeOfUninitializedData += Segment->ImageSize;
break;
default:
assert (false);
break;
}
}
assert (SectionsSize == Context->SectionsSize);
return true;
}
static
bool
ToolImageEmitPeRelocTable (
const image_tool_pe_emit_context_t *Context,
uint8_t **Buffer,
uint32_t *BufferSize
)
{
const image_tool_image_info_t *Image;
uint32_t RelocTableSize;
EFI_IMAGE_BASE_RELOCATION_BLOCK *RelocBlock;
uint32_t BlockAddress;
uint32_t BlockNumRelocs;
uint32_t Index;
uint32_t RelocAddress;
uint32_t RelocTablePadding;
assert (Context != NULL);
assert (Buffer != NULL);
assert (BufferSize != NULL);
if (Context->RelocTableSize == 0) {
return true;
}
Image = Context->Image;
assert (Image->RelocInfo.NumRelocs > 0);
assert (Image->RelocInfo.NumRelocs <= MAX_UINT32);
assert (sizeof (EFI_IMAGE_BASE_RELOCATION_BLOCK) <= *BufferSize);
RelocTableSize = 0;
RelocBlock = (void *) *Buffer;
BlockAddress = PAGE(Image->RelocInfo.Relocs[0].Target);
BlockNumRelocs = 0;
RelocBlock->VirtualAddress = BlockAddress;
RelocBlock->SizeOfBlock = sizeof (*RelocBlock);
for (Index = 0; Index < Image->RelocInfo.NumRelocs; ++Index) {
RelocAddress = PAGE(Image->RelocInfo.Relocs[Index].Target);
if (RelocAddress != BlockAddress) {
RelocBlock->SizeOfBlock = ALIGN_VALUE (RelocBlock->SizeOfBlock, 4);
assert (RelocBlock->SizeOfBlock <= *BufferSize);
*BufferSize -= RelocBlock->SizeOfBlock;
*Buffer += RelocBlock->SizeOfBlock;
RelocTableSize += RelocBlock->SizeOfBlock;
RelocBlock = (void *) *Buffer;
BlockAddress = RelocAddress;
BlockNumRelocs = 0;
RelocBlock->VirtualAddress = BlockAddress;
RelocBlock->SizeOfBlock = sizeof (*RelocBlock);
}
RelocBlock->SizeOfBlock += sizeof (*RelocBlock->Relocations);
assert (RelocBlock->SizeOfBlock <= *BufferSize);
RelocBlock->Relocations[BlockNumRelocs] = PAGE_OFF(Image->RelocInfo.Relocs[Index].Target);
RelocBlock->Relocations[BlockNumRelocs] |= ((uint16_t)Image->RelocInfo.Relocs[Index].Type) << 12U;
++BlockNumRelocs;
}
RelocBlock->SizeOfBlock = ALIGN_VALUE (RelocBlock->SizeOfBlock, 4);
assert (RelocBlock->SizeOfBlock <= *BufferSize);
*BufferSize -= RelocBlock->SizeOfBlock;
*Buffer += RelocBlock->SizeOfBlock;
RelocTableSize += RelocBlock->SizeOfBlock;
assert (RelocTableSize == Context->RelocTableSize);
RelocTablePadding = ALIGN_VALUE_ADDEND (
RelocTableSize,
Context->FileAlignment
);
assert (RelocTablePadding <= *BufferSize);
*BufferSize -= RelocTablePadding;
*Buffer += RelocTablePadding;
return true;
}
typedef struct {
EFI_IMAGE_DEBUG_DIRECTORY_ENTRY CodeViewDirEntry;
EFI_IMAGE_DEBUG_CODEVIEW_RSDS_ENTRY CodeViewEntry;
uint8_t PdbPath[];
} image_tool_debug_dir_t;
STATIC_ASSERT(
OFFSET_OF(image_tool_debug_dir_t, PdbPath) == sizeof (image_tool_debug_dir_t),
"Flexible array aliases padding."
);
static
bool
ToolImageEmitPeDebugTable (
const image_tool_pe_emit_context_t *Context,
uint8_t **Buffer,
uint32_t *BufferSize
)
{
const image_tool_image_info_t *Image;
uint32_t DebugTablePadding;
DebugData *Data;
assert (Context != NULL);
assert (Buffer != NULL);
assert (BufferSize != NULL);
Image = Context->Image;
if (Context->DebugTableSize == 0) {
return true;
}
assert (Image->DebugInfo.SymbolsPathLen <= Context->DebugTableSize);
assert (Context->DebugTableSize <= *BufferSize);
Data = (DebugData *) *Buffer;
Data->Dir.Type = EFI_IMAGE_DEBUG_TYPE_CODEVIEW;
Data->Dir.SizeOfData = sizeof (EFI_IMAGE_DEBUG_CODEVIEW_NB10_ENTRY) + Image->DebugInfo.SymbolsPathLen;
Data->Dir.RVA = (Context->UnsignedFileSize - ALIGN_VALUE (Context->DebugTableSize, Context->FileAlignment)) + sizeof (EFI_IMAGE_DEBUG_DIRECTORY_ENTRY);
Data->Dir.FileOffset = Data->Dir.RVA;
Data->Nb10.Signature = CODEVIEW_SIGNATURE_NB10;
snprintf (Data->Name, Image->DebugInfo.SymbolsPathLen, "%s", Image->DebugInfo.SymbolsPath);
*BufferSize -= Context->DebugTableSize;
*Buffer += Context->DebugTableSize;
DebugTablePadding = ALIGN_VALUE_ADDEND(
Context->DebugTableSize,
Context->FileAlignment
);
assert (DebugTablePadding <= *BufferSize);
*BufferSize -= DebugTablePadding;
*Buffer += DebugTablePadding;
return true;
}
static
bool
ToolImageEmitPeHiiTable (
const image_tool_pe_emit_context_t *Context,
uint8_t **Buffer,
uint32_t *BufferSize
)
{
const image_tool_image_info_t *Image;
uint32_t HiiTablePadding;
assert (Context != NULL);
assert (Buffer != NULL);
assert (BufferSize != NULL);
Image = Context->Image;
if (Context->HiiTableSize == 0) {
return true;
}
assert (Image->HiiInfo.DataSize <= Context->HiiTableSize);
assert (Context->HiiTableSize <= *BufferSize);
memmove (*Buffer, Image->HiiInfo.Data, Image->HiiInfo.DataSize);
*BufferSize -= Context->HiiTableSize;
*Buffer += Context->HiiTableSize;
HiiTablePadding = ALIGN_VALUE_ADDEND(
Context->HiiTableSize,
Context->FileAlignment
);
assert (HiiTablePadding <= *BufferSize);
*BufferSize -= HiiTablePadding;
*Buffer += HiiTablePadding;
return true;
}
static
bool
ToolImageEmitPeExtraSections (
const image_tool_pe_emit_context_t *Context,
uint8_t **Buffer,
uint32_t *BufferSize
)
{
uint32_t OldBufferSize;
bool Result;
assert (Context != NULL);
assert (Buffer != NULL);
assert (BufferSize != NULL);
OldBufferSize = *BufferSize;
Result = ToolImageEmitPeHiiTable (Context, Buffer, BufferSize);
if (!Result) {
return false;
}
Result = ToolImageEmitPeRelocTable (Context, Buffer, BufferSize);
if (!Result) {
return false;
}
Result = ToolImageEmitPeDebugTable (Context, Buffer, BufferSize);
if (!Result) {
return false;
}
assert ((OldBufferSize - *BufferSize) == Context->ExtraSectionsSize);
return true;
}
void *
ToolImageEmitPe (
const image_tool_image_info_t *Image,
uint32_t *FileSize
)
{
image_tool_pe_emit_context_t Context;
bool Result;
uint32_t AlignedHeaderSize;
bool Overflow;
uint32_t SectionsOffset;
void *FileBuffer;
uint8_t *Buffer;
uint32_t RemainingSize;
uint32_t ExpectedSize;
assert (Image != NULL);
assert (FileSize != NULL);
memset (&Context, 0, sizeof (Context));
Context.Image = Image;
Context.FileAlignment = (uint16_t)Image->SegmentInfo.SegmentAlignment;
Result = EmitPeGetHeaderSizes (Image, &Context.HdrInfo);
if (!Result) {
raise ();
return NULL;
}
Overflow = BaseOverflowAlignUpU32 (
Context.HdrInfo.SizeOfHeaders,
Context.FileAlignment,
&AlignedHeaderSize
);
if (Overflow) {
raise ();
return NULL;
}
Result = EmitPeGetSectionsSize (&Context, &Context.SectionsSize);
if (!Result) {
raise ();
return NULL;
}
Overflow = BaseOverflowAddU32 (
AlignedHeaderSize,
Context.SectionsSize,
&SectionsOffset
);
if (Overflow) {
raise ();
return NULL;
}
Result = EmitPeGetExtraSectionsSize (&Context, &Context.ExtraSectionsSize);
if (!Result) {
raise ();
return NULL;
}
Overflow = BaseOverflowAddU32 (
SectionsOffset,
Context.ExtraSectionsSize,
&Context.UnsignedFileSize
);
if (Overflow) {
raise ();
return NULL;
}
FileBuffer = calloc (1, Context.UnsignedFileSize);
if (FileBuffer == NULL) {
raise ();
return NULL;
}
Buffer = FileBuffer;
RemainingSize = Context.UnsignedFileSize;
ExpectedSize = Context.UnsignedFileSize;
Result = ToolImageEmitPeHeaders (&Context, &Buffer, &RemainingSize);
if (!Result) {
raise ();
free (FileBuffer);
return NULL;
}
ExpectedSize -= AlignedHeaderSize;
assert (RemainingSize == ExpectedSize);
Result = ToolImageEmitPeSections (&Context, &Buffer, &RemainingSize);
if (!Result) {
raise ();
free (FileBuffer);
return NULL;
}
ExpectedSize -= Context.SectionsSize;
assert (RemainingSize == ExpectedSize);
Result = ToolImageEmitPeExtraSections (&Context, &Buffer, &RemainingSize);
if (!Result) {
raise ();
free (FileBuffer);
return NULL;
}
ExpectedSize -= Context.ExtraSectionsSize;
assert (RemainingSize == ExpectedSize);
assert (RemainingSize == 0);
Context.PeHdr->SizeOfHeaders = AlignedHeaderSize;
Context.PeHdr->SizeOfImage = Context.UnsignedFileSize;
Context.PeHdr->SizeOfInitializedData += Context.ExtraSectionsSize;
*FileSize = Context.UnsignedFileSize;
return FileBuffer;
}

View File

@ -0,0 +1,597 @@
/** @file
Copyright (c) 2021, Marvin Häuser. All rights reserved.
Copyright (c) 2022, Mikhail Krichanov. All rights reserved.
SPDX-License-Identifier: BSD-3-Clause
**/
#include "ImageTool.h"
#define PE_COFF_SECT_NAME_RELOC ".reloc\0"
#define PE_COFF_SECT_NAME_RESRC ".rsrc\0\0"
#define PE_COFF_SECT_NAME_DEBUG ".debug\0"
static
bool
ScanPeGetHeaderInfo (
OUT image_tool_header_info_t *HeaderInfo,
IN PE_COFF_LOADER_IMAGE_CONTEXT *Context,
IN const char *ModuleType OPTIONAL
)
{
assert (HeaderInfo != NULL);
assert (Context != NULL);
HeaderInfo->PreferredAddress = (uint64_t)PeCoffGetImageBase (Context);
HeaderInfo->EntryPointAddress = PeCoffGetAddressOfEntryPoint (Context);
// FIXME:
HeaderInfo->Machine = PeCoffGetMachine (Context);
HeaderInfo->IsXip = true;
if (ModuleType == NULL) {
HeaderInfo->Subsystem = PeCoffGetSubsystem (Context);
return true;
}
if ((strcmp (ModuleType, "BASE") == 0)
|| (strcmp (ModuleType, "SEC") == 0)
|| (strcmp (ModuleType, "SECURITY_CORE") == 0)
|| (strcmp (ModuleType, "PEI_CORE") == 0)
|| (strcmp (ModuleType, "PEIM") == 0)
|| (strcmp (ModuleType, "COMBINED_PEIM_DRIVER") == 0)
|| (strcmp (ModuleType, "PIC_PEIM") == 0)
|| (strcmp (ModuleType, "RELOCATABLE_PEIM") == 0)
|| (strcmp (ModuleType, "DXE_CORE") == 0)
|| (strcmp (ModuleType, "BS_DRIVER") == 0)
|| (strcmp (ModuleType, "DXE_DRIVER") == 0)
|| (strcmp (ModuleType, "DXE_SMM_DRIVER") == 0)
|| (strcmp (ModuleType, "UEFI_DRIVER") == 0)
|| (strcmp (ModuleType, "SMM_CORE") == 0)
|| (strcmp (ModuleType, "MM_STANDALONE") == 0)
|| (strcmp (ModuleType, "MM_CORE_STANDALONE") == 0)) {
HeaderInfo->Subsystem = EFI_IMAGE_SUBSYSTEM_EFI_BOOT_SERVICE_DRIVER;
} else if ((strcmp (ModuleType, "UEFI_APPLICATION") == 0)
|| (strcmp (ModuleType, "APPLICATION") == 0)) {
HeaderInfo->Subsystem = EFI_IMAGE_SUBSYSTEM_EFI_APPLICATION;
} else if ((strcmp (ModuleType, "DXE_RUNTIME_DRIVER") == 0)
|| (strcmp (ModuleType, "RT_DRIVER") == 0)) {
HeaderInfo->Subsystem = EFI_IMAGE_SUBSYSTEM_EFI_RUNTIME_DRIVER;
} else if ((strcmp (ModuleType, "DXE_SAL_DRIVER") == 0)
|| (strcmp (ModuleType, "SAL_RT_DRIVER") == 0)) {
HeaderInfo->Subsystem = EFI_IMAGE_SUBSYSTEM_SAL_RUNTIME_DRIVER;
} else {
fprintf (stderr, "ImageTool: Unknown EFI_FILETYPE = %s\n", ModuleType);
return false;
}
return true;
}
static
bool
ScanPeGetRelocInfo (
OUT image_tool_reloc_info_t *RelocInfo,
IN const EFI_IMAGE_SECTION_HEADER *Section,
IN PE_COFF_LOADER_IMAGE_CONTEXT *Context
)
{
BOOLEAN Overflow;
UINT32 RelocBlockRvaMax;
UINT32 TopOfRelocDir;
UINT32 RelocBlockRva;
const EFI_IMAGE_BASE_RELOCATION_BLOCK *RelocBlock;
UINT32 RelocBlockSize;
UINT32 SizeOfRelocs;
UINT32 NumRelocs;
UINT32 RelocIndex;
uint32_t RelocDirSize;
const char *FileBuffer;
UINT16 RelocType;
UINT16 RelocOffset;
assert (Context != NULL);
assert (Section != NULL);
RelocInfo->RelocsStripped = false;
// FIXME: PE/COFF context access
RelocBlockRva = Section->PointerToRawData;
RelocDirSize = Section->VirtualSize;
//
// Verify the Relocation Directory is not empty.
//
if (RelocDirSize == 0) {
return true;
}
RelocInfo->Relocs = calloc (RelocDirSize / sizeof (UINT16), sizeof (*RelocInfo->Relocs));
if (RelocInfo->Relocs == NULL) {
fprintf (stderr, "ImageTool: Could not allocate memory for Relocs[]\n");
return false;
}
TopOfRelocDir = RelocBlockRva + RelocDirSize;
RelocBlockRvaMax = TopOfRelocDir - sizeof (EFI_IMAGE_BASE_RELOCATION_BLOCK);
//
// Align TopOfRelocDir because, if the policy does not demand Relocation Block
// sizes to be aligned, the code below will manually align them. Thus, the
// end offset of the last Relocation Block must be compared to a manually
// aligned Relocation Directoriy end offset.
//
Overflow = BaseOverflowAlignUpU32 (
TopOfRelocDir,
ALIGNOF (EFI_IMAGE_BASE_RELOCATION_BLOCK),
&TopOfRelocDir
);
if (Overflow) {
fprintf (stderr, "ImageTool: Overflow during TopOfRelocDir calculation\n");
return false;
}
//
// Apply all Base Relocations of the Image.
//
FileBuffer = (const char *)Context->FileBuffer;
while (RelocBlockRva <= RelocBlockRvaMax) {
RelocBlock = (const EFI_IMAGE_BASE_RELOCATION_BLOCK *)(const void *)(FileBuffer + RelocBlockRva);
//
// Verify the Base Relocation Block size is well-formed.
//
Overflow = BaseOverflowSubU32 (
RelocBlock->SizeOfBlock,
sizeof (EFI_IMAGE_BASE_RELOCATION_BLOCK),
&SizeOfRelocs
);
if (Overflow) {
fprintf (stderr, "ImageTool: Overflow during SizeOfRelocs calculation\n");
return false;
}
//
// Verify the Base Relocation Block is in bounds of the Relocation
// Directory.
//
if (SizeOfRelocs > RelocBlockRvaMax - RelocBlockRva) {
fprintf (stderr, "ImageTool: Base Relocation Block is out of bounds of the Relocation Directory\n");
return false;
}
//
// This arithmetic cannot overflow because we know
// 1) RelocBlock->SizeOfBlock <= RelocMax <= TopOfRelocDir
// 2) IS_ALIGNED (TopOfRelocDir, ALIGNOF (EFI_IMAGE_BASE_RELOCATION_BLOCK)).
//
RelocBlockSize = ALIGN_VALUE (
RelocBlock->SizeOfBlock,
ALIGNOF (EFI_IMAGE_BASE_RELOCATION_BLOCK)
);
//
// This division is safe due to the guarantee made above.
//
NumRelocs = SizeOfRelocs / sizeof (*RelocBlock->Relocations);
//
// Process all Base Relocations of the current Block.
//
for (RelocIndex = 0; RelocIndex < NumRelocs; ++RelocIndex) {
RelocType = IMAGE_RELOC_TYPE (RelocBlock->Relocations[RelocIndex]);
RelocOffset = IMAGE_RELOC_OFFSET (RelocBlock->Relocations[RelocIndex]);
// FIXME: Make separate functions for UE
switch (RelocType) {
case EFI_IMAGE_REL_BASED_ABSOLUTE:
continue;
case EFI_IMAGE_REL_BASED_HIGHLOW:
case EFI_IMAGE_REL_BASED_DIR64:
RelocInfo->Relocs[RelocInfo->NumRelocs].Type = (uint8_t)RelocType;
break;
default:
fprintf (stderr, "ImageTool: Unknown RelocType = 0x%x\n", RelocType);
return false;
}
RelocInfo->Relocs[RelocInfo->NumRelocs].Target = RelocBlock->VirtualAddress + RelocOffset;
++RelocInfo->NumRelocs;
}
//
// This arithmetic cannot overflow because it has been checked that the
// Image Base Relocation Block is in bounds of the Image buffer.
//
RelocBlockRva += RelocBlockSize;
}
//
// Verify the Relocation Directory size matches the contained data.
//
if (RelocBlockRva != TopOfRelocDir) {
fprintf (stderr, "ImageTool: Relocation Directory size does not match the contained data\n");
return false;
}
return true;
}
static
bool
ScanPeGetSegmentInfo (
OUT image_tool_segment_info_t *SegmentInfo,
OUT image_tool_hii_info_t *HiiInfo,
OUT image_tool_reloc_info_t *RelocInfo,
OUT image_tool_debug_info_t *DebugInfo,
IN PE_COFF_LOADER_IMAGE_CONTEXT *Context
)
{
const EFI_IMAGE_SECTION_HEADER *Section;
uint32_t NumSections;
image_tool_segment_t *ImageSegment;
const char *FileBuffer;
uint32_t Index;
UINT32 Size;
const EFI_IMAGE_NT_HEADERS *PeHdr;
const EFI_IMAGE_DATA_DIRECTORY *DebugDir;
UINT32 DebugDirTop;
bool Overflow;
UINT32 IndexD;
const EFI_IMAGE_DEBUG_DIRECTORY_ENTRY *DebugEntry;
const char *CodeView;
UINT32 DebugTop;
UINT32 PdbOffset;
assert (SegmentInfo != NULL);
assert (HiiInfo != NULL);
assert (RelocInfo != NULL);
assert (DebugInfo != NULL);
assert (Context != NULL);
DebugDir = NULL;
SegmentInfo->SegmentAlignment = PeCoffGetSectionAlignment (Context);
NumSections = PeCoffGetSectionTable (Context, &Section);
SegmentInfo->Segments = calloc (NumSections, sizeof (*SegmentInfo->Segments));
if (SegmentInfo->Segments == NULL) {
fprintf (stderr, "ImageTool: Could not allocate memory for Segments[]\n");
return false;
}
FileBuffer = (const char *)Context->FileBuffer;
PeHdr = (const EFI_IMAGE_NT_HEADERS *)(const void *)(FileBuffer + Context->ExeHdrOffset);
if (PeHdr->NumberOfRvaAndSizes > EFI_IMAGE_DIRECTORY_ENTRY_DEBUG) {
DebugDir = PeHdr->DataDirectory + EFI_IMAGE_DIRECTORY_ENTRY_DEBUG;
Overflow = BaseOverflowAddU32 (DebugDir->VirtualAddress, DebugDir->Size, &DebugDirTop);
if (Overflow || (DebugDirTop > Context->SizeOfImage)) {
fprintf (stderr, "ImageTool: Corrupted DEBUG directory entry\n");
DebugDir = NULL;
}
}
ImageSegment = SegmentInfo->Segments;
for (Index = 0; Index < NumSections; ++Index, ++Section) {
STATIC_ASSERT (
sizeof(PE_COFF_SECT_NAME_RELOC) == sizeof(Section->Name) &&
sizeof(PE_COFF_SECT_NAME_RESRC) == sizeof(Section->Name) &&
sizeof(PE_COFF_SECT_NAME_DEBUG) == sizeof(Section->Name),
"Section names exceed section name bounds."
);
if ((Section->Characteristics & EFI_IMAGE_SCN_MEM_DISCARDABLE) == 0
&& memcmp (Section->Name, PE_COFF_SECT_NAME_RELOC, sizeof (Section->Name)) != 0
&& memcmp (Section->Name, PE_COFF_SECT_NAME_RESRC, sizeof (Section->Name)) != 0
&& memcmp (Section->Name, PE_COFF_SECT_NAME_DEBUG, sizeof (Section->Name)) != 0) {
ImageSegment->Name = calloc (1, sizeof (Section->Name));
if (ImageSegment->Name == NULL) {
fprintf (stderr, "ImageTool: Could not allocate memory for Segment Name\n");
return false;
}
memmove (ImageSegment->Name, Section->Name, sizeof (Section->Name));
Size = MAX (Section->VirtualSize, Section->SizeOfRawData);
Size = ALIGN_VALUE (Size, SegmentInfo->SegmentAlignment);
ImageSegment->Data = calloc (1, Size);
if (ImageSegment->Data == NULL) {
fprintf (stderr, "ImageTool: Could not allocate memory for Segment Data\n");
free (ImageSegment->Name);
return false;
}
memmove (ImageSegment->Data, FileBuffer + Section->PointerToRawData, Section->SizeOfRawData);
ImageSegment->DataSize = Size;
ImageSegment->ImageAddress = Section->VirtualAddress;
ImageSegment->ImageSize = Size;
if ((Section->Characteristics & EFI_IMAGE_SCN_MEM_READ) != 0) {
ImageSegment->Read = true;
}
if ((Section->Characteristics & EFI_IMAGE_SCN_MEM_WRITE) != 0) {
ImageSegment->Write = true;
}
if ((Section->Characteristics & EFI_IMAGE_SCN_MEM_EXECUTE) != 0) {
ImageSegment->Execute = true;
}
if (ImageSegment->Execute) {
ImageSegment->Type = ToolImageSectionTypeCode;
} else {
ImageSegment->Type = ToolImageSectionTypeInitialisedData;
}
++SegmentInfo->NumSegments;
++ImageSegment;
} else if (memcmp (Section->Name, PE_COFF_SECT_NAME_RESRC, sizeof (Section->Name)) == 0) {
Size = MAX (Section->VirtualSize, Section->SizeOfRawData);
Size = ALIGN_VALUE (Size, SegmentInfo->SegmentAlignment);
HiiInfo->Data = calloc (1, Size);
if (HiiInfo->Data == NULL) {
fprintf (stderr, "ImageTool: Could not allocate memory for Hii Data\n");
return false;
}
memmove (HiiInfo->Data, FileBuffer + Section->PointerToRawData, Section->SizeOfRawData);
HiiInfo->DataSize = Size;
} else if (memcmp (Section->Name, PE_COFF_SECT_NAME_RELOC, sizeof (Section->Name)) == 0) {
if (!ScanPeGetRelocInfo (RelocInfo, Section, Context)) {
fprintf (stderr, "ImageTool: Could not retrieve reloc info\n");
return false;
}
}
if ((DebugDir != NULL)
&& (DebugDir->VirtualAddress >= Section->VirtualAddress)
&& (DebugDirTop <= Section->VirtualAddress + Section->VirtualSize)) {
DebugEntry = (const EFI_IMAGE_DEBUG_DIRECTORY_ENTRY *)(const void *)(
FileBuffer + Section->PointerToRawData + (DebugDir->VirtualAddress - Section->VirtualAddress));
for (IndexD = 0; (IndexD + sizeof (*DebugEntry)) <= DebugDir->Size; IndexD += sizeof (*DebugEntry), ++DebugEntry) {
if (DebugEntry->Type == EFI_IMAGE_DEBUG_TYPE_CODEVIEW) {
Overflow = BaseOverflowAddU32 (DebugEntry->FileOffset, DebugEntry->SizeOfData, &DebugTop);
if (Overflow || (DebugTop > Context->FileSize)) {
fprintf (stderr, "ImageTool: Corrupted DEBUG information\n");
continue;
}
CodeView = FileBuffer + DebugEntry->FileOffset;
switch (*(const UINT32 *)(const void *) CodeView) {
case CODEVIEW_SIGNATURE_NB10:
PdbOffset = sizeof (EFI_IMAGE_DEBUG_CODEVIEW_NB10_ENTRY);
break;
case CODEVIEW_SIGNATURE_RSDS:
PdbOffset = sizeof (EFI_IMAGE_DEBUG_CODEVIEW_RSDS_ENTRY);
break;
case CODEVIEW_SIGNATURE_MTOC:
PdbOffset = sizeof (EFI_IMAGE_DEBUG_CODEVIEW_MTOC_ENTRY);
break;
default:
fprintf (stderr, "ImageTool: Unknown CODEVIEW_SIGNATURE\n");
continue;
}
Overflow = BaseOverflowSubU32 (DebugEntry->SizeOfData, PdbOffset, &DebugInfo->SymbolsPathLen);
if (Overflow || (DebugInfo->SymbolsPathLen == 0)) {
fprintf (stderr, "ImageTool: Corrupted DEBUG string\n");
continue;
}
DebugInfo->SymbolsPath = calloc (1, DebugInfo->SymbolsPathLen);
if (DebugInfo->SymbolsPath == NULL) {
fprintf (stderr, "ImageTool: Could not allocate memory for SymbolsPath\n");
return false;
}
memmove (DebugInfo->SymbolsPath, CodeView + PdbOffset, DebugInfo->SymbolsPathLen - 1);
}
}
}
}
return true;
}
bool
ScanPeGetDebugInfo (
OUT image_tool_debug_info_t *DebugInfo,
IN PE_COFF_LOADER_IMAGE_CONTEXT *Context
)
{
const CHAR8 *PdbPath;
UINT32 PdbPathSize;
RETURN_STATUS Status;
assert (DebugInfo != NULL);
assert (Context != NULL);
Status = PeCoffGetPdbPath (Context, &PdbPath, &PdbPathSize);
if (Status == RETURN_NOT_FOUND) {
return true;
}
if (RETURN_ERROR (Status)) {
fprintf (stderr, "ImageTool: Could not get PdbPath\n");
return false;
}
DebugInfo->SymbolsPath = calloc (1, PdbPathSize);
if (DebugInfo->SymbolsPath == NULL) {
fprintf (stderr, "ImageTool: Could not allocate memory for SymbolsPath\n");
return false;
}
memmove (DebugInfo->SymbolsPath, PdbPath, PdbPathSize);
assert (PdbPathSize >= 1);
assert (DebugInfo->SymbolsPath[PdbPathSize - 1] == '\0');
DebugInfo->SymbolsPathLen = PdbPathSize - 1;
return true;
}
bool
ScanPeGetHiiInfo (
OUT image_tool_hii_info_t *HiiInfo,
IN PE_COFF_LOADER_IMAGE_CONTEXT *Context
)
{
UINT32 HiiRva;
UINT32 HiiSize;
RETURN_STATUS Status;
const char *ImageBuffer;
assert (HiiInfo != NULL);
assert (Context != NULL);
Status = PeCoffGetHiiDataRva (Context, &HiiRva, &HiiSize);
if (Status == RETURN_NOT_FOUND) {
return true;
}
if (RETURN_ERROR (Status)) {
fprintf (stderr, "ImageTool: Could not get HiiRva\n");
return false;
}
HiiInfo->Data = calloc (1, HiiSize);
if (HiiInfo->Data == NULL) {
fprintf (stderr, "ImageTool: Could not allocate memory for HiiInfo Data\n");
return false;
}
ImageBuffer = (char *)PeCoffLoaderGetImageAddress (Context);
memmove (HiiInfo->Data, ImageBuffer + HiiRva, HiiSize);
HiiInfo->DataSize = HiiSize;
return true;
}
static
bool
FixAddresses (
IN OUT image_tool_image_info_t *Image
)
{
UINT64 SizeOfHeaders;
UINT64 Delta;
UINT32 Index;
UINT32 IndexS;
image_tool_segment_t *Segment;
image_tool_reloc_t *Reloc;
UINT8 *Fixup;
UINT32 Fixup32;
UINT64 Fixup64;
assert (Image != NULL);
SizeOfHeaders = sizeof (EFI_IMAGE_DOS_HEADER) + sizeof (EFI_IMAGE_NT_HEADERS) +
EFI_IMAGE_NUMBER_OF_DIRECTORY_ENTRIES * sizeof (EFI_IMAGE_DATA_DIRECTORY) +
Image->SegmentInfo.NumSegments * sizeof (EFI_IMAGE_SECTION_HEADER);
if (Image->RelocInfo.Relocs != NULL) {
SizeOfHeaders += sizeof (EFI_IMAGE_SECTION_HEADER);
}
if (Image->DebugInfo.SymbolsPath != NULL) {
SizeOfHeaders += sizeof (EFI_IMAGE_SECTION_HEADER);
}
if (Image->HiiInfo.Data != NULL) {
SizeOfHeaders += sizeof (EFI_IMAGE_SECTION_HEADER);
}
SizeOfHeaders = ALIGN_VALUE (SizeOfHeaders, Image->SegmentInfo.SegmentAlignment);
if (SizeOfHeaders == Image->SegmentInfo.Segments[0].ImageAddress) {
return true;
}
Delta = Image->SegmentInfo.Segments[0].ImageAddress - SizeOfHeaders;
Image->HeaderInfo.EntryPointAddress -= (UINT32)Delta;
for (Index = 0; Index < Image->SegmentInfo.NumSegments; ++Index) {
Image->SegmentInfo.Segments[Index].ImageAddress -= Delta;
}
if (Image->RelocInfo.Relocs != NULL) {
Segment = Image->SegmentInfo.Segments;
Reloc = Image->RelocInfo.Relocs;
for (Index = 0; Index < Image->RelocInfo.NumRelocs; ++Index) {
Reloc[Index].Target -= (UINT32)Delta;
for (IndexS = 0; IndexS < Image->SegmentInfo.NumSegments; ++IndexS) {
if ((Reloc[Index].Target >= Segment[IndexS].ImageAddress)
&& ((Reloc[Index].Target - Segment[IndexS].ImageAddress) < Segment[IndexS].ImageSize)) {
Fixup = Segment[IndexS].Data + (Reloc[Index].Target - Segment[IndexS].ImageAddress);
switch (Reloc[Index].Type) {
case EFI_IMAGE_REL_BASED_HIGHLOW:
Fixup32 = ReadUnaligned32 ((CONST VOID *) Fixup);
Fixup32 -= (UINT32)Delta;
WriteUnaligned32 ((VOID *) Fixup, Fixup32);
break;
case EFI_IMAGE_REL_BASED_DIR64:
Fixup64 = ReadUnaligned64 ((CONST VOID *) Fixup);
Fixup64 -= Delta;
WriteUnaligned64 ((VOID *) Fixup, Fixup64);
break;
default:
fprintf (stderr, "ImageTool: Unknown relocation type %u\n", Reloc[Index].Type);
return false;
}
}
}
}
}
if (Image->HiiInfo.Data != NULL) {
SetHiiResourceHeader (Image->HiiInfo.Data, (UINT32)(0ULL - Delta));
}
return true;
}
bool
ToolContextConstructPe (
OUT image_tool_image_info_t *Image,
IN const void *File,
IN size_t FileSize,
IN const char *ModuleType OPTIONAL
)
{
PE_COFF_LOADER_IMAGE_CONTEXT Context;
RETURN_STATUS Status;
bool Result;
assert (Image != NULL);
assert (File != NULL || FileSize == 0);
if (FileSize > MAX_UINT32) {
fprintf (stderr, "ImageTool: FileSize is too huge\n");
return false;
}
Status = PeCoffInitializeContext (&Context, File, (UINT32)FileSize);
if (RETURN_ERROR (Status)) {
fprintf (stderr, "ImageTool: Could not initialise Context\n");
return false;
}
memset (Image, 0, sizeof (*Image));
Result = ScanPeGetHeaderInfo (&Image->HeaderInfo, &Context, ModuleType);
if (!Result) {
fprintf (stderr, "ImageTool: Could not retrieve header info\n");
return false;
}
Result = ScanPeGetSegmentInfo (&Image->SegmentInfo, &Image->HiiInfo, &Image->RelocInfo, &Image->DebugInfo, &Context);
if (!Result) {
fprintf (stderr, "ImageTool: Could not retrieve segment info\n");
return false;
}
Result = FixAddresses (Image);
return Result;
}

View File

@ -0,0 +1,892 @@
/** @file
Copyright (c) 2021, Marvin Häuser. All rights reserved.
SPDX-License-Identifier: BSD-3-Clause
**/
#include "ImageTool.h"
// FIXME: NumSegments <= MAX_UINT8
typedef struct {
uint8_t NumSections;
uint32_t HeaderSize;
uint32_t SegmentHeadersSize;
uint32_t SectionHeadersSize;
} image_tool_emit_ue_hdr_info_t;
typedef struct {
const image_tool_image_info_t *Image;
image_tool_emit_ue_hdr_info_t HdrInfo;
uint32_t SegmentsSize;
uint8_t SegmentsEndPadding;
uint32_t SectionsSize;
uint32_t UnsignedFileSize;
uint32_t RelocTableSize;
uint32_t HiiTableSize;
uint32_t DebugTableSize;
} image_tool_ue_emit_context_t;
static
bool
EmitUeGetHeaderSizes (
const image_tool_image_info_t *Image,
image_tool_emit_ue_hdr_info_t *HdrInfo
)
{
assert (Image != NULL);
assert (HdrInfo != NULL);
if (Image->RelocInfo.NumRelocs > 0) {
++HdrInfo->NumSections;
}
if (Image->HiiInfo.DataSize > 0) {
++HdrInfo->NumSections;
}
//
// A debug section can always be generated; make conditional based on tool arg.
//
++HdrInfo->NumSections;
HdrInfo->SegmentHeadersSize = (uint32_t)Image->SegmentInfo.NumSegments * sizeof (UE_SEGMENT);
HdrInfo->SectionHeadersSize = (uint32_t)HdrInfo->NumSections * sizeof (UE_SECTION);
HdrInfo->HeaderSize = sizeof (UE_HEADER)
+ HdrInfo->SegmentHeadersSize
+ HdrInfo->SectionHeadersSize;
return true;
}
static
bool
EmitUeGetSegmentsSize (
const image_tool_image_info_t *Image,
uint32_t *SegmentsSize
)
{
uint8_t Index;
assert (Image != NULL);
assert (SegmentsSize != NULL);
*SegmentsSize = 0;
for (Index = 0; Index < Image->SegmentInfo.NumSegments; ++Index) {
*SegmentsSize += Image->SegmentInfo.Segments[Index].DataSize;
}
return true;
}
static
bool
EmitUeGetRelocSectionSize (
const image_tool_image_info_t *Image,
uint32_t *RelocsSize
)
{
uint32_t RelocTableSize;
uint32_t BlockAddress;
uint32_t BlockSize;
uint32_t Index;
uint32_t RelocAddress;
assert (Image != NULL);
assert (RelocsSize != NULL);
if (Image->RelocInfo.NumRelocs == 0) {
*RelocsSize = 0;
return true;
}
assert (Image->RelocInfo.NumRelocs <= MAX_UINT32);
RelocTableSize = 0;
BlockAddress = (uint32_t)PAGE (Image->RelocInfo.Relocs[0].Target);
BlockSize = sizeof (UE_RELOCATION_BLOCK);
for (Index = 0; Index < Image->RelocInfo.NumRelocs; ++Index) {
RelocAddress = PAGE (Image->RelocInfo.Relocs[Index].Target);
if (RelocAddress != BlockAddress) {
BlockSize = ALIGN_VALUE (BlockSize, UE_RELOCATION_BLOCK_ALIGNMENT);
RelocTableSize += BlockSize;
BlockAddress = RelocAddress;
BlockSize = sizeof (UE_RELOCATION_BLOCK);
}
BlockSize += sizeof (UINT16);
}
RelocTableSize += BlockSize;
*RelocsSize = RelocTableSize;
return true;
}
static
bool
EmitUeGetHiiSectionSize (
const image_tool_image_info_t *Image,
uint32_t *HiiSize
)
{
assert (Image != NULL);
assert (HiiSize != NULL);
*HiiSize = Image->HiiInfo.DataSize;
return true;
}
static
bool
EmitUeGetDebugSectionSize (
const image_tool_image_info_t *Image,
uint32_t *DebugSize
)
{
assert (Image != NULL);
assert (DebugSize != NULL);
static_assert (
MAX_UINT8 <= (MAX_UINT32 - MAX_UINT8 - sizeof (UE_DEBUG_TABLE)) / sizeof (UE_SEGMENT_NAME),
"The following arithmetics may overflow."
);
*DebugSize = sizeof (UE_DEBUG_TABLE) + Image->SegmentInfo.NumSegments * sizeof (UE_SEGMENT_NAME);
if (Image->DebugInfo.SymbolsPath != NULL) {
assert (Image->DebugInfo.SymbolsPathLen <= MAX_UINT8);
*DebugSize += Image->DebugInfo.SymbolsPathLen;
}
return true;
}
static
bool
EmitUeGetSectionsSize (
image_tool_ue_emit_context_t *Context,
uint32_t *SectionsSize
)
{
const image_tool_image_info_t *Image;
bool Result;
uint32_t AlignedRelocTableSize;
bool Overflow;
uint32_t AlignedDebugTableSize;
uint32_t AlignedHiiTableSize;
assert (Context != NULL);
assert (SectionsSize != NULL);
Image = Context->Image;
Result = EmitUeGetRelocSectionSize (Image, &Context->RelocTableSize);
if (!Result) {
raise ();
return false;
}
Result = EmitUeGetDebugSectionSize (Image, &Context->DebugTableSize);
if (!Result) {
raise ();
return false;
}
Result = EmitUeGetHiiSectionSize (Image, &Context->HiiTableSize);
if (!Result) {
raise ();
return false;
}
Overflow = BaseOverflowAlignUpU32 (
Context->RelocTableSize,
UE_SECTION_ALIGNMENT,
&AlignedRelocTableSize
);
if (Overflow) {
raise ();
return false;
}
Overflow = BaseOverflowAlignUpU32 (
Context->DebugTableSize,
UE_SECTION_ALIGNMENT,
&AlignedDebugTableSize
);
if (Overflow) {
raise ();
return false;
}
Overflow = BaseOverflowAlignUpU32 (
Context->HiiTableSize,
UE_SECTION_ALIGNMENT,
&AlignedHiiTableSize
);
if (Overflow) {
raise ();
return false;
}
Overflow = BaseOverflowAddU32 (
AlignedRelocTableSize,
AlignedDebugTableSize,
SectionsSize
);
if (Overflow) {
raise ();
return false;
}
assert (IS_ALIGNED (*SectionsSize, UE_SECTION_ALIGNMENT));
Overflow = BaseOverflowAddU32 (
*SectionsSize,
AlignedHiiTableSize,
SectionsSize
);
if (Overflow) {
raise ();
return false;
}
assert (IS_ALIGNED (*SectionsSize, UE_SECTION_ALIGNMENT));
return true;
}
static
uint8_t
AlignmentToExponent (
uint64_t Alignment
)
{
uint8_t Index;
assert (IS_POW2 (Alignment));
for (Index = 0; Index < 64; ++Index) {
if ((Alignment & (1ULL << Index)) == Alignment) {
return Index;
}
}
return 0;
}
static
bool
ToolImageEmitUeSegmentHeaders (
const image_tool_ue_emit_context_t *Context,
uint8_t **Buffer,
uint32_t *BufferSize
)
{
const image_tool_image_info_t *Image;
uint16_t SegmentHeadersSize;
UE_SEGMENT *Segments;
uint8_t Index;
assert (Context != NULL);
assert (Buffer != NULL);
assert (BufferSize != NULL);
Image = Context->Image;
SegmentHeadersSize = (uint16_t)(Image->SegmentInfo.NumSegments * sizeof (UE_SEGMENT));
assert (SegmentHeadersSize <= *BufferSize);
Segments = (void *)*Buffer;
for (Index = 0; Index < Image->SegmentInfo.NumSegments; ++Index) {
// FIXME:
Image->SegmentInfo.Segments[Index].ImageSize = ALIGN_VALUE (Image->SegmentInfo.Segments[Index].ImageSize, Image->SegmentInfo.SegmentAlignment);
Segments[Index].ImageInfo = Image->SegmentInfo.Segments[Index].ImageSize;
if (!Image->SegmentInfo.Segments[Index].Read) {
Segments[Index].ImageInfo |= UE_SEGMENT_INFO_RP;
}
if (!Image->SegmentInfo.Segments[Index].Write) {
Segments[Index].ImageInfo |= UE_SEGMENT_INFO_RO;
}
if (!Image->SegmentInfo.Segments[Index].Execute) {
Segments[Index].ImageInfo |= UE_SEGMENT_INFO_XP;
}
assert (UE_SEGMENT_SIZE (Segments[Index].ImageInfo) == Image->SegmentInfo.Segments[Index].ImageSize);
Segments[Index].FileSize = Image->SegmentInfo.Segments[Index].DataSize;
}
*BufferSize -= SegmentHeadersSize;
*Buffer += SegmentHeadersSize;
assert (SegmentHeadersSize == Context->HdrInfo.SegmentHeadersSize);
return true;
}
static
bool
ToolImageEmitUeSectionHeaders (
const image_tool_ue_emit_context_t *Context,
uint8_t **Buffer,
uint32_t *BufferSize
)
{
uint32_t SectionHeadersSize;
UE_SECTION *Section;
uint32_t AlignedRelocTableSize;
uint32_t AlignedDebugTableSize;
uint32_t AlignedHiiTableSize;
assert (Context != NULL);
assert (Buffer != NULL);
assert (BufferSize != NULL);
SectionHeadersSize = 0;
if (Context->RelocTableSize > 0) {
assert (sizeof (UE_SECTION) <= *BufferSize);
Section = (void *)*Buffer;
AlignedRelocTableSize = ALIGN_VALUE (Context->RelocTableSize, UE_SECTION_ALIGNMENT);
Section->FileInfo = AlignedRelocTableSize;
Section->FileInfo |= UeSectionIdRelocTable;
assert (UE_SECTION_ID (Section->FileInfo) == UeSectionIdRelocTable);
assert (UE_SECTION_SIZE (Section->FileInfo) == AlignedRelocTableSize);
*BufferSize -= sizeof (UE_SECTION);
*Buffer += sizeof (UE_SECTION);
SectionHeadersSize += sizeof (UE_SECTION);
}
if (Context->DebugTableSize > 0) {
assert (sizeof (UE_SECTION) <= *BufferSize);
Section = (void *)*Buffer;
AlignedDebugTableSize = ALIGN_VALUE (Context->DebugTableSize, UE_SECTION_ALIGNMENT);
Section->FileInfo = AlignedDebugTableSize;
Section->FileInfo |= UeSectionIdDebugTable;
assert (UE_SECTION_ID (Section->FileInfo) == UeSectionIdDebugTable);
assert (UE_SECTION_SIZE (Section->FileInfo) == AlignedDebugTableSize);
*BufferSize -= sizeof (UE_SECTION);
*Buffer += sizeof (UE_SECTION);
SectionHeadersSize += sizeof (UE_SECTION);
}
if (Context->HiiTableSize > 0) {
assert (sizeof (UE_SECTION) <= *BufferSize);
Section = (void *)*Buffer;
AlignedHiiTableSize = ALIGN_VALUE (Context->HiiTableSize, UE_SECTION_ALIGNMENT);
Section->FileInfo = AlignedHiiTableSize;
Section->FileInfo |= UeSectionIdHiiTable;
assert (UE_SECTION_ID (Section->FileInfo) == UeSectionIdHiiTable);
assert (UE_SECTION_SIZE (Section->FileInfo) == AlignedHiiTableSize);
*BufferSize -= sizeof (UE_SECTION);
*Buffer += sizeof (UE_SECTION);
SectionHeadersSize += sizeof (UE_SECTION);
}
assert (Context->HdrInfo.SectionHeadersSize == SectionHeadersSize);
return true;
}
static
bool
ToolImageEmitUeHeader (
const image_tool_ue_emit_context_t *Context,
uint8_t **Buffer,
uint32_t *BufferSize
)
{
UE_HEADER *UeHdr;
const image_tool_image_info_t *Image;
uint8_t AlignmentExponent;
bool Result;
assert (Context != NULL);
assert (Buffer != NULL);
assert (BufferSize != NULL);
assert (sizeof(UE_HEADER) <= *BufferSize);
UeHdr = (void *)*Buffer;
UeHdr->Signature = UE_HEADER_SIGNATURE;
Image = Context->Image;
AlignmentExponent = AlignmentToExponent (Image->SegmentInfo.SegmentAlignment);
UeHdr->ImageInfo = AlignmentExponent;
if (Image->RelocInfo.RelocsStripped) {
UeHdr->ImageInfo |= UE_HEADER_FLAG_RELOCS_STRIPPED;
}
assert (UE_HEADER_ALIGNMENT (UeHdr->ImageInfo) == 1U << AlignmentExponent);
assert (Image->SegmentInfo.NumSegments > 0);
UeHdr->LastSegmentIndex = (UINT8)(Image->SegmentInfo.NumSegments - 1);
UeHdr->NumSections = Context->HdrInfo.NumSections;
UeHdr->Subsystem = (UINT8)Image->HeaderInfo.Subsystem;
UeHdr->Machine = (UINT8)Image->HeaderInfo.Machine;
UeHdr->PreferredAddress = Image->HeaderInfo.PreferredAddress;
UeHdr->EntryPointAddress = Image->HeaderInfo.EntryPointAddress;
UeHdr->ImageInfo2 = Context->UnsignedFileSize;
assert (UeHdr->ImageInfo2 == UE_HEADER_UNSIGNED_SIZE (UeHdr->ImageInfo2));
assert (UeHdr->Reserved == 0);
STATIC_ASSERT (
OFFSET_OF (UE_HEADER, Segments) == sizeof (UE_HEADER),
"The following code needs to be updated to consider padding."
);
*BufferSize -= sizeof (UE_HEADER);
*Buffer += sizeof (UE_HEADER);
Result = ToolImageEmitUeSegmentHeaders (Context, Buffer, BufferSize);
if (!Result) {
return false;
}
Result = ToolImageEmitUeSectionHeaders (Context, Buffer, BufferSize);
if (!Result) {
return false;
}
return true;
}
static
bool
ToolImageEmitUeSegments (
const image_tool_ue_emit_context_t *Context,
uint8_t **Buffer,
uint32_t *BufferSize
)
{
const image_tool_image_info_t *Image;
uint32_t SegmentsSize;
uint8_t Index;
size_t DataSize;
assert (Context != NULL);
assert (Buffer != NULL);
assert (BufferSize != NULL);
Image = Context->Image;
SegmentsSize = 0;
for (Index = 0; Index < Image->SegmentInfo.NumSegments; ++Index) {
assert (Image->SegmentInfo.Segments[Index].DataSize <= *BufferSize);
DataSize = Image->SegmentInfo.Segments[Index].DataSize;
memmove (*Buffer, Image->SegmentInfo.Segments[Index].Data, DataSize);
*BufferSize -= DataSize;
*Buffer += DataSize;
SegmentsSize += DataSize;
}
assert (SegmentsSize == Context->SegmentsSize);
*BufferSize -= Context->SegmentsEndPadding;
*Buffer += Context->SegmentsEndPadding;
return true;
}
static
bool
ToolImageEmitUeRelocTable (
const image_tool_ue_emit_context_t *Context,
uint8_t **Buffer,
uint32_t *BufferSize
)
{
const image_tool_image_info_t *Image;
uint32_t RelocTableSize;
UE_RELOCATION_BLOCK *RelocBlock;
uint32_t BlockAddress;
uint32_t BlockNumRelocs;
uint32_t BlockSize;
uint32_t Index;
uint32_t RelocAddress;
uint32_t RelocTablePadding;
assert (Context != NULL);
assert (Buffer != NULL);
assert (BufferSize != NULL);
if (Context->RelocTableSize == 0) {
return true;
}
Image = Context->Image;
assert (Image->RelocInfo.NumRelocs > 0);
assert (Image->RelocInfo.NumRelocs <= MAX_UINT32);
assert (sizeof(UE_RELOCATION_BLOCK) <= *BufferSize);
RelocTableSize = 0;
RelocBlock = (void *)*Buffer;
BlockAddress = (uint32_t)PAGE (Image->RelocInfo.Relocs[0].Target);
BlockNumRelocs = 0;
BlockSize = sizeof (*RelocBlock);
RelocBlock->BlockInfo = BlockAddress;
for (Index = 0; Index < Image->RelocInfo.NumRelocs; ++Index) {
RelocAddress = PAGE (Image->RelocInfo.Relocs[Index].Target);
if (RelocAddress != BlockAddress) {
BlockSize = ALIGN_VALUE (BlockSize, UE_RELOCATION_BLOCK_ALIGNMENT);
assert (BlockSize <= *BufferSize);
*BufferSize -= BlockSize;
*Buffer += BlockSize;
RelocTableSize += BlockSize;
RelocBlock = (void *)*Buffer;
BlockAddress = RelocAddress;
BlockNumRelocs = 0;
BlockSize = sizeof (*RelocBlock);
RelocBlock->BlockInfo = BlockAddress;
}
BlockSize += sizeof (*RelocBlock->RelocInfo);
assert (BlockSize <= *BufferSize);
RelocBlock->RelocInfo[BlockNumRelocs] = PAGE_OFF (Image->RelocInfo.Relocs[Index].Target);
RelocBlock->RelocInfo[BlockNumRelocs] |= Image->RelocInfo.Relocs[Index].Type << 12U;
assert (UE_RELOC_OFFSET (RelocBlock->RelocInfo[BlockNumRelocs]) == PAGE_OFF (Image->RelocInfo.Relocs[Index].Target));
assert (UE_RELOC_TYPE (RelocBlock->RelocInfo[BlockNumRelocs]) == Image->RelocInfo.Relocs[Index].Type);
++BlockNumRelocs;
if (BlockNumRelocs > UE_RELOCATION_BLOCK_MAX_RELOCS) {
return false;
}
++RelocBlock->BlockInfo;
assert (BlockNumRelocs == UE_RELOC_BLOCK_NUM (RelocBlock->BlockInfo));
assert (BlockAddress == UE_RELOC_BLOCK_ADDRESS (RelocBlock->BlockInfo));
}
*BufferSize -= BlockSize;
*Buffer += BlockSize;
RelocTableSize += BlockSize;
assert (RelocTableSize == Context->RelocTableSize);
RelocTablePadding = ALIGN_VALUE_ADDEND (RelocTableSize, UE_SECTION_ALIGNMENT);
assert (RelocTablePadding <= *BufferSize);
*BufferSize -= RelocTablePadding;
*Buffer += RelocTablePadding;
return true;
}
static
bool
ToolImageEmitUeDebugTable (
const image_tool_ue_emit_context_t *Context,
uint8_t **Buffer,
uint32_t *BufferSize
)
{
uint32_t DebugTableSize;
UE_DEBUG_TABLE *DebugTable;
const image_tool_image_info_t *Image;
uint8_t Index;
UE_SEGMENT_NAME *SectionName;
uint32_t DebugTablePadding;
assert (Context != NULL);
assert (Buffer != NULL);
assert (BufferSize != NULL);
assert (sizeof (UE_DEBUG_TABLE) <= *BufferSize);
DebugTableSize = sizeof (UE_DEBUG_TABLE);
DebugTable = (void *)*Buffer;
assert (DebugTable->SymbolsBaseOffset == 0);
assert (DebugTable->Reserved == 0);
Image = Context->Image;
*BufferSize -= sizeof (UE_DEBUG_TABLE);
*Buffer += sizeof (UE_DEBUG_TABLE);
if (Image->DebugInfo.SymbolsPath != NULL) {
assert (Image->DebugInfo.SymbolsPathLen <= MAX_UINT8);
DebugTable->SymbolsPathSize = (uint8_t)Image->DebugInfo.SymbolsPathLen;
assert (Image->DebugInfo.SymbolsPathLen <= *BufferSize);
DebugTableSize += Image->DebugInfo.SymbolsPathLen;
memmove (*Buffer, Image->DebugInfo.SymbolsPath, Image->DebugInfo.SymbolsPathLen);
*BufferSize -= Image->DebugInfo.SymbolsPathLen;
*Buffer += Image->DebugInfo.SymbolsPathLen;
} else {
assert (DebugTable->SymbolsPathSize == 0);
}
for (Index = 0; Index < Image->SegmentInfo.NumSegments; ++Index) {
assert (sizeof (UE_SEGMENT_NAME) <= *BufferSize);
DebugTableSize += sizeof (UE_SEGMENT_NAME);
SectionName = (void *)*Buffer;
strncpy (
(char *)SectionName,
Image->SegmentInfo.Segments[Index].Name,
sizeof (*SectionName)
);
*BufferSize -= sizeof (*SectionName);
*Buffer += sizeof (*SectionName);
}
assert (DebugTableSize == Context->DebugTableSize);
DebugTablePadding = ALIGN_VALUE_ADDEND (DebugTableSize, UE_SECTION_ALIGNMENT);
assert (DebugTablePadding <= *BufferSize);
*BufferSize -= DebugTablePadding;
*Buffer += DebugTablePadding;
return true;
}
static
bool
ToolImageEmitUeHiiTable (
const image_tool_ue_emit_context_t *Context,
uint8_t **Buffer,
uint32_t *BufferSize
)
{
const image_tool_image_info_t *Image;
uint32_t HiiTablePadding;
assert (Context != NULL);
assert (Buffer != NULL);
assert (BufferSize != NULL);
Image = Context->Image;
if (Context->HiiTableSize == 0) {
return true;
}
assert (Image->HiiInfo.DataSize == Context->HiiTableSize);
assert (Context->HiiTableSize <= *BufferSize);
memmove (*Buffer, Image->HiiInfo.Data, Image->HiiInfo.DataSize);
*BufferSize -= Image->HiiInfo.DataSize;
*Buffer += Image->HiiInfo.DataSize;
HiiTablePadding = ALIGN_VALUE_ADDEND (Image->HiiInfo.DataSize, UE_SECTION_ALIGNMENT);
assert (HiiTablePadding <= *BufferSize);
*BufferSize -= HiiTablePadding;
*Buffer += HiiTablePadding;
return true;
}
static
bool
ToolImageEmitUeSections (
const image_tool_ue_emit_context_t *Context,
uint8_t **Buffer,
uint32_t *BufferSize
)
{
uint32_t OldBufferSize;
bool Result;
assert (Context != NULL);
assert (Buffer != NULL);
assert (BufferSize != NULL);
OldBufferSize = *BufferSize;
Result = ToolImageEmitUeRelocTable (Context, Buffer, BufferSize);
if (!Result) {
return false;
}
Result = ToolImageEmitUeDebugTable (Context, Buffer, BufferSize);
if (!Result) {
return false;
}
Result = ToolImageEmitUeHiiTable (Context, Buffer, BufferSize);
if (!Result) {
return false;
}
assert ((OldBufferSize - *BufferSize) == Context->SectionsSize);
return true;
}
void *
ToolImageEmitUe (
const image_tool_image_info_t *Image,
uint32_t *FileSize
)
{
image_tool_ue_emit_context_t Context;
bool Result;
uint32_t SectionsOffset;
bool Overflow;
void *FileBuffer;
uint8_t *Buffer;
uint32_t RemainingSize;
uint32_t ExpectedSize;
assert (Image != NULL);
assert (FileSize != NULL);
memset (&Context, 0, sizeof (Context));
Context.Image = Image;
Result = EmitUeGetHeaderSizes (Image, &Context.HdrInfo);
if (!Result) {
raise ();
return NULL;
}
Result = EmitUeGetSegmentsSize (Image, &Context.SegmentsSize);
if (!Result) {
raise ();
return NULL;
}
Overflow = BaseOverflowAddU32 (
Context.HdrInfo.HeaderSize,
Context.SegmentsSize,
&SectionsOffset
);
if (Overflow) {
raise ();
return NULL;
}
Context.SegmentsEndPadding = ALIGN_VALUE_ADDEND (SectionsOffset, UE_SECTION_ALIGNMENT);
Overflow = BaseOverflowAddU32 (
SectionsOffset,
Context.SegmentsEndPadding,
&SectionsOffset
);
if (Overflow) {
raise ();
return NULL;
}
Result = EmitUeGetSectionsSize (&Context, &Context.SectionsSize);
if (!Result) {
raise ();
return NULL;
}
assert (IS_ALIGNED (Context.SectionsSize, UE_SECTION_ALIGNMENT));
Overflow = BaseOverflowAddU32 (
SectionsOffset,
Context.SectionsSize,
&Context.UnsignedFileSize
);
if (Overflow) {
raise ();
return NULL;
}
assert (IS_ALIGNED (Context.UnsignedFileSize, UE_SECTION_ALIGNMENT));
FileBuffer = calloc (1, Context.UnsignedFileSize);
if (FileBuffer == NULL) {
raise ();
return NULL;
}
Buffer = FileBuffer;
RemainingSize = Context.UnsignedFileSize;
ExpectedSize = Context.UnsignedFileSize;
Result = ToolImageEmitUeHeader (&Context, &Buffer, &RemainingSize);
if (!Result) {
raise ();
free (FileBuffer);
return NULL;
}
ExpectedSize -= Context.HdrInfo.HeaderSize;
assert (RemainingSize == ExpectedSize);
Result = ToolImageEmitUeSegments (&Context, &Buffer, &RemainingSize);
if (!Result) {
raise ();
free (FileBuffer);
return NULL;
}
ExpectedSize -= Context.SegmentsSize + Context.SegmentsEndPadding;
assert (RemainingSize == ExpectedSize);
Result = ToolImageEmitUeSections (&Context, &Buffer, &RemainingSize);
if (!Result) {
raise ();
free (FileBuffer);
return NULL;
}
ExpectedSize -= Context.SectionsSize;
assert (RemainingSize == ExpectedSize);
assert (RemainingSize == 0);
*FileSize = Context.UnsignedFileSize;
return FileBuffer;
}

View File

@ -9,13 +9,13 @@
!ERROR "BASE_TOOLS_PATH is not set! Please run toolsetup.bat first!"
!ENDIF
SUBDIRS = $(BASE_TOOLS_PATH)\Source\C $(BASE_TOOLS_PATH)\Source\Python
SUBDIRS = $(BASE_TOOLS_PATH)\Source\C $(BASE_TOOLS_PATH)\Source\Python $(BASE_TOOLS_PATH)\ImageTool $(BASE_TOOLS_PATH)\MicroTool
all: c
c :
@if defined PYTHON_COMMAND $(PYTHON_COMMAND) $(BASE_TOOLS_PATH)\Source\C\Makefiles\NmakeSubdirs.py all $(BASE_TOOLS_PATH)\Source\C
@if not defined PYTHON_COMMAND $(PYTHON_HOME)\python.exe $(BASE_TOOLS_PATH)\Source\C\Makefiles\NmakeSubdirs.py all $(BASE_TOOLS_PATH)\Source\C
@if defined PYTHON_COMMAND $(PYTHON_COMMAND) $(BASE_TOOLS_PATH)\Source\C\Makefiles\NmakeSubdirs.py all $(BASE_TOOLS_PATH)\Source\C $(BASE_TOOLS_PATH)\ImageTool $(BASE_TOOLS_PATH)\MicroTool
@if not defined PYTHON_COMMAND $(PYTHON_HOME)\python.exe $(BASE_TOOLS_PATH)\Source\C\Makefiles\NmakeSubdirs.py all $(BASE_TOOLS_PATH)\Source\C $(BASE_TOOLS_PATH)\ImageTool $(BASE_TOOLS_PATH)\MicroTool
subdirs: $(SUBDIRS)
@ -31,4 +31,3 @@ clean:
cleanall:
@if defined PYTHON_COMMAND $(PYTHON_COMMAND) $(BASE_TOOLS_PATH)\Source\C\Makefiles\NmakeSubdirs.py cleanall $(SUBDIRS)
@if not defined PYTHON_COMMAND $(PYTHON_HOME)\python.exe $(BASE_TOOLS_PATH)\Source\C\Makefiles\NmakeSubdirs.py cleanall $(SUBDIRS)

View File

@ -0,0 +1,15 @@
## @file
# Copyright (c) 2022, Mikhail Krichanov. All rights reserved.
# SPDX-License-Identifier: BSD-3-Clause
##
PROJECT = MicroTool
PRODUCT = $(PROJECT)$(INFIX)$(SUFFIX)
OBJS = $(PROJECT).o
DEBUG = 1
SANITIZE = 0
OC_USER = ../../OpenCorePkg
UDK_PATH = ../..
include $(OC_USER)/User/Makefile

View File

@ -0,0 +1,73 @@
## @file
# Windows makefile for 'MicroTool' module build.
#
# Copyright (c) 2022, Mikhail Krichanov. All rights reserved.
# SPDX-License-Identifier: BSD-3-Clause
#
!INCLUDE ..\Source\C\Makefiles\ms.common
APP = MicroTool
OC_USER = ..\..\OpenCorePkg
UDK_PATH = ..\..
UDK_ARCH = $(HOST_ARCH)
OUT_DIR = .\Windows
OBJECTS = MicroTool.obj
BASE = $(UDK_PATH)\MdePkg\Library\BaseLib
OUT = $(UDK_PATH)\MdePkg\Library\UefiDebugLibConOut
PRIN = $(UDK_PATH)\MdePkg\Library\BasePrintLib
ERRO = $(UDK_PATH)\MdePkg\Library\BaseDebugPrintErrorLevelLib
USER = $(OC_USER)\User\Library
OBJECTS = $(OBJECTS) {$(BASE)}SafeString.obj String.obj SwapBytes16.obj SwapBytes32.obj CpuDeadLoop.obj
OBJECTS = $(OBJECTS) {$(OUT)}DebugLib.obj {$(PRIN)}PrintLib.obj PrintLibInternal.obj {$(ERRO)}BaseDebugPrintErrorLevelLib.obj
OBJECTS = $(OBJECTS) {$(USER)}UserFile.obj UserBaseMemoryLib.obj UserMath.obj UserPcd.obj UserMisc.obj UserGlobalVar.obj UserBootServices.obj
INC = -I . -I $(OC_USER)\User\Include -I $(OC_USER)\Include\Acidanthera
INC = $(INC) -I $(UDK_PATH)\MdePkg\Include -I $(UDK_PATH)\MdePkg\Include\Library -I $(UDK_PATH)\MdePkg\Include\$(UDK_ARCH)
INC = $(INC) -I $(UDK_PATH)\MdePkg\Library\BaseLib -I $(UDK_PATH)\MdeModulePkg\Include -I $(UDK_PATH)\UefiCpuPkg\Include
INC = $(INC) /FI $(OC_USER)\User\Include\UserPcd.h /FI $(UDK_PATH)\MdePkg\Include\Base.h /FI $(OC_USER)\User\Include\UserGlobalVar.h
all:
-@if not exist $(OUT_DIR) mkdir $(OUT_DIR)
$(MAKE) $(APP)
$(APP) : $(OBJECTS)
-@if not exist $(BIN_PATH) mkdir $(BIN_PATH)
@cd $(OUT_DIR)
$(LD) /nologo /debug /OPT:REF /OPT:ICF=10 /incremental:no /nodefaultlib:libc.lib /out:..\$@ $(LIBS) $**
@copy /y ..\$@ $(BIN_PATH)\$@.exe
.PHONY:clean
.PHONY:cleanall
clean:
del /f /q $(OUT_DIR) $(APP) *.pdb > nul
cleanall:
del /f /q $(OUT_DIR) *.pdb $(BIN_PATH)\$(APP).exe $(BIN_PATH)\$(APP).exe > nul
.c.obj :
$(CC) -c $(CFLAGS) $(INC) $< -Fo$@
@move $@ $(OUT_DIR)\
{$(BASE)}.c.obj :
$(CC) -c $(CFLAGS) $(INC) /wd 4005 $< -Fo$@
@move $@ $(OUT_DIR)\
{$(OUT)}.c.obj :
$(CC) -c $(CFLAGS) $(INC) $< -Fo$@
@move $@ $(OUT_DIR)\
{$(PRIN)}.c.obj :
$(CC) -c $(CFLAGS) $(INC) /wd 4005 $< -Fo$@
@move $@ $(OUT_DIR)\
{$(ERRO)}.c.obj :
$(CC) -c $(CFLAGS) $(INC) $< -Fo$@
@move $@ $(OUT_DIR)\
{$(USER)}.c.obj :
$(CC) -c $(CFLAGS) $(INC) /D WIN32 /wd 4754 $< -Fo$@
@move $@ $(OUT_DIR)\

View File

@ -0,0 +1,298 @@
/** @file
Copyright (c) 2022, Mikhail Krichanov. All rights reserved.
SPDX-License-Identifier: BSD-3-Clause
**/
#include <assert.h>
#include <ctype.h>
#include <errno.h>
#include <stdbool.h>
#include <UserFile.h>
#define DEFAULT_MC_ALIGNMENT 16
#define DEFAULT_MC_PAD_BYTE_VALUE 0xFF
typedef struct {
UINT32 HeaderVersion;
UINT32 PatchId;
UINT32 Date;
UINT32 CpuId;
UINT32 Checksum;
UINT32 LoaderVersion;
UINT32 PlatformId;
UINT32 DataSize; // if 0, then TotalSize = 2048, and TotalSize field is invalid
UINT32 TotalSize; // number of bytes
UINT32 Reserved[3];
} MICROCODE_HEADER;
static
RETURN_STATUS
TxtToBin (
IN const char *TxtName,
IN const char *BinName
)
{
char *Txt;
char *TxtStart;
uint32_t TxtSize;
UINT32 *Buffer;
UINT32 *BufferStart;
UINT32 FileLength;
UINT32 Index;
MICROCODE_HEADER *Micro;
UINT32 CheckSum;
assert (TxtName != NULL);
assert (BinName != NULL);
Txt = (char *)UserReadFile (TxtName, &TxtSize);
if (Txt == NULL) {
fprintf (stderr, "MicroTool: Could not open %s: %s\n", TxtName, strerror (errno));
return RETURN_ABORTED;
}
Buffer = calloc (1, TxtSize);
if (Buffer == NULL) {
fprintf (stderr, "MicroTool: Could not allocate memory for Buffer\n");
free (Txt);
return RETURN_OUT_OF_RESOURCES;
}
BufferStart = Buffer;
TxtStart = Txt;
FileLength = 0;
for (Index = 0; Index < TxtSize; ++Index, ++Txt) {
//
// Skip Blank Lines and Comment Lines
//
if (isspace ((int)*Txt)) {
continue;
}
if (*Txt == ';') {
while ((Index < TxtSize) && (*Txt != '\n')) {
++Index;
++Txt;
}
if (Index == TxtSize) {
break;
}
++Index;
++Txt;
}
//
// Look for
// dd 000000001h ; comment
// dd XXXXXXXX
// DD XXXXXXXXX
// DD XXXXXXXXX
//
if (((Index + 2) < TxtSize) && (tolower ((int)Txt[0]) == 'd') && (tolower ((int)Txt[1]) == 'd') && isspace ((int)Txt[2])) {
//
// Skip blanks and look for a hex digit
//
Txt += 3;
Index += 3;
while ((Index < TxtSize) && isspace ((int)*Txt)) {
++Index;
++Txt;
}
if (Index == TxtSize) {
break;
}
if (isxdigit ((int)*Txt)) {
if (sscanf (Txt, "%X", Buffer) != 1) {
fprintf (stderr, "MicroTool: Could not write into Buffer\n");
free (TxtStart);
free (BufferStart);
return RETURN_ABORTED;
}
while ((Index < TxtSize) && (*Txt != '\n')) {
++Index;
++Txt;
}
}
++Buffer;
FileLength += sizeof (*Buffer);
continue;
}
fprintf (stderr, "MicroTool: Corrupted input file\n");
break;
}
free (TxtStart);
if (FileLength == 0) {
fprintf (stderr, "MicroTool: No parseable data found in file %s\n", TxtName);
free (BufferStart);
return RETURN_INVALID_PARAMETER;
}
if (FileLength < sizeof (MICROCODE_HEADER)) {
fprintf (stderr, "MicroTool: Amount of parsable data in %s is insufficient to contain a microcode header\n", TxtName);
free (BufferStart);
return RETURN_VOLUME_CORRUPTED;
}
//
// Can't do much checking on the header because, per the spec, the
// DataSize field may be 0, which means DataSize = 2000 and TotalSize = 2K,
// and the TotalSize field is invalid (actually missing). Thus we can't
// even verify the Reserved fields are 0.
//
Micro = (MICROCODE_HEADER *)BufferStart;
if (Micro->DataSize == 0) {
Index = 2048;
} else {
Index = Micro->TotalSize;
}
if (Index != FileLength) {
fprintf (stderr, "MicroTool: File length of %s (0x%x) does not equal expected TotalSize: 0x%04X\n", TxtName, FileLength, Index);
free (BufferStart);
return RETURN_VOLUME_CORRUPTED;
}
//
// Checksum the contents
//
Buffer = BufferStart;
CheckSum = 0;
Index = 0;
while (Index < FileLength) {
CheckSum += *Buffer;
++Buffer;
Index += sizeof (*Buffer);
}
if (CheckSum != 0) {
fprintf (stderr, "MicroTool: Checksum (0x%x) failed on file %s\n", CheckSum, TxtName);
free (BufferStart);
return RETURN_VOLUME_CORRUPTED;
}
UserWriteFile (BinName, BufferStart, FileLength);
free (BufferStart);
return RETURN_SUCCESS;
}
static
RETURN_STATUS
Merge (
IN const char *Output,
IN const char *FileNames[],
IN UINT32 NumOfFiles
)
{
void *File;
uint32_t FileSize;
UINT32 Index;
UINT32 Total;
char *Buffer;
char *BufferStart;
UINT32 Addend;
assert (Output != NULL);
assert (FileNames != NULL);
Total = 0;
for (Index = 0; Index < NumOfFiles; ++Index) {
File = UserReadFile (FileNames[Index], &FileSize);
if (File == NULL) {
fprintf (stderr, "MicroTool: Could not open %s: %s\n", FileNames[Index], strerror (errno));
return RETURN_ABORTED;
}
Total += ALIGN_VALUE (FileSize, DEFAULT_MC_ALIGNMENT);
free (File);
}
Buffer = calloc (1, Total);
if (Buffer == NULL) {
fprintf (stderr, "MicroTool: Could not allocate memory for Buffer\n");
return RETURN_OUT_OF_RESOURCES;
}
BufferStart = Buffer;
for (Index = 0; Index < NumOfFiles; ++Index) {
File = UserReadFile (FileNames[Index], &FileSize);
if (File == NULL) {
fprintf (stderr, "MicroTool: Could not reopen %s: %s\n", FileNames[Index], strerror (errno));
free (BufferStart);
return RETURN_ABORTED;
}
memcpy (Buffer, File, FileSize);
Buffer += FileSize;
Addend = ALIGN_VALUE_ADDEND (FileSize, DEFAULT_MC_ALIGNMENT);
memset (Buffer, DEFAULT_MC_PAD_BYTE_VALUE, Addend);
Buffer += Addend;
free (File);
}
UserWriteFile (Output, BufferStart, Total);
free (BufferStart);
return RETURN_SUCCESS;
}
int main (int argc, const char *argv[])
{
RETURN_STATUS Status;
UINT32 NumOfFiles;
if (argc < 2) {
fprintf (stderr, "MicroTool: No command is specified\n");
assert (false);
return -1;
}
if (strcmp (argv[1], "TxtToBin") == 0) {
if (argc < 4) {
fprintf (stderr, "MicroTool: Command arguments are missing\n");
fprintf (stderr, " Usage: MicroTool TxtToBin InputFile OutputFile\n");
assert (false);
return -1;
}
Status = TxtToBin (argv[2], argv [3]);
if (RETURN_ERROR (Status)) {
assert (false);
return -1;
}
} else if (strcmp (argv[1], "Merge") == 0) {
if (argc < 4) {
fprintf (stderr, "MicroTool: Command arguments are missing\n");
fprintf (stderr, " Usage: MicroTool Merge OutputFile InputFile1 InputFile2 ...\n");
assert (false);
return -1;
}
NumOfFiles = (UINT32)argc - 3U;
Status = Merge (argv[2], &argv[3], NumOfFiles);
if (RETURN_ERROR (Status)) {
assert (false);
return -1;
}
}
return 0;
}

View File

@ -3591,7 +3591,7 @@ Returns:
return EFI_SUCCESS;
}
EFI_PHYSICAL_ADDRESS
EFI_STATUS
AddPadSection (
IN OUT EFI_PHYSICAL_ADDRESS *BaseAddress,
IN UINT32 Alignment,
@ -3604,14 +3604,14 @@ AddPadSection (
UINT32 FfsHeaderLength;
UINT32 FfsFileLength;
UINT32 PadSize;
UINTN PadAddress;
EFI_PHYSICAL_ADDRESS PadAddress;
UINT8 *FfsPart;
UINT32 PartSize;
UINT32 Offset;
EFI_FFS_INTEGRITY_CHECK *IntegrityCheck;
PadAddress = ALIGN_VALUE (*BaseAddress + sizeof (EFI_COMMON_SECTION_HEADER), Alignment);
PadSize = PadAddress - *BaseAddress;
PadSize = (UINT32)(PadAddress - *BaseAddress);
Offset = (UINT32)((UINTN)((*Section).Pe32Section) - (UINTN)(*FfsFile));
PartSize = GetFfsFileLength (*FfsFile) - Offset;
@ -3641,7 +3641,7 @@ AddPadSection (
++NewSection;
ZeroMem ((VOID *)NewSection, PadSize - sizeof (EFI_COMMON_SECTION_HEADER));
*Section = (EFI_FILE_SECTION_POINTER)(EFI_PE32_SECTION *)((UINT8 *)NewSection + PadSize - sizeof (EFI_COMMON_SECTION_HEADER));
(*Section).Pe32Section = (EFI_PE32_SECTION *)((UINT8 *)NewSection + PadSize - sizeof (EFI_COMMON_SECTION_HEADER));
CopyMem (
(UINT8 *)((*Section).Pe32Section),

View File

@ -19,10 +19,9 @@ $(OBJECTS) : $(SOURCE_PATH)\Include\Common\BuildVersion.h
.PHONY:cleanall
clean:
del /f /q $(OBJECTS) *.pdb > nul
del /f /q *.obj *.pdb > nul
cleanall:
del /f /q $(OBJECTS) $(APPLICATION) *.pdb $(BIN_PATH)\$(APPNAME).pdb > nul
del /f /q *.obj $(APPLICATION) *.pdb $(BIN_PATH)\$(APPNAME).pdb > nul
!INCLUDE $(SOURCE_PATH)\Makefiles\ms.rule

@ -1 +1 @@
Subproject commit 52c587d60be67c337364b830dd3fdc15404a2f04
Subproject commit d82e959e621a3d597f1e0d50ff8c2d8b96915fd7

View File

@ -130,36 +130,6 @@ typedef unsigned __int32 UINT32;
/// 4-byte signed value.
///
typedef __int32 INT32;
///
/// 2-byte unsigned value.
///
typedef unsigned short UINT16;
///
/// 2-byte Character. Unless otherwise specified all strings are stored in the
/// UTF-16 encoding format as defined by Unicode 2.1 and ISO/IEC 10646 standards.
///
typedef unsigned short CHAR16;
///
/// 2-byte signed value.
///
typedef short INT16;
///
/// Logical Boolean. 1-byte value containing 0 for FALSE or a 1 for TRUE. Other
/// values are undefined.
///
typedef unsigned char BOOLEAN;
///
/// 1-byte unsigned value.
///
typedef unsigned char UINT8;
///
/// 1-byte Character.
///
typedef char CHAR8;
///
/// 1-byte signed value.
///
typedef signed char INT8;
#else
///
/// 8-byte unsigned value.
@ -177,6 +147,8 @@ typedef unsigned int UINT32;
/// 4-byte signed value.
///
typedef int INT32;
#endif
///
/// 2-byte unsigned value.
///
@ -207,7 +179,6 @@ typedef char CHAR8;
/// 1-byte signed value
///
typedef signed char INT8;
#endif
///
/// Unsigned value of native width. (4 bytes on supported 32-bit processor instructions;

View File

@ -96,7 +96,17 @@ typedef struct {
//
// Characteristics
//
#define EFI_IMAGE_FILE_RELOCS_STRIPPED 1 ///< 0x0001 Relocation info stripped from file.
#define EFI_IMAGE_FILE_RELOCS_STRIPPED BIT0 ///< 0x0001 Relocation info stripped from file.
#define EFI_IMAGE_FILE_EXECUTABLE_IMAGE BIT1 ///< 0x0002 File is executable (i.e. no unresolved externel references).
#define EFI_IMAGE_FILE_LINE_NUMS_STRIPPED BIT2 ///< 0x0004 Line numbers stripped from file.
#define EFI_IMAGE_FILE_LOCAL_SYMS_STRIPPED BIT3 ///< 0x0008 Local symbols stripped from file.
#define EFI_IMAGE_FILE_LARGE_ADDRESS_AWARE BIT5 ///< 0x0020 Supports addresses > 2-GB
#define EFI_IMAGE_FILE_BYTES_REVERSED_LO BIT7 ///< 0x0080 Bytes of machine word are reversed.
#define EFI_IMAGE_FILE_32BIT_MACHINE BIT8 ///< 0x0100 32 bit word machine.
#define EFI_IMAGE_FILE_DEBUG_STRIPPED BIT9 ///< 0x0200 Debugging info stripped from file in .DBG file.
#define EFI_IMAGE_FILE_SYSTEM BIT12 ///< 0x1000 System File.
#define EFI_IMAGE_FILE_DLL BIT13 ///< 0x2000 File is a DLL.
#define EFI_IMAGE_FILE_BYTES_REVERSED_HI BIT15 ///< 0x8000 Bytes of machine word are reversed.
///
/// Header Data Directories.

View File

@ -0,0 +1,219 @@
/** @file
Definitions of the UE certificate store format.
Copyright (c) 2021, Marvin Häuser. All rights reserved.<BR>
SPDX-License-Identifier: BSD-2-Clause-Patent
**/
#ifndef UE_CERT_STORE_H_
#define UE_CERT_STORE_H_
///
/// Definition of an UE certificate (PKCS).
///
typedef struct {
///
/// The UE certificate (PKCS) information.
///
/// [Bits 23:0] The size, in Bytes, of TbsData.
/// [Bits 31:24] Reserved for future usage. Must be set to 0.
///
UINT32 Info;
///
/// The size, in Bytes, of Signature.
///
UINT32 SignatureSize;
///
/// The ASN.1 DER encoded X.509 tbsCertificate field.
///
UINT8 TbsData[];
///
/// The signature of TbsData, signed by the certificate identified by
/// TbsData.issuer, with the algorithm identified by SignatureAlgorithm. Its
/// size is strictly defined by the signature algorithm.
///
//UINT8 Signature[];
} UE_CERT_PKCS;
/**
Retrieves the size, in Bytes, of TbsData of an UE certificate (PKCS).
@param[in] Info The UE certificate (PKCS) information.
**/
#define UE_CERT_PKCS_TBS_SIZE(Info) ((Info) & 0x00FFFFFFU)
STATIC_ASSERT (
sizeof (UE_CERT_PKCS) == 8 && ALIGNOF (UE_CERT_PKCS) == 4,
"The UE certificate (PKCS) definition does not meet the specification."
);
STATIC_ASSERT (
OFFSET_OF (UE_CERT_PKCS, TbsData) == sizeof (UE_CERT_PKCS),
"The UE certificate (PKCS) definition does not meet the specification."
);
///
/// Definition of the UE certificate (minimal RSA) purpose identifiers.
///
enum {
UeCertMinRsaPurposeExecutable = 0x00U,
UeCertMinRsaPurposeVariables = 0x01U,
UeCertMinRsaPurposeConfig = 0x02U
};
///
/// Definition of an UE certificate (minimal RSA).
/// The RSA exponent is always 65537.
///
typedef struct {
///
/// The certificate subject identifier GUID.
///
GUID SubjectId;
///
/// [Bits 28:0] The time the certificate expires. It is calculated by:
/// S + M * 60 + H * 3600 + D * 86400 + m * 2678400 + Y * 32140800, with
/// S [0,59]: The number of full seconds into the current minute,
/// M [0,59]: The number of full minutes into the current hour,
/// H [0,23]: The number of full hours into the current day,
/// D [0,30]: The number of full days into the current month,
/// m [0,11]: The number of full months into the current year,
/// Y [0,16]: The number of full years since 2021.
/// [Bits 29:31] Reserved for future usage. Must be set to 0.
///
UINT32 ExpiryTime;
///
/// [Bits 1:0] The purpose identifier of the certificate.
/// [Bits 7:1] Reserved for future usage. Must be set to 0.
///
UINT8 Purpose;
///
/// Reserved for future usage. Must be set to 0.
///
UINT8 Reserved;
///
/// [Bits 11:0] The size, in 8 Byte units, of the RSA modulus.
/// [Bits 15:12] Reserved for future usage. Must be set to 0.
///
UINT16 NumQwords;
///
/// The Montgomery Inverse in the 64-bit space: -1 / N[0] mod 2^64.
///
UINT64 N0Inv;
///
/// The RSA parameters. If the number of significant Bits is less than the
/// number of available Bits, the remaining Bits must be set to 0. Storage
/// happens in reverse byte order.
///
/// [0 .. 8 * NumQwords) The RSA key.
/// [8 * NumQwords .. 16 * NumQwords) Montgomery R^2 mod N.
///
UINT8 Data[];
} UE_CERT_MIN_RSA;
STATIC_ASSERT (
sizeof (UE_CERT_MIN_RSA) == 32 && ALIGNOF (UE_CERT_MIN_RSA) == 8,
"The UE certificate (minimal RSA) definition does not meet the specification."
);
STATIC_ASSERT (
OFFSET_OF (UE_CERT_MIN_RSA, Data) == sizeof (UE_CERT_MIN_RSA),
"The UE certificate (minimal RSA) definition does not meet the specification."
);
STATIC_ASSERT (
IS_ALIGNED (OFFSET_OF (UE_CERT_MIN_RSA, Data), ALIGNOF (UINT64)),
"The UE certificate (minimal RSA) definition does not meet the specification."
);
///
/// Definition of the UE certificate store types.
///
enum {
UeCertChainTypePkcs = 0x00
};
///
/// The alignment, in Bytes, of each UE certificate chain in the UE certificate
/// store.
///
#define UE_CERT_CHAIN_ALIGNMENT 8U
///
/// Definition of an UE certificate chain.
///
typedef struct {
///
/// The signature algorithm used to sign the data.
///
GUID Algorithm;
///
/// The UE certificate chain information.
///
/// [Bit 0] If set, the certificate chain is empty and the data may be
/// directly signed by a trusted certificate. In this case,
/// instead of a certificate chain structure, the type-specific
/// issuer information is stored.
/// [Bits 2:1] Reserved for future usage. Must be set to 0.
/// [Bits 23:3] The size, in Bytes, of this UE certificate chain, or of the
/// type-specific issuer information.
/// [Bit 24] The type of the UE certificate store.
/// [Bits 31:25] Reserved for future usage. Must be set to 0.
///
UINT32 Info;
///
/// The size, in Bytes, of Signature.
///
UINT32 SignatureSize;
///
/// The signature of the signed data, signed by the first certificate of the
/// chain, with the algorithm identified by SignatureAlgorithm. Its size is
/// strictly defined by the signature algorithm.
///
UINT8 Signature[];
///
/// The certficate chain. The first certificate signs the data.
///
//UE_CERT Chain[];
} UE_CERT_CHAIN;
/**
Retrieves whether the UE certificate chain is routed, i.e. whether there is
no chain of certificates but a type-specific issuer identifier for the trusted
certificate that signs the data.
@param[in] Info The UE certificate chain information.
**/
#define UE_CERT_CHAIN_ROOTED(Info) ((Info) & 0x00000001U)
/**
Retrieves the size, in Bytes, of the UE certificate chain.
@param[in] Info The UE certificate chain information.
**/
#define UE_CERT_CHAIN_SIZE(Info) ((Info) & 0x00FFFFF8U)
/**
Retrieves the type of the UE certificate chain.
@param[in] Info The UE certificate chain information.
**/
#define UE_CERT_CHAIN_TYPE(Info) (((Info) & 0x1000000U) >> 24U)
STATIC_ASSERT (
IS_ALIGNED (UE_CERT_CHAIN_SIZE (0xFFFFFFFF), UE_CERT_CHAIN_ALIGNMENT),
"The UE certificate chain definition does not meet the specification."
);
STATIC_ASSERT (
sizeof (UE_CERT_CHAIN) == 24 && ALIGNOF (UE_CERT_CHAIN) == 4,
"The UE certificate chain definition does not meet the specification."
);
STATIC_ASSERT (
OFFSET_OF (UE_CERT_CHAIN, Signature) == sizeof (UE_CERT_CHAIN),
"The UE certificate chain definition does not meet the specification."
);
#endif // UE_CERT_STORE_H_

View File

@ -0,0 +1,580 @@
/** @file
Definitions of the UEFI Executable file format.
Copyright (c) 2021, Marvin Häuser. All rights reserved.<BR>
SPDX-License-Identifier: BSD-2-Clause-Patent
**/
#ifndef UE_IMAGE_H_
#define UE_IMAGE_H_
//
// UEFI Executable segment definitions.
//
// NOTE: To guarantee all data is sufficiently aligned, no matter what it is,
// all UE segments are at least 8 Byte aligned in the UE memory space.
// This leaves the bottom 3 Bits unused for valid values. Use them to
// indicate the UE segment permissions.
//
///
/// The alignment, in Bytes, of each UE segment in the UE memory space.
///
#define UE_SEGMENT_ALIGNMENT 8U
///
/// Definition of an UEFI Executable segment header.
///
typedef struct {
///
/// Information about the UE segment in the UE memory space.
///
/// [Bit 0] Indicates whether the UE segment is read-protected.
/// [Bit 1] Indicates whether the UE segment is execute-protected.
/// [Bit 2] Indicates whether the UE segment is write-protected.
/// [Bits 31:3] The size, in 8 Byte units, of the UE segment in the UE memory
/// space.
///
UINT32 ImageInfo;
///
/// The size, in Bytes, of the UE segment in the UE raw file.
///
UINT32 FileSize;
} UE_SEGMENT;
#define UE_SEGMENT_INFO_RP BIT0
#define UE_SEGMENT_INFO_XP BIT1
#define UE_SEGMENT_INFO_RO BIT2
STATIC_ASSERT (
sizeof (UE_SEGMENT) == 8 && ALIGNOF (UE_SEGMENT) == 4,
"The UE segment definition does not meet the specification."
);
///
/// Definition of an UEFI Executable XIP segment header.
///
typedef struct {
///
/// Information about the UE segment in the UE memory space.
///
/// [Bit 0] Indicates whether the UE segment is read-protected.
/// [Bit 1] Indicates whether the UE segment is execute-protected.
/// [Bit 2] Indicates whether the UE segment is write-protected.
/// [Bits 31:3] The size, in 8 Byte units, of the UE segment in the UE memory
/// space.
///
UINT32 ImageInfo;
} UE_SEGMENT_XIP;
STATIC_ASSERT (
sizeof (UE_SEGMENT_XIP) == 4 && ALIGNOF (UE_SEGMENT_XIP) == 4,
"The UE XIP segment definition does not meet the specification."
);
STATIC_ASSERT (
OFFSET_OF (UE_SEGMENT, ImageInfo) == OFFSET_OF (UE_SEGMENT_XIP, ImageInfo),
"The UE and UE XIP segment definitions do not align."
);
/**
Retrieve the UE segment memory permissions.
@param[in] ImageInfo The UE segment memory information.
**/
#define UE_SEGMENT_PERMISSIONS(ImageInfo) ((ImageInfo) & 0x00000007U)
/**
Retrieve the size, in Bytes, of the UE segment in the UE memory space.
@param[in] ImageInfo The UE segment image information.
**/
#define UE_SEGMENT_SIZE(ImageInfo) ((ImageInfo) & 0xFFFFFFF8U)
STATIC_ASSERT (
IS_ALIGNED (UE_SEGMENT_SIZE (0xFFFFFFFF), UE_SEGMENT_ALIGNMENT),
"The UE segment size definition does not meet the specification."
);
//
// UEFI Executable section definitions.
//
// NOTE: To guarantee all data is sufficiently aligned, no matter what it is,
// all UE sections are at least 8 Byte aligned.
//
// UE sections are identified by ID and can be omitted to save space.
//
// UE sections are ordered by ID to allow efficient lookups.
//
// UE relocation table will likely be close to PE/COFF.
//
// UE HII support needs discussion, REF: https://bugzilla.tianocore.org/show_bug.cgi?id=557
//
// UE certificate table will likely be a stripped version of PE/COFF.
//
// UE sections are not loaded into the UE memory space as their data is
// only required by the loader.
//
// UE section Bit 2 is reserved in case more UE section IDs are required
// in the future. If it is set, an extended structure should be used.
//
///
/// The alignment, in Bytes, of each UE section in the UE raw file.
///
#define UE_SECTION_ALIGNMENT 8U
///
/// Definition of UE section identifiers.
///
enum {
UeSectionIdRelocTable = 0x00U,
UeSectionIdDebugTable = 0x01U,
UeSectionIdHiiTable = 0x02U
};
//
// Definition of an UE section header.
//
typedef struct {
///
/// Information about the UE section.
///
/// [Bits 1:0] The identifier of the UE section.
/// [Bit 2] Reserved for future usage. Must be set to 0.
/// [Bits 31:3] The size, in 8 Byte units, of the UE section in the UE raw
/// file.
///
UINT32 FileInfo;
} UE_SECTION;
STATIC_ASSERT (
sizeof (UE_SECTION) == 4 && ALIGNOF (UE_SECTION) == 4,
"The UE section definition does not meet the specification."
);
/**
Retrieves the UE section identifier.
@param[in] FileInfo The UE section raw file information.
**/
#define UE_SECTION_ID(FileInfo) ((FileInfo) & 0x00000003U)
/**
Retrieves the size, in Bytes, of the UE section in the UE raw file.
@param[in] FileInfo The UE section raw file information.
**/
#define UE_SECTION_SIZE(FileInfo) ((FileInfo) & 0xFFFFFFF8U)
STATIC_ASSERT (
IS_ALIGNED (UE_SECTION_SIZE (0xFFFFFFFF), UE_SECTION_ALIGNMENT),
"The UE section size definition does not meet the specification."
);
//
// UEFI Executable relocation table definitions.
//
// NOTE: The rest of the definitions should be close to PE/COFF.
// PE/COFF SizeOfBlock allows for a lot more relocations, however forcing
// 4 KB blocks still allows for one relocation per Byte with this design.
//
///
/// Definition of the UEFI Executable relocation identifiers.
///
enum {
UeRelocRel32 = 0x00U,
UeRelocRel64 = 0x01U,
UeRelocArmMov32t = 0x02U
};
#define UE_RELOCATION_BLOCK_ALIGNMENT 4U
#define UE_RELOCATION_BLOCK_MAX_RELOCS 4095U
///
/// Definition of an UEFI Executable relocation block.
///
typedef struct {
///
/// Information about the UE relocation block.
///
/// [Bits 11:0] The amount of relocations of the UE relocation block.
/// [Bits 31:12] The base address, in 4 KB units, of the UE relocation block.
///
UINT32 BlockInfo;
///
/// The relocations of the UE relocation block.
///
/// [Bits 11:0] The offset of the UE relocation in the UE relocation block.
/// [Bits 31:12] The type of the UE relocation.
///
UINT16 RelocInfo[];
} UE_RELOCATION_BLOCK;
STATIC_ASSERT (
sizeof (UE_RELOCATION_BLOCK) == 4 && ALIGNOF (UE_RELOCATION_BLOCK) == UE_RELOCATION_BLOCK_ALIGNMENT,
"The UE relocation block definition does not meet the specification."
);
STATIC_ASSERT (
ALIGNOF (UE_RELOCATION_BLOCK) <= UE_SECTION_ALIGNMENT,
"The UE relocation block definition does not meet the specification."
);
STATIC_ASSERT (
OFFSET_OF (UE_RELOCATION_BLOCK, RelocInfo) == sizeof (UE_RELOCATION_BLOCK),
"The UE relocation block definition does not meet the specification."
);
/**
Retrieves the target offset of the UE relocation.
@param[in] RelocInfo The UE relocation information.
**/
#define UE_RELOC_OFFSET(RelocInfo) ((RelocInfo) & 0x0FFFU)
/**
Retrieves the type of the UE relocation.
@param[in] RelocInfo The UE relocation information.
**/
#define UE_RELOC_TYPE(RelocInfo) ((RelocInfo) >> 12U)
/**
Retrieves the amount of relocations in the UE relocation block.
@param[in] BlockInfo The UE relocation block information.
**/
#define UE_RELOC_BLOCK_NUM(BlockInfo) ((BlockInfo) & 0x00000FFFU)
/**
Retrieves the base address of the UE relocation block.
@param[in] BlockInfo The UE relocation block information.
**/
#define UE_RELOC_BLOCK_ADDRESS(BlockInfo) ((BlockInfo) & 0xFFFFF000U)
//
// UEFI Executable debug table definitions.
//
// NOTE: The UE symbols base address offset is required for conversion of
// PE/COFF Images that have their first section start after the end of the
// Image headers. As PDBs cannot easily be rebased, store the offset.
//
///
/// Definition of an UEFI Executable segment name.
///
typedef UINT8 UE_SEGMENT_NAME[8];
STATIC_ASSERT (
sizeof (UE_SEGMENT_NAME) == 8 && ALIGNOF (UE_SEGMENT_NAME) == 1,
"The UE segment name definition does not meet the specification."
);
///
/// Definition of an UEFI Executable section header.
///
typedef struct {
///
/// The offset to be added to the UE base address in order to retrieve the
/// UE symbols base address.
/// FIXME: Can we rely on equal layouts for all source file formats?
///
INT16 SymbolsBaseOffset;
//
// Reserved for future usage. Must be set to 0.
//
UINT8 Reserved;
///
/// The size, in Bytes, of the UE symbols path.
///
UINT8 SymbolsPathSize;
///
/// The UE symbols path.
///
UINT8 SymbolsPath[];
///
/// The UE segment name table. In the same order as the UE segment table.
///
//UE_SEGMENT_NAME SegmentNames[];
} UE_DEBUG_TABLE;
///
/// The minimum size, in Bytes, of the UE debug table.
///
#define MIN_SIZE_OF_UE_DEBUG_TABLE OFFSET_OF (UE_DEBUG_TABLE, SymbolsPath)
/**
Retrieves the segment name table of an UE debug table.
@param[in] DebugTable The UE debug table.
**/
#define UE_DEBUG_TABLE_SEGMENT_NAMES(DebugTable) \
(CONST UE_SEGMENT_NAME *) ( \
(DebugTable)->SymbolsPath + (DebugTable)->SymbolsPathSize \
)
STATIC_ASSERT (
sizeof (UE_DEBUG_TABLE) == 4 && ALIGNOF (UE_DEBUG_TABLE) == 2,
"The UE debug table definition does not meet the specification."
);
STATIC_ASSERT (
ALIGNOF (UE_DEBUG_TABLE) <= UE_SECTION_ALIGNMENT,
"The UE debug table definition is misaligned."
);
STATIC_ASSERT (
OFFSET_OF (UE_DEBUG_TABLE, SymbolsPath) == sizeof (UE_DEBUG_TABLE),
"The UE relocation block definition does not meet the specification."
);
//
// UEFI Executable header definitions.
//
// NOTE: The UE segment alignment is stored as shift exponent to save up to
// 3 Bytes. This also guarantees it to be a power fo two.
//
// UE fixed-address loading needs reconsideration.
//
// The UE header can be contained in a separate FFS section to save space.
//
// The UE segment table overlaps the UE header padding. However, as there
// must always be at least one segment, the padding can be ignored.
//
// The index of the last UE segment is stored over the number of segments
// to avoid the check against 0, and to allow for one more segment.
//
// The remaining reserved fields may be used to indicate revision.
//
// The certificate table is not stored as an UE section to both omit its
// size from the headers (allows for multi-step-signing without having to
// hash the certificate table size), and to allow immediate hashing.
//
// The UE XIP header omits all data that can be derived from platform
// constraints. This header is not guaranteed to be backwards-compatible.
//
///
/// The signature of an UEFI Executable header.
///
#define UE_HEADER_SIGNATURE SIGNATURE_16 ('U', 'E')
#define UE_HEADER_FLAG_RELOCS_STRIPPED BIT7
///
/// Definition of the UEFI Executable machine identifiers.
///
enum {
UeMachineI386 = 0x00U,
UeMachineEbc = 0x01U,
UeMachineX64 = 0x02U,
UeMachineArmThumbMixed = 0x03U,
UeMachineArm64 = 0x04U,
UeMachineRiscV32 = 0x05U,
UeMachineRiscV64 = 0x06U,
UeMachineRiscV128 = 0x07U
};
///
/// Definition of the UEFI Executable subsystem identifiers.
///
enum {
UeSubsystemEfiApplication = 0x00U,
UeSubsystemEfiBootServicesDriver = 0x01U,
UeSubsystemEfiRuntimeDriver = 0x02U,
UeSubsystemSalRuntimeDriver = 0x03U,
};
///
/// Definition of an UEFI Executable header.
///
typedef struct {
///
/// The signature to identify the UE raw file format. Must match 'UE'.
///
UINT16 Signature;
///
/// [Bits 7:0] Reserved for future usage. Must be set to 0.
///
UINT8 Reserved;
///
/// Information about the UE Image.
///
/// [Bits 4:0] The shift exponent for the UE segment alignment in Bytes.
/// [Bits 6:5] Reserved for future usage. Must be set to 0.
/// [Bit 7] Indicates whether the UE relocation table has been stripped.
///
UINT8 ImageInfo;
///
/// The index of the last segment in the UE segment table.
///
UINT8 LastSegmentIndex;
///
/// The number of sections in the UE section table.
///
UINT8 NumSections;
///
/// Indicates the subsystem identifier the UE targets.
///
UINT8 Subsystem;
///
/// Indicates the machine identifier the UE targets.
///
UINT8 Machine;
///
/// Indicates the UE preferred load address.
///
UINT64 PreferredAddress;
///
/// Indicates the offset of the UE entry point in the UE memory space.
///
UINT32 EntryPointAddress;
///
/// Extended information about the UE Image.
///
/// [Bits 2:0] Reserved for future usage. Must be set to 0.
/// [Bits 31:3] The size, in 8 Byte units, of the unsigned UE raw file. If the
/// UE raw file size is larger than this value, the appended data
/// is the UE certificate table.
///
UINT32 ImageInfo2;
///
/// The UE segment table. It contains all data of the UE memory space.
///
/// All UE segments are contiguous in the UE memory space.
/// The offset of the first UE segment in the UE memory space is 0.
///
/// All UE segments are contiguous in the UE raw file.
/// The offset of the first UE segment in the UE raw file is the end of the
/// UEFI Executable header in the UE raw file.
///
UE_SEGMENT Segments[];
///
/// The UE section table. It contains data useful for UE loading.
///
/// All UE sections are contiguous in the UE raw file.
/// The offset of the first UE section in the UE raw file is the end of the
/// last UE segment in the UE raw file.
///
/// All UE sections are ordered by their UE section identifier.
///
//UE_SECTION Sections[];
} UE_HEADER;
///
/// The minimum size, in Bytes, of a valid UE header.
///
#define MIN_SIZE_OF_UE_HEADER \
(OFFSET_OF (UE_HEADER, Segments) + sizeof (UE_SEGMENT))
STATIC_ASSERT (
sizeof (UE_HEADER) == 24 && ALIGNOF (UE_HEADER) == 8,
"The UE header definition does not meet the specification."
);
STATIC_ASSERT (
ALIGNOF (UE_SEGMENT) <= ALIGNOF (UE_SECTION),
"The UE header definition is misaligned."
);
STATIC_ASSERT (
OFFSET_OF (UE_HEADER, Segments) == sizeof (UE_HEADER),
"The UE header definition does not meet the specification."
);
/**
Retrieves the UE segment alignment, in Bytes, as a power of two.
@param[in] ImageInfo The UE header image information.
**/
#define UE_HEADER_ALIGNMENT(ImageInfo) ((UINT32) 1U << ((ImageInfo) & 0x1FU))
/**
Retrieves the 8 Byte aligned unsigned UE raw file size.
If the UE raw file size is larger than this value, the appended data is the UE
certificate table.
@param[in] ImageInfo2 The UE header image information.
**/
#define UE_HEADER_UNSIGNED_SIZE(ImageInfo2) ((ImageInfo2) & 0xFFFFFFF8U)
STATIC_ASSERT (
IS_ALIGNED (UE_HEADER_UNSIGNED_SIZE (0xFFFFFFFF), UE_SECTION_ALIGNMENT),
"The unsigned UE raw file size definition does not meet the specification."
);
///
/// Definition of an UEFI Executable XIP header.
///
typedef struct {
///
/// [Bits 7:0] Reserved for future usage. Must be set to 0.
///
UINT8 Reserved;
///
/// Information about the UE Image.
///
/// [Bits 4:0] The shift exponent for the UE segment alignment.
/// [Bits 6:5] Reserved for future usage. Must be set to 0.
/// [Bit 7] Indicates whether the UE relocation table has been stripped.
///
UINT8 ImageInfo;
///
/// The index of the last segment in the UE segment table.
///
UINT8 LastSegmentIndex;
///
/// The number of sections in the UE section table.
///
UINT8 NumSections;
///
/// Indicates the offset of the UE entry point in the UE memory space.
///
UINT32 EntryPointAddress;
///
/// The UE segment table. It contains all data of the UE memory space.
///
/// All UE segments are contiguous in the UE memory space.
/// The offset of the first UE segment in the UE memory space is 0.
///
/// The UE segments are stored separately in XIP memory.
///
UE_SEGMENT_XIP Segments[];
///
/// The UE section table. It contains data useful for UE loading.
///
/// All UE sections are contiguous in the UE raw file.
/// The offset of the first UE section in the UE raw file is the end of the
/// UEFI Executable XIP header in the UE raw file.
///
/// All UE sections are ordered by their UE section identifier.
///
//UE_SECTION Sections[];
} UE_HEADER_XIP;
///
/// The minimum size, in Bytes, of a valid UE XIP header.
///
#define MIN_SIZE_OF_UE_HEADER_XIP \
(OFFSET_OF (UE_HEADER_XIP, Segments) + sizeof (UE_SEGMENT_XIP))
STATIC_ASSERT (
sizeof (UE_HEADER_XIP) == 8 && ALIGNOF (UE_HEADER_XIP) == 4,
"The UE XIP header definition does not meet the specification."
);
STATIC_ASSERT (
ALIGNOF (UE_SEGMENT_XIP) <= ALIGNOF (UE_SECTION),
"The UE XIP header definition is misaligned."
);
STATIC_ASSERT (
OFFSET_OF (UE_HEADER_XIP, Segments) == sizeof (UE_HEADER_XIP),
"The UE XIP header definition does not meet the specification."
);
#endif // UE_IMAGE_H_

View File

@ -0,0 +1,250 @@
/** @file
UEFI Image Loader library implementation for UE Images.
Copyright (c) 2021, Marvin Häuser. All rights reserved.<BR>
SPDX-License-Identifier: BSD-3-Clause
**/
#ifndef UE_LIB_H_
#define UE_LIB_H_
#include <IndustryStandard/UeImage.h>
// FIXME: Deduplicate?
//
// PcdImageLoaderAlignmentPolicy bits.
//
///
/// If set, unaligned Image sections are permitted.
///
#define PCD_ALIGNMENT_POLICY_CONTIGUOUS_SECTIONS BIT0
///
/// If set, unaligned Image Relocation Block sizes are permitted.
///
#define PCD_ALIGNMENT_POLICY_RELOCATION_BLOCK_SIZES BIT1
///
/// If set, unaligned Image certificate sizes are permitted.
///
#define PCD_ALIGNMENT_POLICY_CERTIFICATE_SIZES BIT2
//
// PcdImageLoaderRelocTypePolicy bits.
//
///
/// If set, ARM Thumb Image relocations are supported.
///
#define PCD_RELOC_TYPE_POLICY_ARM BIT0
// FIXME: Add RISC-V support.
/**
Returns whether the Base Relocation type is supported by this loader.
@param[in] Type The type of the Base Relocation.
**/
#define UE_RELOC_TYPE_SUPPORTED(Type) \
(((Type) == EFI_IMAGE_REL_BASED_ABSOLUTE) || \
((Type) == EFI_IMAGE_REL_BASED_HIGHLOW) || \
((Type) == EFI_IMAGE_REL_BASED_DIR64) || \
((PcdGet32 (PcdImageLoaderRelocTypePolicy) & PCD_RELOC_TYPE_POLICY_ARM) != 0 && (Type) == EFI_IMAGE_REL_BASED_ARM_MOV32T))
/**
Returns whether the Base Relocation is supported by this loader.
@param[in] Relocation The composite Base Relocation value.
**/
#define UE_RELOC_SUPPORTED(RelocInfo) \
UE_RELOC_TYPE_SUPPORTED (UE_RELOC_TYPE (RelocInfo))
typedef struct {
CONST VOID *FileBuffer;
UINT32 SegmentAlignment;
VOID *ImageBuffer;
UINT32 SegmentsFileOffset; // Unused for XIP
CONST UE_SECTION *Sections;
CONST VOID *Segments;
UINT32 SectionsFileOffset;
UINT32 ImageSize;
UINT32 UnsignedFileSize;
UINT32 CertTableSize;
UINT32 RelocTableSize;
UINT8 ImageInfo;
UINT8 LastSegmentIndex;
UINT8 NumSections;
UINT8 Subsystem;
UINT8 Machine;
UINT64 PreferredAddress; // Unused for XIP
UINT32 EntryPointAddress;
UINT8 SegmentImageInfoIterSize;
} UE_LOADER_IMAGE_CONTEXT;
typedef struct UE_LOADER_RUNTIME_CONTEXT_ UE_LOADER_RUNTIME_CONTEXT;
/**
Adds the digest of Data to HashContext. This function can be called multiple
times to compute the digest of discontinuous data.
@param[in,out] HashContext The context of the current hash.
@param[in] Data The data to be hashed.
@param[in] DataSize The size, in Bytes, of Data.
@returns Whether hashing has been successful.
**/
typedef
BOOLEAN
(EFIAPI *UE_LOADER_HASH_UPDATE)(
IN OUT VOID *HashContext,
IN CONST VOID *Data,
IN UINTN DataSize
);
RETURN_STATUS
UeInitializeContextPreHash (
OUT UE_LOADER_IMAGE_CONTEXT *Context,
IN CONST VOID *FileBuffer,
IN UINT32 FileSize
);
RETURN_STATUS
UeInitializeContextPostHash (
IN OUT UE_LOADER_IMAGE_CONTEXT *Context
);
RETURN_STATUS
UeInitializeContext (
OUT UE_LOADER_IMAGE_CONTEXT *Context,
IN CONST VOID *FileBuffer,
IN UINT32 FileSize
);
BOOLEAN
UeHashImageDefault (
IN OUT UE_LOADER_IMAGE_CONTEXT *Context,
IN OUT VOID *HashContext,
IN UE_LOADER_HASH_UPDATE HashUpdate
);
RETURN_STATUS
UeLoadImage (
IN OUT UE_LOADER_IMAGE_CONTEXT *Context,
OUT VOID *Destination,
IN UINT32 DestinationSize
);
RETURN_STATUS
UeLoadImageInplace (
IN OUT UE_LOADER_IMAGE_CONTEXT *Context
);
RETURN_STATUS
UeLoaderGetRuntimeContextSize (
IN OUT UE_LOADER_IMAGE_CONTEXT *Context,
OUT UINT32 *Size
);
RETURN_STATUS
UeRelocateImage (
IN OUT UE_LOADER_IMAGE_CONTEXT *Context,
IN UINT64 BaseAddress
);
RETURN_STATUS
UeRelocateImageForRuntime (
IN OUT VOID *Image,
IN UINT32 ImageSize,
IN UINT64 BaseAddress,
IN CONST UE_LOADER_RUNTIME_CONTEXT *RuntimeContext
);
RETURN_STATUS
UeGetSymbolsPath (
IN OUT UE_LOADER_IMAGE_CONTEXT *Context,
OUT CONST CHAR8 **SymbolsPath,
OUT UINT32 *SymbolsPathSize
);
RETURN_STATUS
UeGetFirstCertificate (
IN OUT UE_LOADER_IMAGE_CONTEXT *Context,
OUT CONST WIN_CERTIFICATE **Certificate
);
RETURN_STATUS
UeGetNextCertificate (
IN OUT UE_LOADER_IMAGE_CONTEXT *Context,
IN OUT CONST WIN_CERTIFICATE **Certificate
);
RETURN_STATUS
UeGetHiiDataRva (
IN OUT UE_LOADER_IMAGE_CONTEXT *Context,
OUT UINT32 *HiiRva,
OUT UINT32 *HiiSize
);
UINT32
UeGetAddressOfEntryPoint (
IN OUT UE_LOADER_IMAGE_CONTEXT *Context
);
UINT16
UeGetMachine (
IN OUT UE_LOADER_IMAGE_CONTEXT *Context
);
UINT16
UeGetSubsystem (
IN OUT UE_LOADER_IMAGE_CONTEXT *Context
);
UINT32
UeGetSegmentAlignment (
IN OUT UE_LOADER_IMAGE_CONTEXT *Context
);
UINT32
UeGetImageSize (
IN OUT UE_LOADER_IMAGE_CONTEXT *Context
);
UINT32
UeGetImageSizeInplace (
IN OUT UE_LOADER_IMAGE_CONTEXT *Context
);
UINT64
UeGetPreferredAddress (
IN OUT UE_LOADER_IMAGE_CONTEXT *Context
);
BOOLEAN
UeGetRelocsStripped (
IN OUT UE_LOADER_IMAGE_CONTEXT *Context
);
UINTN
UeLoaderGetImageAddress (
IN OUT UE_LOADER_IMAGE_CONTEXT *Context
);
UINT8
UeGetSegments (
IN OUT UE_LOADER_IMAGE_CONTEXT *Context,
OUT CONST UE_SEGMENT **Segments
);
UINT8
UeGetSegmentImageInfos (
IN OUT UE_LOADER_IMAGE_CONTEXT *Context,
OUT CONST UINT32 **SegmentImageInfos,
OUT UINT8 *SegmentImageInfoIterSize
);
UINT32
UeGetSectionsFileOffset (
IN OUT UE_LOADER_IMAGE_CONTEXT *Context
);
#endif // UE_LIB_H_

View File

@ -143,36 +143,6 @@ typedef unsigned __int32 UINT32;
/// 4-byte signed value
///
typedef __int32 INT32;
///
/// 2-byte unsigned value
///
typedef unsigned short UINT16;
///
/// 2-byte Character. Unless otherwise specified all strings are stored in the
/// UTF-16 encoding format as defined by Unicode 2.1 and ISO/IEC 10646 standards.
///
typedef unsigned short CHAR16;
///
/// 2-byte signed value
///
typedef short INT16;
///
/// Logical Boolean. 1-byte value containing 0 for FALSE or a 1 for TRUE. Other
/// values are undefined.
///
typedef unsigned char BOOLEAN;
///
/// 1-byte unsigned value
///
typedef unsigned char UINT8;
///
/// 1-byte Character
///
typedef char CHAR8;
///
/// 1-byte signed value
///
typedef signed char INT8;
#elif defined (__clang__)
///
/// 8-byte unsigned value
@ -190,36 +160,6 @@ typedef unsigned int UINT32;
/// 4-byte signed value
///
typedef signed int INT32;
///
/// 2-byte unsigned value
///
typedef unsigned short UINT16;
///
/// 2-byte Character. Unless otherwise specified all strings are stored in the
/// UTF-16 encoding format as defined by Unicode 2.1 and ISO/IEC 10646 standards.
///
typedef unsigned short CHAR16;
///
/// 2-byte signed value
///
typedef short INT16;
///
/// Logical Boolean. 1-byte value containing 0 for FALSE or a 1 for TRUE. Other
/// values are undefined.
///
typedef unsigned char BOOLEAN;
///
/// 1-byte unsigned value
///
typedef unsigned char UINT8;
///
/// 1-byte Character
///
typedef char CHAR8;
///
/// 1-byte signed value
///
typedef signed char INT8;
#else
///
/// 8-byte unsigned value
@ -237,6 +177,8 @@ typedef unsigned int UINT32;
/// 4-byte signed value
///
typedef int INT32;
#endif
///
/// 2-byte unsigned value
///
@ -267,7 +209,6 @@ typedef char CHAR8;
/// 1-byte signed value
///
typedef signed char INT8;
#endif
///
/// Unsigned value of native width. (4 bytes on supported 32-bit processor instructions,

View File

@ -19,7 +19,7 @@ WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
#include <Library/BaseLib.h>
#include <Library/BaseOverflowLib.h>
#include "OverflowInternals.h"
#include "BaseOverflowInternals.h"
//
// Software implementations provided try not to be obviously slow, but primarily

View File

@ -19,7 +19,7 @@ WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
#include <Library/BaseLib.h>
#include <Library/BaseOverflowLib.h>
#include "OverflowInternals.h"
#include "BaseOverflowInternals.h"
BOOLEAN
BaseOverflowAddUN (

View File

@ -29,12 +29,12 @@
#
[Sources]
Alignment.c
BitOverflow.c
OverflowInternals.h
Math.c
NativeOverflow.c
TripleOverflow.c
BaseAlignment.c
BaseBitOverflow.c
BaseOverflowInternals.h
BaseMath.c
BaseNativeOverflow.c
BaseTripleOverflow.c
[Packages]
MdePkg/MdePkg.dec

View File

@ -233,7 +233,7 @@ InternalVerifySections (
}
//
// Set SizeOfImage to the aligned end address of the last ImageSection.
//
//
if ((PcdGet32 (PcdImageLoaderAlignmentPolicy) & PCD_ALIGNMENT_POLICY_CONTIGUOUS_SECTIONS) == 0) {
Context->SizeOfImage = NextSectRva;
} else {

View File

@ -0,0 +1,109 @@
#include <Base.h>
#include <IndustryStandard/UeCertStore.h>
#include <Library/DebugLib.h>
#include <Library/BaseOverflowLib.h>
typedef struct {
CONST UE_CERT_CHAIN *CertStore;
UINT32 CertStoreSize;
} UE_CS_CONTEXT;
RETURN_STATUS
UeCsInitializeContext (
OUT UE_CS_CONTEXT *Context,
IN CONST VOID *Buffer,
IN UINT32 BufferSize
)
{
ASSERT (Context != NULL);
ASSERT (Buffer != NULL || BufferSize == 0);
if (sizeof (UE_CERT_CHAIN) > BufferSize) {
DEBUG_RAISE ();
return RETURN_UNSUPPORTED;
}
Context->CertStore = Buffer;
Context->CertStoreSize = BufferSize;
return RETURN_SUCCESS;
}
RETURN_STATUS
UeGetFirstCertChain (
IN OUT UE_CS_CONTEXT *Context,
IN OUT UE_CERT_CHAIN **CertChain
)
{
ASSERT (Context != NULL);
ASSERT (CertChain != NULL);
}
RETURN_STATUS
UeGetNextCertChain (
IN OUT UE_CS_CONTEXT *Context,
IN OUT UE_CERT_CHAIN **CertChain
)
{
ASSERT (Context != NULL);
ASSERT (CertChain != NULL);
}
STATIC
RETURN_STATUS
InternalValidatePkcsCertChain (
IN OUT UE_CS_CONTEXT *Context,
IN OUT UE_CERT_CHAIN *CertChain,
IN UINT32 RemainingSize
)
{
BOOLEAN Overflow;
CONST UE_CERT_PKCS *Certs;
UINT32 CertChainPayloadSize;
UINT32 CertChainChainSize;
UINT32 CertSize;
ASSERT (Context != NULL);
ASSERT (CertChain != NULL);
ASSERT (UE_CERT_CHAIN_TYPE (CertChain->Info) == UeCertChainTypePkcs);
Overflow = BaseOverflowSubU32 (
RemainingSize,
sizeof (UE_CERT_CHAIN),
&RemainingSize
);
if (Overflow) {
DEBUG_RAISE ();
return RETURN_UNSUPPORTED;
}
CertChainChainSize = UE_CERT_CHAIN_SIZE (CertChain->Info);
Overflow = BaseOverflowAddU32 (
CertChain->SignatureSize,
CertChainChainSize,
&CertChainPayloadSize
);
if (Overflow) {
DEBUG_RAISE ();
return RETURN_UNSUPPORTED;
}
if (CertChainPayloadSize > RemainingSize) {
DEBUG_RAISE ();
return RETURN_UNSUPPORTED;
}
Certs = CertChain->Signature + CertChain->SignatureSize;
}
RETURN_STATUS
UeValidateCertChain (
IN OUT UE_CS_CONTEXT *Context,
IN OUT UE_CERT_CHAIN *CertChain
)
{
ASSERT (Context != NULL);
ASSERT (CertChain != NULL);
}

View File

@ -0,0 +1,31 @@
## @file
# UEFI Image Loader library implementation for PE/COFF and TE Images.
#
# Copyright (c) 2021, Marvin Häuser. All rights reserved.<BR>
#
# SPDX-License-Identifier: BSD-3-Clause
##
[Defines]
INF_VERSION = 0x00010005
BASE_NAME = UeImageLib
FILE_GUID = 357AD87E-8D6B-468A-B3FA-0D9CC4C725CD
MODULE_TYPE = BASE
VERSION_STRING = 1.0
LIBRARY_CLASS = BaseUeImageLib
[Sources]
UeImageLib.c
[Packages]
MdePkg/MdePkg.dec
[LibraryClasses]
BaseLib
BaseMemoryLib
BaseOverflowLib
DebugLib
PcdLib
[FixedPcd]
gEfiMdePkgTokenSpaceGuid.PcdImageLoaderRelocTypePolicy

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,33 @@
## @file
# UEFI Image Loader library implementation for UE Images.
#
# Copyright (c) 2021, Marvin Häuser. All rights reserved.<BR>
#
# SPDX-License-Identifier: BSD-3-Clause
##
[Defines]
INF_VERSION = 0x00010005
BASE_NAME = BaseUefiImageLibUe
FILE_GUID = 25BC78F1-426B-4C9D-A60D-173A56FB28C1
MODULE_TYPE = BASE
VERSION_STRING = 1.0
LIBRARY_CLASS = UefiImageLib
[Sources]
CommonSupport.c
UeSupport.h
UeSupport.c
UefiImageLibUe.c
[Packages]
MdePkg/MdePkg.dec
[LibraryClasses]
BaseLib
BaseMemoryLib
BaseOverflowLib
CacheMaintenanceLib
DebugLib
MemoryAllocationLib
UeImageLib

View File

@ -0,0 +1,234 @@
#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/DebugLib.h>
#include <Library/MemoryAllocationLib.h>
#include <Library/UefiImageLib.h>
#include <Library/UeImageLib.h>
STATIC
UINT32
InternalPermissionsToAttributes (
IN UINT32 ImageInfo
)
{
UINT32 Attributes;
STATIC_ASSERT (
(UE_SEGMENT_INFO_RP << 13U) == EFI_MEMORY_RP &&
(UE_SEGMENT_INFO_XP << 13U) == EFI_MEMORY_XP &&
(UE_SEGMENT_INFO_RO << 15U) == EFI_MEMORY_RO,
"The following conversion is incorrect."
);
Attributes = (ImageInfo & (UE_SEGMENT_INFO_RP | UE_SEGMENT_INFO_XP)) << 13U;
Attributes |= (ImageInfo & UE_SEGMENT_INFO_RO) << 15U;
return Attributes;
}
UEFI_IMAGE_RECORD *
UefiImageLoaderGetImageRecordUe (
IN OUT UE_LOADER_IMAGE_CONTEXT *Context
)
{
UEFI_IMAGE_RECORD *ImageRecord;
UINTN ImageAddress;
UINT32 NumRecordSegments;
UEFI_IMAGE_RECORD_SEGMENT *RecordSegment;
UINT16 NumSegments;
UINT8 SegmentIterSize;
CONST UINT32 *SegmentImageInfos;
CONST UINT32 *SegmentImageInfoPtr;
UINT32 SegmentImageInfo;
UINTN SegmentImageAddress;
UINT32 SegmentSize;
UINT32 SegmentPermissions;
UINT32 RangeSize;
UINT32 Permissions;
ASSERT (Context != NULL);
NumSegments = 1 + (UINT16) UeGetSegmentImageInfos (
Context,
&SegmentImageInfos,
&SegmentIterSize
);
ImageRecord = AllocatePool (
sizeof (*ImageRecord)
+ NumSegments * sizeof (*ImageRecord->Segments)
);
if (ImageRecord == NULL) {
DEBUG_RAISE ();
return NULL;
}
ImageRecord->Signature = UEFI_IMAGE_RECORD_SIGNATURE;
InitializeListHead (&ImageRecord->Link);
SegmentImageInfo = *SegmentImageInfos;
RangeSize = UE_SEGMENT_SIZE (SegmentImageInfo);
Permissions = UE_SEGMENT_PERMISSIONS (SegmentImageInfo);
SegmentImageAddress = 0;
NumRecordSegments = 0;
STATIC_ASSERT (
OFFSET_OF (UE_SEGMENT, ImageInfo) == 0 &&
OFFSET_OF (UE_SEGMENT, ImageInfo) == OFFSET_OF (UE_SEGMENT_XIP, ImageInfo),
"Below's logic assumes the given layout."
);
for (
SegmentImageInfoPtr = (CONST VOID *) ((CONST CHAR8 *) SegmentImageInfos + SegmentIterSize);
(CONST CHAR8 *) SegmentImageInfoPtr < (CONST CHAR8 *) SegmentImageInfos + (UINT32) SegmentIterSize * NumSegments;
SegmentImageAddress += SegmentSize,
SegmentImageInfoPtr = (CONST VOID *) ((CONST CHAR8 *) SegmentImageInfoPtr + SegmentIterSize)
) {
SegmentImageInfo = *SegmentImageInfoPtr;
SegmentSize = UE_SEGMENT_SIZE (SegmentImageInfo);
SegmentPermissions = UE_SEGMENT_PERMISSIONS (SegmentImageInfo);
//
// Skip Image segments with the same memory permissions as the current range
// as they can be merged.
//
if (SegmentPermissions == Permissions) {
RangeSize += SegmentSize;
continue;
}
//
// Create an Image record section for the current memory permission range.
//
RecordSegment = &ImageRecord->Segments[NumRecordSegments];
RecordSegment->Size = RangeSize;
RecordSegment->Attributes = InternalPermissionsToAttributes (Permissions);
++NumRecordSegments;
//
// Start a Image record section with the current Image section.
//
RangeSize = SegmentSize;
Permissions = SegmentPermissions;
}
ImageAddress = UeLoaderGetImageAddress (Context);
ImageRecord->NumSegments = NumRecordSegments;
ImageRecord->StartAddress = ImageAddress;
ImageRecord->EndAddress = ImageAddress + SegmentImageAddress;
//
// Zero the remaining array entries to avoid uninitialised data.
//
ZeroMem (
ImageRecord->Segments + NumRecordSegments,
(NumSegments - NumRecordSegments) * sizeof (*ImageRecord->Segments)
);
return ImageRecord;
}
RETURN_STATUS
UefiImageDebugLocateImageUe (
OUT UE_LOADER_IMAGE_CONTEXT *Context,
IN UINTN Address
)
{
ASSERT (Context != NULL);
(VOID) Address;
//
// FIXME:
// This feature is currently unsupported.
//
DEBUG_RAISE ();
return RETURN_NOT_FOUND;
}
RETURN_STATUS
UefiImageGetFixedAddressUe (
IN OUT UE_LOADER_IMAGE_CONTEXT *Context,
OUT UINT64 *Address
)
{
ASSERT (Context != NULL);
ASSERT (Address != NULL);
//
// This feature is currently unsupported.
//
DEBUG_RAISE ();
return RETURN_NOT_FOUND;
}
// FIXME:
RETURN_STATUS
InternalGetDebugTable (
IN CONST UE_LOADER_IMAGE_CONTEXT *Context,
OUT CONST UE_DEBUG_TABLE **DebugTable
);
RETURN_STATUS
UefiImageDebugPrintSegmentsUe (
IN OUT UE_LOADER_IMAGE_CONTEXT *Context
)
{
RETURN_STATUS DebugStatus;
CONST UE_DEBUG_TABLE *DebugTable;
CONST CHAR8 *Name;
CONST UE_SEGMENT *Segments;
UINT8 LastSegmentIndex;
UINT8 SegmentIndex;
UINT32 SectionFileOffset;
UINT32 SegmentImageAddress;
CONST UE_SEGMENT_NAME *NameTable;
UINT32 ImageSize;
DebugStatus = InternalGetDebugTable (Context, &DebugTable);
LastSegmentIndex = UeGetSegments (Context, &Segments);
NameTable = UE_DEBUG_TABLE_SEGMENT_NAMES (DebugTable);
SectionFileOffset = UeGetSectionsFileOffset (Context);
//
// The first Image segment must begin the Image memory space.
//
SegmentImageAddress = 0;
for (SegmentIndex = 0; SegmentIndex <= LastSegmentIndex; ++SegmentIndex) {
if (!RETURN_ERROR (DebugStatus)) {
Name = (CONST CHAR8 *) NameTable[DebugTable->SymbolsPathSize];
} else {
STATIC_ASSERT (
sizeof (*NameTable) == sizeof ("Unknown"),
"The following may cause prohibited memory accesses."
);
Name = "Unknown";
}
ImageSize = UE_SEGMENT_SIZE (Segments[SegmentIndex].ImageInfo);
DEBUG ((
DEBUG_VERBOSE,
" Segment - '%c%c%c%c%c%c%c%c'\n",
" ImageSize - 0x%08x\n"
" ImageAddress - 0x%08x\n"
" FileSize - 0x%08x\n"
" FileOffset - 0x%08x\n"
" Permissions - 0x%08x\n",
Name[0], Name[1], Name[2], Name[3], Name[4], Name[5], Name[6], Name[7],
ImageSize,
SegmentImageAddress,
Segments[SegmentIndex].FileSize,
SectionFileOffset,
UE_SEGMENT_PERMISSIONS (Segments[SegmentIndex].ImageInfo)
));
SegmentImageAddress += ImageSize;
SectionFileOffset += Segments[SegmentIndex].FileSize;
}
return RETURN_SUCCESS;
}

View File

@ -0,0 +1,29 @@
#ifndef UE_SUPPORT_H_
#define UE_SUPPORT_H_
#include <Library/UeImageLib.h>
#include <Library/UefiImageLib.h>
UEFI_IMAGE_RECORD *
UefiImageLoaderGetImageRecordUe (
IN OUT UE_LOADER_IMAGE_CONTEXT *Context
);
RETURN_STATUS
UefiImageDebugLocateImageUe (
OUT UE_LOADER_IMAGE_CONTEXT *Context,
IN UINTN Address
);
RETURN_STATUS
UefiImageGetFixedAddressUe (
IN OUT UE_LOADER_IMAGE_CONTEXT *Context,
OUT UINT64 *Address
);
RETURN_STATUS
UefiImageDebugPrintSegmentsUe (
IN OUT UE_LOADER_IMAGE_CONTEXT *Context
);
#endif // UE_SUPPORT_H_

View File

@ -0,0 +1,281 @@
/** @file
UEFI Image Loader library implementation for UE Images.
Copyright (c) 2021, Marvin Häuser. All rights reserved.<BR>
SPDX-License-Identifier: BSD-3-Clause
**/
#define UEFI_IMAGE_LOADER_IMAGE_CONTEXT UE_LOADER_IMAGE_CONTEXT
#define UEFI_IMAGE_LOADER_RUNTIME_CONTEXT UE_LOADER_RUNTIME_CONTEXT
#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/UeImageLib.h>
#include <Library/PcdLib.h>
#include <Library/UefiImageLib.h>
#include "UeSupport.h"
RETURN_STATUS
UefiImageInitializeContextPreHash (
OUT UEFI_IMAGE_LOADER_IMAGE_CONTEXT *Context,
IN CONST VOID *FileBuffer,
IN UINT32 FileSize
)
{
return UeInitializeContextPreHash (Context, FileBuffer, FileSize);
}
RETURN_STATUS
UefiImageInitializeContextPostHash (
OUT UEFI_IMAGE_LOADER_IMAGE_CONTEXT *Context
)
{
return UeInitializeContextPostHash (Context);
}
BOOLEAN
UefiImageHashImageDefault (
IN OUT UEFI_IMAGE_LOADER_IMAGE_CONTEXT *Context,
IN OUT VOID *HashContext,
IN UEFI_IMAGE_LOADER_HASH_UPDATE HashUpdate
)
{
return UeHashImageDefault (Context, HashContext, HashUpdate);
}
RETURN_STATUS
UefiImageLoadImage (
IN OUT UEFI_IMAGE_LOADER_IMAGE_CONTEXT *Context,
OUT VOID *Destination,
IN UINT32 DestinationSize
)
{
return UeLoadImage (Context, Destination, DestinationSize);
}
BOOLEAN
UefiImageImageIsInplace (
IN OUT UEFI_IMAGE_LOADER_IMAGE_CONTEXT *Context
)
{
ASSERT (Context != NULL);
//
// FIXME: Implement
//
return FALSE;
}
RETURN_STATUS
UefiImageLoadImageInplace (
IN OUT UEFI_IMAGE_LOADER_IMAGE_CONTEXT *Context
)
{
return UeLoadImageInplace (Context);
}
RETURN_STATUS
UefiImageLoaderGetRuntimeContextSize (
IN OUT UEFI_IMAGE_LOADER_IMAGE_CONTEXT *Context,
OUT UINT32 *Size
)
{
return UeLoaderGetRuntimeContextSize (Context, Size);
}
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 UeRelocateImage (
Context,
BaseAddress
);
}
RETURN_STATUS
UefiImageRuntimeRelocateImage (
IN OUT VOID *Image,
IN UINT32 ImageSize,
IN UINT64 BaseAddress,
IN CONST UEFI_IMAGE_LOADER_RUNTIME_CONTEXT *RuntimeContext
)
{
return UeRelocateImageForRuntime (
Image,
ImageSize,
BaseAddress,
RuntimeContext
);
}
VOID
UefiImageDiscardSegments (
IN OUT UEFI_IMAGE_LOADER_IMAGE_CONTEXT *Context
)
{
ASSERT (Context != NULL);
//
// Anything discardable is not loaded in the first place.
//
}
RETURN_STATUS
UefiImageGetSymbolsPath (
IN OUT UEFI_IMAGE_LOADER_IMAGE_CONTEXT *Context,
OUT CONST CHAR8 **SymbolsPath,
OUT UINT32 *SymbolsPathSize
)
{
return UeGetSymbolsPath (Context, SymbolsPath, SymbolsPathSize);
}
RETURN_STATUS
UefiImageGetFirstCertificate (
IN OUT UEFI_IMAGE_LOADER_IMAGE_CONTEXT *Context,
OUT CONST WIN_CERTIFICATE **Certificate
)
{
return UeGetFirstCertificate (Context, Certificate);
}
RETURN_STATUS
UefiImageGetNextCertificate (
IN OUT UEFI_IMAGE_LOADER_IMAGE_CONTEXT *Context,
IN OUT CONST WIN_CERTIFICATE **Certificate
)
{
return UeGetNextCertificate (Context, Certificate);
}
RETURN_STATUS
UefiImageGetHiiDataRva (
IN OUT UEFI_IMAGE_LOADER_IMAGE_CONTEXT *Context,
OUT UINT32 *HiiRva,
OUT UINT32 *HiiSize
)
{
return UeGetHiiDataRva (Context, HiiRva, HiiSize);
}
UINT32
UefiImageGetEntryPointAddress (
IN OUT UEFI_IMAGE_LOADER_IMAGE_CONTEXT *Context
)
{
return UeGetAddressOfEntryPoint (Context);
}
UINT16
UefiImageGetMachine (
IN OUT UEFI_IMAGE_LOADER_IMAGE_CONTEXT *Context
)
{
return UeGetMachine (Context);
}
UINT16
UefiImageGetSubsystem (
IN OUT UEFI_IMAGE_LOADER_IMAGE_CONTEXT *Context
)
{
return UeGetSubsystem (Context);
}
UINT32
UefiImageGetSegmentAlignment (
IN OUT UEFI_IMAGE_LOADER_IMAGE_CONTEXT *Context
)
{
return UeGetSegmentAlignment (Context);
}
UINT32
UefiImageGetImageSize (
IN OUT UEFI_IMAGE_LOADER_IMAGE_CONTEXT *Context
)
{
return UeGetImageSize (Context);
}
UINT32
UefiImageGetImageSizeInplace (
IN OUT UEFI_IMAGE_LOADER_IMAGE_CONTEXT *Context
)
{
return UeGetImageSizeInplace (Context);
}
UINT64
UefiImageGetPreferredAddress (
IN OUT UEFI_IMAGE_LOADER_IMAGE_CONTEXT *Context
)
{
return UeGetPreferredAddress (Context);
}
BOOLEAN
UefiImageGetRelocsStripped (
IN OUT UEFI_IMAGE_LOADER_IMAGE_CONTEXT *Context
)
{
return UeGetRelocsStripped (Context);
}
UINTN
UefiImageLoaderGetImageAddress (
IN OUT UEFI_IMAGE_LOADER_IMAGE_CONTEXT *Context
)
{
return UeLoaderGetImageAddress (Context);
}
UEFI_IMAGE_RECORD *
UefiImageLoaderGetImageRecord (
IN OUT UEFI_IMAGE_LOADER_IMAGE_CONTEXT *Context
)
{
return UefiImageLoaderGetImageRecordUe (Context);
}
RETURN_STATUS
UefiImageDebugLocateImage (
OUT UEFI_IMAGE_LOADER_IMAGE_CONTEXT *Context,
IN UINTN Address
)
{
return UefiImageDebugLocateImageUe (Context, Address);
}
RETURN_STATUS
UefiImageGetFixedAddress (
IN OUT UEFI_IMAGE_LOADER_IMAGE_CONTEXT *Context,
OUT UINT64 *Address
)
{
return UefiImageGetFixedAddressUe (
Context,
Address
);
}
VOID
UefiImageDebugPrintSegments (
IN OUT UEFI_IMAGE_LOADER_IMAGE_CONTEXT *Context
)
{
UefiImageDebugPrintSegmentsUe (Context);
}

View File

@ -16,3 +16,4 @@
RegisterFilterLib|MdePkg/Library/RegisterFilterLibNull/RegisterFilterLibNull.inf
CpuLib|MdePkg/Library/BaseCpuLib/BaseCpuLib.inf
SmmCpuRendezvousLib|MdePkg/Library/SmmCpuRendezvousLibNull/SmmCpuRendezvousLibNull.inf
BaseOverflowLib|MdePkg/Library/BaseOverflowLib/BaseOverflowLib.inf

View File

@ -60,6 +60,8 @@
MdePkg/Library/BaseArmTrngLibNull/BaseArmTrngLibNull.inf
MdePkg/Library/BasePeCoffLib2/BasePeCoffLib2.inf
MdePkg/Library/BaseUefiImageLib/BaseUefiImageLibPeCoff.inf
MdePkg/Library/BaseUeImageLib/BaseUeImageLib.inf
MdePkg/Library/BaseUefiImageLib/BaseUefiImageLibUe.inf
MdePkg/Library/BaseUefiImageExtraActionLibNull/BaseUefiImageExtraActionLibNull.inf
MdePkg/Library/BasePerformanceLibNull/BasePerformanceLibNull.inf
MdePkg/Library/BasePostCodeLibDebug/BasePostCodeLibDebug.inf

View File

@ -46,6 +46,10 @@
SafeIntLib|MdePkg/Library/BaseSafeIntLib/BaseSafeIntLib.inf
RngLib|MdePkg/Library/BaseRngLib/BaseRngLib.inf
VariablePolicyHelperLib|MdeModulePkg/Library/VariablePolicyHelperLib/VariablePolicyHelperLib.inf
PeCoffLib2|MdePkg/Library/BasePeCoffLib2/BasePeCoffLib2.inf
UefiImageLib|MdePkg/Library/BaseUefiImageLib/BaseUefiImageLibPeCoff.inf
CacheMaintenanceLib|MdePkg/Library/BaseCacheMaintenanceLib/BaseCacheMaintenanceLib.inf
UefiImageExtraActionLib|MdePkg/Library/BaseUefiImageExtraActionLibNull/BaseUefiImageExtraActionLibNull.inf
!ifdef CONTINUOUS_INTEGRATION
BaseCryptLib|CryptoPkg/Library/BaseCryptLibNull/BaseCryptLibNull.inf

1
OpenCorePkg Submodule

@ -0,0 +1 @@
Subproject commit 1d65bf850099bc0d8cc3b282bebd16310a3ab487

View File

@ -146,7 +146,6 @@
PrintLib|MdePkg/Library/BasePrintLib/BasePrintLib.inf
BaseMemoryLib|MdePkg/Library/BaseMemoryLibRepStr/BaseMemoryLibRepStr.inf
BaseLib|MdePkg/Library/BaseLib/BaseLib.inf
BaseOverflowLib|MdePkg/Library/BaseOverflowLib/BaseOverflowLib.inf
SafeIntLib|MdePkg/Library/BaseSafeIntLib/BaseSafeIntLib.inf
TimeBaseLib|EmbeddedPkg/Library/TimeBaseLib/TimeBaseLib.inf
BmpSupportLib|MdeModulePkg/Library/BaseBmpSupportLib/BaseBmpSupportLib.inf
@ -600,14 +599,15 @@
#
!if $(LEGACY_WINDOWS_LOADER) == TRUE
# Allow execution of EfiLoaderData memory regions.
gEfiMdeModulePkgTokenSpaceGuid.PcdDxeNxMemoryProtectionPolicy|0x7FD1
gEfiMdeModulePkgTokenSpaceGuid.PcdDxeNxMemoryProtectionPolicy|0xFFFFFFFFFFFFFFD1
!elseif $(LINUX_LOADER) == TRUE
# Allow execution of EfiConventionalMemory, EfiBootServicesData and EfiLoaderData memory regions.
gEfiMdeModulePkgTokenSpaceGuid.PcdDxeNxMemoryProtectionPolicy|0x7F41
# Allow execution of EfiReservedMemoryType, EfiConventionalMemory, EfiBootServicesData and EfiLoaderData memory regions.
gEfiMdeModulePkgTokenSpaceGuid.PcdDxeNxMemoryProtectionPolicy|0xFFFFFFFFFFFFFF40
gEfiMdePkgTokenSpaceGuid.PcdImageLoaderAllowMisalignedOffset|TRUE
!elseif $(WINDOWS_10_IA32) == TRUE
# Allow execution of EfiReservedMemoryType, EfiConventionalMemory, EfiBootServicesData and EfiRuntimeServicesData memory regions.
gEfiMdeModulePkgTokenSpaceGuid.PcdDxeNxMemoryProtectionPolicy|0x7F04
gEfiMdeModulePkgTokenSpaceGuid.PcdDxeNxMemoryProtectionPolicy|0xFFFFFFFFFFFFFF04
gEfiMdeModulePkgTokenSpaceGuid.PcdImageProtectionPolicy|0x0
!endif
################################################################################

View File

@ -143,7 +143,6 @@
PrintLib|MdePkg/Library/BasePrintLib/BasePrintLib.inf
BaseMemoryLib|MdePkg/Library/BaseMemoryLibRepStr/BaseMemoryLibRepStr.inf
BaseLib|MdePkg/Library/BaseLib/BaseLib.inf
BaseOverflowLib|MdePkg/Library/BaseOverflowLib/BaseOverflowLib.inf
SafeIntLib|MdePkg/Library/BaseSafeIntLib/BaseSafeIntLib.inf
TimeBaseLib|EmbeddedPkg/Library/TimeBaseLib/TimeBaseLib.inf
BmpSupportLib|MdeModulePkg/Library/BaseBmpSupportLib/BaseBmpSupportLib.inf
@ -604,14 +603,15 @@
#
!if $(LEGACY_WINDOWS_LOADER) == TRUE
# Allow execution of EfiLoaderData memory regions.
gEfiMdeModulePkgTokenSpaceGuid.PcdDxeNxMemoryProtectionPolicy|0x7FD1
gEfiMdeModulePkgTokenSpaceGuid.PcdDxeNxMemoryProtectionPolicy|0xFFFFFFFFFFFFFFD1
!elseif $(LINUX_LOADER) == TRUE
# Allow execution of EfiConventionalMemory, EfiBootServicesData and EfiLoaderData memory regions.
gEfiMdeModulePkgTokenSpaceGuid.PcdDxeNxMemoryProtectionPolicy|0x7F41
# Allow execution of EfiReservedMemoryType, EfiConventionalMemory, EfiBootServicesData and EfiLoaderData memory regions.
gEfiMdeModulePkgTokenSpaceGuid.PcdDxeNxMemoryProtectionPolicy|0xFFFFFFFFFFFFFF40
gEfiMdePkgTokenSpaceGuid.PcdImageLoaderAllowMisalignedOffset|TRUE
!elseif $(WINDOWS_10_IA32) == TRUE
# Allow execution of EfiReservedMemoryType, EfiConventionalMemory, EfiBootServicesData and EfiRuntimeServicesData memory regions.
gEfiMdeModulePkgTokenSpaceGuid.PcdDxeNxMemoryProtectionPolicy|0x7F04
gEfiMdeModulePkgTokenSpaceGuid.PcdDxeNxMemoryProtectionPolicy|0xFFFFFFFFFFFFFF04
gEfiMdeModulePkgTokenSpaceGuid.PcdImageProtectionPolicy|0x0
!endif
################################################################################

View File

@ -62,10 +62,10 @@ FV = SECFV
[FD.MEMFD]
BaseAddress = $(MEMFD_BASE_ADDRESS)
Size = 0xD00000
Size = 0xE00000
ErasePolarity = 1
BlockSize = 0x10000
NumBlocks = 0xD0
NumBlocks = 0xE0
0x000000|0x006000
gUefiOvmfPkgTokenSpaceGuid.PcdOvmfSecPageTablesBase|gUefiOvmfPkgTokenSpaceGuid.PcdOvmfSecPageTablesSize
@ -86,7 +86,7 @@ gUefiOvmfPkgTokenSpaceGuid.PcdOvmfSecPeiTempRamBase|gUefiOvmfPkgTokenSpaceGuid.P
gUefiOvmfPkgTokenSpaceGuid.PcdOvmfPeiMemFvBase|gUefiOvmfPkgTokenSpaceGuid.PcdOvmfPeiMemFvSize
FV = PEIFV
0x100000|0xC00000
0x100000|0xD00000
gUefiOvmfPkgTokenSpaceGuid.PcdOvmfDxeMemFvBase|gUefiOvmfPkgTokenSpaceGuid.PcdOvmfDxeMemFvSize
FV = DXEFV

View File

@ -166,7 +166,6 @@
PrintLib|MdePkg/Library/BasePrintLib/BasePrintLib.inf
BaseMemoryLib|MdePkg/Library/BaseMemoryLibRepStr/BaseMemoryLibRepStr.inf
BaseLib|MdePkg/Library/BaseLib/BaseLib.inf
BaseOverflowLib|MdePkg/Library/BaseOverflowLib/BaseOverflowLib.inf
SafeIntLib|MdePkg/Library/BaseSafeIntLib/BaseSafeIntLib.inf
TimeBaseLib|EmbeddedPkg/Library/TimeBaseLib/TimeBaseLib.inf
BmpSupportLib|MdeModulePkg/Library/BaseBmpSupportLib/BaseBmpSupportLib.inf
@ -633,10 +632,10 @@
#
!if $(LEGACY_WINDOWS_LOADER) == TRUE
# Allow execution of EfiLoaderData memory regions.
gEfiMdeModulePkgTokenSpaceGuid.PcdDxeNxMemoryProtectionPolicy|0x7FD1
gEfiMdeModulePkgTokenSpaceGuid.PcdDxeNxMemoryProtectionPolicy|0xFFFFFFFFFFFFFFD1
!elseif $(LINUX_LOADER) == TRUE
# Allow execution of EfiConventionalMemory, EfiBootServicesData and EfiLoaderData memory regions.
gEfiMdeModulePkgTokenSpaceGuid.PcdDxeNxMemoryProtectionPolicy|0x7F41
# Allow execution of EfiReservedMemoryType, EfiConventionalMemory, EfiBootServicesData and EfiLoaderData memory regions.
gEfiMdeModulePkgTokenSpaceGuid.PcdDxeNxMemoryProtectionPolicy|0xFFFFFFFFFFFFFF40
gEfiMdePkgTokenSpaceGuid.PcdImageLoaderAllowMisalignedOffset|TRUE
!endif

View File

@ -82,6 +82,14 @@
## SOMETIMES_PRODUCES ## GUID # Unique ID for the type of the signature.
gEfiCertSha256Guid
## SOMETIMES_CONSUMES ## GUID # Unique ID for the type of the signature.
## SOMETIMES_PRODUCES ## GUID # Unique ID for the type of the signature.
gEfiCertSha384Guid
## SOMETIMES_CONSUMES ## GUID # Unique ID for the type of the signature.
## SOMETIMES_PRODUCES ## GUID # Unique ID for the type of the signature.
gEfiCertSha512Guid
## SOMETIMES_CONSUMES ## Variable:L"db"
## SOMETIMES_PRODUCES ## Variable:L"db"
## SOMETIMES_CONSUMES ## Variable:L"dbx"

View File

@ -1983,7 +1983,7 @@ EnrollImageSignatureToSigDB (
Status = UefiImageGetFirstCertificate (&ImageContext, &Certificate);
if (Status == RETURN_NOT_FOUND) {
if (!HashPeImage (&ImageContext, HASHALG_SHA256, ImageDigest, &ImageDigestSize, &CertType)) {
if (!HashPeImage (&ImageContext, HASHALG_SHA256, ImageDigest, &ImageDigestSize)) {
Status = EFI_SECURITY_VIOLATION;
goto ON_EXIT;
}
@ -1995,7 +1995,7 @@ EnrollImageSignatureToSigDB (
goto ON_EXIT;
}
if (!HashPeImage (&ImageContext, HASHALG_SHA256, ImageDigest, &ImageDigestSize, &CertType)) {
if (!HashPeImage (&ImageContext, HASHALG_SHA256, ImageDigest, &ImageDigestSize)) {
Status = EFI_ABORTED;
goto ON_EXIT;
}

View File

@ -1,27 +0,0 @@
# FIXME: Docs
[Defines]
INF_VERSION = 0x00010005
BASE_NAME = UefiPayloadEntryMemoryAllocationLib
FILE_GUID = D3C5B8A1-B946-4D46-8251-9020A527EE40
MODULE_TYPE = BASE
VERSION_STRING = 1.0
LIBRARY_CLASS = UefiPayloadEntryMemoryAllocationLib|SEC
#
# The following information is for reference only and not required by the build tools.
#
# VALID_ARCHITECTURES = IA32 X64
#
[Sources]
MemoryAllocation.c
[Packages]
MdePkg/MdePkg.dec
UefiPayloadPkg/UefiPayloadPkg.dec
[LibraryClasses]
BaseMemoryLib
DebugLib
HobLib

View File

@ -1,198 +1,247 @@
/** @file
Copyright (c) 2008 - 2009, Apple Inc. All rights reserved.<BR>
Copyright (c) 2020, Intel Corporation. All rights reserved.<BR>
SPDX-License-Identifier: BSD-2-Clause-Patent
**/
#include "UefiPayloadEntry.h"
/**
Allocates one or more pages of type EfiBootServicesData.
Allocates the number of pages of MemoryType and returns a pointer to the
allocated buffer. The buffer returned is aligned on a 4KB boundary.
If Pages is 0, then NULL is returned.
If there is not enough memory availble to satisfy the request, then NULL
is returned.
@param Pages The number of 4 KB pages to allocate.
@return A pointer to the allocated buffer or NULL if allocation fails.
**/
VOID *
EFIAPI
AllocatePages (
IN UINTN Pages
)
{
EFI_PEI_HOB_POINTERS Hob;
EFI_PHYSICAL_ADDRESS Offset;
EFI_HOB_HANDOFF_INFO_TABLE *HobTable;
Hob.Raw = GetHobList ();
HobTable = Hob.HandoffInformationTable;
if (Pages == 0) {
return NULL;
}
// Make sure allocation address is page alligned.
Offset = HobTable->EfiFreeMemoryTop & EFI_PAGE_MASK;
if (Offset != 0) {
HobTable->EfiFreeMemoryTop -= Offset;
}
//
// Check available memory for the allocation
//
if (HobTable->EfiFreeMemoryTop - ((Pages * EFI_PAGE_SIZE) + sizeof (EFI_HOB_MEMORY_ALLOCATION)) < HobTable->EfiFreeMemoryBottom) {
return NULL;
}
HobTable->EfiFreeMemoryTop -= Pages * EFI_PAGE_SIZE;
BuildMemoryAllocationHob (HobTable->EfiFreeMemoryTop, Pages * EFI_PAGE_SIZE, EfiBootServicesData);
return (VOID *)(UINTN)HobTable->EfiFreeMemoryTop;
}
/**
Frees one or more 4KB pages that were previously allocated with one of the page allocation
functions in the Memory Allocation Library.
Frees the number of 4KB pages specified by Pages from the buffer specified by Buffer. Buffer
must have been allocated on a previous call to the page allocation services of the Memory
Allocation Library. If it is not possible to free allocated pages, then this function will
perform no actions.
If Buffer was not allocated with a page allocation function in the Memory Allocation Library,
then ASSERT().
If Pages is zero, then ASSERT().
@param Buffer Pointer to the buffer of pages to free.
@param Pages The number of 4 KB pages to free.
**/
VOID
EFIAPI
FreePages (
IN VOID *Buffer,
IN UINTN Pages
)
{
}
/**
Allocates one or more pages of type EfiBootServicesData at a specified alignment.
Allocates the number of pages specified by Pages of type EfiBootServicesData with an
alignment specified by Alignment.
If Pages is 0, then NULL is returned.
If Alignment is not a power of two and Alignment is not zero, then ASSERT().
If there is no enough memory at the specified alignment available to satisfy the
request, then NULL is returned.
@param Pages The number of 4 KB pages to allocate.
@param Alignment The requested alignment of the allocation.
@return A pointer to the allocated buffer or NULL if allocation fails.
**/
VOID *
EFIAPI
AllocateAlignedPages (
IN UINTN Pages,
IN UINTN Alignment
)
{
VOID *Memory;
UINTN AlignmentMask;
//
// Alignment must be a power of two or zero.
//
ASSERT ((Alignment & (Alignment - 1)) == 0);
if (Pages == 0) {
return NULL;
}
//
// Check overflow.
//
ASSERT (Pages <= (MAX_ADDRESS - EFI_SIZE_TO_PAGES (Alignment)));
Memory = (VOID *)(UINTN)AllocatePages (Pages + EFI_SIZE_TO_PAGES (Alignment));
if (Memory == NULL) {
return NULL;
}
if (Alignment == 0) {
AlignmentMask = Alignment;
} else {
AlignmentMask = Alignment - 1;
}
return (VOID *)(UINTN)(((UINTN)Memory + AlignmentMask) & ~AlignmentMask);
}
/**
Allocates a buffer of type EfiBootServicesData.
Allocates the number bytes specified by AllocationSize of type EfiBootServicesData and returns a
pointer to the allocated buffer. If AllocationSize is 0, then a valid buffer of 0 size is
returned. If there is not enough memory remaining to satisfy the request, then NULL is returned.
@param AllocationSize The number of bytes to allocate.
@return A pointer to the allocated buffer or NULL if allocation fails.
**/
VOID *
EFIAPI
AllocatePool (
IN UINTN AllocationSize
)
{
EFI_HOB_MEMORY_POOL *Hob;
if (AllocationSize > 0x4000) {
// Please use AllocatePages for big allocations
return NULL;
}
Hob = (EFI_HOB_MEMORY_POOL *)CreateHob (EFI_HOB_TYPE_MEMORY_POOL, (UINT16)(sizeof (EFI_HOB_MEMORY_POOL) + AllocationSize));
return (VOID *)(Hob + 1);
}
/**
Allocates and zeros a buffer of type EfiBootServicesData.
Allocates the number bytes specified by AllocationSize of type EfiBootServicesData, clears the
buffer with zeros, and returns a pointer to the allocated buffer. If AllocationSize is 0, then a
valid buffer of 0 size is returned. If there is not enough memory remaining to satisfy the
request, then NULL is returned.
@param AllocationSize The number of bytes to allocate and zero.
@return A pointer to the allocated buffer or NULL if allocation fails.
**/
VOID *
EFIAPI
AllocateZeroPool (
IN UINTN AllocationSize
)
{
VOID *Buffer;
Buffer = AllocatePool (AllocationSize);
if (Buffer == NULL) {
return NULL;
}
ZeroMem (Buffer, AllocationSize);
return Buffer;
}
/** @file
Copyright (c) 2008 - 2009, Apple Inc. All rights reserved.<BR>
Copyright (c) 2020, Intel Corporation. All rights reserved.<BR>
SPDX-License-Identifier: BSD-2-Clause-Patent
**/
#include <PiPei.h>
#include <Library/BaseLib.h>
#include <Library/BaseMemoryLib.h>
#include <Library/MemoryAllocationLib.h>
#include <Library/DebugLib.h>
#include <Library/HobLib.h>
#include <Guid/MemoryAllocationHob.h>
/**
Add a new HOB to the HOB List.
@param HobType Type of the new HOB.
@param HobLength Length of the new HOB to allocate.
@return NULL if there is no space to create a hob.
@return The address point to the new created hob.
**/
VOID *
EFIAPI
CreateHob (
IN UINT16 HobType,
IN UINT16 HobLength
);
/**
Allocates one or more pages of type EfiBootServicesData.
Allocates the number of pages of MemoryType and returns a pointer to the
allocated buffer. The buffer returned is aligned on a 4KB boundary.
If Pages is 0, then NULL is returned.
If there is not enough memory availble to satisfy the request, then NULL
is returned.
@param Pages The number of 4 KB pages to allocate.
@return A pointer to the allocated buffer or NULL if allocation fails.
**/
VOID *
EFIAPI
AllocatePages (
IN UINTN Pages
)
{
EFI_PEI_HOB_POINTERS Hob;
EFI_PHYSICAL_ADDRESS Offset;
EFI_HOB_HANDOFF_INFO_TABLE *HobTable;
Hob.Raw = GetHobList ();
HobTable = Hob.HandoffInformationTable;
if (Pages == 0) {
return NULL;
}
// Make sure allocation address is page alligned.
Offset = HobTable->EfiFreeMemoryTop & EFI_PAGE_MASK;
if (Offset != 0) {
HobTable->EfiFreeMemoryTop -= Offset;
}
//
// Check available memory for the allocation
//
if (HobTable->EfiFreeMemoryTop - ((Pages * EFI_PAGE_SIZE) + sizeof (EFI_HOB_MEMORY_ALLOCATION)) < HobTable->EfiFreeMemoryBottom) {
return NULL;
}
HobTable->EfiFreeMemoryTop -= Pages * EFI_PAGE_SIZE;
BuildMemoryAllocationHob (HobTable->EfiFreeMemoryTop, Pages * EFI_PAGE_SIZE, EfiBootServicesData);
return (VOID *)(UINTN)HobTable->EfiFreeMemoryTop;
}
/**
Frees one or more 4KB pages that were previously allocated with one of the page allocation
functions in the Memory Allocation Library.
Frees the number of 4KB pages specified by Pages from the buffer specified by Buffer. Buffer
must have been allocated on a previous call to the page allocation services of the Memory
Allocation Library. If it is not possible to free allocated pages, then this function will
perform no actions.
If Buffer was not allocated with a page allocation function in the Memory Allocation Library,
then ASSERT().
If Pages is zero, then ASSERT().
@param Buffer Pointer to the buffer of pages to free.
@param Pages The number of 4 KB pages to free.
**/
VOID
EFIAPI
FreePages (
IN VOID *Buffer,
IN UINTN Pages
)
{
}
/**
Allocates one or more pages of type EfiBootServicesData at a specified alignment.
Allocates the number of pages specified by Pages of type EfiBootServicesData with an
alignment specified by Alignment.
If Pages is 0, then NULL is returned.
If Alignment is not a power of two and Alignment is not zero, then ASSERT().
If there is no enough memory at the specified alignment available to satisfy the
request, then NULL is returned.
@param Pages The number of 4 KB pages to allocate.
@param Alignment The requested alignment of the allocation.
@return A pointer to the allocated buffer or NULL if allocation fails.
**/
VOID *
EFIAPI
AllocateAlignedPages (
IN UINTN Pages,
IN UINTN Alignment
)
{
VOID *Memory;
UINTN AlignmentMask;
//
// Alignment must be a power of two or zero.
//
ASSERT ((Alignment & (Alignment - 1)) == 0);
if (Pages == 0) {
return NULL;
}
//
// Check overflow.
//
ASSERT (Pages <= (MAX_ADDRESS - EFI_SIZE_TO_PAGES (Alignment)));
Memory = (VOID *)(UINTN)AllocatePages (Pages + EFI_SIZE_TO_PAGES (Alignment));
if (Memory == NULL) {
return NULL;
}
if (Alignment == 0) {
AlignmentMask = Alignment;
} else {
AlignmentMask = Alignment - 1;
}
return (VOID *)(UINTN)(((UINTN)Memory + AlignmentMask) & ~AlignmentMask);
}
/**
Allocates a buffer of type EfiBootServicesData.
Allocates the number bytes specified by AllocationSize of type EfiBootServicesData and returns a
pointer to the allocated buffer. If AllocationSize is 0, then a valid buffer of 0 size is
returned. If there is not enough memory remaining to satisfy the request, then NULL is returned.
@param AllocationSize The number of bytes to allocate.
@return A pointer to the allocated buffer or NULL if allocation fails.
**/
VOID *
EFIAPI
AllocatePool (
IN UINTN AllocationSize
)
{
EFI_HOB_MEMORY_POOL *Hob;
if (AllocationSize > 0x4000) {
// Please use AllocatePages for big allocations
return NULL;
}
Hob = (EFI_HOB_MEMORY_POOL *)CreateHob (EFI_HOB_TYPE_MEMORY_POOL, (UINT16)(sizeof (EFI_HOB_MEMORY_POOL) + AllocationSize));
return (VOID *)(Hob + 1);
}
/**
Allocates and zeros a buffer of type EfiBootServicesData.
Allocates the number bytes specified by AllocationSize of type EfiBootServicesData, clears the
buffer with zeros, and returns a pointer to the allocated buffer. If AllocationSize is 0, then a
valid buffer of 0 size is returned. If there is not enough memory remaining to satisfy the
request, then NULL is returned.
@param AllocationSize The number of bytes to allocate and zero.
@return A pointer to the allocated buffer or NULL if allocation fails.
**/
VOID *
EFIAPI
AllocateZeroPool (
IN UINTN AllocationSize
)
{
VOID *Buffer;
Buffer = AllocatePool (AllocationSize);
if (Buffer == NULL) {
return NULL;
}
ZeroMem (Buffer, AllocationSize);
return Buffer;
}
/**
Frees a buffer that was previously allocated with one of the pool allocation functions in the
Memory Allocation Library.
Frees the buffer specified by Buffer. Buffer must have been allocated on a previous call to the
pool allocation services of the Memory Allocation Library. If it is not possible to free pool
resources, then this function will perform no actions.
If Buffer was not allocated with a pool allocation function in the Memory Allocation Library,
then ASSERT().
@param Buffer The pointer to the buffer to free.
**/
VOID
EFIAPI
FreePool (
IN VOID *Buffer
)
{
//
// PEI phase does not support to free pool, so leave it as NOP.
//
}

View File

@ -0,0 +1,40 @@
## @file
# Instance of Memory Allocation Library using PEI Services.
#
# Memory Allocation Library that uses PEI Services to allocate memory.
# Free operations are ignored.
#
# Copyright (c) 2007 - 2018, Intel Corporation. All rights reserved.<BR>
#
# SPDX-License-Identifier: BSD-2-Clause-Patent
#
#
##
[Defines]
INF_VERSION = 0x00010005
BASE_NAME = UefiPayloadMemoryAllocationLib
MODULE_UNI_FILE = UefiPayloadMemoryAllocationLib.uni
FILE_GUID = b694e0dc-cd4e-4b30-885b-9c164ed3e74a
MODULE_TYPE = PEIM
VERSION_STRING = 1.0
LIBRARY_CLASS = MemoryAllocationLib|PEIM PEI_CORE SEC
#
# VALID_ARCHITECTURES = IA32 X64 EBC (EBC is for build only)
#
[Sources]
MemoryAllocationLib.c
[Packages]
MdePkg/MdePkg.dec
[LibraryClasses]
DebugLib
BaseMemoryLib
BaseLib
HobLib

View File

@ -0,0 +1,17 @@
// /** @file
// Instance of Memory Allocation Library using PEI Services.
//
// Memory Allocation Library that uses PEI Services to allocate memory.
// Free operations are ignored.
//
// Copyright (c) 2007 - 2014, Intel Corporation. All rights reserved.<BR>
//
// SPDX-License-Identifier: BSD-2-Clause-Patent
//
// **/
#string STR_MODULE_ABSTRACT #language en-US "Instance of Memory Allocation Library for Uefi payloads"
#string STR_MODULE_DESCRIPTION #language en-US "Memory Allocation Library that allocates memory in uefi payload implementations. Free operations are ignored."

View File

@ -315,7 +315,7 @@
PcdLib|MdePkg/Library/BasePcdLibNull/BasePcdLibNull.inf
DxeHobListLib|UefiPayloadPkg/Library/DxeHobListLibNull/DxeHobListLibNull.inf
DebugLib|MdePkg/Library/BaseDebugLibSerialPort/BaseDebugLibSerialPort.inf
MemoryAllocationLib|UefiPayloadPkg/Library/UefiPayloadEntryMemoryAllocationLib/UefiPayloadEntryMemoryAllocationLib.inf
MemoryAllocationLib|UefiPayloadPkg/Library/UefiPayloadMemoryAllocationLib/UefiPayloadMemoryAllocationLib.inf
[LibraryClasses.common.DXE_CORE]
DxeHobListLib|UefiPayloadPkg/Library/DxeHobListLibNull/DxeHobListLibNull.inf

View File

@ -1,32 +0,0 @@
-Wall
-Wextra
-Wpedantic
-Wno-missing-prototypes
-Wcast-align
-Wcast-qual
-Wextra-semi-stmt
-Wshorten-64-to-32
-Wshift-sign-overflow
-Wsign-compare
-Wsign-conversion
-Wsigned-enum-bitfield
-Wconditional-uninitialized
-Wimplicit-int-conversion
-fshort-wchar
-target
x86_64-unknown-windows-gnu
-IMdePkg/Include
-IMdeModulePkg/Include
-IMdePkg/Include/X64
-IUefiCpuPkg/Include
-IMdeModulePkg/Core/Dxe
-IMdeModulePkg/Core/Pei
-ISecurityPkg/Include
-IArmPkg/Include
-IArmPlatformPkg/Include
-IStandaloneMmPkg/Include
-ICryptoPkg/Include
-IEmbeddedPkg/Include
-includeUefi.h

View File

@ -72,6 +72,7 @@ function SetWorkspace()
# Set $WORKSPACE
#
export WORKSPACE=$PWD
export PACKAGES_PATH=$PWD
return 0
}