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