zbao | 7d94cf9 | 2012-07-02 14:19:14 +0800 | [diff] [blame] | 1 | /* $NoKeywords:$ */ |
| 2 | /** |
| 3 | * @file |
| 4 | * |
| 5 | * AMD Heap Manager and Heap Allocation APIs, and related functions. |
| 6 | * |
| 7 | * Contains code that initialize, maintain, and allocate the heap space. |
| 8 | * |
| 9 | * @xrefitem bom "File Content Label" "Release Content" |
| 10 | * @e project: AGESA |
| 11 | * @e sub-project: CPU |
| 12 | * @e \$Revision: 63425 $ @e \$Date: 2011-12-22 11:24:10 -0600 (Thu, 22 Dec 2011) $ |
| 13 | * |
| 14 | */ |
| 15 | /******************************************************************************* |
| 16 | * |
Siyuan Wang | 641f00c | 2013-06-08 11:50:55 +0800 | [diff] [blame] | 17 | * Copyright (c) 2008 - 2012, Advanced Micro Devices, Inc. |
| 18 | * All rights reserved. |
zbao | 7d94cf9 | 2012-07-02 14:19:14 +0800 | [diff] [blame] | 19 | * |
Siyuan Wang | 641f00c | 2013-06-08 11:50:55 +0800 | [diff] [blame] | 20 | * Redistribution and use in source and binary forms, with or without |
| 21 | * modification, are permitted provided that the following conditions are met: |
| 22 | * * Redistributions of source code must retain the above copyright |
| 23 | * notice, this list of conditions and the following disclaimer. |
| 24 | * * Redistributions in binary form must reproduce the above copyright |
| 25 | * notice, this list of conditions and the following disclaimer in the |
| 26 | * documentation and/or other materials provided with the distribution. |
| 27 | * * Neither the name of Advanced Micro Devices, Inc. nor the names of |
| 28 | * its contributors may be used to endorse or promote products derived |
| 29 | * from this software without specific prior written permission. |
zbao | 7d94cf9 | 2012-07-02 14:19:14 +0800 | [diff] [blame] | 30 | * |
Siyuan Wang | 641f00c | 2013-06-08 11:50:55 +0800 | [diff] [blame] | 31 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND |
| 32 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED |
| 33 | * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE |
| 34 | * DISCLAIMED. IN NO EVENT SHALL ADVANCED MICRO DEVICES, INC. BE LIABLE FOR ANY |
| 35 | * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES |
| 36 | * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; |
| 37 | * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND |
| 38 | * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
| 39 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS |
| 40 | * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
zbao | 7d94cf9 | 2012-07-02 14:19:14 +0800 | [diff] [blame] | 41 | ****************************************************************************** |
| 42 | */ |
| 43 | |
| 44 | /*---------------------------------------------------------------------------------------- |
| 45 | * M O D U L E S U S E D |
| 46 | *---------------------------------------------------------------------------------------- |
| 47 | */ |
| 48 | |
| 49 | #include "AGESA.h" |
| 50 | #include "amdlib.h" |
| 51 | #include "Ids.h" |
| 52 | #include "cpuRegisters.h" |
| 53 | #include "cpuServices.h" |
| 54 | #include "GeneralServices.h" |
| 55 | #include "heapManager.h" |
| 56 | #include "cpuCacheInit.h" |
| 57 | #include "cpuFamilyTranslation.h" |
| 58 | #include "Filecode.h" |
| 59 | CODE_GROUP (G1_PEICC) |
| 60 | RDATA_GROUP (G1_PEICC) |
| 61 | |
| 62 | #define FILECODE PROC_CPU_HEAPMANAGER_FILECODE |
| 63 | /*---------------------------------------------------------------------------------------- |
| 64 | * D E F I N I T I O N S A N D M A C R O S |
| 65 | *---------------------------------------------------------------------------------------- |
| 66 | */ |
| 67 | |
| 68 | |
| 69 | /*---------------------------------------------------------------------------------------- |
| 70 | * T Y P E D E F S A N D S T R U C T U R E S |
| 71 | *---------------------------------------------------------------------------------------- |
| 72 | */ |
| 73 | |
| 74 | |
| 75 | /*---------------------------------------------------------------------------------------- |
| 76 | * P R O T O T Y P E S O F L O C A L F U N C T I O N S |
| 77 | *---------------------------------------------------------------------------------------- |
| 78 | */ |
| 79 | UINT64 |
| 80 | STATIC |
| 81 | HeapGetCurrentBase ( |
| 82 | IN AMD_CONFIG_PARAMS *StdHeader |
| 83 | ); |
| 84 | |
| 85 | VOID |
| 86 | STATIC |
| 87 | DeleteFreeSpaceNode ( |
| 88 | IN AMD_CONFIG_PARAMS *StdHeader, |
| 89 | IN UINT32 OffsetOfDeletedNode |
| 90 | ); |
| 91 | |
| 92 | VOID |
| 93 | STATIC |
| 94 | InsertFreeSpaceNode ( |
| 95 | IN AMD_CONFIG_PARAMS *StdHeader, |
| 96 | IN UINT32 OffsetOfInsertNode |
| 97 | ); |
| 98 | |
| 99 | /*---------------------------------------------------------------------------------------- |
| 100 | * P U B L I C F U N C T I O N S |
| 101 | *---------------------------------------------------------------------------------------- |
| 102 | */ |
| 103 | |
| 104 | /*---------------------------------------------------------------------------------------- |
| 105 | * E X P O R T E D F U N C T I O N S |
| 106 | *---------------------------------------------------------------------------------------- |
| 107 | */ |
| 108 | extern BUILD_OPT_CFG UserOptions; |
| 109 | |
| 110 | /*---------------------------------------------------------------------------------------*/ |
| 111 | /** |
| 112 | * This function initializes the heap for each CPU core. |
| 113 | * |
| 114 | * Check for already initialized. If not, determine offset of local heap in CAS and |
| 115 | * setup initial heap markers and bookkeeping status. Initialize a couple heap items |
| 116 | * all cores need, for convenience. Currently these are caching the AP mailbox info and |
| 117 | * an initial event log. |
| 118 | * |
| 119 | * @param[in] StdHeader Handle of Header for calling lib functions and services. |
| 120 | * |
| 121 | * @retval AGESA_SUCCESS This core's heap is initialized |
| 122 | * @retval AGESA_FATAL This core's heap cannot be initialized due to any reasons below: |
| 123 | * - current processor family cannot be identified. |
| 124 | * |
| 125 | */ |
| 126 | AGESA_STATUS |
| 127 | HeapManagerInit ( |
| 128 | IN AMD_CONFIG_PARAMS *StdHeader |
| 129 | ) |
| 130 | { |
| 131 | // First Time Initialization |
| 132 | // Note: First 16 bytes of buffer is reserved for Heap Manager use |
| 133 | UINT16 HeapAlreadyInitSizeDword; |
| 134 | UINT32 HeapAlreadyRead; |
| 135 | UINT8 L2LineSize; |
| 136 | UINT8 *HeapBufferPtr; |
| 137 | UINT8 *HeapInitPtr; |
| 138 | UINT32 *HeapDataPtr; |
| 139 | UINT64 MsrData; |
| 140 | UINT64 MsrMask; |
| 141 | UINT8 Ignored; |
| 142 | CPUID_DATA CpuId; |
| 143 | BUFFER_NODE *FreeSpaceNode; |
| 144 | CACHE_INFO *CacheInfoPtr; |
| 145 | AGESA_STATUS IgnoredSts; |
| 146 | CPU_SPECIFIC_SERVICES *FamilySpecificServices; |
| 147 | CPU_LOGICAL_ID CpuFamilyRevision; |
| 148 | |
| 149 | // Check whether this is a known processor family. |
| 150 | GetLogicalIdOfCurrentCore (&CpuFamilyRevision, StdHeader); |
| 151 | if ((CpuFamilyRevision.Family == 0) && (CpuFamilyRevision.Revision == 0)) { |
| 152 | IDS_ERROR_TRAP; |
| 153 | return AGESA_FATAL; |
| 154 | } |
| 155 | |
| 156 | GetCpuServicesOfCurrentCore ((CONST CPU_SPECIFIC_SERVICES **)&FamilySpecificServices, StdHeader); |
| 157 | FamilySpecificServices->GetCacheInfo (FamilySpecificServices, (CONST VOID **) &CacheInfoPtr, &Ignored, StdHeader); |
Stefan Reinauer | d91ddc8 | 2015-07-30 11:17:40 -0700 | [diff] [blame] | 158 | HeapBufferPtr = (UINT8 *)(UINTN) StdHeader->HeapBasePtr; |
zbao | 7d94cf9 | 2012-07-02 14:19:14 +0800 | [diff] [blame] | 159 | |
| 160 | // Check whether the heap manager is already initialized |
| 161 | LibAmdMsrRead (AMD_MTRR_VARIABLE_HEAP_MASK, &MsrData, StdHeader); |
| 162 | if (MsrData == (CacheInfoPtr->VariableMtrrMask & AMD_HEAP_MTRR_MASK)) { |
| 163 | LibAmdMsrRead (AMD_MTRR_VARIABLE_HEAP_BASE, &MsrData, StdHeader); |
| 164 | if ((MsrData & CacheInfoPtr->HeapBaseMask) == ((UINT64) (UINTN) HeapBufferPtr & CacheInfoPtr->HeapBaseMask)) { |
| 165 | if (((HEAP_MANAGER *) HeapBufferPtr)->Signature == HEAP_SIGNATURE_VALID) { |
| 166 | // This is not a bug, there are multiple premem basic entry points, |
| 167 | // and each will call heap init to make sure create struct will succeed. |
| 168 | // If that is later deemed a problem, there needs to be a reasonable test |
| 169 | // for the calling code to make to determine if it needs to init heap or not. |
| 170 | // In the mean time, add this to the event log |
| 171 | PutEventLog (AGESA_SUCCESS, |
| 172 | CPU_ERROR_HEAP_IS_ALREADY_INITIALIZED, |
| 173 | 0, 0, 0, 0, StdHeader); |
| 174 | return AGESA_SUCCESS; |
| 175 | } |
| 176 | } |
| 177 | } |
| 178 | |
| 179 | // Set variable MTRR base and mask |
| 180 | MsrData = ((UINT64) (UINTN) HeapBufferPtr & CacheInfoPtr->HeapBaseMask); |
| 181 | MsrMask = CacheInfoPtr->VariableMtrrHeapMask & AMD_HEAP_MTRR_MASK; |
| 182 | |
| 183 | MsrData |= 0x06; |
| 184 | LibAmdMsrWrite (AMD_MTRR_VARIABLE_HEAP_BASE, &MsrData, StdHeader); |
| 185 | LibAmdMsrWrite (AMD_MTRR_VARIABLE_HEAP_MASK, &MsrMask, StdHeader); |
| 186 | |
| 187 | // Set top of memory to a temp value |
| 188 | MsrData = (UINT64) (AMD_TEMP_TOM); |
| 189 | LibAmdMsrWrite (TOP_MEM, &MsrData, StdHeader); |
| 190 | |
Paul Menzel | 2e0d944 | 2014-01-25 15:59:31 +0100 | [diff] [blame] | 191 | // Enable variable MTRRs |
zbao | 7d94cf9 | 2012-07-02 14:19:14 +0800 | [diff] [blame] | 192 | LibAmdMsrRead (SYS_CFG, &MsrData, StdHeader); |
| 193 | MsrData |= AMD_VAR_MTRR_ENABLE_BIT; |
| 194 | LibAmdMsrWrite (SYS_CFG, &MsrData, StdHeader); |
| 195 | |
| 196 | // Initialize Heap Space |
| 197 | // BIOS may store to a line only after it has been allocated by a load |
| 198 | LibAmdCpuidRead (AMD_CPUID_L2L3Cache_L2TLB, &CpuId, StdHeader); |
| 199 | L2LineSize = (UINT8) (CpuId.ECX_Reg); |
| 200 | HeapInitPtr = HeapBufferPtr ; |
| 201 | for (HeapAlreadyRead = 0; HeapAlreadyRead < AMD_HEAP_SIZE_PER_CORE; |
| 202 | (HeapAlreadyRead = HeapAlreadyRead + L2LineSize)) { |
| 203 | Ignored = *HeapInitPtr; |
| 204 | HeapInitPtr += L2LineSize; |
| 205 | } |
| 206 | |
| 207 | HeapDataPtr = (UINT32 *) HeapBufferPtr; |
| 208 | for (HeapAlreadyInitSizeDword = 0; HeapAlreadyInitSizeDword < AMD_HEAP_SIZE_DWORD_PER_CORE; HeapAlreadyInitSizeDword++) { |
| 209 | *HeapDataPtr = 0; |
| 210 | HeapDataPtr++; |
| 211 | } |
| 212 | |
| 213 | // Note: We are reserving the first 16 bytes for Heap Manager use |
| 214 | // UsedSize indicates the size of heap spaced is used for HEAP_MANAGER, BUFFER_NODE, |
| 215 | // Pad for 16-byte alignment, buffer data, and IDS SENTINEL. |
| 216 | // FirstActiveBufferOffset is initalized as invalid heap offset, AMD_HEAP_INVALID_HEAP_OFFSET. |
| 217 | // FirstFreeSpaceOffset is initalized as the byte right after HEAP_MANAGER header. |
| 218 | // Then we set Signature of HEAP_MANAGER header as valid, HEAP_SIGNATURE_VALID. |
| 219 | ((HEAP_MANAGER*) HeapBufferPtr)->UsedSize = sizeof (HEAP_MANAGER); |
| 220 | ((HEAP_MANAGER*) HeapBufferPtr)->FirstActiveBufferOffset = AMD_HEAP_INVALID_HEAP_OFFSET; |
| 221 | ((HEAP_MANAGER*) HeapBufferPtr)->FirstFreeSpaceOffset = sizeof (HEAP_MANAGER); |
| 222 | ((HEAP_MANAGER*) HeapBufferPtr)->Signature = HEAP_SIGNATURE_VALID; |
| 223 | // Create free space link |
| 224 | FreeSpaceNode = (BUFFER_NODE *) (HeapBufferPtr + sizeof (HEAP_MANAGER)); |
| 225 | FreeSpaceNode->BufferSize = AMD_HEAP_SIZE_PER_CORE - sizeof (HEAP_MANAGER) - sizeof (BUFFER_NODE); |
| 226 | FreeSpaceNode->OffsetOfNextNode = AMD_HEAP_INVALID_HEAP_OFFSET; |
| 227 | |
| 228 | StdHeader->HeapStatus = HEAP_LOCAL_CACHE; |
| 229 | if (!IsBsp (StdHeader, &IgnoredSts)) { |
| 230 | // The BSP's hardware mailbox has not been initialized, so only APs |
| 231 | // can do this at this point. |
| 232 | CacheApMailbox (StdHeader); |
| 233 | } |
| 234 | EventLogInitialization (StdHeader); |
| 235 | return AGESA_SUCCESS; |
| 236 | } |
| 237 | |
| 238 | |
| 239 | /*---------------------------------------------------------------------------------------*/ |
| 240 | /** |
| 241 | * Allocates space for a new buffer in the heap |
| 242 | * |
| 243 | * This function will allocate new buffer either by using internal 'AGESA' heapmanager |
| 244 | * or by using externa (IBV) heapmanager. This function will also determine if whether or not |
| 245 | * there is enough space for the new structure. If so, it will zero out the buffer, |
| 246 | * and return a pointer to the region. |
| 247 | * |
| 248 | * @param[in,out] AllocateHeapParams structure pointer containing the size of the |
| 249 | * desired new region, its handle, and the |
| 250 | * return pointer. |
| 251 | * @param[in,out] StdHeader Config handle for library and services. |
| 252 | * |
| 253 | * @retval AGESA_SUCCESS No error |
| 254 | * @retval AGESA_BOUNDS_CHK Handle already exists, or not enough |
| 255 | * free space |
| 256 | * @retval AGESA_UNSUPPORTED Do not support this kind of heap allocation |
| 257 | * @retval AGESA_ERROR Heap is invaild |
| 258 | * |
| 259 | */ |
| 260 | AGESA_STATUS |
| 261 | HeapAllocateBuffer ( |
| 262 | IN OUT ALLOCATE_HEAP_PARAMS *AllocateHeapParams, |
| 263 | IN OUT AMD_CONFIG_PARAMS *StdHeader |
| 264 | ) |
| 265 | { |
| 266 | UINT8 *BaseAddress; |
| 267 | UINT8 AlignTo16Byte; |
| 268 | UINT8 CalloutFcnData; |
| 269 | UINT32 RemainSize; |
| 270 | UINT32 OffsetOfSplitNode; |
| 271 | UINT32 OffsetOfNode; |
| 272 | HEAP_MANAGER *HeapManager; |
| 273 | BUFFER_NODE *FreeSpaceNode; |
| 274 | BUFFER_NODE *SplitFreeSpaceNode; |
| 275 | BUFFER_NODE *CurrentBufferNode; |
| 276 | BUFFER_NODE *NewBufferNode; |
| 277 | AGESA_BUFFER_PARAMS AgesaBuffer; |
| 278 | |
| 279 | ASSERT (StdHeader != NULL); |
| 280 | if (AllocateHeapParams->Persist == HEAP_RUNTIME_SYSTEM_MEM) { |
| 281 | ASSERT (StdHeader->HeapStatus == HEAP_SYSTEM_MEM); |
| 282 | if (StdHeader->HeapStatus != HEAP_SYSTEM_MEM) { |
| 283 | return AGESA_UNSUPPORTED; |
| 284 | } |
| 285 | } |
| 286 | |
| 287 | // At this stage we will decide to either use external (IBV) heap manger |
| 288 | // or internal (AGESA) heap manager. |
| 289 | |
| 290 | // If (HeapStatus == HEAP_SYSTEM_MEM), then use the call function to call |
| 291 | // external heap manager |
| 292 | if (StdHeader->HeapStatus == HEAP_SYSTEM_MEM) { |
| 293 | AgesaBuffer.StdHeader = *StdHeader; |
| 294 | AgesaBuffer.BufferHandle = AllocateHeapParams->BufferHandle; |
| 295 | AgesaBuffer.BufferLength = AllocateHeapParams->RequestedBufferSize; |
| 296 | |
| 297 | if (AllocateHeapParams->Persist == HEAP_RUNTIME_SYSTEM_MEM) { |
| 298 | CalloutFcnData = HEAP_CALLOUT_RUNTIME; |
| 299 | } else { |
| 300 | CalloutFcnData = HEAP_CALLOUT_BOOTTIME; |
| 301 | } |
| 302 | AGESA_TESTPOINT (TpIfBeforeAllocateHeapBuffer, StdHeader); |
| 303 | if (AgesaAllocateBuffer (CalloutFcnData, &AgesaBuffer) != AGESA_SUCCESS) { |
| 304 | AllocateHeapParams->BufferPtr = NULL; |
| 305 | return AGESA_ERROR; |
| 306 | } |
| 307 | AGESA_TESTPOINT (TpIfAfterAllocateHeapBuffer, StdHeader); |
| 308 | |
| 309 | AllocateHeapParams->BufferPtr = (UINT8 *) (AgesaBuffer.BufferPointer); |
| 310 | return AGESA_SUCCESS; |
| 311 | } |
| 312 | |
| 313 | // If (StdHeader->HeapStatus != HEAP_SYSTEM_MEM), then allocated buffer |
| 314 | // using following AGESA Heap Manager code. |
| 315 | |
| 316 | // Buffer pointer is NULL unless we return a buffer. |
| 317 | AlignTo16Byte = 0; |
| 318 | AllocateHeapParams->BufferPtr = NULL; |
| 319 | AllocateHeapParams->RequestedBufferSize += NUM_OF_SENTINEL * SIZE_OF_SENTINEL; |
| 320 | |
| 321 | // Get base address |
| 322 | BaseAddress = (UINT8 *) (UINTN) StdHeader->HeapBasePtr; |
| 323 | HeapManager = (HEAP_MANAGER *) BaseAddress; |
| 324 | |
| 325 | // Check Heap database is valid |
| 326 | if ((BaseAddress == NULL) || (HeapManager->Signature != HEAP_SIGNATURE_VALID)) { |
| 327 | // The base address in StdHeader is incorrect, get base address by itself |
Stefan Reinauer | d91ddc8 | 2015-07-30 11:17:40 -0700 | [diff] [blame] | 328 | BaseAddress = (UINT8 *)(UINTN) HeapGetBaseAddress (StdHeader); |
zbao | 7d94cf9 | 2012-07-02 14:19:14 +0800 | [diff] [blame] | 329 | HeapManager = (HEAP_MANAGER *) BaseAddress; |
| 330 | if ((BaseAddress == NULL) || (HeapManager->Signature != HEAP_SIGNATURE_VALID)) { |
| 331 | // Heap is not available, ASSERT here |
| 332 | ASSERT (FALSE); |
| 333 | return AGESA_ERROR; |
| 334 | } |
Stefan Reinauer | d91ddc8 | 2015-07-30 11:17:40 -0700 | [diff] [blame] | 335 | StdHeader->HeapBasePtr = (UINTN)BaseAddress; |
zbao | 7d94cf9 | 2012-07-02 14:19:14 +0800 | [diff] [blame] | 336 | } |
| 337 | |
| 338 | // Allocate |
| 339 | CurrentBufferNode = (BUFFER_NODE *) (BaseAddress + sizeof (HEAP_MANAGER)); |
| 340 | // If there already has been a heap with the incoming BufferHandle, we return AGESA_BOUNDS_CHK. |
| 341 | if (HeapManager->FirstActiveBufferOffset != AMD_HEAP_INVALID_HEAP_OFFSET) { |
| 342 | CurrentBufferNode = (BUFFER_NODE *) (BaseAddress + HeapManager->FirstActiveBufferOffset); |
| 343 | while (CurrentBufferNode->OffsetOfNextNode != AMD_HEAP_INVALID_HEAP_OFFSET) { |
| 344 | if (CurrentBufferNode->BufferHandle == AllocateHeapParams->BufferHandle) { |
| 345 | PutEventLog (AGESA_BOUNDS_CHK, |
| 346 | CPU_ERROR_HEAP_BUFFER_HANDLE_IS_ALREADY_USED, |
| 347 | AllocateHeapParams->BufferHandle, 0, 0, 0, StdHeader); |
| 348 | return AGESA_BOUNDS_CHK; |
| 349 | } else { |
| 350 | CurrentBufferNode = (BUFFER_NODE *) (BaseAddress + CurrentBufferNode->OffsetOfNextNode); |
| 351 | } |
| 352 | } |
| 353 | if (CurrentBufferNode->BufferHandle == AllocateHeapParams->BufferHandle) { |
| 354 | PutEventLog (AGESA_BOUNDS_CHK, |
| 355 | CPU_ERROR_HEAP_BUFFER_HANDLE_IS_ALREADY_USED, |
| 356 | AllocateHeapParams->BufferHandle, 0, 0, 0, StdHeader); |
| 357 | return AGESA_BOUNDS_CHK; |
| 358 | } |
| 359 | } |
| 360 | |
| 361 | // Find the buffer size that first matches the requested buffer size (i.e. the first free buffer of greater size). |
| 362 | OffsetOfNode = HeapManager->FirstFreeSpaceOffset; |
| 363 | FreeSpaceNode = (BUFFER_NODE *) (BaseAddress + OffsetOfNode); |
| 364 | while (OffsetOfNode != AMD_HEAP_INVALID_HEAP_OFFSET) { |
| 365 | AlignTo16Byte = (UINT8) ((0x10 - (((UINTN) (VOID *) FreeSpaceNode + sizeof (BUFFER_NODE) + SIZE_OF_SENTINEL) & 0xF)) & 0xF); |
| 366 | AllocateHeapParams->RequestedBufferSize = (UINT32) (AllocateHeapParams->RequestedBufferSize + AlignTo16Byte); |
| 367 | if (FreeSpaceNode->BufferSize >= AllocateHeapParams->RequestedBufferSize) { |
| 368 | break; |
| 369 | } |
| 370 | AllocateHeapParams->RequestedBufferSize = (UINT32) (AllocateHeapParams->RequestedBufferSize - AlignTo16Byte); |
| 371 | OffsetOfNode = FreeSpaceNode->OffsetOfNextNode; |
| 372 | FreeSpaceNode = (BUFFER_NODE *) (BaseAddress + OffsetOfNode); |
| 373 | } |
| 374 | if (OffsetOfNode == AMD_HEAP_INVALID_HEAP_OFFSET) { |
| 375 | // We don't find any free space buffer that matches the requested buffer size. |
| 376 | PutEventLog (AGESA_BOUNDS_CHK, |
| 377 | CPU_ERROR_HEAP_IS_FULL, |
| 378 | AllocateHeapParams->BufferHandle, 0, 0, 0, StdHeader); |
| 379 | return AGESA_BOUNDS_CHK; |
| 380 | } else { |
| 381 | // We find one matched free space buffer. |
| 382 | DeleteFreeSpaceNode (StdHeader, OffsetOfNode); |
| 383 | NewBufferNode = FreeSpaceNode; |
| 384 | // Add new buffer node to the buffer chain |
| 385 | if (HeapManager->FirstActiveBufferOffset == AMD_HEAP_INVALID_HEAP_OFFSET) { |
| 386 | HeapManager->FirstActiveBufferOffset = sizeof (HEAP_MANAGER); |
| 387 | } else { |
| 388 | CurrentBufferNode->OffsetOfNextNode = OffsetOfNode; |
| 389 | } |
| 390 | // New buffer size |
| 391 | RemainSize = FreeSpaceNode->BufferSize - AllocateHeapParams->RequestedBufferSize; |
| 392 | if (RemainSize > sizeof (BUFFER_NODE)) { |
| 393 | NewBufferNode->BufferSize = AllocateHeapParams->RequestedBufferSize; |
| 394 | OffsetOfSplitNode = OffsetOfNode + sizeof (BUFFER_NODE) + NewBufferNode->BufferSize; |
| 395 | SplitFreeSpaceNode = (BUFFER_NODE *) (BaseAddress + OffsetOfSplitNode); |
| 396 | SplitFreeSpaceNode->BufferSize = RemainSize - sizeof (BUFFER_NODE); |
| 397 | InsertFreeSpaceNode (StdHeader, OffsetOfSplitNode); |
| 398 | } else { |
| 399 | // Remain size is less than BUFFER_NODE, we use whole size instead of requested size. |
| 400 | NewBufferNode->BufferSize = FreeSpaceNode->BufferSize; |
| 401 | } |
| 402 | } |
| 403 | |
| 404 | // Initialize BUFFER_NODE structure of NewBufferNode |
| 405 | NewBufferNode->BufferHandle = AllocateHeapParams->BufferHandle; |
| 406 | if ((AllocateHeapParams->Persist == HEAP_TEMP_MEM) || (AllocateHeapParams->Persist == HEAP_SYSTEM_MEM)) { |
| 407 | NewBufferNode->Persist = AllocateHeapParams->Persist; |
| 408 | } else { |
| 409 | NewBufferNode->Persist = HEAP_LOCAL_CACHE; |
| 410 | } |
| 411 | NewBufferNode->OffsetOfNextNode = AMD_HEAP_INVALID_HEAP_OFFSET; |
| 412 | NewBufferNode->PadSize = AlignTo16Byte; |
| 413 | |
| 414 | // Clear to 0x00 |
| 415 | LibAmdMemFill ((VOID *) ((UINT8 *) NewBufferNode + sizeof (BUFFER_NODE)), 0x00, NewBufferNode->BufferSize, StdHeader); |
| 416 | |
| 417 | // Debug feature |
| 418 | SET_SENTINEL_BEFORE (NewBufferNode, AlignTo16Byte); |
| 419 | SET_SENTINEL_AFTER (NewBufferNode); |
| 420 | |
| 421 | // Update global variables |
| 422 | HeapManager->UsedSize += NewBufferNode->BufferSize + sizeof (BUFFER_NODE); |
| 423 | |
| 424 | // Now fill in the incoming structure |
| 425 | AllocateHeapParams->BufferPtr = (UINT8 *) ((UINT8 *) NewBufferNode + sizeof (BUFFER_NODE) + SIZE_OF_SENTINEL + AlignTo16Byte); |
| 426 | AllocateHeapParams->RequestedBufferSize -= (NUM_OF_SENTINEL * SIZE_OF_SENTINEL + AlignTo16Byte); |
| 427 | |
| 428 | return AGESA_SUCCESS; |
| 429 | } |
| 430 | |
| 431 | |
| 432 | /*---------------------------------------------------------------------------------------*/ |
| 433 | /** |
| 434 | * Deallocates a previously allocated buffer in the heap |
| 435 | * |
| 436 | * This function will deallocate buffer either by using internal 'AGESA' heapmanager |
| 437 | * or by using externa (IBV) heapmanager. |
| 438 | * |
| 439 | * @param[in] BufferHandle Handle of the buffer to free. |
| 440 | * @param[in] StdHeader Config handle for library and services. |
| 441 | * |
| 442 | * @retval AGESA_SUCCESS No error |
| 443 | * @retval AGESA_BOUNDS_CHK Handle does not exist on the heap |
| 444 | * |
| 445 | */ |
| 446 | AGESA_STATUS |
| 447 | HeapDeallocateBuffer ( |
| 448 | IN UINT32 BufferHandle, |
| 449 | IN AMD_CONFIG_PARAMS *StdHeader |
| 450 | ) |
| 451 | { |
| 452 | UINT8 *BaseAddress; |
| 453 | UINT32 NodeSize; |
| 454 | UINT32 OffsetOfFreeSpaceNode; |
| 455 | UINT32 OffsetOfPreviousNode; |
| 456 | UINT32 OffsetOfCurrentNode; |
| 457 | BOOLEAN HeapLocateFlag; |
| 458 | HEAP_MANAGER *HeapManager; |
| 459 | BUFFER_NODE *CurrentNode; |
| 460 | BUFFER_NODE *PreviousNode; |
| 461 | BUFFER_NODE *FreeSpaceNode; |
| 462 | AGESA_BUFFER_PARAMS AgesaBuffer; |
| 463 | |
| 464 | ASSERT (StdHeader != NULL); |
| 465 | |
| 466 | HeapLocateFlag = TRUE; |
| 467 | BaseAddress = (UINT8 *) (UINTN) StdHeader->HeapBasePtr; |
| 468 | HeapManager = (HEAP_MANAGER *) BaseAddress; |
| 469 | |
| 470 | // Check Heap database is valid |
| 471 | if ((BaseAddress == NULL) || (HeapManager->Signature != HEAP_SIGNATURE_VALID)) { |
| 472 | // The base address in StdHeader is incorrect, get base address by itself |
Stefan Reinauer | d91ddc8 | 2015-07-30 11:17:40 -0700 | [diff] [blame] | 473 | BaseAddress = (UINT8 *)(UINTN) HeapGetBaseAddress (StdHeader); |
zbao | 7d94cf9 | 2012-07-02 14:19:14 +0800 | [diff] [blame] | 474 | HeapManager = (HEAP_MANAGER *) BaseAddress; |
| 475 | if ((BaseAddress == NULL) || (HeapManager->Signature != HEAP_SIGNATURE_VALID)) { |
| 476 | // Heap is not available, ASSERT here |
| 477 | ASSERT (FALSE); |
| 478 | return AGESA_ERROR; |
| 479 | } |
Stefan Reinauer | d91ddc8 | 2015-07-30 11:17:40 -0700 | [diff] [blame] | 480 | StdHeader->HeapBasePtr = (UINTN)BaseAddress; |
zbao | 7d94cf9 | 2012-07-02 14:19:14 +0800 | [diff] [blame] | 481 | } |
| 482 | |
| 483 | OffsetOfPreviousNode = AMD_HEAP_INVALID_HEAP_OFFSET; |
| 484 | OffsetOfCurrentNode = HeapManager->FirstActiveBufferOffset; |
| 485 | CurrentNode = (BUFFER_NODE *) (BaseAddress + OffsetOfCurrentNode); |
| 486 | |
| 487 | // Locate heap |
| 488 | if ((BaseAddress != NULL) && (HeapManager->Signature == HEAP_SIGNATURE_VALID)) { |
| 489 | if (OffsetOfCurrentNode == AMD_HEAP_INVALID_HEAP_OFFSET) { |
| 490 | HeapLocateFlag = FALSE; |
| 491 | } else { |
| 492 | while (CurrentNode->BufferHandle != BufferHandle) { |
| 493 | if (CurrentNode->OffsetOfNextNode == AMD_HEAP_INVALID_HEAP_OFFSET) { |
| 494 | HeapLocateFlag = FALSE; |
| 495 | break; |
| 496 | } else { |
| 497 | OffsetOfPreviousNode = OffsetOfCurrentNode; |
| 498 | OffsetOfCurrentNode = CurrentNode->OffsetOfNextNode; |
| 499 | CurrentNode = (BUFFER_NODE *) (BaseAddress + OffsetOfCurrentNode); |
| 500 | } |
| 501 | } |
| 502 | } |
| 503 | } else { |
| 504 | HeapLocateFlag = FALSE; |
| 505 | } |
| 506 | |
| 507 | if (HeapLocateFlag == TRUE) { |
| 508 | // CurrentNode points to the buffer which wanted to be deallocated. |
| 509 | // Remove deallocated heap from active buffer chain. |
| 510 | if (OffsetOfPreviousNode == AMD_HEAP_INVALID_HEAP_OFFSET) { |
| 511 | HeapManager->FirstActiveBufferOffset = CurrentNode->OffsetOfNextNode; |
| 512 | } else { |
| 513 | PreviousNode = (BUFFER_NODE *) (BaseAddress + OffsetOfPreviousNode); |
| 514 | PreviousNode->OffsetOfNextNode = CurrentNode->OffsetOfNextNode; |
| 515 | } |
| 516 | // Now, CurrentNode become a free space node. |
| 517 | HeapManager->UsedSize -= CurrentNode->BufferSize + sizeof (BUFFER_NODE); |
| 518 | // Loop free space chain to see if any free space node is just before/after CurrentNode, then merge them. |
| 519 | OffsetOfFreeSpaceNode = HeapManager->FirstFreeSpaceOffset; |
| 520 | FreeSpaceNode = (BUFFER_NODE *) (BaseAddress + OffsetOfFreeSpaceNode); |
| 521 | while (OffsetOfFreeSpaceNode != AMD_HEAP_INVALID_HEAP_OFFSET) { |
| 522 | if ((OffsetOfFreeSpaceNode + sizeof (BUFFER_NODE) + FreeSpaceNode->BufferSize) == OffsetOfCurrentNode) { |
| 523 | DeleteFreeSpaceNode (StdHeader, OffsetOfFreeSpaceNode); |
| 524 | NodeSize = FreeSpaceNode->BufferSize + CurrentNode->BufferSize + sizeof (BUFFER_NODE); |
| 525 | OffsetOfCurrentNode = OffsetOfFreeSpaceNode; |
| 526 | CurrentNode = FreeSpaceNode; |
| 527 | CurrentNode->BufferSize = NodeSize; |
| 528 | } else if (OffsetOfFreeSpaceNode == (OffsetOfCurrentNode + sizeof (BUFFER_NODE) + CurrentNode->BufferSize)) { |
| 529 | DeleteFreeSpaceNode (StdHeader, OffsetOfFreeSpaceNode); |
| 530 | NodeSize = FreeSpaceNode->BufferSize + CurrentNode->BufferSize + sizeof (BUFFER_NODE); |
| 531 | CurrentNode->BufferSize = NodeSize; |
| 532 | } |
| 533 | OffsetOfFreeSpaceNode = FreeSpaceNode->OffsetOfNextNode; |
| 534 | FreeSpaceNode = (BUFFER_NODE *) (BaseAddress + OffsetOfFreeSpaceNode); |
| 535 | } |
| 536 | InsertFreeSpaceNode (StdHeader, OffsetOfCurrentNode); |
| 537 | return AGESA_SUCCESS; |
| 538 | } else { |
| 539 | // If HeapStatus == HEAP_SYSTEM_MEM, try callout function |
| 540 | if (StdHeader->HeapStatus == HEAP_SYSTEM_MEM) { |
| 541 | AgesaBuffer.StdHeader = *StdHeader; |
| 542 | AgesaBuffer.BufferHandle = BufferHandle; |
| 543 | |
| 544 | AGESA_TESTPOINT (TpIfBeforeDeallocateHeapBuffer, StdHeader); |
| 545 | if (AgesaDeallocateBuffer (0, &AgesaBuffer) != AGESA_SUCCESS) { |
| 546 | return AGESA_ERROR; |
| 547 | } |
| 548 | AGESA_TESTPOINT (TpIfAfterDeallocateHeapBuffer, StdHeader); |
| 549 | |
| 550 | return AGESA_SUCCESS; |
| 551 | } |
| 552 | // If we are still unable to locate the buffer handle, return AGESA_BOUNDS_CHK |
| 553 | if ((BaseAddress != NULL) && (HeapManager->Signature == HEAP_SIGNATURE_VALID)) { |
| 554 | PutEventLog (AGESA_BOUNDS_CHK, |
| 555 | CPU_ERROR_HEAP_BUFFER_HANDLE_IS_NOT_PRESENT, |
| 556 | BufferHandle, 0, 0, 0, StdHeader); |
| 557 | } else { |
| 558 | ASSERT (FALSE); |
| 559 | } |
| 560 | return AGESA_BOUNDS_CHK; |
| 561 | } |
| 562 | } |
| 563 | |
| 564 | /*---------------------------------------------------------------------------------------*/ |
| 565 | /** |
| 566 | * Locates a previously allocated buffer on the heap. |
| 567 | * |
| 568 | * This function searches the heap for a buffer with the desired handle, and |
| 569 | * returns a pointer to the buffer. |
| 570 | * |
| 571 | * @param[in,out] LocateHeap Structure containing the buffer's handle, |
| 572 | * and the return pointer. |
| 573 | * @param[in] StdHeader Config handle for library and services. |
| 574 | * |
| 575 | * @retval AGESA_SUCCESS No error |
| 576 | * @retval AGESA_BOUNDS_CHK Handle does not exist on the heap |
| 577 | * |
| 578 | */ |
| 579 | AGESA_STATUS |
| 580 | HeapLocateBuffer ( |
| 581 | IN OUT LOCATE_HEAP_PTR *LocateHeap, |
| 582 | IN AMD_CONFIG_PARAMS *StdHeader |
| 583 | ) |
| 584 | { |
| 585 | UINT8 *BaseAddress; |
| 586 | UINT8 AlignTo16Byte; |
| 587 | UINT32 OffsetOfCurrentNode; |
| 588 | BOOLEAN HeapLocateFlag; |
| 589 | HEAP_MANAGER *HeapManager; |
| 590 | BUFFER_NODE *CurrentNode; |
| 591 | AGESA_BUFFER_PARAMS AgesaBuffer; |
| 592 | |
| 593 | ASSERT (StdHeader != NULL); |
| 594 | |
| 595 | HeapLocateFlag = TRUE; |
| 596 | BaseAddress = (UINT8 *) (UINTN) StdHeader->HeapBasePtr; |
| 597 | HeapManager = (HEAP_MANAGER *) BaseAddress; |
| 598 | |
| 599 | // Check Heap database is valid |
| 600 | if ((BaseAddress == NULL) || (HeapManager->Signature != HEAP_SIGNATURE_VALID)) { |
| 601 | // The base address in StdHeader is incorrect, get base address by itself |
Stefan Reinauer | d91ddc8 | 2015-07-30 11:17:40 -0700 | [diff] [blame] | 602 | BaseAddress = (UINT8 *)(UINTN) HeapGetBaseAddress (StdHeader); |
zbao | 7d94cf9 | 2012-07-02 14:19:14 +0800 | [diff] [blame] | 603 | HeapManager = (HEAP_MANAGER *) BaseAddress; |
| 604 | if ((BaseAddress == NULL) || (HeapManager->Signature != HEAP_SIGNATURE_VALID)) { |
| 605 | // Heap is not available, ASSERT here |
| 606 | ASSERT (FALSE); |
| 607 | return AGESA_ERROR; |
| 608 | } |
Stefan Reinauer | d91ddc8 | 2015-07-30 11:17:40 -0700 | [diff] [blame] | 609 | StdHeader->HeapBasePtr = (UINTN)BaseAddress; |
zbao | 7d94cf9 | 2012-07-02 14:19:14 +0800 | [diff] [blame] | 610 | } |
| 611 | OffsetOfCurrentNode = HeapManager->FirstActiveBufferOffset; |
| 612 | CurrentNode = (BUFFER_NODE *) (BaseAddress + OffsetOfCurrentNode); |
| 613 | |
| 614 | // Find buffer using internal heap manager |
| 615 | // Locate the heap using handle = LocateHeap-> BufferHandle |
| 616 | // If HeapStatus != HEAP_SYSTEM_ MEM |
| 617 | if ((BaseAddress != NULL) && (HeapManager->Signature == HEAP_SIGNATURE_VALID)) { |
| 618 | if (OffsetOfCurrentNode == AMD_HEAP_INVALID_HEAP_OFFSET) { |
| 619 | HeapLocateFlag = FALSE; |
| 620 | } else { |
| 621 | while (CurrentNode->BufferHandle != LocateHeap->BufferHandle) { |
| 622 | if (CurrentNode->OffsetOfNextNode == AMD_HEAP_INVALID_HEAP_OFFSET) { |
| 623 | HeapLocateFlag = FALSE; |
| 624 | break; |
| 625 | } else { |
| 626 | OffsetOfCurrentNode = CurrentNode->OffsetOfNextNode; |
| 627 | CurrentNode = (BUFFER_NODE *) (BaseAddress + OffsetOfCurrentNode); |
| 628 | } |
| 629 | } |
| 630 | } |
| 631 | } else { |
| 632 | HeapLocateFlag = FALSE; |
| 633 | } |
| 634 | |
| 635 | if (HeapLocateFlag) { |
| 636 | AlignTo16Byte = CurrentNode->PadSize; |
| 637 | LocateHeap->BufferPtr = (UINT8 *) ((UINT8 *) CurrentNode + sizeof (BUFFER_NODE) + SIZE_OF_SENTINEL + AlignTo16Byte); |
| 638 | LocateHeap->BufferSize = CurrentNode->BufferSize - NUM_OF_SENTINEL * SIZE_OF_SENTINEL - AlignTo16Byte; |
| 639 | return AGESA_SUCCESS; |
| 640 | } else { |
| 641 | // If HeapStatus == HEAP_SYSTEM_MEM, try callout function |
| 642 | if (StdHeader->HeapStatus == HEAP_SYSTEM_MEM) { |
| 643 | AgesaBuffer.StdHeader = *StdHeader; |
| 644 | AgesaBuffer.BufferHandle = LocateHeap->BufferHandle; |
| 645 | |
| 646 | AGESA_TESTPOINT (TpIfBeforeLocateHeapBuffer, StdHeader); |
| 647 | if (AgesaLocateBuffer (0, &AgesaBuffer) != AGESA_SUCCESS) { |
| 648 | LocateHeap->BufferPtr = NULL; |
| 649 | return AGESA_ERROR; |
| 650 | } |
| 651 | LocateHeap->BufferSize = AgesaBuffer.BufferLength; |
| 652 | AGESA_TESTPOINT (TpIfAfterLocateHeapBuffer, StdHeader); |
| 653 | |
| 654 | LocateHeap->BufferPtr = (UINT8 *) (AgesaBuffer.BufferPointer); |
| 655 | return AGESA_SUCCESS; |
| 656 | } |
| 657 | |
| 658 | // If we are still unable to deallocate the buffer handle, return AGESA_BOUNDS_CHK |
| 659 | LocateHeap->BufferPtr = NULL; |
| 660 | LocateHeap->BufferSize = 0; |
| 661 | if ((BaseAddress != NULL) && (HeapManager->Signature == HEAP_SIGNATURE_VALID)) { |
| 662 | PutEventLog (AGESA_BOUNDS_CHK, |
| 663 | CPU_ERROR_HEAP_BUFFER_HANDLE_IS_NOT_PRESENT, |
| 664 | LocateHeap->BufferHandle, 0, 0, 0, StdHeader); |
| 665 | } else { |
| 666 | ASSERT (FALSE); |
| 667 | } |
| 668 | return AGESA_BOUNDS_CHK; |
| 669 | } |
| 670 | } |
| 671 | |
| 672 | /*---------------------------------------------------------------------------------------*/ |
| 673 | /** |
| 674 | * Get the heap base address |
| 675 | * |
| 676 | * This function will try to locate heap from cache, temp memory, main memory. |
| 677 | * The heap signature will be checked for validity on each possible location. |
| 678 | * Firstly, try if heap base is in cache by calling the function HeapGetCurrentBase. |
| 679 | * Secondly, try if heap base is temp memory by UserOptoions.CfgHeapDramAddress. |
| 680 | * Thirdly, try if heap base is in main memory by doing a buffer locate with buffer handle |
| 681 | * AMD_HEAP_IN_MAIN_MEMORY_HANDLE. |
| 682 | * If no valid heap signature is found in each possible location above, a NULL pointer is returned. |
| 683 | * |
| 684 | * @param[in] StdHeader Config handle for library and services. |
| 685 | * |
| 686 | * @return Heap base address of the executing core's heap. |
| 687 | * |
| 688 | */ |
| 689 | UINT64 |
| 690 | HeapGetBaseAddress ( |
| 691 | IN AMD_CONFIG_PARAMS *StdHeader |
| 692 | ) |
| 693 | { |
| 694 | UINT64 BaseAddress; |
| 695 | HEAP_MANAGER *HeapManager; |
| 696 | AGESA_BUFFER_PARAMS AgesaBuffer; |
| 697 | |
| 698 | // Firstly, we try to see if heap is in cache |
| 699 | BaseAddress = HeapGetCurrentBase (StdHeader); |
| 700 | HeapManager = (HEAP_MANAGER *) (UINTN) BaseAddress; |
| 701 | |
| 702 | if ((HeapManager->Signature != HEAP_SIGNATURE_VALID) && |
| 703 | (StdHeader->HeapStatus != HEAP_DO_NOT_EXIST_YET) && |
| 704 | (StdHeader->HeapStatus != HEAP_LOCAL_CACHE)) { |
| 705 | // Secondly, we try to see if heap is in temp memory |
| 706 | BaseAddress = UserOptions.CfgHeapDramAddress; |
| 707 | HeapManager = (HEAP_MANAGER *) (UINTN) BaseAddress; |
| 708 | if (HeapManager->Signature != HEAP_SIGNATURE_VALID) { |
| 709 | // Thirdly, we try to see if heap in main memory |
| 710 | // by locating with external buffer manager (IBV) |
| 711 | AgesaBuffer.StdHeader = *StdHeader; |
| 712 | AgesaBuffer.BufferHandle = AMD_HEAP_IN_MAIN_MEMORY_HANDLE; |
| 713 | if (AgesaLocateBuffer (0, &AgesaBuffer) == AGESA_SUCCESS) { |
| 714 | BaseAddress = (UINT64) (UINTN) AgesaBuffer.BufferPointer; |
| 715 | HeapManager = (HEAP_MANAGER *) (UINTN) BaseAddress; |
| 716 | if (HeapManager->Signature != HEAP_SIGNATURE_VALID) { |
| 717 | // No valid heap signature ever found, return a NULL pointer |
| 718 | BaseAddress = (UINT64) (UINTN) NULL; |
| 719 | } |
| 720 | } else { |
| 721 | // No heap buffer is allocated by external manager (IBV), return a NULL pointer |
| 722 | BaseAddress = (UINT64) (UINTN) NULL; |
| 723 | } |
| 724 | } |
| 725 | } |
| 726 | |
| 727 | return BaseAddress; |
| 728 | } |
| 729 | |
| 730 | /*--------------------------------------------------------------------------------------- |
| 731 | * L O C A L F U N C T I O N S |
| 732 | *--------------------------------------------------------------------------------------- |
| 733 | */ |
| 734 | /* -----------------------------------------------------------------------------*/ |
| 735 | /** |
| 736 | * |
| 737 | * DeleteFreeSpaceNode |
| 738 | * |
| 739 | * Description: |
| 740 | * Delete a free space node from free space chain |
| 741 | * |
| 742 | * Parameters: |
| 743 | * @param[in] StdHeader Config handle for library and services. |
| 744 | * @param[in] OffsetOfDeletedNode Offset of deleted node. |
| 745 | * |
| 746 | * Processing: |
| 747 | * |
| 748 | */ |
| 749 | VOID |
| 750 | STATIC |
| 751 | DeleteFreeSpaceNode ( |
| 752 | IN AMD_CONFIG_PARAMS *StdHeader, |
| 753 | IN UINT32 OffsetOfDeletedNode |
| 754 | ) |
| 755 | { |
| 756 | UINT8 *BaseAddress; |
| 757 | UINT32 OffsetOfPreviousNode; |
| 758 | UINT32 OffsetOfCurrentNode; |
| 759 | HEAP_MANAGER *HeapManager; |
| 760 | BUFFER_NODE *CurrentFreeSpaceNode; |
| 761 | BUFFER_NODE *PreviousFreeSpaceNode; |
| 762 | |
| 763 | |
| 764 | BaseAddress = (UINT8 *) (UINTN) StdHeader->HeapBasePtr; |
| 765 | HeapManager = (HEAP_MANAGER *) BaseAddress; |
| 766 | |
| 767 | OffsetOfPreviousNode = AMD_HEAP_INVALID_HEAP_OFFSET; |
| 768 | OffsetOfCurrentNode = HeapManager->FirstFreeSpaceOffset; |
| 769 | // |
| 770 | // After AmdInitEnv, there is no free space provided for HeapAllocateBuffer. |
| 771 | // Hence if the FirstFreeSpaceOffset is AMD_HEAP_INVALID_HEAP_OFFSET, then |
| 772 | // no need to do more on delete node. |
| 773 | // |
| 774 | if (OffsetOfCurrentNode != AMD_HEAP_INVALID_HEAP_OFFSET) { |
| 775 | CurrentFreeSpaceNode = (BUFFER_NODE *) (BaseAddress + OffsetOfCurrentNode); |
| 776 | while ((OffsetOfCurrentNode != AMD_HEAP_INVALID_HEAP_OFFSET) && (OffsetOfCurrentNode != OffsetOfDeletedNode)) { |
| 777 | OffsetOfPreviousNode = OffsetOfCurrentNode; |
| 778 | OffsetOfCurrentNode = CurrentFreeSpaceNode->OffsetOfNextNode; |
| 779 | CurrentFreeSpaceNode = (BUFFER_NODE *) (BaseAddress + OffsetOfCurrentNode); |
| 780 | } |
| 781 | if (OffsetOfCurrentNode != AMD_HEAP_INVALID_HEAP_OFFSET) { |
| 782 | if (OffsetOfPreviousNode == AMD_HEAP_INVALID_HEAP_OFFSET) { |
| 783 | HeapManager->FirstFreeSpaceOffset = CurrentFreeSpaceNode->OffsetOfNextNode; |
| 784 | } else { |
| 785 | PreviousFreeSpaceNode = (BUFFER_NODE *) (BaseAddress + OffsetOfPreviousNode); |
| 786 | PreviousFreeSpaceNode->OffsetOfNextNode = CurrentFreeSpaceNode->OffsetOfNextNode; |
| 787 | } |
| 788 | } |
| 789 | } |
| 790 | return; |
| 791 | } |
| 792 | |
| 793 | /* -----------------------------------------------------------------------------*/ |
| 794 | /** |
| 795 | * |
| 796 | * InsertFreeSpaceNode |
| 797 | * |
| 798 | * Description: |
| 799 | * Insert a free space node to free space chain, size order |
| 800 | * |
| 801 | * Parameters: |
| 802 | * @param[in] StdHeader Config handle for library and services. |
| 803 | * @param[in] OffsetOfInsertNode Offset of inserted node. |
| 804 | * |
| 805 | * Processing: |
| 806 | * |
| 807 | */ |
| 808 | VOID |
| 809 | STATIC |
| 810 | InsertFreeSpaceNode ( |
| 811 | IN AMD_CONFIG_PARAMS *StdHeader, |
| 812 | IN UINT32 OffsetOfInsertNode |
| 813 | ) |
| 814 | { |
| 815 | UINT8 *BaseAddress; |
| 816 | UINT32 OffsetOfPreviousNode; |
| 817 | UINT32 OffsetOfCurrentNode; |
| 818 | HEAP_MANAGER *HeapManager; |
| 819 | BUFFER_NODE *CurrentFreeSpaceNode; |
| 820 | BUFFER_NODE *PreviousFreeSpaceNode; |
| 821 | BUFFER_NODE *InsertedFreeSpaceNode; |
| 822 | |
| 823 | BaseAddress = (UINT8 *) (UINTN) StdHeader->HeapBasePtr; |
| 824 | HeapManager = (HEAP_MANAGER *) BaseAddress; |
| 825 | |
| 826 | OffsetOfPreviousNode = AMD_HEAP_INVALID_HEAP_OFFSET; |
| 827 | OffsetOfCurrentNode = HeapManager->FirstFreeSpaceOffset; |
| 828 | CurrentFreeSpaceNode = (BUFFER_NODE *) (BaseAddress + OffsetOfCurrentNode); |
| 829 | InsertedFreeSpaceNode = (BUFFER_NODE *) (BaseAddress + OffsetOfInsertNode); |
| 830 | while ((OffsetOfCurrentNode != AMD_HEAP_INVALID_HEAP_OFFSET) && |
| 831 | (CurrentFreeSpaceNode->BufferSize < InsertedFreeSpaceNode->BufferSize)) { |
| 832 | OffsetOfPreviousNode = OffsetOfCurrentNode; |
| 833 | OffsetOfCurrentNode = CurrentFreeSpaceNode->OffsetOfNextNode; |
| 834 | CurrentFreeSpaceNode = (BUFFER_NODE *) (BaseAddress + OffsetOfCurrentNode); |
| 835 | } |
| 836 | InsertedFreeSpaceNode->OffsetOfNextNode = OffsetOfCurrentNode; |
| 837 | if (OffsetOfPreviousNode == AMD_HEAP_INVALID_HEAP_OFFSET) { |
| 838 | HeapManager->FirstFreeSpaceOffset = OffsetOfInsertNode; |
| 839 | } else { |
| 840 | PreviousFreeSpaceNode = (BUFFER_NODE *) (BaseAddress + OffsetOfPreviousNode); |
| 841 | PreviousFreeSpaceNode->OffsetOfNextNode = OffsetOfInsertNode; |
| 842 | } |
| 843 | return; |
| 844 | } |
| 845 | |
| 846 | /*---------------------------------------------------------------------------------------*/ |
| 847 | /** |
| 848 | * Determines the base address of the executing core's heap. |
| 849 | * |
| 850 | * This function uses the executing core's socket/core numbers to determine |
| 851 | * where it's heap should be located. |
| 852 | * |
| 853 | * @param[in] StdHeader Config handle for library and services. |
| 854 | * |
| 855 | * @return A pointer to the executing core's heap. |
| 856 | * |
| 857 | */ |
| 858 | UINT64 |
| 859 | STATIC |
| 860 | HeapGetCurrentBase ( |
| 861 | IN AMD_CONFIG_PARAMS *StdHeader |
| 862 | ) |
| 863 | { |
| 864 | UINT32 SystemCoreNumber; |
| 865 | UINT64 ReturnPtr; |
| 866 | AGESA_STATUS IgnoredStatus; |
| 867 | CPU_SPECIFIC_SERVICES *FamilyServices; |
| 868 | |
| 869 | if (IsBsp (StdHeader, &IgnoredStatus)) { |
| 870 | ReturnPtr = AMD_HEAP_START_ADDRESS; |
| 871 | } else { |
| 872 | GetCpuServicesOfCurrentCore ((CONST CPU_SPECIFIC_SERVICES **)&FamilyServices, StdHeader); |
| 873 | ASSERT (FamilyServices != NULL); |
| 874 | |
| 875 | SystemCoreNumber = FamilyServices->GetApCoreNumber (FamilyServices, StdHeader); |
| 876 | ASSERT (SystemCoreNumber != 0); |
| 877 | ASSERT (SystemCoreNumber < 64); |
| 878 | ReturnPtr = ((SystemCoreNumber * AMD_HEAP_SIZE_PER_CORE) + AMD_HEAP_START_ADDRESS); |
| 879 | } |
| 880 | ASSERT (ReturnPtr <= ((AMD_HEAP_REGION_END_ADDRESS + 1) - AMD_HEAP_SIZE_PER_CORE)); |
| 881 | return ReturnPtr; |
| 882 | } |
| 883 | |
| 884 | |