From 7797818d3c48bcff71cc327adb0a15b28a014b98 Mon Sep 17 00:00:00 2001 From: Mikhail Krichanov Date: Fri, 8 Sep 2023 14:56:28 +0300 Subject: [PATCH] BaseTools, BaseUeImageLib: Added support for 32-bit chaining relocations. Fixed Windows 10 BlueScreen issue for IA32. --- BaseTools/ImageTool/UeEmit.c | 44 ++++++++++++++++++-- BaseTools/ImageTool/UeScan.c | 26 +++++++++++- MdePkg/Include/IndustryStandard/UeImage.h | 23 +++++++++++ MdePkg/Library/BaseUeImageLib/UeImageLib.c | 47 ++++++++++++++++------ OvmfPkg/OvmfPkgIa32.fdf | 2 +- 5 files changed, 124 insertions(+), 18 deletions(-) diff --git a/BaseTools/ImageTool/UeEmit.c b/BaseTools/ImageTool/UeEmit.c index 13d4466729..b1040df3ad 100644 --- a/BaseTools/ImageTool/UeEmit.c +++ b/BaseTools/ImageTool/UeEmit.c @@ -315,6 +315,7 @@ ToolImageEmitUeRelocTable ( uint32_t RelocOffset; uint64_t ChainRelocInfo; + uint32_t ChainRelocInfo32; uint8_t PrevRelocType; uint32_t PrevRelocTarget; @@ -323,6 +324,7 @@ ToolImageEmitUeRelocTable ( uint8_t PrevRelocSize; uint64_t PrevChainRelocInfo; + uint32_t PrevChainRelocInfo32; bool ChainInProgress; bool ChainSupported; @@ -385,7 +387,7 @@ ToolImageEmitUeRelocTable ( { RelocSize = sizeof (UINT32); RelocType = UeReloc32; - ChainSupported = false; + ChainSupported = Chaining; break; } @@ -426,9 +428,9 @@ ToolImageEmitUeRelocTable ( // if (ChainInProgress) { - ChainInProgress = ChainSupported && RelocOffset <= UE_CHAINED_RELOC_FIXUP_MAX_OFFSET; + ChainInProgress = ChainSupported && (RelocOffset <= UE_CHAINED_RELOC_FIXUP_MAX_OFFSET) && (PrevRelocType == RelocType); - if (ChainInProgress) { + if (ChainInProgress && (RelocType == UeReloc64)) { PrevChainRelocInfo = RelocType; PrevChainRelocInfo |= RelocOffset << 4U; PrevChainRelocInfo |= PrevRelocValue << 16U; @@ -444,10 +446,22 @@ ToolImageEmitUeRelocTable ( &PrevChainRelocInfo, PrevRelocSize ); + } else if (ChainInProgress && (RelocType == UeReloc32)) { + PrevChainRelocInfo32 = RelocOffset; + PrevChainRelocInfo32 |= PrevRelocValue << UE_CHAINED_RELOC_FIXUP_VALUE_32_SHIFT; + + assert (PrevRelocSize <= sizeof (PrevChainRelocInfo32)); + + ImageToolBufferWrite ( + Buffer, + PrevRelocFileOffset, + &PrevChainRelocInfo32, + PrevRelocSize + ); } } - if (ChainSupported) { + if (ChainSupported && (RelocType == UeReloc64)) { ChainRelocInfo = UE_CHAINED_RELOC_FIXUP_OFFSET_END << 4U; ChainRelocInfo |= RelocValue << 16U; if ((ChainRelocInfo >> 16U) != RelocValue) { @@ -471,6 +485,28 @@ ToolImageEmitUeRelocTable ( continue; } + ChainInProgress = true; + } else if (ChainSupported && (RelocType == UeReloc32)) { + ChainRelocInfo32 = UE_CHAINED_RELOC_FIXUP_OFFSET_END; + ChainRelocInfo32 |= RelocValue << UE_CHAINED_RELOC_FIXUP_VALUE_32_SHIFT; + if ((ChainRelocInfo32 >> UE_CHAINED_RELOC_FIXUP_VALUE_32_SHIFT) != RelocValue) { + DEBUG_RAISE (); + return false; + } + + assert (RelocSize <= sizeof (ChainRelocInfo32)); + + ImageToolBufferWrite ( + Buffer, + RelocFileOffset, + &ChainRelocInfo32, + RelocSize + ); + + if (ChainInProgress) { + continue; + } + ChainInProgress = true; } diff --git a/BaseTools/ImageTool/UeScan.c b/BaseTools/ImageTool/UeScan.c index 4c89e30bd2..a69d4fb288 100644 --- a/BaseTools/ImageTool/UeScan.c +++ b/BaseTools/ImageTool/UeScan.c @@ -77,6 +77,30 @@ InternalProcessRelocChain ( WriteUnaligned64 (Fixup, FixupValue.Value64); Reloc.Type = EFI_IMAGE_REL_BASED_DIR64; + } else if (RelocType == UeReloc32) { + FixupSize = sizeof (UINT32); + // + // Verify the image relocation fixup target is in bounds of the image + // buffer. + // + if (FixupSize > RemRelocTargetSize) { + DEBUG_RAISE (); + return RETURN_VOLUME_CORRUPTED; + } + // + // Relocate the target instruction. + // + FixupInfo.Value32 = ReadUnaligned32 (Fixup); + FixupValue.Value32 = UE_CHAINED_RELOC_FIXUP_VALUE_32 (FixupInfo.Value32); + WriteUnaligned32 (Fixup, FixupValue.Value32); + + Reloc.Type = EFI_IMAGE_REL_BASED_HIGHLOW; + // + // Imitate the common header of UE chained relocation fixups, + // as for 32-bit files all relocs have the same type. + // + FixupInfo.Value32 = FixupInfo.Value32 << 4; + FixupInfo.Value32 |= UeReloc32; } else { // // The Image relocation fixup type is unknown, disallow the Image. @@ -272,7 +296,7 @@ ScanUeGetRelocInfo ( // RelocType = UE_RELOC_FIXUP_TYPE (FixupInfo); - if (Chaining && RelocType != UeReloc32) { + if (Chaining) { Status = InternalProcessRelocChain ( &Buffer, SegmentInfo, diff --git a/MdePkg/Include/IndustryStandard/UeImage.h b/MdePkg/Include/IndustryStandard/UeImage.h index 22aa574c6b..42e337abf3 100644 --- a/MdePkg/Include/IndustryStandard/UeImage.h +++ b/MdePkg/Include/IndustryStandard/UeImage.h @@ -321,6 +321,29 @@ typedef UINT16 UE_RELOC_FIXUP_HDR; /// typedef UINT64 UE_RELOC_FIXUP_64; +/// +/// The shift exponent for UE chained 32-bit relocation fixup values. +/// +#define UE_CHAINED_RELOC_FIXUP_VALUE_32_SHIFT 12U + +/** + Retrieves the value of the current UE chained 32-bit relocation fixup. + + @param[in] FixupInfo The UE relocation fixup information. +**/ +#define UE_CHAINED_RELOC_FIXUP_VALUE_32(FixupInfo) \ + (UINT32)((UINT32)(FixupInfo) >> UE_CHAINED_RELOC_FIXUP_VALUE_32_SHIFT) + +/// +/// Definition of the generic 32-bit UE chained relocation fixup. +/// +/// [Bits 11:0] The offset to the next chained relocation fixup from the end +/// of the current one. If 0x0FFF, the current chain is terminated. +/// Consult the fixup root for further relocation fixups. +/// [Bits 31:12] The address value to relocate. +/// +typedef UINT32 UE_RELOC_FIXUP_32; + #if 0 /// /// Definition of the ARM Thumb MOVT/MOVW UE chained relocation fixup. diff --git a/MdePkg/Library/BaseUeImageLib/UeImageLib.c b/MdePkg/Library/BaseUeImageLib/UeImageLib.c index 5de434338a..2245c11cbb 100644 --- a/MdePkg/Library/BaseUeImageLib/UeImageLib.c +++ b/MdePkg/Library/BaseUeImageLib/UeImageLib.c @@ -505,20 +505,20 @@ InternalApplyRelocation ( // // If the Image relocation target value mismatches, skip or abort. // - // if (IsRuntime && (FixupValue.Value32 != (UINT32)*FixupData)) { - // if (PcdGetBool (PcdImageLoaderRtRelocAllowTargetMismatch)) { - // return RETURN_SUCCESS; - // } - // - // return RETURN_VOLUME_CORRUPTED; - // } + if (IsRuntime && (FixupValue.Value64 != *FixupData)) { + if (PcdGetBool (PcdImageLoaderRtRelocAllowTargetMismatch)) { + return RETURN_SUCCESS; + } + + return RETURN_VOLUME_CORRUPTED; + } FixupValue.Value32 += (UINT32) Adjust; WriteUnaligned32 (Fixup, FixupValue.Value32); - // if (!IsRuntime) { - // *FixupData = FixupValue.Value32; - // } + if (!IsRuntime) { + *FixupData = FixupValue.Value64; + } } else { ASSERT (RelocType == UeReloc64); @@ -657,7 +657,30 @@ InternalProcessRelocChain ( FixupInfo.Value64 = ReadUnaligned64 ((CONST VOID *)Fixup); FixupValue.Value64 = UE_CHAINED_RELOC_FIXUP_VALUE (FixupInfo.Value64); FixupValue.Value64 += Adjust; - WriteUnaligned64 ((VOID *) Fixup, FixupValue.Value64); + WriteUnaligned64 ((VOID *)Fixup, FixupValue.Value64); + } else if (RelocType == UeReloc32) { + FixupSize = sizeof (UINT32); + // + // Verify the image relocation fixup target is in bounds of the image + // buffer. + // + if (FixupSize > RemFixupTargetSize) { + DEBUG_RAISE (); + return RETURN_VOLUME_CORRUPTED; + } + // + // Relocate the target instruction. + // + FixupInfo.Value32 = ReadUnaligned32 ((CONST VOID *)Fixup); + FixupValue.Value32 = UE_CHAINED_RELOC_FIXUP_VALUE_32 (FixupInfo.Value32); + FixupValue.Value32 += (UINT32) Adjust; + WriteUnaligned32 ((VOID *)Fixup, FixupValue.Value32); + // + // Imitate the common header of UE chained relocation fixups, + // as for 32-bit files all relocs have the same type. + // + FixupInfo.Value32 = FixupInfo.Value32 << 4; + FixupInfo.Value32 |= UeReloc32; } else { // // The image relocation fixup type is unknown, disallow the image. @@ -790,7 +813,7 @@ InternaRelocateImage ( // RelocType = UE_RELOC_FIXUP_TYPE (FixupInfo); - if (Chaining && RelocType != UeReloc32) { + if (Chaining) { Status = InternalProcessRelocChain ( Image, ImageSize, diff --git a/OvmfPkg/OvmfPkgIa32.fdf b/OvmfPkg/OvmfPkgIa32.fdf index dd8a7b4a7b..204a43fb16 100644 --- a/OvmfPkg/OvmfPkgIa32.fdf +++ b/OvmfPkg/OvmfPkgIa32.fdf @@ -456,7 +456,7 @@ FILE FV_IMAGE = 9E21FD93-9C72-4c15-8C4B-E77F1DB2D792 { [Rule.Common.DXE_RUNTIME_DRIVER] FILE DRIVER = $(NAMED_GUID) { DXE_DEPEX DXE_DEPEX Optional $(INF_OUTPUT)/$(MODULE_NAME).depex - PE32 PE32 $(INF_OUTPUT)/$(MODULE_NAME).efi + UE UE $(INF_OUTPUT)/$(MODULE_NAME).efi UI STRING="$(MODULE_NAME)" Optional VERSION STRING="$(INF_VERSION)" Optional BUILD_NUM=$(BUILD_NUMBER) }