Add UEFI 2.5 properties table support in DXE core.
authorYao, Jiewen <Jiewen.yao@intel.com>
Fri, 5 Jun 2015 12:08:12 +0000 (12:08 +0000)
committerjyao1 <jyao1@Edk2>
Fri, 5 Jun 2015 12:08:12 +0000 (12:08 +0000)
Add PropertiesTableAttributesDxe driver to set ACPINvs/Reserved memory type to be XP, as default policy.

Contributed-under: TianoCore Contribution Agreement 1.0

Signed-off-by: "Yao, Jiewen" <Jiewen.yao@intel.com>
Reviewed-by: "Zeng, Star" <Star.Zeng@intel.com>
Reviewed-by: "Gao, Liming" <Liming.Gao@intel.com>
git-svn-id: https://svn.code.sf.net/p/edk2/code/trunk/edk2@17564 6f19259b-4bc3-4df7-8a09-765794883524

MdeModulePkg/Core/Dxe/DxeMain.h
MdeModulePkg/Core/Dxe/DxeMain.inf
MdeModulePkg/Core/Dxe/DxeMain/DxeMain.c
MdeModulePkg/Core/Dxe/Image/Image.c
MdeModulePkg/Core/Dxe/Misc/PropertiesTable.c [new file with mode: 0644]
MdeModulePkg/MdeModulePkg.dec
MdeModulePkg/MdeModulePkg.dsc
MdeModulePkg/Universal/PropertiesTableAttributesDxe/PropertiesTableAttributesDxe.c [new file with mode: 0644]
MdeModulePkg/Universal/PropertiesTableAttributesDxe/PropertiesTableAttributesDxe.inf [new file with mode: 0644]
MdeModulePkg/Universal/PropertiesTableAttributesDxe/PropertiesTableAttributesDxe.uni [new file with mode: 0644]
MdeModulePkg/Universal/PropertiesTableAttributesDxe/PropertiesTableAttributesDxeExtra.uni [new file with mode: 0644]

index 1e98df9..31277ca 100644 (file)
@@ -2858,4 +2858,33 @@ CoreUpdateMemoryAttributes (
   IN UINT64                NewAttributes\r
   );\r
 \r
+/**\r
+  Initialize PropertiesTable support.\r
+**/\r
+VOID\r
+EFIAPI\r
+CoreInitializePropertiesTable (\r
+  VOID\r
+  );\r
+\r
+/**\r
+  Insert image record.\r
+\r
+  @param  RuntimeImage    Runtime image information\r
+**/\r
+VOID\r
+InsertImageRecord (\r
+  IN EFI_RUNTIME_IMAGE_ENTRY  *RuntimeImage\r
+  );\r
+\r
+/**\r
+  Remove Image record.\r
+\r
+  @param  RuntimeImage    Runtime image information\r
+**/\r
+VOID\r
+RemoveImageRecord (\r
+  IN EFI_RUNTIME_IMAGE_ENTRY  *RuntimeImage\r
+  );\r
+\r
 #endif\r
index 0a63f3c..9afae4e 100644 (file)
@@ -40,6 +40,7 @@
   Misc/Stall.c\r
   Misc/SetWatchdogTimer.c\r
   Misc/InstallConfigurationTable.c\r
+  Misc/PropertiesTable.c\r
   Library/Library.c\r
   Hand/DriverSupport.c\r
   Hand/Notify.c\r
   gEfiVectorHandoffTableGuid                    ## SOMETIMES_PRODUCES   ## SystemTable\r
   gEdkiiMemoryProfileGuid                       ## SOMETIMES_PRODUCES   ## GUID # Install protocol\r
   gZeroGuid                                     ## SOMETIMES_CONSUMES   ## GUID\r
+  gEfiPropertiesTableGuid                       ## SOMETIMES_PRODUCES   ## SystemTable\r
+  gEfiEndOfDxeEventGroupGuid                    ## SOMETIMES_CONSUMES   ## Event\r
 \r
 [Ppis]\r
   gEfiVectorHandoffInfoPpiGuid                  ## UNDEFINED # HOB\r
   gEfiMdeModulePkgTokenSpaceGuid.PcdMaxEfiSystemTablePointerAddress         ## CONSUMES\r
   gEfiMdeModulePkgTokenSpaceGuid.PcdMemoryProfileMemoryType                 ## CONSUMES\r
   gEfiMdeModulePkgTokenSpaceGuid.PcdMemoryProfilePropertyMask               ## CONSUMES\r
+  gEfiMdeModulePkgTokenSpaceGuid.PropertiesTableEnable                      ## CONSUMES\r
 \r
 # [Hob]\r
 # RESOURCE_DESCRIPTOR   ## CONSUMES\r
index c1cf45b..e6ed247 100644 (file)
@@ -387,6 +387,8 @@ DxeMain (
 \r
   MemoryProfileInstallProtocol ();\r
 \r
+  CoreInitializePropertiesTable ();\r
+\r
   //\r
   // Get persisted vector hand-off info from GUIDeed HOB again due to HobStart may be updated,\r
   // and install configuration table\r
index 5b441f0..33686a6 100644 (file)
@@ -710,6 +710,7 @@ CoreLoadPeImage (
       Image->RuntimeData->RelocationData = Image->ImageContext.FixupData;\r
       Image->RuntimeData->Handle         = Image->Handle;\r
       InsertTailList (&gRuntime->ImageHead, &Image->RuntimeData->Link);\r
+      InsertImageRecord (Image->RuntimeData);\r
     }\r
   }\r
 \r
@@ -952,6 +953,7 @@ CoreUnloadAndCloseImage (
       // Remove the Image from the Runtime Image list as we are about to Free it!\r
       //\r
       RemoveEntryList (&Image->RuntimeData->Link);\r
+      RemoveImageRecord (Image->RuntimeData);\r
     }\r
     CoreFreePool (Image->RuntimeData);\r
   }\r
