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