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