| /** @file | |
| Unit tests for BaseMemoryBinLib library. | |
| Copyright (c) Microsoft Corporation. | |
| SPDX-License-Identifier: BSD-2-Clause-Patent | |
| **/ | |
| #include <Library/GoogleTestLib.h> | |
| #include <GoogleTest/Library/MockHobLib.h> | |
| extern "C" { | |
| #include <Uefi/UefiBaseType.h> | |
| #include <Uefi/UefiMultiPhase.h> | |
| #include <Pi/PiMultiPhase.h> | |
| #include <Library/BaseLib.h> | |
| #include <Library/DebugLib.h> | |
| #include <Library/BaseMemoryLib.h> | |
| #include <Library/MemoryAllocationLib.h> | |
| #include <Guid/MemoryTypeInformation.h> | |
| #include <Pi/PiHob.h> | |
| #include <Pi/PiDxeCis.h> | |
| #include <MemoryBin.h> | |
| BOOLEAN mMemoryTypeInformationInitialized = FALSE; | |
| EFI_MEMORY_TYPE_STATISTICS mMemoryTypeStatistics[EfiMaxMemoryType + 1] = { | |
| { 0, MAX_ALLOC_ADDRESS, 0, 0, EfiMaxMemoryType, TRUE, FALSE }, // EfiReservedMemoryType | |
| { 0, MAX_ALLOC_ADDRESS, 0, 0, EfiMaxMemoryType, FALSE, FALSE }, // EfiLoaderCode | |
| { 0, MAX_ALLOC_ADDRESS, 0, 0, EfiMaxMemoryType, FALSE, FALSE }, // EfiLoaderData | |
| { 0, MAX_ALLOC_ADDRESS, 0, 0, EfiMaxMemoryType, FALSE, FALSE }, // EfiBootServicesCode | |
| { 0, MAX_ALLOC_ADDRESS, 0, 0, EfiMaxMemoryType, FALSE, FALSE }, // EfiBootServicesData | |
| { 0, MAX_ALLOC_ADDRESS, 0, 0, EfiMaxMemoryType, TRUE, TRUE }, // EfiRuntimeServicesCode | |
| { 0, MAX_ALLOC_ADDRESS, 0, 0, EfiMaxMemoryType, TRUE, TRUE }, // EfiRuntimeServicesData | |
| { 0, MAX_ALLOC_ADDRESS, 0, 0, EfiMaxMemoryType, FALSE, FALSE }, // EfiConventionalMemory | |
| { 0, MAX_ALLOC_ADDRESS, 0, 0, EfiMaxMemoryType, FALSE, FALSE }, // EfiUnusableMemory | |
| { 0, MAX_ALLOC_ADDRESS, 0, 0, EfiMaxMemoryType, TRUE, FALSE }, // EfiACPIReclaimMemory | |
| { 0, MAX_ALLOC_ADDRESS, 0, 0, EfiMaxMemoryType, TRUE, FALSE }, // EfiACPIMemoryNVS | |
| { 0, MAX_ALLOC_ADDRESS, 0, 0, EfiMaxMemoryType, FALSE, FALSE }, // EfiMemoryMappedIO | |
| { 0, MAX_ALLOC_ADDRESS, 0, 0, EfiMaxMemoryType, FALSE, FALSE }, // EfiMemoryMappedIOPortSpace | |
| { 0, MAX_ALLOC_ADDRESS, 0, 0, EfiMaxMemoryType, TRUE, TRUE }, // EfiPalCode | |
| { 0, MAX_ALLOC_ADDRESS, 0, 0, EfiMaxMemoryType, FALSE, FALSE }, // EfiPersistentMemory | |
| { 0, MAX_ALLOC_ADDRESS, 0, 0, EfiMaxMemoryType, TRUE, FALSE }, // EfiUnacceptedMemoryType | |
| { 0, MAX_ALLOC_ADDRESS, 0, 0, EfiMaxMemoryType, FALSE, FALSE } // EfiMaxMemoryType | |
| }; | |
| EFI_PHYSICAL_ADDRESS mDefaultMaximumAddress = MAX_ALLOC_ADDRESS; | |
| EFI_PHYSICAL_ADDRESS mDefaultBaseAddress = MAX_ALLOC_ADDRESS; | |
| EFI_MEMORY_TYPE_INFORMATION gMemoryTypeInformation[EfiMaxMemoryType + 1] = { | |
| { EfiReservedMemoryType, 0 }, | |
| { EfiLoaderCode, 0 }, | |
| { EfiLoaderData, 0 }, | |
| { EfiBootServicesCode, 0 }, | |
| { EfiBootServicesData, 0 }, | |
| { EfiRuntimeServicesCode, 0 }, | |
| { EfiRuntimeServicesData, 0 }, | |
| { EfiConventionalMemory, 0 }, | |
| { EfiUnusableMemory, 0 }, | |
| { EfiACPIReclaimMemory, 0 }, | |
| { EfiACPIMemoryNVS, 0 }, | |
| { EfiMemoryMappedIO, 0 }, | |
| { EfiMemoryMappedIOPortSpace, 0 }, | |
| { EfiPalCode, 0 }, | |
| { EfiPersistentMemory, 0 }, | |
| { EfiUnacceptedMemoryType, 0 }, | |
| { EfiMaxMemoryType, 0 } | |
| }; | |
| } | |
| using namespace testing; | |
| class BaseMemoryBinLibTest : public ::testing::Test { | |
| protected: | |
| StrictMock<MockHobLib> HobLib; | |
| void | |
| SetUp ( | |
| ) override | |
| { | |
| // | |
| // Reset global state before each test | |
| // | |
| mMemoryTypeInformationInitialized = FALSE; | |
| mDefaultMaximumAddress = MAX_ALLOC_ADDRESS; | |
| mDefaultBaseAddress = MAX_ALLOC_ADDRESS; | |
| for (UINTN i = 0; i < EfiMaxMemoryType + 1; i++) { | |
| gMemoryTypeInformation[i].NumberOfPages = 0; | |
| } | |
| for (UINTN i = 0; i < EfiMaxMemoryType + 1; i++) { | |
| mMemoryTypeStatistics[i].BaseAddress = 0; | |
| mMemoryTypeStatistics[i].MaximumAddress = MAX_ALLOC_ADDRESS; | |
| mMemoryTypeStatistics[i].CurrentNumberOfPages = 0; | |
| mMemoryTypeStatistics[i].NumberOfPages = 0; | |
| mMemoryTypeStatistics[i].InformationIndex = EfiMaxMemoryType; | |
| } | |
| mMemoryTypeStatistics[EfiReservedMemoryType].Special = TRUE; | |
| mMemoryTypeStatistics[EfiRuntimeServicesCode].Special = TRUE; | |
| mMemoryTypeStatistics[EfiRuntimeServicesCode].Runtime = TRUE; | |
| mMemoryTypeStatistics[EfiRuntimeServicesData].Special = TRUE; | |
| mMemoryTypeStatistics[EfiRuntimeServicesData].Runtime = TRUE; | |
| mMemoryTypeStatistics[EfiACPIReclaimMemory].Special = TRUE; | |
| mMemoryTypeStatistics[EfiACPIMemoryNVS].Special = TRUE; | |
| mMemoryTypeStatistics[EfiPalCode].Special = TRUE; | |
| mMemoryTypeStatistics[EfiPalCode].Runtime = TRUE; | |
| mMemoryTypeStatistics[EfiUnacceptedMemoryType].Special = TRUE; | |
| } | |
| }; | |
| // | |
| // Test: CalculateTotalMemoryBinSizeNeeded with no pages allocated | |
| // | |
| TEST_F (BaseMemoryBinLibTest, CalculateTotalMemoryBinSizeNeededReturnsZeroWhenNoPagesAllocated) { | |
| UINT64 TotalSize; | |
| TotalSize = CalculateTotalMemoryBinSizeNeeded (NULL, gMemoryTypeInformation); | |
| ASSERT_EQ (TotalSize, (UINT64)0); | |
| } | |
| // | |
| // Test: CalculateTotalMemoryBinSizeNeeded with pages allocated | |
| // | |
| TEST_F (BaseMemoryBinLibTest, CalculateTotalMemoryBinSizeNeededCalculatesCorrectSize) { | |
| UINT64 TotalSize; | |
| gMemoryTypeInformation[0].Type = EfiRuntimeServicesCode; | |
| gMemoryTypeInformation[0].NumberOfPages = 10; | |
| gMemoryTypeInformation[1].Type = EfiRuntimeServicesData; | |
| gMemoryTypeInformation[1].NumberOfPages = 20; | |
| gMemoryTypeInformation[2].Type = EfiMaxMemoryType; | |
| TotalSize = CalculateTotalMemoryBinSizeNeeded (NULL, gMemoryTypeInformation); | |
| ASSERT_EQ (TotalSize, (UINT64)(30 * EFI_PAGE_SIZE)); | |
| } | |
| // | |
| // Test: CoreSetMemoryTypeInformationRange initializes bins correctly | |
| // | |
| TEST_F (BaseMemoryBinLibTest, CoreSetMemoryTypeInformationRangeSetsUpBinsCorrectly) { | |
| EFI_PHYSICAL_ADDRESS Start; | |
| UINT64 Length; | |
| Start = 0x100000; | |
| Length = 0x100000; | |
| gMemoryTypeInformation[0].Type = EfiRuntimeServicesCode; | |
| gMemoryTypeInformation[0].NumberOfPages = 20; | |
| gMemoryTypeInformation[1].Type = EfiRuntimeServicesData; | |
| gMemoryTypeInformation[1].NumberOfPages = 10; | |
| gMemoryTypeInformation[2].Type = EfiReservedMemoryType; | |
| gMemoryTypeInformation[2].NumberOfPages = 5; | |
| gMemoryTypeInformation[3].Type = EfiACPIReclaimMemory; | |
| gMemoryTypeInformation[3].NumberOfPages = 15; | |
| gMemoryTypeInformation[4].Type = EfiACPIMemoryNVS; | |
| gMemoryTypeInformation[4].NumberOfPages = 25; | |
| gMemoryTypeInformation[5].Type = EfiMaxMemoryType; | |
| CoreSetMemoryTypeInformationRange (Start, Length, gMemoryTypeInformation, &mMemoryTypeInformationInitialized, mMemoryTypeStatistics, &mDefaultMaximumAddress); | |
| ASSERT_TRUE (mMemoryTypeInformationInitialized); | |
| ASSERT_EQ (mMemoryTypeStatistics[EfiRuntimeServicesCode].NumberOfPages, (UINT32)20); | |
| ASSERT_EQ (mMemoryTypeStatistics[EfiRuntimeServicesData].NumberOfPages, (UINT32)10); | |
| ASSERT_EQ (mMemoryTypeStatistics[EfiReservedMemoryType].NumberOfPages, (UINT32)5); | |
| ASSERT_EQ (mMemoryTypeStatistics[EfiACPIReclaimMemory].NumberOfPages, (UINT32)15); | |
| ASSERT_EQ (mMemoryTypeStatistics[EfiACPIMemoryNVS].NumberOfPages, (UINT32)25); | |
| // Confirm contiguous bins | |
| ASSERT_EQ (mMemoryTypeStatistics[EfiRuntimeServicesData].MaximumAddress + 1, mMemoryTypeStatistics[EfiRuntimeServicesCode].BaseAddress); | |
| ASSERT_EQ (mMemoryTypeStatistics[EfiReservedMemoryType].MaximumAddress + 1, mMemoryTypeStatistics[EfiRuntimeServicesData].BaseAddress); | |
| ASSERT_EQ (mMemoryTypeStatistics[EfiACPIReclaimMemory].MaximumAddress + 1, mMemoryTypeStatistics[EfiReservedMemoryType].BaseAddress); | |
| ASSERT_EQ (mMemoryTypeStatistics[EfiACPIMemoryNVS].MaximumAddress + 1, mMemoryTypeStatistics[EfiACPIReclaimMemory].BaseAddress); | |
| } | |
| // | |
| // Test: CoreSetMemoryTypeInformationRange rejects insufficient space | |
| // | |
| TEST_F (BaseMemoryBinLibTest, CoreSetMemoryTypeInformationRangeRejectsInsufficientSpace) { | |
| EFI_PHYSICAL_ADDRESS Start; | |
| UINT64 Length; | |
| Start = 0x100000; | |
| Length = 0x1000; | |
| gMemoryTypeInformation[0].Type = EfiRuntimeServicesCode; | |
| gMemoryTypeInformation[0].NumberOfPages = 100; // Requires more than 4KB | |
| gMemoryTypeInformation[1].Type = EfiMaxMemoryType; | |
| CoreSetMemoryTypeInformationRange (Start, Length, gMemoryTypeInformation, &mMemoryTypeInformationInitialized, mMemoryTypeStatistics, &mDefaultMaximumAddress); | |
| ASSERT_FALSE (mMemoryTypeInformationInitialized); | |
| } | |
| // | |
| // Test: CoreSetMemoryTypeInformationRange respects already initialized state | |
| // | |
| TEST_F (BaseMemoryBinLibTest, CoreSetMemoryTypeInformationRangeRespectsInitializedState) { | |
| EFI_PHYSICAL_ADDRESS Start; | |
| UINT64 Length; | |
| mMemoryTypeInformationInitialized = TRUE; | |
| Start = 0x100000; | |
| Length = 0x100000; | |
| gMemoryTypeInformation[0].Type = EfiRuntimeServicesCode; | |
| gMemoryTypeInformation[0].NumberOfPages = 10; | |
| mMemoryTypeStatistics[EfiRuntimeServicesCode].BaseAddress = 0x1000; | |
| gMemoryTypeInformation[1].Type = EfiMaxMemoryType; | |
| CoreSetMemoryTypeInformationRange (Start, Length, gMemoryTypeInformation, &mMemoryTypeInformationInitialized, mMemoryTypeStatistics, &mDefaultMaximumAddress); | |
| ASSERT_TRUE (mMemoryTypeInformationInitialized); | |
| ASSERT_EQ (mMemoryTypeStatistics[EfiRuntimeServicesCode].BaseAddress, (EFI_PHYSICAL_ADDRESS)0x1000); | |
| } | |
| // | |
| // Test: UpdateMemoryStatistics updates in-bin statistics correctly | |
| // | |
| TEST_F (BaseMemoryBinLibTest, UpdateMemoryStatisticsUpdatesInBinCorrectly) { | |
| mMemoryTypeInformationInitialized = TRUE; | |
| mMemoryTypeStatistics[EfiRuntimeServicesCode].BaseAddress = 0x100000; | |
| mMemoryTypeStatistics[EfiRuntimeServicesCode].MaximumAddress = 0x200000; | |
| mMemoryTypeStatistics[EfiRuntimeServicesCode].InformationIndex = 0; | |
| gMemoryTypeInformation[0].Type = EfiRuntimeServicesCode; | |
| gMemoryTypeInformation[0].NumberOfPages = 0; | |
| UpdateMemoryStatistics ( | |
| EfiConventionalMemory, | |
| EfiRuntimeServicesCode, | |
| 0x150000, // Within bin range | |
| 10, | |
| &mMemoryTypeInformationInitialized, | |
| mMemoryTypeStatistics, | |
| gMemoryTypeInformation, | |
| 0x10000, // Just set these outside of the range | |
| 0x20000 | |
| ); | |
| ASSERT_EQ (mMemoryTypeStatistics[EfiRuntimeServicesCode].CurrentNumberOfPages, (UINT32)10); | |
| } | |
| // | |
| // Test: UpdateMemoryStatistics updates out-of-bin statistics correctly | |
| // | |
| TEST_F (BaseMemoryBinLibTest, UpdateMemoryStatisticsUpdatesOutOfBinCorrectly) { | |
| mMemoryTypeInformationInitialized = TRUE; | |
| mMemoryTypeStatistics[EfiRuntimeServicesCode].BaseAddress = 0x100000; | |
| mMemoryTypeStatistics[EfiRuntimeServicesCode].MaximumAddress = 0x200000; | |
| mMemoryTypeStatistics[EfiRuntimeServicesCode].InformationIndex = 0; | |
| gMemoryTypeInformation[0].Type = EfiRuntimeServicesCode; | |
| gMemoryTypeInformation[0].NumberOfPages = 0; | |
| UpdateMemoryStatistics ( | |
| EfiConventionalMemory, | |
| EfiRuntimeServicesCode, | |
| 0x300000, // Outside bin range | |
| 10, | |
| &mMemoryTypeInformationInitialized, | |
| mMemoryTypeStatistics, | |
| gMemoryTypeInformation, | |
| 0x10000, // Just set these outside of the range | |
| 0x20000 | |
| ); | |
| ASSERT_EQ (mMemoryTypeStatistics[EfiRuntimeServicesCode].CurrentNumberOfPages, (UINT32)0); | |
| } | |
| // | |
| // Test: UpdateMemoryStatistics handles freeing memory | |
| // | |
| TEST_F (BaseMemoryBinLibTest, UpdateMemoryStatisticsHandlesFreeingMemory) { | |
| mMemoryTypeInformationInitialized = TRUE; | |
| mMemoryTypeStatistics[EfiRuntimeServicesCode].BaseAddress = 0x100000; | |
| mMemoryTypeStatistics[EfiRuntimeServicesCode].MaximumAddress = 0x200000; | |
| mMemoryTypeStatistics[EfiRuntimeServicesCode].CurrentNumberOfPages = 20; | |
| mMemoryTypeStatistics[EfiRuntimeServicesCode].InformationIndex = 0; | |
| gMemoryTypeInformation[0].Type = EfiRuntimeServicesCode; | |
| gMemoryTypeInformation[0].NumberOfPages = 20; | |
| UpdateMemoryStatistics ( | |
| EfiRuntimeServicesCode, | |
| EfiConventionalMemory, | |
| 0x150000, // Within bin range | |
| 10, | |
| &mMemoryTypeInformationInitialized, | |
| mMemoryTypeStatistics, | |
| gMemoryTypeInformation, | |
| 0x10000, // Just set these outside of the range | |
| 0x20000 | |
| ); | |
| ASSERT_EQ (mMemoryTypeStatistics[EfiRuntimeServicesCode].CurrentNumberOfPages, (UINT32)10); | |
| } | |
| // | |
| // Tests for AllocateMemoryTypeInformationBins | |
| // | |
| // | |
| // Test: AllocateMemoryTypeInformationBins does nothing when already initialized | |
| // | |
| TEST_F (BaseMemoryBinLibTest, DoesNothingWhenAlreadyInitialized) { | |
| mMemoryTypeInformationInitialized = TRUE; | |
| mMemoryTypeStatistics[EfiRuntimeServicesCode].BaseAddress = 0x1000; | |
| AllocateMemoryTypeInformationBins (&mMemoryTypeInformationInitialized, gMemoryTypeInformation, mMemoryTypeStatistics, &mDefaultMaximumAddress, FALSE); | |
| // Should remain unchanged since already initialized | |
| ASSERT_TRUE (mMemoryTypeInformationInitialized); | |
| ASSERT_EQ (mMemoryTypeStatistics[EfiRuntimeServicesCode].BaseAddress, (EFI_PHYSICAL_ADDRESS)0x1000); | |
| } | |
| // | |
| // Test: AllocateMemoryTypeInformationBins does nothing when no pages needed | |
| // | |
| TEST_F (BaseMemoryBinLibTest, DoesNothingWhenNoPagesNeeded) { | |
| AllocateMemoryTypeInformationBins (&mMemoryTypeInformationInitialized, gMemoryTypeInformation, mMemoryTypeStatistics, &mDefaultMaximumAddress, FALSE); | |
| ASSERT_TRUE (mMemoryTypeInformationInitialized); | |
| ASSERT_EQ (mMemoryTypeStatistics[EfiReservedMemoryType].NumberOfPages, (UINT32)0); | |
| ASSERT_EQ (mMemoryTypeStatistics[EfiRuntimeServicesCode].NumberOfPages, (UINT32)0); | |
| ASSERT_EQ (mMemoryTypeStatistics[EfiRuntimeServicesData].NumberOfPages, (UINT32)0); | |
| ASSERT_EQ (mMemoryTypeStatistics[EfiACPIReclaimMemory].NumberOfPages, (UINT32)0); | |
| ASSERT_EQ (mMemoryTypeStatistics[EfiACPIMemoryNVS].NumberOfPages, (UINT32)0); | |
| } | |
| // | |
| // Test: AllocateMemoryTypeInformationBins allocates pages and initializes bins | |
| // | |
| TEST_F (BaseMemoryBinLibTest, AllocatesPagesAndInitializesBins) { | |
| gMemoryTypeInformation[0].Type = EfiRuntimeServicesCode; | |
| gMemoryTypeInformation[0].NumberOfPages = 20; | |
| gMemoryTypeInformation[1].Type = EfiRuntimeServicesData; | |
| gMemoryTypeInformation[1].NumberOfPages = 10; | |
| gMemoryTypeInformation[2].Type = EfiReservedMemoryType; | |
| gMemoryTypeInformation[2].NumberOfPages = 5; | |
| gMemoryTypeInformation[3].Type = EfiACPIReclaimMemory; | |
| gMemoryTypeInformation[3].NumberOfPages = 15; | |
| gMemoryTypeInformation[4].Type = EfiACPIMemoryNVS; | |
| gMemoryTypeInformation[4].NumberOfPages = 25; | |
| gMemoryTypeInformation[5].Type = EfiMaxMemoryType; | |
| // HOB should not be built in this case | |
| EXPECT_CALL (HobLib, BuildResourceDescriptorWithOwnerHob (_, _, _, _, _)) | |
| .Times (0); | |
| AllocateMemoryTypeInformationBins (&mMemoryTypeInformationInitialized, gMemoryTypeInformation, mMemoryTypeStatistics, &mDefaultMaximumAddress, FALSE); | |
| ASSERT_TRUE (mMemoryTypeInformationInitialized); | |
| ASSERT_EQ (mMemoryTypeStatistics[EfiRuntimeServicesCode].NumberOfPages, (UINT32)20); | |
| ASSERT_EQ (mMemoryTypeStatistics[EfiRuntimeServicesData].NumberOfPages, (UINT32)10); | |
| ASSERT_EQ (mMemoryTypeStatistics[EfiReservedMemoryType].NumberOfPages, (UINT32)5); | |
| ASSERT_EQ (mMemoryTypeStatistics[EfiACPIReclaimMemory].NumberOfPages, (UINT32)15); | |
| ASSERT_EQ (mMemoryTypeStatistics[EfiACPIMemoryNVS].NumberOfPages, (UINT32)25); | |
| // Confirm contiguous bins | |
| ASSERT_EQ (mMemoryTypeStatistics[EfiRuntimeServicesData].MaximumAddress + 1, mMemoryTypeStatistics[EfiRuntimeServicesCode].BaseAddress); | |
| ASSERT_EQ (mMemoryTypeStatistics[EfiReservedMemoryType].MaximumAddress + 1, mMemoryTypeStatistics[EfiRuntimeServicesData].BaseAddress); | |
| ASSERT_EQ (mMemoryTypeStatistics[EfiACPIReclaimMemory].MaximumAddress + 1, mMemoryTypeStatistics[EfiReservedMemoryType].BaseAddress); | |
| ASSERT_EQ (mMemoryTypeStatistics[EfiACPIMemoryNVS].MaximumAddress + 1, mMemoryTypeStatistics[EfiACPIReclaimMemory].BaseAddress); | |
| } | |
| // | |
| // Test: AllocateMemoryTypeInformationBins creates HOB when requested | |
| // | |
| TEST_F (BaseMemoryBinLibTest, CreatesHobWhenRequested) { | |
| UINT64 TotalPages = 30; | |
| gMemoryTypeInformation[0].Type = EfiRuntimeServicesCode; | |
| gMemoryTypeInformation[0].NumberOfPages = 10; | |
| gMemoryTypeInformation[1].Type = EfiRuntimeServicesData; | |
| gMemoryTypeInformation[1].NumberOfPages = 20; | |
| gMemoryTypeInformation[2].Type = EfiMaxMemoryType; | |
| EXPECT_CALL ( | |
| HobLib, | |
| BuildResourceDescriptorWithOwnerHob ( | |
| EFI_RESOURCE_SYSTEM_MEMORY, | |
| EFI_RESOURCE_ATTRIBUTE_PRESENT | EFI_RESOURCE_ATTRIBUTE_INITIALIZED | EFI_RESOURCE_ATTRIBUTE_TESTED, | |
| _, | |
| TotalPages * EFI_PAGE_SIZE, | |
| &gEfiMemoryTypeInformationGuid | |
| ) | |
| ) | |
| .Times (1); | |
| AllocateMemoryTypeInformationBins (&mMemoryTypeInformationInitialized, gMemoryTypeInformation, mMemoryTypeStatistics, &mDefaultMaximumAddress, TRUE); | |
| ASSERT_TRUE (mMemoryTypeInformationInitialized); | |
| } | |
| // | |
| // Test: PopulateMemoryTypeInformation returns NOT_FOUND when Memory Type Information HOB is missing | |
| // | |
| TEST_F (BaseMemoryBinLibTest, ReturnsNotFoundWhenMemoryTypeInformationHobMissing) { | |
| EFI_STATUS Status; | |
| EXPECT_CALL (HobLib, GetFirstGuidHob (&gEfiMemoryTypeInformationGuid)) | |
| .WillOnce (Return ((VOID *)NULL)); | |
| Status = PopulateMemoryTypeInformation (gMemoryTypeInformation); | |
| ASSERT_EQ (Status, EFI_NOT_FOUND); | |
| } | |
| // | |
| // Test: PopulateMemoryTypeInformation populates from valid HOB | |
| // | |
| // | |
| // Align a page count to the allocation granularity that | |
| // PopulateMemoryTypeInformation applies for the given memory type. Runtime | |
| // memory types are rounded up to RUNTIME_PAGE_ALLOCATION_GRANULARITY, which is | |
| // larger than EFI_PAGE_SIZE on some architectures (e.g. 64 KiB on AArch64), so | |
| // the resulting page counts are architecture dependent. | |
| // | |
| static UINT32 | |
| ExpectedAlignedPages ( | |
| EFI_MEMORY_TYPE Type, | |
| UINT32 NumberOfPages | |
| ) | |
| { | |
| UINT32 Granularity; | |
| if ((Type == EfiReservedMemoryType) || | |
| (Type == EfiACPIMemoryNVS) || | |
| (Type == EfiRuntimeServicesCode) || | |
| (Type == EfiRuntimeServicesData)) | |
| { | |
| Granularity = RUNTIME_PAGE_ALLOCATION_GRANULARITY; | |
| } else { | |
| Granularity = DEFAULT_PAGE_ALLOCATION_GRANULARITY; | |
| } | |
| return (UINT32)EFI_SIZE_TO_PAGES ( | |
| ALIGN_VALUE (EFI_PAGES_TO_SIZE ((UINTN)NumberOfPages), Granularity) | |
| ); | |
| } | |
| TEST_F (BaseMemoryBinLibTest, PopulatesFromValidHob) { | |
| EFI_STATUS Status; | |
| UINT8 GuidHobBuffer[sizeof (EFI_HOB_GUID_TYPE) + sizeof (EFI_MEMORY_TYPE_INFORMATION) * 7]; | |
| EFI_HOB_GUID_TYPE *GuidHob; | |
| EFI_MEMORY_TYPE_INFORMATION *MemTypeInfo; | |
| ZeroMem (GuidHobBuffer, sizeof (GuidHobBuffer)); | |
| GuidHob = (EFI_HOB_GUID_TYPE *)GuidHobBuffer; | |
| GuidHob->Header.HobType = EFI_HOB_TYPE_GUID_EXTENSION; | |
| GuidHob->Header.HobLength = sizeof (GuidHobBuffer); | |
| CopyGuid (&GuidHob->Name, &gEfiMemoryTypeInformationGuid); | |
| MemTypeInfo = (EFI_MEMORY_TYPE_INFORMATION *)(GuidHob + 1); | |
| MemTypeInfo[0].Type = EfiReservedMemoryType; | |
| MemTypeInfo[0].NumberOfPages = 5; | |
| MemTypeInfo[1].Type = EfiRuntimeServicesCode; | |
| MemTypeInfo[1].NumberOfPages = 10; | |
| MemTypeInfo[2].Type = EfiRuntimeServicesData; | |
| MemTypeInfo[2].NumberOfPages = 15; | |
| MemTypeInfo[3].Type = EfiACPIReclaimMemory; | |
| MemTypeInfo[3].NumberOfPages = 20; | |
| MemTypeInfo[4].Type = EfiACPIMemoryNVS; | |
| MemTypeInfo[4].NumberOfPages = 25; | |
| MemTypeInfo[5].Type = EfiPalCode; | |
| MemTypeInfo[5].NumberOfPages = 8; | |
| MemTypeInfo[6].Type = EfiMaxMemoryType; | |
| MemTypeInfo[6].NumberOfPages = 0; | |
| EXPECT_CALL (HobLib, GetFirstGuidHob (&gEfiMemoryTypeInformationGuid)) | |
| .WillOnce (Return ((VOID *)GuidHob)); | |
| Status = PopulateMemoryTypeInformation (gMemoryTypeInformation); | |
| ASSERT_EQ (Status, EFI_SUCCESS); | |
| ASSERT_EQ (gMemoryTypeInformation[0].Type, (UINT32)EfiReservedMemoryType); | |
| ASSERT_EQ (gMemoryTypeInformation[0].NumberOfPages, ExpectedAlignedPages (EfiReservedMemoryType, 5)); | |
| ASSERT_EQ (gMemoryTypeInformation[1].Type, (UINT32)EfiRuntimeServicesCode); | |
| ASSERT_EQ (gMemoryTypeInformation[1].NumberOfPages, ExpectedAlignedPages (EfiRuntimeServicesCode, 10)); | |
| ASSERT_EQ (gMemoryTypeInformation[2].Type, (UINT32)EfiRuntimeServicesData); | |
| ASSERT_EQ (gMemoryTypeInformation[2].NumberOfPages, ExpectedAlignedPages (EfiRuntimeServicesData, 15)); | |
| ASSERT_EQ (gMemoryTypeInformation[3].Type, (UINT32)EfiACPIReclaimMemory); | |
| ASSERT_EQ (gMemoryTypeInformation[3].NumberOfPages, ExpectedAlignedPages (EfiACPIReclaimMemory, 20)); | |
| ASSERT_EQ (gMemoryTypeInformation[4].Type, (UINT32)EfiACPIMemoryNVS); | |
| ASSERT_EQ (gMemoryTypeInformation[4].NumberOfPages, ExpectedAlignedPages (EfiACPIMemoryNVS, 25)); | |
| ASSERT_EQ (gMemoryTypeInformation[5].Type, (UINT32)EfiPalCode); | |
| ASSERT_EQ (gMemoryTypeInformation[5].NumberOfPages, ExpectedAlignedPages (EfiPalCode, 8)); | |
| } | |
| // | |
| // Test: PopulateMemoryTypeInformation zeroes all pages when HOB is corrupted | |
| // (i.e. it does not terminate in an EfiMaxMemoryType entry) | |
| // | |
| TEST_F (BaseMemoryBinLibTest, ZeroesAllPagesWhenHobIsCorrupted) { | |
| EFI_STATUS Status; | |
| UINT8 GuidHobBuffer[sizeof (EFI_HOB_GUID_TYPE) + sizeof (EFI_MEMORY_TYPE_INFORMATION) * 7]; | |
| EFI_HOB_GUID_TYPE *GuidHob; | |
| EFI_MEMORY_TYPE_INFORMATION *MemTypeInfo; | |
| ZeroMem (GuidHobBuffer, sizeof (GuidHobBuffer)); | |
| GuidHob = (EFI_HOB_GUID_TYPE *)GuidHobBuffer; | |
| GuidHob->Header.HobType = EFI_HOB_TYPE_GUID_EXTENSION; | |
| GuidHob->Header.HobLength = sizeof (GuidHobBuffer); | |
| CopyGuid (&GuidHob->Name, &gEfiMemoryTypeInformationGuid); | |
| // | |
| // Populate every entry with a valid type and a non-zero page count, but | |
| // deliberately omit the terminating EfiMaxMemoryType entry to corrupt the HOB. | |
| // | |
| MemTypeInfo = (EFI_MEMORY_TYPE_INFORMATION *)(GuidHob + 1); | |
| MemTypeInfo[0].Type = EfiReservedMemoryType; | |
| MemTypeInfo[0].NumberOfPages = 5; | |
| MemTypeInfo[1].Type = EfiRuntimeServicesCode; | |
| MemTypeInfo[1].NumberOfPages = 10; | |
| MemTypeInfo[2].Type = EfiRuntimeServicesData; | |
| MemTypeInfo[2].NumberOfPages = 15; | |
| MemTypeInfo[3].Type = EfiACPIReclaimMemory; | |
| MemTypeInfo[3].NumberOfPages = 20; | |
| MemTypeInfo[4].Type = EfiACPIMemoryNVS; | |
| MemTypeInfo[4].NumberOfPages = 25; | |
| MemTypeInfo[5].Type = EfiPalCode; | |
| MemTypeInfo[5].NumberOfPages = 8; | |
| MemTypeInfo[6].Type = EfiBootServicesData; | |
| MemTypeInfo[6].NumberOfPages = 30; | |
| EXPECT_CALL (HobLib, GetFirstGuidHob (&gEfiMemoryTypeInformationGuid)) | |
| .WillOnce (Return ((VOID *)GuidHob)); | |
| Status = PopulateMemoryTypeInformation (gMemoryTypeInformation); | |
| ASSERT_EQ (Status, EFI_NOT_FOUND); | |
| // | |
| // Regardless of the page counts present in the corrupted HOB, every entry | |
| // should have been reset to zero pages. | |
| // | |
| for (UINTN Index = 0; gMemoryTypeInformation[Index].Type != EfiMaxMemoryType; Index++) { | |
| ASSERT_EQ (gMemoryTypeInformation[Index].NumberOfPages, (UINT32)0); | |
| } | |
| } | |
| // | |
| // Test: GetMemoryTypeInformationResourceHob returns NOT_FOUND when no resource HOB exists | |
| // | |
| TEST_F (BaseMemoryBinLibTest, GetMemoryTypeInformationResourceHobReturnsNotFoundWhenNoResourceHob) { | |
| EFI_HOB_RESOURCE_DESCRIPTOR *ResourceHob; | |
| UINT8 HobListBuffer[sizeof (EFI_HOB_HANDOFF_INFO_TABLE) + sizeof (EFI_HOB_GENERIC_HEADER)]; | |
| EFI_HOB_HANDOFF_INFO_TABLE *HandoffHob; | |
| EFI_HOB_GENERIC_HEADER *EndOfHobList; | |
| VOID *HobStart; | |
| ZeroMem (HobListBuffer, sizeof (HobListBuffer)); | |
| HandoffHob = (EFI_HOB_HANDOFF_INFO_TABLE *)HobListBuffer; | |
| HandoffHob->Header.HobType = EFI_HOB_TYPE_HANDOFF; | |
| HandoffHob->Header.HobLength = sizeof (EFI_HOB_HANDOFF_INFO_TABLE); | |
| EndOfHobList = (EFI_HOB_GENERIC_HEADER *)(HandoffHob + 1); | |
| EndOfHobList->HobType = EFI_HOB_TYPE_END_OF_HOB_LIST; | |
| EndOfHobList->HobLength = sizeof (EFI_HOB_GENERIC_HEADER); | |
| HobStart = (VOID *)HobListBuffer; | |
| ResourceHob = GetMemoryTypeInformationResourceHob (&HobStart, gMemoryTypeInformation); | |
| ASSERT_EQ (ResourceHob, NULL); | |
| } | |
| // | |
| // Test: GetMemoryTypeInformationResourceHob finds matching resource HOB | |
| // | |
| TEST_F (BaseMemoryBinLibTest, GetMemoryTypeInformationResourceHobFindsMatchingHob) { | |
| EFI_HOB_RESOURCE_DESCRIPTOR *ResourceHob; | |
| UINT8 HobListBuffer[sizeof (EFI_HOB_HANDOFF_INFO_TABLE) + 3 *sizeof (EFI_HOB_RESOURCE_DESCRIPTOR) + sizeof (EFI_HOB_GENERIC_HEADER)]; | |
| EFI_HOB_HANDOFF_INFO_TABLE *HandoffHob; | |
| EFI_HOB_RESOURCE_DESCRIPTOR *ResourceDescriptor; | |
| EFI_HOB_GENERIC_HEADER *EndOfHobList; | |
| VOID *HobStart; | |
| EFI_GUID OtherGuid = { 0x12345678, 0x1234, 0x1234, { 0x12, 0x34, 0x56, 0x78, 0x9A, 0xBC, 0xDE, 0xF0 } | |
| }; | |
| ZeroMem (HobListBuffer, sizeof (HobListBuffer)); | |
| HandoffHob = (EFI_HOB_HANDOFF_INFO_TABLE *)HobListBuffer; | |
| HandoffHob->Header.HobType = EFI_HOB_TYPE_HANDOFF; | |
| HandoffHob->Header.HobLength = sizeof (EFI_HOB_HANDOFF_INFO_TABLE); | |
| ResourceDescriptor = (EFI_HOB_RESOURCE_DESCRIPTOR *)(HandoffHob + 1); | |
| ResourceDescriptor->Header.HobType = EFI_HOB_TYPE_RESOURCE_DESCRIPTOR; | |
| ResourceDescriptor->Header.HobLength = sizeof (EFI_HOB_RESOURCE_DESCRIPTOR); | |
| ResourceDescriptor->ResourceType = EFI_RESOURCE_SYSTEM_MEMORY; | |
| CopyGuid (&ResourceDescriptor->Owner, &OtherGuid); | |
| ResourceDescriptor->PhysicalStart = 0x100000; | |
| ResourceDescriptor->ResourceLength = 0x50000; | |
| ResourceDescriptor = (EFI_HOB_RESOURCE_DESCRIPTOR *)(ResourceDescriptor + 1); | |
| ResourceDescriptor->Header.HobType = EFI_HOB_TYPE_RESOURCE_DESCRIPTOR; | |
| ResourceDescriptor->Header.HobLength = sizeof (EFI_HOB_RESOURCE_DESCRIPTOR); | |
| ResourceDescriptor->ResourceType = EFI_RESOURCE_SYSTEM_MEMORY; | |
| CopyGuid (&ResourceDescriptor->Owner, &gEfiMemoryTypeInformationGuid); | |
| ResourceDescriptor->PhysicalStart = 0x200000; | |
| ResourceDescriptor->ResourceLength = 0x75000; | |
| ResourceDescriptor->ResourceAttribute = EFI_RESOURCE_ATTRIBUTE_PRESENT | EFI_RESOURCE_ATTRIBUTE_INITIALIZED | EFI_RESOURCE_ATTRIBUTE_TESTED; | |
| ResourceDescriptor = (EFI_HOB_RESOURCE_DESCRIPTOR *)(ResourceDescriptor + 1); | |
| ResourceDescriptor->Header.HobType = EFI_HOB_TYPE_RESOURCE_DESCRIPTOR; | |
| ResourceDescriptor->Header.HobLength = sizeof (EFI_HOB_RESOURCE_DESCRIPTOR); | |
| ResourceDescriptor->ResourceType = EFI_RESOURCE_SYSTEM_MEMORY; | |
| CopyGuid (&ResourceDescriptor->Owner, &OtherGuid); | |
| ResourceDescriptor->PhysicalStart = 0x300000; | |
| ResourceDescriptor->ResourceLength = 0x50000; | |
| EndOfHobList = (EFI_HOB_GENERIC_HEADER *)(ResourceDescriptor + 1); | |
| EndOfHobList->HobType = EFI_HOB_TYPE_END_OF_HOB_LIST; | |
| EndOfHobList->HobLength = sizeof (EFI_HOB_GENERIC_HEADER); | |
| HobStart = (VOID *)HobListBuffer; | |
| ResourceHob = GetMemoryTypeInformationResourceHob (&HobStart, gMemoryTypeInformation); | |
| ASSERT_EQ (ResourceHob->PhysicalStart, (EFI_PHYSICAL_ADDRESS)0x200000); | |
| ASSERT_EQ (ResourceHob->ResourceLength, (UINT64)0x75000); | |
| } | |
| // | |
| // Test: GetMemoryTypeInformationResourceHob Fails When Multiple Matching HOBs Exist | |
| // | |
| TEST_F (BaseMemoryBinLibTest, GetMemoryTypeInformationResourceHobFailsWithMultipleMatchingHobs) { | |
| EFI_HOB_RESOURCE_DESCRIPTOR *ResourceHob; | |
| UINT8 HobListBuffer[sizeof (EFI_HOB_HANDOFF_INFO_TABLE) + 2 * sizeof (EFI_HOB_RESOURCE_DESCRIPTOR) + sizeof (EFI_HOB_GENERIC_HEADER)]; | |
| EFI_HOB_HANDOFF_INFO_TABLE *HandoffHob; | |
| EFI_HOB_RESOURCE_DESCRIPTOR *FirstMatchingResource; | |
| EFI_HOB_RESOURCE_DESCRIPTOR *SecondMatchingResource; | |
| EFI_HOB_GENERIC_HEADER *EndOfHobList; | |
| VOID *HobStart; | |
| ZeroMem (HobListBuffer, sizeof (HobListBuffer)); | |
| HandoffHob = (EFI_HOB_HANDOFF_INFO_TABLE *)HobListBuffer; | |
| HandoffHob->Header.HobType = EFI_HOB_TYPE_HANDOFF; | |
| HandoffHob->Header.HobLength = sizeof (EFI_HOB_HANDOFF_INFO_TABLE); | |
| // First matching resource HOB | |
| FirstMatchingResource = (EFI_HOB_RESOURCE_DESCRIPTOR *)(HandoffHob + 1); | |
| FirstMatchingResource->Header.HobType = EFI_HOB_TYPE_RESOURCE_DESCRIPTOR; | |
| FirstMatchingResource->Header.HobLength = sizeof (EFI_HOB_RESOURCE_DESCRIPTOR); | |
| FirstMatchingResource->ResourceType = EFI_RESOURCE_SYSTEM_MEMORY; | |
| CopyGuid (&FirstMatchingResource->Owner, &gEfiMemoryTypeInformationGuid); | |
| FirstMatchingResource->PhysicalStart = 0x100000; | |
| FirstMatchingResource->ResourceLength = 0x50000; | |
| FirstMatchingResource->ResourceAttribute = EFI_RESOURCE_ATTRIBUTE_PRESENT | EFI_RESOURCE_ATTRIBUTE_INITIALIZED | EFI_RESOURCE_ATTRIBUTE_TESTED; | |
| // Second matching resource HOB | |
| SecondMatchingResource = (EFI_HOB_RESOURCE_DESCRIPTOR *)(FirstMatchingResource + 1); | |
| SecondMatchingResource->Header.HobType = EFI_HOB_TYPE_RESOURCE_DESCRIPTOR; | |
| SecondMatchingResource->Header.HobLength = sizeof (EFI_HOB_RESOURCE_DESCRIPTOR); | |
| SecondMatchingResource->ResourceType = EFI_RESOURCE_SYSTEM_MEMORY; | |
| CopyGuid (&SecondMatchingResource->Owner, &gEfiMemoryTypeInformationGuid); | |
| SecondMatchingResource->PhysicalStart = 0x400000; | |
| SecondMatchingResource->ResourceLength = 0x80000; | |
| SecondMatchingResource->ResourceAttribute = EFI_RESOURCE_ATTRIBUTE_PRESENT | EFI_RESOURCE_ATTRIBUTE_INITIALIZED | EFI_RESOURCE_ATTRIBUTE_TESTED; | |
| EndOfHobList = (EFI_HOB_GENERIC_HEADER *)(SecondMatchingResource + 1); | |
| EndOfHobList->HobType = EFI_HOB_TYPE_END_OF_HOB_LIST; | |
| EndOfHobList->HobLength = sizeof (EFI_HOB_GENERIC_HEADER); | |
| HobStart = (VOID *)HobListBuffer; | |
| ResourceHob = GetMemoryTypeInformationResourceHob (&HobStart, gMemoryTypeInformation); | |
| ASSERT_EQ (ResourceHob, NULL); | |
| } | |
| int | |
| main ( | |
| int argc, | |
| char *argv[] | |
| ) | |
| { | |
| testing::InitGoogleTest (&argc, argv); | |
| return RUN_ALL_TESTS (); | |
| } |