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