Home | History | Annotate | Download | only in Misc
      1 /** @file
      2   UEFI PropertiesTable support
      3 
      4 Copyright (c) 2015 - 2016, Intel Corporation. All rights reserved.<BR>
      5 This program and the accompanying materials
      6 are licensed and made available under the terms and conditions of the BSD License
      7 which accompanies this distribution.  The full text of the license may be found at
      8 http://opensource.org/licenses/bsd-license.php
      9 
     10 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
     11 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
     12 
     13 **/
     14 
     15 #include <PiDxe.h>
     16 #include <Library/BaseLib.h>
     17 #include <Library/BaseMemoryLib.h>
     18 #include <Library/MemoryAllocationLib.h>
     19 #include <Library/UefiBootServicesTableLib.h>
     20 #include <Library/DxeServicesTableLib.h>
     21 #include <Library/DebugLib.h>
     22 #include <Library/UefiLib.h>
     23 #include <Library/PcdLib.h>
     24 
     25 #include <Guid/EventGroup.h>
     26 #include <Protocol/DxeSmmReadyToLock.h>
     27 
     28 #include <Library/PeCoffLib.h>
     29 #include <Library/PeCoffGetEntryPointLib.h>
     30 #include <Protocol/Runtime.h>
     31 
     32 #include <Guid/PropertiesTable.h>
     33 
     34 #include "DxeMain.h"
     35 
     36 #define PREVIOUS_MEMORY_DESCRIPTOR(MemoryDescriptor, Size) \
     37   ((EFI_MEMORY_DESCRIPTOR *)((UINT8 *)(MemoryDescriptor) - (Size)))
     38 
     39 #define IMAGE_PROPERTIES_RECORD_CODE_SECTION_SIGNATURE SIGNATURE_32 ('I','P','R','C')
     40 
     41 typedef struct {
     42   UINT32                 Signature;
     43   LIST_ENTRY             Link;
     44   EFI_PHYSICAL_ADDRESS   CodeSegmentBase;
     45   UINT64                 CodeSegmentSize;
     46 } IMAGE_PROPERTIES_RECORD_CODE_SECTION;
     47 
     48 #define IMAGE_PROPERTIES_RECORD_SIGNATURE SIGNATURE_32 ('I','P','R','D')
     49 
     50 typedef struct {
     51   UINT32                 Signature;
     52   LIST_ENTRY             Link;
     53   EFI_PHYSICAL_ADDRESS   ImageBase;
     54   UINT64                 ImageSize;
     55   UINTN                  CodeSegmentCount;
     56   LIST_ENTRY             CodeSegmentList;
     57 } IMAGE_PROPERTIES_RECORD;
     58 
     59 #define IMAGE_PROPERTIES_PRIVATE_DATA_SIGNATURE SIGNATURE_32 ('I','P','P','D')
     60 
     61 typedef struct {
     62   UINT32                 Signature;
     63   UINTN                  ImageRecordCount;
     64   UINTN                  CodeSegmentCountMax;
     65   LIST_ENTRY             ImageRecordList;
     66 } IMAGE_PROPERTIES_PRIVATE_DATA;
     67 
     68 IMAGE_PROPERTIES_PRIVATE_DATA  mImagePropertiesPrivateData = {
     69   IMAGE_PROPERTIES_PRIVATE_DATA_SIGNATURE,
     70   0,
     71   0,
     72   INITIALIZE_LIST_HEAD_VARIABLE (mImagePropertiesPrivateData.ImageRecordList)
     73 };
     74 
     75 EFI_PROPERTIES_TABLE  mPropertiesTable = {
     76   EFI_PROPERTIES_TABLE_VERSION,
     77   sizeof(EFI_PROPERTIES_TABLE),
     78   EFI_PROPERTIES_RUNTIME_MEMORY_PROTECTION_NON_EXECUTABLE_PE_DATA
     79 };
     80 
     81 EFI_LOCK           mPropertiesTableLock = EFI_INITIALIZE_LOCK_VARIABLE (TPL_NOTIFY);
     82 
     83 BOOLEAN            mPropertiesTableEnable;
     84 
     85 //
     86 // Below functions are for MemoryMap
     87 //
     88 
     89 /**
     90   Converts a number of EFI_PAGEs to a size in bytes.
     91 
     92   NOTE: Do not use EFI_PAGES_TO_SIZE because it handles UINTN only.
     93 
     94   @param  Pages     The number of EFI_PAGES.
     95 
     96   @return  The number of bytes associated with the number of EFI_PAGEs specified
     97            by Pages.
     98 **/
     99 STATIC
    100 UINT64
    101 EfiPagesToSize (
    102   IN UINT64 Pages
    103   )
    104 {
    105   return LShiftU64 (Pages, EFI_PAGE_SHIFT);
    106 }
    107 
    108 /**
    109   Converts a size, in bytes, to a number of EFI_PAGESs.
    110 
    111   NOTE: Do not use EFI_SIZE_TO_PAGES because it handles UINTN only.
    112 
    113   @param  Size      A size in bytes.
    114 
    115   @return  The number of EFI_PAGESs associated with the number of bytes specified
    116            by Size.
    117 
    118 **/
    119 STATIC
    120 UINT64
    121 EfiSizeToPages (
    122   IN UINT64 Size
    123   )
    124 {
    125   return RShiftU64 (Size, EFI_PAGE_SHIFT) + ((((UINTN)Size) & EFI_PAGE_MASK) ? 1 : 0);
    126 }
    127 
    128 /**
    129   Acquire memory lock on mPropertiesTableLock.
    130 **/
    131 STATIC
    132 VOID
    133 CoreAcquirePropertiesTableLock (
    134   VOID
    135   )
    136 {
    137   CoreAcquireLock (&mPropertiesTableLock);
    138 }
    139 
    140 /**
    141   Release memory lock on mPropertiesTableLock.
    142 **/
    143 STATIC
    144 VOID
    145 CoreReleasePropertiesTableLock (
    146   VOID
    147   )
    148 {
    149   CoreReleaseLock (&mPropertiesTableLock);
    150 }
    151 
    152 /**
    153   Sort memory map entries based upon PhysicalStart, from low to high.
    154 
    155   @param  MemoryMap              A pointer to the buffer in which firmware places
    156                                  the current memory map.
    157   @param  MemoryMapSize          Size, in bytes, of the MemoryMap buffer.
    158   @param  DescriptorSize         Size, in bytes, of an individual EFI_MEMORY_DESCRIPTOR.
    159 **/
    160 STATIC
    161 VOID
    162 SortMemoryMap (
    163   IN OUT EFI_MEMORY_DESCRIPTOR  *MemoryMap,
    164   IN UINTN                      MemoryMapSize,
    165   IN UINTN                      DescriptorSize
    166   )
    167 {
    168   EFI_MEMORY_DESCRIPTOR       *MemoryMapEntry;
    169   EFI_MEMORY_DESCRIPTOR       *NextMemoryMapEntry;
    170   EFI_MEMORY_DESCRIPTOR       *MemoryMapEnd;
    171   EFI_MEMORY_DESCRIPTOR       TempMemoryMap;
    172 
    173   MemoryMapEntry = MemoryMap;
    174   NextMemoryMapEntry = NEXT_MEMORY_DESCRIPTOR (MemoryMapEntry, DescriptorSize);
    175   MemoryMapEnd = (EFI_MEMORY_DESCRIPTOR *) ((UINT8 *) MemoryMap + MemoryMapSize);
    176   while (MemoryMapEntry < MemoryMapEnd) {
    177     while (NextMemoryMapEntry < MemoryMapEnd) {
    178       if (MemoryMapEntry->PhysicalStart > NextMemoryMapEntry->PhysicalStart) {
    179         CopyMem (&TempMemoryMap, MemoryMapEntry, sizeof(EFI_MEMORY_DESCRIPTOR));
    180         CopyMem (MemoryMapEntry, NextMemoryMapEntry, sizeof(EFI_MEMORY_DESCRIPTOR));
    181         CopyMem (NextMemoryMapEntry, &TempMemoryMap, sizeof(EFI_MEMORY_DESCRIPTOR));
    182       }
    183 
    184       NextMemoryMapEntry = NEXT_MEMORY_DESCRIPTOR (NextMemoryMapEntry, DescriptorSize);
    185     }
    186 
    187     MemoryMapEntry      = NEXT_MEMORY_DESCRIPTOR (MemoryMapEntry, DescriptorSize);
    188     NextMemoryMapEntry  = NEXT_MEMORY_DESCRIPTOR (MemoryMapEntry, DescriptorSize);
    189   }
    190 
    191   return ;
    192 }
    193 
    194 /**
    195   Merge continous memory map entries whose have same attributes.
    196 
    197   @param  MemoryMap              A pointer to the buffer in which firmware places
    198                                  the current memory map.
    199   @param  MemoryMapSize          A pointer to the size, in bytes, of the
    200                                  MemoryMap buffer. On input, this is the size of
    201                                  the current memory map.  On output,
    202                                  it is the size of new memory map after merge.
    203   @param  DescriptorSize         Size, in bytes, of an individual EFI_MEMORY_DESCRIPTOR.
    204 **/
    205 STATIC
    206 VOID
    207 MergeMemoryMap (
    208   IN OUT EFI_MEMORY_DESCRIPTOR  *MemoryMap,
    209   IN OUT UINTN                  *MemoryMapSize,
    210   IN UINTN                      DescriptorSize
    211   )
    212 {
    213   EFI_MEMORY_DESCRIPTOR       *MemoryMapEntry;
    214   EFI_MEMORY_DESCRIPTOR       *MemoryMapEnd;
    215   UINT64                      MemoryBlockLength;
    216   EFI_MEMORY_DESCRIPTOR       *NewMemoryMapEntry;
    217   EFI_MEMORY_DESCRIPTOR       *NextMemoryMapEntry;
    218 
    219   MemoryMapEntry = MemoryMap;
    220   NewMemoryMapEntry = MemoryMap;
    221   MemoryMapEnd = (EFI_MEMORY_DESCRIPTOR *) ((UINT8 *) MemoryMap + *MemoryMapSize);
    222   while ((UINTN)MemoryMapEntry < (UINTN)MemoryMapEnd) {
    223     CopyMem (NewMemoryMapEntry, MemoryMapEntry, sizeof(EFI_MEMORY_DESCRIPTOR));
    224     NextMemoryMapEntry = NEXT_MEMORY_DESCRIPTOR (MemoryMapEntry, DescriptorSize);
    225 
    226     do {
    227       MemoryBlockLength = (UINT64) (EfiPagesToSize (MemoryMapEntry->NumberOfPages));
    228       if (((UINTN)NextMemoryMapEntry < (UINTN)MemoryMapEnd) &&
    229           (MemoryMapEntry->Type == NextMemoryMapEntry->Type) &&
    230           (MemoryMapEntry->Attribute == NextMemoryMapEntry->Attribute) &&
    231           ((MemoryMapEntry->PhysicalStart + MemoryBlockLength) == NextMemoryMapEntry->PhysicalStart)) {
    232         MemoryMapEntry->NumberOfPages += NextMemoryMapEntry->NumberOfPages;
    233         if (NewMemoryMapEntry != MemoryMapEntry) {
    234           NewMemoryMapEntry->NumberOfPages += NextMemoryMapEntry->NumberOfPages;
    235         }
    236 
    237         NextMemoryMapEntry = NEXT_MEMORY_DESCRIPTOR (NextMemoryMapEntry, DescriptorSize);
    238         continue;
    239       } else {
    240         MemoryMapEntry = PREVIOUS_MEMORY_DESCRIPTOR (NextMemoryMapEntry, DescriptorSize);
    241         break;
    242       }
    243     } while (TRUE);
    244 
    245     MemoryMapEntry = NEXT_MEMORY_DESCRIPTOR (MemoryMapEntry, DescriptorSize);
    246     NewMemoryMapEntry = NEXT_MEMORY_DESCRIPTOR (NewMemoryMapEntry, DescriptorSize);
    247   }
    248 
    249   *MemoryMapSize = (UINTN)NewMemoryMapEntry - (UINTN)MemoryMap;
    250 
    251   return ;
    252 }
    253 
    254 /**
    255   Enforce memory map attributes.
    256   This function will set EfiRuntimeServicesData/EfiMemoryMappedIO/EfiMemoryMappedIOPortSpace to be EFI_MEMORY_XP.
    257 
    258   @param  MemoryMap              A pointer to the buffer in which firmware places
    259                                  the current memory map.
    260   @param  MemoryMapSize          Size, in bytes, of the MemoryMap buffer.
    261   @param  DescriptorSize         Size, in bytes, of an individual EFI_MEMORY_DESCRIPTOR.
    262 **/
    263 STATIC
    264 VOID
    265 EnforceMemoryMapAttribute (
    266   IN OUT EFI_MEMORY_DESCRIPTOR  *MemoryMap,
    267   IN UINTN                      MemoryMapSize,
    268   IN UINTN                      DescriptorSize
    269   )
    270 {
    271   EFI_MEMORY_DESCRIPTOR       *MemoryMapEntry;
    272   EFI_MEMORY_DESCRIPTOR       *MemoryMapEnd;
    273 
    274   MemoryMapEntry = MemoryMap;
    275   MemoryMapEnd   = (EFI_MEMORY_DESCRIPTOR *) ((UINT8 *) MemoryMap + MemoryMapSize);
    276   while ((UINTN)MemoryMapEntry < (UINTN)MemoryMapEnd) {
    277     switch (MemoryMapEntry->Type) {
    278     case EfiRuntimeServicesCode:
    279       // do nothing
    280       break;
    281     case EfiRuntimeServicesData:
    282     case EfiMemoryMappedIO:
    283     case EfiMemoryMappedIOPortSpace:
    284       MemoryMapEntry->Attribute |= EFI_MEMORY_XP;
    285       break;
    286     case EfiReservedMemoryType:
    287     case EfiACPIMemoryNVS:
    288       break;
    289     }
    290 
    291     MemoryMapEntry = NEXT_MEMORY_DESCRIPTOR (MemoryMapEntry, DescriptorSize);
    292   }
    293 
    294   return ;
    295 }
    296 
    297 /**
    298   Return the first image record, whose [ImageBase, ImageSize] covered by [Buffer, Length].
    299 
    300   @param Buffer  Start Address
    301   @param Length  Address length
    302 
    303   @return first image record covered by [buffer, length]
    304 **/
    305 STATIC
    306 IMAGE_PROPERTIES_RECORD *
    307 GetImageRecordByAddress (
    308   IN EFI_PHYSICAL_ADDRESS  Buffer,
    309   IN UINT64                Length
    310   )
    311 {
    312   IMAGE_PROPERTIES_RECORD    *ImageRecord;
    313   LIST_ENTRY                 *ImageRecordLink;
    314   LIST_ENTRY                 *ImageRecordList;
    315 
    316   ImageRecordList = &mImagePropertiesPrivateData.ImageRecordList;
    317 
    318   for (ImageRecordLink = ImageRecordList->ForwardLink;
    319        ImageRecordLink != ImageRecordList;
    320        ImageRecordLink = ImageRecordLink->ForwardLink) {
    321     ImageRecord = CR (
    322                     ImageRecordLink,
    323                     IMAGE_PROPERTIES_RECORD,
    324                     Link,
    325                     IMAGE_PROPERTIES_RECORD_SIGNATURE
    326                     );
    327 
    328     if ((Buffer <= ImageRecord->ImageBase) &&
    329         (Buffer + Length >= ImageRecord->ImageBase + ImageRecord->ImageSize)) {
    330       return ImageRecord;
    331     }
    332   }
    333 
    334   return NULL;
    335 }
    336 
    337 /**
    338   Set the memory map to new entries, according to one old entry,
    339   based upon PE code section and data section in image record
    340 
    341   @param  ImageRecord            An image record whose [ImageBase, ImageSize] covered
    342                                  by old memory map entry.
    343   @param  NewRecord              A pointer to several new memory map entries.
    344                                  The caller gurantee the buffer size be 1 +
    345                                  (SplitRecordCount * DescriptorSize) calculated
    346                                  below.
    347   @param  OldRecord              A pointer to one old memory map entry.
    348   @param  DescriptorSize         Size, in bytes, of an individual EFI_MEMORY_DESCRIPTOR.
    349 **/
    350 STATIC
    351 UINTN
    352 SetNewRecord (
    353   IN IMAGE_PROPERTIES_RECORD       *ImageRecord,
    354   IN OUT EFI_MEMORY_DESCRIPTOR     *NewRecord,
    355   IN EFI_MEMORY_DESCRIPTOR         *OldRecord,
    356   IN UINTN                         DescriptorSize
    357   )
    358 {
    359   EFI_MEMORY_DESCRIPTOR                     TempRecord;
    360   IMAGE_PROPERTIES_RECORD_CODE_SECTION      *ImageRecordCodeSection;
    361   LIST_ENTRY                                *ImageRecordCodeSectionLink;
    362   LIST_ENTRY                                *ImageRecordCodeSectionEndLink;
    363   LIST_ENTRY                                *ImageRecordCodeSectionList;
    364   UINTN                                     NewRecordCount;
    365   UINT64                                    PhysicalEnd;
    366   UINT64                                    ImageEnd;
    367 
    368   CopyMem (&TempRecord, OldRecord, sizeof(EFI_MEMORY_DESCRIPTOR));
    369   PhysicalEnd = TempRecord.PhysicalStart + EfiPagesToSize(TempRecord.NumberOfPages);
    370   NewRecordCount = 0;
    371 
    372   ImageRecordCodeSectionList = &ImageRecord->CodeSegmentList;
    373 
    374   ImageRecordCodeSectionLink = ImageRecordCodeSectionList->ForwardLink;
    375   ImageRecordCodeSectionEndLink = ImageRecordCodeSectionList;
    376   while (ImageRecordCodeSectionLink != ImageRecordCodeSectionEndLink) {
    377     ImageRecordCodeSection = CR (
    378                                ImageRecordCodeSectionLink,
    379                                IMAGE_PROPERTIES_RECORD_CODE_SECTION,
    380                                Link,
    381                                IMAGE_PROPERTIES_RECORD_CODE_SECTION_SIGNATURE
    382                                );
    383     ImageRecordCodeSectionLink = ImageRecordCodeSectionLink->ForwardLink;
    384 
    385     if (TempRecord.PhysicalStart <= ImageRecordCodeSection->CodeSegmentBase) {
    386       //
    387       // DATA
    388       //
    389       if (!mPropertiesTableEnable) {
    390         NewRecord->Type = TempRecord.Type;
    391       } else {
    392         NewRecord->Type = EfiRuntimeServicesData;
    393       }
    394       NewRecord->PhysicalStart = TempRecord.PhysicalStart;
    395       NewRecord->VirtualStart  = 0;
    396       NewRecord->NumberOfPages = EfiSizeToPages(ImageRecordCodeSection->CodeSegmentBase - NewRecord->PhysicalStart);
    397       NewRecord->Attribute     = TempRecord.Attribute | EFI_MEMORY_XP;
    398       if (NewRecord->NumberOfPages != 0) {
    399         NewRecord = NEXT_MEMORY_DESCRIPTOR (NewRecord, DescriptorSize);
    400         NewRecordCount ++;
    401       }
    402 
    403       //
    404       // CODE
    405       //
    406       if (!mPropertiesTableEnable) {
    407         NewRecord->Type = TempRecord.Type;
    408       } else {
    409         NewRecord->Type = EfiRuntimeServicesCode;
    410       }
    411       NewRecord->PhysicalStart = ImageRecordCodeSection->CodeSegmentBase;
    412       NewRecord->VirtualStart  = 0;
    413       NewRecord->NumberOfPages = EfiSizeToPages(ImageRecordCodeSection->CodeSegmentSize);
    414       NewRecord->Attribute     = (TempRecord.Attribute & (~EFI_MEMORY_XP)) | EFI_MEMORY_RO;
    415       if (NewRecord->NumberOfPages != 0) {
    416         NewRecord = NEXT_MEMORY_DESCRIPTOR (NewRecord, DescriptorSize);
    417         NewRecordCount ++;
    418       }
    419 
    420       TempRecord.PhysicalStart = ImageRecordCodeSection->CodeSegmentBase + EfiPagesToSize (EfiSizeToPages(ImageRecordCodeSection->CodeSegmentSize));
    421       TempRecord.NumberOfPages = EfiSizeToPages(PhysicalEnd - TempRecord.PhysicalStart);
    422       if (TempRecord.NumberOfPages == 0) {
    423         break;
    424       }
    425     }
    426   }
    427 
    428   ImageEnd = ImageRecord->ImageBase + ImageRecord->ImageSize;
    429 
    430   //
    431   // Final DATA
    432   //
    433   if (TempRecord.PhysicalStart < ImageEnd) {
    434     if (!mPropertiesTableEnable) {
    435       NewRecord->Type = TempRecord.Type;
    436     } else {
    437       NewRecord->Type = EfiRuntimeServicesData;
    438     }
    439     NewRecord->PhysicalStart = TempRecord.PhysicalStart;
    440     NewRecord->VirtualStart  = 0;
    441     NewRecord->NumberOfPages = EfiSizeToPages (ImageEnd - TempRecord.PhysicalStart);
    442     NewRecord->Attribute     = TempRecord.Attribute | EFI_MEMORY_XP;
    443     NewRecordCount ++;
    444   }
    445 
    446   return NewRecordCount;
    447 }
    448 
    449 /**
    450   Return the max number of new splitted entries, according to one old entry,
    451   based upon PE code section and data section.
    452 
    453   @param  OldRecord              A pointer to one old memory map entry.
    454 
    455   @retval  0 no entry need to be splitted.
    456   @return  the max number of new splitted entries
    457 **/
    458 STATIC
    459 UINTN
    460 GetMaxSplitRecordCount (
    461   IN EFI_MEMORY_DESCRIPTOR *OldRecord
    462   )
    463 {
    464   IMAGE_PROPERTIES_RECORD *ImageRecord;
    465   UINTN                   SplitRecordCount;
    466   UINT64                  PhysicalStart;
    467   UINT64                  PhysicalEnd;
    468 
    469   SplitRecordCount = 0;
    470   PhysicalStart = OldRecord->PhysicalStart;
    471   PhysicalEnd = OldRecord->PhysicalStart + EfiPagesToSize(OldRecord->NumberOfPages);
    472 
    473   do {
    474     ImageRecord = GetImageRecordByAddress (PhysicalStart, PhysicalEnd - PhysicalStart);
    475     if (ImageRecord == NULL) {
    476       break;
    477     }
    478     SplitRecordCount += (2 * ImageRecord->CodeSegmentCount + 1);
    479     PhysicalStart = ImageRecord->ImageBase + ImageRecord->ImageSize;
    480   } while ((ImageRecord != NULL) && (PhysicalStart < PhysicalEnd));
    481 
    482   if (SplitRecordCount != 0) {
    483     SplitRecordCount--;
    484   }
    485 
    486   return SplitRecordCount;
    487 }
    488 
    489 /**
    490   Split the memory map to new entries, according to one old entry,
    491   based upon PE code section and data section.
    492 
    493   @param  OldRecord              A pointer to one old memory map entry.
    494   @param  NewRecord              A pointer to several new memory map entries.
    495                                  The caller gurantee the buffer size be 1 +
    496                                  (SplitRecordCount * DescriptorSize) calculated
    497                                  below.
    498   @param  MaxSplitRecordCount    The max number of splitted entries
    499   @param  DescriptorSize         Size, in bytes, of an individual EFI_MEMORY_DESCRIPTOR.
    500 
    501   @retval  0 no entry is splitted.
    502   @return  the real number of splitted record.
    503 **/
    504 STATIC
    505 UINTN
    506 SplitRecord (
    507   IN EFI_MEMORY_DESCRIPTOR     *OldRecord,
    508   IN OUT EFI_MEMORY_DESCRIPTOR *NewRecord,
    509   IN UINTN                     MaxSplitRecordCount,
    510   IN UINTN                     DescriptorSize
    511   )
    512 {
    513   EFI_MEMORY_DESCRIPTOR   TempRecord;
    514   IMAGE_PROPERTIES_RECORD *ImageRecord;
    515   IMAGE_PROPERTIES_RECORD *NewImageRecord;
    516   UINT64                  PhysicalStart;
    517   UINT64                  PhysicalEnd;
    518   UINTN                   NewRecordCount;
    519   UINTN                   TotalNewRecordCount;
    520   BOOLEAN                 IsLastRecordData;
    521 
    522   if (MaxSplitRecordCount == 0) {
    523     CopyMem (NewRecord, OldRecord, DescriptorSize);
    524     return 0;
    525   }
    526 
    527   TotalNewRecordCount = 0;
    528 
    529   //
    530   // Override previous record
    531   //
    532   CopyMem (&TempRecord, OldRecord, sizeof(EFI_MEMORY_DESCRIPTOR));
    533   PhysicalStart = TempRecord.PhysicalStart;
    534   PhysicalEnd = TempRecord.PhysicalStart + EfiPagesToSize(TempRecord.NumberOfPages);
    535 
    536   ImageRecord = NULL;
    537   do {
    538     NewImageRecord = GetImageRecordByAddress (PhysicalStart, PhysicalEnd - PhysicalStart);
    539     if (NewImageRecord == NULL) {
    540       //
    541       // No more image covered by this range, stop
    542       //
    543       if ((PhysicalEnd > PhysicalStart) && (ImageRecord != NULL)) {
    544         //
    545         // If this is still address in this record, need record.
    546         //
    547         NewRecord = PREVIOUS_MEMORY_DESCRIPTOR (NewRecord, DescriptorSize);
    548         IsLastRecordData = FALSE;
    549         if (!mPropertiesTableEnable) {
    550           if ((NewRecord->Attribute & EFI_MEMORY_XP) != 0) {
    551             IsLastRecordData = TRUE;
    552           }
    553         } else {
    554           if (NewRecord->Type == EfiRuntimeServicesData) {
    555             IsLastRecordData = TRUE;
    556           }
    557         }
    558         if (IsLastRecordData) {
    559           //
    560           // Last record is DATA, just merge it.
    561           //
    562           NewRecord->NumberOfPages = EfiSizeToPages(PhysicalEnd - NewRecord->PhysicalStart);
    563         } else {
    564           //
    565           // Last record is CODE, create a new DATA entry.
    566           //
    567           NewRecord = NEXT_MEMORY_DESCRIPTOR (NewRecord, DescriptorSize);
    568           if (!mPropertiesTableEnable) {
    569             NewRecord->Type = TempRecord.Type;
    570           } else {
    571             NewRecord->Type = EfiRuntimeServicesData;
    572           }
    573           NewRecord->PhysicalStart = TempRecord.PhysicalStart;
    574           NewRecord->VirtualStart  = 0;
    575           NewRecord->NumberOfPages = TempRecord.NumberOfPages;
    576           NewRecord->Attribute     = TempRecord.Attribute | EFI_MEMORY_XP;
    577           TotalNewRecordCount ++;
    578         }
    579       }
    580       break;
    581     }
    582     ImageRecord = NewImageRecord;
    583 
    584     //
    585     // Set new record
    586     //
    587     NewRecordCount = SetNewRecord (ImageRecord, NewRecord, &TempRecord, DescriptorSize);
    588     TotalNewRecordCount += NewRecordCount;
    589     NewRecord = (EFI_MEMORY_DESCRIPTOR *)((UINT8 *)NewRecord + NewRecordCount * DescriptorSize);
    590 
    591     //
    592     // Update PhysicalStart, in order to exclude the image buffer already splitted.
    593     //
    594     PhysicalStart = ImageRecord->ImageBase + ImageRecord->ImageSize;
    595     TempRecord.PhysicalStart = PhysicalStart;
    596     TempRecord.NumberOfPages = EfiSizeToPages (PhysicalEnd - PhysicalStart);
    597   } while ((ImageRecord != NULL) && (PhysicalStart < PhysicalEnd));
    598 
    599   return TotalNewRecordCount - 1;
    600 }
    601 
    602 /**
    603   Split the original memory map, and add more entries to describe PE code section and data section.
    604   This function will set EfiRuntimeServicesData to be EFI_MEMORY_XP.
    605   This function will merge entries with same attributes finally.
    606 
    607   NOTE: It assumes PE code/data section are page aligned.
    608   NOTE: It assumes enough entry is prepared for new memory map.
    609 
    610   Split table:
    611    +---------------+
    612    | Record X      |
    613    +---------------+
    614    | Record RtCode |
    615    +---------------+
    616    | Record Y      |
    617    +---------------+
    618    ==>
    619    +---------------+
    620    | Record X      |
    621    +---------------+ ----
    622    | Record RtData |     |
    623    +---------------+     |
    624    | Record RtCode |     |-> PE/COFF1
    625    +---------------+     |
    626    | Record RtData |     |
    627    +---------------+ ----
    628    | Record RtData |     |
    629    +---------------+     |
    630    | Record RtCode |     |-> PE/COFF2
    631    +---------------+     |
    632    | Record RtData |     |
    633    +---------------+ ----
    634    | Record Y      |
    635    +---------------+
    636 
    637   @param  MemoryMapSize          A pointer to the size, in bytes, of the
    638                                  MemoryMap buffer. On input, this is the size of
    639                                  old MemoryMap before split. The actual buffer
    640                                  size of MemoryMap is MemoryMapSize +
    641                                  (AdditionalRecordCount * DescriptorSize) calculated
    642                                  below. On output, it is the size of new MemoryMap
    643                                  after split.
    644   @param  MemoryMap              A pointer to the buffer in which firmware places
    645                                  the current memory map.
    646   @param  DescriptorSize         Size, in bytes, of an individual EFI_MEMORY_DESCRIPTOR.
    647 **/
    648 STATIC
    649 VOID
    650 SplitTable (
    651   IN OUT UINTN                  *MemoryMapSize,
    652   IN OUT EFI_MEMORY_DESCRIPTOR  *MemoryMap,
    653   IN UINTN                      DescriptorSize
    654   )
    655 {
    656   INTN        IndexOld;
    657   INTN        IndexNew;
    658   UINTN       MaxSplitRecordCount;
    659   UINTN       RealSplitRecordCount;
    660   UINTN       TotalSplitRecordCount;
    661   UINTN       AdditionalRecordCount;
    662 
    663   AdditionalRecordCount = (2 * mImagePropertiesPrivateData.CodeSegmentCountMax + 1) * mImagePropertiesPrivateData.ImageRecordCount;
    664 
    665   TotalSplitRecordCount = 0;
    666   //
    667   // Let old record point to end of valid MemoryMap buffer.
    668   //
    669   IndexOld = ((*MemoryMapSize) / DescriptorSize) - 1;
    670   //
    671   // Let new record point to end of full MemoryMap buffer.
    672   //
    673   IndexNew = ((*MemoryMapSize) / DescriptorSize) - 1 + AdditionalRecordCount;
    674   for (; IndexOld >= 0; IndexOld--) {
    675     MaxSplitRecordCount = GetMaxSplitRecordCount ((EFI_MEMORY_DESCRIPTOR *)((UINT8 *)MemoryMap + IndexOld * DescriptorSize));
    676     //
    677     // Split this MemoryMap record
    678     //
    679     IndexNew -= MaxSplitRecordCount;
    680     RealSplitRecordCount = SplitRecord (
    681                              (EFI_MEMORY_DESCRIPTOR *)((UINT8 *)MemoryMap + IndexOld * DescriptorSize),
    682                              (EFI_MEMORY_DESCRIPTOR *)((UINT8 *)MemoryMap + IndexNew * DescriptorSize),
    683                              MaxSplitRecordCount,
    684                              DescriptorSize
    685                              );
    686     //
    687     // Adjust IndexNew according to real split.
    688     //
    689     CopyMem (
    690       ((UINT8 *)MemoryMap + (IndexNew + MaxSplitRecordCount - RealSplitRecordCount) * DescriptorSize),
    691       ((UINT8 *)MemoryMap + IndexNew * DescriptorSize),
    692       RealSplitRecordCount * DescriptorSize
    693       );
    694     IndexNew = IndexNew + MaxSplitRecordCount - RealSplitRecordCount;
    695     TotalSplitRecordCount += RealSplitRecordCount;
    696     IndexNew --;
    697   }
    698   //
    699   // Move all records to the beginning.
    700   //
    701   CopyMem (
    702     MemoryMap,
    703     (UINT8 *)MemoryMap + (AdditionalRecordCount - TotalSplitRecordCount) * DescriptorSize,
    704     (*MemoryMapSize) + TotalSplitRecordCount * DescriptorSize
    705     );
    706 
    707   *MemoryMapSize = (*MemoryMapSize) + DescriptorSize * TotalSplitRecordCount;
    708 
    709   //
    710   // Sort from low to high (Just in case)
    711   //
    712   SortMemoryMap (MemoryMap, *MemoryMapSize, DescriptorSize);
    713 
    714   //
    715   // Set RuntimeData to XP
    716   //
    717   EnforceMemoryMapAttribute (MemoryMap, *MemoryMapSize, DescriptorSize);
    718 
    719   //
    720   // Merge same type to save entry size
    721   //
    722   MergeMemoryMap (MemoryMap, MemoryMapSize, DescriptorSize);
    723 
    724   return ;
    725 }
    726 
    727 /**
    728   This function for GetMemoryMap() with properties table capability.
    729 
    730   It calls original GetMemoryMap() to get the original memory map information. Then
    731   plus the additional memory map entries for PE Code/Data seperation.
    732 
    733   @param  MemoryMapSize          A pointer to the size, in bytes, of the
    734                                  MemoryMap buffer. On input, this is the size of
    735                                  the buffer allocated by the caller.  On output,
    736                                  it is the size of the buffer returned by the
    737                                  firmware  if the buffer was large enough, or the
    738                                  size of the buffer needed  to contain the map if
    739                                  the buffer was too small.
    740   @param  MemoryMap              A pointer to the buffer in which firmware places
    741                                  the current memory map.
    742   @param  MapKey                 A pointer to the location in which firmware
    743                                  returns the key for the current memory map.
    744   @param  DescriptorSize         A pointer to the location in which firmware
    745                                  returns the size, in bytes, of an individual
    746                                  EFI_MEMORY_DESCRIPTOR.
    747   @param  DescriptorVersion      A pointer to the location in which firmware
    748                                  returns the version number associated with the
    749                                  EFI_MEMORY_DESCRIPTOR.
    750 
    751   @retval EFI_SUCCESS            The memory map was returned in the MemoryMap
    752                                  buffer.
    753   @retval EFI_BUFFER_TOO_SMALL   The MemoryMap buffer was too small. The current
    754                                  buffer size needed to hold the memory map is
    755                                  returned in MemoryMapSize.
    756   @retval EFI_INVALID_PARAMETER  One of the parameters has an invalid value.
    757 
    758 **/
    759 EFI_STATUS
    760 EFIAPI
    761 CoreGetMemoryMapWithSeparatedImageSection (
    762   IN OUT UINTN                  *MemoryMapSize,
    763   IN OUT EFI_MEMORY_DESCRIPTOR  *MemoryMap,
    764   OUT UINTN                     *MapKey,
    765   OUT UINTN                     *DescriptorSize,
    766   OUT UINT32                    *DescriptorVersion
    767   )
    768 {
    769   EFI_STATUS  Status;
    770   UINTN       OldMemoryMapSize;
    771   UINTN       AdditionalRecordCount;
    772 
    773   //
    774   // If PE code/data is not aligned, just return.
    775   //
    776   if ((mPropertiesTable.MemoryProtectionAttribute & EFI_PROPERTIES_RUNTIME_MEMORY_PROTECTION_NON_EXECUTABLE_PE_DATA) == 0) {
    777     return CoreGetMemoryMap (MemoryMapSize, MemoryMap, MapKey, DescriptorSize, DescriptorVersion);
    778   }
    779 
    780   if (MemoryMapSize == NULL) {
    781     return EFI_INVALID_PARAMETER;
    782   }
    783 
    784   CoreAcquirePropertiesTableLock ();
    785 
    786   AdditionalRecordCount = (2 * mImagePropertiesPrivateData.CodeSegmentCountMax + 1) * mImagePropertiesPrivateData.ImageRecordCount;
    787 
    788   OldMemoryMapSize = *MemoryMapSize;
    789   Status = CoreGetMemoryMap (MemoryMapSize, MemoryMap, MapKey, DescriptorSize, DescriptorVersion);
    790   if (Status == EFI_BUFFER_TOO_SMALL) {
    791     *MemoryMapSize = *MemoryMapSize + (*DescriptorSize) * AdditionalRecordCount;
    792   } else if (Status == EFI_SUCCESS) {
    793     ASSERT (MemoryMap != NULL);
    794     if (OldMemoryMapSize - *MemoryMapSize < (*DescriptorSize) * AdditionalRecordCount) {
    795       *MemoryMapSize = *MemoryMapSize + (*DescriptorSize) * AdditionalRecordCount;
    796       //
    797       // Need update status to buffer too small
    798       //
    799       Status = EFI_BUFFER_TOO_SMALL;
    800     } else {
    801       //
    802       // Split PE code/data
    803       //
    804       SplitTable (MemoryMapSize, MemoryMap, *DescriptorSize);
    805     }
    806   }
    807 
    808   CoreReleasePropertiesTableLock ();
    809   return Status;
    810 }
    811 
    812 //
    813 // Below functions are for ImageRecord
    814 //
    815 
    816 /**
    817   Set PropertiesTable according to PE/COFF image section alignment.
    818 
    819   @param  SectionAlignment    PE/COFF section alignment
    820 **/
    821 STATIC
    822 VOID
    823 SetPropertiesTableSectionAlignment (
    824   IN UINT32  SectionAlignment
    825   )
    826 {
    827   if (((SectionAlignment & (EFI_ACPI_RUNTIME_PAGE_ALLOCATION_ALIGNMENT - 1)) != 0) &&
    828       ((mPropertiesTable.MemoryProtectionAttribute & EFI_PROPERTIES_RUNTIME_MEMORY_PROTECTION_NON_EXECUTABLE_PE_DATA) != 0)) {
    829     DEBUG ((EFI_D_VERBOSE, "SetPropertiesTableSectionAlignment - Clear\n"));
    830     mPropertiesTable.MemoryProtectionAttribute &= ~((UINT64)EFI_PROPERTIES_RUNTIME_MEMORY_PROTECTION_NON_EXECUTABLE_PE_DATA);
    831     gBS->GetMemoryMap = CoreGetMemoryMap;
    832     gBS->Hdr.CRC32 = 0;
    833     gBS->CalculateCrc32 ((UINT8 *)gBS, gBS->Hdr.HeaderSize, &gBS->Hdr.CRC32);
    834   }
    835 }
    836 
    837 /**
    838   Swap two code sections in image record.
    839 
    840   @param  FirstImageRecordCodeSection    first code section in image record
    841   @param  SecondImageRecordCodeSection   second code section in image record
    842 **/
    843 STATIC
    844 VOID
    845 SwapImageRecordCodeSection (
    846   IN IMAGE_PROPERTIES_RECORD_CODE_SECTION      *FirstImageRecordCodeSection,
    847   IN IMAGE_PROPERTIES_RECORD_CODE_SECTION      *SecondImageRecordCodeSection
    848   )
    849 {
    850   IMAGE_PROPERTIES_RECORD_CODE_SECTION      TempImageRecordCodeSection;
    851 
    852   TempImageRecordCodeSection.CodeSegmentBase = FirstImageRecordCodeSection->CodeSegmentBase;
    853   TempImageRecordCodeSection.CodeSegmentSize = FirstImageRecordCodeSection->CodeSegmentSize;
    854 
    855   FirstImageRecordCodeSection->CodeSegmentBase = SecondImageRecordCodeSection->CodeSegmentBase;
    856   FirstImageRecordCodeSection->CodeSegmentSize = SecondImageRecordCodeSection->CodeSegmentSize;
    857 
    858   SecondImageRecordCodeSection->CodeSegmentBase = TempImageRecordCodeSection.CodeSegmentBase;
    859   SecondImageRecordCodeSection->CodeSegmentSize = TempImageRecordCodeSection.CodeSegmentSize;
    860 }
    861 
    862 /**
    863   Sort code section in image record, based upon CodeSegmentBase from low to high.
    864 
    865   @param  ImageRecord    image record to be sorted
    866 **/
    867 STATIC
    868 VOID
    869 SortImageRecordCodeSection (
    870   IN IMAGE_PROPERTIES_RECORD              *ImageRecord
    871   )
    872 {
    873   IMAGE_PROPERTIES_RECORD_CODE_SECTION      *ImageRecordCodeSection;
    874   IMAGE_PROPERTIES_RECORD_CODE_SECTION      *NextImageRecordCodeSection;
    875   LIST_ENTRY                                *ImageRecordCodeSectionLink;
    876   LIST_ENTRY                                *NextImageRecordCodeSectionLink;
    877   LIST_ENTRY                                *ImageRecordCodeSectionEndLink;
    878   LIST_ENTRY                                *ImageRecordCodeSectionList;
    879 
    880   ImageRecordCodeSectionList = &ImageRecord->CodeSegmentList;
    881 
    882   ImageRecordCodeSectionLink = ImageRecordCodeSectionList->ForwardLink;
    883   NextImageRecordCodeSectionLink = ImageRecordCodeSectionLink->ForwardLink;
    884   ImageRecordCodeSectionEndLink = ImageRecordCodeSectionList;
    885   while (ImageRecordCodeSectionLink != ImageRecordCodeSectionEndLink) {
    886     ImageRecordCodeSection = CR (
    887                                ImageRecordCodeSectionLink,
    888                                IMAGE_PROPERTIES_RECORD_CODE_SECTION,
    889                                Link,
    890                                IMAGE_PROPERTIES_RECORD_CODE_SECTION_SIGNATURE
    891                                );
    892     while (NextImageRecordCodeSectionLink != ImageRecordCodeSectionEndLink) {
    893       NextImageRecordCodeSection = CR (
    894                                      NextImageRecordCodeSectionLink,
    895                                      IMAGE_PROPERTIES_RECORD_CODE_SECTION,
    896                                      Link,
    897                                      IMAGE_PROPERTIES_RECORD_CODE_SECTION_SIGNATURE
    898                                      );
    899       if (ImageRecordCodeSection->CodeSegmentBase > NextImageRecordCodeSection->CodeSegmentBase) {
    900         SwapImageRecordCodeSection (ImageRecordCodeSection, NextImageRecordCodeSection);
    901       }
    902       NextImageRecordCodeSectionLink = NextImageRecordCodeSectionLink->ForwardLink;
    903     }
    904 
    905     ImageRecordCodeSectionLink = ImageRecordCodeSectionLink->ForwardLink;
    906     NextImageRecordCodeSectionLink = ImageRecordCodeSectionLink->ForwardLink;
    907   }
    908 }
    909 
    910 /**
    911   Check if code section in image record is valid.
    912 
    913   @param  ImageRecord    image record to be checked
    914 
    915   @retval TRUE  image record is valid
    916   @retval FALSE image record is invalid
    917 **/
    918 STATIC
    919 BOOLEAN
    920 IsImageRecordCodeSectionValid (
    921   IN IMAGE_PROPERTIES_RECORD              *ImageRecord
    922   )
    923 {
    924   IMAGE_PROPERTIES_RECORD_CODE_SECTION      *ImageRecordCodeSection;
    925   IMAGE_PROPERTIES_RECORD_CODE_SECTION      *LastImageRecordCodeSection;
    926   LIST_ENTRY                                *ImageRecordCodeSectionLink;
    927   LIST_ENTRY                                *ImageRecordCodeSectionEndLink;
    928   LIST_ENTRY                                *ImageRecordCodeSectionList;
    929 
    930   DEBUG ((EFI_D_VERBOSE, "ImageCode SegmentCount - 0x%x\n", ImageRecord->CodeSegmentCount));
    931 
    932   ImageRecordCodeSectionList = &ImageRecord->CodeSegmentList;
    933 
    934   ImageRecordCodeSectionLink = ImageRecordCodeSectionList->ForwardLink;
    935   ImageRecordCodeSectionEndLink = ImageRecordCodeSectionList;
    936   LastImageRecordCodeSection = NULL;
    937   while (ImageRecordCodeSectionLink != ImageRecordCodeSectionEndLink) {
    938     ImageRecordCodeSection = CR (
    939                                ImageRecordCodeSectionLink,
    940                                IMAGE_PROPERTIES_RECORD_CODE_SECTION,
    941                                Link,
    942                                IMAGE_PROPERTIES_RECORD_CODE_SECTION_SIGNATURE
    943                                );
    944     if (ImageRecordCodeSection->CodeSegmentSize == 0) {
    945       return FALSE;
    946     }
    947     if (ImageRecordCodeSection->CodeSegmentBase < ImageRecord->ImageBase) {
    948       return FALSE;
    949     }
    950     if (ImageRecordCodeSection->CodeSegmentBase >= MAX_ADDRESS - ImageRecordCodeSection->CodeSegmentSize) {
    951       return FALSE;
    952     }
    953     if ((ImageRecordCodeSection->CodeSegmentBase + ImageRecordCodeSection->CodeSegmentSize) > (ImageRecord->ImageBase + ImageRecord->ImageSize)) {
    954       return FALSE;
    955     }
    956     if (LastImageRecordCodeSection != NULL) {
    957       if ((LastImageRecordCodeSection->CodeSegmentBase + LastImageRecordCodeSection->CodeSegmentSize) > ImageRecordCodeSection->CodeSegmentBase) {
    958         return FALSE;
    959       }
    960     }
    961 
    962     LastImageRecordCodeSection = ImageRecordCodeSection;
    963     ImageRecordCodeSectionLink = ImageRecordCodeSectionLink->ForwardLink;
    964   }
    965 
    966   return TRUE;
    967 }
    968 
    969 /**
    970   Swap two image records.
    971 
    972   @param  FirstImageRecord   first image record.
    973   @param  SecondImageRecord  second image record.
    974 **/
    975 STATIC
    976 VOID
    977 SwapImageRecord (
    978   IN IMAGE_PROPERTIES_RECORD      *FirstImageRecord,
    979   IN IMAGE_PROPERTIES_RECORD      *SecondImageRecord
    980   )
    981 {
    982   IMAGE_PROPERTIES_RECORD      TempImageRecord;
    983 
    984   TempImageRecord.ImageBase = FirstImageRecord->ImageBase;
    985   TempImageRecord.ImageSize = FirstImageRecord->ImageSize;
    986   TempImageRecord.CodeSegmentCount = FirstImageRecord->CodeSegmentCount;
    987 
    988   FirstImageRecord->ImageBase = SecondImageRecord->ImageBase;
    989   FirstImageRecord->ImageSize = SecondImageRecord->ImageSize;
    990   FirstImageRecord->CodeSegmentCount = SecondImageRecord->CodeSegmentCount;
    991 
    992   SecondImageRecord->ImageBase = TempImageRecord.ImageBase;
    993   SecondImageRecord->ImageSize = TempImageRecord.ImageSize;
    994   SecondImageRecord->CodeSegmentCount = TempImageRecord.CodeSegmentCount;
    995 
    996   SwapListEntries (&FirstImageRecord->CodeSegmentList, &SecondImageRecord->CodeSegmentList);
    997 }
    998 
    999 /**
   1000   Sort image record based upon the ImageBase from low to high.
   1001 **/
   1002 STATIC
   1003 VOID
   1004 SortImageRecord (
   1005   VOID
   1006   )
   1007 {
   1008   IMAGE_PROPERTIES_RECORD      *ImageRecord;
   1009   IMAGE_PROPERTIES_RECORD      *NextImageRecord;
   1010   LIST_ENTRY                   *ImageRecordLink;
   1011   LIST_ENTRY                   *NextImageRecordLink;
   1012   LIST_ENTRY                   *ImageRecordEndLink;
   1013   LIST_ENTRY                   *ImageRecordList;
   1014 
   1015   ImageRecordList = &mImagePropertiesPrivateData.ImageRecordList;
   1016 
   1017   ImageRecordLink = ImageRecordList->ForwardLink;
   1018   NextImageRecordLink = ImageRecordLink->ForwardLink;
   1019   ImageRecordEndLink = ImageRecordList;
   1020   while (ImageRecordLink != ImageRecordEndLink) {
   1021     ImageRecord = CR (
   1022                     ImageRecordLink,
   1023                     IMAGE_PROPERTIES_RECORD,
   1024                     Link,
   1025                     IMAGE_PROPERTIES_RECORD_SIGNATURE
   1026                     );
   1027     while (NextImageRecordLink != ImageRecordEndLink) {
   1028       NextImageRecord = CR (
   1029                           NextImageRecordLink,
   1030                           IMAGE_PROPERTIES_RECORD,
   1031                           Link,
   1032                           IMAGE_PROPERTIES_RECORD_SIGNATURE
   1033                           );
   1034       if (ImageRecord->ImageBase > NextImageRecord->ImageBase) {
   1035         SwapImageRecord (ImageRecord, NextImageRecord);
   1036       }
   1037       NextImageRecordLink = NextImageRecordLink->ForwardLink;
   1038     }
   1039 
   1040     ImageRecordLink = ImageRecordLink->ForwardLink;
   1041     NextImageRecordLink = ImageRecordLink->ForwardLink;
   1042   }
   1043 }
   1044 
   1045 /**
   1046   Dump image record.
   1047 **/
   1048 STATIC
   1049 VOID
   1050 DumpImageRecord (
   1051   VOID
   1052   )
   1053 {
   1054   IMAGE_PROPERTIES_RECORD      *ImageRecord;
   1055   LIST_ENTRY                   *ImageRecordLink;
   1056   LIST_ENTRY                   *ImageRecordList;
   1057   UINTN                        Index;
   1058 
   1059   ImageRecordList = &mImagePropertiesPrivateData.ImageRecordList;
   1060 
   1061   for (ImageRecordLink = ImageRecordList->ForwardLink, Index= 0;
   1062        ImageRecordLink != ImageRecordList;
   1063        ImageRecordLink = ImageRecordLink->ForwardLink, Index++) {
   1064     ImageRecord = CR (
   1065                     ImageRecordLink,
   1066                     IMAGE_PROPERTIES_RECORD,
   1067                     Link,
   1068                     IMAGE_PROPERTIES_RECORD_SIGNATURE
   1069                     );
   1070     DEBUG ((EFI_D_VERBOSE, "  Image[%d]: 0x%016lx - 0x%016lx\n", Index, ImageRecord->ImageBase, ImageRecord->ImageSize));
   1071   }
   1072 }
   1073 
   1074 /**
   1075   Insert image record.
   1076 
   1077   @param  RuntimeImage    Runtime image information
   1078 **/
   1079 VOID
   1080 InsertImageRecord (
   1081   IN EFI_RUNTIME_IMAGE_ENTRY  *RuntimeImage
   1082   )
   1083 {
   1084   VOID                                 *ImageAddress;
   1085   EFI_IMAGE_DOS_HEADER                 *DosHdr;
   1086   UINT32                               PeCoffHeaderOffset;
   1087   UINT32                               SectionAlignment;
   1088   EFI_IMAGE_SECTION_HEADER             *Section;
   1089   EFI_IMAGE_OPTIONAL_HEADER_PTR_UNION  Hdr;
   1090   UINT8                                *Name;
   1091   UINTN                                Index;
   1092   IMAGE_PROPERTIES_RECORD              *ImageRecord;
   1093   CHAR8                                *PdbPointer;
   1094   IMAGE_PROPERTIES_RECORD_CODE_SECTION *ImageRecordCodeSection;
   1095   UINT16                               Magic;
   1096 
   1097   DEBUG ((EFI_D_VERBOSE, "InsertImageRecord - 0x%x\n", RuntimeImage));
   1098   DEBUG ((EFI_D_VERBOSE, "InsertImageRecord - 0x%016lx - 0x%016lx\n", (EFI_PHYSICAL_ADDRESS)(UINTN)RuntimeImage->ImageBase, RuntimeImage->ImageSize));
   1099 
   1100   ImageRecord = AllocatePool (sizeof(*ImageRecord));
   1101   if (ImageRecord == NULL) {
   1102     return ;
   1103   }
   1104   ImageRecord->Signature = IMAGE_PROPERTIES_RECORD_SIGNATURE;
   1105 
   1106   DEBUG ((EFI_D_VERBOSE, "ImageRecordCount - 0x%x\n", mImagePropertiesPrivateData.ImageRecordCount));
   1107 
   1108   //
   1109   // Step 1: record whole region
   1110   //
   1111   ImageRecord->ImageBase = (EFI_PHYSICAL_ADDRESS)(UINTN)RuntimeImage->ImageBase;
   1112   ImageRecord->ImageSize = RuntimeImage->ImageSize;
   1113 
   1114   ImageAddress = RuntimeImage->ImageBase;
   1115 
   1116   PdbPointer = PeCoffLoaderGetPdbPointer ((VOID*) (UINTN) ImageAddress);
   1117   if (PdbPointer != NULL) {
   1118     DEBUG ((EFI_D_VERBOSE, "  Image - %a\n", PdbPointer));
   1119   }
   1120 
   1121   //
   1122   // Check PE/COFF image
   1123   //
   1124   DosHdr = (EFI_IMAGE_DOS_HEADER *) (UINTN) ImageAddress;
   1125   PeCoffHeaderOffset = 0;
   1126   if (DosHdr->e_magic == EFI_IMAGE_DOS_SIGNATURE) {
   1127     PeCoffHeaderOffset = DosHdr->e_lfanew;
   1128   }
   1129 
   1130   Hdr.Pe32 = (EFI_IMAGE_NT_HEADERS32 *)((UINT8 *) (UINTN) ImageAddress + PeCoffHeaderOffset);
   1131   if (Hdr.Pe32->Signature != EFI_IMAGE_NT_SIGNATURE) {
   1132     DEBUG ((EFI_D_VERBOSE, "Hdr.Pe32->Signature invalid - 0x%x\n", Hdr.Pe32->Signature));
   1133     // It might be image in SMM.
   1134     goto Finish;
   1135   }
   1136 
   1137   //
   1138   // Get SectionAlignment
   1139   //
   1140   if (Hdr.Pe32->FileHeader.Machine == IMAGE_FILE_MACHINE_IA64 && Hdr.Pe32->OptionalHeader.Magic == EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC) {
   1141     //
   1142     // NOTE: Some versions of Linux ELILO for Itanium have an incorrect magic value
   1143     //       in the PE/COFF Header. If the MachineType is Itanium(IA64) and the
   1144     //       Magic value in the OptionalHeader is EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC
   1145     //       then override the magic value to EFI_IMAGE_NT_OPTIONAL_HDR64_MAGIC
   1146     //
   1147     Magic = EFI_IMAGE_NT_OPTIONAL_HDR64_MAGIC;
   1148   } else {
   1149     //
   1150     // Get the magic value from the PE/COFF Optional Header
   1151     //
   1152     Magic = Hdr.Pe32->OptionalHeader.Magic;
   1153   }
   1154   if (Magic == EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC) {
   1155     SectionAlignment  = Hdr.Pe32->OptionalHeader.SectionAlignment;
   1156   } else {
   1157     SectionAlignment  = Hdr.Pe32Plus->OptionalHeader.SectionAlignment;
   1158   }
   1159 
   1160   SetPropertiesTableSectionAlignment (SectionAlignment);
   1161   if ((SectionAlignment & (EFI_ACPI_RUNTIME_PAGE_ALLOCATION_ALIGNMENT - 1)) != 0) {
   1162     DEBUG ((EFI_D_WARN, "!!!!!!!!  InsertImageRecord - Section Alignment(0x%x) is not %dK  !!!!!!!!\n",
   1163       SectionAlignment, EFI_ACPI_RUNTIME_PAGE_ALLOCATION_ALIGNMENT >> 10));
   1164     PdbPointer = PeCoffLoaderGetPdbPointer ((VOID*) (UINTN) ImageAddress);
   1165     if (PdbPointer != NULL) {
   1166       DEBUG ((EFI_D_WARN, "!!!!!!!!  Image - %a  !!!!!!!!\n", PdbPointer));
   1167     }
   1168     goto Finish;
   1169   }
   1170 
   1171   Section = (EFI_IMAGE_SECTION_HEADER *) (
   1172                (UINT8 *) (UINTN) ImageAddress +
   1173                PeCoffHeaderOffset +
   1174                sizeof(UINT32) +
   1175                sizeof(EFI_IMAGE_FILE_HEADER) +
   1176                Hdr.Pe32->FileHeader.SizeOfOptionalHeader
   1177                );
   1178   ImageRecord->CodeSegmentCount = 0;
   1179   InitializeListHead (&ImageRecord->CodeSegmentList);
   1180   for (Index = 0; Index < Hdr.Pe32->FileHeader.NumberOfSections; Index++) {
   1181     Name = Section[Index].Name;
   1182     DEBUG ((
   1183       EFI_D_VERBOSE,
   1184       "  Section - '%c%c%c%c%c%c%c%c'\n",
   1185       Name[0],
   1186       Name[1],
   1187       Name[2],
   1188       Name[3],
   1189       Name[4],
   1190       Name[5],
   1191       Name[6],
   1192       Name[7]
   1193       ));
   1194 
   1195     if ((Section[Index].Characteristics & EFI_IMAGE_SCN_CNT_CODE) != 0) {
   1196       DEBUG ((EFI_D_VERBOSE, "  VirtualSize          - 0x%08x\n", Section[Index].Misc.VirtualSize));
   1197       DEBUG ((EFI_D_VERBOSE, "  VirtualAddress       - 0x%08x\n", Section[Index].VirtualAddress));
   1198       DEBUG ((EFI_D_VERBOSE, "  SizeOfRawData        - 0x%08x\n", Section[Index].SizeOfRawData));
   1199       DEBUG ((EFI_D_VERBOSE, "  PointerToRawData     - 0x%08x\n", Section[Index].PointerToRawData));
   1200       DEBUG ((EFI_D_VERBOSE, "  PointerToRelocations - 0x%08x\n", Section[Index].PointerToRelocations));
   1201       DEBUG ((EFI_D_VERBOSE, "  PointerToLinenumbers - 0x%08x\n", Section[Index].PointerToLinenumbers));
   1202       DEBUG ((EFI_D_VERBOSE, "  NumberOfRelocations  - 0x%08x\n", Section[Index].NumberOfRelocations));
   1203       DEBUG ((EFI_D_VERBOSE, "  NumberOfLinenumbers  - 0x%08x\n", Section[Index].NumberOfLinenumbers));
   1204       DEBUG ((EFI_D_VERBOSE, "  Characteristics      - 0x%08x\n", Section[Index].Characteristics));
   1205 
   1206       //
   1207       // Step 2: record code section
   1208       //
   1209       ImageRecordCodeSection = AllocatePool (sizeof(*ImageRecordCodeSection));
   1210       if (ImageRecordCodeSection == NULL) {
   1211         return ;
   1212       }
   1213       ImageRecordCodeSection->Signature = IMAGE_PROPERTIES_RECORD_CODE_SECTION_SIGNATURE;
   1214 
   1215       ImageRecordCodeSection->CodeSegmentBase = (UINTN)ImageAddress + Section[Index].VirtualAddress;
   1216       ImageRecordCodeSection->CodeSegmentSize = Section[Index].SizeOfRawData;
   1217 
   1218       DEBUG ((EFI_D_VERBOSE, "ImageCode: 0x%016lx - 0x%016lx\n", ImageRecordCodeSection->CodeSegmentBase, ImageRecordCodeSection->CodeSegmentSize));
   1219 
   1220       InsertTailList (&ImageRecord->CodeSegmentList, &ImageRecordCodeSection->Link);
   1221       ImageRecord->CodeSegmentCount++;
   1222     }
   1223   }
   1224 
   1225   if (ImageRecord->CodeSegmentCount == 0) {
   1226     SetPropertiesTableSectionAlignment (1);
   1227     DEBUG ((EFI_D_ERROR, "!!!!!!!!  InsertImageRecord - CodeSegmentCount is 0  !!!!!!!!\n"));
   1228     PdbPointer = PeCoffLoaderGetPdbPointer ((VOID*) (UINTN) ImageAddress);
   1229     if (PdbPointer != NULL) {
   1230       DEBUG ((EFI_D_ERROR, "!!!!!!!!  Image - %a  !!!!!!!!\n", PdbPointer));
   1231     }
   1232     goto Finish;
   1233   }
   1234 
   1235   //
   1236   // Final
   1237   //
   1238   SortImageRecordCodeSection (ImageRecord);
   1239   //
   1240   // Check overlap all section in ImageBase/Size
   1241   //
   1242   if (!IsImageRecordCodeSectionValid (ImageRecord)) {
   1243     DEBUG ((EFI_D_ERROR, "IsImageRecordCodeSectionValid - FAIL\n"));
   1244     goto Finish;
   1245   }
   1246 
   1247   InsertTailList (&mImagePropertiesPrivateData.ImageRecordList, &ImageRecord->Link);
   1248   mImagePropertiesPrivateData.ImageRecordCount++;
   1249 
   1250   SortImageRecord ();
   1251 
   1252   if (mImagePropertiesPrivateData.CodeSegmentCountMax < ImageRecord->CodeSegmentCount) {
   1253     mImagePropertiesPrivateData.CodeSegmentCountMax = ImageRecord->CodeSegmentCount;
   1254   }
   1255 
   1256 Finish:
   1257   return ;
   1258 }
   1259 
   1260 /**
   1261   Find image record according to image base and size.
   1262 
   1263   @param  ImageBase    Base of PE image
   1264   @param  ImageSize    Size of PE image
   1265 
   1266   @return image record
   1267 **/
   1268 STATIC
   1269 IMAGE_PROPERTIES_RECORD *
   1270 FindImageRecord (
   1271   IN EFI_PHYSICAL_ADDRESS  ImageBase,
   1272   IN UINT64                ImageSize
   1273   )
   1274 {
   1275   IMAGE_PROPERTIES_RECORD    *ImageRecord;
   1276   LIST_ENTRY                 *ImageRecordLink;
   1277   LIST_ENTRY                 *ImageRecordList;
   1278 
   1279   ImageRecordList = &mImagePropertiesPrivateData.ImageRecordList;
   1280 
   1281   for (ImageRecordLink = ImageRecordList->ForwardLink;
   1282        ImageRecordLink != ImageRecordList;
   1283        ImageRecordLink = ImageRecordLink->ForwardLink) {
   1284     ImageRecord = CR (
   1285                     ImageRecordLink,
   1286                     IMAGE_PROPERTIES_RECORD,
   1287                     Link,
   1288                     IMAGE_PROPERTIES_RECORD_SIGNATURE
   1289                     );
   1290 
   1291     if ((ImageBase == ImageRecord->ImageBase) &&
   1292         (ImageSize == ImageRecord->ImageSize)) {
   1293       return ImageRecord;
   1294     }
   1295   }
   1296 
   1297   return NULL;
   1298 }
   1299 
   1300 /**
   1301   Remove Image record.
   1302 
   1303   @param  RuntimeImage    Runtime image information
   1304 **/
   1305 VOID
   1306 RemoveImageRecord (
   1307   IN EFI_RUNTIME_IMAGE_ENTRY  *RuntimeImage
   1308   )
   1309 {
   1310   IMAGE_PROPERTIES_RECORD              *ImageRecord;
   1311   LIST_ENTRY                           *CodeSegmentListHead;
   1312   IMAGE_PROPERTIES_RECORD_CODE_SECTION *ImageRecordCodeSection;
   1313 
   1314   DEBUG ((EFI_D_VERBOSE, "RemoveImageRecord - 0x%x\n", RuntimeImage));
   1315   DEBUG ((EFI_D_VERBOSE, "RemoveImageRecord - 0x%016lx - 0x%016lx\n", (EFI_PHYSICAL_ADDRESS)(UINTN)RuntimeImage->ImageBase, RuntimeImage->ImageSize));
   1316 
   1317   ImageRecord = FindImageRecord ((EFI_PHYSICAL_ADDRESS)(UINTN)RuntimeImage->ImageBase, RuntimeImage->ImageSize);
   1318   if (ImageRecord == NULL) {
   1319     DEBUG ((EFI_D_ERROR, "!!!!!!!! ImageRecord not found !!!!!!!!\n"));
   1320     return ;
   1321   }
   1322 
   1323   CodeSegmentListHead = &ImageRecord->CodeSegmentList;
   1324   while (!IsListEmpty (CodeSegmentListHead)) {
   1325     ImageRecordCodeSection = CR (
   1326                                CodeSegmentListHead->ForwardLink,
   1327                                IMAGE_PROPERTIES_RECORD_CODE_SECTION,
   1328                                Link,
   1329                                IMAGE_PROPERTIES_RECORD_CODE_SECTION_SIGNATURE
   1330                                );
   1331     RemoveEntryList (&ImageRecordCodeSection->Link);
   1332     FreePool (ImageRecordCodeSection);
   1333   }
   1334 
   1335   RemoveEntryList (&ImageRecord->Link);
   1336   FreePool (ImageRecord);
   1337   mImagePropertiesPrivateData.ImageRecordCount--;
   1338 }
   1339 
   1340 
   1341 /**
   1342   Install PropertiesTable.
   1343 
   1344   @param[in]  Event     The Event this notify function registered to.
   1345   @param[in]  Context   Pointer to the context data registered to the Event.
   1346 **/
   1347 VOID
   1348 EFIAPI
   1349 InstallPropertiesTable (
   1350   EFI_EVENT                               Event,
   1351   VOID                                    *Context
   1352   )
   1353 {
   1354   if (PcdGetBool (PcdPropertiesTableEnable)) {
   1355     EFI_STATUS  Status;
   1356 
   1357     Status = gBS->InstallConfigurationTable (&gEfiPropertiesTableGuid, &mPropertiesTable);
   1358     ASSERT_EFI_ERROR (Status);
   1359 
   1360     DEBUG ((EFI_D_INFO, "MemoryProtectionAttribute - 0x%016lx\n", mPropertiesTable.MemoryProtectionAttribute));
   1361     if ((mPropertiesTable.MemoryProtectionAttribute & EFI_PROPERTIES_RUNTIME_MEMORY_PROTECTION_NON_EXECUTABLE_PE_DATA) == 0) {
   1362       DEBUG ((EFI_D_ERROR, "MemoryProtectionAttribute NON_EXECUTABLE_PE_DATA is not set, "));
   1363       DEBUG ((EFI_D_ERROR, "because Runtime Driver Section Alignment is not %dK.\n", EFI_ACPI_RUNTIME_PAGE_ALLOCATION_ALIGNMENT >> 10));
   1364       return ;
   1365     }
   1366 
   1367     gBS->GetMemoryMap = CoreGetMemoryMapWithSeparatedImageSection;
   1368     gBS->Hdr.CRC32 = 0;
   1369     gBS->CalculateCrc32 ((UINT8 *)gBS, gBS->Hdr.HeaderSize, &gBS->Hdr.CRC32);
   1370 
   1371     DEBUG ((EFI_D_VERBOSE, "Total Image Count - 0x%x\n", mImagePropertiesPrivateData.ImageRecordCount));
   1372     DEBUG ((EFI_D_VERBOSE, "Dump ImageRecord:\n"));
   1373     DumpImageRecord ();
   1374 
   1375     mPropertiesTableEnable = TRUE;
   1376   }
   1377 }
   1378 
   1379 /**
   1380   Initialize PropertiesTable support.
   1381 **/
   1382 VOID
   1383 EFIAPI
   1384 CoreInitializePropertiesTable (
   1385   VOID
   1386   )
   1387 {
   1388   EFI_STATUS  Status;
   1389   EFI_EVENT   EndOfDxeEvent;
   1390 
   1391   Status = gBS->CreateEventEx (
   1392                   EVT_NOTIFY_SIGNAL,
   1393                   TPL_NOTIFY,
   1394                   InstallPropertiesTable,
   1395                   NULL,
   1396                   &gEfiEndOfDxeEventGroupGuid,
   1397                   &EndOfDxeEvent
   1398                   );
   1399   ASSERT_EFI_ERROR (Status);
   1400   return ;
   1401 }
   1402