3 Virtual Memory Management Services to set or clear the memory encryption.
5 Copyright (c) 2006 - 2018, Intel Corporation. All rights reserved.<BR>
6 Copyright (c) 2017, AMD Incorporated. All rights reserved.<BR>
8 SPDX-License-Identifier: BSD-2-Clause-Patent
10 Code is derived from MdeModulePkg/Core/DxeIplPeim/X64/VirtualMemory.c
13 There a lot of duplicated codes for Page Table operations. These
14 codes should be moved to a common library (PageTablesLib) so that it is
15 more friendly for review and maintain. There is a new feature requirement
16 https://bugzilla.tianocore.org/show_bug.cgi?id=847 which is to implement
17 the library. After the lib is introduced, this file will be refactored.
22 #include <Uefi/UefiBaseType.h>
23 #include <Library/CpuLib.h>
24 #include <Library/BaseLib.h>
25 #include <Library/DebugLib.h>
26 #include <Library/MemEncryptTdxLib.h>
27 #include "VirtualMemory.h"
28 #include <IndustryStandard/Tdx.h>
29 #include <Library/TdxLib.h>
30 #include <Library/UefiBootServicesTableLib.h>
31 #include <Protocol/MemoryAccept.h>
32 #include <ConfidentialComputingGuestAttr.h>
39 STATIC PAGE_TABLE_POOL
*mPageTablePool
= NULL
;
42 Returns boolean to indicate whether to indicate which, if any, memory encryption is enabled
44 @param[in] Type Bitmask of encryption technologies to check is enabled
46 @retval TRUE The encryption type(s) are enabled
47 @retval FALSE The encryption type(s) are not enabled
51 MemEncryptTdxIsEnabled (
55 return CC_GUEST_IS_TDX (PcdGet64 (PcdConfidentialComputingGuestAttr
));
59 Get the memory encryption mask
61 @param[out] EncryptionMask contains the pte mask.
66 GetMemEncryptionAddressMask (
70 return TdSharedPageMask ();
74 Initialize a buffer pool for page table use only.
76 To reduce the potential split operation on page table, the pages reserved for
77 page table should be allocated in the times of PAGE_TABLE_POOL_UNIT_PAGES and
78 at the boundary of PAGE_TABLE_POOL_ALIGNMENT. So the page pool is always
79 initialized with number of pages greater than or equal to the given
82 Once the pages in the pool are used up, this method should be called again to
83 reserve at least another PAGE_TABLE_POOL_UNIT_PAGES. Usually this won't
84 happen often in practice.
86 @param[in] PoolPages The least page number of the pool to be created.
88 @retval TRUE The pool is initialized successfully.
89 @retval FALSE The memory is out of resource.
93 InitializePageTablePool (
100 // Always reserve at least PAGE_TABLE_POOL_UNIT_PAGES, including one page for
103 PoolPages
+= 1; // Add one page for header.
104 PoolPages
= ((PoolPages
- 1) / PAGE_TABLE_POOL_UNIT_PAGES
+ 1) *
105 PAGE_TABLE_POOL_UNIT_PAGES
;
106 Buffer
= AllocateAlignedPages (PoolPages
, PAGE_TABLE_POOL_ALIGNMENT
);
107 if (Buffer
== NULL
) {
108 DEBUG ((DEBUG_ERROR
, "ERROR: Out of aligned pages\r\n"));
113 // Link all pools into a list for easier track later.
115 if (mPageTablePool
== NULL
) {
116 mPageTablePool
= Buffer
;
117 mPageTablePool
->NextPool
= mPageTablePool
;
119 ((PAGE_TABLE_POOL
*)Buffer
)->NextPool
= mPageTablePool
->NextPool
;
120 mPageTablePool
->NextPool
= Buffer
;
121 mPageTablePool
= Buffer
;
125 // Reserve one page for pool header.
127 mPageTablePool
->FreePages
= PoolPages
- 1;
128 mPageTablePool
->Offset
= EFI_PAGES_TO_SIZE (1);
134 This API provides a way to allocate memory for page table.
136 This API can be called more than once to allocate memory for page tables.
138 Allocates the number of 4KB pages and returns a pointer to the allocated
139 buffer. The buffer returned is aligned on a 4KB boundary.
141 If Pages is 0, then NULL is returned.
142 If there is not enough memory remaining to satisfy the request, then NULL is
145 @param Pages The number of 4 KB pages to allocate.
147 @return A pointer to the allocated buffer or NULL if allocation fails.
153 AllocatePageTableMemory (
164 // Renew the pool if necessary.
166 if ((mPageTablePool
== NULL
) ||
167 (Pages
> mPageTablePool
->FreePages
))
169 if (!InitializePageTablePool (Pages
)) {
174 Buffer
= (UINT8
*)mPageTablePool
+ mPageTablePool
->Offset
;
176 mPageTablePool
->Offset
+= EFI_PAGES_TO_SIZE (Pages
);
177 mPageTablePool
->FreePages
-= Pages
;
181 "%a:%a: Buffer=0x%Lx Pages=%ld\n",
194 @param[in] PhysicalAddress Start physical address the 2M page
196 @param[in, out] PageEntry2M Pointer to 2M page entry.
197 @param[in] StackBase Stack base address.
198 @param[in] StackSize Stack size.
204 IN PHYSICAL_ADDRESS PhysicalAddress
,
205 IN OUT UINT64
*PageEntry2M
,
206 IN PHYSICAL_ADDRESS StackBase
,
208 IN UINT64 AddressEncMask
211 PHYSICAL_ADDRESS PhysicalAddress4K
;
212 UINTN IndexOfPageTableEntries
;
213 PAGE_TABLE_4K_ENTRY
*PageTableEntry
, *PageTableEntry1
;
215 PageTableEntry
= AllocatePageTableMemory (1);
217 PageTableEntry1
= PageTableEntry
;
219 if (PageTableEntry
== NULL
) {
224 PhysicalAddress4K
= PhysicalAddress
;
225 for (IndexOfPageTableEntries
= 0;
226 IndexOfPageTableEntries
< 512;
227 (IndexOfPageTableEntries
++,
229 PhysicalAddress4K
+= SIZE_4KB
))
232 // Fill in the Page Table entries
234 PageTableEntry
->Uint64
= (UINT64
)PhysicalAddress4K
| AddressEncMask
;
235 PageTableEntry
->Bits
.ReadWrite
= 1;
236 PageTableEntry
->Bits
.Present
= 1;
237 if ((PhysicalAddress4K
>= StackBase
) &&
238 (PhysicalAddress4K
< StackBase
+ StackSize
))
241 // Set Nx bit for stack.
243 PageTableEntry
->Bits
.Nx
= 1;
248 // Fill in 2M page entry.
250 *PageEntry2M
= ((UINT64
)(UINTN
)PageTableEntry1
|
251 IA32_PG_P
| IA32_PG_RW
| AddressEncMask
);
255 Set one page of page table pool memory to be read-only.
257 @param[in] PageTableBase Base address of page table (CR3).
258 @param[in] Address Start address of a page to be set as read-only.
259 @param[in] Level4Paging Level 4 paging flag.
264 SetPageTablePoolReadOnly (
265 IN UINTN PageTableBase
,
266 IN EFI_PHYSICAL_ADDRESS Address
,
267 IN BOOLEAN Level4Paging
272 UINT64 AddressEncMask
;
273 UINT64 ActiveAddressEncMask
;
274 EFI_PHYSICAL_ADDRESS PhysicalAddress
;
276 UINT64
*NewPageTable
;
284 if (PageTableBase
== 0) {
290 // Since the page table is always from page table pool, which is always
291 // located at the boundary of PcdPageTablePoolAlignment, we just need to
292 // set the whole pool unit to be read-only.
294 Address
= Address
& PAGE_TABLE_POOL_ALIGN_MASK
;
296 LevelShift
[1] = PAGING_L1_ADDRESS_SHIFT
;
297 LevelShift
[2] = PAGING_L2_ADDRESS_SHIFT
;
298 LevelShift
[3] = PAGING_L3_ADDRESS_SHIFT
;
299 LevelShift
[4] = PAGING_L4_ADDRESS_SHIFT
;
301 LevelMask
[1] = PAGING_4K_ADDRESS_MASK_64
;
302 LevelMask
[2] = PAGING_2M_ADDRESS_MASK_64
;
303 LevelMask
[3] = PAGING_1G_ADDRESS_MASK_64
;
304 LevelMask
[4] = PAGING_1G_ADDRESS_MASK_64
;
306 LevelSize
[1] = SIZE_4KB
;
307 LevelSize
[2] = SIZE_2MB
;
308 LevelSize
[3] = SIZE_1GB
;
309 LevelSize
[4] = SIZE_512GB
;
311 AddressEncMask
= GetMemEncryptionAddressMask () &
312 PAGING_1G_ADDRESS_MASK_64
;
313 PageTable
= (UINT64
*)(UINTN
)PageTableBase
;
314 PoolUnitSize
= PAGE_TABLE_POOL_UNIT_SIZE
;
316 for (Level
= (Level4Paging
) ? 4 : 3; Level
> 0; --Level
) {
317 Index
= ((UINTN
)RShiftU64 (Address
, LevelShift
[Level
]));
318 Index
&= PAGING_PAE_INDEX_MASK
;
320 PageAttr
= PageTable
[Index
];
321 ActiveAddressEncMask
= GetMemEncryptionAddressMask () & PageAttr
;
323 if ((PageAttr
& IA32_PG_PS
) == 0) {
325 // Go to next level of table.
327 PageTable
= (UINT64
*)(UINTN
)(PageAttr
& ~AddressEncMask
&
328 PAGING_4K_ADDRESS_MASK_64
);
332 if (PoolUnitSize
>= LevelSize
[Level
]) {
334 // Clear R/W bit if current page granularity is not larger than pool unit
337 if ((PageAttr
& IA32_PG_RW
) != 0) {
338 while (PoolUnitSize
> 0) {
340 // PAGE_TABLE_POOL_UNIT_SIZE and PAGE_TABLE_POOL_ALIGNMENT are fit in
341 // one page (2MB). Then we don't need to update attributes for pages
342 // crossing page directory. ASSERT below is for that purpose.
344 ASSERT (Index
< EFI_PAGE_SIZE
/sizeof (UINT64
));
346 PageTable
[Index
] &= ~(UINT64
)IA32_PG_RW
;
347 PoolUnitSize
-= LevelSize
[Level
];
356 // The smaller granularity of page must be needed.
360 NewPageTable
= AllocatePageTableMemory (1);
361 if (NewPageTable
== NULL
) {
366 PhysicalAddress
= PageAttr
& LevelMask
[Level
];
368 EntryIndex
< EFI_PAGE_SIZE
/sizeof (UINT64
);
371 NewPageTable
[EntryIndex
] = PhysicalAddress
| ActiveAddressEncMask
|
372 IA32_PG_P
| IA32_PG_RW
;
374 NewPageTable
[EntryIndex
] |= IA32_PG_PS
;
377 PhysicalAddress
+= LevelSize
[Level
- 1];
380 PageTable
[Index
] = (UINT64
)(UINTN
)NewPageTable
| ActiveAddressEncMask
|
381 IA32_PG_P
| IA32_PG_RW
;
382 PageTable
= NewPageTable
;
388 Prevent the memory pages used for page table from been overwritten.
390 @param[in] PageTableBase Base address of page table (CR3).
391 @param[in] Level4Paging Level 4 paging flag.
396 EnablePageTableProtection (
397 IN UINTN PageTableBase
,
398 IN BOOLEAN Level4Paging
401 PAGE_TABLE_POOL
*HeadPool
;
402 PAGE_TABLE_POOL
*Pool
;
404 EFI_PHYSICAL_ADDRESS Address
;
406 if (mPageTablePool
== NULL
) {
411 // SetPageTablePoolReadOnly might update mPageTablePool. It's safer to
412 // remember original one in advance.
414 HeadPool
= mPageTablePool
;
417 Address
= (EFI_PHYSICAL_ADDRESS
)(UINTN
)Pool
;
418 PoolSize
= Pool
->Offset
+ EFI_PAGES_TO_SIZE (Pool
->FreePages
);
421 // The size of one pool must be multiple of PAGE_TABLE_POOL_UNIT_SIZE,
422 // which is one of page size of the processor (2MB by default). Let's apply
423 // the protection to them one by one.
425 while (PoolSize
> 0) {
426 SetPageTablePoolReadOnly (PageTableBase
, Address
, Level4Paging
);
427 Address
+= PAGE_TABLE_POOL_UNIT_SIZE
;
428 PoolSize
-= PAGE_TABLE_POOL_UNIT_SIZE
;
431 Pool
= Pool
->NextPool
;
432 } while (Pool
!= HeadPool
);
438 @param[in] PhysicalAddress Start physical address the 1G page
440 @param[in, out] PageEntry1G Pointer to 1G page entry.
441 @param[in] StackBase Stack base address.
442 @param[in] StackSize Stack size.
448 IN PHYSICAL_ADDRESS PhysicalAddress
,
449 IN OUT UINT64
*PageEntry1G
,
450 IN PHYSICAL_ADDRESS StackBase
,
454 PHYSICAL_ADDRESS PhysicalAddress2M
;
455 UINTN IndexOfPageDirectoryEntries
;
456 PAGE_TABLE_ENTRY
*PageDirectoryEntry
;
457 UINT64 AddressEncMask
;
458 UINT64 ActiveAddressEncMask
;
460 PageDirectoryEntry
= AllocatePageTableMemory (1);
461 if (PageDirectoryEntry
== NULL
) {
465 AddressEncMask
= GetMemEncryptionAddressMask ();
466 ASSERT (PageDirectoryEntry
!= NULL
);
468 ActiveAddressEncMask
= *PageEntry1G
& AddressEncMask
;
470 // Fill in 1G page entry.
472 *PageEntry1G
= ((UINT64
)(UINTN
)PageDirectoryEntry
|
473 IA32_PG_P
| IA32_PG_RW
| ActiveAddressEncMask
);
475 PhysicalAddress2M
= PhysicalAddress
;
476 for (IndexOfPageDirectoryEntries
= 0;
477 IndexOfPageDirectoryEntries
< 512;
478 (IndexOfPageDirectoryEntries
++,
479 PageDirectoryEntry
++,
480 PhysicalAddress2M
+= SIZE_2MB
))
482 if ((PhysicalAddress2M
< StackBase
+ StackSize
) &&
483 ((PhysicalAddress2M
+ SIZE_2MB
) > StackBase
))
486 // Need to split this 2M page that covers stack range.
490 (UINT64
*)PageDirectoryEntry
,
497 // Fill in the Page Directory entries
499 PageDirectoryEntry
->Uint64
= (UINT64
)PhysicalAddress2M
| ActiveAddressEncMask
;
500 PageDirectoryEntry
->Bits
.ReadWrite
= 1;
501 PageDirectoryEntry
->Bits
.Present
= 1;
502 PageDirectoryEntry
->Bits
.MustBe1
= 1;
508 Set or Clear the memory shared bit
510 @param[in] PagetablePoint Page table entry pointer (PTE).
511 @param[in] Mode Set or Clear shared bit
513 @retval EFI_SUCCESS Successfully set or clear the memory shared bit
514 @retval Others Other error as indicated
518 SetOrClearSharedBit (
519 IN OUT UINT64
*PageTablePointer
,
520 IN TDX_PAGETABLE_MODE Mode
,
521 IN PHYSICAL_ADDRESS PhysicalAddress
,
525 UINT64 AddressEncMask
;
528 EDKII_MEMORY_ACCEPT_PROTOCOL
*MemoryAcceptProtocol
;
530 AddressEncMask
= GetMemEncryptionAddressMask ();
533 // Set or clear page table entry. Also, set shared bit in physical address, before calling MapGPA
535 if (Mode
== SetSharedBit
) {
536 *PageTablePointer
|= AddressEncMask
;
537 PhysicalAddress
|= AddressEncMask
;
539 *PageTablePointer
&= ~AddressEncMask
;
540 PhysicalAddress
&= ~AddressEncMask
;
543 TdStatus
= TdVmCall (TDVMCALL_MAPGPA
, PhysicalAddress
, Length
, 0, 0, NULL
);
545 DEBUG ((DEBUG_ERROR
, "%a: TdVmcall(MAPGPA) failed with %llx\n", __FUNCTION__
, TdStatus
));
547 return EFI_DEVICE_ERROR
;
551 // If changing shared to private, must accept-page again
553 if (Mode
== ClearSharedBit
) {
554 Status
= gBS
->LocateProtocol (&gEdkiiMemoryAcceptProtocolGuid
, NULL
, (VOID
**)&MemoryAcceptProtocol
);
555 if (EFI_ERROR (Status
)) {
556 DEBUG ((DEBUG_ERROR
, "%a: Failed to locate MemoryAcceptProtocol with %r\n", __FUNCTION__
, Status
));
561 Status
= MemoryAcceptProtocol
->AcceptMemory (MemoryAcceptProtocol
, PhysicalAddress
, Length
);
562 if (EFI_ERROR (Status
)) {
563 DEBUG ((DEBUG_ERROR
, "%a: Failed to AcceptMemory with %r\n", __FUNCTION__
, Status
));
571 "%a:%a: pte=0x%Lx AddressEncMask=0x%Lx Mode=0x%x MapGPA Status=0x%x\n",
584 Check the WP status in CR0 register. This bit is used to lock or unlock write
585 access to pages marked as read-only.
587 @retval TRUE Write protection is enabled.
588 @retval FALSE Write protection is disabled.
592 IsReadOnlyPageWriteProtected (
596 return ((AsmReadCr0 () & BIT16
) != 0);
600 Disable Write Protect on pages marked as read-only.
604 DisableReadOnlyPageWriteProtect (
608 AsmWriteCr0 (AsmReadCr0 () & ~BIT16
);
612 Enable Write Protect on pages marked as read-only.
615 EnableReadOnlyPageWriteProtect (
619 AsmWriteCr0 (AsmReadCr0 () | BIT16
);
623 This function either sets or clears memory encryption for the memory
624 region specified by PhysicalAddress and Length from the current page table
627 The function iterates through the PhysicalAddress one page at a time, and set
628 or clears the memory encryption in the page table. If it encounters
629 that a given physical address range is part of large page then it attempts to
630 change the attribute at one go (based on size), otherwise it splits the
631 large pages into smaller (e.g 2M page into 4K pages) and then try to set or
632 clear the shared bit on the smallest page size.
634 @param[in] Cr3BaseAddress Cr3 Base Address (if zero then use
636 @param[in] PhysicalAddress The physical address that is the start
637 address of a memory region.
638 @param[in] Length The length of memory region
639 @param[in] Mode Set or Clear mode
641 @retval RETURN_SUCCESS The attributes were cleared for the
643 @retval RETURN_INVALID_PARAMETER Number of pages is zero.
644 @retval RETURN_UNSUPPORTED Setting the memory encyrption attribute
650 SetMemorySharedOrPrivate (
651 IN PHYSICAL_ADDRESS Cr3BaseAddress
,
652 IN PHYSICAL_ADDRESS PhysicalAddress
,
654 IN TDX_PAGETABLE_MODE Mode
657 PAGE_MAP_AND_DIRECTORY_POINTER
*PageMapLevel4Entry
;
658 PAGE_MAP_AND_DIRECTORY_POINTER
*PageUpperDirectoryPointerEntry
;
659 PAGE_MAP_AND_DIRECTORY_POINTER
*PageDirectoryPointerEntry
;
660 PAGE_TABLE_1G_ENTRY
*PageDirectory1GEntry
;
661 PAGE_TABLE_ENTRY
*PageDirectory2MEntry
;
662 PAGE_TABLE_4K_ENTRY
*PageTableEntry
;
664 UINT64 AddressEncMask
;
665 UINT64 ActiveEncMask
;
667 RETURN_STATUS Status
;
669 BOOLEAN Page5LevelSupport
;
672 // Set PageMapLevel4Entry to suppress incorrect compiler/analyzer warnings.
674 PageMapLevel4Entry
= NULL
;
678 "%a:%a: Cr3Base=0x%Lx Physical=0x%Lx Length=0x%Lx Mode=%a\n",
684 (Mode
== SetSharedBit
) ? "Shared" : "Private"
688 // Check if we have a valid memory encryption mask
690 AddressEncMask
= GetMemEncryptionAddressMask ();
692 PgTableMask
= AddressEncMask
| EFI_PAGE_MASK
;
695 return RETURN_INVALID_PARAMETER
;
699 // Make sure that the page table is changeable.
701 IsWpEnabled
= IsReadOnlyPageWriteProtected ();
703 DisableReadOnlyPageWriteProtect ();
707 // If Cr3BaseAddress is not specified then read the current CR3
709 if (Cr3BaseAddress
== 0) {
710 Cr3BaseAddress
= AsmReadCr3 ();
714 // CPU will already have LA57 enabled so just check CR4
716 Cr4
.UintN
= AsmReadCr4 ();
718 Page5LevelSupport
= (Cr4
.Bits
.LA57
? TRUE
: FALSE
);
720 // If 5-level pages, adjust Cr3BaseAddress to point to first 4-level page directory,
721 // we will only have 1
723 if (Page5LevelSupport
) {
724 Cr3BaseAddress
= *(UINT64
*)Cr3BaseAddress
& ~PgTableMask
;
727 Status
= EFI_SUCCESS
;
730 PageMapLevel4Entry
= (VOID
*)(Cr3BaseAddress
& ~PgTableMask
);
731 PageMapLevel4Entry
+= PML4_OFFSET (PhysicalAddress
);
732 if (!PageMapLevel4Entry
->Bits
.Present
) {
735 "%a:%a: bad PML4 for Physical=0x%Lx\n",
740 Status
= RETURN_NO_MAPPING
;
744 PageDirectory1GEntry
= (VOID
*)(
745 (PageMapLevel4Entry
->Bits
.PageTableBaseAddress
<<
748 PageDirectory1GEntry
+= PDP_OFFSET (PhysicalAddress
);
749 if (!PageDirectory1GEntry
->Bits
.Present
) {
752 "%a:%a: bad PDPE for Physical=0x%Lx\n",
757 Status
= RETURN_NO_MAPPING
;
762 // If the MustBe1 bit is not 1, it's not actually a 1GB entry
764 if (PageDirectory1GEntry
->Bits
.MustBe1
) {
767 // If we have at least 1GB to go, we can just update this entry
769 if (!(PhysicalAddress
& (BIT30
- 1)) && (Length
>= BIT30
)) {
770 Status
= SetOrClearSharedBit (&PageDirectory1GEntry
->Uint64
, Mode
, PhysicalAddress
, BIT30
);
771 if (EFI_ERROR (Status
)) {
777 "%a:%a: updated 1GB entry for Physical=0x%Lx\n",
782 PhysicalAddress
+= BIT30
;
786 // We must split the page
790 "%a:%a: splitting 1GB page for Physical=0x%Lx\n",
796 (UINT64
)PageDirectory1GEntry
->Bits
.PageTableBaseAddress
<< 30,
797 (UINT64
*)PageDirectory1GEntry
,
807 PageUpperDirectoryPointerEntry
=
808 (PAGE_MAP_AND_DIRECTORY_POINTER
*)PageDirectory1GEntry
;
809 PageDirectory2MEntry
=
811 (PageUpperDirectoryPointerEntry
->Bits
.PageTableBaseAddress
<<
814 PageDirectory2MEntry
+= PDE_OFFSET (PhysicalAddress
);
815 if (!PageDirectory2MEntry
->Bits
.Present
) {
818 "%a:%a: bad PDE for Physical=0x%Lx\n",
823 Status
= RETURN_NO_MAPPING
;
828 // If the MustBe1 bit is not a 1, it's not a 2MB entry
830 if (PageDirectory2MEntry
->Bits
.MustBe1
) {
833 // If we have at least 2MB left to go, we can just update this entry
835 if (!(PhysicalAddress
& (BIT21
-1)) && (Length
>= BIT21
)) {
836 Status
= SetOrClearSharedBit (&PageDirectory2MEntry
->Uint64
, Mode
, PhysicalAddress
, BIT21
);
837 if (EFI_ERROR (Status
)) {
841 PhysicalAddress
+= BIT21
;
845 // We must split up this page into 4K pages
849 "%a:%a: splitting 2MB page for Physical=0x%Lx\n",
855 ActiveEncMask
= PageDirectory2MEntry
->Uint64
& AddressEncMask
;
858 (UINT64
)PageDirectory2MEntry
->Bits
.PageTableBaseAddress
<< 21,
859 (UINT64
*)PageDirectory2MEntry
,
867 PageDirectoryPointerEntry
=
868 (PAGE_MAP_AND_DIRECTORY_POINTER
*)PageDirectory2MEntry
;
871 (PageDirectoryPointerEntry
->Bits
.PageTableBaseAddress
<<
874 PageTableEntry
+= PTE_OFFSET (PhysicalAddress
);
875 if (!PageTableEntry
->Bits
.Present
) {
878 "%a:%a: bad PTE for Physical=0x%Lx\n",
883 Status
= RETURN_NO_MAPPING
;
887 Status
= SetOrClearSharedBit (&PageTableEntry
->Uint64
, Mode
, PhysicalAddress
, EFI_PAGE_SIZE
);
888 if (EFI_ERROR (Status
)) {
892 PhysicalAddress
+= EFI_PAGE_SIZE
;
893 Length
-= EFI_PAGE_SIZE
;
899 // Protect the page table by marking the memory used for page table to be
903 EnablePageTableProtection ((UINTN
)PageMapLevel4Entry
, TRUE
);
913 // Restore page table write protection, if any.
916 EnableReadOnlyPageWriteProtect ();
923 This function clears memory shared bit for the memory region specified by
924 BaseAddress and NumPages from the current page table context.
926 @param[in] Cr3BaseAddress Cr3 Base Address (if zero then use
928 @param[in] BaseAddress The physical address that is the start
929 address of a memory region.
930 @param[in] NumPages The number of pages from start memory
933 @retval RETURN_SUCCESS The attributes were cleared for the
935 @retval RETURN_INVALID_PARAMETER Number of pages is zero.
936 @retval RETURN_UNSUPPORTED Clearing the memory encryption attribute
941 MemEncryptTdxSetPageSharedBit (
942 IN PHYSICAL_ADDRESS Cr3BaseAddress
,
943 IN PHYSICAL_ADDRESS BaseAddress
,
947 return SetMemorySharedOrPrivate (
950 EFI_PAGES_TO_SIZE (NumPages
),
956 This function sets memory shared bit for the memory region specified by
957 BaseAddress and NumPages from the current page table context.
959 @param[in] Cr3BaseAddress Cr3 Base Address (if zero then use
961 @param[in] BaseAddress The physical address that is the start
962 address of a memory region.
963 @param[in] NumPages The number of pages from start memory
966 @retval RETURN_SUCCESS The attributes were set for the memory
968 @retval RETURN_INVALID_PARAMETER Number of pages is zero.
969 @retval RETURN_UNSUPPORTED Setting the memory encryption attribute
974 MemEncryptTdxClearPageSharedBit (
975 IN PHYSICAL_ADDRESS Cr3BaseAddress
,
976 IN PHYSICAL_ADDRESS BaseAddress
,
980 return SetMemorySharedOrPrivate (
983 EFI_PAGES_TO_SIZE (NumPages
),