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