• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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
EfiPagesToSize(IN UINT64 Pages)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
EfiSizeToPages(IN UINT64 Size)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
CoreAcquirePropertiesTableLock(VOID)133 CoreAcquirePropertiesTableLock (
134   VOID
135   )
136 {
137   CoreAcquireLock (&mPropertiesTableLock);
138 }
139 
140 /**
141   Release memory lock on mPropertiesTableLock.
142 **/
143 STATIC
144 VOID
CoreReleasePropertiesTableLock(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
SortMemoryMap(IN OUT EFI_MEMORY_DESCRIPTOR * MemoryMap,IN UINTN MemoryMapSize,IN UINTN DescriptorSize)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
MergeMemoryMap(IN OUT EFI_MEMORY_DESCRIPTOR * MemoryMap,IN OUT UINTN * MemoryMapSize,IN UINTN DescriptorSize)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
EnforceMemoryMapAttribute(IN OUT EFI_MEMORY_DESCRIPTOR * MemoryMap,IN UINTN MemoryMapSize,IN UINTN DescriptorSize)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 *
GetImageRecordByAddress(IN EFI_PHYSICAL_ADDRESS Buffer,IN UINT64 Length)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
SetNewRecord(IN IMAGE_PROPERTIES_RECORD * ImageRecord,IN OUT EFI_MEMORY_DESCRIPTOR * NewRecord,IN EFI_MEMORY_DESCRIPTOR * OldRecord,IN UINTN DescriptorSize)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
GetMaxSplitRecordCount(IN EFI_MEMORY_DESCRIPTOR * OldRecord)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
SplitRecord(IN EFI_MEMORY_DESCRIPTOR * OldRecord,IN OUT EFI_MEMORY_DESCRIPTOR * NewRecord,IN UINTN MaxSplitRecordCount,IN UINTN DescriptorSize)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
SplitTable(IN OUT UINTN * MemoryMapSize,IN OUT EFI_MEMORY_DESCRIPTOR * MemoryMap,IN UINTN DescriptorSize)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
CoreGetMemoryMapWithSeparatedImageSection(IN OUT UINTN * MemoryMapSize,IN OUT EFI_MEMORY_DESCRIPTOR * MemoryMap,OUT UINTN * MapKey,OUT UINTN * DescriptorSize,OUT UINT32 * DescriptorVersion)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
SetPropertiesTableSectionAlignment(IN UINT32 SectionAlignment)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
SwapImageRecordCodeSection(IN IMAGE_PROPERTIES_RECORD_CODE_SECTION * FirstImageRecordCodeSection,IN IMAGE_PROPERTIES_RECORD_CODE_SECTION * SecondImageRecordCodeSection)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
SortImageRecordCodeSection(IN IMAGE_PROPERTIES_RECORD * ImageRecord)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
IsImageRecordCodeSectionValid(IN IMAGE_PROPERTIES_RECORD * ImageRecord)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
SwapImageRecord(IN IMAGE_PROPERTIES_RECORD * FirstImageRecord,IN IMAGE_PROPERTIES_RECORD * SecondImageRecord)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
SortImageRecord(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
DumpImageRecord(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
InsertImageRecord(IN EFI_RUNTIME_IMAGE_ENTRY * RuntimeImage)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 *
FindImageRecord(IN EFI_PHYSICAL_ADDRESS ImageBase,IN UINT64 ImageSize)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
RemoveImageRecord(IN EFI_RUNTIME_IMAGE_ENTRY * RuntimeImage)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
InstallPropertiesTable(EFI_EVENT Event,VOID * Context)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
CoreInitializePropertiesTable(VOID)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