]> git.proxmox.com Git - mirror_edk2.git/blob - MdeModulePkg/Core/Dxe/Misc/PropertiesTable.c
MdeModulePkg/DxeCore: switch to MdePkg allocation granularity macros
[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 return TotalNewRecordCount - 1;
580 }
581
582 /**
583 Split the original memory map, and add more entries to describe PE code section and data section.
584 This function will set EfiRuntimeServicesData to be EFI_MEMORY_XP.
585 This function will merge entries with same attributes finally.
586
587 NOTE: It assumes PE code/data section are page aligned.
588 NOTE: It assumes enough entry is prepared for new memory map.
589
590 Split table:
591 +---------------+
592 | Record X |
593 +---------------+
594 | Record RtCode |
595 +---------------+
596 | Record Y |
597 +---------------+
598 ==>
599 +---------------+
600 | Record X |
601 +---------------+ ----
602 | Record RtData | |
603 +---------------+ |
604 | Record RtCode | |-> PE/COFF1
605 +---------------+ |
606 | Record RtData | |
607 +---------------+ ----
608 | Record RtData | |
609 +---------------+ |
610 | Record RtCode | |-> PE/COFF2
611 +---------------+ |
612 | Record RtData | |
613 +---------------+ ----
614 | Record Y |
615 +---------------+
616
617 @param MemoryMapSize A pointer to the size, in bytes, of the
618 MemoryMap buffer. On input, this is the size of
619 old MemoryMap before split. The actual buffer
620 size of MemoryMap is MemoryMapSize +
621 (AdditionalRecordCount * DescriptorSize) calculated
622 below. On output, it is the size of new MemoryMap
623 after split.
624 @param MemoryMap A pointer to the buffer in which firmware places
625 the current memory map.
626 @param DescriptorSize Size, in bytes, of an individual EFI_MEMORY_DESCRIPTOR.
627 **/
628 STATIC
629 VOID
630 SplitTable (
631 IN OUT UINTN *MemoryMapSize,
632 IN OUT EFI_MEMORY_DESCRIPTOR *MemoryMap,
633 IN UINTN DescriptorSize
634 )
635 {
636 INTN IndexOld;
637 INTN IndexNew;
638 UINTN MaxSplitRecordCount;
639 UINTN RealSplitRecordCount;
640 UINTN TotalSplitRecordCount;
641 UINTN AdditionalRecordCount;
642
643 AdditionalRecordCount = (2 * mImagePropertiesPrivateData.CodeSegmentCountMax + 1) * mImagePropertiesPrivateData.ImageRecordCount;
644
645 TotalSplitRecordCount = 0;
646 //
647 // Let old record point to end of valid MemoryMap buffer.
648 //
649 IndexOld = ((*MemoryMapSize) / DescriptorSize) - 1;
650 //
651 // Let new record point to end of full MemoryMap buffer.
652 //
653 IndexNew = ((*MemoryMapSize) / DescriptorSize) - 1 + AdditionalRecordCount;
654 for (; IndexOld >= 0; IndexOld--) {
655 MaxSplitRecordCount = GetMaxSplitRecordCount ((EFI_MEMORY_DESCRIPTOR *)((UINT8 *)MemoryMap + IndexOld * DescriptorSize));
656 //
657 // Split this MemoryMap record
658 //
659 IndexNew -= MaxSplitRecordCount;
660 RealSplitRecordCount = SplitRecord (
661 (EFI_MEMORY_DESCRIPTOR *)((UINT8 *)MemoryMap + IndexOld * DescriptorSize),
662 (EFI_MEMORY_DESCRIPTOR *)((UINT8 *)MemoryMap + IndexNew * DescriptorSize),
663 MaxSplitRecordCount,
664 DescriptorSize
665 );
666 //
667 // Adjust IndexNew according to real split.
668 //
669 CopyMem (
670 ((UINT8 *)MemoryMap + (IndexNew + MaxSplitRecordCount - RealSplitRecordCount) * DescriptorSize),
671 ((UINT8 *)MemoryMap + IndexNew * DescriptorSize),
672 RealSplitRecordCount * DescriptorSize
673 );
674 IndexNew = IndexNew + MaxSplitRecordCount - RealSplitRecordCount;
675 TotalSplitRecordCount += RealSplitRecordCount;
676 IndexNew --;
677 }
678 //
679 // Move all records to the beginning.
680 //
681 CopyMem (
682 MemoryMap,
683 (UINT8 *)MemoryMap + (AdditionalRecordCount - TotalSplitRecordCount) * DescriptorSize,
684 (*MemoryMapSize) + TotalSplitRecordCount * DescriptorSize
685 );
686
687 *MemoryMapSize = (*MemoryMapSize) + DescriptorSize * TotalSplitRecordCount;
688
689 //
690 // Sort from low to high (Just in case)
691 //
692 SortMemoryMap (MemoryMap, *MemoryMapSize, DescriptorSize);
693
694 //
695 // Set RuntimeData to XP
696 //
697 EnforceMemoryMapAttribute (MemoryMap, *MemoryMapSize, DescriptorSize);
698
699 //
700 // Merge same type to save entry size
701 //
702 MergeMemoryMap (MemoryMap, MemoryMapSize, DescriptorSize);
703
704 return ;
705 }
706
707 /**
708 This function for GetMemoryMap() with properties table capability.
709
710 It calls original GetMemoryMap() to get the original memory map information. Then
711 plus the additional memory map entries for PE Code/Data seperation.
712
713 @param MemoryMapSize A pointer to the size, in bytes, of the
714 MemoryMap buffer. On input, this is the size of
715 the buffer allocated by the caller. On output,
716 it is the size of the buffer returned by the
717 firmware if the buffer was large enough, or the
718 size of the buffer needed to contain the map if
719 the buffer was too small.
720 @param MemoryMap A pointer to the buffer in which firmware places
721 the current memory map.
722 @param MapKey A pointer to the location in which firmware
723 returns the key for the current memory map.
724 @param DescriptorSize A pointer to the location in which firmware
725 returns the size, in bytes, of an individual
726 EFI_MEMORY_DESCRIPTOR.
727 @param DescriptorVersion A pointer to the location in which firmware
728 returns the version number associated with the
729 EFI_MEMORY_DESCRIPTOR.
730
731 @retval EFI_SUCCESS The memory map was returned in the MemoryMap
732 buffer.
733 @retval EFI_BUFFER_TOO_SMALL The MemoryMap buffer was too small. The current
734 buffer size needed to hold the memory map is
735 returned in MemoryMapSize.
736 @retval EFI_INVALID_PARAMETER One of the parameters has an invalid value.
737
738 **/
739 EFI_STATUS
740 EFIAPI
741 CoreGetMemoryMapWithSeparatedImageSection (
742 IN OUT UINTN *MemoryMapSize,
743 IN OUT EFI_MEMORY_DESCRIPTOR *MemoryMap,
744 OUT UINTN *MapKey,
745 OUT UINTN *DescriptorSize,
746 OUT UINT32 *DescriptorVersion
747 )
748 {
749 EFI_STATUS Status;
750 UINTN OldMemoryMapSize;
751 UINTN AdditionalRecordCount;
752
753 //
754 // If PE code/data is not aligned, just return.
755 //
756 if ((mPropertiesTable.MemoryProtectionAttribute & EFI_PROPERTIES_RUNTIME_MEMORY_PROTECTION_NON_EXECUTABLE_PE_DATA) == 0) {
757 return CoreGetMemoryMap (MemoryMapSize, MemoryMap, MapKey, DescriptorSize, DescriptorVersion);
758 }
759
760 if (MemoryMapSize == NULL) {
761 return EFI_INVALID_PARAMETER;
762 }
763
764 CoreAcquirePropertiesTableLock ();
765
766 AdditionalRecordCount = (2 * mImagePropertiesPrivateData.CodeSegmentCountMax + 1) * mImagePropertiesPrivateData.ImageRecordCount;
767
768 OldMemoryMapSize = *MemoryMapSize;
769 Status = CoreGetMemoryMap (MemoryMapSize, MemoryMap, MapKey, DescriptorSize, DescriptorVersion);
770 if (Status == EFI_BUFFER_TOO_SMALL) {
771 *MemoryMapSize = *MemoryMapSize + (*DescriptorSize) * AdditionalRecordCount;
772 } else if (Status == EFI_SUCCESS) {
773 ASSERT (MemoryMap != NULL);
774 if (OldMemoryMapSize - *MemoryMapSize < (*DescriptorSize) * AdditionalRecordCount) {
775 *MemoryMapSize = *MemoryMapSize + (*DescriptorSize) * AdditionalRecordCount;
776 //
777 // Need update status to buffer too small
778 //
779 Status = EFI_BUFFER_TOO_SMALL;
780 } else {
781 //
782 // Split PE code/data
783 //
784 SplitTable (MemoryMapSize, MemoryMap, *DescriptorSize);
785 }
786 }
787
788 CoreReleasePropertiesTableLock ();
789 return Status;
790 }
791
792 //
793 // Below functions are for ImageRecord
794 //
795
796 /**
797 Set PropertiesTable according to PE/COFF image section alignment.
798
799 @param SectionAlignment PE/COFF section alignment
800 **/
801 STATIC
802 VOID
803 SetPropertiesTableSectionAlignment (
804 IN UINT32 SectionAlignment
805 )
806 {
807 if (((SectionAlignment & (RUNTIME_PAGE_ALLOCATION_GRANULARITY - 1)) != 0) &&
808 ((mPropertiesTable.MemoryProtectionAttribute & EFI_PROPERTIES_RUNTIME_MEMORY_PROTECTION_NON_EXECUTABLE_PE_DATA) != 0)) {
809 DEBUG ((EFI_D_VERBOSE, "SetPropertiesTableSectionAlignment - Clear\n"));
810 mPropertiesTable.MemoryProtectionAttribute &= ~((UINT64)EFI_PROPERTIES_RUNTIME_MEMORY_PROTECTION_NON_EXECUTABLE_PE_DATA);
811 gBS->GetMemoryMap = CoreGetMemoryMap;
812 gBS->Hdr.CRC32 = 0;
813 gBS->CalculateCrc32 ((UINT8 *)gBS, gBS->Hdr.HeaderSize, &gBS->Hdr.CRC32);
814 }
815 }
816
817 /**
818 Swap two code sections in image record.
819
820 @param FirstImageRecordCodeSection first code section in image record
821 @param SecondImageRecordCodeSection second code section in image record
822 **/
823 STATIC
824 VOID
825 SwapImageRecordCodeSection (
826 IN IMAGE_PROPERTIES_RECORD_CODE_SECTION *FirstImageRecordCodeSection,
827 IN IMAGE_PROPERTIES_RECORD_CODE_SECTION *SecondImageRecordCodeSection
828 )
829 {
830 IMAGE_PROPERTIES_RECORD_CODE_SECTION TempImageRecordCodeSection;
831
832 TempImageRecordCodeSection.CodeSegmentBase = FirstImageRecordCodeSection->CodeSegmentBase;
833 TempImageRecordCodeSection.CodeSegmentSize = FirstImageRecordCodeSection->CodeSegmentSize;
834
835 FirstImageRecordCodeSection->CodeSegmentBase = SecondImageRecordCodeSection->CodeSegmentBase;
836 FirstImageRecordCodeSection->CodeSegmentSize = SecondImageRecordCodeSection->CodeSegmentSize;
837
838 SecondImageRecordCodeSection->CodeSegmentBase = TempImageRecordCodeSection.CodeSegmentBase;
839 SecondImageRecordCodeSection->CodeSegmentSize = TempImageRecordCodeSection.CodeSegmentSize;
840 }
841
842 /**
843 Sort code section in image record, based upon CodeSegmentBase from low to high.
844
845 @param ImageRecord image record to be sorted
846 **/
847 VOID
848 SortImageRecordCodeSection (
849 IN IMAGE_PROPERTIES_RECORD *ImageRecord
850 )
851 {
852 IMAGE_PROPERTIES_RECORD_CODE_SECTION *ImageRecordCodeSection;
853 IMAGE_PROPERTIES_RECORD_CODE_SECTION *NextImageRecordCodeSection;
854 LIST_ENTRY *ImageRecordCodeSectionLink;
855 LIST_ENTRY *NextImageRecordCodeSectionLink;
856 LIST_ENTRY *ImageRecordCodeSectionEndLink;
857 LIST_ENTRY *ImageRecordCodeSectionList;
858
859 ImageRecordCodeSectionList = &ImageRecord->CodeSegmentList;
860
861 ImageRecordCodeSectionLink = ImageRecordCodeSectionList->ForwardLink;
862 NextImageRecordCodeSectionLink = ImageRecordCodeSectionLink->ForwardLink;
863 ImageRecordCodeSectionEndLink = ImageRecordCodeSectionList;
864 while (ImageRecordCodeSectionLink != ImageRecordCodeSectionEndLink) {
865 ImageRecordCodeSection = CR (
866 ImageRecordCodeSectionLink,
867 IMAGE_PROPERTIES_RECORD_CODE_SECTION,
868 Link,
869 IMAGE_PROPERTIES_RECORD_CODE_SECTION_SIGNATURE
870 );
871 while (NextImageRecordCodeSectionLink != ImageRecordCodeSectionEndLink) {
872 NextImageRecordCodeSection = CR (
873 NextImageRecordCodeSectionLink,
874 IMAGE_PROPERTIES_RECORD_CODE_SECTION,
875 Link,
876 IMAGE_PROPERTIES_RECORD_CODE_SECTION_SIGNATURE
877 );
878 if (ImageRecordCodeSection->CodeSegmentBase > NextImageRecordCodeSection->CodeSegmentBase) {
879 SwapImageRecordCodeSection (ImageRecordCodeSection, NextImageRecordCodeSection);
880 }
881 NextImageRecordCodeSectionLink = NextImageRecordCodeSectionLink->ForwardLink;
882 }
883
884 ImageRecordCodeSectionLink = ImageRecordCodeSectionLink->ForwardLink;
885 NextImageRecordCodeSectionLink = ImageRecordCodeSectionLink->ForwardLink;
886 }
887 }
888
889 /**
890 Check if code section in image record is valid.
891
892 @param ImageRecord image record to be checked
893
894 @retval TRUE image record is valid
895 @retval FALSE image record is invalid
896 **/
897 BOOLEAN
898 IsImageRecordCodeSectionValid (
899 IN IMAGE_PROPERTIES_RECORD *ImageRecord
900 )
901 {
902 IMAGE_PROPERTIES_RECORD_CODE_SECTION *ImageRecordCodeSection;
903 IMAGE_PROPERTIES_RECORD_CODE_SECTION *LastImageRecordCodeSection;
904 LIST_ENTRY *ImageRecordCodeSectionLink;
905 LIST_ENTRY *ImageRecordCodeSectionEndLink;
906 LIST_ENTRY *ImageRecordCodeSectionList;
907
908 DEBUG ((EFI_D_VERBOSE, "ImageCode SegmentCount - 0x%x\n", ImageRecord->CodeSegmentCount));
909
910 ImageRecordCodeSectionList = &ImageRecord->CodeSegmentList;
911
912 ImageRecordCodeSectionLink = ImageRecordCodeSectionList->ForwardLink;
913 ImageRecordCodeSectionEndLink = ImageRecordCodeSectionList;
914 LastImageRecordCodeSection = NULL;
915 while (ImageRecordCodeSectionLink != ImageRecordCodeSectionEndLink) {
916 ImageRecordCodeSection = CR (
917 ImageRecordCodeSectionLink,
918 IMAGE_PROPERTIES_RECORD_CODE_SECTION,
919 Link,
920 IMAGE_PROPERTIES_RECORD_CODE_SECTION_SIGNATURE
921 );
922 if (ImageRecordCodeSection->CodeSegmentSize == 0) {
923 return FALSE;
924 }
925 if (ImageRecordCodeSection->CodeSegmentBase < ImageRecord->ImageBase) {
926 return FALSE;
927 }
928 if (ImageRecordCodeSection->CodeSegmentBase >= MAX_ADDRESS - ImageRecordCodeSection->CodeSegmentSize) {
929 return FALSE;
930 }
931 if ((ImageRecordCodeSection->CodeSegmentBase + ImageRecordCodeSection->CodeSegmentSize) > (ImageRecord->ImageBase + ImageRecord->ImageSize)) {
932 return FALSE;
933 }
934 if (LastImageRecordCodeSection != NULL) {
935 if ((LastImageRecordCodeSection->CodeSegmentBase + LastImageRecordCodeSection->CodeSegmentSize) > ImageRecordCodeSection->CodeSegmentBase) {
936 return FALSE;
937 }
938 }
939
940 LastImageRecordCodeSection = ImageRecordCodeSection;
941 ImageRecordCodeSectionLink = ImageRecordCodeSectionLink->ForwardLink;
942 }
943
944 return TRUE;
945 }
946
947 /**
948 Swap two image records.
949
950 @param FirstImageRecord first image record.
951 @param SecondImageRecord second image record.
952 **/
953 STATIC
954 VOID
955 SwapImageRecord (
956 IN IMAGE_PROPERTIES_RECORD *FirstImageRecord,
957 IN IMAGE_PROPERTIES_RECORD *SecondImageRecord
958 )
959 {
960 IMAGE_PROPERTIES_RECORD TempImageRecord;
961
962 TempImageRecord.ImageBase = FirstImageRecord->ImageBase;
963 TempImageRecord.ImageSize = FirstImageRecord->ImageSize;
964 TempImageRecord.CodeSegmentCount = FirstImageRecord->CodeSegmentCount;
965
966 FirstImageRecord->ImageBase = SecondImageRecord->ImageBase;
967 FirstImageRecord->ImageSize = SecondImageRecord->ImageSize;
968 FirstImageRecord->CodeSegmentCount = SecondImageRecord->CodeSegmentCount;
969
970 SecondImageRecord->ImageBase = TempImageRecord.ImageBase;
971 SecondImageRecord->ImageSize = TempImageRecord.ImageSize;
972 SecondImageRecord->CodeSegmentCount = TempImageRecord.CodeSegmentCount;
973
974 SwapListEntries (&FirstImageRecord->CodeSegmentList, &SecondImageRecord->CodeSegmentList);
975 }
976
977 /**
978 Sort image record based upon the ImageBase from low to high.
979 **/
980 STATIC
981 VOID
982 SortImageRecord (
983 VOID
984 )
985 {
986 IMAGE_PROPERTIES_RECORD *ImageRecord;
987 IMAGE_PROPERTIES_RECORD *NextImageRecord;
988 LIST_ENTRY *ImageRecordLink;
989 LIST_ENTRY *NextImageRecordLink;
990 LIST_ENTRY *ImageRecordEndLink;
991 LIST_ENTRY *ImageRecordList;
992
993 ImageRecordList = &mImagePropertiesPrivateData.ImageRecordList;
994
995 ImageRecordLink = ImageRecordList->ForwardLink;
996 NextImageRecordLink = ImageRecordLink->ForwardLink;
997 ImageRecordEndLink = ImageRecordList;
998 while (ImageRecordLink != ImageRecordEndLink) {
999 ImageRecord = CR (
1000 ImageRecordLink,
1001 IMAGE_PROPERTIES_RECORD,
1002 Link,
1003 IMAGE_PROPERTIES_RECORD_SIGNATURE
1004 );
1005 while (NextImageRecordLink != ImageRecordEndLink) {
1006 NextImageRecord = CR (
1007 NextImageRecordLink,
1008 IMAGE_PROPERTIES_RECORD,
1009 Link,
1010 IMAGE_PROPERTIES_RECORD_SIGNATURE
1011 );
1012 if (ImageRecord->ImageBase > NextImageRecord->ImageBase) {
1013 SwapImageRecord (ImageRecord, NextImageRecord);
1014 }
1015 NextImageRecordLink = NextImageRecordLink->ForwardLink;
1016 }
1017
1018 ImageRecordLink = ImageRecordLink->ForwardLink;
1019 NextImageRecordLink = ImageRecordLink->ForwardLink;
1020 }
1021 }
1022
1023 /**
1024 Dump image record.
1025 **/
1026 STATIC
1027 VOID
1028 DumpImageRecord (
1029 VOID
1030 )
1031 {
1032 IMAGE_PROPERTIES_RECORD *ImageRecord;
1033 LIST_ENTRY *ImageRecordLink;
1034 LIST_ENTRY *ImageRecordList;
1035 UINTN Index;
1036
1037 ImageRecordList = &mImagePropertiesPrivateData.ImageRecordList;
1038
1039 for (ImageRecordLink = ImageRecordList->ForwardLink, Index= 0;
1040 ImageRecordLink != ImageRecordList;
1041 ImageRecordLink = ImageRecordLink->ForwardLink, Index++) {
1042 ImageRecord = CR (
1043 ImageRecordLink,
1044 IMAGE_PROPERTIES_RECORD,
1045 Link,
1046 IMAGE_PROPERTIES_RECORD_SIGNATURE
1047 );
1048 DEBUG ((EFI_D_VERBOSE, " Image[%d]: 0x%016lx - 0x%016lx\n", Index, ImageRecord->ImageBase, ImageRecord->ImageSize));
1049 }
1050 }
1051
1052 /**
1053 Insert image record.
1054
1055 @param RuntimeImage Runtime image information
1056 **/
1057 VOID
1058 InsertImageRecord (
1059 IN EFI_RUNTIME_IMAGE_ENTRY *RuntimeImage
1060 )
1061 {
1062 VOID *ImageAddress;
1063 EFI_IMAGE_DOS_HEADER *DosHdr;
1064 UINT32 PeCoffHeaderOffset;
1065 UINT32 SectionAlignment;
1066 EFI_IMAGE_SECTION_HEADER *Section;
1067 EFI_IMAGE_OPTIONAL_HEADER_PTR_UNION Hdr;
1068 UINT8 *Name;
1069 UINTN Index;
1070 IMAGE_PROPERTIES_RECORD *ImageRecord;
1071 CHAR8 *PdbPointer;
1072 IMAGE_PROPERTIES_RECORD_CODE_SECTION *ImageRecordCodeSection;
1073 UINT16 Magic;
1074
1075 DEBUG ((EFI_D_VERBOSE, "InsertImageRecord - 0x%x\n", RuntimeImage));
1076 DEBUG ((EFI_D_VERBOSE, "InsertImageRecord - 0x%016lx - 0x%016lx\n", (EFI_PHYSICAL_ADDRESS)(UINTN)RuntimeImage->ImageBase, RuntimeImage->ImageSize));
1077
1078 ImageRecord = AllocatePool (sizeof(*ImageRecord));
1079 if (ImageRecord == NULL) {
1080 return ;
1081 }
1082 ImageRecord->Signature = IMAGE_PROPERTIES_RECORD_SIGNATURE;
1083
1084 DEBUG ((EFI_D_VERBOSE, "ImageRecordCount - 0x%x\n", mImagePropertiesPrivateData.ImageRecordCount));
1085
1086 //
1087 // Step 1: record whole region
1088 //
1089 ImageRecord->ImageBase = (EFI_PHYSICAL_ADDRESS)(UINTN)RuntimeImage->ImageBase;
1090 ImageRecord->ImageSize = RuntimeImage->ImageSize;
1091
1092 ImageAddress = RuntimeImage->ImageBase;
1093
1094 PdbPointer = PeCoffLoaderGetPdbPointer ((VOID*) (UINTN) ImageAddress);
1095 if (PdbPointer != NULL) {
1096 DEBUG ((EFI_D_VERBOSE, " Image - %a\n", PdbPointer));
1097 }
1098
1099 //
1100 // Check PE/COFF image
1101 //
1102 DosHdr = (EFI_IMAGE_DOS_HEADER *) (UINTN) ImageAddress;
1103 PeCoffHeaderOffset = 0;
1104 if (DosHdr->e_magic == EFI_IMAGE_DOS_SIGNATURE) {
1105 PeCoffHeaderOffset = DosHdr->e_lfanew;
1106 }
1107
1108 Hdr.Pe32 = (EFI_IMAGE_NT_HEADERS32 *)((UINT8 *) (UINTN) ImageAddress + PeCoffHeaderOffset);
1109 if (Hdr.Pe32->Signature != EFI_IMAGE_NT_SIGNATURE) {
1110 DEBUG ((EFI_D_VERBOSE, "Hdr.Pe32->Signature invalid - 0x%x\n", Hdr.Pe32->Signature));
1111 // It might be image in SMM.
1112 goto Finish;
1113 }
1114
1115 //
1116 // Get SectionAlignment
1117 //
1118 if (Hdr.Pe32->FileHeader.Machine == IMAGE_FILE_MACHINE_IA64 && Hdr.Pe32->OptionalHeader.Magic == EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC) {
1119 //
1120 // NOTE: Some versions of Linux ELILO for Itanium have an incorrect magic value
1121 // in the PE/COFF Header. If the MachineType is Itanium(IA64) and the
1122 // Magic value in the OptionalHeader is EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC
1123 // then override the magic value to EFI_IMAGE_NT_OPTIONAL_HDR64_MAGIC
1124 //
1125 Magic = EFI_IMAGE_NT_OPTIONAL_HDR64_MAGIC;
1126 } else {
1127 //
1128 // Get the magic value from the PE/COFF Optional Header
1129 //
1130 Magic = Hdr.Pe32->OptionalHeader.Magic;
1131 }
1132 if (Magic == EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC) {
1133 SectionAlignment = Hdr.Pe32->OptionalHeader.SectionAlignment;
1134 } else {
1135 SectionAlignment = Hdr.Pe32Plus->OptionalHeader.SectionAlignment;
1136 }
1137
1138 SetPropertiesTableSectionAlignment (SectionAlignment);
1139 if ((SectionAlignment & (RUNTIME_PAGE_ALLOCATION_GRANULARITY - 1)) != 0) {
1140 DEBUG ((EFI_D_WARN, "!!!!!!!! InsertImageRecord - Section Alignment(0x%x) is not %dK !!!!!!!!\n",
1141 SectionAlignment, RUNTIME_PAGE_ALLOCATION_GRANULARITY >> 10));
1142 PdbPointer = PeCoffLoaderGetPdbPointer ((VOID*) (UINTN) ImageAddress);
1143 if (PdbPointer != NULL) {
1144 DEBUG ((EFI_D_WARN, "!!!!!!!! Image - %a !!!!!!!!\n", PdbPointer));
1145 }
1146 goto Finish;
1147 }
1148
1149 Section = (EFI_IMAGE_SECTION_HEADER *) (
1150 (UINT8 *) (UINTN) ImageAddress +
1151 PeCoffHeaderOffset +
1152 sizeof(UINT32) +
1153 sizeof(EFI_IMAGE_FILE_HEADER) +
1154 Hdr.Pe32->FileHeader.SizeOfOptionalHeader
1155 );
1156 ImageRecord->CodeSegmentCount = 0;
1157 InitializeListHead (&ImageRecord->CodeSegmentList);
1158 for (Index = 0; Index < Hdr.Pe32->FileHeader.NumberOfSections; Index++) {
1159 Name = Section[Index].Name;
1160 DEBUG ((
1161 EFI_D_VERBOSE,
1162 " Section - '%c%c%c%c%c%c%c%c'\n",
1163 Name[0],
1164 Name[1],
1165 Name[2],
1166 Name[3],
1167 Name[4],
1168 Name[5],
1169 Name[6],
1170 Name[7]
1171 ));
1172
1173 if ((Section[Index].Characteristics & EFI_IMAGE_SCN_CNT_CODE) != 0) {
1174 DEBUG ((EFI_D_VERBOSE, " VirtualSize - 0x%08x\n", Section[Index].Misc.VirtualSize));
1175 DEBUG ((EFI_D_VERBOSE, " VirtualAddress - 0x%08x\n", Section[Index].VirtualAddress));
1176 DEBUG ((EFI_D_VERBOSE, " SizeOfRawData - 0x%08x\n", Section[Index].SizeOfRawData));
1177 DEBUG ((EFI_D_VERBOSE, " PointerToRawData - 0x%08x\n", Section[Index].PointerToRawData));
1178 DEBUG ((EFI_D_VERBOSE, " PointerToRelocations - 0x%08x\n", Section[Index].PointerToRelocations));
1179 DEBUG ((EFI_D_VERBOSE, " PointerToLinenumbers - 0x%08x\n", Section[Index].PointerToLinenumbers));
1180 DEBUG ((EFI_D_VERBOSE, " NumberOfRelocations - 0x%08x\n", Section[Index].NumberOfRelocations));
1181 DEBUG ((EFI_D_VERBOSE, " NumberOfLinenumbers - 0x%08x\n", Section[Index].NumberOfLinenumbers));
1182 DEBUG ((EFI_D_VERBOSE, " Characteristics - 0x%08x\n", Section[Index].Characteristics));
1183
1184 //
1185 // Step 2: record code section
1186 //
1187 ImageRecordCodeSection = AllocatePool (sizeof(*ImageRecordCodeSection));
1188 if (ImageRecordCodeSection == NULL) {
1189 return ;
1190 }
1191 ImageRecordCodeSection->Signature = IMAGE_PROPERTIES_RECORD_CODE_SECTION_SIGNATURE;
1192
1193 ImageRecordCodeSection->CodeSegmentBase = (UINTN)ImageAddress + Section[Index].VirtualAddress;
1194 ImageRecordCodeSection->CodeSegmentSize = Section[Index].SizeOfRawData;
1195
1196 DEBUG ((EFI_D_VERBOSE, "ImageCode: 0x%016lx - 0x%016lx\n", ImageRecordCodeSection->CodeSegmentBase, ImageRecordCodeSection->CodeSegmentSize));
1197
1198 InsertTailList (&ImageRecord->CodeSegmentList, &ImageRecordCodeSection->Link);
1199 ImageRecord->CodeSegmentCount++;
1200 }
1201 }
1202
1203 if (ImageRecord->CodeSegmentCount == 0) {
1204 SetPropertiesTableSectionAlignment (1);
1205 DEBUG ((EFI_D_ERROR, "!!!!!!!! InsertImageRecord - CodeSegmentCount is 0 !!!!!!!!\n"));
1206 PdbPointer = PeCoffLoaderGetPdbPointer ((VOID*) (UINTN) ImageAddress);
1207 if (PdbPointer != NULL) {
1208 DEBUG ((EFI_D_ERROR, "!!!!!!!! Image - %a !!!!!!!!\n", PdbPointer));
1209 }
1210 goto Finish;
1211 }
1212
1213 //
1214 // Final
1215 //
1216 SortImageRecordCodeSection (ImageRecord);
1217 //
1218 // Check overlap all section in ImageBase/Size
1219 //
1220 if (!IsImageRecordCodeSectionValid (ImageRecord)) {
1221 DEBUG ((EFI_D_ERROR, "IsImageRecordCodeSectionValid - FAIL\n"));
1222 goto Finish;
1223 }
1224
1225 InsertTailList (&mImagePropertiesPrivateData.ImageRecordList, &ImageRecord->Link);
1226 mImagePropertiesPrivateData.ImageRecordCount++;
1227
1228 SortImageRecord ();
1229
1230 if (mImagePropertiesPrivateData.CodeSegmentCountMax < ImageRecord->CodeSegmentCount) {
1231 mImagePropertiesPrivateData.CodeSegmentCountMax = ImageRecord->CodeSegmentCount;
1232 }
1233
1234 Finish:
1235 return ;
1236 }
1237
1238 /**
1239 Find image record according to image base and size.
1240
1241 @param ImageBase Base of PE image
1242 @param ImageSize Size of PE image
1243
1244 @return image record
1245 **/
1246 STATIC
1247 IMAGE_PROPERTIES_RECORD *
1248 FindImageRecord (
1249 IN EFI_PHYSICAL_ADDRESS ImageBase,
1250 IN UINT64 ImageSize
1251 )
1252 {
1253 IMAGE_PROPERTIES_RECORD *ImageRecord;
1254 LIST_ENTRY *ImageRecordLink;
1255 LIST_ENTRY *ImageRecordList;
1256
1257 ImageRecordList = &mImagePropertiesPrivateData.ImageRecordList;
1258
1259 for (ImageRecordLink = ImageRecordList->ForwardLink;
1260 ImageRecordLink != ImageRecordList;
1261 ImageRecordLink = ImageRecordLink->ForwardLink) {
1262 ImageRecord = CR (
1263 ImageRecordLink,
1264 IMAGE_PROPERTIES_RECORD,
1265 Link,
1266 IMAGE_PROPERTIES_RECORD_SIGNATURE
1267 );
1268
1269 if ((ImageBase == ImageRecord->ImageBase) &&
1270 (ImageSize == ImageRecord->ImageSize)) {
1271 return ImageRecord;
1272 }
1273 }
1274
1275 return NULL;
1276 }
1277
1278 /**
1279 Remove Image record.
1280
1281 @param RuntimeImage Runtime image information
1282 **/
1283 VOID
1284 RemoveImageRecord (
1285 IN EFI_RUNTIME_IMAGE_ENTRY *RuntimeImage
1286 )
1287 {
1288 IMAGE_PROPERTIES_RECORD *ImageRecord;
1289 LIST_ENTRY *CodeSegmentListHead;
1290 IMAGE_PROPERTIES_RECORD_CODE_SECTION *ImageRecordCodeSection;
1291
1292 DEBUG ((EFI_D_VERBOSE, "RemoveImageRecord - 0x%x\n", RuntimeImage));
1293 DEBUG ((EFI_D_VERBOSE, "RemoveImageRecord - 0x%016lx - 0x%016lx\n", (EFI_PHYSICAL_ADDRESS)(UINTN)RuntimeImage->ImageBase, RuntimeImage->ImageSize));
1294
1295 ImageRecord = FindImageRecord ((EFI_PHYSICAL_ADDRESS)(UINTN)RuntimeImage->ImageBase, RuntimeImage->ImageSize);
1296 if (ImageRecord == NULL) {
1297 DEBUG ((EFI_D_ERROR, "!!!!!!!! ImageRecord not found !!!!!!!!\n"));
1298 return ;
1299 }
1300
1301 CodeSegmentListHead = &ImageRecord->CodeSegmentList;
1302 while (!IsListEmpty (CodeSegmentListHead)) {
1303 ImageRecordCodeSection = CR (
1304 CodeSegmentListHead->ForwardLink,
1305 IMAGE_PROPERTIES_RECORD_CODE_SECTION,
1306 Link,
1307 IMAGE_PROPERTIES_RECORD_CODE_SECTION_SIGNATURE
1308 );
1309 RemoveEntryList (&ImageRecordCodeSection->Link);
1310 FreePool (ImageRecordCodeSection);
1311 }
1312
1313 RemoveEntryList (&ImageRecord->Link);
1314 FreePool (ImageRecord);
1315 mImagePropertiesPrivateData.ImageRecordCount--;
1316 }
1317
1318
1319 /**
1320 Install PropertiesTable.
1321
1322 @param[in] Event The Event this notify function registered to.
1323 @param[in] Context Pointer to the context data registered to the Event.
1324 **/
1325 VOID
1326 EFIAPI
1327 InstallPropertiesTable (
1328 EFI_EVENT Event,
1329 VOID *Context
1330 )
1331 {
1332 if (PcdGetBool (PcdPropertiesTableEnable)) {
1333 EFI_STATUS Status;
1334
1335 Status = gBS->InstallConfigurationTable (&gEfiPropertiesTableGuid, &mPropertiesTable);
1336 ASSERT_EFI_ERROR (Status);
1337
1338 DEBUG ((EFI_D_INFO, "MemoryProtectionAttribute - 0x%016lx\n", mPropertiesTable.MemoryProtectionAttribute));
1339 if ((mPropertiesTable.MemoryProtectionAttribute & EFI_PROPERTIES_RUNTIME_MEMORY_PROTECTION_NON_EXECUTABLE_PE_DATA) == 0) {
1340 DEBUG ((EFI_D_ERROR, "MemoryProtectionAttribute NON_EXECUTABLE_PE_DATA is not set, "));
1341 DEBUG ((EFI_D_ERROR, "because Runtime Driver Section Alignment is not %dK.\n", RUNTIME_PAGE_ALLOCATION_GRANULARITY >> 10));
1342 return ;
1343 }
1344
1345 gBS->GetMemoryMap = CoreGetMemoryMapWithSeparatedImageSection;
1346 gBS->Hdr.CRC32 = 0;
1347 gBS->CalculateCrc32 ((UINT8 *)gBS, gBS->Hdr.HeaderSize, &gBS->Hdr.CRC32);
1348
1349 DEBUG ((EFI_D_VERBOSE, "Total Image Count - 0x%x\n", mImagePropertiesPrivateData.ImageRecordCount));
1350 DEBUG ((EFI_D_VERBOSE, "Dump ImageRecord:\n"));
1351 DumpImageRecord ();
1352
1353 mPropertiesTableEnable = TRUE;
1354 }
1355 }
1356
1357 /**
1358 Initialize PropertiesTable support.
1359 **/
1360 VOID
1361 EFIAPI
1362 CoreInitializePropertiesTable (
1363 VOID
1364 )
1365 {
1366 EFI_STATUS Status;
1367 EFI_EVENT EndOfDxeEvent;
1368
1369 Status = gBS->CreateEventEx (
1370 EVT_NOTIFY_SIGNAL,
1371 TPL_NOTIFY,
1372 InstallPropertiesTable,
1373 NULL,
1374 &gEfiEndOfDxeEventGroupGuid,
1375 &EndOfDxeEvent
1376 );
1377 ASSERT_EFI_ERROR (Status);
1378 return ;
1379 }