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