/** @file Copyright (c) 2020, PMheart. All rights reserved. SPDX-License-Identifier: BSD-3-Clause **/ #include #include #include #include #include #include #include #include #include #include #ifdef WIN32 #include #endif // WIN32 GLOBAL_REMOVE_IF_UNREFERENCED CONST EFI_MEMORY_TYPE gPhaseDefaultDataType = EfiBootServicesData; GLOBAL_REMOVE_IF_UNREFERENCED CONST EFI_MEMORY_TYPE gPhaseDefaultCodeType = EfiBootServicesCode; // // Limits single pool allocation size to 512MB by default. // Use SetPoolAllocationSizeLimit to change this limit. // STATIC UINTN mPoolAllocationSizeLimit = BASE_512MB; GLOBAL_REMOVE_IF_UNREFERENCED UINTN mPoolAllocations; GLOBAL_REMOVE_IF_UNREFERENCED UINTN mPageAllocations; STATIC UINT64 mPoolAllocationMask = MAX_UINT64; STATIC UINTN mPoolAllocationIndex; STATIC UINT64 mPageAllocationMask = MAX_UINT64; STATIC UINTN mPageAllocationIndex; VOID ConfigureMemoryAllocations ( IN CONST UINT8 *Data, IN UINTN Size, IN OUT UINT32 *ConfigSize ) { mPoolAllocationIndex = 0; mPageAllocationIndex = 0; if (Size - *ConfigSize >= sizeof (UINT64)) { *ConfigSize += sizeof (UINT64); CopyMem (&mPoolAllocationMask, &Data[Size - *ConfigSize], sizeof (UINT64)); } else { mPoolAllocationMask = MAX_UINT64; } if (Size - *ConfigSize >= sizeof (UINT64)) { *ConfigSize += sizeof (UINT64); CopyMem (&mPageAllocationMask, &Data[Size - *ConfigSize], sizeof (UINT64)); } else { mPageAllocationMask = MAX_UINT64; } } VOID SetPoolAllocationSizeLimit ( UINTN AllocationSize ) { mPoolAllocationSizeLimit = AllocationSize; } VOID * EFIAPI CopyMem ( OUT VOID *DestinationBuffer, IN CONST VOID *SourceBuffer, IN UINTN Length ) { ASSERT (DestinationBuffer != NULL); ASSERT (SourceBuffer != NULL); return memmove (DestinationBuffer, SourceBuffer, Length); } VOID * EFIAPI SetMem ( OUT VOID *Buffer, IN UINTN Length, IN UINT8 Value ) { ASSERT (Buffer != NULL); return memset (Buffer, Value, Length); } VOID * EFIAPI ZeroMem ( OUT VOID *Buffer, IN UINTN Length ) { ASSERT (Buffer != NULL); return memset (Buffer, 0, Length); } BOOLEAN EFIAPI IsZeroBuffer ( IN CONST VOID *Buffer, IN UINTN Length ) { UINTN Index; UINT8 *Walker; Walker = (UINT8 *)Buffer; for (Index = 0; Index < Length; ++Index) { if (Walker[Index] != 0) { return FALSE; } } return TRUE; } BOOLEAN EFIAPI IsZeroGuid ( IN CONST GUID *Guid ) { UINT64 LowPartOfGuid; UINT64 HighPartOfGuid; LowPartOfGuid = ReadUnaligned64 ((CONST UINT64 *)Guid); HighPartOfGuid = ReadUnaligned64 ((CONST UINT64 *)Guid + 1); return (BOOLEAN)(LowPartOfGuid == 0 && HighPartOfGuid == 0); } INTN EFIAPI CompareMem ( IN CONST VOID *DestinationBuffer, IN CONST VOID *SourceBuffer, IN UINTN Length ) { ASSERT (DestinationBuffer != NULL); ASSERT (SourceBuffer != NULL); return memcmp (DestinationBuffer, SourceBuffer, Length); } VOID * EFIAPI ScanMem16 ( IN CONST VOID *Buffer, IN UINTN Length, IN UINT16 Value ) { UINT16 *Walker; UINTN Index; Walker = (UINT16 *)Buffer; for (Index = 0; Index < Length; ++Index) { if (Walker[Index] == Value) { return Walker; } } return NULL; } VOID * EFIAPI PhaseAllocatePool ( IN EFI_MEMORY_TYPE MemoryType, IN UINTN AllocationSize ) { VOID *Buffer; UINTN RequestedAllocationSize; Buffer = NULL; RequestedAllocationSize = 0; if (((mPoolAllocationMask & (1ULL << mPoolAllocationIndex)) != 0) && (AllocationSize + 7ULL > AllocationSize)) { // // UEFI guarantees 8-byte alignment. // RequestedAllocationSize = (AllocationSize + 7ULL) & ~7ULL; // // Check that we have not gone beyond the single allocation size limit // if (RequestedAllocationSize <= mPoolAllocationSizeLimit) { Buffer = malloc (RequestedAllocationSize); } else { DEBUG (( DEBUG_POOL, "UMEM: Requested allocation size %u exceeds the pool allocation limit %u \n", (UINT32)RequestedAllocationSize, (UINT32)mPoolAllocationSizeLimit )); } } ++mPoolAllocationIndex; mPoolAllocationIndex &= 63ULL; DEBUG (( DEBUG_POOL, "UMEM: Allocating pool %u at 0x%p\n", (UINT32)AllocationSize, Buffer )); ASSERT (((UINTN)Buffer & 7ULL) == 0); if (Buffer != NULL) { ++mPoolAllocations; } return Buffer; } STATIC EFI_STATUS InternalAllocatePagesAlign ( IN EFI_ALLOCATE_TYPE Type, IN EFI_MEMORY_TYPE MemoryType, IN UINTN Pages, IN OUT EFI_PHYSICAL_ADDRESS *Memory, IN UINT32 Alignment ) { VOID *Buffer; UINTN RequestedAllocationSize; ASSERT (Type == AllocateAnyPages); Buffer = NULL; RequestedAllocationSize = Pages * EFI_PAGE_SIZE; if (((mPageAllocationMask & (1ULL << mPageAllocationIndex)) != 0) && ((Pages != 0) && (RequestedAllocationSize / Pages == EFI_PAGE_SIZE))) { // // Check that we have not gone beyond the single allocation size limit // if (RequestedAllocationSize <= mPoolAllocationSizeLimit) { if (Alignment < EFI_PAGE_SIZE) { Alignment = EFI_PAGE_SIZE; } #ifdef _WIN32 Buffer = _aligned_malloc (RequestedAllocationSize, Alignment); #else // !_WIN32 Buffer = NULL; INTN RetVal; RetVal = posix_memalign (&Buffer, Alignment, RequestedAllocationSize); if (RetVal != 0) { DEBUG ((DEBUG_ERROR, "posix_memalign returns error %d\n", RetVal)); Buffer = NULL; } #endif // _WIN32 } } ++mPageAllocationIndex; mPageAllocationIndex &= 63U; DEBUG (( DEBUG_PAGE, "UMEM: Allocating %u pages at 0x%p\n", (UINT32)Pages, Buffer )); if (Buffer == NULL) { return EFI_NOT_FOUND; } mPageAllocations += Pages; *Memory = (UINTN)Buffer; return EFI_SUCCESS; } EFI_STATUS EFIAPI PhaseAllocatePages ( IN EFI_ALLOCATE_TYPE Type, IN EFI_MEMORY_TYPE MemoryType, IN UINTN Pages, IN OUT EFI_PHYSICAL_ADDRESS *Memory ) { return InternalAllocatePagesAlign ( Type, MemoryType, Pages, Memory, EFI_PAGE_SIZE ); } VOID EFIAPI PhaseFreePool ( IN VOID *Buffer ) { ASSERT (Buffer != NULL); DEBUG (( DEBUG_POOL, "UMEM: Deallocating pool 0x%p\n", Buffer )); // // Check that we are freeing buffer produced by our AllocatePool implementation // if (mPoolAllocations == 0) { DEBUG (( DEBUG_ERROR, "UMEM: Requested buffer to free allocated not by AllocatePool implementations \n" )); abort (); } --mPoolAllocations; free (Buffer); } EFI_STATUS EFIAPI PhaseFreePages ( IN EFI_PHYSICAL_ADDRESS Memory, IN UINTN Pages ) { VOID *Buffer; UINTN BytesToFree; Buffer = (VOID *)(UINTN)Memory; ASSERT (Buffer != NULL); DEBUG (( DEBUG_PAGE, "UMEM: Deallocating %u pages at 0x%p\n", (UINT32)Pages, Buffer )); // // Check that requested pages count to free not exceeds total // allocated pages count // if (Pages > mPageAllocations) { DEBUG (( DEBUG_ERROR, "UMEM: Requested pages count %u to free exceeds total allocated pages %u\n", (UINT32)Pages, (UINT32)mPageAllocations )); abort (); } BytesToFree = Pages * EFI_PAGE_SIZE; if ((Pages != 0) && (BytesToFree / Pages == EFI_PAGE_SIZE)) { mPageAllocations -= Pages; } else { DEBUG (( DEBUG_ERROR, "UMEM: Passed pages count %u proceeds unsigned integer overflow during BytesToFree multiplication\n", (UINT32)Pages )); abort (); } #ifdef _WIN32 _aligned_free (Buffer); #else free (Buffer); #endif return EFI_SUCCESS; } VOID * InternalAllocateAlignedPages ( IN EFI_MEMORY_TYPE MemoryType, IN UINTN Pages, IN UINTN Alignment ) { EFI_STATUS Status; EFI_PHYSICAL_ADDRESS Memory; Status = InternalAllocatePagesAlign ( AllocateAnyPages, MemoryType, Pages, &Memory, (UINT32)Alignment ); if (EFI_ERROR (Status)) { return NULL; } return (VOID *)(UINTN)Memory; } VOID InternalFreeAlignedPages ( IN VOID *Buffer, IN UINTN Pages ) { PhaseFreePages ((UINTN)Buffer, Pages); } GUID * EFIAPI CopyGuid ( OUT GUID *DestinationGuid, IN CONST GUID *SourceGuid ) { ASSERT (DestinationGuid != NULL); ASSERT (SourceGuid != NULL); CopyMem (DestinationGuid, SourceGuid, sizeof (GUID)); return DestinationGuid; } BOOLEAN EFIAPI CompareGuid ( IN CONST GUID *Guid1, IN CONST GUID *Guid2 ) { ASSERT (Guid1 != NULL); ASSERT (Guid2 != NULL); return CompareMem (Guid1, Guid2, sizeof (GUID)) == 0; } UINT16 EFIAPI ReadUnaligned16 ( IN CONST UINT16 *Buffer ) { UINT16 Value; CopyMem (&Value, Buffer, sizeof (UINT16)); return Value; } UINT16 EFIAPI WriteUnaligned16 ( OUT UINT16 *Buffer, IN UINT16 Value ) { ASSERT (Buffer != NULL); CopyMem (Buffer, &Value, sizeof (UINT16)); return Value; } UINT32 EFIAPI ReadUnaligned24 ( IN CONST UINT32 *Buffer ) { UINT32 Value; Value = ReadUnaligned32 (Buffer) & 0xFFFFFFU; return Value; } UINT32 EFIAPI ReadUnaligned32 ( IN CONST UINT32 *Buffer ) { UINT32 Value; ASSERT (Buffer != NULL); CopyMem (&Value, Buffer, sizeof (UINT32)); return Value; } UINT64 EFIAPI ReadUnaligned64 ( IN CONST UINT64 *Buffer ) { UINT64 Value; ASSERT (Buffer != NULL); CopyMem (&Value, Buffer, sizeof (UINT64)); return Value; } UINT32 EFIAPI WriteUnaligned32 ( OUT UINT32 *Buffer, IN UINT32 Value ) { ASSERT (Buffer != NULL); CopyMem (Buffer, &Value, sizeof (UINT32)); return Value; } UINT64 EFIAPI WriteUnaligned64 ( OUT UINT64 *Buffer, IN UINT64 Value ) { ASSERT (Buffer != NULL); CopyMem (Buffer, &Value, sizeof (UINT64)); return Value; }