diff options
| author | kx <kx@radix.pro> | 2024-06-04 06:43:08 +0300 |
|---|---|---|
| committer | kx <kx@radix.pro> | 2024-06-04 06:43:08 +0300 |
| commit | 7e2ccccace24636f29ddc210b94606abd4c7e42b (patch) | |
| tree | 545d43ea12671048956cafeb12303e84d601e571 /MdeModulePkg/Library/ImagePropertiesRecordLib/ImagePropertiesRecordLib.c | |
| parent | 27b044605cd5f6b33a3d231576003850b3fe305b (diff) | |
| download | edk2-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.c | 2380 |
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); +} |
