summaryrefslogtreecommitdiff
path: root/MdeModulePkg/Library/ImagePropertiesRecordLib/ImagePropertiesRecordLib.c
diff options
context:
space:
mode:
authorkx <kx@radix.pro>2024-06-04 06:43:08 +0300
committerkx <kx@radix.pro>2024-06-04 06:43:08 +0300
commit7e2ccccace24636f29ddc210b94606abd4c7e42b (patch)
tree545d43ea12671048956cafeb12303e84d601e571 /MdeModulePkg/Library/ImagePropertiesRecordLib/ImagePropertiesRecordLib.c
parent27b044605cd5f6b33a3d231576003850b3fe305b (diff)
downloadedk2-trunk.tar.xz
Renormalized end-of-lines from master@27b044605cd5f6b33a3d231576003850b3fe305btrunk
Diffstat (limited to 'MdeModulePkg/Library/ImagePropertiesRecordLib/ImagePropertiesRecordLib.c')
-rw-r--r--MdeModulePkg/Library/ImagePropertiesRecordLib/ImagePropertiesRecordLib.c2380
1 files changed, 1190 insertions, 1190 deletions
diff --git a/MdeModulePkg/Library/ImagePropertiesRecordLib/ImagePropertiesRecordLib.c b/MdeModulePkg/Library/ImagePropertiesRecordLib/ImagePropertiesRecordLib.c
index 3ac043f980..1fd095a542 100644
--- a/MdeModulePkg/Library/ImagePropertiesRecordLib/ImagePropertiesRecordLib.c
+++ b/MdeModulePkg/Library/ImagePropertiesRecordLib/ImagePropertiesRecordLib.c
@@ -1,1190 +1,1190 @@
-/** @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);
-}
-
-/**
- Frees the memory for each ImageRecordCodeSection within an ImageRecord
- and removes the entries from the list. It does not free the ImageRecord
- itself.
-
- @param[in] ImageRecord The ImageRecord in which to free code sections
-**/
-STATIC
-VOID
-FreeImageRecordCodeSections (
- 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);
- }
-}
-
-/**
- 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;
- CHAR8 *PdbPointer;
-
- 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);
-
- PdbPointer = PeCoffLoaderGetPdbPointer ((VOID *)(UINTN)ImageBase);
- if (PdbPointer != NULL) {
- DEBUG ((DEBUG_ERROR, " Image - %a\n", PdbPointer));
- }
-
- // 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) {
- Status = EFI_OUT_OF_RESOURCES;
- goto CreateImagePropertiesRecordEnd;
- }
-
- ImageRecordCodeSection->Signature = IMAGE_PROPERTIES_RECORD_CODE_SECTION_SIGNATURE;
-
- ImageRecordCodeSection->CodeSegmentBase = (UINTN)ImageBase + Section[Index].VirtualAddress;
- // We still need to align the VirtualSize to the SectionAlignment because MSVC does not do
- // this when creating a PE image. It expects the loader to do this.
- ImageRecordCodeSection->CodeSegmentSize = ALIGN_VALUE (Section[Index].Misc.VirtualSize, SectionAlignment);
-
- InsertTailList (&ImageRecord->CodeSegmentList, &ImageRecordCodeSection->Link);
- ImageRecord->CodeSegmentCount++;
- }
- }
-
- if (ImageRecord->CodeSegmentCount > 0) {
- SortImageRecordCodeSection (ImageRecord);
- }
-
- //
- // Check overlap all section in ImageBase/Size
- //
- if (!IsImageRecordCodeSectionValid (ImageRecord)) {
- DEBUG ((DEBUG_ERROR, "IsImageRecordCodeSectionValid - FAIL\n"));
- Status = EFI_INVALID_PARAMETER;
- goto CreateImagePropertiesRecordEnd;
- }
-
- //
- // Round up the ImageSize, some CPU arch may return EFI_UNSUPPORTED if ImageSize is not aligned.
- // Given that the loader always allocates full pages, we know the space after the image is not used.
- //
- ImageRecord->ImageSize = ALIGN_VALUE (ImageRecord->ImageSize, EFI_PAGE_SIZE);
-
-CreateImagePropertiesRecordEnd:
- if (EFI_ERROR (Status)) {
- // we failed to create a valid record, free the section memory that was allocated
- FreeImageRecordCodeSections (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
- )
-{
- FreeImageRecordCodeSections (ImageRecord);
-
- if (!IsListEmpty (&ImageRecord->Link)) {
- RemoveEntryList (&ImageRecord->Link);
- }
-
- FreePool (ImageRecord);
-}
+/** @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);
+}
+
+/**
+ Frees the memory for each ImageRecordCodeSection within an ImageRecord
+ and removes the entries from the list. It does not free the ImageRecord
+ itself.
+
+ @param[in] ImageRecord The ImageRecord in which to free code sections
+**/
+STATIC
+VOID
+FreeImageRecordCodeSections (
+ 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);
+ }
+}
+
+/**
+ 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;
+ CHAR8 *PdbPointer;
+
+ 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);
+
+ PdbPointer = PeCoffLoaderGetPdbPointer ((VOID *)(UINTN)ImageBase);
+ if (PdbPointer != NULL) {
+ DEBUG ((DEBUG_ERROR, " Image - %a\n", PdbPointer));
+ }
+
+ // 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) {
+ Status = EFI_OUT_OF_RESOURCES;
+ goto CreateImagePropertiesRecordEnd;
+ }
+
+ ImageRecordCodeSection->Signature = IMAGE_PROPERTIES_RECORD_CODE_SECTION_SIGNATURE;
+
+ ImageRecordCodeSection->CodeSegmentBase = (UINTN)ImageBase + Section[Index].VirtualAddress;
+ // We still need to align the VirtualSize to the SectionAlignment because MSVC does not do
+ // this when creating a PE image. It expects the loader to do this.
+ ImageRecordCodeSection->CodeSegmentSize = ALIGN_VALUE (Section[Index].Misc.VirtualSize, SectionAlignment);
+
+ InsertTailList (&ImageRecord->CodeSegmentList, &ImageRecordCodeSection->Link);
+ ImageRecord->CodeSegmentCount++;
+ }
+ }
+
+ if (ImageRecord->CodeSegmentCount > 0) {
+ SortImageRecordCodeSection (ImageRecord);
+ }
+
+ //
+ // Check overlap all section in ImageBase/Size
+ //
+ if (!IsImageRecordCodeSectionValid (ImageRecord)) {
+ DEBUG ((DEBUG_ERROR, "IsImageRecordCodeSectionValid - FAIL\n"));
+ Status = EFI_INVALID_PARAMETER;
+ goto CreateImagePropertiesRecordEnd;
+ }
+
+ //
+ // Round up the ImageSize, some CPU arch may return EFI_UNSUPPORTED if ImageSize is not aligned.
+ // Given that the loader always allocates full pages, we know the space after the image is not used.
+ //
+ ImageRecord->ImageSize = ALIGN_VALUE (ImageRecord->ImageSize, EFI_PAGE_SIZE);
+
+CreateImagePropertiesRecordEnd:
+ if (EFI_ERROR (Status)) {
+ // we failed to create a valid record, free the section memory that was allocated
+ FreeImageRecordCodeSections (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
+ )
+{
+ FreeImageRecordCodeSections (ImageRecord);
+
+ if (!IsListEmpty (&ImageRecord->Link)) {
+ RemoveEntryList (&ImageRecord->Link);
+ }
+
+ FreePool (ImageRecord);
+}