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