]> git.proxmox.com Git - mirror_edk2.git/blob - MdeModulePkg/Core/Dxe/Misc/PropertiesTable.c
a96d442fbc6458247f2f1aa9868bc0439618573d
[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 UINT16 Magic;
1080
1081 DEBUG ((EFI_D_VERBOSE, "InsertImageRecord - 0x%x\n", RuntimeImage));
1082 DEBUG ((EFI_D_VERBOSE, "InsertImageRecord - 0x%016lx - 0x%016lx\n", (EFI_PHYSICAL_ADDRESS)(UINTN)RuntimeImage->ImageBase, RuntimeImage->ImageSize));
1083
1084 if (mPropertiesTableEndOfDxe) {
1085 DEBUG ((DEBUG_INFO, "Do not insert runtime image record after EndOfDxe\n"));
1086 return ;
1087 }
1088
1089 ImageRecord = AllocatePool (sizeof(*ImageRecord));
1090 if (ImageRecord == NULL) {
1091 return ;
1092 }
1093 ImageRecord->Signature = IMAGE_PROPERTIES_RECORD_SIGNATURE;
1094
1095 DEBUG ((EFI_D_VERBOSE, "ImageRecordCount - 0x%x\n", mImagePropertiesPrivateData.ImageRecordCount));
1096
1097 //
1098 // Step 1: record whole region
1099 //
1100 ImageRecord->ImageBase = (EFI_PHYSICAL_ADDRESS)(UINTN)RuntimeImage->ImageBase;
1101 ImageRecord->ImageSize = RuntimeImage->ImageSize;
1102
1103 ImageAddress = RuntimeImage->ImageBase;
1104
1105 PdbPointer = PeCoffLoaderGetPdbPointer ((VOID*) (UINTN) ImageAddress);
1106 if (PdbPointer != NULL) {
1107 DEBUG ((EFI_D_VERBOSE, " Image - %a\n", PdbPointer));
1108 }
1109
1110 //
1111 // Check PE/COFF image
1112 //
1113 DosHdr = (EFI_IMAGE_DOS_HEADER *) (UINTN) ImageAddress;
1114 PeCoffHeaderOffset = 0;
1115 if (DosHdr->e_magic == EFI_IMAGE_DOS_SIGNATURE) {
1116 PeCoffHeaderOffset = DosHdr->e_lfanew;
1117 }
1118
1119 Hdr.Pe32 = (EFI_IMAGE_NT_HEADERS32 *)((UINT8 *) (UINTN) ImageAddress + PeCoffHeaderOffset);
1120 if (Hdr.Pe32->Signature != EFI_IMAGE_NT_SIGNATURE) {
1121 DEBUG ((EFI_D_VERBOSE, "Hdr.Pe32->Signature invalid - 0x%x\n", Hdr.Pe32->Signature));
1122 // It might be image in SMM.
1123 goto Finish;
1124 }
1125
1126 //
1127 // Get SectionAlignment
1128 //
1129 if (Hdr.Pe32->FileHeader.Machine == IMAGE_FILE_MACHINE_IA64 && Hdr.Pe32->OptionalHeader.Magic == EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC) {
1130 //
1131 // NOTE: Some versions of Linux ELILO for Itanium have an incorrect magic value
1132 // in the PE/COFF Header. If the MachineType is Itanium(IA64) and the
1133 // Magic value in the OptionalHeader is EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC
1134 // then override the magic value to EFI_IMAGE_NT_OPTIONAL_HDR64_MAGIC
1135 //
1136 Magic = EFI_IMAGE_NT_OPTIONAL_HDR64_MAGIC;
1137 } else {
1138 //
1139 // Get the magic value from the PE/COFF Optional Header
1140 //
1141 Magic = Hdr.Pe32->OptionalHeader.Magic;
1142 }
1143 if (Magic == EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC) {
1144 SectionAlignment = Hdr.Pe32->OptionalHeader.SectionAlignment;
1145 } else {
1146 SectionAlignment = Hdr.Pe32Plus->OptionalHeader.SectionAlignment;
1147 }
1148
1149 SetPropertiesTableSectionAlignment (SectionAlignment);
1150 if ((SectionAlignment & (RUNTIME_PAGE_ALLOCATION_GRANULARITY - 1)) != 0) {
1151 DEBUG ((EFI_D_WARN, "!!!!!!!! InsertImageRecord - Section Alignment(0x%x) is not %dK !!!!!!!!\n",
1152 SectionAlignment, RUNTIME_PAGE_ALLOCATION_GRANULARITY >> 10));
1153 PdbPointer = PeCoffLoaderGetPdbPointer ((VOID*) (UINTN) ImageAddress);
1154 if (PdbPointer != NULL) {
1155 DEBUG ((EFI_D_WARN, "!!!!!!!! Image - %a !!!!!!!!\n", PdbPointer));
1156 }
1157 goto Finish;
1158 }
1159
1160 Section = (EFI_IMAGE_SECTION_HEADER *) (
1161 (UINT8 *) (UINTN) ImageAddress +
1162 PeCoffHeaderOffset +
1163 sizeof(UINT32) +
1164 sizeof(EFI_IMAGE_FILE_HEADER) +
1165 Hdr.Pe32->FileHeader.SizeOfOptionalHeader
1166 );
1167 ImageRecord->CodeSegmentCount = 0;
1168 InitializeListHead (&ImageRecord->CodeSegmentList);
1169 for (Index = 0; Index < Hdr.Pe32->FileHeader.NumberOfSections; Index++) {
1170 Name = Section[Index].Name;
1171 DEBUG ((
1172 EFI_D_VERBOSE,
1173 " Section - '%c%c%c%c%c%c%c%c'\n",
1174 Name[0],
1175 Name[1],
1176 Name[2],
1177 Name[3],
1178 Name[4],
1179 Name[5],
1180 Name[6],
1181 Name[7]
1182 ));
1183
1184 if ((Section[Index].Characteristics & EFI_IMAGE_SCN_CNT_CODE) != 0) {
1185 DEBUG ((EFI_D_VERBOSE, " VirtualSize - 0x%08x\n", Section[Index].Misc.VirtualSize));
1186 DEBUG ((EFI_D_VERBOSE, " VirtualAddress - 0x%08x\n", Section[Index].VirtualAddress));
1187 DEBUG ((EFI_D_VERBOSE, " SizeOfRawData - 0x%08x\n", Section[Index].SizeOfRawData));
1188 DEBUG ((EFI_D_VERBOSE, " PointerToRawData - 0x%08x\n", Section[Index].PointerToRawData));
1189 DEBUG ((EFI_D_VERBOSE, " PointerToRelocations - 0x%08x\n", Section[Index].PointerToRelocations));
1190 DEBUG ((EFI_D_VERBOSE, " PointerToLinenumbers - 0x%08x\n", Section[Index].PointerToLinenumbers));
1191 DEBUG ((EFI_D_VERBOSE, " NumberOfRelocations - 0x%08x\n", Section[Index].NumberOfRelocations));
1192 DEBUG ((EFI_D_VERBOSE, " NumberOfLinenumbers - 0x%08x\n", Section[Index].NumberOfLinenumbers));
1193 DEBUG ((EFI_D_VERBOSE, " Characteristics - 0x%08x\n", Section[Index].Characteristics));
1194
1195 //
1196 // Step 2: record code section
1197 //
1198 ImageRecordCodeSection = AllocatePool (sizeof(*ImageRecordCodeSection));
1199 if (ImageRecordCodeSection == NULL) {
1200 return ;
1201 }
1202 ImageRecordCodeSection->Signature = IMAGE_PROPERTIES_RECORD_CODE_SECTION_SIGNATURE;
1203
1204 ImageRecordCodeSection->CodeSegmentBase = (UINTN)ImageAddress + Section[Index].VirtualAddress;
1205 ImageRecordCodeSection->CodeSegmentSize = Section[Index].SizeOfRawData;
1206
1207 DEBUG ((EFI_D_VERBOSE, "ImageCode: 0x%016lx - 0x%016lx\n", ImageRecordCodeSection->CodeSegmentBase, ImageRecordCodeSection->CodeSegmentSize));
1208
1209 InsertTailList (&ImageRecord->CodeSegmentList, &ImageRecordCodeSection->Link);
1210 ImageRecord->CodeSegmentCount++;
1211 }
1212 }
1213
1214 if (ImageRecord->CodeSegmentCount == 0) {
1215 SetPropertiesTableSectionAlignment (1);
1216 DEBUG ((EFI_D_ERROR, "!!!!!!!! InsertImageRecord - CodeSegmentCount is 0 !!!!!!!!\n"));
1217 PdbPointer = PeCoffLoaderGetPdbPointer ((VOID*) (UINTN) ImageAddress);
1218 if (PdbPointer != NULL) {
1219 DEBUG ((EFI_D_ERROR, "!!!!!!!! Image - %a !!!!!!!!\n", PdbPointer));
1220 }
1221 goto Finish;
1222 }
1223
1224 //
1225 // Final
1226 //
1227 SortImageRecordCodeSection (ImageRecord);
1228 //
1229 // Check overlap all section in ImageBase/Size
1230 //
1231 if (!IsImageRecordCodeSectionValid (ImageRecord)) {
1232 DEBUG ((EFI_D_ERROR, "IsImageRecordCodeSectionValid - FAIL\n"));
1233 goto Finish;
1234 }
1235
1236 InsertTailList (&mImagePropertiesPrivateData.ImageRecordList, &ImageRecord->Link);
1237 mImagePropertiesPrivateData.ImageRecordCount++;
1238
1239 if (mImagePropertiesPrivateData.CodeSegmentCountMax < ImageRecord->CodeSegmentCount) {
1240 mImagePropertiesPrivateData.CodeSegmentCountMax = ImageRecord->CodeSegmentCount;
1241 }
1242
1243 SortImageRecord ();
1244
1245 Finish:
1246 return ;
1247 }
1248
1249 /**
1250 Find image record according to image base and size.
1251
1252 @param ImageBase Base of PE image
1253 @param ImageSize Size of PE image
1254
1255 @return image record
1256 **/
1257 STATIC
1258 IMAGE_PROPERTIES_RECORD *
1259 FindImageRecord (
1260 IN EFI_PHYSICAL_ADDRESS ImageBase,
1261 IN UINT64 ImageSize
1262 )
1263 {
1264 IMAGE_PROPERTIES_RECORD *ImageRecord;
1265 LIST_ENTRY *ImageRecordLink;
1266 LIST_ENTRY *ImageRecordList;
1267
1268 ImageRecordList = &mImagePropertiesPrivateData.ImageRecordList;
1269
1270 for (ImageRecordLink = ImageRecordList->ForwardLink;
1271 ImageRecordLink != ImageRecordList;
1272 ImageRecordLink = ImageRecordLink->ForwardLink) {
1273 ImageRecord = CR (
1274 ImageRecordLink,
1275 IMAGE_PROPERTIES_RECORD,
1276 Link,
1277 IMAGE_PROPERTIES_RECORD_SIGNATURE
1278 );
1279
1280 if ((ImageBase == ImageRecord->ImageBase) &&
1281 (ImageSize == ImageRecord->ImageSize)) {
1282 return ImageRecord;
1283 }
1284 }
1285
1286 return NULL;
1287 }
1288
1289 /**
1290 Remove Image record.
1291
1292 @param RuntimeImage Runtime image information
1293 **/
1294 VOID
1295 RemoveImageRecord (
1296 IN EFI_RUNTIME_IMAGE_ENTRY *RuntimeImage
1297 )
1298 {
1299 IMAGE_PROPERTIES_RECORD *ImageRecord;
1300 LIST_ENTRY *CodeSegmentListHead;
1301 IMAGE_PROPERTIES_RECORD_CODE_SECTION *ImageRecordCodeSection;
1302
1303 DEBUG ((EFI_D_VERBOSE, "RemoveImageRecord - 0x%x\n", RuntimeImage));
1304 DEBUG ((EFI_D_VERBOSE, "RemoveImageRecord - 0x%016lx - 0x%016lx\n", (EFI_PHYSICAL_ADDRESS)(UINTN)RuntimeImage->ImageBase, RuntimeImage->ImageSize));
1305
1306 if (mPropertiesTableEndOfDxe) {
1307 DEBUG ((DEBUG_INFO, "Do not remove runtime image record after EndOfDxe\n"));
1308 return ;
1309 }
1310
1311 ImageRecord = FindImageRecord ((EFI_PHYSICAL_ADDRESS)(UINTN)RuntimeImage->ImageBase, RuntimeImage->ImageSize);
1312 if (ImageRecord == NULL) {
1313 DEBUG ((EFI_D_ERROR, "!!!!!!!! ImageRecord not found !!!!!!!!\n"));
1314 return ;
1315 }
1316
1317 CodeSegmentListHead = &ImageRecord->CodeSegmentList;
1318 while (!IsListEmpty (CodeSegmentListHead)) {
1319 ImageRecordCodeSection = CR (
1320 CodeSegmentListHead->ForwardLink,
1321 IMAGE_PROPERTIES_RECORD_CODE_SECTION,
1322 Link,
1323 IMAGE_PROPERTIES_RECORD_CODE_SECTION_SIGNATURE
1324 );
1325 RemoveEntryList (&ImageRecordCodeSection->Link);
1326 FreePool (ImageRecordCodeSection);
1327 }
1328
1329 RemoveEntryList (&ImageRecord->Link);
1330 FreePool (ImageRecord);
1331 mImagePropertiesPrivateData.ImageRecordCount--;
1332 }
1333
1334
1335 /**
1336 Install PropertiesTable.
1337
1338 @param[in] Event The Event this notify function registered to.
1339 @param[in] Context Pointer to the context data registered to the Event.
1340 **/
1341 VOID
1342 EFIAPI
1343 InstallPropertiesTable (
1344 EFI_EVENT Event,
1345 VOID *Context
1346 )
1347 {
1348 mPropertiesTableEndOfDxe = TRUE;
1349 if (PcdGetBool (PcdPropertiesTableEnable)) {
1350 EFI_STATUS Status;
1351
1352 Status = gBS->InstallConfigurationTable (&gEfiPropertiesTableGuid, &mPropertiesTable);
1353 ASSERT_EFI_ERROR (Status);
1354
1355 DEBUG ((EFI_D_INFO, "MemoryProtectionAttribute - 0x%016lx\n", mPropertiesTable.MemoryProtectionAttribute));
1356 if ((mPropertiesTable.MemoryProtectionAttribute & EFI_PROPERTIES_RUNTIME_MEMORY_PROTECTION_NON_EXECUTABLE_PE_DATA) == 0) {
1357 DEBUG ((EFI_D_ERROR, "MemoryProtectionAttribute NON_EXECUTABLE_PE_DATA is not set, "));
1358 DEBUG ((EFI_D_ERROR, "because Runtime Driver Section Alignment is not %dK.\n", RUNTIME_PAGE_ALLOCATION_GRANULARITY >> 10));
1359 return ;
1360 }
1361
1362 gBS->GetMemoryMap = CoreGetMemoryMapWithSeparatedImageSection;
1363 gBS->Hdr.CRC32 = 0;
1364 gBS->CalculateCrc32 ((UINT8 *)gBS, gBS->Hdr.HeaderSize, &gBS->Hdr.CRC32);
1365
1366 DEBUG ((EFI_D_VERBOSE, "Total Image Count - 0x%x\n", mImagePropertiesPrivateData.ImageRecordCount));
1367 DEBUG ((EFI_D_VERBOSE, "Dump ImageRecord:\n"));
1368 DumpImageRecord ();
1369
1370 mPropertiesTableEnable = TRUE;
1371 }
1372 }
1373
1374 /**
1375 Initialize PropertiesTable support.
1376 **/
1377 VOID
1378 EFIAPI
1379 CoreInitializePropertiesTable (
1380 VOID
1381 )
1382 {
1383 EFI_STATUS Status;
1384 EFI_EVENT EndOfDxeEvent;
1385
1386 Status = gBS->CreateEventEx (
1387 EVT_NOTIFY_SIGNAL,
1388 TPL_NOTIFY,
1389 InstallPropertiesTable,
1390 NULL,
1391 &gEfiEndOfDxeEventGroupGuid,
1392 &EndOfDxeEvent
1393 );
1394 ASSERT_EFI_ERROR (Status);
1395 return ;
1396 }