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