41#define MAX_RETRIES_PER_PAGE 3
57 return CC_GUEST_IS_TDX (
PcdGet64 (PcdConfidentialComputingGuestAttr));
106 PoolPages = ((PoolPages - 1) / PAGE_TABLE_POOL_UNIT_PAGES + 1) *
107 PAGE_TABLE_POOL_UNIT_PAGES;
109 if (Buffer ==
NULL) {
110 DEBUG ((DEBUG_ERROR,
"ERROR: Out of aligned pages\r\n"));
117 if (mPageTablePool ==
NULL) {
118 mPageTablePool = Buffer;
119 mPageTablePool->NextPool = mPageTablePool;
122 mPageTablePool->NextPool = Buffer;
123 mPageTablePool = Buffer;
129 mPageTablePool->FreePages = PoolPages - 1;
168 if ((mPageTablePool ==
NULL) ||
169 (Pages > mPageTablePool->FreePages))
176 Buffer = (UINT8 *)mPageTablePool + mPageTablePool->Offset;
179 mPageTablePool->FreePages -= Pages;
183 "%a:%a: Buffer=0x%Lx Pages=%ld\n",
206 IN PHYSICAL_ADDRESS PhysicalAddress,
207 IN OUT UINT64 *PageEntry2M,
208 IN PHYSICAL_ADDRESS StackBase,
210 IN UINT64 AddressEncMask
213 PHYSICAL_ADDRESS PhysicalAddress4K;
214 UINTN IndexOfPageTableEntries;
219 PageTableEntry1 = PageTableEntry;
221 if (PageTableEntry ==
NULL) {
226 PhysicalAddress4K = PhysicalAddress;
227 for (IndexOfPageTableEntries = 0;
228 IndexOfPageTableEntries < 512;
229 (IndexOfPageTableEntries++,
231 PhysicalAddress4K += SIZE_4KB))
236 PageTableEntry->Uint64 = (UINT64)PhysicalAddress4K | AddressEncMask;
237 PageTableEntry->Bits.ReadWrite = 1;
238 PageTableEntry->Bits.Present = 1;
239 if ((PhysicalAddress4K >= StackBase) &&
240 (PhysicalAddress4K < StackBase + StackSize))
245 PageTableEntry->Bits.Nx = 1;
252 *PageEntry2M = ((UINT64)(
UINTN)PageTableEntry1 |
253 IA32_PG_P | IA32_PG_RW | AddressEncMask);
269 IN BOOLEAN Level4Paging
274 UINT64 AddressEncMask;
275 UINT64 ActiveAddressEncMask;
278 UINT64 *NewPageTable;
286 if (PageTableBase == 0) {
296 Address = Address & PAGE_TABLE_POOL_ALIGN_MASK;
298 LevelShift[1] = PAGING_L1_ADDRESS_SHIFT;
299 LevelShift[2] = PAGING_L2_ADDRESS_SHIFT;
300 LevelShift[3] = PAGING_L3_ADDRESS_SHIFT;
301 LevelShift[4] = PAGING_L4_ADDRESS_SHIFT;
303 LevelMask[1] = PAGING_4K_ADDRESS_MASK_64;
304 LevelMask[2] = PAGING_2M_ADDRESS_MASK_64;
305 LevelMask[3] = PAGING_1G_ADDRESS_MASK_64;
306 LevelMask[4] = PAGING_1G_ADDRESS_MASK_64;
308 LevelSize[1] = SIZE_4KB;
309 LevelSize[2] = SIZE_2MB;
310 LevelSize[3] = SIZE_1GB;
311 LevelSize[4] = SIZE_512GB;
314 PAGING_1G_ADDRESS_MASK_64;
315 PageTable = (UINT64 *)(
UINTN)PageTableBase;
316 PoolUnitSize = PAGE_TABLE_POOL_UNIT_SIZE;
318 for (Level = (Level4Paging) ? 4 : 3; Level > 0; --Level) {
320 Index &= PAGING_PAE_INDEX_MASK;
322 PageAttr = PageTable[Index];
325 if ((PageAttr & IA32_PG_PS) == 0) {
329 PageTable = (UINT64 *)(
UINTN)(PageAttr & ~AddressEncMask &
330 PAGING_4K_ADDRESS_MASK_64);
334 if (PoolUnitSize >= LevelSize[Level]) {
339 if ((PageAttr & IA32_PG_RW) != 0) {
340 while (PoolUnitSize > 0) {
346 ASSERT (Index < EFI_PAGE_SIZE/
sizeof (UINT64));
348 PageTable[Index] &= ~(UINT64)IA32_PG_RW;
349 PoolUnitSize -= LevelSize[Level];
363 if (NewPageTable ==
NULL) {
368 PhysicalAddress = PageAttr & LevelMask[Level];
370 EntryIndex < EFI_PAGE_SIZE/
sizeof (UINT64);
373 NewPageTable[EntryIndex] = PhysicalAddress | ActiveAddressEncMask |
374 IA32_PG_P | IA32_PG_RW;
376 NewPageTable[EntryIndex] |= IA32_PG_PS;
379 PhysicalAddress += LevelSize[Level - 1];
382 PageTable[Index] = (UINT64)(
UINTN)NewPageTable | ActiveAddressEncMask |
383 IA32_PG_P | IA32_PG_RW;
384 PageTable = NewPageTable;
400 IN BOOLEAN Level4Paging
408 if (mPageTablePool ==
NULL) {
416 HeadPool = mPageTablePool;
427 while (PoolSize > 0) {
429 Address += PAGE_TABLE_POOL_UNIT_SIZE;
430 PoolSize -= PAGE_TABLE_POOL_UNIT_SIZE;
433 Pool = Pool->NextPool;
434 }
while (Pool != HeadPool);
450 IN PHYSICAL_ADDRESS PhysicalAddress,
451 IN OUT UINT64 *PageEntry1G,
452 IN PHYSICAL_ADDRESS StackBase,
456 PHYSICAL_ADDRESS PhysicalAddress2M;
457 UINTN IndexOfPageDirectoryEntries;
459 UINT64 AddressEncMask;
460 UINT64 ActiveAddressEncMask;
463 if (PageDirectoryEntry ==
NULL) {
468 ASSERT (PageDirectoryEntry !=
NULL);
470 ActiveAddressEncMask = *PageEntry1G & AddressEncMask;
474 *PageEntry1G = ((UINT64)(
UINTN)PageDirectoryEntry |
475 IA32_PG_P | IA32_PG_RW | ActiveAddressEncMask);
477 PhysicalAddress2M = PhysicalAddress;
478 for (IndexOfPageDirectoryEntries = 0;
479 IndexOfPageDirectoryEntries < 512;
480 (IndexOfPageDirectoryEntries++,
481 PageDirectoryEntry++,
482 PhysicalAddress2M += SIZE_2MB))
484 if ((PhysicalAddress2M < StackBase + StackSize) &&
485 ((PhysicalAddress2M + SIZE_2MB) > StackBase))
492 (UINT64 *)PageDirectoryEntry,
501 PageDirectoryEntry->Uint64 = (UINT64)PhysicalAddress2M | ActiveAddressEncMask;
502 PageDirectoryEntry->Bits.ReadWrite = 1;
503 PageDirectoryEntry->Bits.Present = 1;
504 PageDirectoryEntry->Bits.MustBe1 = 1;
521 IN OUT UINT64 *PageTablePointer,
522 IN TDX_PAGETABLE_MODE Mode,
523 IN PHYSICAL_ADDRESS PhysicalAddress,
527 UINT64 AddressEncMask;
532 UINT64 MapGpaRetryAddr;
544 if (Mode == SetSharedBit) {
545 *PageTablePointer |= AddressEncMask;
546 PhysicalAddress |= AddressEncMask;
548 *PageTablePointer &= ~AddressEncMask;
549 PhysicalAddress &= ~AddressEncMask;
552 EndAddress = PhysicalAddress + Length;
553 while (RetryCount < MAX_RETRIES_PER_PAGE) {
554 TdStatus =
TdVmCall (TDVMCALL_MAPGPA, PhysicalAddress, Length, 0, 0, &MapGpaRetryAddr);
555 if (TdStatus != TDVMCALL_STATUS_RETRY) {
559 DEBUG ((DEBUG_VERBOSE,
"%a: TdVmcall(MAPGPA) Retry PhysicalAddress is %llx, MapGpaRetryAddr is %llx\n", __func__, PhysicalAddress, MapGpaRetryAddr));
561 if ((MapGpaRetryAddr < PhysicalAddress) || (MapGpaRetryAddr >= EndAddress)) {
564 "%a: TdVmcall(MAPGPA) failed with MapGpaRetryAddr(%llx) less than PhysicalAddress(%llx) or more than or equal to EndAddress(%llx) \n",
573 if (MapGpaRetryAddr == PhysicalAddress) {
578 PhysicalAddress = MapGpaRetryAddr;
579 Length = EndAddress - PhysicalAddress;
584 DEBUG ((DEBUG_ERROR,
"%a: TdVmcall(MAPGPA) failed with %llx\n", __func__, TdStatus));
586 return EFI_DEVICE_ERROR;
592 if (Mode == ClearSharedBit) {
593 Status =
gBS->LocateProtocol (&gEdkiiMemoryAcceptProtocolGuid,
NULL, (VOID **)&MemoryAcceptProtocol);
594 if (EFI_ERROR (Status)) {
595 DEBUG ((DEBUG_ERROR,
"%a: Failed to locate MemoryAcceptProtocol with %r\n", __func__, Status));
600 Status = MemoryAcceptProtocol->AcceptMemory (MemoryAcceptProtocol, PhysicalAddress, Length);
601 if (EFI_ERROR (Status)) {
602 DEBUG ((DEBUG_ERROR,
"%a: Failed to AcceptMemory with %r\n", __func__, Status));
610 "%a:%a: pte=0x%Lx AddressEncMask=0x%Lx Mode=0x%x MapGPA Status=0x%x\n",
690 IN PHYSICAL_ADDRESS Cr3BaseAddress,
691 IN PHYSICAL_ADDRESS PhysicalAddress,
693 IN TDX_PAGETABLE_MODE Mode
703 UINT64 AddressEncMask;
704 UINT64 ActiveEncMask;
706 RETURN_STATUS Status;
708 BOOLEAN Page5LevelSupport;
713 PageMapLevel4Entry =
NULL;
717 "%a:%a: Cr3Base=0x%Lx Physical=0x%Lx Length=0x%Lx Mode=%a\n",
723 (Mode == SetSharedBit) ?
"Shared" :
"Private"
731 PgTableMask = AddressEncMask | EFI_PAGE_MASK;
748 if (Cr3BaseAddress == 0) {
757 Page5LevelSupport = (Cr4.Bits.LA57 ?
TRUE :
FALSE);
762 if (Page5LevelSupport) {
763 Cr3BaseAddress = *(UINT64 *)Cr3BaseAddress & ~PgTableMask;
769 PageMapLevel4Entry = (VOID *)(Cr3BaseAddress & ~PgTableMask);
770 PageMapLevel4Entry += PML4_OFFSET (PhysicalAddress);
771 if (!PageMapLevel4Entry->Bits.Present) {
774 "%a:%a: bad PML4 for Physical=0x%Lx\n",
783 PageDirectory1GEntry = (VOID *)(
784 (PageMapLevel4Entry->Bits.PageTableBaseAddress <<
787 PageDirectory1GEntry += PDP_OFFSET (PhysicalAddress);
788 if (!PageDirectory1GEntry->Bits.Present) {
791 "%a:%a: bad PDPE for Physical=0x%Lx\n",
803 if (PageDirectory1GEntry->Bits.MustBe1) {
808 if (!(PhysicalAddress & (BIT30 - 1)) && (Length >= BIT30)) {
809 Status =
SetOrClearSharedBit (&PageDirectory1GEntry->Uint64, Mode, PhysicalAddress, BIT30);
810 if (EFI_ERROR (Status)) {
816 "%a:%a: updated 1GB entry for Physical=0x%Lx\n",
821 PhysicalAddress += BIT30;
829 "%a:%a: splitting 1GB page for Physical=0x%Lx\n",
835 (UINT64)PageDirectory1GEntry->Bits.PageTableBaseAddress << 30,
836 (UINT64 *)PageDirectory1GEntry,
846 PageUpperDirectoryPointerEntry =
848 PageDirectory2MEntry =
850 (PageUpperDirectoryPointerEntry->Bits.PageTableBaseAddress <<
853 PageDirectory2MEntry += PDE_OFFSET (PhysicalAddress);
854 if (!PageDirectory2MEntry->Bits.Present) {
857 "%a:%a: bad PDE for Physical=0x%Lx\n",
869 if (PageDirectory2MEntry->Bits.MustBe1) {
874 if (!(PhysicalAddress & (BIT21-1)) && (Length >= BIT21)) {
875 Status =
SetOrClearSharedBit (&PageDirectory2MEntry->Uint64, Mode, PhysicalAddress, BIT21);
876 if (EFI_ERROR (Status)) {
880 PhysicalAddress += BIT21;
888 "%a:%a: splitting 2MB page for Physical=0x%Lx\n",
894 ActiveEncMask = PageDirectory2MEntry->Uint64 & AddressEncMask;
897 (UINT64)PageDirectory2MEntry->Bits.PageTableBaseAddress << 21,
898 (UINT64 *)PageDirectory2MEntry,
906 PageDirectoryPointerEntry =
910 (PageDirectoryPointerEntry->Bits.PageTableBaseAddress <<
913 PageTableEntry += PTE_OFFSET (PhysicalAddress);
914 if (!PageTableEntry->Bits.Present) {
917 "%a:%a: bad PTE for Physical=0x%Lx\n",
926 Status =
SetOrClearSharedBit (&PageTableEntry->Uint64, Mode, PhysicalAddress, EFI_PAGE_SIZE);
927 if (EFI_ERROR (Status)) {
931 PhysicalAddress += EFI_PAGE_SIZE;
932 Length -= EFI_PAGE_SIZE;
981 IN PHYSICAL_ADDRESS Cr3BaseAddress,
982 IN PHYSICAL_ADDRESS BaseAddress,
1014 IN PHYSICAL_ADDRESS Cr3BaseAddress,
1015 IN PHYSICAL_ADDRESS BaseAddress,
UINT64 EFIAPI RShiftU64(IN UINT64 Operand, IN UINTN Count)
UINTN EFIAPI TdVmCall(IN UINT64 Leaf, IN UINT64 Arg1, IN UINT64 Arg2, IN UINT64 Arg3, IN UINT64 Arg4, IN OUT VOID *Results)
VOID EFIAPI CpuFlushTlb(VOID)
UINTN EFIAPI AsmReadCr3(VOID)
UINTN EFIAPI AsmReadCr0(VOID)
UINTN EFIAPI AsmWriteCr0(UINTN Cr0)
UINTN EFIAPI AsmReadCr4(VOID)
#define RETURN_NO_MAPPING
#define RETURN_INVALID_PARAMETER
#define DEBUG(Expression)
STATIC EFI_STATUS SetOrClearSharedBit(IN OUT UINT64 *PageTablePointer, IN TDX_PAGETABLE_MODE Mode, IN PHYSICAL_ADDRESS PhysicalAddress, IN UINT64 Length)
STATIC VOID SetPageTablePoolReadOnly(IN UINTN PageTableBase, IN EFI_PHYSICAL_ADDRESS Address, IN BOOLEAN Level4Paging)
STATIC VOID Split1GPageTo2M(IN PHYSICAL_ADDRESS PhysicalAddress, IN OUT UINT64 *PageEntry1G, IN PHYSICAL_ADDRESS StackBase, IN UINTN StackSize)
VOID EnableReadOnlyPageWriteProtect(VOID)
STATIC UINT64 GetMemEncryptionAddressMask(VOID)
RETURN_STATUS EFIAPI MemEncryptTdxSetPageSharedBit(IN PHYSICAL_ADDRESS Cr3BaseAddress, IN PHYSICAL_ADDRESS BaseAddress, IN UINTN NumPages)
STATIC RETURN_STATUS EFIAPI SetMemorySharedOrPrivate(IN PHYSICAL_ADDRESS Cr3BaseAddress, IN PHYSICAL_ADDRESS PhysicalAddress, IN UINTN Length, IN TDX_PAGETABLE_MODE Mode)
STATIC BOOLEAN InitializePageTablePool(IN UINTN PoolPages)
STATIC VOID *EFIAPI AllocatePageTableMemory(IN UINTN Pages)
STATIC VOID Split2MPageTo4K(IN PHYSICAL_ADDRESS PhysicalAddress, IN OUT UINT64 *PageEntry2M, IN PHYSICAL_ADDRESS StackBase, IN UINTN StackSize, IN UINT64 AddressEncMask)
STATIC VOID DisableReadOnlyPageWriteProtect(VOID)
BOOLEAN EFIAPI MemEncryptTdxIsEnabled(VOID)
STATIC VOID EnablePageTableProtection(IN UINTN PageTableBase, IN BOOLEAN Level4Paging)
RETURN_STATUS EFIAPI MemEncryptTdxClearPageSharedBit(IN PHYSICAL_ADDRESS Cr3BaseAddress, IN PHYSICAL_ADDRESS BaseAddress, IN UINTN NumPages)
STATIC BOOLEAN IsReadOnlyPageWriteProtected(VOID)
#define PcdGet64(TokenName)
VOID *EFIAPI AllocateAlignedPages(IN UINTN Pages, IN UINTN Alignment)
UINT64 EFIAPI TdSharedPageMask(VOID)
UINT64 EFI_PHYSICAL_ADDRESS
#define EFI_PAGES_TO_SIZE(Pages)