Create a library for manipulating image properties records. Image
properties record logic is already present in both the SMM and
UEFI MAT logic, and this is a copy of the UEFI MAT logic with added
function arguments to remove dependencies on global variables.

Signed-off-by: Taylor Beebe <t...@taylorbeebe.com>
Cc: Jian J Wang <jian.j.w...@intel.com>
Cc: Liming Gao <gaolim...@byosoft.com.cn>
Cc: Dandan Bi <dandan...@intel.com>
---
 MdeModulePkg/Library/ImagePropertiesRecordLib/ImagePropertiesRecordLib.c   | 
807 ++++++++++++++++++++
 MdeModulePkg/Include/Library/ImagePropertiesRecordLib.h                    | 
151 ++++
 MdeModulePkg/Library/ImagePropertiesRecordLib/ImagePropertiesRecordLib.inf |  
28 +
 MdeModulePkg/MdeModulePkg.dec                                              |   
5 +
 MdeModulePkg/MdeModulePkg.dsc                                              |   
2 +
 5 files changed, 993 insertions(+)

diff --git 
a/MdeModulePkg/Library/ImagePropertiesRecordLib/ImagePropertiesRecordLib.c 
b/MdeModulePkg/Library/ImagePropertiesRecordLib/ImagePropertiesRecordLib.c
new file mode 100644
index 000000000000..46f4f401a4d5
--- /dev/null
+++ b/MdeModulePkg/Library/ImagePropertiesRecordLib/ImagePropertiesRecordLib.c
@@ -0,0 +1,807 @@
+/** @file
+
+  Provides definitions and functionality for manipulating Image Properties 
Records.
+
+  Copyright (c) 2016 - 2018, Intel Corporation. All rights reserved.<BR>
+  SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include <PiDxe.h>
+
+#include <Library/BaseLib.h>
+#include <Library/BaseMemoryLib.h>
+#include <Library/DebugLib.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 EFI_PAGEs to a size in bytes.
+
+  NOTE: Do not use EFI_PAGES_TO_SIZE because it handles UINTN only.
+
+  @param  Pages     The number of EFI_PAGES.
+
+  @return  The number of bytes associated with the number of EFI_PAGEs 
specified
+           by 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  Size      A size in bytes.
+
+  @return  The number of EFI_PAGESs associated with the number of bytes 
specified
+           by Size.
+
+**/
+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  MemoryMap              A pointer to the buffer in which firmware 
places
+                                 the current memory map.
+  @param  MemoryMapSize          Size, in bytes, of the MemoryMap buffer.
+  @param  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;
+}
+
+/**
+  Swap two code sections in image record.
+
+  @param  FirstImageRecordCodeSection    first code section in image record
+  @param  SecondImageRecordCodeSection   second code section in image record
+**/
+STATIC
+VOID
+SwapImageRecordCodeSection (
+  IN IMAGE_PROPERTIES_RECORD_CODE_SECTION  *FirstImageRecordCodeSection,
+  IN IMAGE_PROPERTIES_RECORD_CODE_SECTION  *SecondImageRecordCodeSection
+  )
+{
+  IMAGE_PROPERTIES_RECORD_CODE_SECTION  TempImageRecordCodeSection;
+
+  TempImageRecordCodeSection.CodeSegmentBase = 
FirstImageRecordCodeSection->CodeSegmentBase;
+  TempImageRecordCodeSection.CodeSegmentSize = 
FirstImageRecordCodeSection->CodeSegmentSize;
+
+  FirstImageRecordCodeSection->CodeSegmentBase = 
SecondImageRecordCodeSection->CodeSegmentBase;
+  FirstImageRecordCodeSection->CodeSegmentSize = 
SecondImageRecordCodeSection->CodeSegmentSize;
+
+  SecondImageRecordCodeSection->CodeSegmentBase = 
TempImageRecordCodeSection.CodeSegmentBase;
+  SecondImageRecordCodeSection->CodeSegmentSize = 
TempImageRecordCodeSection.CodeSegmentSize;
+}
+
+/**
+  Check if code section in image record is valid.
+
+  @param  ImageRecord    image record to be checked
+
+  @retval TRUE  image record is valid
+  @retval FALSE image record is 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;
+
+  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  FirstImageRecord   first image record.
+  @param  SecondImageRecord  second image record.
+**/
+STATIC
+VOID
+SwapImageRecord (
+  IN IMAGE_PROPERTIES_RECORD  *FirstImageRecord,
+  IN IMAGE_PROPERTIES_RECORD  *SecondImageRecord
+  )
+{
+  IMAGE_PROPERTIES_RECORD  TempImageRecord;
+
+  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);
+}
+
+/**
+  Sort code section in image record, based upon CodeSegmentBase from low to 
high.
+
+  @param  ImageRecord    image record to be sorted
+**/
+VOID
+EFIAPI
+SortImageRecordCodeSection (
+  IN IMAGE_PROPERTIES_RECORD  *ImageRecord
+  )
+{
+  IMAGE_PROPERTIES_RECORD_CODE_SECTION  *ImageRecordCodeSection;
+  IMAGE_PROPERTIES_RECORD_CODE_SECTION  *NextImageRecordCodeSection;
+  LIST_ENTRY                            *ImageRecordCodeSectionLink;
+  LIST_ENTRY                            *NextImageRecordCodeSectionLink;
+  LIST_ENTRY                            *ImageRecordCodeSectionEndLink;
+  LIST_ENTRY                            *ImageRecordCodeSectionList;
+
+  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) {
+        SwapImageRecordCodeSection (ImageRecordCodeSection, 
NextImageRecordCodeSection);
+      }
+
+      NextImageRecordCodeSectionLink = 
NextImageRecordCodeSectionLink->ForwardLink;
+    }
+
+    ImageRecordCodeSectionLink     = ImageRecordCodeSectionLink->ForwardLink;
+    NextImageRecordCodeSectionLink = ImageRecordCodeSectionLink->ForwardLink;
+  }
+}
+
+/**
+  Dump image record.
+
+  @param[in]  ImageRecordList  A list of IMAGE_PROPERTIES_RECORD entries
+**/
+VOID
+EFIAPI
+DumpImageRecord (
+  IN LIST_ENTRY  *ImageRecordList
+  )
+{
+  IMAGE_PROPERTIES_RECORD  *ImageRecord;
+  LIST_ENTRY               *ImageRecordLink;
+  UINTN                    Index;
+
+  for (ImageRecordLink = ImageRecordList->ForwardLink, Index = 0;
+       ImageRecordLink != ImageRecordList;
+       ImageRecordLink = ImageRecordLink->ForwardLink, Index++)
+  {
+    ImageRecord = CR (
+                    ImageRecordLink,
+                    IMAGE_PROPERTIES_RECORD,
+                    Link,
+                    IMAGE_PROPERTIES_RECORD_SIGNATURE
+                    );
+    DEBUG ((DEBUG_VERBOSE, "Image[%d]: 0x%016lx - 0x%016lx\n", Index, 
ImageRecord->ImageBase, ImageRecord->ImageSize));
+  }
+}
+
+/**
+  Sort image record based upon the ImageBase from low to high.
+
+  @param[in] ImageRecordList  A list of IMAGE_PROPERTIES_RECORD entries
+**/
+VOID
+EFIAPI
+SortImageRecord (
+  IN LIST_ENTRY  *ImageRecordList
+  )
+{
+  IMAGE_PROPERTIES_RECORD  *ImageRecord;
+  IMAGE_PROPERTIES_RECORD  *NextImageRecord;
+  LIST_ENTRY               *ImageRecordLink;
+  LIST_ENTRY               *NextImageRecordLink;
+  LIST_ENTRY               *ImageRecordEndLink;
+
+  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) {
+        SwapImageRecord (ImageRecord, NextImageRecord);
+      }
+
+      NextImageRecordLink = NextImageRecordLink->ForwardLink;
+    }
+
+    ImageRecordLink     = ImageRecordLink->ForwardLink;
+    NextImageRecordLink = ImageRecordLink->ForwardLink;
+  }
+}
+
+/**
+  Return the first image record, whose [ImageBase, ImageSize] covered by 
[Buffer, Length].
+
+  @param[in] Buffer           Start Address
+  @param[in] Length           Address length
+  @param[in] ImageRecordList  A list of IMAGE_PROPERTIES_RECORD entries to 
check against
+                              the memory range Buffer -> Buffer + Length
+
+  @return 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;
+}
+
+/**
+  Set the memory map to new entries, according to one old entry,
+  based upon PE code section and data section in image record
+
+  @param  ImageRecord            An image record whose [ImageBase, ImageSize] 
covered
+                                 by old memory map entry.
+  @param  NewRecord              A pointer to several new memory map entries.
+                                 The caller gurantee the buffer size be 1 +
+                                 (SplitRecordCount * DescriptorSize) calculated
+                                 below.
+  @param  OldRecord              A pointer to one old memory map entry.
+  @param  DescriptorSize         Size, in bytes, of an individual 
EFI_MEMORY_DESCRIPTOR.
+**/
+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 max number of new splitted entries, according to one old entry,
+  based upon PE code section and data section.
+
+  @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 in
+                                the existing EFI memory map descriptor 
OldRecord
+
+  @retval  0 no entry need to be splitted.
+  @return  the max number of new splitted entries
+**/
+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 + 1);
+    PhysicalStart     = ImageRecord->ImageBase + ImageRecord->ImageSize;
+  } while ((ImageRecord != NULL) && (PhysicalStart < PhysicalEnd));
+
+  if (SplitRecordCount != 0) {
+    SplitRecordCount--;
+  }
+
+  return SplitRecordCount;
+}
+
+/**
+  Split the memory map to new entries, according to one old entry,
+  based upon PE code section and data section.
+
+  @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 1 +
+                                          (SplitRecordCount * DescriptorSize) 
calculated
+                                          below.
+  @param[in]        MaxSplitRecordCount   The max number of splitted entries
+  @param[in]        DescriptorSize        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  0 no entry is splitted.
+  @return  the real number of splitted record.
+**/
+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;
+  BOOLEAN                  IsLastRecordData;
+
+  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 image covered by this range, stop
+      //
+      if ((PhysicalEnd > PhysicalStart) && (ImageRecord != NULL)) {
+        //
+        // If this is still address in this record, need record.
+        //
+        NewRecord        = PREVIOUS_MEMORY_DESCRIPTOR (NewRecord, 
DescriptorSize);
+        IsLastRecordData = FALSE;
+        if ((NewRecord->Attribute & EFI_MEMORY_XP) != 0) {
+          IsLastRecordData = TRUE;
+        }
+
+        if (IsLastRecordData) {
+          //
+          // Last record is DATA, just merge it.
+          //
+          NewRecord->NumberOfPages = EfiSizeToPages (PhysicalEnd - 
NewRecord->PhysicalStart);
+        } else {
+          //
+          // Last record is CODE, create a new DATA entry.
+          //
+          NewRecord                = NEXT_MEMORY_DESCRIPTOR (NewRecord, 
DescriptorSize);
+          NewRecord->Type          = TempRecord.Type;
+          NewRecord->PhysicalStart = TempRecord.PhysicalStart;
+          NewRecord->VirtualStart  = 0;
+          NewRecord->NumberOfPages = TempRecord.NumberOfPages;
+          NewRecord->Attribute     = TempRecord.Attribute | EFI_MEMORY_XP;
+          TotalNewRecordCount++;
+        }
+      }
+
+      break;
+    }
+
+    ImageRecord = NewImageRecord;
+
+    //
+    // 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 
section and data section.
+  This function will set EfiRuntimeServicesData to be EFI_MEMORY_XP.
+  This function will merge entries with same attributes finally.
+
+  NOTE: It assumes PE code/data section are page aligned.
+  NOTE: It assumes enough entry is prepared for new memory map.
+
+  Split table:
+   +---------------+
+   | Record X      |
+   +---------------+
+   | Record RtCode |
+   +---------------+
+   | Record Y      |
+   +---------------+
+   ==>
+   +---------------+
+   | Record X      |
+   +---------------+ ----
+   | Record RtData |     |
+   +---------------+     |
+   | Record RtCode |     |-> PE/COFF1
+   +---------------+     |
+   | Record RtData |     |
+   +---------------+ ----
+   | Record RtData |     |
+   +---------------+     |
+   | Record RtCode |     |-> PE/COFF2
+   +---------------+     |
+   | Record RtData |     |
+   +---------------+ ----
+   | Record Y      |
+   +---------------+
+
+  @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.
+**/
+VOID
+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;
+  UINTN  MaxSplitRecordCount;
+  UINTN  RealSplitRecordCount;
+  UINTN  TotalSplitRecordCount;
+
+  TotalSplitRecordCount = 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;
+  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
+                             );
+    //
+    // Adjust IndexNew according to real split.
+    //
+    CopyMem (
+      ((UINT8 *)MemoryMap + (IndexNew + MaxSplitRecordCount - 
RealSplitRecordCount) * DescriptorSize),
+      ((UINT8 *)MemoryMap + IndexNew * DescriptorSize),
+      RealSplitRecordCount * DescriptorSize
+      );
+    IndexNew               = IndexNew + MaxSplitRecordCount - 
RealSplitRecordCount;
+    TotalSplitRecordCount += RealSplitRecordCount;
+    IndexNew--;
+  }
+
+  //
+  // Move all records to the beginning.
+  //
+  CopyMem (
+    MemoryMap,
+    (UINT8 *)MemoryMap + (NumberOfAdditionalDescriptors - 
TotalSplitRecordCount) * DescriptorSize,
+    (*MemoryMapSize) + TotalSplitRecordCount * DescriptorSize
+    );
+
+  *MemoryMapSize = (*MemoryMapSize) + DescriptorSize * TotalSplitRecordCount;
+
+  //
+  // Sort from low to high (Just in case)
+  //
+  SortMemoryMap (MemoryMap, *MemoryMapSize, DescriptorSize);
+
+  return;
+}
+
+/**
+  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  A list of IMAGE_PROPERTIES_RECORD entries
+
+  @return image 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;
+
+  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;
+}
diff --git a/MdeModulePkg/Include/Library/ImagePropertiesRecordLib.h 
b/MdeModulePkg/Include/Library/ImagePropertiesRecordLib.h
new file mode 100644
index 000000000000..64bbf572d596
--- /dev/null
+++ b/MdeModulePkg/Include/Library/ImagePropertiesRecordLib.h
@@ -0,0 +1,151 @@
+/** @file
+
+  Provides definitions and functionality for manipulating Image Properties 
Records.
+
+  Copyright (c) 2016 - 2018, Intel Corporation. All rights reserved.<BR>
+  SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#ifndef IMAGE_PROPERTIES_RECORD_SUPPORT_LIB_H_
+#define IMAGE_PROPERTIES_RECORD_SUPPORT_LIB_H_
+
+#define IMAGE_PROPERTIES_RECORD_CODE_SECTION_SIGNATURE  SIGNATURE_32 
('I','P','R','C')
+
+typedef struct {
+  UINT32                  Signature;
+  LIST_ENTRY              Link;
+  EFI_PHYSICAL_ADDRESS    CodeSegmentBase;
+  UINT64                  CodeSegmentSize;
+} IMAGE_PROPERTIES_RECORD_CODE_SECTION;
+
+#define IMAGE_PROPERTIES_RECORD_SIGNATURE  SIGNATURE_32 ('I','P','R','D')
+
+typedef struct {
+  UINT32                  Signature;
+  LIST_ENTRY              Link;
+  EFI_PHYSICAL_ADDRESS    ImageBase;
+  UINT64                  ImageSize;
+  UINTN                   CodeSegmentCount;
+  LIST_ENTRY              CodeSegmentList;
+} IMAGE_PROPERTIES_RECORD;
+
+/**
+  Split the original memory map, and add more entries to describe PE code 
section and data section.
+  This function will set EfiRuntimeServicesData to be EFI_MEMORY_XP.
+  This function will merge entries with same attributes finally.
+
+  NOTE: It assumes PE code/data section are page aligned.
+  NOTE: It assumes enough entry is prepared for new memory map.
+
+  Split table:
+   +---------------+
+   | Record X      |
+   +---------------+
+   | Record RtCode |
+   +---------------+
+   | Record Y      |
+   +---------------+
+   ==>
+   +---------------+
+   | Record X      |
+   +---------------+ ----
+   | Record RtData |     |
+   +---------------+     |
+   | Record RtCode |     |-> PE/COFF1
+   +---------------+     |
+   | Record RtData |     |
+   +---------------+ ----
+   | Record RtData |     |
+   +---------------+     |
+   | Record RtCode |     |-> PE/COFF2
+   +---------------+     |
+   | Record RtData |     |
+   +---------------+ ----
+   | Record Y      |
+   +---------------+
+
+  @param  MemoryMapSize          A pointer to the size, in bytes, of the
+                                 MemoryMap buffer. On input, this is the size 
of
+                                 old MemoryMap before split. The actual buffer
+                                 size of MemoryMap is MemoryMapSize +
+                                 (AdditionalRecordCount * DescriptorSize) 
calculated
+                                 below. On output, it is the size of new 
MemoryMap
+                                 after split.
+  @param  MemoryMap              A pointer to the buffer in which firmware 
places
+                                 the current memory map.
+  @param  DescriptorSize         Size, in bytes, of an individual 
EFI_MEMORY_DESCRIPTOR.
+**/
+VOID
+EFIAPI
+SplitTable (
+  IN OUT UINTN                  *MemoryMapSize,
+  IN OUT EFI_MEMORY_DESCRIPTOR  *MemoryMap,
+  IN     UINTN                  DescriptorSize,
+  IN     LIST_ENTRY             *ImageRecordList,
+  IN     UINTN                  NumberOfAdditionalDescriptors
+  );
+
+/**
+  Sort code section in image record, based upon CodeSegmentBase from low to 
high.
+
+  @param  ImageRecord    image record to be sorted
+**/
+VOID
+EFIAPI
+SortImageRecordCodeSection (
+  IN IMAGE_PROPERTIES_RECORD  *ImageRecord
+  );
+
+/**
+  Check if code section in image record is valid.
+
+  @param  ImageRecord    image record to be checked
+
+  @retval TRUE  image record is valid
+  @retval FALSE image record is invalid
+**/
+BOOLEAN
+EFIAPI
+IsImageRecordCodeSectionValid (
+  IN IMAGE_PROPERTIES_RECORD  *ImageRecord
+  );
+
+/**
+  Sort image record based upon the ImageBase from low to high.
+**/
+VOID
+EFIAPI
+SortImageRecord (
+  IN     LIST_ENTRY  *ImageRecordList
+  );
+
+/**
+  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  A list of IMAGE_PROPERTIES_RECORD entries
+
+  @return image record
+**/
+IMAGE_PROPERTIES_RECORD *
+EFIAPI
+FindImageRecord (
+  IN EFI_PHYSICAL_ADDRESS  ImageBase,
+  IN UINT64                ImageSize,
+  IN LIST_ENTRY            *ImageRecordList
+  );
+
+/**
+  Dump image record.
+
+  @param[in]  ImageRecordList  A list of IMAGE_PROPERTIES_RECORD entries
+**/
+VOID
+EFIAPI
+DumpImageRecord (
+  IN LIST_ENTRY  *ImageRecordList
+  );
+
+#endif
diff --git 
a/MdeModulePkg/Library/ImagePropertiesRecordLib/ImagePropertiesRecordLib.inf 
b/MdeModulePkg/Library/ImagePropertiesRecordLib/ImagePropertiesRecordLib.inf
new file mode 100644
index 000000000000..9062d20eb48b
--- /dev/null
+++ b/MdeModulePkg/Library/ImagePropertiesRecordLib/ImagePropertiesRecordLib.inf
@@ -0,0 +1,28 @@
+## @file
+#  Provides definitions and functionality for manipulating
+#  Image Properties Records.
+#
+#  Copyright (c) 2016 - 2018, Intel Corporation. All rights reserved.<BR>
+#  SPDX-License-Identifier: BSD-2-Clause-Patent
+#
+##
+
+[Defines]
+  INF_VERSION                    = 0x00010005
+  BASE_NAME                      = ImagePropertiesRecordLib
+  FILE_GUID                      = 5CCA36C1-C430-4A90-8BF7-23D2719D5928
+  MODULE_TYPE                    = BASE
+  VERSION_STRING                 = 1.0
+  LIBRARY_CLASS                  = ImagePropertiesRecordLib
+
+[Sources.common]
+  ImagePropertiesRecordLib.c
+
+[LibraryClasses]
+  BaseLib
+  BaseMemoryLib
+  DebugLib
+
+[Packages]
+  MdePkg/MdePkg.dec
+  MdeModulePkg/MdeModulePkg.dec
diff --git a/MdeModulePkg/MdeModulePkg.dec b/MdeModulePkg/MdeModulePkg.dec
index 0ff058b0a9da..80df553b2a5f 100644
--- a/MdeModulePkg/MdeModulePkg.dec
+++ b/MdeModulePkg/MdeModulePkg.dec
@@ -164,6 +164,11 @@ [LibraryClasses]
   #
   VariableFlashInfoLib|Include/Library/VariableFlashInfoLib.h
 
