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