Skip to content

Commit

Permalink
UE: Added support for relocatable XIP images.
Browse files Browse the repository at this point in the history
  • Loading branch information
Mikhail Krichanov committed Oct 17, 2023
1 parent c21a7a4 commit 02332b3
Show file tree
Hide file tree
Showing 3 changed files with 86 additions and 50 deletions.
89 changes: 59 additions & 30 deletions BaseTools/ImageTool/UeEmit.c
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,8 @@ static
bool
ToolImageEmitUeSegmentHeaders (
image_tool_dynamic_buffer *Buffer,
const image_tool_image_info_t *Image
const image_tool_image_info_t *Image,
bool Xip
)
{
uint16_t Index;
Expand Down Expand Up @@ -82,7 +83,7 @@ ToolImageEmitUeSegmentHeaders (
assert (UE_SEGMENT_SIZE (Segment.ImageInfo) == Image->SegmentInfo.Segments[Index].ImageSize);
assert (UE_SEGMENT_PERMISSIONS (Segment.ImageInfo) == Permissions);

Segment.FileSize = Image->SegmentInfo.Segments[Index].UnpaddedSize;
Segment.FileSize = Xip ? Image->SegmentInfo.Segments[Index].ImageSize : Image->SegmentInfo.Segments[Index].UnpaddedSize;

Offset = ImageToolBufferAppend (Buffer, &Segment, sizeof (Segment));
if (Offset == MAX_UINT32) {
Expand Down Expand Up @@ -798,7 +799,7 @@ ToolImageEmitUeFile (
uint8_t NumLoadTables;
uint32_t Offset;
bool Chaining;
uint32_t SegmentHeaersOffset;
uint32_t SegmentHeadersOffset;
uint32_t LoadTablesOffset;
uint32_t SegmentsOffset;

Expand Down Expand Up @@ -866,9 +867,9 @@ ToolImageEmitUeFile (
return false;
}

SegmentHeaersOffset = ImageToolBufferGetSize (Buffer);
SegmentHeadersOffset = ImageToolBufferGetSize (Buffer);

Success = ToolImageEmitUeSegmentHeaders (Buffer, Image);
Success = ToolImageEmitUeSegmentHeaders (Buffer, Image, false);
if (!Success) {
DEBUG_RAISE ();
return false;
Expand All @@ -894,7 +895,7 @@ ToolImageEmitUeFile (
Success = ToolImageEmitUeLoadTables (
Buffer,
LoadTablesOffset,
SegmentHeaersOffset,
SegmentHeadersOffset,
SegmentsOffset,
Image,
BaseAddressSubtrahend,
Expand All @@ -912,7 +913,8 @@ static
bool
ToolImageEmitUeXipFile (
image_tool_dynamic_buffer *Buffer,
image_tool_image_info_t *Image
image_tool_image_info_t *Image,
bool Strip
)
{
bool Success;
Expand All @@ -923,9 +925,10 @@ ToolImageEmitUeXipFile (
uint8_t LastSegmentIndex;
uint8_t NumLoadTables;
uint32_t Offset;
uint32_t UeHdrOff;
uint16_t Index;
uint64_t BaseAddress;
uint32_t SegmentHeadersOffset;
uint32_t LoadTablesOffset;
uint32_t SegmentsOffset;

assert (Image->SegmentInfo.NumSegments > 0);

Expand All @@ -939,15 +942,6 @@ ToolImageEmitUeXipFile (
return false;
}

BaseAddress = Image->HeaderInfo.BaseAddress;
UeHdrOff = ALIGN_VALUE(sizeof (UeHdr), Image->SegmentInfo.SegmentAlignment);

Success = ToolImageRelocate (Image, BaseAddress + UeHdrOff, 0);
if (!Success) {
DEBUG_RAISE ();
return false;
}

AlignmentExponent = AlignmentToExponent (Image->SegmentInfo.SegmentAlignment);
if (12 > AlignmentExponent || AlignmentExponent > 27) {
DEBUG_RAISE ();
Expand All @@ -960,7 +954,7 @@ ToolImageEmitUeXipFile (
return false;
}

NumLoadTables = 0U;
NumLoadTables = (!Strip && ToolImageUeRelocTableRequired (Image)) ? 1U : 0U;
Subsystem = (uint8_t)(Image->HeaderInfo.Subsystem - 10U);
LastSegmentIndex = (uint8_t)(Image->SegmentInfo.NumSegments - 1U);

Expand All @@ -975,33 +969,42 @@ ToolImageEmitUeXipFile (
assert (UE_HEADER_LAST_SEGMENT_INDEX (UeHdr.TableCounts) == LastSegmentIndex);
assert (UE_HEADER_NUM_LOAD_TABLES (UeHdr.TableCounts) == NumLoadTables);

UeHdr.EntryPointAddress = Image->HeaderInfo.EntryPointAddress + UeHdrOff;

UeHdr.ImageInfo = BaseAddress >> 12ULL;
UeHdr.ImageInfo = Image->HeaderInfo.BaseAddress >> 12ULL;
UeHdr.ImageInfo |= UE_HEADER_IMAGE_INFO_XIP;
UeHdr.ImageInfo |= UE_HEADER_IMAGE_INFO_FIXED_ADDRESS;
UeHdr.ImageInfo |= UE_HEADER_IMAGE_INFO_RELOCATION_FIXUPS_STRIPPED;
UeHdr.ImageInfo |= (uint64_t)Image->HeaderInfo.FixedAddress << 57ULL;
UeHdr.ImageInfo |= (uint64_t)Strip << 58ULL;
UeHdr.ImageInfo |= (uint64_t)(AlignmentExponent - 12U) << 60ULL;
assert (UE_HEADER_BASE_ADDRESS (UeHdr.ImageInfo) == BaseAddress);
assert (UE_HEADER_BASE_ADDRESS (UeHdr.ImageInfo) == Image->HeaderInfo.BaseAddress);
assert ((UeHdr.ImageInfo & (0xFULL << 52ULL)) == 0);
assert (((UeHdr.ImageInfo & UE_HEADER_IMAGE_INFO_FIXED_ADDRESS) != 0) == TRUE);
assert (((UeHdr.ImageInfo & UE_HEADER_IMAGE_INFO_RELOCATION_FIXUPS_STRIPPED) != 0) == TRUE);
assert (((UeHdr.ImageInfo & UE_HEADER_IMAGE_INFO_FIXED_ADDRESS) != 0) == Image->HeaderInfo.FixedAddress);
assert (((UeHdr.ImageInfo & UE_HEADER_IMAGE_INFO_RELOCATION_FIXUPS_STRIPPED) != 0) == Strip);
assert (((UeHdr.ImageInfo & UE_HEADER_IMAGE_INFO_CHAINED_FIXUPS) != 0) == FALSE);
assert (((UeHdr.ImageInfo & UE_HEADER_IMAGE_INFO_XIP) != 0) == TRUE);
assert (UE_HEADER_SEGMENT_ALIGNMENT (UeHdr.ImageInfo) == Image->SegmentInfo.SegmentAlignment);

Offset = ImageToolBufferAppend (Buffer, &UeHdr, sizeof (UeHdr));
Offset = ImageToolBufferAppendReserve (Buffer, sizeof (UeHdr));
if (Offset == MAX_UINT32) {
DEBUG_RAISE ();
return false;
}

Success = ToolImageEmitUeSegmentHeaders (Buffer, Image);
SegmentHeadersOffset = ImageToolBufferGetSize (Buffer);

Success = ToolImageEmitUeSegmentHeaders (Buffer, Image, true);
if (!Success) {
DEBUG_RAISE ();
return false;
}

LoadTablesOffset = ImageToolBufferAppendReserve (
Buffer,
NumLoadTables * sizeof (UE_LOAD_TABLE)
);
if (LoadTablesOffset == MAX_UINT32) {
DEBUG_RAISE ();
return false;
}

Offset = ImageToolBufferAppendReserveAlign (
Buffer,
Image->SegmentInfo.SegmentAlignment
Expand All @@ -1011,6 +1014,17 @@ ToolImageEmitUeXipFile (
return false;
}

SegmentsOffset = ImageToolBufferGetSize (Buffer);

UeHdr.EntryPointAddress = Image->HeaderInfo.EntryPointAddress + SegmentsOffset;
ImageToolBufferWrite (Buffer, 0, &UeHdr, sizeof (UeHdr));

Success = ToolImageRelocate (Image, Image->HeaderInfo.BaseAddress + SegmentsOffset, 0);
if (!Success) {
DEBUG_RAISE ();
return false;
}

for (Index = 0; Index < Image->SegmentInfo.NumSegments; ++Index) {
Offset = ImageToolBufferAppend (
Buffer,
Expand All @@ -1032,6 +1046,21 @@ ToolImageEmitUeXipFile (
}
}

if (!Strip && ToolImageUeRelocTableRequired (Image)) {
Success = ToolImageEmitUeRelocTable (
Buffer,
LoadTablesOffset,
SegmentHeadersOffset,
SegmentsOffset,
Image,
false
);
if (!Success) {
DEBUG_RAISE ();
return false;
}
}

return true;
}

Expand All @@ -1054,7 +1083,7 @@ ToolImageEmitUe (
ToolImageEmitUePadChainedRelocs (Image);

if (Xip) {
Success = ToolImageEmitUeXipFile (&Buffer, Image);
Success = ToolImageEmitUeXipFile (&Buffer, Image, Strip);
} else {
Success = ToolImageStripEmptyPrefix (&BaseAddressSubtrahend, Image);
if (!Success) {
Expand Down
2 changes: 1 addition & 1 deletion BaseTools/Source/C/GenFv/GenFvInternalLib.c
Original file line number Diff line number Diff line change
Expand Up @@ -3864,7 +3864,7 @@ Routine Description:
NewBaseAddress,
NULL,
TRUE,
Strip,
ImageFormat == UefiImageFormatUe ? (*FfsFile)->Type == EFI_FV_FILETYPE_SECURITY_CORE : Strip,
FALSE
);

Expand Down
45 changes: 26 additions & 19 deletions MdePkg/Library/BaseUeImageLib/UeImageLib.c
Original file line number Diff line number Diff line change
Expand Up @@ -119,6 +119,10 @@ InternalVerifySegments (
Context->LoadTablesFileOffset = SegmentEndFileOffset;
Context->ImageSize = SegmentEndImageAddress;

if (Context->XIP) {
Context->ImageSize += Context->SegmentsFileOffset;
}

return RETURN_SUCCESS;
}

Expand Down Expand Up @@ -273,10 +277,6 @@ InternalInitializeContextLate (
return RETURN_UNSUPPORTED;
}

if (Context->XIP) {
return RETURN_SUCCESS;
}

return InternalVerifyLoadTables (Context);
}

Expand All @@ -297,6 +297,14 @@ UeInitializeContextPostHash (

UeHdr = (CONST UE_HEADER *)Context->FileBuffer;

Context->FixedAddress = (UeHdr->ImageInfo & UE_HEADER_IMAGE_INFO_FIXED_ADDRESS) != 0;
Context->RelocsStripped = (UeHdr->ImageInfo & UE_HEADER_IMAGE_INFO_RELOCATION_FIXUPS_STRIPPED) != 0;
Context->XIP = (UeHdr->ImageInfo & UE_HEADER_IMAGE_INFO_XIP) != 0;

Context->Segments = UeHdr->Segments;
Context->SegmentImageInfoIterSize = sizeof (*UeHdr->Segments);
Context->SegmentAlignment = UE_HEADER_SEGMENT_ALIGNMENT (UeHdr->ImageInfo);

LastSegmentIndex = UE_HEADER_LAST_SEGMENT_INDEX (UeHdr->TableCounts);
NumLoadTables = UE_HEADER_NUM_LOAD_TABLES (UeHdr->TableCounts);

Expand All @@ -305,6 +313,9 @@ UeInitializeContextPostHash (

HeaderSize = LoadTablesFileOffset + (UINT32) NumLoadTables * sizeof (UE_LOAD_TABLE);
ASSERT (HeaderSize <= MAX_SIZE_OF_UE_HEADER);
if (Context->XIP) {
HeaderSize = ALIGN_VALUE (HeaderSize, Context->SegmentAlignment);
}

if (HeaderSize > Context->UnsignedFileSize) {
DEBUG_RAISE ();
Expand All @@ -317,17 +328,9 @@ UeInitializeContextPostHash (
(CONST UINT8 *) UeHdr + LoadTablesFileOffset
);

Context->SegmentsFileOffset = HeaderSize;
Context->Segments = UeHdr->Segments;
Context->SegmentImageInfoIterSize = sizeof (*UeHdr->Segments);
Context->SegmentAlignment = UE_HEADER_SEGMENT_ALIGNMENT (UeHdr->ImageInfo);

Context->FixedAddress = (UeHdr->ImageInfo & UE_HEADER_IMAGE_INFO_FIXED_ADDRESS) != 0;
Context->RelocsStripped = (UeHdr->ImageInfo & UE_HEADER_IMAGE_INFO_RELOCATION_FIXUPS_STRIPPED) != 0;
Context->XIP = (UeHdr->ImageInfo & UE_HEADER_IMAGE_INFO_XIP) != 0;

Context->LastSegmentIndex = LastSegmentIndex;
Context->NumLoadTables = NumLoadTables;
Context->SegmentsFileOffset = HeaderSize;
Context->LastSegmentIndex = LastSegmentIndex;
Context->NumLoadTables = NumLoadTables;

BaseAddress = UE_HEADER_BASE_ADDRESS (UeHdr->ImageInfo);

Expand Down Expand Up @@ -508,7 +511,7 @@ InternalApplyRelocation (
//
// If the Image relocation target value mismatches, skip or abort.
//
if (FixupValue.Value32 != (UINT32)*FixupData) {
if (IsRuntime && (FixupValue.Value32 != (UINT32)*FixupData)) {
if (PcdGetBool (PcdImageLoaderRtRelocAllowTargetMismatch)) {
return RETURN_SUCCESS;
}
Expand All @@ -535,7 +538,7 @@ InternalApplyRelocation (
//
// If the Image relocation target value mismatches, skip or abort.
//
if (FixupValue.Value64 != *FixupData) {
if (IsRuntime && (FixupValue.Value64 != *FixupData)) {
if (PcdGetBool (PcdImageLoaderRtRelocAllowTargetMismatch)) {
return RETURN_SUCCESS;
}
Expand Down Expand Up @@ -960,7 +963,7 @@ InternaRelocateImage (
//
RelocType = UE_RELOC_FIXUP_TYPE (FixupInfo);

if (!IsRuntime && (RelocType != UeReloc32NoMeta)) {
if (Chaining && !IsRuntime && (RelocType != UeReloc32NoMeta)) {
Status = InternalProcessRelocChain (
Image,
ImageSize,
Expand Down Expand Up @@ -1080,11 +1083,15 @@ UeRelocateImage (
RuntimeContext->Machine = Context->Machine;
}

if (Context->XIP) {
Context->EntryPointAddress -= Context->SegmentsFileOffset;
}

return InternaRelocateImage (
Context->ImageBuffer,
Context->ImageSize,
Context->Machine,
Context->BaseAddress,
Context->XIP ? (Context->BaseAddress + Context->SegmentsFileOffset) : Context->BaseAddress,
RelocTable,
Context->RelocTableSize,
Chaining,
Expand Down

0 comments on commit 02332b3

Please sign in to comment.