X-Git-Url: https://git.proxmox.com/?p=mirror_edk2.git;a=blobdiff_plain;f=StandaloneMmPkg%2FCore%2FPool.c;fp=StandaloneMmPkg%2FCore%2FPool.c;h=ce6cfcb9a4cfc078cded7fd25710246e2bfa378d;hp=0000000000000000000000000000000000000000;hb=6b46d77243e02d23ce922803998e01277fe9f399;hpb=0f4db639bb2a16a09a82f2b5b77a7c2aba7f8ae8 diff --git a/StandaloneMmPkg/Core/Pool.c b/StandaloneMmPkg/Core/Pool.c new file mode 100644 index 0000000000..ce6cfcb9a4 --- /dev/null +++ b/StandaloneMmPkg/Core/Pool.c @@ -0,0 +1,293 @@ +/** @file + SMM Memory pool management functions. + + Copyright (c) 2009 - 2014, Intel Corporation. All rights reserved.
+ Copyright (c) 2016 - 2018, ARM Limited. All rights reserved.
+ This program and the accompanying materials are licensed and made available + under the terms and conditions of the BSD License which accompanies this + distribution. The full text of the license may be found at + http://opensource.org/licenses/bsd-license.php + + THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, + WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +**/ + +#include "StandaloneMmCore.h" + +LIST_ENTRY mMmPoolLists[MAX_POOL_INDEX]; +// +// To cache the MMRAM base since when Loading modules At fixed address feature is enabled, +// all module is assigned an offset relative the MMRAM base in build time. +// +GLOBAL_REMOVE_IF_UNREFERENCED EFI_PHYSICAL_ADDRESS gLoadModuleAtFixAddressMmramBase = 0; + +/** + Called to initialize the memory service. + + @param MmramRangeCount Number of MMRAM Regions + @param MmramRanges Pointer to MMRAM Descriptors + +**/ +VOID +MmInitializeMemoryServices ( + IN UINTN MmramRangeCount, + IN EFI_MMRAM_DESCRIPTOR *MmramRanges + ) +{ + UINTN Index; + + // + // Initialize Pool list + // + for (Index = sizeof (mMmPoolLists) / sizeof (*mMmPoolLists); Index > 0;) { + InitializeListHead (&mMmPoolLists[--Index]); + } + + + // + // Initialize free MMRAM regions + // + for (Index = 0; Index < MmramRangeCount; Index++) { + // + // BUGBUG: Add legacy MMRAM region is buggy. + // + if (MmramRanges[Index].CpuStart < BASE_1MB) { + continue; + } + DEBUG ((DEBUG_INFO, "MmAddMemoryRegion %d : 0x%016lx - 0x%016lx\n", + Index, MmramRanges[Index].CpuStart, MmramRanges[Index].PhysicalSize)); + MmAddMemoryRegion ( + MmramRanges[Index].CpuStart, + MmramRanges[Index].PhysicalSize, + EfiConventionalMemory, + MmramRanges[Index].RegionState + ); + } + +} + +/** + Internal Function. Allocate a pool by specified PoolIndex. + + @param PoolIndex Index which indicate the Pool size. + @param FreePoolHdr The returned Free pool. + + @retval EFI_OUT_OF_RESOURCES Allocation failed. + @retval EFI_SUCCESS Pool successfully allocated. + +**/ +EFI_STATUS +InternalAllocPoolByIndex ( + IN UINTN PoolIndex, + OUT FREE_POOL_HEADER **FreePoolHdr + ) +{ + EFI_STATUS Status; + FREE_POOL_HEADER *Hdr; + EFI_PHYSICAL_ADDRESS Address; + + ASSERT (PoolIndex <= MAX_POOL_INDEX); + Status = EFI_SUCCESS; + Hdr = NULL; + if (PoolIndex == MAX_POOL_INDEX) { + Status = MmInternalAllocatePages ( + AllocateAnyPages, + EfiRuntimeServicesData, + EFI_SIZE_TO_PAGES (MAX_POOL_SIZE << 1), + &Address + ); + if (EFI_ERROR (Status)) { + return EFI_OUT_OF_RESOURCES; + } + Hdr = (FREE_POOL_HEADER *) (UINTN) Address; + } else if (!IsListEmpty (&mMmPoolLists[PoolIndex])) { + Hdr = BASE_CR (GetFirstNode (&mMmPoolLists[PoolIndex]), FREE_POOL_HEADER, Link); + RemoveEntryList (&Hdr->Link); + } else { + Status = InternalAllocPoolByIndex (PoolIndex + 1, &Hdr); + if (!EFI_ERROR (Status)) { + Hdr->Header.Size >>= 1; + Hdr->Header.Available = TRUE; + InsertHeadList (&mMmPoolLists[PoolIndex], &Hdr->Link); + Hdr = (FREE_POOL_HEADER*)((UINT8*)Hdr + Hdr->Header.Size); + } + } + + if (!EFI_ERROR (Status)) { + Hdr->Header.Size = MIN_POOL_SIZE << PoolIndex; + Hdr->Header.Available = FALSE; + } + + *FreePoolHdr = Hdr; + return Status; +} + +/** + Internal Function. Free a pool by specified PoolIndex. + + @param FreePoolHdr The pool to free. + + @retval EFI_SUCCESS Pool successfully freed. + +**/ +EFI_STATUS +InternalFreePoolByIndex ( + IN FREE_POOL_HEADER *FreePoolHdr + ) +{ + UINTN PoolIndex; + + ASSERT ((FreePoolHdr->Header.Size & (FreePoolHdr->Header.Size - 1)) == 0); + ASSERT (((UINTN)FreePoolHdr & (FreePoolHdr->Header.Size - 1)) == 0); + ASSERT (FreePoolHdr->Header.Size >= MIN_POOL_SIZE); + + PoolIndex = (UINTN) (HighBitSet32 ((UINT32)FreePoolHdr->Header.Size) - MIN_POOL_SHIFT); + FreePoolHdr->Header.Available = TRUE; + ASSERT (PoolIndex < MAX_POOL_INDEX); + InsertHeadList (&mMmPoolLists[PoolIndex], &FreePoolHdr->Link); + return EFI_SUCCESS; +} + +/** + Allocate pool of a particular type. + + @param PoolType Type of pool to allocate. + @param Size The amount of pool to allocate. + @param Buffer The address to return a pointer to the allocated + pool. + + @retval EFI_INVALID_PARAMETER PoolType not valid. + @retval EFI_OUT_OF_RESOURCES Size exceeds max pool size or allocation failed. + @retval EFI_SUCCESS Pool successfully allocated. + +**/ +EFI_STATUS +EFIAPI +MmInternalAllocatePool ( + IN EFI_MEMORY_TYPE PoolType, + IN UINTN Size, + OUT VOID **Buffer + ) +{ + POOL_HEADER *PoolHdr; + FREE_POOL_HEADER *FreePoolHdr; + EFI_STATUS Status; + EFI_PHYSICAL_ADDRESS Address; + UINTN PoolIndex; + + if (PoolType != EfiRuntimeServicesCode && + PoolType != EfiRuntimeServicesData) { + return EFI_INVALID_PARAMETER; + } + + Size += sizeof (*PoolHdr); + if (Size > MAX_POOL_SIZE) { + Size = EFI_SIZE_TO_PAGES (Size); + Status = MmInternalAllocatePages (AllocateAnyPages, PoolType, Size, &Address); + if (EFI_ERROR (Status)) { + return Status; + } + + PoolHdr = (POOL_HEADER*)(UINTN)Address; + PoolHdr->Size = EFI_PAGES_TO_SIZE (Size); + PoolHdr->Available = FALSE; + *Buffer = PoolHdr + 1; + return Status; + } + + Size = (Size + MIN_POOL_SIZE - 1) >> MIN_POOL_SHIFT; + PoolIndex = (UINTN) HighBitSet32 ((UINT32)Size); + if ((Size & (Size - 1)) != 0) { + PoolIndex++; + } + + Status = InternalAllocPoolByIndex (PoolIndex, &FreePoolHdr); + if (!EFI_ERROR (Status)) { + *Buffer = &FreePoolHdr->Header + 1; + } + return Status; +} + +/** + Allocate pool of a particular type. + + @param PoolType Type of pool to allocate. + @param Size The amount of pool to allocate. + @param Buffer The address to return a pointer to the allocated + pool. + + @retval EFI_INVALID_PARAMETER PoolType not valid. + @retval EFI_OUT_OF_RESOURCES Size exceeds max pool size or allocation failed. + @retval EFI_SUCCESS Pool successfully allocated. + +**/ +EFI_STATUS +EFIAPI +MmAllocatePool ( + IN EFI_MEMORY_TYPE PoolType, + IN UINTN Size, + OUT VOID **Buffer + ) +{ + EFI_STATUS Status; + + Status = MmInternalAllocatePool (PoolType, Size, Buffer); + return Status; +} + +/** + Frees pool. + + @param Buffer The allocated pool entry to free. + + @retval EFI_INVALID_PARAMETER Buffer is not a valid value. + @retval EFI_SUCCESS Pool successfully freed. + +**/ +EFI_STATUS +EFIAPI +MmInternalFreePool ( + IN VOID *Buffer + ) +{ + FREE_POOL_HEADER *FreePoolHdr; + + if (Buffer == NULL) { + return EFI_INVALID_PARAMETER; + } + + FreePoolHdr = (FREE_POOL_HEADER*)((POOL_HEADER*)Buffer - 1); + ASSERT (!FreePoolHdr->Header.Available); + + if (FreePoolHdr->Header.Size > MAX_POOL_SIZE) { + ASSERT (((UINTN)FreePoolHdr & EFI_PAGE_MASK) == 0); + ASSERT ((FreePoolHdr->Header.Size & EFI_PAGE_MASK) == 0); + return MmInternalFreePages ( + (EFI_PHYSICAL_ADDRESS)(UINTN)FreePoolHdr, + EFI_SIZE_TO_PAGES (FreePoolHdr->Header.Size) + ); + } + return InternalFreePoolByIndex (FreePoolHdr); +} + +/** + Frees pool. + + @param Buffer The allocated pool entry to free. + + @retval EFI_INVALID_PARAMETER Buffer is not a valid value. + @retval EFI_SUCCESS Pool successfully freed. + +**/ +EFI_STATUS +EFIAPI +MmFreePool ( + IN VOID *Buffer + ) +{ + EFI_STATUS Status; + + Status = MmInternalFreePool (Buffer); + return Status; +}