microsoft/mu_feature_ffa
Publicmirrored fromhttps://github.com/microsoft/mu_feature_ffaAvailable
FfaFeaturePkg/Library/SecurePartitionMemoryAllocationLib/Pool.c
333lines · modecode
| 1 | /** @file |
| 2 | SMM Memory pool management functions. |
| 3 | |
| 4 | Copyright (c) 2009 - 2014, Intel Corporation. All rights reserved.<BR> |
| 5 | Copyright (c) 2016 - 2021, Arm Limited. All rights reserved.<BR> |
| 6 | SPDX-License-Identifier: BSD-2-Clause-Patent |
| 7 | |
| 8 | **/ |
| 9 | |
| 10 | #include <PiMm.h> |
| 11 | |
| 12 | #include <Library/BaseLib.h> |
| 13 | #include <Library/DebugLib.h> |
| 14 | |
| 15 | #include "SecurePartitionMemoryAllocationLib.h" |
| 16 | |
| 17 | typedef struct { |
| 18 | UINT32 Signature; |
| 19 | BOOLEAN Available; |
| 20 | EFI_MEMORY_TYPE Type; |
| 21 | UINTN Size; |
| 22 | } POOL_HEADER; |
| 23 | |
| 24 | typedef struct { |
| 25 | POOL_HEADER Header; |
| 26 | LIST_ENTRY Link; |
| 27 | } FREE_POOL_HEADER; |
| 28 | |
| 29 | // |
| 30 | // MIN_POOL_SHIFT must not be less than 5 |
| 31 | // |
| 32 | #define MIN_POOL_SHIFT 6 |
| 33 | #define MIN_POOL_SIZE (1 << MIN_POOL_SHIFT) |
| 34 | |
| 35 | // |
| 36 | // MAX_POOL_SHIFT must not be less than EFI_PAGE_SHIFT - 1 |
| 37 | // |
| 38 | #define MAX_POOL_SHIFT (EFI_PAGE_SHIFT - 1) |
| 39 | #define MAX_POOL_SIZE (1 << MAX_POOL_SHIFT) |
| 40 | |
| 41 | // |
| 42 | // MAX_POOL_INDEX are calculated by maximum and minimum pool sizes |
| 43 | // |
| 44 | #define MAX_POOL_INDEX (MAX_POOL_SHIFT - MIN_POOL_SHIFT + 1) |
| 45 | |
| 46 | LIST_ENTRY mMmPoolLists[MAX_POOL_INDEX]; |
| 47 | // |
| 48 | // To cache the MMRAM base since when Loading modules At fixed address feature is enabled, |
| 49 | // all module is assigned an offset relative the MMRAM base in build time. |
| 50 | // |
| 51 | GLOBAL_REMOVE_IF_UNREFERENCED EFI_PHYSICAL_ADDRESS gLoadModuleAtFixAddressMmramBase = 0; |
| 52 | |
| 53 | /** |
| 54 | Called to initialize the memory service. |
| 55 | |
| 56 | @param MmramRangeCount Number of MMRAM Regions |
| 57 | @param MmramRanges Pointer to MMRAM Descriptors |
| 58 | |
| 59 | **/ |
| 60 | VOID |
| 61 | MmInitializeMemoryServices ( |
| 62 | IN UINTN MmramRangeCount, |
| 63 | IN EFI_MMRAM_DESCRIPTOR *MmramRanges |
| 64 | ) |
| 65 | { |
| 66 | UINTN Index; |
| 67 | |
| 68 | // |
| 69 | // Initialize Pool list |
| 70 | // |
| 71 | for (Index = sizeof (mMmPoolLists) / sizeof (*mMmPoolLists); Index > 0;) { |
| 72 | InitializeListHead (&mMmPoolLists[--Index]); |
| 73 | } |
| 74 | |
| 75 | // |
| 76 | // Initialize free MMRAM regions |
| 77 | // |
| 78 | for (Index = 0; Index < MmramRangeCount; Index++) { |
| 79 | // |
| 80 | // BUGBUG: Add legacy MMRAM region is buggy. |
| 81 | // |
| 82 | if (MmramRanges[Index].CpuStart < BASE_1MB) { |
| 83 | continue; |
| 84 | } |
| 85 | |
| 86 | DEBUG (( |
| 87 | DEBUG_INFO, |
| 88 | "MmAddMemoryRegion %d : 0x%016lx - 0x%016lx\n", |
| 89 | Index, |
| 90 | MmramRanges[Index].CpuStart, |
| 91 | MmramRanges[Index].PhysicalSize |
| 92 | )); |
| 93 | MmAddMemoryRegion ( |
| 94 | MmramRanges[Index].CpuStart, |
| 95 | MmramRanges[Index].PhysicalSize, |
| 96 | EfiConventionalMemory, |
| 97 | MmramRanges[Index].RegionState |
| 98 | ); |
| 99 | } |
| 100 | } |
| 101 | |
| 102 | /** |
| 103 | Internal Function. Allocate a pool by specified PoolIndex. |
| 104 | |
| 105 | @param PoolIndex Index which indicate the Pool size. |
| 106 | @param FreePoolHdr The returned Free pool. |
| 107 | |
| 108 | @retval EFI_OUT_OF_RESOURCES Allocation failed. |
| 109 | @retval EFI_SUCCESS Pool successfully allocated. |
| 110 | |
| 111 | **/ |
| 112 | EFI_STATUS |
| 113 | InternalAllocPoolByIndex ( |
| 114 | IN UINTN PoolIndex, |
| 115 | OUT FREE_POOL_HEADER **FreePoolHdr |
| 116 | ) |
| 117 | { |
| 118 | EFI_STATUS Status; |
| 119 | FREE_POOL_HEADER *Hdr; |
| 120 | EFI_PHYSICAL_ADDRESS Address; |
| 121 | |
| 122 | ASSERT (PoolIndex <= MAX_POOL_INDEX); |
| 123 | Status = EFI_SUCCESS; |
| 124 | Hdr = NULL; |
| 125 | if (PoolIndex == MAX_POOL_INDEX) { |
| 126 | Status = MmInternalAllocatePages ( |
| 127 | AllocateAnyPages, |
| 128 | EfiRuntimeServicesData, |
| 129 | EFI_SIZE_TO_PAGES (MAX_POOL_SIZE << 1), |
| 130 | &Address |
| 131 | ); |
| 132 | if (EFI_ERROR (Status)) { |
| 133 | return EFI_OUT_OF_RESOURCES; |
| 134 | } |
| 135 | |
| 136 | Hdr = (FREE_POOL_HEADER *)(UINTN)Address; |
| 137 | } else if (!IsListEmpty (&mMmPoolLists[PoolIndex])) { |
| 138 | Hdr = BASE_CR (GetFirstNode (&mMmPoolLists[PoolIndex]), FREE_POOL_HEADER, Link); |
| 139 | RemoveEntryList (&Hdr->Link); |
| 140 | } else { |
| 141 | Status = InternalAllocPoolByIndex (PoolIndex + 1, &Hdr); |
| 142 | if (!EFI_ERROR (Status)) { |
| 143 | Hdr->Header.Size >>= 1; |
| 144 | Hdr->Header.Available = TRUE; |
| 145 | InsertHeadList (&mMmPoolLists[PoolIndex], &Hdr->Link); |
| 146 | Hdr = (FREE_POOL_HEADER *)((UINT8 *)Hdr + Hdr->Header.Size); |
| 147 | } |
| 148 | } |
| 149 | |
| 150 | if (!EFI_ERROR (Status)) { |
| 151 | Hdr->Header.Size = MIN_POOL_SIZE << PoolIndex; |
| 152 | Hdr->Header.Available = FALSE; |
| 153 | } |
| 154 | |
| 155 | *FreePoolHdr = Hdr; |
| 156 | return Status; |
| 157 | } |
| 158 | |
| 159 | /** |
| 160 | Internal Function. Free a pool by specified PoolIndex. |
| 161 | |
| 162 | @param FreePoolHdr The pool to free. |
| 163 | |
| 164 | @retval EFI_SUCCESS Pool successfully freed. |
| 165 | |
| 166 | **/ |
| 167 | EFI_STATUS |
| 168 | InternalFreePoolByIndex ( |
| 169 | IN FREE_POOL_HEADER *FreePoolHdr |
| 170 | ) |
| 171 | { |
| 172 | UINTN PoolIndex; |
| 173 | |
| 174 | ASSERT ((FreePoolHdr->Header.Size & (FreePoolHdr->Header.Size - 1)) == 0); |
| 175 | ASSERT (((UINTN)FreePoolHdr & (FreePoolHdr->Header.Size - 1)) == 0); |
| 176 | ASSERT (FreePoolHdr->Header.Size >= MIN_POOL_SIZE); |
| 177 | |
| 178 | PoolIndex = (UINTN)(HighBitSet32 ((UINT32)FreePoolHdr->Header.Size) - MIN_POOL_SHIFT); |
| 179 | FreePoolHdr->Header.Available = TRUE; |
| 180 | if (PoolIndex >= MAX_POOL_INDEX) { |
| 181 | ASSERT (PoolIndex < MAX_POOL_INDEX); |
| 182 | return EFI_OUT_OF_RESOURCES; |
| 183 | } |
| 184 | |
| 185 | InsertHeadList (&mMmPoolLists[PoolIndex], &FreePoolHdr->Link); |
| 186 | return EFI_SUCCESS; |
| 187 | } |
| 188 | |
| 189 | /** |
| 190 | Allocate pool of a particular type. |
| 191 | |
| 192 | @param PoolType Type of pool to allocate. |
| 193 | @param Size The amount of pool to allocate. |
| 194 | @param Buffer The address to return a pointer to the allocated |
| 195 | pool. |
| 196 | |
| 197 | @retval EFI_INVALID_PARAMETER PoolType not valid. |
| 198 | @retval EFI_OUT_OF_RESOURCES Size exceeds max pool size or allocation failed. |
| 199 | @retval EFI_SUCCESS Pool successfully allocated. |
| 200 | |
| 201 | **/ |
| 202 | EFI_STATUS |
| 203 | EFIAPI |
| 204 | MmInternalAllocatePool ( |
| 205 | IN EFI_MEMORY_TYPE PoolType, |
| 206 | IN UINTN Size, |
| 207 | OUT VOID **Buffer |
| 208 | ) |
| 209 | { |
| 210 | POOL_HEADER *PoolHdr; |
| 211 | FREE_POOL_HEADER *FreePoolHdr; |
| 212 | EFI_STATUS Status; |
| 213 | EFI_PHYSICAL_ADDRESS Address; |
| 214 | UINTN PoolIndex; |
| 215 | |
| 216 | if ((PoolType != EfiRuntimeServicesCode) && |
| 217 | (PoolType != EfiRuntimeServicesData)) |
| 218 | { |
| 219 | return EFI_INVALID_PARAMETER; |
| 220 | } |
| 221 | |
| 222 | Size += sizeof (*PoolHdr); |
| 223 | if (Size > MAX_POOL_SIZE) { |
| 224 | Size = EFI_SIZE_TO_PAGES (Size); |
| 225 | Status = MmInternalAllocatePages (AllocateAnyPages, PoolType, Size, &Address); |
| 226 | if (EFI_ERROR (Status)) { |
| 227 | return Status; |
| 228 | } |
| 229 | |
| 230 | PoolHdr = (POOL_HEADER *)(UINTN)Address; |
| 231 | PoolHdr->Size = EFI_PAGES_TO_SIZE (Size); |
| 232 | PoolHdr->Available = FALSE; |
| 233 | *Buffer = PoolHdr + 1; |
| 234 | return Status; |
| 235 | } |
| 236 | |
| 237 | Size = (Size + MIN_POOL_SIZE - 1) >> MIN_POOL_SHIFT; |
| 238 | PoolIndex = (UINTN)HighBitSet32 ((UINT32)Size); |
| 239 | if ((Size & (Size - 1)) != 0) { |
| 240 | PoolIndex++; |
| 241 | } |
| 242 | |
| 243 | Status = InternalAllocPoolByIndex (PoolIndex, &FreePoolHdr); |
| 244 | if (!EFI_ERROR (Status)) { |
| 245 | *Buffer = &FreePoolHdr->Header + 1; |
| 246 | } |
| 247 | |
| 248 | return Status; |
| 249 | } |
| 250 | |
| 251 | /** |
| 252 | Allocate pool of a particular type. |
| 253 | |
| 254 | @param PoolType Type of pool to allocate. |
| 255 | @param Size The amount of pool to allocate. |
| 256 | @param Buffer The address to return a pointer to the allocated |
| 257 | pool. |
| 258 | |
| 259 | @retval EFI_INVALID_PARAMETER PoolType not valid. |
| 260 | @retval EFI_OUT_OF_RESOURCES Size exceeds max pool size or allocation failed. |
| 261 | @retval EFI_SUCCESS Pool successfully allocated. |
| 262 | |
| 263 | **/ |
| 264 | EFI_STATUS |
| 265 | EFIAPI |
| 266 | MmAllocatePool ( |
| 267 | IN EFI_MEMORY_TYPE PoolType, |
| 268 | IN UINTN Size, |
| 269 | OUT VOID **Buffer |
| 270 | ) |
| 271 | { |
| 272 | EFI_STATUS Status; |
| 273 | |
| 274 | Status = MmInternalAllocatePool (PoolType, Size, Buffer); |
| 275 | return Status; |
| 276 | } |
| 277 | |
| 278 | /** |
| 279 | Frees pool. |
| 280 | |
| 281 | @param Buffer The allocated pool entry to free. |
| 282 | |
| 283 | @retval EFI_INVALID_PARAMETER Buffer is not a valid value. |
| 284 | @retval EFI_SUCCESS Pool successfully freed. |
| 285 | |
| 286 | **/ |
| 287 | EFI_STATUS |
| 288 | EFIAPI |
| 289 | MmInternalFreePool ( |
| 290 | IN VOID *Buffer |
| 291 | ) |
| 292 | { |
| 293 | FREE_POOL_HEADER *FreePoolHdr; |
| 294 | |
| 295 | if (Buffer == NULL) { |
| 296 | return EFI_INVALID_PARAMETER; |
| 297 | } |
| 298 | |
| 299 | FreePoolHdr = (FREE_POOL_HEADER *)((POOL_HEADER *)Buffer - 1); |
| 300 | ASSERT (!FreePoolHdr->Header.Available); |
| 301 | |
| 302 | if (FreePoolHdr->Header.Size > MAX_POOL_SIZE) { |
| 303 | ASSERT (((UINTN)FreePoolHdr & EFI_PAGE_MASK) == 0); |
| 304 | ASSERT ((FreePoolHdr->Header.Size & EFI_PAGE_MASK) == 0); |
| 305 | return MmInternalFreePages ( |
| 306 | (EFI_PHYSICAL_ADDRESS)(UINTN)FreePoolHdr, |
| 307 | EFI_SIZE_TO_PAGES (FreePoolHdr->Header.Size) |
| 308 | ); |
| 309 | } |
| 310 | |
| 311 | return InternalFreePoolByIndex (FreePoolHdr); |
| 312 | } |
| 313 | |
| 314 | /** |
| 315 | Frees pool. |
| 316 | |
| 317 | @param Buffer The allocated pool entry to free. |
| 318 | |
| 319 | @retval EFI_INVALID_PARAMETER Buffer is not a valid value. |
| 320 | @retval EFI_SUCCESS Pool successfully freed. |
| 321 | |
| 322 | **/ |
| 323 | EFI_STATUS |
| 324 | EFIAPI |
| 325 | MmFreePool ( |
| 326 | IN VOID *Buffer |
| 327 | ) |
| 328 | { |
| 329 | EFI_STATUS Status; |
| 330 | |
| 331 | Status = MmInternalFreePool (Buffer); |
| 332 | return Status; |
| 333 | } |
| 334 | |