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