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