diff --git a/MdeModulePkg/Core/Dxe/Misc/PropertiesTable.c b/MdeModulePkg/Core/Dxe/Misc/PropertiesTable.c
new file mode 100644 (file)
index 0000000..5e409eb
--- /dev/null
@@ -0,0 +1,1418 @@
+/** @file\r
+  UEFI PropertiesTable support\r
+\r
+Copyright (c) 2015, Intel Corporation. All rights reserved.<BR>\r
+This program and the accompanying materials\r
+are licensed and made available under the terms and conditions of the BSD License\r
+which accompanies this distribution.  The full text of the license may be found at\r
+http://opensource.org/licenses/bsd-license.php\r
+\r
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+\r
+**/\r
+\r
+#include <PiDxe.h>\r
+#include <Library/BaseLib.h>\r
+#include <Library/BaseMemoryLib.h>\r
+#include <Library/MemoryAllocationLib.h>\r
+#include <Library/UefiBootServicesTableLib.h>\r
+#include <Library/DxeServicesTableLib.h>\r
+#include <Library/DebugLib.h>\r
+#include <Library/UefiLib.h>\r
+#include <Library/PcdLib.h>\r
+\r
+#include <Guid/EventGroup.h>\r
+#include <Protocol/DxeSmmReadyToLock.h>\r
+\r
+#include <Library/PeCoffLib.h>\r
+#include <Library/PeCoffGetEntryPointLib.h>\r
+#include <Protocol/Runtime.h>\r
+\r
+#include <Guid/PropertiesTable.h>\r
+\r
+#include "DxeMain.h"\r
+\r
+#define PREVIOUS_MEMORY_DESCRIPTOR(MemoryDescriptor, Size) \\r
+  ((EFI_MEMORY_DESCRIPTOR *)((UINT8 *)(MemoryDescriptor) - (Size)))\r
+\r
+#define IMAGE_PROPERTIES_RECORD_CODE_SECTION_SIGNATURE SIGNATURE_32 ('I','P','R','C')\r
+\r
+typedef struct {\r
+  UINT32                 Signature;\r
+  LIST_ENTRY             Link;\r
+  EFI_PHYSICAL_ADDRESS   CodeSegmentBase;\r
+  UINT64                 CodeSegmentSize;\r
+} IMAGE_PROPERTIES_RECORD_CODE_SECTION;\r
+\r
+#define IMAGE_PROPERTIES_RECORD_SIGNATURE SIGNATURE_32 ('I','P','R','D')\r
+\r
+typedef struct {\r
+  UINT32                 Signature;\r
+  LIST_ENTRY             Link;\r
+  EFI_PHYSICAL_ADDRESS   ImageBase;\r
+  UINT64                 ImageSize;\r
+  UINTN                  CodeSegmentCount;\r
+  LIST_ENTRY             CodeSegmentList;\r
+} IMAGE_PROPERTIES_RECORD;\r
+\r
+#define IMAGE_PROPERTIES_PRIVATE_DATA_SIGNATURE SIGNATURE_32 ('I','P','P','D')\r
+\r
+typedef struct {\r
+  UINT32                 Signature;\r
+  UINTN                  ImageRecordCount;\r
+  UINTN                  CodeSegmentCountMax;\r
+  LIST_ENTRY             ImageRecordList;\r
+} IMAGE_PROPERTIES_PRIVATE_DATA;\r
+\r
+IMAGE_PROPERTIES_PRIVATE_DATA  mImagePropertiesPrivateData = {\r
+  IMAGE_PROPERTIES_PRIVATE_DATA_SIGNATURE,\r
+  0,\r
+  0,\r
+  INITIALIZE_LIST_HEAD_VARIABLE (mImagePropertiesPrivateData.ImageRecordList)\r
+};\r
+\r
+EFI_PROPERTIES_TABLE  mPropertiesTable = {\r
+  EFI_PROPERTIES_TABLE_VERSION,\r
+  sizeof(EFI_PROPERTIES_TABLE),\r
+  EFI_PROPERTIES_RUNTIME_MEMORY_PROTECTION_NON_EXECUTABLE_PE_DATA\r
+};\r
+\r
+EFI_LOCK           mPropertiesTableLock = EFI_INITIALIZE_LOCK_VARIABLE (TPL_NOTIFY);\r
+\r
+//\r
+// Below functions are for MemoryMap\r
+//\r
+\r
+/**\r
+  Converts a number of EFI_PAGEs to a size in bytes.\r
+\r
+  NOTE: Do not use EFI_PAGES_TO_SIZE because it handles UINTN only.\r
+\r
+  @param  Pages     The number of EFI_PAGES.\r
+\r
+  @return  The number of bytes associated with the number of EFI_PAGEs specified\r
+           by Pages.\r
+**/\r
+UINT64\r
+EfiPagesToSize (\r
+  IN UINT64 Pages\r
+  )\r
+{\r
+  return LShiftU64 (Pages, EFI_PAGE_SHIFT);\r
+}\r
+\r
+/**\r
+  Converts a size, in bytes, to a number of EFI_PAGESs.\r
+\r
+  NOTE: Do not use EFI_SIZE_TO_PAGES because it handles UINTN only.\r
+\r
+  @param  Size      A size in bytes.\r
+\r
+  @return  The number of EFI_PAGESs associated with the number of bytes specified\r
+           by Size.\r
+\r
+**/\r
+UINT64\r
+EfiSizeToPages (\r
+  IN UINT64 Size\r
+  )\r
+{\r
+  return RShiftU64 (Size, EFI_PAGE_SHIFT) + ((((UINTN)Size) & EFI_PAGE_MASK) ? 1 : 0);\r
+}\r
+\r
+/**\r
+  Acquire memory lock on mPropertiesTableLock.\r
+**/\r
+VOID\r
+CoreAcquirePropertiesTableLock (\r
+  VOID\r
+  )\r
+{\r
+  CoreAcquireLock (&mPropertiesTableLock);\r
+}\r
+\r
+/**\r
+  Release memory lock on mPropertiesTableLock.\r
+**/\r
+VOID\r
+CoreReleasePropertiesTableLock (\r
+  VOID\r
+  )\r
+{\r
+  CoreReleaseLock (&mPropertiesTableLock);\r
+}\r
+\r
+/**\r
+  Dump memory map.\r
+\r
+  @param  MemoryMap              A pointer to the buffer in which firmware places\r
+                                 the current memory map.\r
+  @param  MemoryMapSize          Size, in bytes, of the MemoryMap buffer.\r
+  @param  DescriptorSize         Size, in bytes, of an individual EFI_MEMORY_DESCRIPTOR.\r
+**/\r
+VOID\r
+DumpMemoryMap (\r
+  IN EFI_MEMORY_DESCRIPTOR  *MemoryMap,\r
+  IN UINTN                  MemoryMapSize,\r
+  IN UINTN                  DescriptorSize\r
+  )\r
+{\r
+  EFI_MEMORY_DESCRIPTOR       *MemoryMapEntry;\r
+  EFI_MEMORY_DESCRIPTOR       *MemoryMapEnd;\r
+  UINT64                      MemoryBlockLength;\r
+\r
+  DEBUG ((EFI_D_VERBOSE, "  MemoryMap:\n"));\r
+  MemoryMapEntry = MemoryMap;\r
+  MemoryMapEnd   = (EFI_MEMORY_DESCRIPTOR *) ((UINT8 *) MemoryMap + MemoryMapSize);\r
+  while (MemoryMapEntry < MemoryMapEnd) {\r
+    MemoryBlockLength = (UINT64) (EfiPagesToSize (MemoryMapEntry->NumberOfPages));\r
+    DEBUG ((EFI_D_VERBOSE, "    Entry(0x%02x) 0x%016lx - 0x%016lx (0x%016lx)\n", MemoryMapEntry->Type, MemoryMapEntry->PhysicalStart, MemoryMapEntry->PhysicalStart + MemoryBlockLength, MemoryMapEntry->Attribute));\r
+    MemoryMapEntry = NEXT_MEMORY_DESCRIPTOR (MemoryMapEntry, DescriptorSize);\r
+  }\r
+}\r
+\r
+/**\r
+  Sort memory map entries based upon PhysicalStart, from low to high.\r
+\r
+  @param  MemoryMap              A pointer to the buffer in which firmware places\r
+                                 the current memory map.\r
+  @param  MemoryMapSize          Size, in bytes, of the MemoryMap buffer.\r
+  @param  DescriptorSize         Size, in bytes, of an individual EFI_MEMORY_DESCRIPTOR.\r
+**/\r
+VOID\r
+SortMemoryMap (\r
+  IN OUT EFI_MEMORY_DESCRIPTOR  *MemoryMap,\r
+  IN UINTN                      MemoryMapSize,\r
+  IN UINTN                      DescriptorSize\r
+  )\r
+{\r
+  EFI_MEMORY_DESCRIPTOR       *MemoryMapEntry;\r
+  EFI_MEMORY_DESCRIPTOR       *NextMemoryMapEntry;\r
+  EFI_MEMORY_DESCRIPTOR       *MemoryMapEnd;\r
+  EFI_MEMORY_DESCRIPTOR       TempMemoryMap;\r
+\r
+  MemoryMapEntry = MemoryMap;\r
+  NextMemoryMapEntry = NEXT_MEMORY_DESCRIPTOR (MemoryMapEntry, DescriptorSize);\r
+  MemoryMapEnd = (EFI_MEMORY_DESCRIPTOR *) ((UINT8 *) MemoryMap + MemoryMapSize);\r
+  while (MemoryMapEntry < MemoryMapEnd) {\r
+    while (NextMemoryMapEntry < MemoryMapEnd) {\r
+      if (MemoryMapEntry->PhysicalStart > NextMemoryMapEntry->PhysicalStart) {\r
+        CopyMem (&TempMemoryMap, MemoryMapEntry, sizeof(EFI_MEMORY_DESCRIPTOR));\r
+        CopyMem (MemoryMapEntry, NextMemoryMapEntry, sizeof(EFI_MEMORY_DESCRIPTOR));\r
+        CopyMem (NextMemoryMapEntry, &TempMemoryMap, sizeof(EFI_MEMORY_DESCRIPTOR));\r
+      }\r
+\r
+      NextMemoryMapEntry = NEXT_MEMORY_DESCRIPTOR (NextMemoryMapEntry, DescriptorSize);\r
+    }\r
+\r
+    MemoryMapEntry      = NEXT_MEMORY_DESCRIPTOR (MemoryMapEntry, DescriptorSize);\r
+    NextMemoryMapEntry  = NEXT_MEMORY_DESCRIPTOR (MemoryMapEntry, DescriptorSize);\r
+  }\r
+\r
+  return ;\r
+}\r
+\r
+/**\r
+  Merge continous memory map entries whose have same attributes.\r
+\r
+  @param  MemoryMap              A pointer to the buffer in which firmware places\r
+                                 the current memory map.\r
+  @param  MemoryMapSize          A pointer to the size, in bytes, of the\r
+                                 MemoryMap buffer. On input, this is the size of\r
+                                 the current memory map.  On output,\r
+                                 it is the size of new memory map after merge.\r
+  @param  DescriptorSize         Size, in bytes, of an individual EFI_MEMORY_DESCRIPTOR.\r
+**/\r
+VOID\r
+MergeMemoryMap (\r
+  IN OUT EFI_MEMORY_DESCRIPTOR  *MemoryMap,\r
+  IN OUT UINTN                  *MemoryMapSize,\r
+  IN UINTN                      DescriptorSize\r
+  )\r
+{\r
+  EFI_MEMORY_DESCRIPTOR       *MemoryMapEntry;\r
+  EFI_MEMORY_DESCRIPTOR       *MemoryMapEnd;\r
+  UINT64                      MemoryBlockLength;\r
+  EFI_MEMORY_DESCRIPTOR       *NewMemoryMapEntry;\r
+  EFI_MEMORY_DESCRIPTOR       *NextMemoryMapEntry;\r
+\r
+  MemoryMapEntry = MemoryMap;\r
+  NewMemoryMapEntry = MemoryMap;\r
+  MemoryMapEnd = (EFI_MEMORY_DESCRIPTOR *) ((UINT8 *) MemoryMap + *MemoryMapSize);\r
+  while ((UINTN)MemoryMapEntry < (UINTN)MemoryMapEnd) {\r
+    CopyMem (NewMemoryMapEntry, MemoryMapEntry, sizeof(EFI_MEMORY_DESCRIPTOR));\r
+    NextMemoryMapEntry = NEXT_MEMORY_DESCRIPTOR (MemoryMapEntry, DescriptorSize);\r
+\r
+    MemoryBlockLength = (UINT64) (EfiPagesToSize (MemoryMapEntry->NumberOfPages));\r
+    if (((UINTN)NextMemoryMapEntry < (UINTN)MemoryMapEnd) &&\r
+        (MemoryMapEntry->Type == NextMemoryMapEntry->Type) &&\r
+        (MemoryMapEntry->Attribute == NextMemoryMapEntry->Attribute) &&\r
+        ((MemoryMapEntry->PhysicalStart + MemoryBlockLength) == NextMemoryMapEntry->PhysicalStart)) {\r
+      NewMemoryMapEntry->NumberOfPages += NextMemoryMapEntry->NumberOfPages;\r
+      MemoryMapEntry = NextMemoryMapEntry;\r
+    }\r
+\r
+    MemoryMapEntry = NEXT_MEMORY_DESCRIPTOR (MemoryMapEntry, DescriptorSize);\r
+    NewMemoryMapEntry = NEXT_MEMORY_DESCRIPTOR (NewMemoryMapEntry, DescriptorSize);\r
+  }\r
+\r
+  *MemoryMapSize = (UINTN)NewMemoryMapEntry - (UINTN)MemoryMap;\r
+\r
+  return ;\r
+}\r
+\r
+/**\r
+  Enforce memory map attributes.\r
+  This function will set EfiRuntimeServicesData/EfiMemoryMappedIO/EfiMemoryMappedIOPortSpace to be EFI_MEMORY_XP.\r
+\r
+  @param  MemoryMap              A pointer to the buffer in which firmware places\r
+                                 the current memory map.\r
+  @param  MemoryMapSize          Size, in bytes, of the MemoryMap buffer.\r
+  @param  DescriptorSize         Size, in bytes, of an individual EFI_MEMORY_DESCRIPTOR.\r
+**/\r
+VOID\r
+EnforceMemoryMapAttribute (\r
+  IN OUT EFI_MEMORY_DESCRIPTOR  *MemoryMap,\r
+  IN UINTN                      MemoryMapSize,\r
+  IN UINTN                      DescriptorSize\r
+  )\r
+{\r
+  EFI_MEMORY_DESCRIPTOR       *MemoryMapEntry;\r
+  EFI_MEMORY_DESCRIPTOR       *MemoryMapEnd;\r
+\r
+  MemoryMapEntry = MemoryMap;\r
+  MemoryMapEnd   = (EFI_MEMORY_DESCRIPTOR *) ((UINT8 *) MemoryMap + MemoryMapSize);\r
+  while ((UINTN)MemoryMapEntry < (UINTN)MemoryMapEnd) {\r
+    switch (MemoryMapEntry->Type) {\r
+    case EfiRuntimeServicesCode:\r
+      // do nothing\r
+      break;\r
+    case EfiRuntimeServicesData:\r
+    case EfiMemoryMappedIO:\r
+    case EfiMemoryMappedIOPortSpace:\r
+      MemoryMapEntry->Attribute |= EFI_MEMORY_XP;\r
+      break;\r
+    case EfiReservedMemoryType:\r
+    case EfiACPIMemoryNVS:\r
+      break;\r
+    }\r
+\r
+    MemoryMapEntry = NEXT_MEMORY_DESCRIPTOR (MemoryMapEntry, DescriptorSize);\r
+  }\r
+\r
+  return ;\r
+}\r
+\r
+/**\r
+  Sort memory map entries whose type is EfiRuntimeServicesCode/EfiRuntimeServicesData,\r
+  from high to low.\r
+  This function assumes memory map is already from low to high, so it just reverts them.\r
+\r
+  @param  MemoryMap              A pointer to the buffer in which firmware places\r
+                                 the current memory map.\r
+  @param  MemoryMapSize          Size, in bytes, of the MemoryMap buffer.\r
+  @param  DescriptorSize         Size, in bytes, of an individual EFI_MEMORY_DESCRIPTOR.\r
+**/\r
+VOID\r
+RevertRuntimeMemoryMap (\r
+  IN OUT EFI_MEMORY_DESCRIPTOR  *MemoryMap,\r
+  IN UINTN                      MemoryMapSize,\r
+  IN UINTN                      DescriptorSize\r
+  )\r
+{\r
+  EFI_MEMORY_DESCRIPTOR       *MemoryMapEntry;\r
+  EFI_MEMORY_DESCRIPTOR       *MemoryMapEnd;\r
+  EFI_MEMORY_DESCRIPTOR       TempMemoryMap;\r
+\r
+  EFI_MEMORY_DESCRIPTOR       *RuntimeMapEntryBegin;\r
+  EFI_MEMORY_DESCRIPTOR       *RuntimeMapEntryEnd;\r
+\r
+  MemoryMapEntry = MemoryMap;\r
+  RuntimeMapEntryBegin = NULL;\r
+  RuntimeMapEntryEnd = NULL;\r
+  MemoryMapEnd   = (EFI_MEMORY_DESCRIPTOR *) ((UINT8 *) MemoryMap + MemoryMapSize);\r
+  while ((UINTN)MemoryMapEntry < (UINTN)MemoryMapEnd) {\r
+    if ((MemoryMapEntry->Type == EfiRuntimeServicesCode) ||\r
+        (MemoryMapEntry->Type == EfiRuntimeServicesData)) {\r
+      if (RuntimeMapEntryBegin == NULL) {\r
+        RuntimeMapEntryBegin = MemoryMapEntry;\r
+      }\r
+      RuntimeMapEntryEnd = MemoryMapEntry;\r
+    }\r
+    MemoryMapEntry = NEXT_MEMORY_DESCRIPTOR (MemoryMapEntry, DescriptorSize);\r
+  }\r
+\r
+  MemoryMapEntry = RuntimeMapEntryBegin;\r
+  MemoryMapEnd = RuntimeMapEntryEnd;\r
+  while (MemoryMapEntry < MemoryMapEnd) {\r
+    CopyMem (&TempMemoryMap, MemoryMapEntry, sizeof(EFI_MEMORY_DESCRIPTOR));\r
+    CopyMem (MemoryMapEntry, MemoryMapEnd, sizeof(EFI_MEMORY_DESCRIPTOR));\r
+    CopyMem (MemoryMapEnd, &TempMemoryMap, sizeof(EFI_MEMORY_DESCRIPTOR));\r
+\r
+    MemoryMapEntry = NEXT_MEMORY_DESCRIPTOR (MemoryMapEntry, DescriptorSize);\r
+    MemoryMapEnd = PREVIOUS_MEMORY_DESCRIPTOR (MemoryMapEnd, DescriptorSize);\r
+  }\r
+\r
+  return ;\r
+}\r
+\r
+/**\r
+  Return the first image record, whose [ImageBase, ImageSize] covered by [Buffer, Length].\r
+\r
+  @param Buffer  Start Address\r
+  @param Length  Address length\r
+\r
+  @return first image record covered by [buffer, length]\r
+**/\r
+IMAGE_PROPERTIES_RECORD *\r
+GetImageRecordByAddress (\r
+  IN EFI_PHYSICAL_ADDRESS  Buffer,\r
+  IN UINT64                Length\r
+  )\r
+{\r
+  IMAGE_PROPERTIES_RECORD    *ImageRecord;\r
+  LIST_ENTRY                 *ImageRecordLink;\r
+  LIST_ENTRY                 *ImageRecordList;\r
+\r
+  ImageRecordList = &mImagePropertiesPrivateData.ImageRecordList;\r
+\r
+  for (ImageRecordLink = ImageRecordList->ForwardLink;\r
+       ImageRecordLink != ImageRecordList;\r
+       ImageRecordLink = ImageRecordLink->ForwardLink) {\r
+    ImageRecord = CR (\r
+                    ImageRecordLink,\r
+                    IMAGE_PROPERTIES_RECORD,\r
+                    Link,\r
+                    IMAGE_PROPERTIES_RECORD_SIGNATURE\r
+                    );\r
+\r
+    if ((Buffer <= ImageRecord->ImageBase) &&\r
+        (Buffer + Length >= ImageRecord->ImageBase + ImageRecord->ImageSize)) {\r
+      return ImageRecord;\r
+    }\r
+  }\r
+\r
+  return NULL;\r
+}\r
+\r
+/**\r
+  Set the memory map to new entries, according to one old entry,\r
+  based upon PE code section and data section in image record\r
+\r
+  @param  ImageRecord            An image record whose [ImageBase, ImageSize] covered\r
+                                 by old memory map entry.\r
+  @param  NewRecord              A pointer to several new memory map entries.\r
+                                 The caller gurantee the buffer size be 1 +\r
+                                 (SplitRecordCount * DescriptorSize) calculated\r
+                                 below.\r
+  @param  OldRecord              A pointer to one old memory map entry.\r
+  @param  DescriptorSize         Size, in bytes, of an individual EFI_MEMORY_DESCRIPTOR.\r
+**/\r
+UINTN\r
+SetNewRecord (\r
+  IN IMAGE_PROPERTIES_RECORD       *ImageRecord,\r
+  IN OUT EFI_MEMORY_DESCRIPTOR     *NewRecord,\r
+  IN EFI_MEMORY_DESCRIPTOR         *OldRecord,\r
+  IN UINTN                         DescriptorSize\r
+  )\r
+{\r
+  EFI_MEMORY_DESCRIPTOR                     TempRecord;\r
+  IMAGE_PROPERTIES_RECORD_CODE_SECTION      *ImageRecordCodeSection;\r
+  LIST_ENTRY                                *ImageRecordCodeSectionLink;\r
+  LIST_ENTRY                                *ImageRecordCodeSectionEndLink;\r
+  LIST_ENTRY                                *ImageRecordCodeSectionList;\r
+  UINTN                                     NewRecordCount;\r
+  UINT64                                    PhysicalEnd;\r
+  UINT64                                    ImageEnd;\r
+\r
+  CopyMem (&TempRecord, OldRecord, sizeof(EFI_MEMORY_DESCRIPTOR));\r
+  PhysicalEnd = TempRecord.PhysicalStart + EfiPagesToSize(TempRecord.NumberOfPages);\r
+  NewRecordCount = 0;\r
+\r
+  ImageRecordCodeSectionList = &ImageRecord->CodeSegmentList;\r
+\r
+  ImageRecordCodeSectionLink = ImageRecordCodeSectionList->ForwardLink;\r
+  ImageRecordCodeSectionEndLink = ImageRecordCodeSectionList;\r
+  while (ImageRecordCodeSectionLink != ImageRecordCodeSectionEndLink) {\r
+    ImageRecordCodeSection = CR (\r
+                               ImageRecordCodeSectionLink,\r
+                               IMAGE_PROPERTIES_RECORD_CODE_SECTION,\r
+                               Link,\r
+                               IMAGE_PROPERTIES_RECORD_CODE_SECTION_SIGNATURE\r
+                               );\r
+    ImageRecordCodeSectionLink = ImageRecordCodeSectionLink->ForwardLink;\r
+\r
+    if (TempRecord.PhysicalStart <= ImageRecordCodeSection->CodeSegmentBase) {\r
+      //\r
+      // DATA\r
+      //\r
+      NewRecord->Type = EfiRuntimeServicesData;\r
+      NewRecord->PhysicalStart = TempRecord.PhysicalStart;\r
+      NewRecord->VirtualStart  = 0;\r
+      NewRecord->NumberOfPages = EfiSizeToPages(ImageRecordCodeSection->CodeSegmentBase - NewRecord->PhysicalStart);\r
+      NewRecord->Attribute     = TempRecord.Attribute | EFI_MEMORY_XP;\r
+      if (NewRecord->NumberOfPages != 0) {\r
+        NewRecord = NEXT_MEMORY_DESCRIPTOR (NewRecord, DescriptorSize);\r
+        NewRecordCount ++;\r
+      }\r
+\r
+      //\r
+      // CODE\r
+      //\r
+      NewRecord->Type = EfiRuntimeServicesCode;\r
+      NewRecord->PhysicalStart = ImageRecordCodeSection->CodeSegmentBase;\r
+      NewRecord->VirtualStart  = 0;\r
+      NewRecord->NumberOfPages = EfiSizeToPages(ImageRecordCodeSection->CodeSegmentSize);\r
+      NewRecord->Attribute     = (TempRecord.Attribute & (~EFI_MEMORY_XP)) | EFI_MEMORY_RO;\r
+      if (NewRecord->NumberOfPages != 0) {\r
+        NewRecord = NEXT_MEMORY_DESCRIPTOR (NewRecord, DescriptorSize);\r
+        NewRecordCount ++;\r
+      }\r
+\r
+      TempRecord.PhysicalStart = ImageRecordCodeSection->CodeSegmentBase + EfiPagesToSize (EfiSizeToPages(ImageRecordCodeSection->CodeSegmentSize));\r
+      TempRecord.NumberOfPages = EfiSizeToPages(PhysicalEnd - TempRecord.PhysicalStart);\r
+      if (TempRecord.NumberOfPages == 0) {\r
+        break;\r
+      }\r
+    }\r
+  }\r
+\r
+  ImageEnd = ImageRecord->ImageBase + ImageRecord->ImageSize;\r
+\r
+  //\r
+  // Final DATA\r
+  //\r
+  if (TempRecord.PhysicalStart < ImageEnd) {\r
+    NewRecord->Type = EfiRuntimeServicesData;\r
+    NewRecord->PhysicalStart = TempRecord.PhysicalStart;\r
+    NewRecord->VirtualStart  = 0;\r
+    NewRecord->NumberOfPages = EfiSizeToPages (ImageEnd - TempRecord.PhysicalStart);\r
+    NewRecord->Attribute     = TempRecord.Attribute | EFI_MEMORY_XP;\r
+    NewRecordCount ++;\r
+  }\r
+\r
+  return NewRecordCount;\r
+}\r
+\r
+/**\r
+  Return the max number of new splitted entries, according to one old entry,\r
+  based upon PE code section and data section.\r
+\r
+  @param  OldRecord              A pointer to one old memory map entry.\r
+\r
+  @retval  0 no entry need to be splitted.\r
+  @return  the max number of new splitted entries\r
+**/\r
+UINTN\r
+GetMaxSplitRecordCount (\r
+  IN EFI_MEMORY_DESCRIPTOR *OldRecord\r
+  )\r
+{\r
+  IMAGE_PROPERTIES_RECORD *ImageRecord;\r
+  UINTN                   SplitRecordCount;\r
+  UINT64                  PhysicalStart;\r
+  UINT64                  PhysicalEnd;\r
+\r
+  SplitRecordCount = 0;\r
+  PhysicalStart = OldRecord->PhysicalStart;\r
+  PhysicalEnd = OldRecord->PhysicalStart + EfiPagesToSize(OldRecord->NumberOfPages);\r
+\r
+  do {\r
+    ImageRecord = GetImageRecordByAddress (PhysicalStart, PhysicalEnd - PhysicalStart);\r
+    if (ImageRecord == NULL) {\r
+      break;\r
+    }\r
+    SplitRecordCount += (2 * ImageRecord->CodeSegmentCount + 1);\r
+    PhysicalStart = ImageRecord->ImageBase + ImageRecord->ImageSize;\r
+  } while ((ImageRecord != NULL) && (PhysicalStart < PhysicalEnd));\r
+\r
+  if (SplitRecordCount != 0) {\r
+    SplitRecordCount--;\r
+  }\r
+\r
+  return SplitRecordCount;\r
+}\r
+\r
+/**\r
+  Split the memory map to new entries, according to one old entry,\r
+  based upon PE code section and data section.\r
+\r
+  @param  OldRecord              A pointer to one old memory map entry.\r
+  @param  NewRecord              A pointer to several new memory map entries.\r
+                                 The caller gurantee the buffer size be 1 +\r
+                                 (SplitRecordCount * DescriptorSize) calculated\r
+                                 below.\r
+  @param  DescriptorSize         Size, in bytes, of an individual EFI_MEMORY_DESCRIPTOR.\r
+\r
+  @retval  0 no entry is splitted.\r
+  @return  the real number of splitted record.\r
+**/\r
+UINTN\r
+SplitRecord (\r
+  IN EFI_MEMORY_DESCRIPTOR     *OldRecord,\r
+  IN OUT EFI_MEMORY_DESCRIPTOR *NewRecord,\r
+  IN UINTN                     MaxSplitRecordCount,\r
+  IN UINTN                     DescriptorSize\r
+  )\r
+{\r
+  EFI_MEMORY_DESCRIPTOR   TempRecord;\r
+  IMAGE_PROPERTIES_RECORD *ImageRecord;\r
+  IMAGE_PROPERTIES_RECORD *NewImageRecord;\r
+  UINT64                  PhysicalStart;\r
+  UINT64                  PhysicalEnd;\r
+  UINTN                   NewRecordCount;\r
+  UINTN                   TotalNewRecordCount;\r
+\r
+  if (MaxSplitRecordCount == 0) {\r
+    CopyMem (NewRecord, OldRecord, DescriptorSize);\r
+    return 0;\r
+  }\r
+\r
+  TotalNewRecordCount = 0;\r
+\r
+  //\r
+  // Override previous record\r
+  //\r
+  CopyMem (&TempRecord, OldRecord, sizeof(EFI_MEMORY_DESCRIPTOR));\r
+  PhysicalStart = TempRecord.PhysicalStart;\r
+  PhysicalEnd = TempRecord.PhysicalStart + EfiPagesToSize(TempRecord.NumberOfPages);\r
+\r
+  ImageRecord = NULL;\r
+  do {\r
+    NewImageRecord = GetImageRecordByAddress (PhysicalStart, PhysicalEnd - PhysicalStart);\r
+    if (NewImageRecord == NULL) {\r
+      //\r
+      // No more image covered by this range, stop\r
+      //\r
+      if ((PhysicalEnd > PhysicalStart) && (ImageRecord != NULL)) {\r
+        //\r
+        // If this is still address in this record, need record.\r
+        //\r
+        NewRecord = PREVIOUS_MEMORY_DESCRIPTOR (NewRecord, DescriptorSize);\r
+        if (NewRecord->Type == EfiRuntimeServicesData) {\r
+          //\r
+          // Last record is DATA, just merge it.\r
+          //\r
+          NewRecord->NumberOfPages = EfiSizeToPages(PhysicalEnd - NewRecord->PhysicalStart);\r
+        } else {\r
+          //\r
+          // Last record is CODE, create a new DATA entry.\r
+          //\r
+          NewRecord = NEXT_MEMORY_DESCRIPTOR (NewRecord, DescriptorSize);\r
+          NewRecord->Type = EfiRuntimeServicesData;\r
+          NewRecord->PhysicalStart = TempRecord.PhysicalStart;\r
+          NewRecord->VirtualStart  = 0;\r
+          NewRecord->NumberOfPages = TempRecord.NumberOfPages;\r
+          NewRecord->Attribute     = TempRecord.Attribute | EFI_MEMORY_XP;\r
+          TotalNewRecordCount ++;\r
+        }\r
+      }\r
+      break;\r
+    }\r
+    ImageRecord = NewImageRecord;\r
+\r
+    //\r
+    // Set new record\r
+    //\r
+    NewRecordCount = SetNewRecord (ImageRecord, NewRecord, &TempRecord, DescriptorSize);\r
+    TotalNewRecordCount += NewRecordCount;\r
+    NewRecord = (EFI_MEMORY_DESCRIPTOR *)((UINT8 *)NewRecord + NewRecordCount * DescriptorSize);\r
+\r
+    //\r
+    // Update PhysicalStart, in order to exclude the image buffer already splitted.\r
+    //\r
+    PhysicalStart = ImageRecord->ImageBase + ImageRecord->ImageSize;\r
+    TempRecord.PhysicalStart = PhysicalStart;\r
+    TempRecord.NumberOfPages = EfiSizeToPages (PhysicalEnd - PhysicalStart);\r
+  } while ((ImageRecord != NULL) && (PhysicalStart < PhysicalEnd));\r
+\r
+  return TotalNewRecordCount - 1;\r
+}\r
+\r
+/**\r
+  Split the original memory map, and add more entries to describe PE code section and data section.\r
+  This function will set EfiRuntimeServicesData to be EFI_MEMORY_XP.\r
+  This function will merge entries with same attributes finally.\r
+\r
+  NOTE: It assumes PE code/data section are page aligned.\r
+  NOTE: It assumes enough entry is prepared for new memory map.\r
+\r
+  Split table:\r
+   +---------------+\r
+   | Record X      |\r
+   +---------------+\r
+   | Record RtCode |\r
+   +---------------+\r
+   | Record Y      |\r
+   +---------------+\r
+   ==>\r
+   +---------------+\r
+   | Record X      |\r
+   +---------------+ ----\r
+   | Record RtData |     |\r
+   +---------------+     |\r
+   | Record RtCode |     |-> PE/COFF1\r
+   +---------------+     |\r
+   | Record RtData |     |\r
+   +---------------+ ----\r
+   | Record RtData |     |\r
+   +---------------+     |\r
+   | Record RtCode |     |-> PE/COFF2\r
+   +---------------+     |\r
+   | Record RtData |     |\r
+   +---------------+ ----\r
+   | Record Y      |\r
+   +---------------+\r
+\r
+  @param  MemoryMapSize          A pointer to the size, in bytes, of the\r
+                                 MemoryMap buffer. On input, this is the size of\r
+                                 old MemoryMap before split. The actual buffer\r
+                                 size of MemoryMap is MemoryMapSize +\r
+                                 (AdditionalRecordCount * DescriptorSize) calculated\r
+                                 below. On output, it is the size of new MemoryMap\r
+                                 after split.\r
+  @param  MemoryMap              A pointer to the buffer in which firmware places\r
+                                 the current memory map.\r
+  @param  DescriptorSize         Size, in bytes, of an individual EFI_MEMORY_DESCRIPTOR.\r
+**/\r
+VOID\r
+SplitTable (\r
+  IN OUT UINTN                  *MemoryMapSize,\r
+  IN OUT EFI_MEMORY_DESCRIPTOR  *MemoryMap,\r
+  IN UINTN                      DescriptorSize\r
+  )\r
+{\r
+  INTN        IndexOld;\r
+  INTN        IndexNew;\r
+  UINTN       MaxSplitRecordCount;\r
+  UINTN       RealSplitRecordCount;\r
+  UINTN       TotalSplitRecordCount;\r
+  UINTN       AdditionalRecordCount;\r
+\r
+  AdditionalRecordCount = (2 * mImagePropertiesPrivateData.CodeSegmentCountMax + 1) * mImagePropertiesPrivateData.ImageRecordCount;\r
+\r
+  TotalSplitRecordCount = 0;\r
+  //\r
+  // Let old record point to end of valid MemoryMap buffer.\r
+  //\r
+  IndexOld = ((*MemoryMapSize) / DescriptorSize) - 1;\r
+  //\r
+  // Let new record point to end of full MemoryMap buffer.\r
+  //\r
+  IndexNew = ((*MemoryMapSize) / DescriptorSize) - 1 + AdditionalRecordCount;\r
+  for (; IndexOld >= 0; IndexOld--) {\r
+    MaxSplitRecordCount = GetMaxSplitRecordCount ((EFI_MEMORY_DESCRIPTOR *)((UINT8 *)MemoryMap + IndexOld * DescriptorSize));\r
+    //\r
+    // Split this MemoryMap record\r
+    //\r
+    IndexNew -= MaxSplitRecordCount;\r
+    RealSplitRecordCount = SplitRecord (\r
+                             (EFI_MEMORY_DESCRIPTOR *)((UINT8 *)MemoryMap + IndexOld * DescriptorSize),\r
+                             (EFI_MEMORY_DESCRIPTOR *)((UINT8 *)MemoryMap + IndexNew * DescriptorSize),\r
+                             MaxSplitRecordCount,\r
+                             DescriptorSize\r
+                             );\r
+    //\r
+    // Adjust IndexNew according to real split.\r
+    //\r
+    CopyMem (\r
+      ((UINT8 *)MemoryMap + (IndexNew + MaxSplitRecordCount - RealSplitRecordCount) * DescriptorSize),\r
+      ((UINT8 *)MemoryMap + IndexNew * DescriptorSize),\r
+      RealSplitRecordCount * DescriptorSize\r
+      );\r
+    IndexNew = IndexNew + MaxSplitRecordCount - RealSplitRecordCount;\r
+    TotalSplitRecordCount += RealSplitRecordCount;\r
+    IndexNew --;\r
+  }\r
+  //\r
+  // Move all records to the beginning.\r
+  //\r
+  CopyMem (\r
+    MemoryMap,\r
+    (UINT8 *)MemoryMap + (AdditionalRecordCount - TotalSplitRecordCount) * DescriptorSize,\r
+    (*MemoryMapSize) + TotalSplitRecordCount * DescriptorSize\r
+    );\r
+\r
+  *MemoryMapSize = (*MemoryMapSize) + DescriptorSize * TotalSplitRecordCount;\r
+\r
+  //\r
+  // Sort from low to high (Just in case)\r
+  //\r
+  SortMemoryMap (MemoryMap, *MemoryMapSize, DescriptorSize);\r
+\r
+  //\r
+  // Set RuntimeData to XP\r
+  //\r
+  EnforceMemoryMapAttribute (MemoryMap, *MemoryMapSize, DescriptorSize);\r
+\r
+  //\r
+  // Merge same type to save entry size\r
+  //\r
+  MergeMemoryMap (MemoryMap, MemoryMapSize, DescriptorSize);\r
+\r
+  return ;\r
+}\r
+\r
+/**\r
+  This function for GetMemoryMap() with properties table.\r
+\r
+  It calls original GetMemoryMap() to get the original memory map information. Then\r
+  plus the additional memory map entries for PE Code/Data seperation.\r
+\r
+  @param  MemoryMapSize          A pointer to the size, in bytes, of the\r
+                                 MemoryMap buffer. On input, this is the size of\r
+                                 the buffer allocated by the caller.  On output,\r
+                                 it is the size of the buffer returned by the\r
+                                 firmware  if the buffer was large enough, or the\r
+                                 size of the buffer needed  to contain the map if\r
+                                 the buffer was too small.\r
+  @param  MemoryMap              A pointer to the buffer in which firmware places\r
+                                 the current memory map.\r
+  @param  MapKey                 A pointer to the location in which firmware\r
+                                 returns the key for the current memory map.\r
+  @param  DescriptorSize         A pointer to the location in which firmware\r
+                                 returns the size, in bytes, of an individual\r
+                                 EFI_MEMORY_DESCRIPTOR.\r
+  @param  DescriptorVersion      A pointer to the location in which firmware\r
+                                 returns the version number associated with the\r
+                                 EFI_MEMORY_DESCRIPTOR.\r
+\r
+  @retval EFI_SUCCESS            The memory map was returned in the MemoryMap\r
+                                 buffer.\r
+  @retval EFI_BUFFER_TOO_SMALL   The MemoryMap buffer was too small. The current\r
+                                 buffer size needed to hold the memory map is\r
+                                 returned in MemoryMapSize.\r
+  @retval EFI_INVALID_PARAMETER  One of the parameters has an invalid value.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+CoreGetMemoryMapPropertiesTable (\r
+  IN OUT UINTN                  *MemoryMapSize,\r
+  IN OUT EFI_MEMORY_DESCRIPTOR  *MemoryMap,\r
+  OUT UINTN                     *MapKey,\r
+  OUT UINTN                     *DescriptorSize,\r
+  OUT UINT32                    *DescriptorVersion\r
+  )\r
+{\r
+  EFI_STATUS  Status;\r
+  UINTN       OldMemoryMapSize;\r
+  UINTN       AdditionalRecordCount;\r
+\r
+  //\r
+  // If PE code/data is not aligned, just return.\r
+  //\r
+  if ((mPropertiesTable.MemoryProtectionAttribute & EFI_PROPERTIES_RUNTIME_MEMORY_PROTECTION_NON_EXECUTABLE_PE_DATA) == 0) {\r
+    return CoreGetMemoryMap (MemoryMapSize, MemoryMap, MapKey, DescriptorSize, DescriptorVersion);\r
+  }\r
+\r
+  if (MemoryMapSize == NULL) {\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+\r
+  CoreAcquirePropertiesTableLock ();\r
+\r
+  AdditionalRecordCount = (2 * mImagePropertiesPrivateData.CodeSegmentCountMax + 1) * mImagePropertiesPrivateData.ImageRecordCount;\r
+\r
+  OldMemoryMapSize = *MemoryMapSize;\r
+  Status = CoreGetMemoryMap (MemoryMapSize, MemoryMap, MapKey, DescriptorSize, DescriptorVersion);\r
+  if (Status == EFI_BUFFER_TOO_SMALL) {\r
+    *MemoryMapSize = *MemoryMapSize + (*DescriptorSize) * AdditionalRecordCount;\r
+  } else if (Status == EFI_SUCCESS) {\r
+    if (OldMemoryMapSize - *MemoryMapSize < (*DescriptorSize) * AdditionalRecordCount) {\r
+      *MemoryMapSize = *MemoryMapSize + (*DescriptorSize) * AdditionalRecordCount;\r
+      //\r
+      // Need update status to buffer too small\r
+      //\r
+      Status = EFI_BUFFER_TOO_SMALL;\r
+    } else {\r
+      //\r
+      // Split PE code/data\r
+      //\r
+      SplitTable (MemoryMapSize, MemoryMap, *DescriptorSize);\r
+    }\r
+  }\r
+\r
+  CoreReleasePropertiesTableLock ();\r
+  return Status;\r
+}\r
+\r
+//\r
+// Below functions are for ImageRecord\r
+//\r
+\r
+/**\r
+  Set PropertiesTable accroding to PE/COFF image section alignment.\r
+\r
+  @param  SectionAlignment    PE/COFF section alignment\r
+**/\r
+VOID\r
+SetPropertiesTableSectionAlignment (\r
+  IN UINT32  SectionAlignment\r
+  )\r
+{\r
+  if (((SectionAlignment & (SIZE_4KB - 1)) != 0) &&\r
+      ((mPropertiesTable.MemoryProtectionAttribute & EFI_PROPERTIES_RUNTIME_MEMORY_PROTECTION_NON_EXECUTABLE_PE_DATA) != 0)) {\r
+    DEBUG ((EFI_D_VERBOSE, "SetPropertiesTableSectionAlignment - Clear\n"));\r
+    mPropertiesTable.MemoryProtectionAttribute &= ~EFI_PROPERTIES_RUNTIME_MEMORY_PROTECTION_NON_EXECUTABLE_PE_DATA;\r
+    gBS->GetMemoryMap = CoreGetMemoryMap;\r
+    gBS->Hdr.CRC32 = 0;\r
+    gBS->CalculateCrc32 ((UINT8 *)gBS, gBS->Hdr.HeaderSize, &gBS->Hdr.CRC32);\r
+  }\r
+}\r
+\r
+/**\r
+  Swap two code sections in image record.\r
+\r
+  @param  FirstImageRecordCodeSection    first code section in image record\r
+  @param  SecondImageRecordCodeSection   second code section in image record\r
+**/\r
+VOID\r
+SwapImageRecordCodeSection (\r
+  IN IMAGE_PROPERTIES_RECORD_CODE_SECTION      *FirstImageRecordCodeSection,\r
+  IN IMAGE_PROPERTIES_RECORD_CODE_SECTION      *SecondImageRecordCodeSection\r
+  )\r
+{\r
+  IMAGE_PROPERTIES_RECORD_CODE_SECTION      TempImageRecordCodeSection;\r
+\r
+  TempImageRecordCodeSection.CodeSegmentBase = FirstImageRecordCodeSection->CodeSegmentBase;\r
+  TempImageRecordCodeSection.CodeSegmentSize = FirstImageRecordCodeSection->CodeSegmentSize;\r
+\r
+  FirstImageRecordCodeSection->CodeSegmentBase = SecondImageRecordCodeSection->CodeSegmentBase;\r
+  FirstImageRecordCodeSection->CodeSegmentSize = SecondImageRecordCodeSection->CodeSegmentSize;\r
+\r
+  SecondImageRecordCodeSection->CodeSegmentBase = TempImageRecordCodeSection.CodeSegmentBase;\r
+  SecondImageRecordCodeSection->CodeSegmentSize = TempImageRecordCodeSection.CodeSegmentSize;\r
+}\r
+\r
+/**\r
+  Sort code section in image record, based upon CodeSegmentBase from low to high.\r
+\r
+  @param  ImageRecord    image record to be sorted\r
+**/\r
+VOID\r
+SortImageRecordCodeSection (\r
+  IN IMAGE_PROPERTIES_RECORD              *ImageRecord\r
+  )\r
+{\r
+  IMAGE_PROPERTIES_RECORD_CODE_SECTION      *ImageRecordCodeSection;\r
+  IMAGE_PROPERTIES_RECORD_CODE_SECTION      *NextImageRecordCodeSection;\r
+  LIST_ENTRY                                *ImageRecordCodeSectionLink;\r
+  LIST_ENTRY                                *NextImageRecordCodeSectionLink;\r
+  LIST_ENTRY                                *ImageRecordCodeSectionEndLink;\r
+  LIST_ENTRY                                *ImageRecordCodeSectionList;\r
+\r
+  ImageRecordCodeSectionList = &ImageRecord->CodeSegmentList;\r
+\r
+  ImageRecordCodeSectionLink = ImageRecordCodeSectionList->ForwardLink;\r
+  NextImageRecordCodeSectionLink = ImageRecordCodeSectionLink->ForwardLink;\r
+  ImageRecordCodeSectionEndLink = ImageRecordCodeSectionList;\r
+  while (ImageRecordCodeSectionLink != ImageRecordCodeSectionEndLink) {\r
+    ImageRecordCodeSection = CR (\r
+                               ImageRecordCodeSectionLink,\r
+                               IMAGE_PROPERTIES_RECORD_CODE_SECTION,\r
+                               Link,\r
+                               IMAGE_PROPERTIES_RECORD_CODE_SECTION_SIGNATURE\r
+                               );\r
+    while (NextImageRecordCodeSectionLink != ImageRecordCodeSectionEndLink) {\r
+      NextImageRecordCodeSection = CR (\r
+                                     NextImageRecordCodeSectionLink,\r
+                                     IMAGE_PROPERTIES_RECORD_CODE_SECTION,\r
+                                     Link,\r
+                                     IMAGE_PROPERTIES_RECORD_CODE_SECTION_SIGNATURE\r
+                                     );\r
+      if (ImageRecordCodeSection->CodeSegmentBase > NextImageRecordCodeSection->CodeSegmentBase) {\r
+        SwapImageRecordCodeSection (ImageRecordCodeSection, NextImageRecordCodeSection);\r
+      }\r
+      NextImageRecordCodeSectionLink = NextImageRecordCodeSectionLink->ForwardLink;\r
+    }\r
+\r
+    ImageRecordCodeSectionLink = ImageRecordCodeSectionLink->ForwardLink;\r
+    NextImageRecordCodeSectionLink = ImageRecordCodeSectionLink->ForwardLink;\r
+  }\r
+}\r
+\r
+/**\r
+  Check if code section in image record is valid\r
+\r
+  @param  ImageRecord    image record to be checked\r
+\r
+  @retval TRUE  image record is valid\r
+  @retval FALSE image record is invalid\r
+**/\r
+BOOLEAN\r
+IsImageRecordCodeSectionValid (\r
+  IN IMAGE_PROPERTIES_RECORD              *ImageRecord\r
+  )\r
+{\r
+  IMAGE_PROPERTIES_RECORD_CODE_SECTION      *ImageRecordCodeSection;\r
+  IMAGE_PROPERTIES_RECORD_CODE_SECTION      *LastImageRecordCodeSection;\r
+  LIST_ENTRY                                *ImageRecordCodeSectionLink;\r
+  LIST_ENTRY                                *ImageRecordCodeSectionEndLink;\r
+  LIST_ENTRY                                *ImageRecordCodeSectionList;\r
+\r
+  DEBUG ((EFI_D_VERBOSE, "ImageCode SegmentCount - 0x%x\n", ImageRecord->CodeSegmentCount));\r
+\r
+  ImageRecordCodeSectionList = &ImageRecord->CodeSegmentList;\r
+\r
+  ImageRecordCodeSectionLink = ImageRecordCodeSectionList->ForwardLink;\r
+  ImageRecordCodeSectionEndLink = ImageRecordCodeSectionList;\r
+  LastImageRecordCodeSection = NULL;\r
+  while (ImageRecordCodeSectionLink != ImageRecordCodeSectionEndLink) {\r
+    ImageRecordCodeSection = CR (\r
+                               ImageRecordCodeSectionLink,\r
+                               IMAGE_PROPERTIES_RECORD_CODE_SECTION,\r
+                               Link,\r
+                               IMAGE_PROPERTIES_RECORD_CODE_SECTION_SIGNATURE\r
+                               );\r
+    if (ImageRecordCodeSection->CodeSegmentSize == 0) {\r
+      return FALSE;\r
+    }\r
+    if (ImageRecordCodeSection->CodeSegmentBase < ImageRecord->ImageBase) {\r
+      return FALSE;\r
+    }\r
+    if (ImageRecordCodeSection->CodeSegmentBase >= MAX_ADDRESS - ImageRecordCodeSection->CodeSegmentSize) {\r
+      return FALSE;\r
+    }\r
+    if ((ImageRecordCodeSection->CodeSegmentBase + ImageRecordCodeSection->CodeSegmentSize) > (ImageRecord->ImageBase + ImageRecord->ImageSize)) {\r
+      return FALSE;\r
+    }\r
+    if (LastImageRecordCodeSection != NULL) {\r
+      if ((LastImageRecordCodeSection->CodeSegmentBase + LastImageRecordCodeSection->CodeSegmentSize) > ImageRecordCodeSection->CodeSegmentBase) {\r
+        return FALSE;\r
+      }\r
+    }\r
+\r
+    LastImageRecordCodeSection = ImageRecordCodeSection;\r
+    ImageRecordCodeSectionLink = ImageRecordCodeSectionLink->ForwardLink;\r
+  }\r
+\r
+  return TRUE;\r
+}\r
+\r
+/**\r
+  Swap two image records.\r
+\r
+  @param  FirstImageRecord   first image record.\r
+  @param  SecondImageRecord  second image record.\r
+**/\r
+VOID\r
+SwapImageRecord (\r
+  IN IMAGE_PROPERTIES_RECORD      *FirstImageRecord,\r
+  IN IMAGE_PROPERTIES_RECORD      *SecondImageRecord\r
+  )\r
+{\r
+  IMAGE_PROPERTIES_RECORD      TempImageRecord;\r
+\r
+  TempImageRecord.ImageBase = FirstImageRecord->ImageBase;\r
+  TempImageRecord.ImageSize = FirstImageRecord->ImageSize;\r
+  TempImageRecord.CodeSegmentCount = FirstImageRecord->CodeSegmentCount;\r
+\r
+  FirstImageRecord->ImageBase = SecondImageRecord->ImageBase;\r
+  FirstImageRecord->ImageSize = SecondImageRecord->ImageSize;\r
+  FirstImageRecord->CodeSegmentCount = SecondImageRecord->CodeSegmentCount;\r
+\r
+  SecondImageRecord->ImageBase = TempImageRecord.ImageBase;\r
+  SecondImageRecord->ImageSize = TempImageRecord.ImageSize;\r
+  SecondImageRecord->CodeSegmentCount = TempImageRecord.CodeSegmentCount;\r
+\r
+  SwapListEntries (&FirstImageRecord->CodeSegmentList, &SecondImageRecord->CodeSegmentList);\r
+}\r
+\r
+/**\r
+  Sort image record based upon the ImageBase from low to high.\r
+**/\r
+VOID\r
+SortImageRecord (\r
+  VOID\r
+  )\r
+{\r
+  IMAGE_PROPERTIES_RECORD      *ImageRecord;\r
+  IMAGE_PROPERTIES_RECORD      *NextImageRecord;\r
+  LIST_ENTRY                   *ImageRecordLink;\r
+  LIST_ENTRY                   *NextImageRecordLink;\r
+  LIST_ENTRY                   *ImageRecordEndLink;\r
+  LIST_ENTRY                   *ImageRecordList;\r
+\r
+  ImageRecordList = &mImagePropertiesPrivateData.ImageRecordList;\r
+\r
+  ImageRecordLink = ImageRecordList->ForwardLink;\r
+  NextImageRecordLink = ImageRecordLink->ForwardLink;\r
+  ImageRecordEndLink = ImageRecordList;\r
+  while (ImageRecordLink != ImageRecordEndLink) {\r
+    ImageRecord = CR (\r
+                    ImageRecordLink,\r
+                    IMAGE_PROPERTIES_RECORD,\r
+                    Link,\r
+                    IMAGE_PROPERTIES_RECORD_SIGNATURE\r
+                    );\r
+    while (NextImageRecordLink != ImageRecordEndLink) {\r
+      NextImageRecord = CR (\r
+                          NextImageRecordLink,\r
+                          IMAGE_PROPERTIES_RECORD,\r
+                          Link,\r
+                          IMAGE_PROPERTIES_RECORD_SIGNATURE\r
+                          );\r
+      if (ImageRecord->ImageBase > NextImageRecord->ImageBase) {\r
+        SwapImageRecord (ImageRecord, NextImageRecord);\r
+      }\r
+      NextImageRecordLink = NextImageRecordLink->ForwardLink;\r
+    }\r
+\r
+    ImageRecordLink = ImageRecordLink->ForwardLink;\r
+    NextImageRecordLink = ImageRecordLink->ForwardLink;\r
+  }\r
+}\r
+\r
+/**\r
+  Dump image record\r
+**/\r
+VOID\r
+DumpImageRecord (\r
+  VOID\r
+  )\r
+{\r
+  IMAGE_PROPERTIES_RECORD      *ImageRecord;\r
+  LIST_ENTRY                   *ImageRecordLink;\r
+  LIST_ENTRY                   *ImageRecordList;\r
+  UINTN                        Index;\r
+\r
+  ImageRecordList = &mImagePropertiesPrivateData.ImageRecordList;\r
+\r
+  for (ImageRecordLink = ImageRecordList->ForwardLink, Index= 0;\r
+       ImageRecordLink != ImageRecordList;\r
+       ImageRecordLink = ImageRecordLink->ForwardLink, Index++) {\r
+    ImageRecord = CR (\r
+                    ImageRecordLink,\r
+                    IMAGE_PROPERTIES_RECORD,\r
+                    Link,\r
+                    IMAGE_PROPERTIES_RECORD_SIGNATURE\r
+                    );\r
+    DEBUG ((EFI_D_VERBOSE, "  Image[%d]: 0x%016lx - 0x%016lx\n", Index, ImageRecord->ImageBase, ImageRecord->ImageSize));\r
+  }\r
+}\r
+\r
+/**\r
+  Insert image record.\r
+\r
+  @param  RuntimeImage    Runtime image information\r
+**/\r
+VOID\r
+InsertImageRecord (\r
+  IN EFI_RUNTIME_IMAGE_ENTRY  *RuntimeImage\r
+  )\r
+{\r
+  VOID                                 *ImageAddress;\r
+  EFI_IMAGE_DOS_HEADER                 *DosHdr;\r
+  UINT32                               PeCoffHeaderOffset;\r
+  UINT32                               SectionAlignment;\r
+  UINT16                               ImageType;\r
+  EFI_IMAGE_SECTION_HEADER             *Section;\r
+  EFI_IMAGE_OPTIONAL_HEADER_PTR_UNION  Hdr;\r
+  UINT16                               Magic;\r
+  UINT8                                *Name;\r
+  UINTN                                Index;\r
+  IMAGE_PROPERTIES_RECORD              *ImageRecord;\r
+  CHAR8                                *PdbPointer;\r
+  IMAGE_PROPERTIES_RECORD_CODE_SECTION *ImageRecordCodeSection;\r
+\r
+  DEBUG ((EFI_D_VERBOSE, "InsertImageRecord - 0x%x\n", RuntimeImage));\r
+  DEBUG ((EFI_D_VERBOSE, "InsertImageRecord - 0x%016lx - 0x%016lx\n", (EFI_PHYSICAL_ADDRESS)(UINTN)RuntimeImage->ImageBase, RuntimeImage->ImageSize));\r
+\r
+  ImageRecord = AllocatePool (sizeof(*ImageRecord));\r
+  if (ImageRecord == NULL) {\r
+    return ;\r
+  }\r
+  ImageRecord->Signature = IMAGE_PROPERTIES_RECORD_SIGNATURE;\r
+\r
+  DEBUG ((EFI_D_VERBOSE, "ImageRecordCount - 0x%x\n", mImagePropertiesPrivateData.ImageRecordCount));\r
+\r
+  //\r
+  // Step 1: record whole region\r
+  //\r
+  ImageRecord->ImageBase = (EFI_PHYSICAL_ADDRESS)(UINTN)RuntimeImage->ImageBase;\r
+  ImageRecord->ImageSize = RuntimeImage->ImageSize;\r
+\r
+  ImageAddress = RuntimeImage->ImageBase;\r
+\r
+  PdbPointer = PeCoffLoaderGetPdbPointer ((VOID*) (UINTN) ImageAddress);\r
+  if (PdbPointer != NULL) {\r
+    DEBUG ((EFI_D_VERBOSE, "  Image - %a\n", PdbPointer));\r
+  }\r
+\r
+  //\r
+  // Check PE/COFF image\r
+  //\r
+  DosHdr = (EFI_IMAGE_DOS_HEADER *) (UINTN) ImageAddress;\r
+  PeCoffHeaderOffset = 0;\r
+  if (DosHdr->e_magic == EFI_IMAGE_DOS_SIGNATURE) {\r
+    PeCoffHeaderOffset = DosHdr->e_lfanew;\r
+  }\r
+\r
+  Hdr.Pe32 = (EFI_IMAGE_NT_HEADERS32 *)((UINT8 *) (UINTN) ImageAddress + PeCoffHeaderOffset);\r
+  if (Hdr.Pe32->Signature != EFI_IMAGE_NT_SIGNATURE) {\r
+    DEBUG ((EFI_D_VERBOSE, "Hdr.Pe32->Signature invalid - 0x%x\n", Hdr.Pe32->Signature));\r
+       // It might be image in SMM.\r
+    goto Finish;\r
+  }\r
+\r
+  //\r
+  // Measuring PE/COFF Image Header;\r
+  // But CheckSum field and SECURITY data directory (certificate) are excluded\r
+  //\r
+  if (Hdr.Pe32->FileHeader.Machine == IMAGE_FILE_MACHINE_IA64 && Hdr.Pe32->OptionalHeader.Magic == EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC) {\r
+    //\r
+    // NOTE: Some versions of Linux ELILO for Itanium have an incorrect magic value\r
+    //       in the PE/COFF Header. If the MachineType is Itanium(IA64) and the\r
+    //       Magic value in the OptionalHeader is EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC\r
+    //       then override the magic value to EFI_IMAGE_NT_OPTIONAL_HDR64_MAGIC\r
+    //\r
+    Magic = EFI_IMAGE_NT_OPTIONAL_HDR64_MAGIC;\r
+    ImageType         = Hdr.Pe32->OptionalHeader.Subsystem;\r
+    SectionAlignment  = Hdr.Pe32->OptionalHeader.SectionAlignment;\r
+  } else {\r
+    //\r
+    // Get the magic value from the PE/COFF Optional Header\r
+    //\r
+    Magic = Hdr.Pe32->OptionalHeader.Magic;\r
+    ImageType         = Hdr.Pe32Plus->OptionalHeader.Subsystem;\r
+    SectionAlignment  = Hdr.Pe32Plus->OptionalHeader.SectionAlignment;\r
+  }\r
+\r
+  SetPropertiesTableSectionAlignment (SectionAlignment);\r
+  if ((SectionAlignment & (SIZE_4KB - 1)) != 0) {\r
+    DEBUG ((EFI_D_ERROR, "!!!!!!!!  InsertImageRecord - Section Alignment(0x%x) is not 4K  !!!!!!!!\n", SectionAlignment));\r
+    PdbPointer = PeCoffLoaderGetPdbPointer ((VOID*) (UINTN) ImageAddress);\r
+    if (PdbPointer != NULL) {\r
+      DEBUG ((EFI_D_ERROR, "!!!!!!!!  Image - %a  !!!!!!!!\n", PdbPointer));\r
+    }\r
+    goto Finish;\r
+  }\r
+\r
+  Section = (EFI_IMAGE_SECTION_HEADER *) (\r
+               (UINT8 *) (UINTN) ImageAddress +\r
+               PeCoffHeaderOffset +\r
+               sizeof(UINT32) +\r
+               sizeof(EFI_IMAGE_FILE_HEADER) +\r
+               Hdr.Pe32->FileHeader.SizeOfOptionalHeader\r
+               );\r
+  ImageRecord->CodeSegmentCount = 0;\r
+  InitializeListHead (&ImageRecord->CodeSegmentList);\r
+  for (Index = 0; Index < Hdr.Pe32->FileHeader.NumberOfSections; Index++) {\r
+    Name = Section[Index].Name;\r
+    DEBUG ((\r
+      EFI_D_VERBOSE,\r
+      "  Section - '%c%c%c%c%c%c%c%c'\n",\r
+      Name[0],\r
+      Name[1],\r
+      Name[2],\r
+      Name[3],\r
+      Name[4],\r
+      Name[5],\r
+      Name[6],\r
+      Name[7]\r
+      ));\r
+\r
+    if ((Section[Index].Characteristics & EFI_IMAGE_SCN_CNT_CODE) != 0) {\r
+      DEBUG ((EFI_D_VERBOSE, "  VirtualSize          - 0x%08x\n", Section[Index].Misc.VirtualSize));\r
+      DEBUG ((EFI_D_VERBOSE, "  VirtualAddress       - 0x%08x\n", Section[Index].VirtualAddress));\r
+      DEBUG ((EFI_D_VERBOSE, "  SizeOfRawData        - 0x%08x\n", Section[Index].SizeOfRawData));\r
+      DEBUG ((EFI_D_VERBOSE, "  PointerToRawData     - 0x%08x\n", Section[Index].PointerToRawData));\r
+      DEBUG ((EFI_D_VERBOSE, "  PointerToRelocations - 0x%08x\n", Section[Index].PointerToRelocations));\r
+      DEBUG ((EFI_D_VERBOSE, "  PointerToLinenumbers - 0x%08x\n", Section[Index].PointerToLinenumbers));\r
+      DEBUG ((EFI_D_VERBOSE, "  NumberOfRelocations  - 0x%08x\n", Section[Index].NumberOfRelocations));\r
+      DEBUG ((EFI_D_VERBOSE, "  NumberOfLinenumbers  - 0x%08x\n", Section[Index].NumberOfLinenumbers));\r
+      DEBUG ((EFI_D_VERBOSE, "  Characteristics      - 0x%08x\n", Section[Index].Characteristics));\r
+\r
+      //\r
+      // Step 2: record code section\r
+      //\r
+      ImageRecordCodeSection = AllocatePool (sizeof(*ImageRecordCodeSection));\r
+      if (ImageRecordCodeSection == NULL) {\r
+        return ;\r
+      }\r
+      ImageRecordCodeSection->Signature = IMAGE_PROPERTIES_RECORD_CODE_SECTION_SIGNATURE;\r
+\r
+      ImageRecordCodeSection->CodeSegmentBase = (UINTN)ImageAddress + Section[Index].VirtualAddress;\r
+      ImageRecordCodeSection->CodeSegmentSize = Section[Index].SizeOfRawData;\r
+\r
+      DEBUG ((EFI_D_VERBOSE, "ImageCode: 0x%016lx - 0x%016lx\n", ImageRecordCodeSection->CodeSegmentBase, ImageRecordCodeSection->CodeSegmentSize));\r
+\r
+      InsertTailList (&ImageRecord->CodeSegmentList, &ImageRecordCodeSection->Link);\r
+      ImageRecord->CodeSegmentCount++;\r
+    }\r
+  }\r
+\r
+  if (ImageRecord->CodeSegmentCount == 0) {\r
+    SetPropertiesTableSectionAlignment (1);\r
+    DEBUG ((EFI_D_ERROR, "!!!!!!!!  InsertImageRecord - CodeSegmentCount is 0  !!!!!!!!\n"));\r
+    PdbPointer = PeCoffLoaderGetPdbPointer ((VOID*) (UINTN) ImageAddress);\r
+    if (PdbPointer != NULL) {\r
+      DEBUG ((EFI_D_ERROR, "!!!!!!!!  Image - %a  !!!!!!!!\n", PdbPointer));\r
+    }\r
+    goto Finish;\r
+  }\r
+\r
+  //\r
+  // Final\r
+  //\r
+  SortImageRecordCodeSection (ImageRecord);\r
+  //\r
+  // Check overlap all section in ImageBase/Size\r
+  //\r
+  if (!IsImageRecordCodeSectionValid (ImageRecord)) {\r
+    DEBUG ((EFI_D_ERROR, "IsImageRecordCodeSectionValid - FAIL\n"));\r
+    goto Finish;\r
+  }\r
+\r
+  InsertTailList (&mImagePropertiesPrivateData.ImageRecordList, &ImageRecord->Link);\r
+  mImagePropertiesPrivateData.ImageRecordCount++;\r
+\r
+  SortImageRecord ();\r
+\r
+  if (mImagePropertiesPrivateData.CodeSegmentCountMax < ImageRecord->CodeSegmentCount) {\r
+    mImagePropertiesPrivateData.CodeSegmentCountMax = ImageRecord->CodeSegmentCount;\r
+  }\r
+\r
+Finish:\r
+  return ;\r
+}\r
+\r
+/**\r
+  Find image record accroding to image base and size.\r
+\r
+  @param  ImageBase    Base of PE image\r
+  @param  ImageSize    Size of PE image\r
+\r
+  @return image record\r
+**/\r
+IMAGE_PROPERTIES_RECORD *\r
+FindImageRecord (\r
+  IN EFI_PHYSICAL_ADDRESS  ImageBase,\r
+  IN UINT64                ImageSize\r
+  )\r
+{\r
+  IMAGE_PROPERTIES_RECORD    *ImageRecord;\r
+  LIST_ENTRY                 *ImageRecordLink;\r
+  LIST_ENTRY                 *ImageRecordList;\r
+\r
+  ImageRecordList = &mImagePropertiesPrivateData.ImageRecordList;\r
+\r
+  for (ImageRecordLink = ImageRecordList->ForwardLink;\r
+       ImageRecordLink != ImageRecordList;\r
+       ImageRecordLink = ImageRecordLink->ForwardLink) {\r
+    ImageRecord = CR (\r
+                    ImageRecordLink,\r
+                    IMAGE_PROPERTIES_RECORD,\r
+                    Link,\r
+                    IMAGE_PROPERTIES_RECORD_SIGNATURE\r
+                    );\r
+\r
+    if ((ImageBase == ImageRecord->ImageBase) &&\r
+        (ImageSize == ImageRecord->ImageSize)) {\r
+      return ImageRecord;\r
+    }\r
+  }\r
+\r
+  return NULL;\r
+}\r
+\r
+/**\r
+  Remove Image record.\r
+\r
+  @param  RuntimeImage    Runtime image information\r
+**/\r
+VOID\r
+RemoveImageRecord (\r
+  IN EFI_RUNTIME_IMAGE_ENTRY  *RuntimeImage\r
+  )\r
+{\r
+  IMAGE_PROPERTIES_RECORD              *ImageRecord;\r
+  LIST_ENTRY                           *CodeSegmentListHead;\r
+  IMAGE_PROPERTIES_RECORD_CODE_SECTION *ImageRecordCodeSection;\r
+\r
+  DEBUG ((EFI_D_VERBOSE, "RemoveImageRecord - 0x%x\n", RuntimeImage));\r
+  DEBUG ((EFI_D_VERBOSE, "RemoveImageRecord - 0x%016lx - 0x%016lx\n", (EFI_PHYSICAL_ADDRESS)(UINTN)RuntimeImage->ImageBase, RuntimeImage->ImageSize));\r
+\r
+  ImageRecord = FindImageRecord ((EFI_PHYSICAL_ADDRESS)(UINTN)RuntimeImage->ImageBase, RuntimeImage->ImageSize);\r
+  if (ImageRecord == NULL) {\r
+    DEBUG ((EFI_D_ERROR, "!!!!!!!! ImageRecord not found !!!!!!!!\n"));\r
+    return ;\r
+  }\r
+\r
+  CodeSegmentListHead = &ImageRecord->CodeSegmentList;\r
+  while (!IsListEmpty (CodeSegmentListHead)) {\r
+    ImageRecordCodeSection = CR (\r
+                               CodeSegmentListHead->ForwardLink,\r
+                               IMAGE_PROPERTIES_RECORD_CODE_SECTION,\r
+                               Link,\r
+                               IMAGE_PROPERTIES_RECORD_CODE_SECTION_SIGNATURE\r
+                               );\r
+    RemoveEntryList (&ImageRecordCodeSection->Link);\r
+    FreePool (ImageRecordCodeSection);\r
+  }\r
+\r
+  RemoveEntryList (&ImageRecord->Link);\r
+  FreePool (ImageRecord);\r
+  mImagePropertiesPrivateData.ImageRecordCount--;\r
+}\r
+\r
+\r
+/**\r
+  Install PropertiesTable.\r
+\r
+  @param[in]  Event     The Event this notify function registered to.\r
+  @param[in]  Context   Pointer to the context data registered to the Event.\r
+**/\r
+VOID\r
+EFIAPI\r
+InstallPropertiesTable (\r
+  EFI_EVENT                               Event,\r
+  VOID                                    *Context\r
+  )\r
+{\r
+  if (PcdGetBool (PropertiesTableEnable)) {\r
+    EFI_STATUS  Status;\r
+\r
+    Status = gBS->InstallConfigurationTable (&gEfiPropertiesTableGuid, &mPropertiesTable);\r
+    ASSERT_EFI_ERROR (Status);\r
+\r
+    DEBUG ((EFI_D_INFO, "MemoryProtectionAttribute - 0x%016lx\n", mPropertiesTable.MemoryProtectionAttribute));\r
+    if ((mPropertiesTable.MemoryProtectionAttribute & EFI_PROPERTIES_RUNTIME_MEMORY_PROTECTION_NON_EXECUTABLE_PE_DATA) == 0) {\r
+      return ;\r
+    }\r
+\r
+    gBS->GetMemoryMap = CoreGetMemoryMapPropertiesTable;\r
+    gBS->Hdr.CRC32 = 0;\r
+    gBS->CalculateCrc32 ((UINT8 *)gBS, gBS->Hdr.HeaderSize, &gBS->Hdr.CRC32);\r
+\r
+    DEBUG ((EFI_D_VERBOSE, "Total Image Count - 0x%x\n", mImagePropertiesPrivateData.ImageRecordCount));\r
+    DEBUG ((EFI_D_VERBOSE, "Dump ImageRecord:\n"));\r
+    DumpImageRecord ();\r
+  }\r
+}\r
+\r
+/**\r
+  Initialize PropertiesTable support.\r
+**/\r
+VOID\r
+EFIAPI\r
+CoreInitializePropertiesTable (\r
+  VOID\r
+  )\r
+{\r
+  EFI_STATUS  Status;\r
+  EFI_EVENT   EndOfDxeEvent;\r
+\r
+  Status = gBS->CreateEventEx (\r
+                  EVT_NOTIFY_SIGNAL,\r
+                  TPL_NOTIFY,\r
+                  InstallPropertiesTable,\r
+                  NULL,\r
+                  &gEfiEndOfDxeEventGroupGuid,\r
+                  &EndOfDxeEvent\r
+                  );\r
+  ASSERT_EFI_ERROR (Status);\r
+  return ;\r
+}\r
index 4d89a57..e3f4600 100644 (file)
   # @Prompt Flag to request system reboot after processing capsule.\r
   gEfiMdeModulePkgTokenSpaceGuid.PcdSystemRebootAfterCapsuleProcessFlag|0x0001|UINT16|0x0000006d\r
 \r
