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