diff --git a/OvmfPkg/Library/PeilessStartupLib/X64/VirtualMemory.c b/OvmfPkg/Library/PeilessStartupLib/X64/VirtualMemory.c index 6877e521e4..b444c052d1 100644 --- a/OvmfPkg/Library/PeilessStartupLib/X64/VirtualMemory.c +++ b/OvmfPkg/Library/PeilessStartupLib/X64/VirtualMemory.c @@ -21,11 +21,6 @@ SPDX-License-Identifier: BSD-2-Clause-Patent #include #include "PageTables.h" -// -// Global variable to keep track current available memory used as page table. -// -PAGE_TABLE_POOL *mPageTablePool = NULL; - UINTN mLevelShift[5] = { 0, PAGING_L1_ADDRESS_SHIFT, @@ -273,14 +268,17 @@ ToSplitPageTable ( reserve at least another PAGE_TABLE_POOL_UNIT_PAGES. But usually this won't happen in practice. - @param PoolPages The least page number of the pool to be created. + @param[in] PoolPages The least page number of the pool to be created. + @param[in, out] PageTablePool Pointer of Pointer to the current available memory + used as page table. @retval TRUE The pool is initialized successfully. @retval FALSE The memory is out of resource. **/ BOOLEAN InitializePageTablePool ( - IN UINTN PoolPages + IN UINTN PoolPages, + IN OUT PAGE_TABLE_POOL **PageTablePool ) { VOID *Buffer; @@ -303,20 +301,20 @@ InitializePageTablePool ( // // Link all pools into a list for easier track later. // - if (mPageTablePool == NULL) { - mPageTablePool = Buffer; - mPageTablePool->NextPool = mPageTablePool; + if (*PageTablePool == NULL) { + *(UINT64 *)(UINTN)PageTablePool = (UINT64)(UINTN)Buffer; + (*PageTablePool)->NextPool = *PageTablePool; } else { - ((PAGE_TABLE_POOL *)Buffer)->NextPool = mPageTablePool->NextPool; - mPageTablePool->NextPool = Buffer; - mPageTablePool = Buffer; + ((PAGE_TABLE_POOL *)Buffer)->NextPool = (*PageTablePool)->NextPool; + (*PageTablePool)->NextPool = Buffer; + *PageTablePool = Buffer; } // // Reserve one page for pool header. // - mPageTablePool->FreePages = PoolPages - 1; - mPageTablePool->Offset = EFI_PAGES_TO_SIZE (1); + (*PageTablePool)->FreePages = PoolPages - 1; + (*PageTablePool)->Offset = EFI_PAGES_TO_SIZE (1); return TRUE; } @@ -333,14 +331,17 @@ InitializePageTablePool ( If there is not enough memory remaining to satisfy the request, then NULL is returned. - @param Pages The number of 4 KB pages to allocate. + @param[in] Pages The number of 4 KB pages to allocate. + @param[in, out] PageTablePool Pointer of pointer to the current available + memory used as page table. @return A pointer to the allocated buffer or NULL if allocation fails. **/ VOID * AllocatePageTableMemory ( - IN UINTN Pages + IN UINTN Pages, + IN OUT PAGE_TABLE_POOL **PageTablePool ) { VOID *Buffer; @@ -349,30 +350,31 @@ AllocatePageTableMemory ( return NULL; } - DEBUG ((DEBUG_INFO, "AllocatePageTableMemory. mPageTablePool=%p, Pages=%d\n", mPageTablePool, Pages)); + DEBUG ((DEBUG_INFO, "AllocatePageTableMemory. PageTablePool=%p, Pages=%d\n", *PageTablePool, Pages)); // // Renew the pool if necessary. // - if ((mPageTablePool == NULL) || - (Pages > mPageTablePool->FreePages)) + if ((*PageTablePool == NULL) || + (Pages > (*PageTablePool)->FreePages)) { - if (!InitializePageTablePool (Pages)) { + if (!InitializePageTablePool (Pages, PageTablePool)) { return NULL; } } - Buffer = (UINT8 *)mPageTablePool + mPageTablePool->Offset; + Buffer = (UINT8 *)(*PageTablePool) + (*PageTablePool)->Offset; - mPageTablePool->Offset += EFI_PAGES_TO_SIZE (Pages); - mPageTablePool->FreePages -= Pages; + (*PageTablePool)->Offset += EFI_PAGES_TO_SIZE (Pages); + (*PageTablePool)->FreePages -= Pages; DEBUG (( DEBUG_INFO, - "%a:%a: Buffer=0x%Lx Pages=%ld\n", + "%a:%a: Buffer=0x%Lx Pages=%ld, PageTablePool=%p\n", gEfiCallerBaseName, __FUNCTION__, Buffer, - Pages + Pages, + *PageTablePool )); return Buffer; @@ -385,6 +387,8 @@ AllocatePageTableMemory ( @param[in, out] PageEntry2M Pointer to 2M page entry. @param[in] StackBase Stack base address. @param[in] StackSize Stack size. + @param[in, out] PageTablePool Pointer to the current available memory used as + page table. **/ VOID @@ -392,7 +396,8 @@ Split2MPageTo4K ( IN EFI_PHYSICAL_ADDRESS PhysicalAddress, IN OUT UINT64 *PageEntry2M, IN EFI_PHYSICAL_ADDRESS StackBase, - IN UINTN StackSize + IN UINTN StackSize, + IN OUT PAGE_TABLE_POOL *PageTablePool ) { EFI_PHYSICAL_ADDRESS PhysicalAddress4K; @@ -401,7 +406,7 @@ Split2MPageTo4K ( DEBUG ((DEBUG_INFO, "Split2MPageTo4K\n")); - PageTableEntry = AllocatePageTableMemory (1); + PageTableEntry = AllocatePageTableMemory (1, &PageTablePool); if (PageTableEntry == NULL) { ASSERT (FALSE); @@ -448,6 +453,8 @@ Split2MPageTo4K ( @param[in, out] PageEntry1G Pointer to 1G page entry. @param[in] StackBase Stack base address. @param[in] StackSize Stack size. + @param[in, out] PageTablePool Pointer to the current available memory used as + page table. **/ VOID @@ -455,14 +462,16 @@ Split1GPageTo2M ( IN EFI_PHYSICAL_ADDRESS PhysicalAddress, IN OUT UINT64 *PageEntry1G, IN EFI_PHYSICAL_ADDRESS StackBase, - IN UINTN StackSize + IN UINTN StackSize, + IN OUT PAGE_TABLE_POOL *PageTablePool ) { EFI_PHYSICAL_ADDRESS PhysicalAddress2M; UINTN IndexOfPageDirectoryEntries; PAGE_TABLE_ENTRY *PageDirectoryEntry; - PageDirectoryEntry = AllocatePageTableMemory (1); + DEBUG ((DEBUG_INFO, "Split1GPageTo2M\n")); + PageDirectoryEntry = AllocatePageTableMemory (1, &PageTablePool); if (PageDirectoryEntry == NULL) { ASSERT (FALSE); @@ -480,7 +489,7 @@ Split1GPageTo2M ( // // Need to split this 2M page that covers NULL or stack range. // - Split2MPageTo4K (PhysicalAddress2M, (UINT64 *)PageDirectoryEntry, StackBase, StackSize); + Split2MPageTo4K (PhysicalAddress2M, (UINT64 *)PageDirectoryEntry, StackBase, StackSize, PageTablePool); } else { // // Fill in the Page Directory entries @@ -496,16 +505,19 @@ Split1GPageTo2M ( /** Set one page of page table pool memory to be read-only. - @param[in] PageTableBase Base address of page table (CR3). - @param[in] Address Start address of a page to be set as read-only. - @param[in] Level4Paging Level 4 paging flag. + @param[in] PageTableBase Base address of page table (CR3). + @param[in] Address Start address of a page to be set as read-only. + @param[in] Level4Paging Level 4 paging flag. + @param[in, out] PageTablePool Pointer to the current available memory used as + page table. **/ VOID SetPageTablePoolReadOnly ( IN UINTN PageTableBase, IN EFI_PHYSICAL_ADDRESS Address, - IN BOOLEAN Level4Paging + IN BOOLEAN Level4Paging, + IN OUT PAGE_TABLE_POOL *PageTablePool ) { UINTN Index; @@ -573,7 +585,8 @@ SetPageTablePoolReadOnly ( // ASSERT (Level > 1); - NewPageTable = AllocatePageTableMemory (1); + DEBUG ((DEBUG_INFO, "SetPageTablePoolReadOnly\n")); + NewPageTable = AllocatePageTableMemory (1, &PageTablePool); if (NewPageTable == NULL) { ASSERT (FALSE); @@ -604,14 +617,17 @@ SetPageTablePoolReadOnly ( /** Prevent the memory pages used for page table from been overwritten. - @param[in] PageTableBase Base address of page table (CR3). - @param[in] Level4Paging Level 4 paging flag. + @param[in] PageTableBase Base address of page table (CR3). + @param[in] Level4Paging Level 4 paging flag. + @param[in, out] PageTablePool Pointer to the current available memory used as + page table. **/ VOID EnablePageTableProtection ( - IN UINTN PageTableBase, - IN BOOLEAN Level4Paging + IN UINTN PageTableBase, + IN BOOLEAN Level4Paging, + IN OUT PAGE_TABLE_POOL *PageTablePool ) { PAGE_TABLE_POOL *HeadPool; @@ -621,7 +637,7 @@ EnablePageTableProtection ( DEBUG ((DEBUG_INFO, "EnablePageTableProtection\n")); - if (mPageTablePool == NULL) { + if (PageTablePool == NULL) { return; } @@ -632,10 +648,10 @@ EnablePageTableProtection ( AsmWriteCr0 (AsmReadCr0 () & ~CR0_WP); // - // SetPageTablePoolReadOnly might update mPageTablePool. It's safer to + // SetPageTablePoolReadOnly might update PageTablePool. It's safer to // remember original one in advance. // - HeadPool = mPageTablePool; + HeadPool = PageTablePool; Pool = HeadPool; do { Address = (EFI_PHYSICAL_ADDRESS)(UINTN)Pool; @@ -647,7 +663,7 @@ EnablePageTableProtection ( // protection to them one by one. // while (PoolSize > 0) { - SetPageTablePoolReadOnly (PageTableBase, Address, Level4Paging); + SetPageTablePoolReadOnly (PageTableBase, Address, Level4Paging, PageTablePool); Address += PAGE_TABLE_POOL_UNIT_SIZE; PoolSize -= PAGE_TABLE_POOL_UNIT_SIZE; } @@ -700,6 +716,7 @@ CreateIdentityMappingPageTables ( BOOLEAN Page1GSupport; PAGE_TABLE_1G_ENTRY *PageDirectory1GEntry; IA32_CR4 Cr4; + PAGE_TABLE_POOL *PageTablePool; // // Set PageMapLevel5Entry to suppress incorrect compiler/analyzer warnings @@ -785,13 +802,14 @@ CreateIdentityMappingPageTables ( (UINT64)TotalPagesNum )); - BigPageAddress = (UINTN)AllocatePageTableMemory (TotalPagesNum); + PageTablePool = NULL; + BigPageAddress = (UINTN)AllocatePageTableMemory (TotalPagesNum, &PageTablePool); if (BigPageAddress == 0) { ASSERT (FALSE); return 0; } - DEBUG ((DEBUG_INFO, "BigPageAddress = 0x%llx\n", BigPageAddress)); + DEBUG ((DEBUG_INFO, "BigPageAddress = 0x%llx, PageTablePool=%p\n", BigPageAddress, PageTablePool)); // // By architecture only one PageMapLevel4 exists - so lets allocate storage for it. @@ -856,7 +874,8 @@ CreateIdentityMappingPageTables ( PageAddress, (UINT64 *)PageDirectory1GEntry, StackBase, - StackSize + StackSize, + PageTablePool ); } else { // @@ -892,7 +911,7 @@ CreateIdentityMappingPageTables ( // // Need to split this 2M page that covers NULL or stack range. // - Split2MPageTo4K (PageAddress, (UINT64 *)PageDirectoryEntry, StackBase, StackSize); + Split2MPageTo4K (PageAddress, (UINT64 *)PageDirectoryEntry, StackBase, StackSize, PageTablePool); } else { // // Fill in the Page Directory entries @@ -929,7 +948,7 @@ CreateIdentityMappingPageTables ( // Protect the page table by marking the memory used for page table to be // read-only. // - EnablePageTableProtection ((UINTN)PageMap, TRUE); + EnablePageTableProtection ((UINTN)PageMap, TRUE, PageTablePool); return (UINTN)PageMap; }