mirror of https://github.com/acidanthera/audk.git
1145 lines
42 KiB
C
1145 lines
42 KiB
C
/** @file
|
|
|
|
Provides definitions and functionality for manipulating IMAGE_PROPERTIES_RECORD.
|
|
|
|
Copyright (c) 2016 - 2018, Intel Corporation. All rights reserved.<BR>
|
|
Copyright (c) Microsoft Corporation.
|
|
SPDX-License-Identifier: BSD-2-Clause-Patent
|
|
|
|
**/
|
|
|
|
#include <PiDxe.h>
|
|
|
|
#include <Library/BaseLib.h>
|
|
#include <Library/BaseMemoryLib.h>
|
|
#include <Library/DebugLib.h>
|
|
#include <Library/MemoryAllocationLib.h>
|
|
#include <Library/PeCoffGetEntryPointLib.h>
|
|
#include <Library/ImagePropertiesRecordLib.h>
|
|
|
|
#define PREVIOUS_MEMORY_DESCRIPTOR(MemoryDescriptor, Size) \
|
|
((EFI_MEMORY_DESCRIPTOR *)((UINT8 *)(MemoryDescriptor) - (Size)))
|
|
|
|
#define NEXT_MEMORY_DESCRIPTOR(MemoryDescriptor, Size) \
|
|
((EFI_MEMORY_DESCRIPTOR *)((UINT8 *)(MemoryDescriptor) + (Size)))
|
|
|
|
/**
|
|
Converts a number of pages to a size in bytes.
|
|
|
|
NOTE: Do not use EFI_PAGES_TO_SIZE because it handles UINTN only.
|
|
|
|
@param[in] Pages The number of EFI_PAGES.
|
|
|
|
@retval The number of bytes associated with the input number of pages.
|
|
**/
|
|
STATIC
|
|
UINT64
|
|
EfiPagesToSize (
|
|
IN UINT64 Pages
|
|
)
|
|
{
|
|
return LShiftU64 (Pages, EFI_PAGE_SHIFT);
|
|
}
|
|
|
|
/**
|
|
Converts a size, in bytes, to a number of EFI_PAGESs.
|
|
|
|
NOTE: Do not use EFI_SIZE_TO_PAGES because it handles UINTN only.
|
|
|
|
@param[in] Size A size in bytes.
|
|
|
|
@retval The number of pages associated with the input number of bytes.
|
|
|
|
**/
|
|
STATIC
|
|
UINT64
|
|
EfiSizeToPages (
|
|
IN UINT64 Size
|
|
)
|
|
{
|
|
return RShiftU64 (Size, EFI_PAGE_SHIFT) + ((((UINTN)Size) & EFI_PAGE_MASK) ? 1 : 0);
|
|
}
|
|
|
|
/**
|
|
Sort memory map entries based upon PhysicalStart from low to high.
|
|
|
|
@param[in, out] MemoryMap A pointer to the buffer in which firmware places
|
|
the current memory map.
|
|
@param[in] MemoryMapSize Size, in bytes, of the MemoryMap buffer.
|
|
@param[in] DescriptorSize Size, in bytes, of an individual EFI_MEMORY_DESCRIPTOR.
|
|
**/
|
|
STATIC
|
|
VOID
|
|
SortMemoryMap (
|
|
IN OUT EFI_MEMORY_DESCRIPTOR *MemoryMap,
|
|
IN UINTN MemoryMapSize,
|
|
IN UINTN DescriptorSize
|
|
)
|
|
{
|
|
EFI_MEMORY_DESCRIPTOR *MemoryMapEntry;
|
|
EFI_MEMORY_DESCRIPTOR *NextMemoryMapEntry;
|
|
EFI_MEMORY_DESCRIPTOR *MemoryMapEnd;
|
|
EFI_MEMORY_DESCRIPTOR TempMemoryMap;
|
|
|
|
MemoryMapEntry = MemoryMap;
|
|
NextMemoryMapEntry = NEXT_MEMORY_DESCRIPTOR (MemoryMapEntry, DescriptorSize);
|
|
MemoryMapEnd = (EFI_MEMORY_DESCRIPTOR *)((UINT8 *)MemoryMap + MemoryMapSize);
|
|
while (MemoryMapEntry < MemoryMapEnd) {
|
|
while (NextMemoryMapEntry < MemoryMapEnd) {
|
|
if (MemoryMapEntry->PhysicalStart > NextMemoryMapEntry->PhysicalStart) {
|
|
CopyMem (&TempMemoryMap, MemoryMapEntry, sizeof (EFI_MEMORY_DESCRIPTOR));
|
|
CopyMem (MemoryMapEntry, NextMemoryMapEntry, sizeof (EFI_MEMORY_DESCRIPTOR));
|
|
CopyMem (NextMemoryMapEntry, &TempMemoryMap, sizeof (EFI_MEMORY_DESCRIPTOR));
|
|
}
|
|
|
|
NextMemoryMapEntry = NEXT_MEMORY_DESCRIPTOR (NextMemoryMapEntry, DescriptorSize);
|
|
}
|
|
|
|
MemoryMapEntry = NEXT_MEMORY_DESCRIPTOR (MemoryMapEntry, DescriptorSize);
|
|
NextMemoryMapEntry = NEXT_MEMORY_DESCRIPTOR (MemoryMapEntry, DescriptorSize);
|
|
}
|
|
|
|
return;
|
|
}
|
|
|
|
/**
|
|
Return the first image record, whose [ImageBase, ImageSize] covered by [Buffer, Length].
|
|
|
|
@param[in] Buffer Starting Address
|
|
@param[in] Length Length to check
|
|
@param[in] ImageRecordList A list of IMAGE_PROPERTIES_RECORD entries to check against
|
|
the memory range Buffer -> Buffer + Length
|
|
|
|
@retval The first image record covered by [Buffer, Length]
|
|
**/
|
|
STATIC
|
|
IMAGE_PROPERTIES_RECORD *
|
|
GetImageRecordByAddress (
|
|
IN EFI_PHYSICAL_ADDRESS Buffer,
|
|
IN UINT64 Length,
|
|
IN LIST_ENTRY *ImageRecordList
|
|
)
|
|
{
|
|
IMAGE_PROPERTIES_RECORD *ImageRecord;
|
|
LIST_ENTRY *ImageRecordLink;
|
|
|
|
for (ImageRecordLink = ImageRecordList->ForwardLink;
|
|
ImageRecordLink != ImageRecordList;
|
|
ImageRecordLink = ImageRecordLink->ForwardLink)
|
|
{
|
|
ImageRecord = CR (
|
|
ImageRecordLink,
|
|
IMAGE_PROPERTIES_RECORD,
|
|
Link,
|
|
IMAGE_PROPERTIES_RECORD_SIGNATURE
|
|
);
|
|
|
|
if ((Buffer <= ImageRecord->ImageBase) &&
|
|
(Buffer + Length >= ImageRecord->ImageBase + ImageRecord->ImageSize))
|
|
{
|
|
return ImageRecord;
|
|
}
|
|
}
|
|
|
|
return NULL;
|
|
}
|
|
|
|
/**
|
|
Break up the input OldRecord into multiple new records based on the code
|
|
and data sections in the input ImageRecord.
|
|
|
|
@param[in] ImageRecord An IMAGE_PROPERTIES_RECORD whose ImageBase and
|
|
ImageSize is covered by by OldRecord.
|
|
@param[in, out] NewRecord A pointer to several new memory map entries.
|
|
The caller gurantee the buffer size be 1 +
|
|
(SplitRecordCount * DescriptorSize) calculated
|
|
below.
|
|
@param[in] OldRecord A pointer to one old memory map entry.
|
|
@param[in] DescriptorSize The size, in bytes, of an individual EFI_MEMORY_DESCRIPTOR.
|
|
|
|
@retval The number of new descriptors created.
|
|
**/
|
|
STATIC
|
|
UINTN
|
|
SetNewRecord (
|
|
IN IMAGE_PROPERTIES_RECORD *ImageRecord,
|
|
IN OUT EFI_MEMORY_DESCRIPTOR *NewRecord,
|
|
IN EFI_MEMORY_DESCRIPTOR *OldRecord,
|
|
IN UINTN DescriptorSize
|
|
)
|
|
{
|
|
EFI_MEMORY_DESCRIPTOR TempRecord;
|
|
IMAGE_PROPERTIES_RECORD_CODE_SECTION *ImageRecordCodeSection;
|
|
LIST_ENTRY *ImageRecordCodeSectionLink;
|
|
LIST_ENTRY *ImageRecordCodeSectionEndLink;
|
|
LIST_ENTRY *ImageRecordCodeSectionList;
|
|
UINTN NewRecordCount;
|
|
UINT64 PhysicalEnd;
|
|
UINT64 ImageEnd;
|
|
|
|
CopyMem (&TempRecord, OldRecord, sizeof (EFI_MEMORY_DESCRIPTOR));
|
|
PhysicalEnd = TempRecord.PhysicalStart + EfiPagesToSize (TempRecord.NumberOfPages);
|
|
NewRecordCount = 0;
|
|
|
|
ImageRecordCodeSectionList = &ImageRecord->CodeSegmentList;
|
|
|
|
ImageRecordCodeSectionLink = ImageRecordCodeSectionList->ForwardLink;
|
|
ImageRecordCodeSectionEndLink = ImageRecordCodeSectionList;
|
|
while (ImageRecordCodeSectionLink != ImageRecordCodeSectionEndLink) {
|
|
ImageRecordCodeSection = CR (
|
|
ImageRecordCodeSectionLink,
|
|
IMAGE_PROPERTIES_RECORD_CODE_SECTION,
|
|
Link,
|
|
IMAGE_PROPERTIES_RECORD_CODE_SECTION_SIGNATURE
|
|
);
|
|
ImageRecordCodeSectionLink = ImageRecordCodeSectionLink->ForwardLink;
|
|
|
|
if (TempRecord.PhysicalStart <= ImageRecordCodeSection->CodeSegmentBase) {
|
|
//
|
|
// DATA
|
|
//
|
|
NewRecord->Type = TempRecord.Type;
|
|
NewRecord->PhysicalStart = TempRecord.PhysicalStart;
|
|
NewRecord->VirtualStart = 0;
|
|
NewRecord->NumberOfPages = EfiSizeToPages (ImageRecordCodeSection->CodeSegmentBase - NewRecord->PhysicalStart);
|
|
NewRecord->Attribute = TempRecord.Attribute | EFI_MEMORY_XP;
|
|
if (NewRecord->NumberOfPages != 0) {
|
|
NewRecord = NEXT_MEMORY_DESCRIPTOR (NewRecord, DescriptorSize);
|
|
NewRecordCount++;
|
|
}
|
|
|
|
//
|
|
// CODE
|
|
//
|
|
NewRecord->Type = TempRecord.Type;
|
|
NewRecord->PhysicalStart = ImageRecordCodeSection->CodeSegmentBase;
|
|
NewRecord->VirtualStart = 0;
|
|
NewRecord->NumberOfPages = EfiSizeToPages (ImageRecordCodeSection->CodeSegmentSize);
|
|
NewRecord->Attribute = (TempRecord.Attribute & (~EFI_MEMORY_XP)) | EFI_MEMORY_RO;
|
|
if (NewRecord->NumberOfPages != 0) {
|
|
NewRecord = NEXT_MEMORY_DESCRIPTOR (NewRecord, DescriptorSize);
|
|
NewRecordCount++;
|
|
}
|
|
|
|
TempRecord.PhysicalStart = ImageRecordCodeSection->CodeSegmentBase + EfiPagesToSize (EfiSizeToPages (ImageRecordCodeSection->CodeSegmentSize));
|
|
TempRecord.NumberOfPages = EfiSizeToPages (PhysicalEnd - TempRecord.PhysicalStart);
|
|
if (TempRecord.NumberOfPages == 0) {
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
ImageEnd = ImageRecord->ImageBase + ImageRecord->ImageSize;
|
|
|
|
//
|
|
// Final DATA
|
|
//
|
|
if (TempRecord.PhysicalStart < ImageEnd) {
|
|
NewRecord->Type = TempRecord.Type;
|
|
NewRecord->PhysicalStart = TempRecord.PhysicalStart;
|
|
NewRecord->VirtualStart = 0;
|
|
NewRecord->NumberOfPages = EfiSizeToPages (ImageEnd - TempRecord.PhysicalStart);
|
|
NewRecord->Attribute = TempRecord.Attribute | EFI_MEMORY_XP;
|
|
NewRecordCount++;
|
|
}
|
|
|
|
return NewRecordCount;
|
|
}
|
|
|
|
/**
|
|
Return the maximum number of new entries required to describe the code and data sections
|
|
of all images covered by the input OldRecord.
|
|
|
|
@param[in] OldRecord A pointer to one old memory map entry.
|
|
@param[in] ImageRecordList A list of IMAGE_PROPERTIES_RECORD entries used when searching
|
|
for an image record contained by the memory range described by
|
|
OldRecord
|
|
|
|
@retval The maximum number of new descriptors required to describe the code and data sections
|
|
of all images covered by OldRecord.
|
|
**/
|
|
STATIC
|
|
UINTN
|
|
GetMaxSplitRecordCount (
|
|
IN EFI_MEMORY_DESCRIPTOR *OldRecord,
|
|
IN LIST_ENTRY *ImageRecordList
|
|
)
|
|
{
|
|
IMAGE_PROPERTIES_RECORD *ImageRecord;
|
|
UINTN SplitRecordCount;
|
|
UINT64 PhysicalStart;
|
|
UINT64 PhysicalEnd;
|
|
|
|
SplitRecordCount = 0;
|
|
PhysicalStart = OldRecord->PhysicalStart;
|
|
PhysicalEnd = OldRecord->PhysicalStart + EfiPagesToSize (OldRecord->NumberOfPages);
|
|
|
|
do {
|
|
ImageRecord = GetImageRecordByAddress (PhysicalStart, PhysicalEnd - PhysicalStart, ImageRecordList);
|
|
if (ImageRecord == NULL) {
|
|
break;
|
|
}
|
|
|
|
SplitRecordCount += (2 * ImageRecord->CodeSegmentCount + 3);
|
|
PhysicalStart = ImageRecord->ImageBase + ImageRecord->ImageSize;
|
|
} while ((ImageRecord != NULL) && (PhysicalStart < PhysicalEnd));
|
|
|
|
if (SplitRecordCount != 0) {
|
|
SplitRecordCount--;
|
|
}
|
|
|
|
return SplitRecordCount;
|
|
}
|
|
|
|
/**
|
|
Split the memory map into new entries based upon the PE code and data sections
|
|
in ImageRecordList covered by the input OldRecord.
|
|
|
|
@param[in] OldRecord A pointer to one old memory map entry.
|
|
@param[in, out] NewRecord A pointer to several new memory map entries.
|
|
The caller gurantee the buffer size be
|
|
(SplitRecordCount * DescriptorSize).
|
|
@param[in] MaxSplitRecordCount The maximum number of entries post-split.
|
|
@param[in] DescriptorSize The size, in bytes, of an individual EFI_MEMORY_DESCRIPTOR.
|
|
@param[in] ImageRecordList A list of IMAGE_PROPERTIES_RECORD entries used when searching
|
|
for an image record contained by the memory range described in
|
|
the existing EFI memory map descriptor OldRecord
|
|
|
|
@retval The number of split entries.
|
|
**/
|
|
STATIC
|
|
UINTN
|
|
SplitRecord (
|
|
IN EFI_MEMORY_DESCRIPTOR *OldRecord,
|
|
IN OUT EFI_MEMORY_DESCRIPTOR *NewRecord,
|
|
IN UINTN MaxSplitRecordCount,
|
|
IN UINTN DescriptorSize,
|
|
IN LIST_ENTRY *ImageRecordList
|
|
)
|
|
{
|
|
EFI_MEMORY_DESCRIPTOR TempRecord;
|
|
IMAGE_PROPERTIES_RECORD *ImageRecord;
|
|
IMAGE_PROPERTIES_RECORD *NewImageRecord;
|
|
UINT64 PhysicalStart;
|
|
UINT64 PhysicalEnd;
|
|
UINTN NewRecordCount;
|
|
UINTN TotalNewRecordCount;
|
|
|
|
if (MaxSplitRecordCount == 0) {
|
|
CopyMem (NewRecord, OldRecord, DescriptorSize);
|
|
return 0;
|
|
}
|
|
|
|
TotalNewRecordCount = 0;
|
|
|
|
//
|
|
// Override previous record
|
|
//
|
|
CopyMem (&TempRecord, OldRecord, sizeof (EFI_MEMORY_DESCRIPTOR));
|
|
PhysicalStart = TempRecord.PhysicalStart;
|
|
PhysicalEnd = TempRecord.PhysicalStart + EfiPagesToSize (TempRecord.NumberOfPages);
|
|
|
|
ImageRecord = NULL;
|
|
do {
|
|
NewImageRecord = GetImageRecordByAddress (PhysicalStart, PhysicalEnd - PhysicalStart, ImageRecordList);
|
|
if (NewImageRecord == NULL) {
|
|
//
|
|
// No more images cover this range, check if we've reached the end of the old descriptor. If not,
|
|
// add the remaining range to the new descriptor list.
|
|
//
|
|
if (PhysicalEnd > PhysicalStart) {
|
|
NewRecord->Type = TempRecord.Type;
|
|
NewRecord->PhysicalStart = PhysicalStart;
|
|
NewRecord->VirtualStart = 0;
|
|
NewRecord->NumberOfPages = EfiSizeToPages (PhysicalEnd - PhysicalStart);
|
|
NewRecord->Attribute = TempRecord.Attribute;
|
|
TotalNewRecordCount++;
|
|
}
|
|
|
|
break;
|
|
}
|
|
|
|
ImageRecord = NewImageRecord;
|
|
|
|
//
|
|
// Update PhysicalStart to exclude the portion before the image buffer
|
|
//
|
|
if (TempRecord.PhysicalStart < ImageRecord->ImageBase) {
|
|
NewRecord->Type = TempRecord.Type;
|
|
NewRecord->PhysicalStart = TempRecord.PhysicalStart;
|
|
NewRecord->VirtualStart = 0;
|
|
NewRecord->NumberOfPages = EfiSizeToPages (ImageRecord->ImageBase - TempRecord.PhysicalStart);
|
|
NewRecord->Attribute = TempRecord.Attribute;
|
|
TotalNewRecordCount++;
|
|
|
|
PhysicalStart = ImageRecord->ImageBase;
|
|
TempRecord.PhysicalStart = PhysicalStart;
|
|
TempRecord.NumberOfPages = EfiSizeToPages (PhysicalEnd - PhysicalStart);
|
|
|
|
NewRecord = (EFI_MEMORY_DESCRIPTOR *)((UINT8 *)NewRecord + DescriptorSize);
|
|
}
|
|
|
|
//
|
|
// Set new record
|
|
//
|
|
NewRecordCount = SetNewRecord (ImageRecord, NewRecord, &TempRecord, DescriptorSize);
|
|
TotalNewRecordCount += NewRecordCount;
|
|
NewRecord = (EFI_MEMORY_DESCRIPTOR *)((UINT8 *)NewRecord + NewRecordCount * DescriptorSize);
|
|
|
|
//
|
|
// Update PhysicalStart, in order to exclude the image buffer already splitted.
|
|
//
|
|
PhysicalStart = ImageRecord->ImageBase + ImageRecord->ImageSize;
|
|
TempRecord.PhysicalStart = PhysicalStart;
|
|
TempRecord.NumberOfPages = EfiSizeToPages (PhysicalEnd - PhysicalStart);
|
|
} while ((ImageRecord != NULL) && (PhysicalStart < PhysicalEnd));
|
|
|
|
//
|
|
// The logic in function SplitTable() ensures that TotalNewRecordCount will not be zero if the
|
|
// code reaches here.
|
|
//
|
|
ASSERT (TotalNewRecordCount != 0);
|
|
return TotalNewRecordCount - 1;
|
|
}
|
|
|
|
/**
|
|
Split the original memory map and add more entries to describe PE code
|
|
and data sections for each image in the input ImageRecordList.
|
|
|
|
NOTE: This function assumes PE code/data section are page aligned.
|
|
NOTE: This function assumes there are enough entries for the new memory map.
|
|
|
|
| | | | | | | |
|
|
| 4K PAGE | DATA | CODE | DATA | CODE | DATA | 4K PAGE |
|
|
| | | | | | | |
|
|
Assume the above memory region is the result of one split memory map descriptor. It's unlikely
|
|
that a linker will orient an image this way, but the caller must assume the worst case scenario.
|
|
This image layout example contains code sections oriented in a way that maximizes the number of
|
|
descriptors which would be required to describe each section. To ensure we have enough space
|
|
for every descriptor of the broken up memory map, the caller must assume that every image will
|
|
have the maximum number of code sections oriented in a way which maximizes the number of data
|
|
sections with unrelated memory regions flanking each image within a single descriptor.
|
|
|
|
Given an image record list, the caller should use the following formula when allocating extra descriptors:
|
|
NumberOfAdditionalDescriptors = (MemoryMapSize / DescriptorSize) +
|
|
((2 * <Most Code Segments in a Single Image> + 3) * <Number of Images>)
|
|
|
|
@param[in, out] MemoryMapSize IN: The size, in bytes, of the old memory map before the split.
|
|
OUT: The size, in bytes, of the used descriptors of the split
|
|
memory map
|
|
@param[in, out] MemoryMap IN: A pointer to the buffer containing the current memory map.
|
|
This buffer must have enough space to accomodate the "worst case"
|
|
scenario where every image in ImageRecordList needs a new descriptor
|
|
to describe its code and data sections.
|
|
OUT: A pointer to the updated memory map with separated image section
|
|
descriptors.
|
|
@param[in] DescriptorSize The size, in bytes, of an individual EFI_MEMORY_DESCRIPTOR.
|
|
@param[in] ImageRecordList A list of IMAGE_PROPERTIES_RECORD entries used when searching
|
|
for an image record contained by the memory range described in
|
|
EFI memory map descriptors.
|
|
@param[in] NumberOfAdditionalDescriptors The number of unused descriptors at the end of the input MemoryMap.
|
|
The formula in the description should be used to calculate this value.
|
|
|
|
@retval EFI_SUCCESS The memory map was successfully split.
|
|
@retval EFI_INVALID_PARAMETER MemoryMapSize, MemoryMap, or ImageRecordList was NULL.
|
|
**/
|
|
EFI_STATUS
|
|
EFIAPI
|
|
SplitTable (
|
|
IN OUT UINTN *MemoryMapSize,
|
|
IN OUT EFI_MEMORY_DESCRIPTOR *MemoryMap,
|
|
IN UINTN DescriptorSize,
|
|
IN LIST_ENTRY *ImageRecordList,
|
|
IN UINTN NumberOfAdditionalDescriptors
|
|
)
|
|
{
|
|
INTN IndexOld;
|
|
INTN IndexNew;
|
|
INTN IndexNewStarting;
|
|
UINTN MaxSplitRecordCount;
|
|
UINTN RealSplitRecordCount;
|
|
UINTN TotalSkippedRecords;
|
|
|
|
if ((MemoryMapSize == NULL) || (MemoryMap == NULL) || (ImageRecordList == NULL)) {
|
|
return EFI_INVALID_PARAMETER;
|
|
}
|
|
|
|
TotalSkippedRecords = 0;
|
|
//
|
|
// Let old record point to end of valid MemoryMap buffer.
|
|
//
|
|
IndexOld = ((*MemoryMapSize) / DescriptorSize) - 1;
|
|
//
|
|
// Let new record point to end of full MemoryMap buffer.
|
|
//
|
|
IndexNew = ((*MemoryMapSize) / DescriptorSize) - 1 + NumberOfAdditionalDescriptors;
|
|
IndexNewStarting = IndexNew;
|
|
for ( ; IndexOld >= 0; IndexOld--) {
|
|
MaxSplitRecordCount = GetMaxSplitRecordCount ((EFI_MEMORY_DESCRIPTOR *)((UINT8 *)MemoryMap + IndexOld * DescriptorSize), ImageRecordList);
|
|
//
|
|
// Split this MemoryMap record
|
|
//
|
|
IndexNew -= MaxSplitRecordCount;
|
|
RealSplitRecordCount = SplitRecord (
|
|
(EFI_MEMORY_DESCRIPTOR *)((UINT8 *)MemoryMap + IndexOld * DescriptorSize),
|
|
(EFI_MEMORY_DESCRIPTOR *)((UINT8 *)MemoryMap + IndexNew * DescriptorSize),
|
|
MaxSplitRecordCount,
|
|
DescriptorSize,
|
|
ImageRecordList
|
|
);
|
|
|
|
// If we didn't utilize all the extra allocated descriptor slots, set the physical address of the unused slots
|
|
// to MAX_ADDRESS so they are moved to the bottom of the list when sorting.
|
|
for ( ; RealSplitRecordCount < MaxSplitRecordCount; RealSplitRecordCount++) {
|
|
((EFI_MEMORY_DESCRIPTOR *)((UINT8 *)MemoryMap + ((IndexNew + RealSplitRecordCount + 1) * DescriptorSize)))->PhysicalStart = MAX_ADDRESS;
|
|
TotalSkippedRecords++;
|
|
}
|
|
|
|
IndexNew--;
|
|
}
|
|
|
|
//
|
|
// Move all records to the beginning.
|
|
//
|
|
CopyMem (
|
|
MemoryMap,
|
|
(UINT8 *)MemoryMap + ((IndexNew + 1) * DescriptorSize),
|
|
(IndexNewStarting - IndexNew) * DescriptorSize
|
|
);
|
|
|
|
//
|
|
// Sort from low to high to filter out the MAX_ADDRESS records.
|
|
//
|
|
SortMemoryMap (MemoryMap, (IndexNewStarting - IndexNew) * DescriptorSize, DescriptorSize);
|
|
|
|
*MemoryMapSize = (IndexNewStarting - IndexNew - TotalSkippedRecords) * DescriptorSize;
|
|
|
|
return EFI_SUCCESS;
|
|
}
|
|
|
|
/**
|
|
Swap two code sections in a single IMAGE_PROPERTIES_RECORD.
|
|
|
|
@param[in] FirstImageRecordCodeSection The first code section
|
|
@param[in] SecondImageRecordCodeSection The second code section
|
|
|
|
@retval EFI_SUCCESS The code sections were swapped successfully
|
|
@retval EFI_INVALID_PARAMETER FirstImageRecordCodeSection or SecondImageRecordCodeSection is NULL
|
|
**/
|
|
EFI_STATUS
|
|
EFIAPI
|
|
SwapImageRecordCodeSection (
|
|
IN IMAGE_PROPERTIES_RECORD_CODE_SECTION *FirstImageRecordCodeSection,
|
|
IN IMAGE_PROPERTIES_RECORD_CODE_SECTION *SecondImageRecordCodeSection
|
|
)
|
|
{
|
|
IMAGE_PROPERTIES_RECORD_CODE_SECTION TempImageRecordCodeSection;
|
|
|
|
if ((FirstImageRecordCodeSection == NULL) || (SecondImageRecordCodeSection == NULL)) {
|
|
return EFI_INVALID_PARAMETER;
|
|
}
|
|
|
|
TempImageRecordCodeSection.CodeSegmentBase = FirstImageRecordCodeSection->CodeSegmentBase;
|
|
TempImageRecordCodeSection.CodeSegmentSize = FirstImageRecordCodeSection->CodeSegmentSize;
|
|
|
|
FirstImageRecordCodeSection->CodeSegmentBase = SecondImageRecordCodeSection->CodeSegmentBase;
|
|
FirstImageRecordCodeSection->CodeSegmentSize = SecondImageRecordCodeSection->CodeSegmentSize;
|
|
|
|
SecondImageRecordCodeSection->CodeSegmentBase = TempImageRecordCodeSection.CodeSegmentBase;
|
|
SecondImageRecordCodeSection->CodeSegmentSize = TempImageRecordCodeSection.CodeSegmentSize;
|
|
|
|
return EFI_SUCCESS;
|
|
}
|
|
|
|
/**
|
|
Sort the code sections in the input ImageRecord based upon CodeSegmentBase from low to high.
|
|
|
|
@param[in] ImageRecord IMAGE_PROPERTIES_RECORD to be sorted
|
|
|
|
@retval EFI_SUCCESS The code sections in the input ImageRecord were sorted successfully
|
|
@retval EFI_ABORTED An error occurred while sorting the code sections in the input ImageRecord
|
|
@retval EFI_INVALID_PARAMETER ImageRecord is NULL
|
|
**/
|
|
EFI_STATUS
|
|
EFIAPI
|
|
SortImageRecordCodeSection (
|
|
IN IMAGE_PROPERTIES_RECORD *ImageRecord
|
|
)
|
|
{
|
|
EFI_STATUS Status;
|
|
IMAGE_PROPERTIES_RECORD_CODE_SECTION *ImageRecordCodeSection;
|
|
IMAGE_PROPERTIES_RECORD_CODE_SECTION *NextImageRecordCodeSection;
|
|
LIST_ENTRY *ImageRecordCodeSectionLink;
|
|
LIST_ENTRY *NextImageRecordCodeSectionLink;
|
|
LIST_ENTRY *ImageRecordCodeSectionEndLink;
|
|
LIST_ENTRY *ImageRecordCodeSectionList;
|
|
|
|
if (ImageRecord == NULL) {
|
|
return EFI_INVALID_PARAMETER;
|
|
}
|
|
|
|
ImageRecordCodeSectionList = &ImageRecord->CodeSegmentList;
|
|
|
|
ImageRecordCodeSectionLink = ImageRecordCodeSectionList->ForwardLink;
|
|
NextImageRecordCodeSectionLink = ImageRecordCodeSectionLink->ForwardLink;
|
|
ImageRecordCodeSectionEndLink = ImageRecordCodeSectionList;
|
|
while (ImageRecordCodeSectionLink != ImageRecordCodeSectionEndLink) {
|
|
ImageRecordCodeSection = CR (
|
|
ImageRecordCodeSectionLink,
|
|
IMAGE_PROPERTIES_RECORD_CODE_SECTION,
|
|
Link,
|
|
IMAGE_PROPERTIES_RECORD_CODE_SECTION_SIGNATURE
|
|
);
|
|
while (NextImageRecordCodeSectionLink != ImageRecordCodeSectionEndLink) {
|
|
NextImageRecordCodeSection = CR (
|
|
NextImageRecordCodeSectionLink,
|
|
IMAGE_PROPERTIES_RECORD_CODE_SECTION,
|
|
Link,
|
|
IMAGE_PROPERTIES_RECORD_CODE_SECTION_SIGNATURE
|
|
);
|
|
if (ImageRecordCodeSection->CodeSegmentBase > NextImageRecordCodeSection->CodeSegmentBase) {
|
|
Status = SwapImageRecordCodeSection (ImageRecordCodeSection, NextImageRecordCodeSection);
|
|
if (EFI_ERROR (Status)) {
|
|
ASSERT_EFI_ERROR (Status);
|
|
return EFI_ABORTED;
|
|
}
|
|
}
|
|
|
|
NextImageRecordCodeSectionLink = NextImageRecordCodeSectionLink->ForwardLink;
|
|
}
|
|
|
|
ImageRecordCodeSectionLink = ImageRecordCodeSectionLink->ForwardLink;
|
|
NextImageRecordCodeSectionLink = ImageRecordCodeSectionLink->ForwardLink;
|
|
}
|
|
|
|
return EFI_SUCCESS;
|
|
}
|
|
|
|
/**
|
|
Check if the code sections in the input ImageRecord are valid.
|
|
The code sections are valid if they don't overlap, are contained
|
|
within the the ImageRecord's ImageBase and ImageSize, and are
|
|
contained within the MAX_ADDRESS.
|
|
|
|
@param[in] ImageRecord IMAGE_PROPERTIES_RECORD to be checked
|
|
|
|
@retval TRUE The code sections in the input ImageRecord are valid
|
|
@retval FALSE The code sections in the input ImageRecord are invalid
|
|
**/
|
|
BOOLEAN
|
|
EFIAPI
|
|
IsImageRecordCodeSectionValid (
|
|
IN IMAGE_PROPERTIES_RECORD *ImageRecord
|
|
)
|
|
{
|
|
IMAGE_PROPERTIES_RECORD_CODE_SECTION *ImageRecordCodeSection;
|
|
IMAGE_PROPERTIES_RECORD_CODE_SECTION *LastImageRecordCodeSection;
|
|
LIST_ENTRY *ImageRecordCodeSectionLink;
|
|
LIST_ENTRY *ImageRecordCodeSectionEndLink;
|
|
LIST_ENTRY *ImageRecordCodeSectionList;
|
|
|
|
if (ImageRecord == NULL) {
|
|
return FALSE;
|
|
}
|
|
|
|
DEBUG ((DEBUG_VERBOSE, "ImageCode SegmentCount - 0x%x\n", ImageRecord->CodeSegmentCount));
|
|
|
|
ImageRecordCodeSectionList = &ImageRecord->CodeSegmentList;
|
|
|
|
ImageRecordCodeSectionLink = ImageRecordCodeSectionList->ForwardLink;
|
|
ImageRecordCodeSectionEndLink = ImageRecordCodeSectionList;
|
|
LastImageRecordCodeSection = NULL;
|
|
while (ImageRecordCodeSectionLink != ImageRecordCodeSectionEndLink) {
|
|
ImageRecordCodeSection = CR (
|
|
ImageRecordCodeSectionLink,
|
|
IMAGE_PROPERTIES_RECORD_CODE_SECTION,
|
|
Link,
|
|
IMAGE_PROPERTIES_RECORD_CODE_SECTION_SIGNATURE
|
|
);
|
|
if (ImageRecordCodeSection->CodeSegmentSize == 0) {
|
|
return FALSE;
|
|
}
|
|
|
|
if (ImageRecordCodeSection->CodeSegmentBase < ImageRecord->ImageBase) {
|
|
return FALSE;
|
|
}
|
|
|
|
if (ImageRecordCodeSection->CodeSegmentBase >= MAX_ADDRESS - ImageRecordCodeSection->CodeSegmentSize) {
|
|
return FALSE;
|
|
}
|
|
|
|
if ((ImageRecordCodeSection->CodeSegmentBase + ImageRecordCodeSection->CodeSegmentSize) > (ImageRecord->ImageBase + ImageRecord->ImageSize)) {
|
|
return FALSE;
|
|
}
|
|
|
|
if (LastImageRecordCodeSection != NULL) {
|
|
if ((LastImageRecordCodeSection->CodeSegmentBase + LastImageRecordCodeSection->CodeSegmentSize) > ImageRecordCodeSection->CodeSegmentBase) {
|
|
return FALSE;
|
|
}
|
|
}
|
|
|
|
LastImageRecordCodeSection = ImageRecordCodeSection;
|
|
ImageRecordCodeSectionLink = ImageRecordCodeSectionLink->ForwardLink;
|
|
}
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
/**
|
|
Swap two image records.
|
|
|
|
@param[in] FirstImageRecord The first image record.
|
|
@param[in] SecondImageRecord The second image record.
|
|
|
|
@retval EFI_SUCCESS The image records were swapped successfully
|
|
@retval EFI_INVALID_PARAMETER FirstImageRecord or SecondImageRecord is NULL
|
|
**/
|
|
EFI_STATUS
|
|
EFIAPI
|
|
SwapImageRecord (
|
|
IN IMAGE_PROPERTIES_RECORD *FirstImageRecord,
|
|
IN IMAGE_PROPERTIES_RECORD *SecondImageRecord
|
|
)
|
|
{
|
|
IMAGE_PROPERTIES_RECORD TempImageRecord;
|
|
|
|
if ((FirstImageRecord == NULL) || (SecondImageRecord == NULL)) {
|
|
return EFI_INVALID_PARAMETER;
|
|
}
|
|
|
|
TempImageRecord.ImageBase = FirstImageRecord->ImageBase;
|
|
TempImageRecord.ImageSize = FirstImageRecord->ImageSize;
|
|
TempImageRecord.CodeSegmentCount = FirstImageRecord->CodeSegmentCount;
|
|
|
|
FirstImageRecord->ImageBase = SecondImageRecord->ImageBase;
|
|
FirstImageRecord->ImageSize = SecondImageRecord->ImageSize;
|
|
FirstImageRecord->CodeSegmentCount = SecondImageRecord->CodeSegmentCount;
|
|
|
|
SecondImageRecord->ImageBase = TempImageRecord.ImageBase;
|
|
SecondImageRecord->ImageSize = TempImageRecord.ImageSize;
|
|
SecondImageRecord->CodeSegmentCount = TempImageRecord.CodeSegmentCount;
|
|
|
|
SwapListEntries (&FirstImageRecord->CodeSegmentList, &SecondImageRecord->CodeSegmentList);
|
|
return EFI_SUCCESS;
|
|
}
|
|
|
|
/**
|
|
Sort the input ImageRecordList based upon the ImageBase from low to high.
|
|
|
|
@param[in] ImageRecordList Image record list to be sorted
|
|
|
|
@retval EFI_SUCCESS The image record list was sorted successfully
|
|
@retval EFI_ABORTED An error occurred while sorting the image record list
|
|
@retval EFI_INVALID_PARAMETER ImageRecordList is NULL
|
|
**/
|
|
EFI_STATUS
|
|
EFIAPI
|
|
SortImageRecord (
|
|
IN LIST_ENTRY *ImageRecordList
|
|
)
|
|
{
|
|
IMAGE_PROPERTIES_RECORD *ImageRecord;
|
|
IMAGE_PROPERTIES_RECORD *NextImageRecord;
|
|
LIST_ENTRY *ImageRecordLink;
|
|
LIST_ENTRY *NextImageRecordLink;
|
|
LIST_ENTRY *ImageRecordEndLink;
|
|
EFI_STATUS Status;
|
|
|
|
if (ImageRecordList == NULL) {
|
|
return EFI_INVALID_PARAMETER;
|
|
}
|
|
|
|
ImageRecordLink = ImageRecordList->ForwardLink;
|
|
NextImageRecordLink = ImageRecordLink->ForwardLink;
|
|
ImageRecordEndLink = ImageRecordList;
|
|
while (ImageRecordLink != ImageRecordEndLink) {
|
|
ImageRecord = CR (
|
|
ImageRecordLink,
|
|
IMAGE_PROPERTIES_RECORD,
|
|
Link,
|
|
IMAGE_PROPERTIES_RECORD_SIGNATURE
|
|
);
|
|
while (NextImageRecordLink != ImageRecordEndLink) {
|
|
NextImageRecord = CR (
|
|
NextImageRecordLink,
|
|
IMAGE_PROPERTIES_RECORD,
|
|
Link,
|
|
IMAGE_PROPERTIES_RECORD_SIGNATURE
|
|
|
|
);
|
|
if (ImageRecord->ImageBase > NextImageRecord->ImageBase) {
|
|
Status = SwapImageRecord (ImageRecord, NextImageRecord);
|
|
if (EFI_ERROR (Status)) {
|
|
ASSERT_EFI_ERROR (Status);
|
|
return EFI_ABORTED;
|
|
}
|
|
}
|
|
|
|
NextImageRecordLink = NextImageRecordLink->ForwardLink;
|
|
}
|
|
|
|
ImageRecordLink = ImageRecordLink->ForwardLink;
|
|
NextImageRecordLink = ImageRecordLink->ForwardLink;
|
|
}
|
|
|
|
return EFI_SUCCESS;
|
|
}
|
|
|
|
/**
|
|
Extract the .efi filename out of the input PDB.
|
|
|
|
@param[in] PdbPointer Pointer to the PDB file path.
|
|
@param[out] EfiFileName Pointer to the .efi filename.
|
|
@param[in] EfiFileNameSize Size of the .efi filename buffer.
|
|
**/
|
|
STATIC
|
|
VOID
|
|
GetFilename (
|
|
IN CHAR8 *PdbPointer,
|
|
OUT CHAR8 *EfiFileName,
|
|
IN UINTN EfiFileNameSize
|
|
)
|
|
{
|
|
UINTN Index;
|
|
UINTN StartIndex;
|
|
|
|
if ((PdbPointer == NULL) || (EfiFileNameSize < 5)) {
|
|
return;
|
|
}
|
|
|
|
// Print Module Name by Pdb file path.
|
|
StartIndex = 0;
|
|
for (Index = 0; PdbPointer[Index] != 0; Index++) {
|
|
if ((PdbPointer[Index] == '\\') || (PdbPointer[Index] == '/')) {
|
|
StartIndex = Index + 1;
|
|
}
|
|
}
|
|
|
|
// Copy the PDB file name to EfiFileName and replace .pdb with .efi
|
|
for (Index = 0; Index < EfiFileNameSize - 4; Index++) {
|
|
EfiFileName[Index] = PdbPointer[Index + StartIndex];
|
|
if (EfiFileName[Index] == 0) {
|
|
EfiFileName[Index] = '.';
|
|
}
|
|
|
|
if (EfiFileName[Index] == '.') {
|
|
EfiFileName[Index + 1] = 'e';
|
|
EfiFileName[Index + 2] = 'f';
|
|
EfiFileName[Index + 3] = 'i';
|
|
EfiFileName[Index + 4] = 0;
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (Index == sizeof (EfiFileName) - 4) {
|
|
EfiFileName[Index] = 0;
|
|
}
|
|
}
|
|
|
|
/**
|
|
Debug dumps the input list of IMAGE_PROPERTIES_RECORD structs.
|
|
|
|
@param[in] ImageRecordList Head of the IMAGE_PROPERTIES_RECORD list
|
|
**/
|
|
VOID
|
|
EFIAPI
|
|
DumpImageRecords (
|
|
IN LIST_ENTRY *ImageRecordList
|
|
)
|
|
{
|
|
LIST_ENTRY *ImageRecordLink;
|
|
IMAGE_PROPERTIES_RECORD *CurrentImageRecord;
|
|
LIST_ENTRY *CodeSectionLink;
|
|
IMAGE_PROPERTIES_RECORD_CODE_SECTION *CurrentCodeSection;
|
|
CHAR8 *PdbPointer;
|
|
CHAR8 EfiFileName[256];
|
|
|
|
if (ImageRecordList == NULL) {
|
|
return;
|
|
}
|
|
|
|
ImageRecordLink = ImageRecordList->ForwardLink;
|
|
|
|
while (ImageRecordLink != ImageRecordList) {
|
|
CurrentImageRecord = CR (
|
|
ImageRecordLink,
|
|
IMAGE_PROPERTIES_RECORD,
|
|
Link,
|
|
IMAGE_PROPERTIES_RECORD_SIGNATURE
|
|
);
|
|
|
|
PdbPointer = PeCoffLoaderGetPdbPointer ((VOID *)(UINTN)CurrentImageRecord->ImageBase);
|
|
if (PdbPointer != NULL) {
|
|
GetFilename (PdbPointer, EfiFileName, sizeof (EfiFileName));
|
|
DEBUG ((
|
|
DEBUG_INFO,
|
|
"%a: 0x%llx - 0x%llx\n",
|
|
EfiFileName,
|
|
CurrentImageRecord->ImageBase,
|
|
CurrentImageRecord->ImageBase + CurrentImageRecord->ImageSize
|
|
));
|
|
} else {
|
|
DEBUG ((
|
|
DEBUG_INFO,
|
|
"Unknown Image: 0x%llx - 0x%llx\n",
|
|
CurrentImageRecord->ImageBase,
|
|
CurrentImageRecord->ImageBase + CurrentImageRecord->ImageSize
|
|
));
|
|
}
|
|
|
|
CodeSectionLink = CurrentImageRecord->CodeSegmentList.ForwardLink;
|
|
|
|
while (CodeSectionLink != &CurrentImageRecord->CodeSegmentList) {
|
|
CurrentCodeSection = CR (
|
|
CodeSectionLink,
|
|
IMAGE_PROPERTIES_RECORD_CODE_SECTION,
|
|
Link,
|
|
IMAGE_PROPERTIES_RECORD_CODE_SECTION_SIGNATURE
|
|
);
|
|
|
|
DEBUG ((
|
|
DEBUG_INFO,
|
|
" Code Section: 0x%llx - 0x%llx\n",
|
|
CurrentCodeSection->CodeSegmentBase,
|
|
CurrentCodeSection->CodeSegmentBase + CurrentCodeSection->CodeSegmentSize
|
|
));
|
|
|
|
CodeSectionLink = CodeSectionLink->ForwardLink;
|
|
}
|
|
|
|
ImageRecordLink = ImageRecordLink->ForwardLink;
|
|
}
|
|
}
|
|
|
|
/**
|
|
Find image record according to image base and size.
|
|
|
|
@param[in] ImageBase Base of PE image
|
|
@param[in] ImageSize Size of PE image
|
|
@param[in] ImageRecordList Image record list to be searched
|
|
|
|
@retval NULL No IMAGE_PROPERTIES_RECORD matches ImageBase
|
|
and ImageSize in the input ImageRecordList
|
|
@retval Other The found IMAGE_PROPERTIES_RECORD
|
|
**/
|
|
IMAGE_PROPERTIES_RECORD *
|
|
EFIAPI
|
|
FindImageRecord (
|
|
IN EFI_PHYSICAL_ADDRESS ImageBase,
|
|
IN UINT64 ImageSize,
|
|
IN LIST_ENTRY *ImageRecordList
|
|
)
|
|
{
|
|
IMAGE_PROPERTIES_RECORD *ImageRecord;
|
|
LIST_ENTRY *ImageRecordLink;
|
|
|
|
if (ImageRecordList == NULL) {
|
|
return NULL;
|
|
}
|
|
|
|
for (ImageRecordLink = ImageRecordList->ForwardLink;
|
|
ImageRecordLink != ImageRecordList;
|
|
ImageRecordLink = ImageRecordLink->ForwardLink)
|
|
{
|
|
ImageRecord = CR (
|
|
ImageRecordLink,
|
|
IMAGE_PROPERTIES_RECORD,
|
|
Link,
|
|
IMAGE_PROPERTIES_RECORD_SIGNATURE
|
|
);
|
|
|
|
if ((ImageBase == ImageRecord->ImageBase) &&
|
|
(ImageSize == ImageRecord->ImageSize))
|
|
{
|
|
return ImageRecord;
|
|
}
|
|
}
|
|
|
|
return NULL;
|
|
}
|
|
|
|
/**
|
|
Creates an IMAGE_PROPERTIES_RECORD from a loaded PE image. The PE/COFF header will be found
|
|
and parsed to determine the number of code segments and their base addresses and sizes.
|
|
|
|
@param[in] ImageBase Base of the PE image
|
|
@param[in] ImageSize Size of the PE image
|
|
@param[in] RequiredAlignment If non-NULL, the alignment specified in the PE/COFF header
|
|
will be compared against this value.
|
|
@param[out] ImageRecord On out, a populated image properties record
|
|
|
|
@retval EFI_INVALID_PARAMETER This function ImageBase or ImageRecord was NULL, or the
|
|
image located at ImageBase was not a valid PE/COFF image
|
|
@retval EFI_OUT_OF_RESOURCES Failure to Allocate()
|
|
@retval EFI_ABORTED The input Alignment was non-NULL and did not match the
|
|
alignment specified in the PE/COFF header
|
|
@retval EFI_SUCCESS The image properties record was successfully created
|
|
**/
|
|
EFI_STATUS
|
|
EFIAPI
|
|
CreateImagePropertiesRecord (
|
|
IN CONST VOID *ImageBase,
|
|
IN CONST UINT64 ImageSize,
|
|
IN CONST UINT32 *RequiredAlignment OPTIONAL,
|
|
OUT IMAGE_PROPERTIES_RECORD *ImageRecord
|
|
)
|
|
{
|
|
EFI_STATUS Status;
|
|
EFI_IMAGE_DOS_HEADER *DosHdr;
|
|
EFI_IMAGE_OPTIONAL_HEADER_PTR_UNION Hdr;
|
|
EFI_IMAGE_SECTION_HEADER *Section;
|
|
IMAGE_PROPERTIES_RECORD_CODE_SECTION *ImageRecordCodeSection;
|
|
UINTN Index;
|
|
UINT8 *Name;
|
|
UINT32 SectionAlignment;
|
|
UINT32 PeCoffHeaderOffset;
|
|
|
|
if ((ImageRecord == NULL) || (ImageBase == NULL)) {
|
|
return EFI_INVALID_PARAMETER;
|
|
}
|
|
|
|
DEBUG ((
|
|
DEBUG_VERBOSE,
|
|
"Creating Image Properties Record: 0x%016lx - 0x%016lx\n",
|
|
(EFI_PHYSICAL_ADDRESS)(UINTN)ImageBase,
|
|
ImageSize
|
|
));
|
|
|
|
//
|
|
// Step 1: record whole region
|
|
//
|
|
Status = EFI_SUCCESS;
|
|
ImageRecord->Signature = IMAGE_PROPERTIES_RECORD_SIGNATURE;
|
|
ImageRecord->ImageBase = (EFI_PHYSICAL_ADDRESS)(UINTN)ImageBase;
|
|
ImageRecord->ImageSize = ImageSize;
|
|
ImageRecord->CodeSegmentCount = 0;
|
|
InitializeListHead (&ImageRecord->Link);
|
|
InitializeListHead (&ImageRecord->CodeSegmentList);
|
|
|
|
// Check PE/COFF image
|
|
DosHdr = (EFI_IMAGE_DOS_HEADER *)(UINTN)ImageBase;
|
|
PeCoffHeaderOffset = 0;
|
|
if (DosHdr->e_magic == EFI_IMAGE_DOS_SIGNATURE) {
|
|
PeCoffHeaderOffset = DosHdr->e_lfanew;
|
|
}
|
|
|
|
Hdr.Pe32 = (EFI_IMAGE_NT_HEADERS32 *)((UINT8 *)(UINTN)ImageBase + PeCoffHeaderOffset);
|
|
if (Hdr.Pe32->Signature != EFI_IMAGE_NT_SIGNATURE) {
|
|
DEBUG ((DEBUG_VERBOSE, "Hdr.Pe32->Signature invalid - 0x%x\n", Hdr.Pe32->Signature));
|
|
return EFI_INVALID_PARAMETER;
|
|
}
|
|
|
|
// Get SectionAlignment
|
|
if (Hdr.Pe32->OptionalHeader.Magic == EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC) {
|
|
SectionAlignment = Hdr.Pe32->OptionalHeader.SectionAlignment;
|
|
} else {
|
|
SectionAlignment = Hdr.Pe32Plus->OptionalHeader.SectionAlignment;
|
|
}
|
|
|
|
// Check RequiredAlignment
|
|
if ((RequiredAlignment != NULL) && ((SectionAlignment & (*RequiredAlignment - 1)) != 0)) {
|
|
DEBUG ((
|
|
DEBUG_WARN,
|
|
"!!!!!!!! Image Section Alignment(0x%x) does not match Required Alignment (0x%x) !!!!!!!!\n",
|
|
SectionAlignment,
|
|
*RequiredAlignment
|
|
));
|
|
|
|
return EFI_ABORTED;
|
|
}
|
|
|
|
Section = (EFI_IMAGE_SECTION_HEADER *)(
|
|
(UINT8 *)(UINTN)ImageBase +
|
|
PeCoffHeaderOffset +
|
|
sizeof (UINT32) +
|
|
sizeof (EFI_IMAGE_FILE_HEADER) +
|
|
Hdr.Pe32->FileHeader.SizeOfOptionalHeader
|
|
);
|
|
for (Index = 0; Index < Hdr.Pe32->FileHeader.NumberOfSections; Index++) {
|
|
Name = Section[Index].Name;
|
|
DEBUG ((
|
|
DEBUG_VERBOSE,
|
|
" Section - '%c%c%c%c%c%c%c%c'\n",
|
|
Name[0],
|
|
Name[1],
|
|
Name[2],
|
|
Name[3],
|
|
Name[4],
|
|
Name[5],
|
|
Name[6],
|
|
Name[7]
|
|
));
|
|
|
|
if ((Section[Index].Characteristics & EFI_IMAGE_SCN_CNT_CODE) != 0) {
|
|
DEBUG ((DEBUG_VERBOSE, " VirtualSize - 0x%08x\n", Section[Index].Misc.VirtualSize));
|
|
DEBUG ((DEBUG_VERBOSE, " VirtualAddress - 0x%08x\n", Section[Index].VirtualAddress));
|
|
DEBUG ((DEBUG_VERBOSE, " SizeOfRawData - 0x%08x\n", Section[Index].SizeOfRawData));
|
|
DEBUG ((DEBUG_VERBOSE, " PointerToRawData - 0x%08x\n", Section[Index].PointerToRawData));
|
|
DEBUG ((DEBUG_VERBOSE, " PointerToRelocations - 0x%08x\n", Section[Index].PointerToRelocations));
|
|
DEBUG ((DEBUG_VERBOSE, " PointerToLinenumbers - 0x%08x\n", Section[Index].PointerToLinenumbers));
|
|
DEBUG ((DEBUG_VERBOSE, " NumberOfRelocations - 0x%08x\n", Section[Index].NumberOfRelocations));
|
|
DEBUG ((DEBUG_VERBOSE, " NumberOfLinenumbers - 0x%08x\n", Section[Index].NumberOfLinenumbers));
|
|
DEBUG ((DEBUG_VERBOSE, " Characteristics - 0x%08x\n", Section[Index].Characteristics));
|
|
|
|
// Record code section(s)
|
|
ImageRecordCodeSection = AllocatePool (sizeof (*ImageRecordCodeSection));
|
|
if (ImageRecordCodeSection == NULL) {
|
|
return EFI_OUT_OF_RESOURCES;
|
|
}
|
|
|
|
ImageRecordCodeSection->Signature = IMAGE_PROPERTIES_RECORD_CODE_SECTION_SIGNATURE;
|
|
|
|
ImageRecordCodeSection->CodeSegmentBase = (UINTN)ImageBase + Section[Index].VirtualAddress;
|
|
ImageRecordCodeSection->CodeSegmentSize = Section[Index].SizeOfRawData;
|
|
|
|
InsertTailList (&ImageRecord->CodeSegmentList, &ImageRecordCodeSection->Link);
|
|
ImageRecord->CodeSegmentCount++;
|
|
}
|
|
}
|
|
|
|
if (ImageRecord->CodeSegmentCount > 0) {
|
|
SortImageRecordCodeSection (ImageRecord);
|
|
}
|
|
|
|
return Status;
|
|
}
|
|
|
|
/**
|
|
Deleted an image properties record. The function will also call
|
|
RemoveEntryList() on each code segment and the input ImageRecord before
|
|
freeing each pool.
|
|
|
|
@param[in] ImageRecord The IMAGE_PROPERTIES_RECORD to delete
|
|
**/
|
|
VOID
|
|
EFIAPI
|
|
DeleteImagePropertiesRecord (
|
|
IN IMAGE_PROPERTIES_RECORD *ImageRecord
|
|
)
|
|
{
|
|
LIST_ENTRY *CodeSegmentListHead;
|
|
IMAGE_PROPERTIES_RECORD_CODE_SECTION *ImageRecordCodeSection;
|
|
|
|
if (ImageRecord == NULL) {
|
|
return;
|
|
}
|
|
|
|
CodeSegmentListHead = &ImageRecord->CodeSegmentList;
|
|
while (!IsListEmpty (CodeSegmentListHead)) {
|
|
ImageRecordCodeSection = CR (
|
|
CodeSegmentListHead->ForwardLink,
|
|
IMAGE_PROPERTIES_RECORD_CODE_SECTION,
|
|
Link,
|
|
IMAGE_PROPERTIES_RECORD_CODE_SECTION_SIGNATURE
|
|
);
|
|
RemoveEntryList (&ImageRecordCodeSection->Link);
|
|
FreePool (ImageRecordCodeSection);
|
|
}
|
|
|
|
if (!IsListEmpty (&ImageRecord->Link)) {
|
|
RemoveEntryList (&ImageRecord->Link);
|
|
}
|
|
|
|
FreePool (ImageRecord);
|
|
}
|