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