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