UE: Added support for XIP.

This commit is contained in:
Mikhail Krichanov 2023-10-03 17:44:13 +03:00 committed by MikhailKrichanov
parent 923004dd69
commit f60c587094
6 changed files with 242 additions and 46 deletions

View File

@ -187,6 +187,11 @@ ToolImageEmit (
return NULL;
}
if ((Format == UefiImageFormatUe) && Xip) {
ToolImageDestruct (&ImageInfo);
return OutputFile;
}
Status = ValidateOutputFile (OutputFile, *OutputFileSize, &ImageInfo);
ToolImageDestruct (&ImageInfo);

View File

@ -908,6 +908,136 @@ ToolImageEmitUeFile (
return true;
}
static
bool
ToolImageEmitUeXipFile (
image_tool_dynamic_buffer *Buffer,
image_tool_image_info_t *Image
)
{
bool Success;
UE_HEADER UeHdr;
uint8_t AlignmentExponent;
int8_t Machine;
uint8_t Subsystem;
uint8_t LastSegmentIndex;
uint8_t NumLoadTables;
uint32_t Offset;
uint32_t UeHdrOff;
bool Chaining;
uint16_t Index;
uint64_t BaseAddress;
assert (Image->SegmentInfo.NumSegments > 0);
if (Image->SegmentInfo.NumSegments > UE_HEADER_NUM_SEGMENTS_MAX) {
DEBUG_RAISE ();
return false;
}
if (Image->HiiInfo.DataSize > 0) {
DEBUG_RAISE ();
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 ();
return false;
}
Machine = InternalGetUeMachine (Image->HeaderInfo.Machine);
if (Machine < 0) {
DEBUG_RAISE ();
return false;
}
NumLoadTables = 0U;
Subsystem = (uint8_t)(Image->HeaderInfo.Subsystem - 10U);
LastSegmentIndex = (uint8_t)(Image->SegmentInfo.NumSegments - 1U);
Chaining = false;
UeHdr.Magic = UE_HEADER_MAGIC;
UeHdr.Type = (Machine << 3U) | Subsystem;
assert (UE_HEADER_SUBSYSTEM (UeHdr.Type) == Subsystem);
assert (UE_HEADER_ARCH (UeHdr.Type) == Machine);
UeHdr.TableCounts = NumLoadTables;
UeHdr.TableCounts |= LastSegmentIndex << 3U;
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 |= UE_HEADER_IMAGE_INFO_XIP;
UeHdr.ImageInfo |= (uint64_t)Image->HeaderInfo.FixedAddress << 57ULL;
UeHdr.ImageInfo |= (uint64_t)Image->RelocInfo.RelocsStripped << 58ULL;
UeHdr.ImageInfo |= (uint64_t)Chaining << 59ULL;
UeHdr.ImageInfo |= (uint64_t)(AlignmentExponent - 12U) << 60ULL;
assert (UE_HEADER_BASE_ADDRESS (UeHdr.ImageInfo) == BaseAddress);
assert ((UeHdr.ImageInfo & (0xFULL << 52ULL)) == 0);
assert (((UeHdr.ImageInfo & UE_HEADER_IMAGE_INFO_FIXED_ADDRESS) != 0) == Image->HeaderInfo.FixedAddress);
assert (((UeHdr.ImageInfo & UE_HEADER_IMAGE_INFO_RELOCATION_FIXUPS_STRIPPED) != 0) == Image->RelocInfo.RelocsStripped);
assert (((UeHdr.ImageInfo & UE_HEADER_IMAGE_INFO_CHAINED_FIXUPS) != 0) == Chaining);
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));
if (Offset == MAX_UINT32) {
DEBUG_RAISE ();
return false;
}
Success = ToolImageEmitUeSegmentHeaders (Buffer, Image);
if (!Success) {
DEBUG_RAISE ();
return false;
}
Offset = ImageToolBufferAppendReserveAlign (
Buffer,
Image->SegmentInfo.SegmentAlignment
);
if (Offset == MAX_UINT32) {
DEBUG_RAISE ();
return false;
}
for (Index = 0; Index < Image->SegmentInfo.NumSegments; ++Index) {
Offset = ImageToolBufferAppend (
Buffer,
Image->SegmentInfo.Segments[Index].Data,
Image->SegmentInfo.Segments[Index].UnpaddedSize
);
if (Offset == MAX_UINT32) {
DEBUG_RAISE ();
return false;
}
Offset = ImageToolBufferAppendReserve (
Buffer,
Image->SegmentInfo.Segments[Index].ImageSize - Image->SegmentInfo.Segments[Index].UnpaddedSize
);
if (Offset == MAX_UINT32) {
DEBUG_RAISE ();
return false;
}
}
return true;
}
void *
ToolImageEmitUe (
image_tool_image_info_t *Image,
@ -921,13 +1051,14 @@ ToolImageEmitUe (
uint32_t BaseAddressSubtrahend;
void *FileBuffer;
// LCOV_EXCL_START
if (Xip) {
DEBUG_RAISE ();
return NULL;
}
// LCOV_EXCL_STOP
ImageToolBufferInit (&Buffer);
ImageInitUnpaddedSize (Image);
ToolImageEmitUePadChainedRelocs (Image);
if (Xip) {
Success = ToolImageEmitUeXipFile (&Buffer, Image);
} else {
Success = ToolImageStripEmptyPrefix (&BaseAddressSubtrahend, Image);
if (!Success) {
DEBUG_RAISE ();
@ -938,12 +1069,9 @@ ToolImageEmitUe (
ToolImageStripRelocs (Image);
}
ImageInitUnpaddedSize (Image);
ToolImageEmitUePadChainedRelocs (Image);
ImageToolBufferInit (&Buffer);
Success = ToolImageEmitUeFile (&Buffer, Image, BaseAddressSubtrahend);
}
if (!Success) {
DEBUG_RAISE ();
ImageToolBufferFree (&Buffer);

View File

@ -3622,6 +3622,9 @@ Returns:
UINT8 ImageFormat;
UINT32 RebasedImageSize;
VOID *RebasedImage;
UINT32 FfsFileLength;
UINTN FileOffset;
EFI_FFS_INTEGRITY_CHECK *IntegrityCheck;
Index = 0;
Cptr = NULL;
@ -3790,6 +3793,7 @@ Returns:
UefiImageFileBuffer = (VOID *) ((UINTN) CurrentPe32Section.Pe32Section + CurSecHdrSize);
UefiImageFileSize = SectPeSize;
FileOffset = (UINTN)UefiImageFileBuffer - (UINTN)(*FfsFile);
//
// UefiImage has no reloc section. It will try to get reloc data from the original UEFI image.
//
@ -3871,9 +3875,52 @@ Returns:
return EFI_UNSUPPORTED;
}
UefiImageFileBuffer = NULL;
UefiImageFileSize = 0;
if (ImageFormat == UefiImageFormatUe) {
FfsFileLength = GetFfsFileLength (*FfsFile) - SectPeSize + RebasedImageSize;
*FfsFile = realloc (*FfsFile, FfsFileLength);
if (*FfsFile == NULL) {
fprintf (stderr, "GenFv: Could not reallocate memory for rebased FfsFile\n");
return EFI_OUT_OF_RESOURCES;
}
*FileSize = FfsFileLength;
memmove (
(UINT8 *)((UINTN)(*FfsFile) + FileOffset),
RebasedImage,
RebasedImageSize
);
if (FfsHeaderSize > sizeof(EFI_FFS_FILE_HEADER)) {
((EFI_FFS_FILE_HEADER2 *)(*FfsFile))->ExtendedSize = FfsFileLength;
} else {
(*FfsFile)->Size[0] = (UINT8)(FfsFileLength & 0x000000FF);
(*FfsFile)->Size[1] = (UINT8)((FfsFileLength & 0x0000FF00) >> 8);
(*FfsFile)->Size[2] = (UINT8)((FfsFileLength & 0x00FF0000) >> 16);
}
//
// Recalculate the FFS header checksum. Instead of setting Header and State
// both to zero, set Header to (UINT8)(-State) so State preserves its original
// value
//
IntegrityCheck = &(*FfsFile)->IntegrityCheck;
IntegrityCheck->Checksum.Header = (UINT8) (0x100 - (*FfsFile)->State);
IntegrityCheck->Checksum.File = 0;
IntegrityCheck->Checksum.Header = CalculateChecksum8 (
(UINT8 *)(*FfsFile), FfsHeaderSize);
if ((*FfsFile)->Attributes & FFS_ATTRIB_CHECKSUM) {
//
// Ffs header checksum = zero, so only need to calculate ffs body.
//
IntegrityCheck->Checksum.File = CalculateChecksum8 (
(UINT8 *)(*FfsFile) + FfsHeaderSize,
FfsFileLength - FfsHeaderSize);
} else {
IntegrityCheck->Checksum.File = FFS_FIXED_CHECKSUM;
}
} else {
if (RebasedImageSize > SectPeSize) {
Error (NULL, 0, 4001, "Invalid", "rebased file is too large (%s)", FileName);
return EFI_UNSUPPORTED;
@ -3903,6 +3950,7 @@ Returns:
);
(*FfsFile)->State = SavedState;
}
}
//
// Get this module function address from ModulePeMapFile and add them into FvMap file
@ -3910,7 +3958,7 @@ Returns:
Status = UefiImageInitializeContext (
&ImageContext,
(VOID *) ((UINTN) CurrentPe32Section.Pe32Section + CurSecHdrSize),
(VOID *) ((UINTN)(*FfsFile) + FileOffset),
RebasedImageSize,
UEFI_IMAGE_SOURCE_FV
);
@ -3927,6 +3975,9 @@ Returns:
&ImageContext
);
UefiImageFileBuffer = NULL;
UefiImageFileSize = 0;
free (SymbolsPathCpy);
}

