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