+  ## Publish PropertiesTable or not.\r
+  #\r
+  # If this PCD is TRUE, DxeCore publishs PropertiesTable.\r
+  # DxeCore evaluates if all runtime drivers has 4K aligned PE sections. If all\r
+  # PE sections in runtime drivers are 4K aligned, DxeCore sets BIT0 in\r
+  # PropertiesTable. Or DxeCore clears BIT0 in PropertiesTable.\r
+  # If this PCD is FALSE, DxeCore does not publish PropertiesTable.\r
+  #\r
+  # If PropertiesTable has BIT0 set, DxeCore uses below policy in UEFI memory map:\r
+  #   1) Use EfiRuntimeServicesCode for runtime driver PE image code section and\r
+  #      use EfiRuntimeServicesData for runtime driver PE image header and other section.\r
+  #   2) Set EfiRuntimeServicesCode to be EFI_MEMORY_RO.\r
+  #   3) Set EfiRuntimeServicesData to be EFI_MEMORY_XP.\r
+  #   4) Set EfiMemoryMappedIO and EfiMemoryMappedIOPortSpace to be EFI_MEMORY_XP.\r
+  #\r
+  # NOTE: Platform need gurantee this PCD is set correctly. Platform should set\r
+  # this PCD to be TURE if and only if all runtime driver has seperated Code/Data\r
+  # section. If PE code/data sections are merged, the result is unpredictable.\r
+  #\r
+  # @Prompt Publish UEFI PropertiesTable.\r
+  gEfiMdeModulePkgTokenSpaceGuid.PropertiesTableEnable|TRUE|BOOLEAN|0x0000006e\r
+\r
   ## Default OEM ID for ACPI table creation, its length must be 0x6 bytes to follow ACPI specification.\r
   # @Prompt Default OEM ID for ACPI table creation.\r
   gEfiMdeModulePkgTokenSpaceGuid.PcdAcpiDefaultOemId|"INTEL "|VOID*|0x30001034\r
