]> git.proxmox.com Git - mirror_edk2.git/blob - UefiCpuPkg/PiSmmCpuDxeSmm/SmmCpuMemoryManagement.c
UefiCpuPkg/PiSmmCpuDxeSmm: Add paging protection.
[mirror_edk2.git] / UefiCpuPkg / PiSmmCpuDxeSmm / SmmCpuMemoryManagement.c
1 /** @file
2
3 Copyright (c) 2016, Intel Corporation. All rights reserved.<BR>
4 This program and the accompanying materials
5 are licensed and made available under the terms and conditions of the BSD License
6 which accompanies this distribution. The full text of the license may be found at
7 http://opensource.org/licenses/bsd-license.php
8
9 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
10 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
11
12 **/
13
14 #include "PiSmmCpuDxeSmm.h"
15
16 #define NEXT_MEMORY_DESCRIPTOR(MemoryDescriptor, Size) \
17 ((EFI_MEMORY_DESCRIPTOR *)((UINT8 *)(MemoryDescriptor) + (Size)))
18
19 PAGE_ATTRIBUTE_TABLE mPageAttributeTable[] = {
20 {Page4K, SIZE_4KB, PAGING_4K_ADDRESS_MASK_64},
21 {Page2M, SIZE_2MB, PAGING_2M_ADDRESS_MASK_64},
22 {Page1G, SIZE_1GB, PAGING_1G_ADDRESS_MASK_64},
23 };
24
25 /**
26 Return page table base.
27
28 @return page table base.
29 **/
30 UINTN
31 GetPageTableBase (
32 VOID
33 )
34 {
35 return (AsmReadCr3 () & PAGING_4K_ADDRESS_MASK_64);
36 }
37
38 /**
39 Return length according to page attributes.
40
41 @param[in] PageAttributes The page attribute of the page entry.
42
43 @return The length of page entry.
44 **/
45 UINTN
46 PageAttributeToLength (
47 IN PAGE_ATTRIBUTE PageAttribute
48 )
49 {
50 UINTN Index;
51 for (Index = 0; Index < sizeof(mPageAttributeTable)/sizeof(mPageAttributeTable[0]); Index++) {
52 if (PageAttribute == mPageAttributeTable[Index].Attribute) {
53 return (UINTN)mPageAttributeTable[Index].Length;
54 }
55 }
56 return 0;
57 }
58
59 /**
60 Return address mask according to page attributes.
61
62 @param[in] PageAttributes The page attribute of the page entry.
63
64 @return The address mask of page entry.
65 **/
66 UINTN
67 PageAttributeToMask (
68 IN PAGE_ATTRIBUTE PageAttribute
69 )
70 {
71 UINTN Index;
72 for (Index = 0; Index < sizeof(mPageAttributeTable)/sizeof(mPageAttributeTable[0]); Index++) {
73 if (PageAttribute == mPageAttributeTable[Index].Attribute) {
74 return (UINTN)mPageAttributeTable[Index].AddressMask;
75 }
76 }
77 return 0;
78 }
79
80 /**
81 Return page table entry to match the address.
82
83 @param[in] Address The address to be checked.
84 @param[out] PageAttributes The page attribute of the page entry.
85
86 @return The page entry.
87 **/
88 VOID *
89 GetPageTableEntry (
90 IN PHYSICAL_ADDRESS Address,
91 OUT PAGE_ATTRIBUTE *PageAttribute
92 )
93 {
94 UINTN Index1;
95 UINTN Index2;
96 UINTN Index3;
97 UINTN Index4;
98 UINT64 *L1PageTable;
99 UINT64 *L2PageTable;
100 UINT64 *L3PageTable;
101 UINT64 *L4PageTable;
102
103 Index4 = ((UINTN)RShiftU64 (Address, 39)) & PAGING_PAE_INDEX_MASK;
104 Index3 = ((UINTN)Address >> 30) & PAGING_PAE_INDEX_MASK;
105 Index2 = ((UINTN)Address >> 21) & PAGING_PAE_INDEX_MASK;
106 Index1 = ((UINTN)Address >> 12) & PAGING_PAE_INDEX_MASK;
107
108 if (sizeof(UINTN) == sizeof(UINT64)) {
109 L4PageTable = (UINT64 *)GetPageTableBase ();
110 if (L4PageTable[Index4] == 0) {
111 *PageAttribute = PageNone;
112 return NULL;
113 }
114
115 L3PageTable = (UINT64 *)(UINTN)(L4PageTable[Index4] & PAGING_4K_ADDRESS_MASK_64);
116 } else {
117 L3PageTable = (UINT64 *)GetPageTableBase ();
118 }
119 if (L3PageTable[Index3] == 0) {
120 *PageAttribute = PageNone;
121 return NULL;
122 }
123 if ((L3PageTable[Index3] & IA32_PG_PS) != 0) {
124 // 1G
125 *PageAttribute = Page1G;
126 return &L3PageTable[Index3];
127 }
128
129 L2PageTable = (UINT64 *)(UINTN)(L3PageTable[Index3] & PAGING_4K_ADDRESS_MASK_64);
130 if (L2PageTable[Index2] == 0) {
131 *PageAttribute = PageNone;
132 return NULL;
133 }
134 if ((L2PageTable[Index2] & IA32_PG_PS) != 0) {
135 // 2M
136 *PageAttribute = Page2M;
137 return &L2PageTable[Index2];
138 }
139
140 // 4k
141 L1PageTable = (UINT64 *)(UINTN)(L2PageTable[Index2] & PAGING_4K_ADDRESS_MASK_64);
142 if ((L1PageTable[Index1] == 0) && (Address != 0)) {
143 *PageAttribute = PageNone;
144 return NULL;
145 }
146 *PageAttribute = Page4K;
147 return &L1PageTable[Index1];
148 }
149
150 /**
151 Return memory attributes of page entry.
152
153 @param[in] PageEntry The page entry.
154
155 @return Memory attributes of page entry.
156 **/
157 UINT64
158 GetAttributesFromPageEntry (
159 IN UINT64 *PageEntry
160 )
161 {
162 UINT64 Attributes;
163 Attributes = 0;
164 if ((*PageEntry & IA32_PG_P) == 0) {
165 Attributes |= EFI_MEMORY_RP;
166 }
167 if ((*PageEntry & IA32_PG_RW) == 0) {
168 Attributes |= EFI_MEMORY_RO;
169 }
170 if ((*PageEntry & IA32_PG_NX) != 0) {
171 Attributes |= EFI_MEMORY_XP;
172 }
173 return Attributes;
174 }
175
176 /**
177 Modify memory attributes of page entry.
178
179 @param[in] PageEntry The page entry.
180 @param[in] Attributes The bit mask of attributes to modify for the memory region.
181 @param[in] IsSet TRUE means to set attributes. FALSE means to clear attributes.
182 @param[out] IsModified TRUE means page table modified. FALSE means page table not modified.
183 **/
184 VOID
185 ConvertPageEntryAttribute (
186 IN UINT64 *PageEntry,
187 IN UINT64 Attributes,
188 IN BOOLEAN IsSet,
189 OUT BOOLEAN *IsModified
190 )
191 {
192 UINT64 CurrentPageEntry;
193 UINT64 NewPageEntry;
194
195 CurrentPageEntry = *PageEntry;
196 NewPageEntry = CurrentPageEntry;
197 if ((Attributes & EFI_MEMORY_RP) != 0) {
198 if (IsSet) {
199 NewPageEntry &= ~(UINT64)IA32_PG_P;
200 } else {
201 NewPageEntry |= IA32_PG_P;
202 }
203 }
204 if ((Attributes & EFI_MEMORY_RO) != 0) {
205 if (IsSet) {
206 NewPageEntry &= ~(UINT64)IA32_PG_RW;
207 } else {
208 NewPageEntry |= IA32_PG_RW;
209 }
210 }
211 if ((Attributes & EFI_MEMORY_XP) != 0) {
212 if (IsSet) {
213 NewPageEntry |= IA32_PG_NX;
214 } else {
215 NewPageEntry &= ~IA32_PG_NX;
216 }
217 }
218 *PageEntry = NewPageEntry;
219 if (CurrentPageEntry != NewPageEntry) {
220 *IsModified = TRUE;
221 DEBUG ((DEBUG_VERBOSE, "ConvertPageEntryAttribute 0x%lx", CurrentPageEntry));
222 DEBUG ((DEBUG_VERBOSE, "->0x%lx\n", NewPageEntry));
223 } else {
224 *IsModified = FALSE;
225 }
226 }
227
228 /**
229 This function returns if there is need to split page entry.
230
231 @param[in] BaseAddress The base address to be checked.
232 @param[in] Length The length to be checked.
233 @param[in] PageEntry The page entry to be checked.
234 @param[in] PageAttribute The page attribute of the page entry.
235
236 @retval SplitAttributes on if there is need to split page entry.
237 **/
238 PAGE_ATTRIBUTE
239 NeedSplitPage (
240 IN PHYSICAL_ADDRESS BaseAddress,
241 IN UINT64 Length,
242 IN UINT64 *PageEntry,
243 IN PAGE_ATTRIBUTE PageAttribute
244 )
245 {
246 UINT64 PageEntryLength;
247
248 PageEntryLength = PageAttributeToLength (PageAttribute);
249
250 if (((BaseAddress & (PageEntryLength - 1)) == 0) && (Length >= PageEntryLength)) {
251 return PageNone;
252 }
253
254 if (((BaseAddress & PAGING_2M_MASK) != 0) || (Length < SIZE_2MB)) {
255 return Page4K;
256 }
257
258 return Page2M;
259 }
260
261 /**
262 This function splits one page entry to small page entries.
263
264 @param[in] PageEntry The page entry to be splitted.
265 @param[in] PageAttribute The page attribute of the page entry.
266 @param[in] SplitAttribute How to split the page entry.
267
268 @retval RETURN_SUCCESS The page entry is splitted.
269 @retval RETURN_UNSUPPORTED The page entry does not support to be splitted.
270 @retval RETURN_OUT_OF_RESOURCES No resource to split page entry.
271 **/
272 RETURN_STATUS
273 SplitPage (
274 IN UINT64 *PageEntry,
275 IN PAGE_ATTRIBUTE PageAttribute,
276 IN PAGE_ATTRIBUTE SplitAttribute
277 )
278 {
279 UINT64 BaseAddress;
280 UINT64 *NewPageEntry;
281 UINTN Index;
282
283 ASSERT (PageAttribute == Page2M || PageAttribute == Page1G);
284
285 if (PageAttribute == Page2M) {
286 //
287 // Split 2M to 4K
288 //
289 ASSERT (SplitAttribute == Page4K);
290 if (SplitAttribute == Page4K) {
291 NewPageEntry = AllocatePageTableMemory (1);
292 DEBUG ((DEBUG_VERBOSE, "Split - 0x%x\n", NewPageEntry));
293 if (NewPageEntry == NULL) {
294 return RETURN_OUT_OF_RESOURCES;
295 }
296 BaseAddress = *PageEntry & PAGING_2M_ADDRESS_MASK_64;
297 for (Index = 0; Index < SIZE_4KB / sizeof(UINT64); Index++) {
298 NewPageEntry[Index] = BaseAddress + SIZE_4KB * Index + ((*PageEntry) & PAGE_PROGATE_BITS);
299 }
300 (*PageEntry) = (UINT64)(UINTN)NewPageEntry + ((*PageEntry) & PAGE_PROGATE_BITS);
301 return RETURN_SUCCESS;
302 } else {
303 return RETURN_UNSUPPORTED;
304 }
305 } else if (PageAttribute == Page1G) {
306 //
307 // Split 1G to 2M
308 // No need support 1G->4K directly, we should use 1G->2M, then 2M->4K to get more compact page table.
309 //
310 ASSERT (SplitAttribute == Page2M || SplitAttribute == Page4K);
311 if ((SplitAttribute == Page2M || SplitAttribute == Page4K)) {
312 NewPageEntry = AllocatePageTableMemory (1);
313 DEBUG ((DEBUG_VERBOSE, "Split - 0x%x\n", NewPageEntry));
314 if (NewPageEntry == NULL) {
315 return RETURN_OUT_OF_RESOURCES;
316 }
317 BaseAddress = *PageEntry & PAGING_1G_ADDRESS_MASK_64;
318 for (Index = 0; Index < SIZE_4KB / sizeof(UINT64); Index++) {
319 NewPageEntry[Index] = BaseAddress + SIZE_2MB * Index + IA32_PG_PS + ((*PageEntry) & PAGE_PROGATE_BITS);
320 }
321 (*PageEntry) = (UINT64)(UINTN)NewPageEntry + ((*PageEntry) & PAGE_PROGATE_BITS);
322 return RETURN_SUCCESS;
323 } else {
324 return RETURN_UNSUPPORTED;
325 }
326 } else {
327 return RETURN_UNSUPPORTED;
328 }
329 }
330
331 /**
332 This function modifies the page attributes for the memory region specified by BaseAddress and
333 Length from their current attributes to the attributes specified by Attributes.
334
335 Caller should make sure BaseAddress and Length is at page boundary.
336
337 @param[in] BaseAddress The physical address that is the start address of a memory region.
338 @param[in] Length The size in bytes of the memory region.
339 @param[in] Attributes The bit mask of attributes to modify for the memory region.
340 @param[in] IsSet TRUE means to set attributes. FALSE means to clear attributes.
341 @param[out] IsSplitted TRUE means page table splitted. FALSE means page table not splitted.
342 @param[out] IsModified TRUE means page table modified. FALSE means page table not modified.
343
344 @retval RETURN_SUCCESS The attributes were modified for the memory region.
345 @retval RETURN_ACCESS_DENIED The attributes for the memory resource range specified by
346 BaseAddress and Length cannot be modified.
347 @retval RETURN_INVALID_PARAMETER Length is zero.
348 Attributes specified an illegal combination of attributes that
349 cannot be set together.
350 @retval RETURN_OUT_OF_RESOURCES There are not enough system resources to modify the attributes of
351 the memory resource range.
352 @retval RETURN_UNSUPPORTED The processor does not support one or more bytes of the memory
353 resource range specified by BaseAddress and Length.
354 The bit mask of attributes is not support for the memory resource
355 range specified by BaseAddress and Length.
356 **/
357 RETURN_STATUS
358 EFIAPI
359 ConvertMemoryPageAttributes (
360 IN PHYSICAL_ADDRESS BaseAddress,
361 IN UINT64 Length,
362 IN UINT64 Attributes,
363 IN BOOLEAN IsSet,
364 OUT BOOLEAN *IsSplitted, OPTIONAL
365 OUT BOOLEAN *IsModified OPTIONAL
366 )
367 {
368 UINT64 *PageEntry;
369 PAGE_ATTRIBUTE PageAttribute;
370 UINTN PageEntryLength;
371 PAGE_ATTRIBUTE SplitAttribute;
372 RETURN_STATUS Status;
373 BOOLEAN IsEntryModified;
374
375 ASSERT (Attributes != 0);
376 ASSERT ((Attributes & ~(EFI_MEMORY_RP | EFI_MEMORY_RO | EFI_MEMORY_XP)) == 0);
377
378 ASSERT ((BaseAddress & (SIZE_4KB - 1)) == 0);
379 ASSERT ((Length & (SIZE_4KB - 1)) == 0);
380
381 if (Length == 0) {
382 return RETURN_INVALID_PARAMETER;
383 }
384
385 // DEBUG ((DEBUG_ERROR, "ConvertMemoryPageAttributes(%x) - %016lx, %016lx, %02lx\n", IsSet, BaseAddress, Length, Attributes));
386
387 if (IsSplitted != NULL) {
388 *IsSplitted = FALSE;
389 }
390 if (IsModified != NULL) {
391 *IsModified = FALSE;
392 }
393
394 //
395 // Below logic is to check 2M/4K page to make sure we donot waist memory.
396 //
397 while (Length != 0) {
398 PageEntry = GetPageTableEntry (BaseAddress, &PageAttribute);
399 if (PageEntry == NULL) {
400 return RETURN_UNSUPPORTED;
401 }
402 PageEntryLength = PageAttributeToLength (PageAttribute);
403 SplitAttribute = NeedSplitPage (BaseAddress, Length, PageEntry, PageAttribute);
404 if (SplitAttribute == PageNone) {
405 ConvertPageEntryAttribute (PageEntry, Attributes, IsSet, &IsEntryModified);
406 if (IsEntryModified) {
407 if (IsModified != NULL) {
408 *IsModified = TRUE;
409 }
410 }
411 //
412 // Convert success, move to next
413 //
414 BaseAddress += PageEntryLength;
415 Length -= PageEntryLength;
416 } else {
417 Status = SplitPage (PageEntry, PageAttribute, SplitAttribute);
418 if (RETURN_ERROR (Status)) {
419 return RETURN_UNSUPPORTED;
420 }
421 if (IsSplitted != NULL) {
422 *IsSplitted = TRUE;
423 }
424 if (IsModified != NULL) {
425 *IsModified = TRUE;
426 }
427 //
428 // Just split current page
429 // Convert success in next around
430 //
431 }
432 }
433
434 return RETURN_SUCCESS;
435 }
436
437 /**
438 FlushTlb on current processor.
439
440 @param[in,out] Buffer Pointer to private data buffer.
441 **/
442 VOID
443 EFIAPI
444 FlushTlbOnCurrentProcessor (
445 IN OUT VOID *Buffer
446 )
447 {
448 CpuFlushTlb ();
449 }
450
451 /**
452 FlushTlb for all processors.
453 **/
454 VOID
455 FlushTlbForAll (
456 VOID
457 )
458 {
459 UINTN Index;
460
461 FlushTlbOnCurrentProcessor (NULL);
462
463 for (Index = 0; Index < gSmst->NumberOfCpus; Index++) {
464 if (Index != gSmst->CurrentlyExecutingCpu) {
465 // Force to start up AP in blocking mode,
466 SmmBlockingStartupThisAp (FlushTlbOnCurrentProcessor, Index, NULL);
467 // Do not check return status, because AP might not be present in some corner cases.
468 }
469 }
470 }
471
472 /**
473 This function sets the attributes for the memory region specified by BaseAddress and
474 Length from their current attributes to the attributes specified by Attributes.
475
476 @param[in] BaseAddress The physical address that is the start address of a memory region.
477 @param[in] Length The size in bytes of the memory region.
478 @param[in] Attributes The bit mask of attributes to set for the memory region.
479 @param[out] IsSplitted TRUE means page table splitted. FALSE means page table not splitted.
480
481 @retval EFI_SUCCESS The attributes were set for the memory region.
482 @retval EFI_ACCESS_DENIED The attributes for the memory resource range specified by
483 BaseAddress and Length cannot be modified.
484 @retval EFI_INVALID_PARAMETER Length is zero.
485 Attributes specified an illegal combination of attributes that
486 cannot be set together.
487 @retval EFI_OUT_OF_RESOURCES There are not enough system resources to modify the attributes of
488 the memory resource range.
489 @retval EFI_UNSUPPORTED The processor does not support one or more bytes of the memory
490 resource range specified by BaseAddress and Length.
491 The bit mask of attributes is not support for the memory resource
492 range specified by BaseAddress and Length.
493
494 **/
495 EFI_STATUS
496 EFIAPI
497 SmmSetMemoryAttributesEx (
498 IN EFI_PHYSICAL_ADDRESS BaseAddress,
499 IN UINT64 Length,
500 IN UINT64 Attributes,
501 OUT BOOLEAN *IsSplitted OPTIONAL
502 )
503 {
504 EFI_STATUS Status;
505 BOOLEAN IsModified;
506
507 Status = ConvertMemoryPageAttributes (BaseAddress, Length, Attributes, TRUE, IsSplitted, &IsModified);
508 if (!EFI_ERROR(Status)) {
509 if (IsModified) {
510 //
511 // Flush TLB as last step
512 //
513 FlushTlbForAll();
514 }
515 }
516
517 return Status;
518 }
519
520 /**
521 This function clears the attributes for the memory region specified by BaseAddress and
522 Length from their current attributes to the attributes specified by Attributes.
523
524 @param[in] BaseAddress The physical address that is the start address of a memory region.
525 @param[in] Length The size in bytes of the memory region.
526 @param[in] Attributes The bit mask of attributes to clear for the memory region.
527 @param[out] IsSplitted TRUE means page table splitted. FALSE means page table not splitted.
528
529 @retval EFI_SUCCESS The attributes were cleared for the memory region.
530 @retval EFI_ACCESS_DENIED The attributes for the memory resource range specified by
531 BaseAddress and Length cannot be modified.
532 @retval EFI_INVALID_PARAMETER Length is zero.
533 Attributes specified an illegal combination of attributes that
534 cannot be set together.
535 @retval EFI_OUT_OF_RESOURCES There are not enough system resources to modify the attributes of
536 the memory resource range.
537 @retval EFI_UNSUPPORTED The processor does not support one or more bytes of the memory
538 resource range specified by BaseAddress and Length.
539 The bit mask of attributes is not support for the memory resource
540 range specified by BaseAddress and Length.
541
542 **/
543 EFI_STATUS
544 EFIAPI
545 SmmClearMemoryAttributesEx (
546 IN EFI_PHYSICAL_ADDRESS BaseAddress,
547 IN UINT64 Length,
548 IN UINT64 Attributes,
549 OUT BOOLEAN *IsSplitted OPTIONAL
550 )
551 {
552 EFI_STATUS Status;
553 BOOLEAN IsModified;
554
555 Status = ConvertMemoryPageAttributes (BaseAddress, Length, Attributes, FALSE, IsSplitted, &IsModified);
556 if (!EFI_ERROR(Status)) {
557 if (IsModified) {
558 //
559 // Flush TLB as last step
560 //
561 FlushTlbForAll();
562 }
563 }
564
565 return Status;
566 }
567
568 /**
569 This function sets the attributes for the memory region specified by BaseAddress and
570 Length from their current attributes to the attributes specified by Attributes.
571
572 @param[in] BaseAddress The physical address that is the start address of a memory region.
573 @param[in] Length The size in bytes of the memory region.
574 @param[in] Attributes The bit mask of attributes to set for the memory region.
575
576 @retval EFI_SUCCESS The attributes were set for the memory region.
577 @retval EFI_ACCESS_DENIED The attributes for the memory resource range specified by
578 BaseAddress and Length cannot be modified.
579 @retval EFI_INVALID_PARAMETER Length is zero.
580 Attributes specified an illegal combination of attributes that
581 cannot be set together.
582 @retval EFI_OUT_OF_RESOURCES There are not enough system resources to modify the attributes of
583 the memory resource range.
584 @retval EFI_UNSUPPORTED The processor does not support one or more bytes of the memory
585 resource range specified by BaseAddress and Length.
586 The bit mask of attributes is not support for the memory resource
587 range specified by BaseAddress and Length.
588
589 **/
590 EFI_STATUS
591 EFIAPI
592 SmmSetMemoryAttributes (
593 IN EFI_PHYSICAL_ADDRESS BaseAddress,
594 IN UINT64 Length,
595 IN UINT64 Attributes
596 )
597 {
598 return SmmSetMemoryAttributesEx (BaseAddress, Length, Attributes, NULL);
599 }
600
601 /**
602 This function clears the attributes for the memory region specified by BaseAddress and
603 Length from their current attributes to the attributes specified by Attributes.
604
605 @param[in] BaseAddress The physical address that is the start address of a memory region.
606 @param[in] Length The size in bytes of the memory region.
607 @param[in] Attributes The bit mask of attributes to clear for the memory region.
608
609 @retval EFI_SUCCESS The attributes were cleared for the memory region.
610 @retval EFI_ACCESS_DENIED The attributes for the memory resource range specified by
611 BaseAddress and Length cannot be modified.
612 @retval EFI_INVALID_PARAMETER Length is zero.
613 Attributes specified an illegal combination of attributes that
614 cannot be set together.
615 @retval EFI_OUT_OF_RESOURCES There are not enough system resources to modify the attributes of
616 the memory resource range.
617 @retval EFI_UNSUPPORTED The processor does not support one or more bytes of the memory
618 resource range specified by BaseAddress and Length.
619 The bit mask of attributes is not support for the memory resource
620 range specified by BaseAddress and Length.
621
622 **/
623 EFI_STATUS
624 EFIAPI
625 SmmClearMemoryAttributes (
626 IN EFI_PHYSICAL_ADDRESS BaseAddress,
627 IN UINT64 Length,
628 IN UINT64 Attributes
629 )
630 {
631 return SmmClearMemoryAttributesEx (BaseAddress, Length, Attributes, NULL);
632 }
633
634
635
636 /**
637 Retrieves a pointer to the system configuration table from the SMM System Table
638 based on a specified GUID.
639
640 @param[in] TableGuid The pointer to table's GUID type.
641 @param[out] Table The pointer to the table associated with TableGuid in the EFI System Table.
642
643 @retval EFI_SUCCESS A configuration table matching TableGuid was found.
644 @retval EFI_NOT_FOUND A configuration table matching TableGuid could not be found.
645
646 **/
647 EFI_STATUS
648 EFIAPI
649 SmmGetSystemConfigurationTable (
650 IN EFI_GUID *TableGuid,
651 OUT VOID **Table
652 )
653 {
654 UINTN Index;
655
656 ASSERT (TableGuid != NULL);
657 ASSERT (Table != NULL);
658
659 *Table = NULL;
660 for (Index = 0; Index < gSmst->NumberOfTableEntries; Index++) {
661 if (CompareGuid (TableGuid, &(gSmst->SmmConfigurationTable[Index].VendorGuid))) {
662 *Table = gSmst->SmmConfigurationTable[Index].VendorTable;
663 return EFI_SUCCESS;
664 }
665 }
666
667 return EFI_NOT_FOUND;
668 }
669
670 /**
671 This function sets SMM save state buffer to be RW and XP.
672 **/
673 VOID
674 PatchSmmSaveStateMap (
675 VOID
676 )
677 {
678 UINTN Index;
679 UINTN TileCodeSize;
680 UINTN TileDataSize;
681 UINTN TileSize;
682
683 TileCodeSize = GetSmiHandlerSize ();
684 TileCodeSize = ALIGN_VALUE(TileCodeSize, SIZE_4KB);
685 TileDataSize = sizeof (SMRAM_SAVE_STATE_MAP) + sizeof (PROCESSOR_SMM_DESCRIPTOR);
686 TileDataSize = ALIGN_VALUE(TileDataSize, SIZE_4KB);
687 TileSize = TileDataSize + TileCodeSize - 1;
688 TileSize = 2 * GetPowerOfTwo32 ((UINT32)TileSize);
689
690 DEBUG ((DEBUG_INFO, "PatchSmmSaveStateMap:\n"));
691 for (Index = 0; Index < mMaxNumberOfCpus - 1; Index++) {
692 //
693 // Code
694 //
695 SmmSetMemoryAttributes (
696 mCpuHotPlugData.SmBase[Index] + SMM_HANDLER_OFFSET,
697 TileCodeSize,
698 EFI_MEMORY_RO
699 );
700 SmmClearMemoryAttributes (
701 mCpuHotPlugData.SmBase[Index] + SMM_HANDLER_OFFSET,
702 TileCodeSize,
703 EFI_MEMORY_XP
704 );
705
706 //
707 // Data
708 //
709 SmmClearMemoryAttributes (
710 mCpuHotPlugData.SmBase[Index] + SMM_HANDLER_OFFSET + TileCodeSize,
711 TileSize - TileCodeSize,
712 EFI_MEMORY_RO
713 );
714 SmmSetMemoryAttributes (
715 mCpuHotPlugData.SmBase[Index] + SMM_HANDLER_OFFSET + TileCodeSize,
716 TileSize - TileCodeSize,
717 EFI_MEMORY_XP
718 );
719 }
720
721 //
722 // Code
723 //
724 SmmSetMemoryAttributes (
725 mCpuHotPlugData.SmBase[mMaxNumberOfCpus - 1] + SMM_HANDLER_OFFSET,
726 TileCodeSize,
727 EFI_MEMORY_RO
728 );
729 SmmClearMemoryAttributes (
730 mCpuHotPlugData.SmBase[mMaxNumberOfCpus - 1] + SMM_HANDLER_OFFSET,
731 TileCodeSize,
732 EFI_MEMORY_XP
733 );
734
735 //
736 // Data
737 //
738 SmmClearMemoryAttributes (
739 mCpuHotPlugData.SmBase[mMaxNumberOfCpus - 1] + SMM_HANDLER_OFFSET + TileCodeSize,
740 SIZE_32KB - TileCodeSize,
741 EFI_MEMORY_RO
742 );
743 SmmSetMemoryAttributes (
744 mCpuHotPlugData.SmBase[mMaxNumberOfCpus - 1] + SMM_HANDLER_OFFSET + TileCodeSize,
745 SIZE_32KB - TileCodeSize,
746 EFI_MEMORY_XP
747 );
748 }
749
750 /**
751 This function sets GDT/IDT buffer to be RO and XP.
752 **/
753 VOID
754 PatchGdtIdtMap (
755 VOID
756 )
757 {
758 EFI_PHYSICAL_ADDRESS BaseAddress;
759 UINTN Size;
760
761 //
762 // GDT
763 //
764 DEBUG ((DEBUG_INFO, "PatchGdtIdtMap - GDT:\n"));
765
766 BaseAddress = mGdtBuffer;
767 Size = ALIGN_VALUE(mGdtBufferSize, SIZE_4KB);
768 SmmSetMemoryAttributes (
769 BaseAddress,
770 Size,
771 EFI_MEMORY_RO
772 );
773 SmmSetMemoryAttributes (
774 BaseAddress,
775 Size,
776 EFI_MEMORY_XP
777 );
778
779 //
780 // IDT
781 //
782 DEBUG ((DEBUG_INFO, "PatchGdtIdtMap - IDT:\n"));
783
784 BaseAddress = gcSmiIdtr.Base;
785 Size = ALIGN_VALUE(gcSmiIdtr.Limit + 1, SIZE_4KB);
786 SmmSetMemoryAttributes (
787 BaseAddress,
788 Size,
789 EFI_MEMORY_RO
790 );
791 SmmSetMemoryAttributes (
792 BaseAddress,
793 Size,
794 EFI_MEMORY_XP
795 );
796 }
797
798 /**
799 This function sets memory attribute according to MemoryAttributesTable.
800 **/
801 VOID
802 SetMemMapAttributes (
803 VOID
804 )
805 {
806 EFI_MEMORY_DESCRIPTOR *MemoryMap;
807 EFI_MEMORY_DESCRIPTOR *MemoryMapStart;
808 UINTN MemoryMapEntryCount;
809 UINTN DescriptorSize;
810 UINTN Index;
811 EDKII_PI_SMM_MEMORY_ATTRIBUTES_TABLE *MemoryAttributesTable;
812
813 SmmGetSystemConfigurationTable (&gEdkiiPiSmmMemoryAttributesTableGuid, (VOID **)&MemoryAttributesTable);
814 if (MemoryAttributesTable == NULL) {
815 DEBUG ((DEBUG_INFO, "MemoryAttributesTable - NULL\n"));
816 return ;
817 }
818
819 DEBUG ((DEBUG_INFO, "MemoryAttributesTable:\n"));
820 DEBUG ((DEBUG_INFO, " Version - 0x%08x\n", MemoryAttributesTable->Version));
821 DEBUG ((DEBUG_INFO, " NumberOfEntries - 0x%08x\n", MemoryAttributesTable->NumberOfEntries));
822 DEBUG ((DEBUG_INFO, " DescriptorSize - 0x%08x\n", MemoryAttributesTable->DescriptorSize));
823
824 MemoryMapEntryCount = MemoryAttributesTable->NumberOfEntries;
825 DescriptorSize = MemoryAttributesTable->DescriptorSize;
826 MemoryMapStart = (EFI_MEMORY_DESCRIPTOR *)(MemoryAttributesTable + 1);
827 MemoryMap = MemoryMapStart;
828 for (Index = 0; Index < MemoryMapEntryCount; Index++) {
829 DEBUG ((DEBUG_INFO, "Entry (0x%x)\n", MemoryMap));
830 DEBUG ((DEBUG_INFO, " Type - 0x%x\n", MemoryMap->Type));
831 DEBUG ((DEBUG_INFO, " PhysicalStart - 0x%016lx\n", MemoryMap->PhysicalStart));
832 DEBUG ((DEBUG_INFO, " VirtualStart - 0x%016lx\n", MemoryMap->VirtualStart));
833 DEBUG ((DEBUG_INFO, " NumberOfPages - 0x%016lx\n", MemoryMap->NumberOfPages));
834 DEBUG ((DEBUG_INFO, " Attribute - 0x%016lx\n", MemoryMap->Attribute));
835 MemoryMap = NEXT_MEMORY_DESCRIPTOR(MemoryMap, DescriptorSize);
836 }
837
838 MemoryMap = MemoryMapStart;
839 for (Index = 0; Index < MemoryMapEntryCount; Index++) {
840 DEBUG ((DEBUG_VERBOSE, "SetAttribute: Memory Entry - 0x%lx, 0x%x\n", MemoryMap->PhysicalStart, MemoryMap->NumberOfPages));
841 switch (MemoryMap->Type) {
842 case EfiRuntimeServicesCode:
843 SmmSetMemoryAttributes (
844 MemoryMap->PhysicalStart,
845 EFI_PAGES_TO_SIZE((UINTN)MemoryMap->NumberOfPages),
846 EFI_MEMORY_RO
847 );
848 break;
849 case EfiRuntimeServicesData:
850 SmmSetMemoryAttributes (
851 MemoryMap->PhysicalStart,
852 EFI_PAGES_TO_SIZE((UINTN)MemoryMap->NumberOfPages),
853 EFI_MEMORY_XP
854 );
855 break;
856 default:
857 SmmSetMemoryAttributes (
858 MemoryMap->PhysicalStart,
859 EFI_PAGES_TO_SIZE((UINTN)MemoryMap->NumberOfPages),
860 EFI_MEMORY_XP
861 );
862 break;
863 }
864 MemoryMap = NEXT_MEMORY_DESCRIPTOR(MemoryMap, DescriptorSize);
865 }
866
867 PatchSmmSaveStateMap ();
868 PatchGdtIdtMap ();
869
870 return ;
871 }