+  ##  @libraryclass   Memory Attribute Table support logic for tracking and 
reporting
+  #                   runtime images
+  #
+  ImagePropertiesRecordLib|Include/Library/ImagePropertiesRecordLib.h
+
 [Guids]
   ## MdeModule package token space guid
   # Include/Guid/MdeModulePkgTokenSpace.h
diff --git a/MdeModulePkg/MdeModulePkg.dsc b/MdeModulePkg/MdeModulePkg.dsc
index db3b5af53795..6444111b9214 100644
--- a/MdeModulePkg/MdeModulePkg.dsc
+++ b/MdeModulePkg/MdeModulePkg.dsc
@@ -96,6 +96,7 @@ [LibraryClasses]
   VarCheckLib|MdeModulePkg/Library/VarCheckLib/VarCheckLib.inf
   FileExplorerLib|MdeModulePkg/Library/FileExplorerLib/FileExplorerLib.inf
   
NonDiscoverableDeviceRegistrationLib|MdeModulePkg/Library/NonDiscoverableDeviceRegistrationLib/NonDiscoverableDeviceRegistrationLib.inf
+  
ImagePropertiesRecordLib|MdeModulePkg/Library/ImagePropertiesRecordLib/ImagePropertiesRecordLib.inf
 
   
FmpAuthenticationLib|MdeModulePkg/Library/FmpAuthenticationLibNull/FmpAuthenticationLibNull.inf
   CapsuleLib|MdeModulePkg/Library/DxeCapsuleLibNull/DxeCapsuleLibNull.inf
@@ -237,6 +238,7 @@ [Components]
   MdeModulePkg/Library/BaseHobLibNull/BaseHobLibNull.inf
   
MdeModulePkg/Library/BaseMemoryAllocationLibNull/BaseMemoryAllocationLibNull.inf
   MdeModulePkg/Library/VariablePolicyHelperLib/VariablePolicyHelperLib.inf
+  MdeModulePkg/Library/ImagePropertiesRecordLib/ImagePropertiesRecordLib.inf
 
   MdeModulePkg/Bus/Pci/PciHostBridgeDxe/PciHostBridgeDxe.inf
   MdeModulePkg/Bus/Pci/PciSioSerialDxe/PciSioSerialDxe.inf
-- 
2.41.0.windows.2



-=-=-=-=-=-=-=-=-=-=-=-
Groups.io Links: You receive all messages sent to this group.
View/Reply Online (#107022): https://edk2.groups.io/g/devel/message/107022
Mute This Topic: https://groups.io/mt/100221557/21656
Group Owner: devel+ow...@edk2.groups.io
Unsubscribe: https://edk2.groups.io/g/devel/unsub [arch...@mail-archive.com]
-=-=-=-=-=-=-=-=-=-=-=-



Reply via email to