View File

@ -501,7 +501,8 @@ typedef struct {
///
/// [Bits 51:0] The base UEFI page of the UE image, i.e., the base address in
/// 4 KiB units.
/// [Bits 56:52] Reserved for future use. Must be zero.
/// [Bits 55:52] Reserved for future use. Must be zero.
/// [Bit 56] Indicates whether the UE image is XIP
/// [Bit 57] Indicates whether the UE image is designated for a fixed
/// address.
/// [Bit 58] Indicates whether the UE relocation table has been stripped.
@ -569,6 +570,11 @@ STATIC_ASSERT (
#define UE_HEADER_SEGMENT_ALIGNMENT(ImageInfo) \
(1U << ((UINT8)RShiftU64 (ImageInfo, 60) + 12U))
///
/// UE header image information bit that indicates whether the image is XIP.
///
#define UE_HEADER_IMAGE_INFO_XIP 0x0100000000000000ULL
///
/// UE header image information bit that indicates whether the image is
/// designated to be loaded to a fixed address.

View File

@ -17,6 +17,7 @@ typedef struct {
UINT8 Subsystem;
UINT8 Machine;
BOOLEAN FixedAddress;
BOOLEAN XIP;
UINT8 LastSegmentIndex;
UINT32 SegmentsFileOffset; // Unused for XIP
UINT32 SegmentAlignment;

View File

@ -273,6 +273,10 @@ InternalInitializeContextLate (
return RETURN_UNSUPPORTED;
}
if (Context->XIP) {
return RETURN_SUCCESS;
}
return InternalVerifyLoadTables (Context);
}
@ -320,6 +324,7 @@ UeInitializeContextPostHash (
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;