From efb6eea39eb3868079a5a93c1f35d897785e4756 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marvin=20Ha=CC=88user?= <8659494+mhaeuser@users.noreply.github.com> Date: Sun, 23 Apr 2023 21:46:50 +0200 Subject: [PATCH] ImageTool: Separate image generation from file I/O logic --- BaseTools/ImageTool/GNUmakefile | 2 +- BaseTools/ImageTool/ImageTool.c | 202 ++++++++++---------------- BaseTools/ImageTool/ImageToolEmit.c | 179 +++++++++++++++++++++++ BaseTools/ImageTool/ImageToolEmit.h | 27 ++++ BaseTools/ImageTool/Makefile | 2 +- MdePkg/Include/Library/UefiImageLib.h | 5 + 6 files changed, 290 insertions(+), 127 deletions(-) create mode 100644 BaseTools/ImageTool/ImageToolEmit.c create mode 100644 BaseTools/ImageTool/ImageToolEmit.h diff --git a/BaseTools/ImageTool/GNUmakefile b/BaseTools/ImageTool/GNUmakefile index ce5e8c9c1e..43291a4ac1 100644 --- a/BaseTools/ImageTool/GNUmakefile +++ b/BaseTools/ImageTool/GNUmakefile @@ -7,7 +7,7 @@ PROJECT = ImageTool PRODUCT = $(PROJECT)$(INFIX)$(SUFFIX) OBJS = $(PROJECT).o -OBJS += Image.o PeEmit32.o PeEmit64.o PeEmitCommon.o PeScan.o ElfScan32.o ElfScan64.o ElfScanCommon.o BinEmit.o +OBJS += Image.o PeEmit32.o PeEmit64.o PeEmitCommon.o PeScan.o ElfScan32.o ElfScan64.o ElfScanCommon.o BinEmit.o ImageToolEmit.o OBJS += UefiImageExtraActionLib.o OBJS += PeCoffInit.o PeCoffInfo.o PeCoffLoad.o PeCoffRelocate.o PeCoffHii.o PeCoffDebug.o diff --git a/BaseTools/ImageTool/ImageTool.c b/BaseTools/ImageTool/ImageTool.c index f78543882b..aa88c1d0d6 100644 --- a/BaseTools/ImageTool/ImageTool.c +++ b/BaseTools/ImageTool/ImageTool.c @@ -9,6 +9,8 @@ #include #include +#include "ImageToolEmit.h" + #define EFI_ACPI_1_0_FIRMWARE_ACPI_CONTROL_STRUCTURE_VERSION 0x0 @@ -224,16 +226,11 @@ GetAcpi ( } static -bool -ImageSetModuleType ( - OUT image_tool_image_info_t *Image, - IN const char *TypeName +int32_t +NameToType ( + IN const char *TypeName ) { - uint16_t ModuleType; - - assert (Image != NULL); - if ((strcmp (TypeName, "BASE") == 0) || (strcmp (TypeName, "SEC") == 0) || (strcmp (TypeName, "SECURITY_CORE") == 0) @@ -250,61 +247,38 @@ ImageSetModuleType ( || (strcmp (TypeName, "SMM_CORE") == 0) || (strcmp (TypeName, "MM_STANDALONE") == 0) || (strcmp (TypeName, "MM_CORE_STANDALONE") == 0)) { - ModuleType = EFI_IMAGE_SUBSYSTEM_EFI_BOOT_SERVICE_DRIVER; - } else if ((strcmp (TypeName, "UEFI_APPLICATION") == 0) + return EFI_IMAGE_SUBSYSTEM_EFI_BOOT_SERVICE_DRIVER; + } + + if ((strcmp (TypeName, "UEFI_APPLICATION") == 0) || (strcmp (TypeName, "APPLICATION") == 0)) { - ModuleType = EFI_IMAGE_SUBSYSTEM_EFI_APPLICATION; - } else if ((strcmp (TypeName, "DXE_RUNTIME_DRIVER") == 0) + return EFI_IMAGE_SUBSYSTEM_EFI_APPLICATION; + } + + if ((strcmp (TypeName, "DXE_RUNTIME_DRIVER") == 0) || (strcmp (TypeName, "RT_DRIVER") == 0)) { - ModuleType = EFI_IMAGE_SUBSYSTEM_EFI_RUNTIME_DRIVER; - } else if ((strcmp (TypeName, "DXE_SAL_DRIVER") == 0) + return EFI_IMAGE_SUBSYSTEM_EFI_RUNTIME_DRIVER; + } + + if ((strcmp (TypeName, "DXE_SAL_DRIVER") == 0) || (strcmp (TypeName, "SAL_RT_DRIVER") == 0)) { - ModuleType = EFI_IMAGE_SUBSYSTEM_SAL_RUNTIME_DRIVER; - } else { - fprintf (stderr, "ImageTool: Unknown EFI_FILETYPE = %s\n", TypeName); - return false; + return EFI_IMAGE_SUBSYSTEM_SAL_RUNTIME_DRIVER; } - Image->HeaderInfo.Subsystem = ModuleType; - - return true; + return -1; } static -RETURN_STATUS -ValidateOutputFile ( - void *OutputFile, - uint32_t OutputFileSize, - const image_tool_image_info_t *ImageInfo +int8_t +NameToFormat ( + IN const char *FormatName ) { - RETURN_STATUS Status; - bool Result; - image_tool_image_info_t OutputImageInfo; - - Status = ToolContextConstructPe (&OutputImageInfo, OutputFile, OutputFileSize); - if (EFI_ERROR (Status)) { - assert (false); - return Status; + if (strcmp (FormatName, "PE") == 0) { + return UefiImageFormatPe; } - Result = CheckToolImage (&OutputImageInfo); - if (!Result) { - raise (); - ToolImageDestruct (&OutputImageInfo); - return RETURN_UNSUPPORTED; - } - - Result = ToolImageCompare (&OutputImageInfo, ImageInfo); - - ToolImageDestruct (&OutputImageInfo); - - if (!Result) { - assert (false); - return RETURN_VOLUME_CORRUPTED; - } - - return RETURN_SUCCESS; + return -1; } static @@ -318,16 +292,43 @@ GenExecutable ( IN const char *BaseAddress ) { - UINT32 InputFileSize; - VOID *InputFile; - UINT32 HiiFileSize; - VOID *HiiFile; - RETURN_STATUS Status; - bool Result; - image_tool_image_info_t ImageInfo; - UINT64 NewBaseAddress; - void *OutputFile; - uint32_t OutputFileSize; + UINT32 InputFileSize; + VOID *InputFile; + int8_t Format; + int32_t Type; + UINT32 HiiFileSize; + VOID *HiiFile; + RETURN_STATUS Status; + UINT64 NewBaseAddress; + void *OutputFile; + uint32_t OutputFileSize; + + Format = -1; + if (FormatName != NULL) { + Format = NameToFormat (FormatName); + if (Format == -1) { + fprintf (stderr, "ImageTool: Unknown output format %s\n", FormatName); + return RETURN_UNSUPPORTED; + } + } + + Type = -1; + if (TypeName != NULL) { + Type = NameToType (TypeName); + if (Type == -1) { + fprintf (stderr, "ImageTool: Unknown EFI_FILETYPE = %s\n", TypeName); + return RETURN_UNSUPPORTED; + } + } + + NewBaseAddress = 0; + if (BaseAddress != NULL) { + Status = AsciiStrHexToUint64S (BaseAddress, NULL, &NewBaseAddress); + if (RETURN_ERROR (Status)) { + fprintf (stderr, "ImageTool: Could not convert ASCII string to UINT64\n"); + return Status; + } + } InputFile = UserReadFile (InputFileName, &InputFileSize); if (InputFile == NULL) { @@ -335,83 +336,34 @@ GenExecutable ( return RETURN_ABORTED; } - Status = ToolContextConstructPe (&ImageInfo, InputFile, InputFileSize); - if (Status == RETURN_UNSUPPORTED) { - Status = ScanElf (&ImageInfo, InputFile, InputFileSize, InputFileName); - } - - free (InputFile); - - if (RETURN_ERROR (Status)) { - fprintf (stderr, "ImageTool: Could not parse input file %s - %llx\n", InputFileName, (unsigned long long)Status); - return Status; - } - - if (TypeName != NULL) { - Result = ImageSetModuleType (&ImageInfo, TypeName); - if (!Result) { - ToolImageDestruct (&ImageInfo); - return RETURN_UNSUPPORTED; - } - } - + HiiFile = NULL; + HiiFileSize = 0; if (HiiFileName != NULL) { HiiFile = UserReadFile (HiiFileName, &HiiFileSize); if (HiiFile == NULL) { fprintf (stderr, "ImageTool: Could not open %s: %s\n", HiiFileName, strerror (errno)); return RETURN_ABORTED; } - - free (ImageInfo.HiiInfo.Data); - - ImageInfo.HiiInfo.Data = HiiFile; - ImageInfo.HiiInfo.DataSize = HiiFileSize; } - ToolImageSortRelocs (&ImageInfo); - - Result = CheckToolImage (&ImageInfo); - if (!Result) { - ToolImageDestruct (&ImageInfo); - return RETURN_UNSUPPORTED; - } - - if (BaseAddress != NULL) { - Status = AsciiStrHexToUint64S (BaseAddress, NULL, &NewBaseAddress); - if (RETURN_ERROR (Status)) { - fprintf (stderr, "ImageTool: Could not convert ASCII string to UINT64\n"); - ToolImageDestruct (&ImageInfo); - return Status; - } - - Result = ToolImageRelocate (&ImageInfo, NewBaseAddress); - if (!Result) { - fprintf (stderr, "ImageTool: Failed to relocate input file %s\n", InputFileName); - ToolImageDestruct (&ImageInfo); - return RETURN_UNSUPPORTED; - } - } - - if (strcmp (FormatName, "PE") == 0) { - OutputFile = ToolImageEmitPe (&ImageInfo, &OutputFileSize); - } else { - assert (false); - } + OutputFile = ToolImageEmit ( + &OutputFileSize, + InputFile, + InputFileSize, + Format, + Type, + HiiFile, + HiiFileSize, + BaseAddress != NULL, + NewBaseAddress, + InputFileName + ); if (OutputFile == NULL) { - ToolImageDestruct (&ImageInfo); + free (HiiFile); return RETURN_ABORTED; } - Status = ValidateOutputFile (OutputFile, OutputFileSize, &ImageInfo); - - ToolImageDestruct (&ImageInfo); - - if (EFI_ERROR (Status)) { - assert (false); - return Status; - } - UserWriteFile (OutputFileName, OutputFile, OutputFileSize); free (OutputFile); diff --git a/BaseTools/ImageTool/ImageToolEmit.c b/BaseTools/ImageTool/ImageToolEmit.c new file mode 100644 index 0000000000..0062a89a78 --- /dev/null +++ b/BaseTools/ImageTool/ImageToolEmit.c @@ -0,0 +1,179 @@ +/** @file + Copyright (c) 2023, Marvin Häuser. All rights reserved. + SPDX-License-Identifier: BSD-3-Clause +**/ + +#include "ImageTool.h" + +#include + +#include + +#include + +#include "ImageToolEmit.h" + +static +RETURN_STATUS +ToolContextConstruct ( + OUT image_tool_image_info_t *ImageInfo, + OUT int8_t *Format, + IN const void *File, + IN size_t FileSize, + IN const char *SymbolsPath OPTIONAL + ) +{ + RETURN_STATUS Status; + + *Format = -1; + + Status = ToolContextConstructPe ( + ImageInfo, + File, + FileSize + ); + if (!RETURN_ERROR (Status)) { + *Format = UefiImageFormatPe; + } else if (Status == RETURN_UNSUPPORTED) { + Status = ScanElf (ImageInfo, File, FileSize, SymbolsPath); + } + + return Status; +} + +static +RETURN_STATUS +ValidateOutputFile ( + void *OutputFile, + uint32_t OutputFileSize, + const image_tool_image_info_t *ImageInfo + ) +{ + RETURN_STATUS Status; + bool Result; + image_tool_image_info_t OutputImageInfo; + int8_t Format; + + Status = ToolContextConstruct ( + &OutputImageInfo, + &Format, + OutputFile, + OutputFileSize, + NULL + ); + if (EFI_ERROR (Status)) { + assert (false); + return Status; + } + + Result = CheckToolImage (&OutputImageInfo); + if (!Result) { + raise (); + ToolImageDestruct (&OutputImageInfo); + return RETURN_UNSUPPORTED; + } + + Result = ToolImageCompare (&OutputImageInfo, ImageInfo); + + ToolImageDestruct (&OutputImageInfo); + + if (!Result) { + assert (false); + return RETURN_VOLUME_CORRUPTED; + } + + return RETURN_SUCCESS; +} + +void * +ToolImageEmit ( + OUT uint32_t *OutputFileSize, + IN const void *Buffer, + IN uint64_t BufferSize, + IN int8_t Format, + IN int32_t Type, + IN void *HiiFile, + IN uint32_t HiiFileSize, + IN bool Relocate, + IN uint64_t BaseAddress, + IN const char *SymbolsPath OPTIONAL + ) +{ + RETURN_STATUS Status; + bool Success; + image_tool_image_info_t ImageInfo; + int8_t SourceFormat; + void *OutputFile; + + Status = ToolContextConstruct ( + &ImageInfo, + &SourceFormat, + Buffer, + BufferSize, + SymbolsPath + ); + + if (SymbolsPath == NULL) { + SymbolsPath = ""; + } + + if (RETURN_ERROR (Status)) { + fprintf (stderr, "ImageTool: Could not parse input file %s - %llx\n", SymbolsPath, (unsigned long long)Status); + return NULL; + } + + if (Format == -1) { + Format = SourceFormat; + if (Format == -1) { + fprintf (stderr, "ImageTool: Unknown output format of file %s\n", SymbolsPath); + ToolImageDestruct (&ImageInfo); + return NULL; + } + } + + if (Type != -1) { + ImageInfo.HeaderInfo.Subsystem = (uint16_t)Type; + } + + if (HiiFile != NULL) { + free (ImageInfo.HiiInfo.Data); + + ImageInfo.HiiInfo.Data = HiiFile; + ImageInfo.HiiInfo.DataSize = HiiFileSize; + } + + ToolImageSortRelocs (&ImageInfo); + + Success = CheckToolImage (&ImageInfo); + if (!Success) { + ToolImageDestruct (&ImageInfo); + return NULL; + } + + if (Relocate) { + Success = ToolImageRelocate (&ImageInfo, BaseAddress); + if (!Success) { + fprintf (stderr, "ImageTool: Failed to relocate input file %s\n", SymbolsPath); + ToolImageDestruct (&ImageInfo); + return NULL; + } + } + + OutputFile = NULL; + if (Format == UefiImageFormatPe) { + OutputFile = ToolImageEmitPe (&ImageInfo, OutputFileSize); + } else { + assert (false); + } + + Status = ValidateOutputFile (OutputFile, *OutputFileSize, &ImageInfo); + + ToolImageDestruct (&ImageInfo); + + if (EFI_ERROR (Status)) { + assert (false); + return NULL; + } + + return OutputFile; +} diff --git a/BaseTools/ImageTool/ImageToolEmit.h b/BaseTools/ImageTool/ImageToolEmit.h new file mode 100644 index 0000000000..d52a2bf7d3 --- /dev/null +++ b/BaseTools/ImageTool/ImageToolEmit.h @@ -0,0 +1,27 @@ +/** @file + Copyright (c) 2023, Marvin Häuser. All rights reserved. + SPDX-License-Identifier: BSD-3-Clause +**/ + +#ifndef IMAGE_TOOL_EMIT_H +#define IMAGE_TOOL_EMIT_H + +#include + +#include + +void * +ToolImageEmit ( + OUT uint32_t *OutputFileSize, + IN const void *Buffer, + IN uint64_t BufferSize, + IN int8_t Format, + IN int32_t Type, + IN void *HiiFile, + IN uint32_t HiiFileSize, + IN bool Relocate, + IN uint64_t BaseAddress, + IN const char *SymbolsPath OPTIONAL + ); + +#endif // IMAGE_TOOL_EMIT_H diff --git a/BaseTools/ImageTool/Makefile b/BaseTools/ImageTool/Makefile index c09875b183..d071a6554e 100644 --- a/BaseTools/ImageTool/Makefile +++ b/BaseTools/ImageTool/Makefile @@ -19,7 +19,7 @@ OV = $(UDK_PATH)\MdePkg\Library\BaseOverflowLib PE = $(UDK_PATH)\MdePkg\Library\BasePeCoffLib2 UA = $(UDK_PATH)\MdePkg\Library\BaseUefiImageExtraActionLibNull -OBJECTS = ImageTool.obj Image.obj PeEmit32.obj PeEmit64.obj PeEmitCommon.obj PeScan.obj ElfScan32.obj ElfScan64.obj ElfScanCommon.obj BinEmit.obj +OBJECTS = ImageTool.obj Image.obj PeEmit32.obj PeEmit64.obj PeEmitCommon.obj PeScan.obj ElfScan32.obj ElfScan64.obj ElfScanCommon.obj BinEmit.obj ImageToolEmit.obj OBJECTS = $(OBJECTS) {$(OV)}BaseAlignment.obj BaseBitOverflow.obj {$(UA)}UefiImageExtraActionLib.obj OBJECTS = $(OBJECTS) {$(PE)}PeCoffInit.obj PeCoffInfo.obj PeCoffRelocate.obj PeCoffLoad.obj PeCoffHii.obj PeCoffDebug.obj diff --git a/MdePkg/Include/Library/UefiImageLib.h b/MdePkg/Include/Library/UefiImageLib.h index 0595334718..58573746a7 100644 --- a/MdePkg/Include/Library/UefiImageLib.h +++ b/MdePkg/Include/Library/UefiImageLib.h @@ -2,6 +2,11 @@ #ifndef UEFI_IMAGE_LIB_H_ #define UEFI_IMAGE_LIB_H_ +typedef enum { + UefiImageFormatPe = 0, + UefiImageFormatMax +} UEFI_IMAGE_FORMAT; + // FIXME: Work on reasonable abstraction #ifndef UEFI_IMAGE_LOADER_IMAGE_CONTEXT #include