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