index 032d1c7..f718b3e 100644 (file)
 \r
   MdeModulePkg/Universal/FvSimpleFileSystemDxe/FvSimpleFileSystemDxe.inf\r
   MdeModulePkg/Universal/EsrtDxe/EsrtDxe.inf\r
+  \r
+  MdeModulePkg/Universal/PropertiesTableAttributesDxe/PropertiesTableAttributesDxe.inf\r
 \r
 [Components.IA32, Components.X64, Components.IPF]  \r
   MdeModulePkg/Universal/Network/UefiPxeBcDxe/UefiPxeBcDxe.inf\r
diff --git a/MdeModulePkg/Universal/PropertiesTableAttributesDxe/PropertiesTableAttributesDxe.c b/MdeModulePkg/Universal/PropertiesTableAttributesDxe/PropertiesTableAttributesDxe.c
new file mode 100644 (file)
index 0000000..12e4566
--- /dev/null
@@ -0,0 +1,206 @@
+/**@file\r
+  This module sets default policy for attributes of EfiACPIMemoryNVS and EfiReservedMemoryType.\r
+\r
+  This module sets EFI_MEMORY_XP for attributes of EfiACPIMemoryNVS and EfiReservedMemoryType\r
+  in UEFI memory map, if and only of PropertiesTable is published and has BIT0 set.\r
+\r
+Copyright (c) 2015, Intel Corporation. All rights reserved.<BR>\r
+This program and the accompanying materials\r
+are licensed and made available under the terms and conditions of the BSD License\r
+which accompanies this distribution.  The full text of the license may be found at\r
+http://opensource.org/licenses/bsd-license.php\r
+\r
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+\r
+**/\r
+\r
+#include <Uefi.h>\r
+#include <Library/DebugLib.h>\r
+#include <Library/UefiBootServicesTableLib.h>\r
+#include <Library/DxeServicesTableLib.h>\r
+#include <Library/UefiLib.h>\r
+#include <Library/MemoryAllocationLib.h>\r
+#include <Guid/EventGroup.h>\r
+#include <Guid/PropertiesTable.h>\r
+\r
+/**\r
+  Converts a number of EFI_PAGEs to a size in bytes.\r
+\r
+  NOTE: Do not use EFI_PAGES_TO_SIZE because it handles UINTN only.\r
+\r
+  @param  Pages     The number of EFI_PAGES.\r
+\r
+  @return  The number of bytes associated with the number of EFI_PAGEs specified\r
+           by Pages.\r
+**/\r
+UINT64\r
+EfiPagesToSize (\r
+  IN UINT64 Pages\r
+  )\r
+{\r
+  return LShiftU64 (Pages, EFI_PAGE_SHIFT);\r
+}\r
+\r
+/**\r
+  Set memory attributes according to default policy.\r
+\r
+  @param  MemoryMap        A pointer to the buffer in which firmware places the current memory map.\r
+  @param  MemoryMapSize    Size, in bytes, of the MemoryMap buffer.\r
+  @param  DescriptorSize   size, in bytes, of an individual EFI_MEMORY_DESCRIPTOR.\r
+**/\r
+VOID\r
+SetMemorySpaceAttributesDefault (\r
+  IN EFI_MEMORY_DESCRIPTOR  *MemoryMap,\r
+  IN UINTN                  MemoryMapSize,\r
+  IN UINTN                  DescriptorSize\r
+  )\r
+{\r
+  EFI_MEMORY_DESCRIPTOR       *MemoryMapEntry;\r
+  EFI_MEMORY_DESCRIPTOR       *MemoryMapEnd;\r
+  EFI_STATUS                  Status;\r
+\r
+  DEBUG ((EFI_D_INFO, "SetMemorySpaceAttributesDefault\n"));\r
+\r
+  MemoryMapEntry = MemoryMap;\r
+  MemoryMapEnd   = (EFI_MEMORY_DESCRIPTOR *) ((UINT8 *) MemoryMap + MemoryMapSize);\r
+  while ((UINTN)MemoryMapEntry < (UINTN)MemoryMapEnd) {\r
+    if (MemoryMapEntry->PhysicalStart < BASE_1MB) {\r
+      //\r
+      // Do not touch memory space below 1MB\r
+      //\r
+      MemoryMapEntry = NEXT_MEMORY_DESCRIPTOR (MemoryMapEntry, DescriptorSize);\r
+      continue;\r
+    }\r
+    switch (MemoryMapEntry->Type) {\r
+    case EfiRuntimeServicesCode:\r
+    case EfiRuntimeServicesData:\r
+      //\r
+      // should be handled later;\r
+      //\r
+      break;\r
+    case EfiReservedMemoryType:\r
+    case EfiACPIMemoryNVS:\r
+      //\r
+      // Handle EfiReservedMemoryType and EfiACPIMemoryNVS, because there might be firmware executable there.\r
+      //\r
+      DEBUG ((EFI_D_INFO, "SetMemorySpaceAttributes - %016lx - %016lx (%016lx) ...\n",\r
+        MemoryMapEntry->PhysicalStart,\r
+        MemoryMapEntry->PhysicalStart + EfiPagesToSize (MemoryMapEntry->NumberOfPages),\r
+        MemoryMapEntry->Attribute\r
+        ));\r
+      Status = gDS->SetMemorySpaceCapabilities (\r
+                      MemoryMapEntry->PhysicalStart,\r
+                      EfiPagesToSize (MemoryMapEntry->NumberOfPages),\r
+                      MemoryMapEntry->Attribute | EFI_MEMORY_XP\r
+                      );\r
+      DEBUG ((EFI_D_INFO, "SetMemorySpaceCapabilities - %r\n", Status));\r
+      break;\r
+    }\r
+\r
+    MemoryMapEntry = NEXT_MEMORY_DESCRIPTOR (MemoryMapEntry, DescriptorSize);\r
+  }\r
+\r
+  return ;\r
+}\r
+\r
+/**\r
+  Update memory attributes according to default policy.\r
+\r
+  @param[in]  Event     The Event this notify function registered to.\r
+  @param[in]  Context   Pointer to the context data registered to the Event.\r
+**/\r
+VOID\r
+EFIAPI\r
+UpdateMemoryAttributesDefault (\r
+  EFI_EVENT                               Event,\r
+  VOID                                    *Context\r
+  )\r
+{\r
+  EFI_STATUS                  Status;\r
+  EFI_MEMORY_DESCRIPTOR       *MemoryMap;\r
+  UINTN                       MemoryMapSize;\r
+  UINTN                       MapKey;\r
+  UINTN                       DescriptorSize;\r
+  UINT32                      DescriptorVersion;\r
+  EFI_PROPERTIES_TABLE        *PropertiesTable;\r
+\r
+  DEBUG ((EFI_D_INFO, "UpdateMemoryAttributesDefault\n"));\r
+  Status = EfiGetSystemConfigurationTable (&gEfiPropertiesTableGuid, &PropertiesTable);\r
+  if (EFI_ERROR (Status)) {\r
+    goto Done;\r
+  }\r
+\r
+  DEBUG ((EFI_D_INFO, "MemoryProtectionAttribute - 0x%016lx\n", PropertiesTable->MemoryProtectionAttribute));\r
+  if ((PropertiesTable->MemoryProtectionAttribute & EFI_PROPERTIES_RUNTIME_MEMORY_PROTECTION_NON_EXECUTABLE_PE_DATA) == 0) {\r
+    goto Done;\r
+  }\r
+\r
+  //\r
+  // Get the EFI memory map.\r
+  //\r
+  MemoryMapSize  = 0;\r
+  MemoryMap      = NULL;\r
+  Status = gBS->GetMemoryMap (\r
+                  &MemoryMapSize,\r
+                  MemoryMap,\r
+                  &MapKey,\r
+                  &DescriptorSize,\r
+                  &DescriptorVersion\r
+                  );\r
+  ASSERT (Status == EFI_BUFFER_TOO_SMALL);\r
+  do {\r
+    MemoryMap = (EFI_MEMORY_DESCRIPTOR *) AllocatePool (MemoryMapSize);\r
+    ASSERT (MemoryMap != NULL);\r
+    Status = gBS->GetMemoryMap (\r
+                    &MemoryMapSize,\r
+                    MemoryMap,\r
+                    &MapKey,\r
+                    &DescriptorSize,\r
+                    &DescriptorVersion\r
+                    );\r
+    if (EFI_ERROR (Status)) {\r
+      FreePool (MemoryMap);\r
+    }\r
+  } while (Status == EFI_BUFFER_TOO_SMALL);\r
+  ASSERT_EFI_ERROR (Status);\r
+\r
+  SetMemorySpaceAttributesDefault (MemoryMap, MemoryMapSize, DescriptorSize);\r
+\r
+Done:\r
+  gBS->CloseEvent (Event);\r
+\r
+  return ;\r
+}\r
+\r
+/**\r
+  The entrypoint of properties table attribute driver.\r
+\r
+  @param  ImageHandle    The firmware allocated handle for the EFI image.\r
+  @param  SystemTable    A pointer to the EFI System Table.\r
+\r
+  @retval EFI_SUCCESS    It always returns EFI_SUCCESS.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+InitializePropertiesTableAttributesDxe (\r
+  IN EFI_HANDLE        ImageHandle,\r
+  IN EFI_SYSTEM_TABLE  *SystemTable\r
+  )\r
+{\r
+  EFI_STATUS  Status;\r
+  EFI_EVENT   ReadyToBootEvent;\r
+\r
+  Status = gBS->CreateEventEx (\r
+                  EVT_NOTIFY_SIGNAL,\r
+                  TPL_CALLBACK,\r
+                  UpdateMemoryAttributesDefault,\r
+                  NULL,\r
+                  &gEfiEventReadyToBootGuid,\r
+                  &ReadyToBootEvent\r
+                  );\r
+  ASSERT_EFI_ERROR (Status);\r
+\r
+  return EFI_SUCCESS;\r
+}\r
diff --git a/MdeModulePkg/Universal/PropertiesTableAttributesDxe/PropertiesTableAttributesDxe.inf b/MdeModulePkg/Universal/PropertiesTableAttributesDxe/PropertiesTableAttributesDxe.inf
new file mode 100644 (file)
index 0000000..7b3025a
--- /dev/null
@@ -0,0 +1,57 @@
+## @file\r
+#\r
+# This module sets default policy for attributes of EfiACPIMemoryNVS and EfiReservedMemoryType.\r
+#\r
+# This module sets EFI_MEMORY_XP for attributes of EfiACPIMemoryNVS and EfiReservedMemoryType\r
+# in UEFI memory map, if and only of PropertiesTable is published and has BIT0 set.\r
+#\r
+# Copyright (c) 2015, Intel Corporation. All rights reserved.<BR>\r
+#\r
+#  This program and the accompanying materials\r
+#  are licensed and made available under the terms and conditions of the BSD License\r
+#  which accompanies this distribution. The full text of the license may be found at\r
+#  http://opensource.org/licenses/bsd-license.php\r
+#  THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
+#  WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+#\r
+#\r
+##\r
+\r
+[Defines]\r
+  INF_VERSION                    = 0x00010005\r
+  BASE_NAME                      = PropertiesTableAttributesDxe\r
+  MODULE_UNI_FILE                = PropertiesTableAttributesDxe.uni\r
+  FILE_GUID                      = AA48FBB2-9F87-4DFD-B416-575938F0C8F4\r
+  MODULE_TYPE                    = DXE_DRIVER\r
+  VERSION_STRING                 = 1.0\r
+  ENTRY_POINT                    = InitializePropertiesTableAttributesDxe\r
+\r
+#\r
+# The following information is for reference only and not required by the build tools.\r
+#\r
+#  VALID_ARCHITECTURES           = IA32 X64 IPF EBC\r
+#\r
+\r
+[Sources]\r
+  PropertiesTableAttributesDxe.c\r
+\r
+[Packages]\r
+  MdePkg/MdePkg.dec\r
+\r
+[LibraryClasses]\r
+  UefiDriverEntryPoint\r
+  UefiBootServicesTableLib\r
+  DxeServicesTableLib\r
+  DebugLib\r
+  UefiLib\r
+  MemoryAllocationLib\r
+\r
+[Guids]\r
+  gEfiEventReadyToBootGuid                      ## CONSUMES ## Event\r
+  gEfiPropertiesTableGuid                       ## CONSUMES ## SystemTable\r
+\r
+[Depex]\r
+  TRUE\r
+\r
+[UserExtensions.TianoCore."ExtraFiles"]\r
+  PropertiesTableAttributesDxeExtra.uni\r
diff --git a/MdeModulePkg/Universal/PropertiesTableAttributesDxe/PropertiesTableAttributesDxe.uni b/MdeModulePkg/Universal/PropertiesTableAttributesDxe/PropertiesTableAttributesDxe.uni
new file mode 100644 (file)
index 0000000..e413fe6
Binary files /dev/null and b/MdeModulePkg/Universal/PropertiesTableAttributesDxe/PropertiesTableAttributesDxe.uni differ
diff --git a/MdeModulePkg/Universal/PropertiesTableAttributesDxe/PropertiesTableAttributesDxeExtra.uni b/MdeModulePkg/Universal/PropertiesTableAttributesDxe/PropertiesTableAttributesDxeExtra.uni
new file mode 100644 (file)
index 0000000..24841aa
Binary files /dev/null and b/MdeModulePkg/Universal/PropertiesTableAttributesDxe/PropertiesTableAttributesDxeExtra.uni differ