diff --git a/.gitmodules b/.gitmodules index 8011a88d9d..ad2570a1c9 100644 --- a/.gitmodules +++ b/.gitmodules @@ -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 diff --git a/BaseTools/.gitignore b/BaseTools/.gitignore index ec9c69f8b2..7bb6eea44b 100644 --- a/BaseTools/.gitignore +++ b/BaseTools/.gitignore @@ -18,4 +18,8 @@ Source/C/bin/ Source/C/libs/ Bin/Win32 Lib -BaseToolsBuild/ \ No newline at end of file +BaseToolsBuild/ +ImageTool/ImageTool +ImageTool/ImageTool32 +ImageTool/ImageTool64 +MicroTool/MicroTool diff --git a/BaseTools/BinWrappers/PosixLike/ImageTool b/BaseTools/BinWrappers/PosixLike/ImageTool new file mode 100755 index 0000000000..0be45b7a68 --- /dev/null +++ b/BaseTools/BinWrappers/PosixLike/ImageTool @@ -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 diff --git a/BaseTools/BinWrappers/PosixLike/MicroTool b/BaseTools/BinWrappers/PosixLike/MicroTool new file mode 100644 index 0000000000..0e22e2775d --- /dev/null +++ b/BaseTools/BinWrappers/PosixLike/MicroTool @@ -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 diff --git a/BaseTools/BinWrappers/WindowsLike/ImageTool.bat b/BaseTools/BinWrappers/WindowsLike/ImageTool.bat new file mode 100644 index 0000000000..687fd2e078 --- /dev/null +++ b/BaseTools/BinWrappers/WindowsLike/ImageTool.bat @@ -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! + ) +) diff --git a/BaseTools/BinWrappers/WindowsLike/MicroTool.bat b/BaseTools/BinWrappers/WindowsLike/MicroTool.bat new file mode 100644 index 0000000000..abd86e9a22 --- /dev/null +++ b/BaseTools/BinWrappers/WindowsLike/MicroTool.bat @@ -0,0 +1,6 @@ +:: +:: Copyright (c) 2022, Mikhail Krichanov. All rights reserved. +:: SPDX-License-Identifier: BSD-3-Clause +:: +@echo off +call MicroTool.exe %* diff --git a/BaseTools/Conf/build_rule.template b/BaseTools/Conf/build_rule.template index 77227738b7..5ee1ab8da6 100755 --- a/BaseTools/Conf/build_rule.template +++ b/BaseTools/Conf/build_rule.template @@ -272,7 +272,14 @@ $(RM) ${dst} "$(SLINK)" cr ${dst} $(SLINK_FLAGS) @$(OBJECT_FILES_LIST) - + + + "$(SLINK)" $(SLINK_FLAGS) ${dst} --via $(OBJECT_FILES_LIST) + + + # $(OBJECT_FILES_LIST) has wrong paths for cygwin + "$(SLINK)" $(SLINK_FLAGS) ${dst} $(OBJECT_FILES) + "$(SLINK)" $(SLINK_FLAGS) ${dst} -filelist $(OBJECT_FILES_LIST) @@ -299,8 +306,8 @@ "$(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] *.lib @@ -334,8 +341,8 @@ "$(DLINK)" -o ${dst} $(DLINK_FLAGS) $(DLINK_SPATH) -filelist $(STATIC_LIBRARY_FILES_LIST) $(DLINK2_FLAGS) - - + + [Dynamic-Library-File] ?.dll @@ -346,32 +353,33 @@ $(OUTPUT_DIR)(+)$(MODULE_NAME).map - "$(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) - + -$(CP) $(DEBUG_DIR)(+)*.pdb $(OUTPUT_DIR) + + $(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) - + # 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 @@ 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 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 @@ "$(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} "$(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] @@ -459,25 +467,24 @@ "$(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} "$(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} "$(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} - + "$(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] ?.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 - + 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] @@ -538,7 +545,7 @@ $(OUTPUT_DIR)(+)${s_base}.mcb - "$(GENFW)" -o ${dst} -m ${src} $(GENFW_FLAGS) + MicroTool TxtToBin ${src} ${dst} [Microcode-Binary-File] @@ -551,7 +558,7 @@ $(OUTPUT_DIR)(+)$(MODULE_NAME).bin - "$(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 - "$(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 - "$(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} - "$(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) diff --git a/BaseTools/Conf/tools_def.template b/BaseTools/Conf/tools_def.template index 764c25b187..42fe4ca2c2 100755 --- a/BaseTools/Conf/tools_def.template +++ b/BaseTools/Conf/tools_def.template @@ -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 diff --git a/BaseTools/GNUmakefile b/BaseTools/GNUmakefile index d29f6d9c9b..fdaa7fa9ec 100644 --- a/BaseTools/GNUmakefile +++ b/BaseTools/GNUmakefile @@ -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) diff --git a/BaseTools/ImageTool/BinEmit.c b/BaseTools/ImageTool/BinEmit.c new file mode 100644 index 0000000000..36a5f61863 --- /dev/null +++ b/BaseTools/ImageTool/BinEmit.c @@ -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; +} diff --git a/BaseTools/ImageTool/ElfScan.c b/BaseTools/ImageTool/ElfScan.c new file mode 100644 index 0000000000..a8a7bc9bdf --- /dev/null +++ b/BaseTools/ImageTool/ElfScan.c @@ -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; +} diff --git a/BaseTools/ImageTool/GNUmakefile b/BaseTools/ImageTool/GNUmakefile new file mode 100644 index 0000000000..812d6fbda1 --- /dev/null +++ b/BaseTools/ImageTool/GNUmakefile @@ -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 diff --git a/BaseTools/ImageTool/Image.c b/BaseTools/ImageTool/Image.c new file mode 100644 index 0000000000..1bd818a24d --- /dev/null +++ b/BaseTools/ImageTool/Image.c @@ -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)); +} diff --git a/BaseTools/ImageTool/ImageTool.c b/BaseTools/ImageTool/ImageTool.c new file mode 100644 index 0000000000..714626e29d --- /dev/null +++ b/BaseTools/ImageTool/ImageTool.c @@ -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 +#include +#include + +#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; +} diff --git a/BaseTools/ImageTool/ImageTool.h b/BaseTools/ImageTool/ImageTool.h new file mode 100644 index 0000000000..40e01b4bcb --- /dev/null +++ b/BaseTools/ImageTool/ImageTool.h @@ -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 +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#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 diff --git a/BaseTools/ImageTool/Makefile b/BaseTools/ImageTool/Makefile new file mode 100644 index 0000000000..2b1ad69ea0 --- /dev/null +++ b/BaseTools/ImageTool/Makefile @@ -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)\ diff --git a/BaseTools/ImageTool/Pcds.h b/BaseTools/ImageTool/Pcds.h new file mode 100644 index 0000000000..248c42e458 --- /dev/null +++ b/BaseTools/ImageTool/Pcds.h @@ -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 diff --git a/BaseTools/ImageTool/PeEmit.c b/BaseTools/ImageTool/PeEmit.c new file mode 100644 index 0000000000..a756242a37 --- /dev/null +++ b/BaseTools/ImageTool/PeEmit.c @@ -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; +} diff --git a/BaseTools/ImageTool/PeScan.c b/BaseTools/ImageTool/PeScan.c new file mode 100644 index 0000000000..e682d6ee10 --- /dev/null +++ b/BaseTools/ImageTool/PeScan.c @@ -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; +} diff --git a/BaseTools/ImageTool/UeEmit.c b/BaseTools/ImageTool/UeEmit.c new file mode 100644 index 0000000000..6990177989 --- /dev/null +++ b/BaseTools/ImageTool/UeEmit.c @@ -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; +} diff --git a/BaseTools/Makefile b/BaseTools/Makefile index 10963009e9..28fa83e4dc 100644 --- a/BaseTools/Makefile +++ b/BaseTools/Makefile @@ -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) - diff --git a/BaseTools/MicroTool/GNUmakefile b/BaseTools/MicroTool/GNUmakefile new file mode 100644 index 0000000000..f85f58f62e --- /dev/null +++ b/BaseTools/MicroTool/GNUmakefile @@ -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 diff --git a/BaseTools/MicroTool/Makefile b/BaseTools/MicroTool/Makefile new file mode 100644 index 0000000000..c6b679091a --- /dev/null +++ b/BaseTools/MicroTool/Makefile @@ -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)\ diff --git a/BaseTools/MicroTool/MicroTool.c b/BaseTools/MicroTool/MicroTool.c new file mode 100644 index 0000000000..a01bf20f68 --- /dev/null +++ b/BaseTools/MicroTool/MicroTool.c @@ -0,0 +1,298 @@ +/** @file + Copyright (c) 2022, Mikhail Krichanov. All rights reserved. + SPDX-License-Identifier: BSD-3-Clause +**/ + +#include +#include +#include +#include + +#include + +#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; +} diff --git a/BaseTools/Source/C/GenFv/GenFvInternalLib.c b/BaseTools/Source/C/GenFv/GenFvInternalLib.c index 2b65b33271..a921eaf450 100644 --- a/BaseTools/Source/C/GenFv/GenFvInternalLib.c +++ b/BaseTools/Source/C/GenFv/GenFvInternalLib.c @@ -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), diff --git a/BaseTools/Source/C/Makefiles/ms.app b/BaseTools/Source/C/Makefiles/ms.app index aecae37396..0e6e16474c 100644 --- a/BaseTools/Source/C/Makefiles/ms.app +++ b/BaseTools/Source/C/Makefiles/ms.app @@ -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 - diff --git a/CryptoPkg/Library/OpensslLib/openssl b/CryptoPkg/Library/OpensslLib/openssl index 52c587d60b..d82e959e62 160000 --- a/CryptoPkg/Library/OpensslLib/openssl +++ b/CryptoPkg/Library/OpensslLib/openssl @@ -1 +1 @@ -Subproject commit 52c587d60be67c337364b830dd3fdc15404a2f04 +Subproject commit d82e959e621a3d597f1e0d50ff8c2d8b96915fd7 diff --git a/MdePkg/Include/Ia32/ProcessorBind.h b/MdePkg/Include/Ia32/ProcessorBind.h index ee39d1cfe1..b77e50e84f 100644 --- a/MdePkg/Include/Ia32/ProcessorBind.h +++ b/MdePkg/Include/Ia32/ProcessorBind.h @@ -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; diff --git a/MdePkg/Include/IndustryStandard/PeImage2.h b/MdePkg/Include/IndustryStandard/PeImage2.h index 7c04d0f42a..6f4a1e144e 100644 --- a/MdePkg/Include/IndustryStandard/PeImage2.h +++ b/MdePkg/Include/IndustryStandard/PeImage2.h @@ -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. diff --git a/MdePkg/Include/IndustryStandard/UeCertStore.h b/MdePkg/Include/IndustryStandard/UeCertStore.h new file mode 100644 index 0000000000..0f87997ba5 --- /dev/null +++ b/MdePkg/Include/IndustryStandard/UeCertStore.h @@ -0,0 +1,219 @@ +/** @file + Definitions of the UE certificate store format. + + Copyright (c) 2021, Marvin Häuser. All rights reserved.
+ + 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_ diff --git a/MdePkg/Include/IndustryStandard/UeImage.h b/MdePkg/Include/IndustryStandard/UeImage.h new file mode 100644 index 0000000000..0722763425 --- /dev/null +++ b/MdePkg/Include/IndustryStandard/UeImage.h @@ -0,0 +1,580 @@ +/** @file + Definitions of the UEFI Executable file format. + + Copyright (c) 2021, Marvin Häuser. All rights reserved.
+ + 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_ diff --git a/MdePkg/Include/Library/UeImageLib.h b/MdePkg/Include/Library/UeImageLib.h new file mode 100644 index 0000000000..e2ed2e6fde --- /dev/null +++ b/MdePkg/Include/Library/UeImageLib.h @@ -0,0 +1,250 @@ +/** @file + UEFI Image Loader library implementation for UE Images. + + Copyright (c) 2021, Marvin Häuser. All rights reserved.
+ + SPDX-License-Identifier: BSD-3-Clause +**/ + +#ifndef UE_LIB_H_ +#define UE_LIB_H_ + +#include + +// 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_ diff --git a/MdePkg/Include/X64/ProcessorBind.h b/MdePkg/Include/X64/ProcessorBind.h index ca84616ddf..8cc9633419 100644 --- a/MdePkg/Include/X64/ProcessorBind.h +++ b/MdePkg/Include/X64/ProcessorBind.h @@ -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, diff --git a/MdePkg/Library/BaseOverflowLib/Alignment.c b/MdePkg/Library/BaseOverflowLib/BaseAlignment.c similarity index 100% rename from MdePkg/Library/BaseOverflowLib/Alignment.c rename to MdePkg/Library/BaseOverflowLib/BaseAlignment.c diff --git a/MdePkg/Library/BaseOverflowLib/BitOverflow.c b/MdePkg/Library/BaseOverflowLib/BaseBitOverflow.c similarity index 99% rename from MdePkg/Library/BaseOverflowLib/BitOverflow.c rename to MdePkg/Library/BaseOverflowLib/BaseBitOverflow.c index c70418f8ca..7589b01c64 100644 --- a/MdePkg/Library/BaseOverflowLib/BitOverflow.c +++ b/MdePkg/Library/BaseOverflowLib/BaseBitOverflow.c @@ -19,7 +19,7 @@ WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. #include #include -#include "OverflowInternals.h" +#include "BaseOverflowInternals.h" // // Software implementations provided try not to be obviously slow, but primarily diff --git a/MdePkg/Library/BaseOverflowLib/Math.c b/MdePkg/Library/BaseOverflowLib/BaseMath.c similarity index 100% rename from MdePkg/Library/BaseOverflowLib/Math.c rename to MdePkg/Library/BaseOverflowLib/BaseMath.c diff --git a/MdePkg/Library/BaseOverflowLib/NativeOverflow.c b/MdePkg/Library/BaseOverflowLib/BaseNativeOverflow.c similarity index 99% rename from MdePkg/Library/BaseOverflowLib/NativeOverflow.c rename to MdePkg/Library/BaseOverflowLib/BaseNativeOverflow.c index 1edac9fb1e..ca04f5c2a7 100644 --- a/MdePkg/Library/BaseOverflowLib/NativeOverflow.c +++ b/MdePkg/Library/BaseOverflowLib/BaseNativeOverflow.c @@ -19,7 +19,7 @@ WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. #include #include -#include "OverflowInternals.h" +#include "BaseOverflowInternals.h" BOOLEAN BaseOverflowAddUN ( diff --git a/MdePkg/Library/BaseOverflowLib/OverflowInternals.h b/MdePkg/Library/BaseOverflowLib/BaseOverflowInternals.h similarity index 100% rename from MdePkg/Library/BaseOverflowLib/OverflowInternals.h rename to MdePkg/Library/BaseOverflowLib/BaseOverflowInternals.h diff --git a/MdePkg/Library/BaseOverflowLib/BaseOverflowLib.inf b/MdePkg/Library/BaseOverflowLib/BaseOverflowLib.inf index 529a33690c..a14bd80e56 100644 --- a/MdePkg/Library/BaseOverflowLib/BaseOverflowLib.inf +++ b/MdePkg/Library/BaseOverflowLib/BaseOverflowLib.inf @@ -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 diff --git a/MdePkg/Library/BaseOverflowLib/TripleOverflow.c b/MdePkg/Library/BaseOverflowLib/BaseTripleOverflow.c similarity index 100% rename from MdePkg/Library/BaseOverflowLib/TripleOverflow.c rename to MdePkg/Library/BaseOverflowLib/BaseTripleOverflow.c diff --git a/MdePkg/Library/BasePeCoffLib2/PeCoffInit.c b/MdePkg/Library/BasePeCoffLib2/PeCoffInit.c index dd6b9c6796..ddc658e395 100644 --- a/MdePkg/Library/BasePeCoffLib2/PeCoffInit.c +++ b/MdePkg/Library/BasePeCoffLib2/PeCoffInit.c @@ -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 { diff --git a/MdePkg/Library/BaseUeCertStoreLib/UeCertStoreLib.c b/MdePkg/Library/BaseUeCertStoreLib/UeCertStoreLib.c new file mode 100644 index 0000000000..9a1a0ee8f3 --- /dev/null +++ b/MdePkg/Library/BaseUeCertStoreLib/UeCertStoreLib.c @@ -0,0 +1,109 @@ +#include + +#include + +#include +#include + +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); +} diff --git a/MdePkg/Library/BaseUeImageLib/BaseUeImageLib.inf b/MdePkg/Library/BaseUeImageLib/BaseUeImageLib.inf new file mode 100644 index 0000000000..be1e57710d --- /dev/null +++ b/MdePkg/Library/BaseUeImageLib/BaseUeImageLib.inf @@ -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.
+# +# 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 diff --git a/MdePkg/Library/BaseUeImageLib/UeImageLib.c b/MdePkg/Library/BaseUeImageLib/UeImageLib.c new file mode 100644 index 0000000000..51ead23d00 --- /dev/null +++ b/MdePkg/Library/BaseUeImageLib/UeImageLib.c @@ -0,0 +1,1132 @@ +/** @file + UEFI Image Loader library implementation for UE Images. + + Copyright (c) 2021, Marvin Häuser. All rights reserved.
+ + SPDX-License-Identifier: BSD-3-Clause +**/ + +#include +#include +#include + +#include + +#include +#include +#include +#include +#include +#include +#include + +VOID +ThumbMovwMovtImmediateFixup ( + IN OUT VOID *Fixup, + IN UINT64 Adjust + ); + +STATIC +RETURN_STATUS +InternalVerifySegments ( + IN OUT UE_LOADER_IMAGE_CONTEXT *Context + ) +{ + CONST UE_SEGMENT *Segments; + UINT8 LastSegmentIndex; + UINT8 SegmentIndex; + UINT32 SegmentEndFileOffset; + UINT32 SegmentEndImageAddress; + BOOLEAN Overflow; + UINT32 SegmentImageSize; + + Segments = Context->Segments; + LastSegmentIndex = Context->LastSegmentIndex; + + SegmentEndFileOffset = Context->SegmentsFileOffset; + // + // The first Image segment must begin the Image memory space. + // + SegmentEndImageAddress = 0; + + for (SegmentIndex = 0; SegmentIndex <= LastSegmentIndex; ++SegmentIndex) { + // + // Verify the Image segment adheres to the W^X principle. + // + if ((Segments[SegmentIndex].ImageInfo & (UE_SEGMENT_INFO_XP | UE_SEGMENT_INFO_RO)) == 0) { + DEBUG_RAISE (); + return RETURN_UNSUPPORTED; + } + + SegmentImageSize = UE_SEGMENT_SIZE (Segments[SegmentIndex].ImageInfo); + + if (Segments[SegmentIndex].FileSize > SegmentImageSize) { + DEBUG_RAISE (); + return RETURN_UNSUPPORTED; + } + // + // Verify the Image segments are aligned and adjacent. + // + if (!IS_ALIGNED (SegmentImageSize, Context->SegmentAlignment)) { + DEBUG_RAISE (); + return RETURN_UNSUPPORTED; + } + // + // Verify the Image segment with data are in bounds of the file buffer. + // + Overflow = BaseOverflowAddU32 ( + SegmentEndFileOffset, + Segments[SegmentIndex].FileSize, + &SegmentEndFileOffset + ); + if (Overflow) { + DEBUG_RAISE (); + return RETURN_UNSUPPORTED; + } + // + // Determine the end of the current Image segment. + // + Overflow = BaseOverflowAddU32 ( + SegmentEndImageAddress, + SegmentImageSize, + &SegmentEndImageAddress + ); + if (Overflow) { + DEBUG_RAISE (); + return RETURN_UNSUPPORTED; + } + } + + if (SegmentEndFileOffset > Context->UnsignedFileSize) { + DEBUG_RAISE (); + return RETURN_UNSUPPORTED; + } + + Overflow = BaseOverflowAlignUpU32 ( + SegmentEndFileOffset, + UE_SECTION_ALIGNMENT, + &Context->SectionsFileOffset + ); + if (Overflow) { + DEBUG_RAISE (); + return RETURN_UNSUPPORTED; + } + + Context->ImageSize = SegmentEndImageAddress; + + return RETURN_SUCCESS; +} + +STATIC +RETURN_STATUS +InternalVerifySegmentsXip ( + IN OUT UE_LOADER_IMAGE_CONTEXT *Context + ) +{ + CONST UE_SEGMENT_XIP *Segments; + UINT8 LastSegmentIndex; + UINT8 SegmentIndex; + UINT32 SegmentEndImageAddress; + BOOLEAN Overflow; + UINT32 SegmentImageSize; + + Segments = Context->Segments; + LastSegmentIndex = Context->LastSegmentIndex; + // + // The first Image segment must begin the Image memory space. + // + SegmentEndImageAddress = 0; + + for (SegmentIndex = 0; SegmentIndex <= LastSegmentIndex; ++SegmentIndex) { + // + // Verify the Image segment adheres to the W^X principle. + // + if ((Segments[SegmentIndex].ImageInfo & (UE_SEGMENT_INFO_XP | UE_SEGMENT_INFO_RO)) == 0) { + DEBUG_RAISE (); + return RETURN_UNSUPPORTED; + } + + SegmentImageSize = UE_SEGMENT_SIZE (Segments[SegmentIndex].ImageInfo); + // + // Verify the Image segments are aligned and adjacent. + // + if (!IS_ALIGNED (SegmentImageSize, Context->SegmentAlignment)) { + DEBUG_RAISE (); + return RETURN_UNSUPPORTED; + } + // + // Determine the end of the current Image segment. + // + Overflow = BaseOverflowAddU32 ( + SegmentEndImageAddress, + SegmentImageSize, + &SegmentEndImageAddress + ); + if (Overflow) { + DEBUG_RAISE (); + return RETURN_UNSUPPORTED; + } + } + + Context->ImageSize = SegmentEndImageAddress; + + return RETURN_SUCCESS; +} + +RETURN_STATUS +InternalVerifySections ( + IN OUT UE_LOADER_IMAGE_CONTEXT *Context + ) +{ + BOOLEAN Overflow; + CONST UE_SECTION *Section; + UINT8 SectionIndex; + //INT16 PreviousSectionId; + UINT32 SectionFileOffset; + UINT32 SectionFileSize; + //UINT8 SectionId; + UINT32 SectionEndFileOffset; + //UINT8 SectionIndex2; + UINT8 NumSections; + + Context->RelocTableSize = 0; + + SectionEndFileOffset = Context->SectionsFileOffset; + NumSections = Context->NumSections; + //PreviousSectionId = -1; + + if (0 < NumSections) { + SectionIndex = 0; + do { + Section = Context->Sections + SectionIndex; + + DEBUG((DEBUG_ERROR, "Found sect id %u\n", UE_SECTION_ID (Section->FileInfo))); + + //SectionId = UE_SECTION_ID (Section->FileInfo); + + // FIXME: Keep? + /*if (PcdGetBool (PcdImageLoaderExtendedVerification)) { + if (PreviousSectionId >= SectIdentifier) { + DEBUG_RAISE (); + return RETURN_UNSUPPORTED; + } + + for ( + SectionIndex2 = SectionIndex + 1; + SectionIndex2 < NumSections; + ++SectionIndex2 + ) { + if (UE_SECTION_ID (Context->Sections[SectionIndex2].FileInfo) == SectIdentifier) { + DEBUG_RAISE (); + return RETURN_UNSUPPORTED; + } + } + }*/ + + SectionFileOffset = SectionEndFileOffset; + SectionFileSize = UE_SECTION_SIZE (Section->FileInfo); + + Overflow = BaseOverflowAddU32 ( + SectionFileOffset, + SectionFileSize, + &SectionEndFileOffset + ); + if (Overflow) { + DEBUG_RAISE (); + return RETURN_UNSUPPORTED; + } + + //PreviousSectionId = SectionId; + ++SectionIndex; + } while (SectionIndex < NumSections); + + if (UE_SECTION_ID (Context->Sections[0].FileInfo) == UeSectionIdRelocTable) { + if ((Context->ImageInfo & UE_HEADER_FLAG_RELOCS_STRIPPED) != 0) { + DEBUG_RAISE (); + return RETURN_UNSUPPORTED; + } + + Context->RelocTableSize = UE_SECTION_SIZE (Context->Sections[0].FileInfo); + } + } + + if (SectionEndFileOffset != Context->UnsignedFileSize) { + DEBUG_RAISE (); + return RETURN_UNSUPPORTED; + } + + return RETURN_SUCCESS; +} + +RETURN_STATUS +UeInitializeContextPreHash ( + OUT UE_LOADER_IMAGE_CONTEXT *Context, + IN CONST VOID *FileBuffer, + IN UINT32 FileSize + ) +{ + BOOLEAN Overflow; + CONST UE_HEADER *UeHdr; + UINT32 UnsignedFileSize; + + ASSERT (Context != NULL); + ASSERT (FileBuffer != NULL || FileSize == 0); + + if (MIN_SIZE_OF_UE_HEADER > FileSize) { + DEBUG_RAISE (); + return RETURN_UNSUPPORTED; + } + + UeHdr = (CONST UE_HEADER *) FileBuffer; + + if (UeHdr->Signature != UE_HEADER_SIGNATURE) { + DEBUG_RAISE (); + return RETURN_UNSUPPORTED; + } + + ZeroMem (Context, sizeof (*Context)); + + UnsignedFileSize = UE_HEADER_UNSIGNED_SIZE (UeHdr->ImageInfo2); + + Overflow = BaseOverflowSubU32 ( + FileSize, + UnsignedFileSize, + &Context->CertTableSize + ); + if (Overflow) { + DEBUG_RAISE (); + return RETURN_UNSUPPORTED; + } + + Context->FileBuffer = UeHdr; + Context->UnsignedFileSize = UnsignedFileSize; + + return RETURN_SUCCESS; +} + +BOOLEAN +UeHashImageDefault ( + IN OUT UE_LOADER_IMAGE_CONTEXT *Context, + IN OUT VOID *HashContext, + IN UE_LOADER_HASH_UPDATE HashUpdate + ) +{ + BOOLEAN Result; + + ASSERT (Context != NULL); + ASSERT (HashContext != NULL); + ASSERT (HashUpdate != NULL); + + Result = HashUpdate ( + HashContext, + Context->FileBuffer, + Context->UnsignedFileSize + ); + if (!Result) { + DEBUG_RAISE (); + } + + return Result; +} + +STATIC +RETURN_STATUS +InternalInitializeContextLate ( + OUT UE_LOADER_IMAGE_CONTEXT *Context + ) +{ + if (Context->EntryPointAddress > Context->ImageSize) { + DEBUG_RAISE (); + return RETURN_UNSUPPORTED; + } + + return InternalVerifySections (Context); +} + +RETURN_STATUS +UeInitializeContextPostHash ( + IN OUT UE_LOADER_IMAGE_CONTEXT *Context + ) +{ + CONST UE_HEADER *UeHdr; + UINT32 SectionsFileOffset; + UINT32 HeaderSize; + RETURN_STATUS Status; + + ASSERT (Context != NULL); + + UeHdr = (CONST UE_HEADER *) Context->FileBuffer; + + SectionsFileOffset = MIN_SIZE_OF_UE_HEADER + + (UINT32) UeHdr->LastSegmentIndex * sizeof (UE_SEGMENT); + + HeaderSize = SectionsFileOffset + (UINT32) UeHdr->NumSections * sizeof (UE_SECTION); + + if (HeaderSize > Context->UnsignedFileSize) { + DEBUG_RAISE (); + return RETURN_UNSUPPORTED; + } + + ASSERT (IS_ALIGNED (SectionsFileOffset, ALIGNOF (UE_SECTION))); + + Context->Sections = (CONST UE_SECTION *) (CONST VOID *) ( + (CONST CHAR8 *) UeHdr + SectionsFileOffset + ); + + Context->SegmentsFileOffset = HeaderSize; + Context->Segments = UeHdr->Segments; + Context->SegmentImageInfoIterSize = sizeof (*UeHdr->Segments); + Context->SegmentAlignment = UE_HEADER_ALIGNMENT (UeHdr->ImageInfo); + + Context->LastSegmentIndex = UeHdr->LastSegmentIndex; + Context->NumSections = UeHdr->NumSections; + + if (!IS_ALIGNED (UeHdr->PreferredAddress, Context->SegmentAlignment)) { + DEBUG_RAISE (); + return RETURN_UNSUPPORTED; + } + + Context->FileBuffer = UeHdr; + + Status = InternalVerifySegments (Context); + if (RETURN_ERROR (Status)) { + return Status; + } + + Context->EntryPointAddress = UeHdr->EntryPointAddress; + + return InternalInitializeContextLate (Context); +} + +RETURN_STATUS +UeInitializeContext ( + OUT UE_LOADER_IMAGE_CONTEXT *Context, + IN CONST VOID *FileBuffer, + IN UINT32 FileSize + ) +{ + RETURN_STATUS Status; + + Status = UeInitializeContextPreHash (Context, FileBuffer, FileSize); + if (RETURN_ERROR (Status)) { + return Status; + } + + return UeInitializeContextPostHash(Context); +} + +RETURN_STATUS +UeInitializeContextXip ( + OUT UE_LOADER_IMAGE_CONTEXT *Context, + IN CONST VOID *XipInfoBuffer, + IN UINT32 XipInfoSize, + IN CONST VOID *XipImageBuffer, + IN UINT32 XipImageSize + ) +{ + CONST UE_HEADER_XIP *UeHdrXip; + UINT32 SectionHeadersFileOffset; + UINT32 HeaderSize; + RETURN_STATUS Status; + + ASSERT (Context != NULL); + ASSERT (XipInfoBuffer != NULL || XipInfoSize == 0); + ASSERT (XipImageBuffer != NULL || XipImageSize == 0); + + if (MIN_SIZE_OF_UE_HEADER_XIP > XipInfoSize) { + DEBUG_RAISE (); + return RETURN_UNSUPPORTED; + } + + UeHdrXip = (CONST UE_HEADER_XIP *) XipInfoBuffer; + + SectionHeadersFileOffset = MIN_SIZE_OF_UE_HEADER_XIP + + (UINT32) UeHdrXip->LastSegmentIndex * sizeof (UE_SEGMENT); + + HeaderSize = SectionHeadersFileOffset + (UINT32) UeHdrXip->NumSections * sizeof (UE_SECTION); + + if (HeaderSize > XipInfoSize) { + DEBUG_RAISE (); + return RETURN_UNSUPPORTED; + } + + ASSERT (IS_ALIGNED (SectionHeadersFileOffset, ALIGNOF (UE_SECTION))); + + Context->Sections = (CONST UE_SECTION *) (CONST VOID *) ( + (CONST CHAR8 *) XipInfoBuffer + SectionHeadersFileOffset + ); + + Context->SectionsFileOffset = HeaderSize; + Context->SegmentsFileOffset = HeaderSize; + Context->Segments = UeHdrXip->Segments; + Context->SegmentImageInfoIterSize = sizeof (*UeHdrXip->Segments); + Context->SegmentAlignment = UE_HEADER_ALIGNMENT (UeHdrXip->ImageInfo); + + Context->LastSegmentIndex = UeHdrXip->LastSegmentIndex; + Context->NumSections = UeHdrXip->NumSections; + + Context->FileBuffer = UeHdrXip; + Context->PreferredAddress = (UINTN) XipImageBuffer; + + Context->UnsignedFileSize = XipInfoSize; + + Status = InternalVerifySegmentsXip (Context); + if (RETURN_ERROR (Status)) { + return Status; + } + + Context->EntryPointAddress = UeHdrXip->EntryPointAddress; + + return InternalInitializeContextLate (Context); +} + +RETURN_STATUS +UeLoadImage ( + IN OUT UE_LOADER_IMAGE_CONTEXT *Context, + OUT VOID *Destination, + IN UINT32 DestinationSize + ) +{ + UINT32 AlignOffset; + UINTN DestAddress; + + UINT8 SegmentIndex; + UINT32 SegmentFileOffset; + UINT32 SegmentFileSize; + UINT32 SegmentImageAddress; + UINT32 SegmentImageSize; + UINT32 PrevSegmentDataEnd; + + CONST UE_SEGMENT *Segments; + + ASSERT (Context != NULL); + ASSERT (Destination != NULL); + ASSERT (Context->SegmentAlignment <= DestinationSize); + // + // Sufficiently align the Image data in memory. + // + if (Context->SegmentAlignment <= EFI_PAGE_SIZE) { + // + // The caller is required to allocate page memory, hence we have at least + // 4 KB alignment guaranteed. + // + AlignOffset = 0; + Context->ImageBuffer = Destination; + } else { + // + // Images aligned stricter than by the UEFI page size have an increased + // destination size to internally align the Image. + // + DestAddress = (UINTN) Destination; + AlignOffset = ALIGN_VALUE_ADDEND ((UINT32) DestAddress, Context->SegmentAlignment); + Context->ImageBuffer = (CHAR8 *) Destination + AlignOffset; + } + + // + // Load all Image sections into the memory space. + // + Segments = Context->Segments; + + // + // Start zeroing from the start of the destination buffer. + // + PrevSegmentDataEnd = 0; + + SegmentFileOffset = Context->SegmentsFileOffset; + // + // Image segments are loaded at offset StartOffset to ensure alignment. + // + SegmentImageAddress = AlignOffset; + + SegmentIndex = 0; + do { + SegmentFileSize = Segments[SegmentIndex].FileSize; + SegmentImageSize = UE_SEGMENT_SIZE (Segments[SegmentIndex].ImageInfo); + // + // Zero from the end of the previous segment to the start of this segment. + // + ZeroMem ( + (CHAR8 *) Destination + PrevSegmentDataEnd, + SegmentImageAddress - PrevSegmentDataEnd + ); + // + // Load the current Image segment into the memory space. + // + ASSERT (SegmentFileSize <= SegmentImageSize); + CopyMem ( + (CHAR8 *) Destination + SegmentImageAddress, + (CONST CHAR8 *) Context->FileBuffer + SegmentFileOffset, + SegmentFileSize + ); + PrevSegmentDataEnd = SegmentImageAddress + SegmentFileSize; + + SegmentFileOffset += SegmentFileSize; + SegmentImageAddress += SegmentImageSize; + ++SegmentIndex; + } while (SegmentIndex <= Context->LastSegmentIndex); + // + // Zero the trailing data after the last Image segment. + // + ZeroMem ( + (CHAR8 *) Destination + PrevSegmentDataEnd, + DestinationSize - PrevSegmentDataEnd + ); + + return RETURN_SUCCESS; +} + +RETURN_STATUS +UeLoaderGetRuntimeContextSize ( + IN OUT UE_LOADER_IMAGE_CONTEXT *Context, + OUT UINT32 *Size + ) +{ + ASSERT (Context != NULL); + ASSERT (Size != NULL); + // + // FIXME: Do we need bookkeeping? Can we prevent relocs to writable segments? + // + return Context->RelocTableSize; +} + +/** + Apply an Image Base Relocation. + + Only a subset of the PE/COFF Base Relocation types are permited. + The Base Relocation target must be in bounds, aligned, and must not overlap + with the Relocation Directory. + + @param[in] Context The context describing the Image. Must have been + loaded by PeCoffLoadImage(). + @param[in] RelocBlock The Base Relocation Block to apply from. + @param[in] RelocIndex The index of the Base Relocation to apply. + @param[in] Adjust The delta to add to the addresses. + + @retval RETURN_SUCCESS The Base Relocation has been applied successfully. + @retval other The Base Relocation could not be applied successfully. +**/ +STATIC +RETURN_STATUS +InternalApplyRelocation ( + IN CONST UE_LOADER_IMAGE_CONTEXT *Context, + IN CONST UE_RELOCATION_BLOCK *RelocBlock, + IN UINT32 RelocIndex, + IN UINT64 Adjust + ) +{ + BOOLEAN Overflow; + + UINT16 RelocType; + UINT16 RelocOffset; + UINT32 RelocTargetRva; + UINT32 RemRelocTargetSize; + + CHAR8 *Fixup; + UINT32 Fixup32; + UINT64 Fixup64; + + RelocType = UE_RELOC_TYPE (RelocBlock->RelocInfo[RelocIndex]); + RelocOffset = UE_RELOC_OFFSET (RelocBlock->RelocInfo[RelocIndex]); + // + // Verify the Base Relocation target address is in bounds of the Image buffer. + // + RelocTargetRva = UE_RELOC_BLOCK_ADDRESS (RelocBlock->BlockInfo) + RelocOffset; + + Overflow = BaseOverflowSubU32 ( + Context->ImageSize, + RelocTargetRva, + &RemRelocTargetSize + ); + if (Overflow) { + DEBUG_RAISE (); + return RETURN_UNSUPPORTED; + } + + Fixup = (CHAR8 *) Context->ImageBuffer + RelocTargetRva; + // + // Apply the Base Relocation fixup per type. + // + switch (RelocType) { + case UeRelocRel32: + // + // Verify the Base Relocation target is in bounds of the Image buffer. + // + if (sizeof (UINT32) > RemRelocTargetSize) { + DEBUG_RAISE (); + return RETURN_UNSUPPORTED; + } + // + // Relocate the target instruction. + // + Fixup32 = ReadUnaligned32 ((CONST VOID *) Fixup); + Fixup32 += (UINT32) Adjust; + WriteUnaligned32 ((VOID *) Fixup, Fixup32); + + break; + + case UeRelocRel64: + // + // Verify the Image Base Relocation target is in bounds of the Image + // buffer. + // + if (sizeof (UINT64) > RemRelocTargetSize) { + DEBUG_RAISE (); + return RETURN_UNSUPPORTED; + } + // + // Relocate target the instruction. + // + Fixup64 = ReadUnaligned64 ((CONST VOID *) Fixup); + Fixup64 += Adjust; + WriteUnaligned64 ((VOID *) Fixup, Fixup64); + + break; + + case UeRelocArmMov32t: + // + // Verify ARM Thumb mode Base Relocations are supported. + // + if ((PcdGet32 (PcdImageLoaderRelocTypePolicy) & PCD_RELOC_TYPE_POLICY_ARM) == 0) { + DEBUG_RAISE (); + return RETURN_UNSUPPORTED; + } + // + // Verify the Base Relocation target is in bounds of the Image buffer. + // + if (sizeof (UINT64) > RemRelocTargetSize) { + DEBUG_RAISE (); + return RETURN_UNSUPPORTED; + } + // + // Verify the Base Relocation target is sufficiently aligned. + // The ARM THunb instruction pait must start on a 32-bit boundary. + // + if (!IS_ALIGNED (RelocTargetRva, ALIGNOF (UINT32))) { + DEBUG_RAISE (); + return RETURN_UNSUPPORTED; + } + // + // Relocate the target instruction. + // + ThumbMovwMovtImmediateFixup (Fixup, Adjust); + + break; + + default: + // + // The Image Base Relocation type is unknown, disallow the Image. + // + DEBUG_RAISE (); + return RETURN_UNSUPPORTED; + } + + return RETURN_SUCCESS; +} + +RETURN_STATUS +UeRelocateImage ( + IN OUT UE_LOADER_IMAGE_CONTEXT *Context, + IN UINT64 BaseAddress + ) +{ + RETURN_STATUS Status; + + UINT64 Adjust; + + UINT32 RelocBlockOffsetMax; + UINT32 EndOfRelocTable; + + UINT32 RelocBlockOffset; + CONST UE_RELOCATION_BLOCK *RelocBlock; + UINT32 RelocBlockSize; + UINT32 SizeOfRelocs; + UINT16 NumRelocs; + UINT32 RelocIndex; + + ASSERT (Context != NULL); + ASSERT ((Context->ImageInfo & UE_HEADER_FLAG_RELOCS_STRIPPED) == 0 || BaseAddress == Context->PreferredAddress); + ASSERT (IS_ALIGNED (Context->SectionsFileOffset, UE_SECTION_ALIGNMENT)); + ASSERT (IS_ALIGNED (Context->RelocTableSize, UE_SECTION_ALIGNMENT)); + ASSERT (IS_ALIGNED (BaseAddress, Context->SegmentAlignment)); + // + // Verify the Relocation Directory is not empty. + // + if (Context->RelocTableSize == 0) { + return RETURN_SUCCESS; + } + // + // Calculate the Image displacement from its prefered load address. + // + Adjust = BaseAddress - Context->PreferredAddress; + // + // FIXME: RT driver check is removed in the hope we can force no relocs in + // writable segments. + // + // Skip explicit Relocation when the Image is already loaded at its + // prefered location. + // + if (Adjust == 0) { + return RETURN_SUCCESS; + } + + EndOfRelocTable = Context->SectionsFileOffset + Context->RelocTableSize; + + STATIC_ASSERT ( + sizeof (UE_RELOCATION_BLOCK) <= UE_SECTION_ALIGNMENT, + "The following arithmetic may overflow." + ); + + RelocBlockOffsetMax = EndOfRelocTable - sizeof (UE_RELOCATION_BLOCK); + // + // Apply all Base Relocations of the Image. + // + // This arithmetic cannot overflow because it has been checked that the Image + // Base Relocation Block is in bounds of the Image buffer. + // + for ( + RelocBlockOffset = Context->SectionsFileOffset; + RelocBlockOffset <= RelocBlockOffsetMax; + RelocBlockOffset += RelocBlockSize + ) { + RelocBlock = (CONST UE_RELOCATION_BLOCK *) (CONST VOID *) ( + (CONST CHAR8 *) Context->FileBuffer + RelocBlockOffset + ); + // + // Verify the Base Relocation Block size is well-formed. + // + NumRelocs = UE_RELOC_BLOCK_NUM (RelocBlock->BlockInfo); + SizeOfRelocs = (UINT32) NumRelocs * sizeof (UINT16); + // + // Verify the Base Relocation Block is in bounds of the Relocation + // Directory. + // + if (SizeOfRelocs > RelocBlockOffsetMax - RelocBlockOffset) { + DEBUG_RAISE (); + return RETURN_UNSUPPORTED; + } + // + // Advance to the next Base Relocation Block offset based on the alignment + // policy. + // + RelocBlockSize = sizeof (UE_RELOCATION_BLOCK) + SizeOfRelocs; + // + // Safe because we checked the Reloc Dir size. + // + RelocBlockSize = ALIGN_VALUE (RelocBlockSize, ALIGNOF (UE_RELOCATION_BLOCK)); + // + // Process all Base Relocations of the current Block. + // + for (RelocIndex = 0; RelocIndex < NumRelocs; ++RelocIndex) { + // + // Apply the Image Base Relocation fixup. + // If RuntimeContext is not NULL, store the current value of the fixup + // target to determine whether it has been changed during runtime + // execution. + // + Status = InternalApplyRelocation ( + Context, + RelocBlock, + RelocIndex, + Adjust + ); + if (!RETURN_ERROR (Status)) { + return Status; + } + } + } + + STATIC_ASSERT ( + sizeof (UE_RELOCATION_BLOCK) <= UE_SECTION_ALIGNMENT, + "The following ASSERT may not hold." + ); + + ASSERT (RelocBlockOffset == EndOfRelocTable); + + // + // FIXME: Alignment to 8 Bytes should just work, zero'd BRB should be no-op. + // + + return RETURN_SUCCESS; +} + +RETURN_STATUS +UeRelocateImageForRuntime ( + IN OUT VOID *Image, + IN UINT32 ImageSize, + IN UINT64 BaseAddress, + IN CONST UE_LOADER_RUNTIME_CONTEXT *RuntimeContext + ) +{ + ASSERT (Image != NULL); + ASSERT (ImageSize != 0); + ASSERT (RuntimeContext != NULL); + + (VOID) BaseAddress; + // + // FIXME: + // This feature is currently unsupported. + // + return RETURN_UNSUPPORTED; +} + +RETURN_STATUS +InternalGetDebugTable ( + IN CONST UE_LOADER_IMAGE_CONTEXT *Context, + OUT CONST UE_DEBUG_TABLE **DebugTable + ) +{ + CONST UE_SECTION *Section; + UINT8 SectionIndex; + UINT8 NumSections; + UINT32 SectionFileOffset; + UINT32 SectionFileSize; + + ASSERT (Context != NULL); + ASSERT (DebugTable != NULL); + + SectionFileOffset = Context->SectionsFileOffset; + NumSections = Context->NumSections; + + for (SectionIndex = 0; SectionIndex < NumSections; ++SectionIndex) { + Section = Context->Sections + SectionIndex; + if (UE_SECTION_ID (Section->FileInfo) != UeSectionIdDebugTable) { + SectionFileOffset += UE_SECTION_SIZE (Section->FileInfo); + continue; + } + + ASSERT (IS_ALIGNED (SectionFileOffset, ALIGNOF (UE_DEBUG_TABLE))); + + SectionFileSize = UE_SECTION_SIZE (Section->FileInfo); + + if (MIN_SIZE_OF_UE_DEBUG_TABLE > SectionFileSize) { + DEBUG_RAISE (); + return RETURN_UNSUPPORTED; + } + + *DebugTable = (CONST UE_DEBUG_TABLE *) (CONST VOID *) ( + (CONST CHAR8 *) Context->FileBuffer + SectionFileOffset + ); + + if ((*DebugTable)->SymbolsPathSize > SectionFileSize - MIN_SIZE_OF_UE_DEBUG_TABLE) { + DEBUG_RAISE (); + return RETURN_UNSUPPORTED; + } + + if ((UINT32) (Context->LastSegmentIndex + 1) * sizeof (UE_SEGMENT_NAME) > SectionFileSize - MIN_SIZE_OF_UE_DEBUG_TABLE - (*DebugTable)->SymbolsPathSize) { + DEBUG_RAISE (); + return RETURN_UNSUPPORTED; + } + + return RETURN_SUCCESS; + } + + return RETURN_NOT_FOUND; +} + +RETURN_STATUS +UeGetSymbolsPath ( + IN OUT UE_LOADER_IMAGE_CONTEXT *Context, + OUT CONST CHAR8 **SymbolsPath, + OUT UINT32 *SymbolsPathSize + ) +{ + RETURN_STATUS Status; + CONST UE_DEBUG_TABLE *DebugTable; + + ASSERT (Context != NULL); + ASSERT (SymbolsPath != NULL); + ASSERT (SymbolsPathSize != NULL); + + Status = InternalGetDebugTable (Context, &DebugTable); + if (RETURN_ERROR (Status)) { + return Status; + } + + if (DebugTable->SymbolsPathSize == 0) { + return RETURN_NOT_FOUND; + } + + // FIXME: Do we require termination? + + *SymbolsPath = (CONST CHAR8 *) DebugTable->SymbolsPath; + *SymbolsPathSize = DebugTable->SymbolsPathSize; + return RETURN_SUCCESS; +} + +RETURN_STATUS +UeGetFirstCertificate ( + IN OUT UE_LOADER_IMAGE_CONTEXT *Context, + OUT CONST WIN_CERTIFICATE **Certificate + ) +{ + ASSERT (Context != NULL); + ASSERT (Certificate != NULL); + // + // FIXME: + // This feature is currently unsupported. + // + return RETURN_NOT_FOUND; +} + +RETURN_STATUS +UeGetNextCertificate ( + IN OUT UE_LOADER_IMAGE_CONTEXT *Context, + IN OUT CONST WIN_CERTIFICATE **Certificate + ) +{ + ASSERT (Context != NULL); + ASSERT (Certificate != NULL); + // + // FIXME: + // This feature is currently unsupported. + // + return RETURN_NOT_FOUND; +} + +RETURN_STATUS +UeGetHiiDataRva ( + IN OUT UE_LOADER_IMAGE_CONTEXT *Context, + OUT UINT32 *HiiRva, + OUT UINT32 *HiiSize + ) +{ + ASSERT (Context != NULL); + ASSERT (HiiRva != NULL); + ASSERT (HiiSize != NULL); + // + // This feature is currently unsupported. + // FIXME: HII data can be stored, but it is not mapped into the Image memory. + // + return RETURN_NOT_FOUND; +} + +UINT32 +UeGetAddressOfEntryPoint ( + IN OUT UE_LOADER_IMAGE_CONTEXT *Context + ) +{ + ASSERT (Context != NULL); + + return Context->EntryPointAddress; +} + +UINT16 +UeGetMachine ( + IN OUT UE_LOADER_IMAGE_CONTEXT *Context + ) +{ + ASSERT (Context != NULL); + // + // FIXME: Return UE value and translate PE to not be stuck with PE-value-using + // callers later? + return Context->Machine; +} + +UINT16 +UeGetSubsystem ( + IN OUT UE_LOADER_IMAGE_CONTEXT *Context + ) +{ + ASSERT (Context != NULL); + + return Context->Subsystem; +} + +UINT32 +UeGetSegmentAlignment ( + IN OUT UE_LOADER_IMAGE_CONTEXT *Context + ) +{ + ASSERT (Context != NULL); + + return Context->SegmentAlignment; +} + +UINT32 +UeGetImageSize ( + IN OUT UE_LOADER_IMAGE_CONTEXT *Context + ) +{ + ASSERT (Context != NULL); + + return Context->ImageSize; +} + +UINT32 +UeGetImageSizeInplace ( + IN OUT UE_LOADER_IMAGE_CONTEXT *Context + ) +{ + return UeGetImageSize (Context); +} + +UINT64 +UeGetPreferredAddress ( + IN OUT UE_LOADER_IMAGE_CONTEXT *Context + ) +{ + ASSERT (Context != NULL); + + return Context->PreferredAddress; +} + +BOOLEAN +UeGetRelocsStripped ( + IN OUT UE_LOADER_IMAGE_CONTEXT *Context + ) +{ + ASSERT (Context != NULL); + + return (Context->ImageInfo & UE_HEADER_FLAG_RELOCS_STRIPPED) != 0; +} + +UINTN +UeLoaderGetImageAddress ( + IN OUT UE_LOADER_IMAGE_CONTEXT *Context + ) +{ + ASSERT (Context != NULL); + + return (UINTN) Context->ImageBuffer; +} + +UINT8 +UeGetSegments ( + IN OUT UE_LOADER_IMAGE_CONTEXT *Context, + OUT CONST UE_SEGMENT **Segments + ) +{ + ASSERT (Context != NULL); + ASSERT (Segments != NULL); + + *Segments = Context->Segments; + return Context->LastSegmentIndex; +} + +UINT8 +UeGetSegmentImageInfos ( + IN OUT UE_LOADER_IMAGE_CONTEXT *Context, + OUT CONST UINT32 **SegmentImageInfos, + OUT UINT8 *SegmentImageInfoIterSize + ) +{ + ASSERT (Context != NULL); + ASSERT (SegmentImageInfos != NULL); + ASSERT (SegmentImageInfoIterSize != NULL); + + ASSERT (IS_ALIGNED (Context->SegmentImageInfoIterSize, ALIGNOF (UINT32))); + + *SegmentImageInfos = Context->Segments; + *SegmentImageInfoIterSize = Context->SegmentImageInfoIterSize; + return Context->LastSegmentIndex; +} + +UINT32 +UeGetSectionsFileOffset ( + IN OUT UE_LOADER_IMAGE_CONTEXT *Context + ) +{ + ASSERT (Context != NULL); + + return Context->SectionsFileOffset; +} diff --git a/MdePkg/Library/BaseUefiImageLib/BaseUefiImageLibUe.inf b/MdePkg/Library/BaseUefiImageLib/BaseUefiImageLibUe.inf new file mode 100644 index 0000000000..d4caa7aca6 --- /dev/null +++ b/MdePkg/Library/BaseUefiImageLib/BaseUefiImageLibUe.inf @@ -0,0 +1,33 @@ +## @file +# UEFI Image Loader library implementation for UE Images. +# +# Copyright (c) 2021, Marvin Häuser. All rights reserved.
+# +# 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 diff --git a/MdePkg/Library/BaseUefiImageLib/UeSupport.c b/MdePkg/Library/BaseUefiImageLib/UeSupport.c new file mode 100644 index 0000000000..0620eda82d --- /dev/null +++ b/MdePkg/Library/BaseUefiImageLib/UeSupport.c @@ -0,0 +1,234 @@ +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +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; +} diff --git a/MdePkg/Library/BaseUefiImageLib/UeSupport.h b/MdePkg/Library/BaseUefiImageLib/UeSupport.h new file mode 100644 index 0000000000..98e5cf2891 --- /dev/null +++ b/MdePkg/Library/BaseUefiImageLib/UeSupport.h @@ -0,0 +1,29 @@ +#ifndef UE_SUPPORT_H_ +#define UE_SUPPORT_H_ + +#include +#include + +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_ diff --git a/MdePkg/Library/BaseUefiImageLib/UefiImageLibUe.c b/MdePkg/Library/BaseUefiImageLib/UefiImageLibUe.c new file mode 100644 index 0000000000..469b1cfd86 --- /dev/null +++ b/MdePkg/Library/BaseUefiImageLib/UefiImageLibUe.c @@ -0,0 +1,281 @@ +/** @file + UEFI Image Loader library implementation for UE Images. + + Copyright (c) 2021, Marvin Häuser. All rights reserved.
+ + 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 +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#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); +} diff --git a/MdePkg/MdeLibs.dsc.inc b/MdePkg/MdeLibs.dsc.inc index 4580481cb5..87cc94546e 100644 --- a/MdePkg/MdeLibs.dsc.inc +++ b/MdePkg/MdeLibs.dsc.inc @@ -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 diff --git a/MdePkg/MdePkg.dsc b/MdePkg/MdePkg.dsc index 9fb2e2e7a7..e9635c86d6 100644 --- a/MdePkg/MdePkg.dsc +++ b/MdePkg/MdePkg.dsc @@ -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 diff --git a/NetworkPkg/NetworkPkg.dsc b/NetworkPkg/NetworkPkg.dsc index 4e707bea30..ce856c8df0 100644 --- a/NetworkPkg/NetworkPkg.dsc +++ b/NetworkPkg/NetworkPkg.dsc @@ -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 diff --git a/OpenCorePkg b/OpenCorePkg new file mode 160000 index 0000000000..1d65bf8500 --- /dev/null +++ b/OpenCorePkg @@ -0,0 +1 @@ +Subproject commit 1d65bf850099bc0d8cc3b282bebd16310a3ab487 diff --git a/OvmfPkg/OvmfPkgIa32.dsc b/OvmfPkg/OvmfPkgIa32.dsc index a9f1e51dcd..cefb8d7482 100644 --- a/OvmfPkg/OvmfPkgIa32.dsc +++ b/OvmfPkg/OvmfPkgIa32.dsc @@ -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 ################################################################################ diff --git a/OvmfPkg/OvmfPkgIa32X64.dsc b/OvmfPkg/OvmfPkgIa32X64.dsc index 0663ce1eae..2da5cf000a 100644 --- a/OvmfPkg/OvmfPkgIa32X64.dsc +++ b/OvmfPkg/OvmfPkgIa32X64.dsc @@ -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 ################################################################################ diff --git a/OvmfPkg/OvmfPkgIa32X64.fdf b/OvmfPkg/OvmfPkgIa32X64.fdf index 23f04d2a1f..deae90bf94 100644 --- a/OvmfPkg/OvmfPkgIa32X64.fdf +++ b/OvmfPkg/OvmfPkgIa32X64.fdf @@ -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 diff --git a/OvmfPkg/OvmfPkgX64.dsc b/OvmfPkg/OvmfPkgX64.dsc index 36724ed7d5..44bb0134e2 100644 --- a/OvmfPkg/OvmfPkgX64.dsc +++ b/OvmfPkg/OvmfPkgX64.dsc @@ -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 diff --git a/SecurityPkg/VariableAuthenticated/SecureBootConfigDxe/SecureBootConfigDxe.inf b/SecurityPkg/VariableAuthenticated/SecureBootConfigDxe/SecureBootConfigDxe.inf index 247074cb71..ba5775198f 100644 --- a/SecurityPkg/VariableAuthenticated/SecureBootConfigDxe/SecureBootConfigDxe.inf +++ b/SecurityPkg/VariableAuthenticated/SecureBootConfigDxe/SecureBootConfigDxe.inf @@ -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" diff --git a/SecurityPkg/VariableAuthenticated/SecureBootConfigDxe/SecureBootConfigImpl.c b/SecurityPkg/VariableAuthenticated/SecureBootConfigDxe/SecureBootConfigImpl.c index 612a918760..7a0c5455d1 100644 --- a/SecurityPkg/VariableAuthenticated/SecureBootConfigDxe/SecureBootConfigImpl.c +++ b/SecurityPkg/VariableAuthenticated/SecureBootConfigDxe/SecureBootConfigImpl.c @@ -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; } diff --git a/UefiPayloadPkg/Library/UefiPayloadEntryMemoryAllocationLib/UefiPayloadEntryMemoryAllocationLib.inf b/UefiPayloadPkg/Library/UefiPayloadEntryMemoryAllocationLib/UefiPayloadEntryMemoryAllocationLib.inf deleted file mode 100644 index d8f9849470..0000000000 --- a/UefiPayloadPkg/Library/UefiPayloadEntryMemoryAllocationLib/UefiPayloadEntryMemoryAllocationLib.inf +++ /dev/null @@ -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 diff --git a/UefiPayloadPkg/Library/UefiPayloadEntryMemoryAllocationLib/MemoryAllocation.c b/UefiPayloadPkg/Library/UefiPayloadMemoryAllocationLib/MemoryAllocationLib.c old mode 100644 new mode 100755 similarity index 80% rename from UefiPayloadPkg/Library/UefiPayloadEntryMemoryAllocationLib/MemoryAllocation.c rename to UefiPayloadPkg/Library/UefiPayloadMemoryAllocationLib/MemoryAllocationLib.c index 83936ae26e..aa95571179 --- a/UefiPayloadPkg/Library/UefiPayloadEntryMemoryAllocationLib/MemoryAllocation.c +++ b/UefiPayloadPkg/Library/UefiPayloadMemoryAllocationLib/MemoryAllocationLib.c @@ -1,198 +1,247 @@ -/** @file - - - Copyright (c) 2008 - 2009, Apple Inc. All rights reserved.
- Copyright (c) 2020, Intel Corporation. All rights reserved.
- - 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.
+ Copyright (c) 2020, Intel Corporation. All rights reserved.
+ + SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#include + +#include +#include +#include +#include +#include +#include + +/** + 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. + // +} diff --git a/UefiPayloadPkg/Library/UefiPayloadMemoryAllocationLib/UefiPayloadMemoryAllocationLib.inf b/UefiPayloadPkg/Library/UefiPayloadMemoryAllocationLib/UefiPayloadMemoryAllocationLib.inf new file mode 100755 index 0000000000..244882ed65 --- /dev/null +++ b/UefiPayloadPkg/Library/UefiPayloadMemoryAllocationLib/UefiPayloadMemoryAllocationLib.inf @@ -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.
+# +# 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 + diff --git a/UefiPayloadPkg/Library/UefiPayloadMemoryAllocationLib/UefiPayloadMemoryAllocationLib.uni b/UefiPayloadPkg/Library/UefiPayloadMemoryAllocationLib/UefiPayloadMemoryAllocationLib.uni new file mode 100755 index 0000000000..9822b382e0 --- /dev/null +++ b/UefiPayloadPkg/Library/UefiPayloadMemoryAllocationLib/UefiPayloadMemoryAllocationLib.uni @@ -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.
+// +// 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." + diff --git a/UefiPayloadPkg/UefiPayloadPkg.dsc b/UefiPayloadPkg/UefiPayloadPkg.dsc index 691cf93c91..07623310d4 100644 --- a/UefiPayloadPkg/UefiPayloadPkg.dsc +++ b/UefiPayloadPkg/UefiPayloadPkg.dsc @@ -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 diff --git a/compile_flags.txt b/compile_flags.txt deleted file mode 100644 index e02347ae10..0000000000 --- a/compile_flags.txt +++ /dev/null @@ -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 \ No newline at end of file diff --git a/edksetup.sh b/edksetup.sh index 06d2f041e6..9d304eeeef 100755 --- a/edksetup.sh +++ b/edksetup.sh @@ -72,6 +72,7 @@ function SetWorkspace() # Set $WORKSPACE # export WORKSPACE=$PWD + export PACKAGES_PATH=$PWD return 0 }