5 * AMD Heap Manager and Heap Allocation APIs, and related functions.
7 * Contains code that initialize, maintain, and allocate the heap space.
9 * @xrefitem bom "File Content Label" "Release Content"
12 * @e \$Revision: 44324 $ @e \$Date: 2010-12-22 17:16:51 +0800 (Wed, 22 Dec 2010) $
15 /*******************************************************************************
17 * Copyright (c) 2011, Advanced Micro Devices, Inc.
18 * All rights reserved.
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.
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.
41 ******************************************************************************
44 /*----------------------------------------------------------------------------------------
45 * M O D U L E S U S E D
46 *----------------------------------------------------------------------------------------
52 #include "cpuRegisters.h"
53 #include "cpuServices.h"
54 #include "GeneralServices.h"
55 #include "heapManager.h"
56 #include "cpuCacheInit.h"
57 #include "cpuFamilyTranslation.h"
60 RDATA_GROUP (G1_PEICC)
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 *----------------------------------------------------------------------------------------
69 /*----------------------------------------------------------------------------------------
70 * T Y P E D E F S A N D S T R U C T U R E S
71 *----------------------------------------------------------------------------------------
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 *----------------------------------------------------------------------------------------
82 IN AMD_CONFIG_PARAMS *StdHeader
88 IN AMD_CONFIG_PARAMS *StdHeader,
89 IN UINT32 OffsetOfDeletedNode
95 IN AMD_CONFIG_PARAMS *StdHeader,
96 IN UINT32 OffsetOfInsertNode
99 /*----------------------------------------------------------------------------------------
100 * P U B L I C F U N C T I O N S
101 *----------------------------------------------------------------------------------------
104 /*----------------------------------------------------------------------------------------
105 * E X P O R T E D F U N C T I O N S
106 *----------------------------------------------------------------------------------------
108 extern BUILD_OPT_CFG UserOptions;
110 /*---------------------------------------------------------------------------------------*/
112 * This function initializes the heap for each CPU core.
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.
119 * @param[in] StdHeader Handle of Header for calling lib functions and services.
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.
128 IN AMD_CONFIG_PARAMS *StdHeader
131 // First Time Initialization
132 // Note: First 16 bytes of buffer is reserved for Heap Manager use
133 UINT16 HeapAlreadyInitSizeDword;
134 UINT32 HeapAlreadyRead;
136 UINT8 *HeapBufferPtr;
143 BUFFER_NODE *FreeSpaceNode;
144 CACHE_INFO *CacheInfoPtr;
145 AGESA_STATUS IgnoredSts;
146 CPU_SPECIFIC_SERVICES *FamilySpecificServices;
147 CPU_LOGICAL_ID CpuFamilyRevision;
149 // Check whether this is a known processor family.
150 GetLogicalIdOfCurrentCore (&CpuFamilyRevision, StdHeader);
151 if ((CpuFamilyRevision.Family == 0) && (CpuFamilyRevision.Revision == 0)) {
156 GetCpuServicesOfCurrentCore ((const CPU_SPECIFIC_SERVICES **)&FamilySpecificServices, StdHeader);
157 FamilySpecificServices->GetCacheInfo (FamilySpecificServices, (const VOID **)&CacheInfoPtr, &Ignored, StdHeader);
158 HeapBufferPtr = (UINT8 *) StdHeader->HeapBasePtr;
160 // Check whether the heap manager is already initialized
161 LibAmdMsrRead (AMD_MTRR_VARIABLE_HEAP_MASK, &MsrData, StdHeader);
162 if (MsrData == (CacheInfoPtr->VariableMtrrMask & (UINT64) AMD_HEAP_MTRR_MASK)) {
163 LibAmdMsrRead (AMD_MTRR_VARIABLE_HEAP_BASE, &MsrData, StdHeader);
164 if ((MsrData & CacheInfoPtr->HeapBaseMask) == ((UINT64) 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;
179 // Set variable MTRR base and mask
180 MsrData = ((UINT64) HeapBufferPtr & CacheInfoPtr->HeapBaseMask);
181 MsrMask = CacheInfoPtr->VariableMtrrHeapMask & (UINT64) AMD_HEAP_MTRR_MASK;
184 LibAmdMsrWrite (AMD_MTRR_VARIABLE_HEAP_BASE, &MsrData, StdHeader);
185 LibAmdMsrWrite (AMD_MTRR_VARIABLE_HEAP_MASK, &MsrMask, StdHeader);
187 // Set top of memory to a temp value
188 MsrData = (UINT64) (AMD_TEMP_TOM);
189 LibAmdMsrWrite (TOP_MEM, &MsrData, StdHeader);
191 // Enable variable MTTRs
192 LibAmdMsrRead (SYS_CFG, &MsrData, StdHeader);
193 MsrData |= AMD_VAR_MTRR_ENABLE_BIT;
194 LibAmdMsrWrite (SYS_CFG, &MsrData, StdHeader);
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;
207 HeapDataPtr = (UINT32 *) HeapBufferPtr;
208 for (HeapAlreadyInitSizeDword = 0; HeapAlreadyInitSizeDword < AMD_HEAP_SIZE_DWORD_PER_CORE; HeapAlreadyInitSizeDword++) {
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;
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);
234 EventLogInitialization (StdHeader);
235 return AGESA_SUCCESS;
239 /*---------------------------------------------------------------------------------------*/
241 * Allocates space for a new buffer in the heap
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.
248 * @param[in,out] AllocateHeapParams structure pointer containing the size of the
249 * desired new region, its handle, and the
251 * @param[in,out] StdHeader Config handle for library and services.
253 * @retval AGESA_SUCCESS No error
254 * @retval AGESA_BOUNDS_CHK Handle already exists, or not enough
256 * @retval AGESA_ERROR Heap is invaild
261 IN OUT ALLOCATE_HEAP_PARAMS *AllocateHeapParams,
262 IN OUT AMD_CONFIG_PARAMS *StdHeader
268 UINT32 OffsetOfSplitNode;
270 HEAP_MANAGER *HeapManager;
271 BUFFER_NODE *FreeSpaceNode;
272 BUFFER_NODE *SplitFreeSpaceNode;
273 BUFFER_NODE *CurrentBufferNode;
274 BUFFER_NODE *NewBufferNode;
275 AGESA_BUFFER_PARAMS AgesaBuffer;
277 ASSERT (StdHeader != NULL);
279 // At this stage we will decide to either use external (IBV) heap manger
280 // or internal (AGESA) heap manager.
282 // If (HeapStatus == HEAP_SYSTEM_MEM), then use the call function to call
283 // external heap manager
284 if (StdHeader->HeapStatus == HEAP_SYSTEM_MEM) {
285 AgesaBuffer.StdHeader = *StdHeader;
286 AgesaBuffer.BufferHandle = AllocateHeapParams->BufferHandle;
287 AgesaBuffer.BufferLength = AllocateHeapParams->RequestedBufferSize;
289 AGESA_TESTPOINT (TpIfBeforeAllocateHeapBuffer, StdHeader);
290 if (AgesaAllocateBuffer (0, &AgesaBuffer) != AGESA_SUCCESS) {
291 AllocateHeapParams->BufferPtr = NULL;
294 AGESA_TESTPOINT (TpIfAfterAllocateHeapBuffer, StdHeader);
296 AllocateHeapParams->BufferPtr = (UINT8 *) (AgesaBuffer.BufferPointer);
297 return AGESA_SUCCESS;
300 // If (StdHeader->HeapStatus != HEAP_SYSTEM_MEM), then allocated buffer
301 // using following AGESA Heap Manager code.
303 // Buffer pointer is NULL unless we return a buffer.
305 AllocateHeapParams->BufferPtr = NULL;
306 AllocateHeapParams->RequestedBufferSize += NUM_OF_SENTINEL * SIZE_OF_SENTINEL;
309 BaseAddress = (UINT8 *) StdHeader->HeapBasePtr;
310 HeapManager = (HEAP_MANAGER *) BaseAddress;
312 // Check Heap database is valid
313 if ((BaseAddress == NULL) || (HeapManager->Signature != HEAP_SIGNATURE_VALID)) {
314 // The base address in StdHeader is incorrect, get base address by itself
315 BaseAddress = (UINT8 *) HeapGetBaseAddress (StdHeader);
316 HeapManager = (HEAP_MANAGER *) BaseAddress;
317 if ((BaseAddress == NULL) || (HeapManager->Signature != HEAP_SIGNATURE_VALID)) {
318 // Heap is not available, ASSERT here
322 StdHeader->HeapBasePtr = (UINT64) BaseAddress;
326 CurrentBufferNode = (BUFFER_NODE *) (BaseAddress + sizeof (HEAP_MANAGER));
327 // If there already has been a heap with the incoming BufferHandle, we return AGESA_BOUNDS_CHK.
328 if (HeapManager->FirstActiveBufferOffset != AMD_HEAP_INVALID_HEAP_OFFSET) {
329 CurrentBufferNode = (BUFFER_NODE *) (BaseAddress + HeapManager->FirstActiveBufferOffset);
330 while (CurrentBufferNode->OffsetOfNextNode != AMD_HEAP_INVALID_HEAP_OFFSET) {
331 if (CurrentBufferNode->BufferHandle == AllocateHeapParams->BufferHandle) {
332 PutEventLog (AGESA_BOUNDS_CHK,
333 CPU_ERROR_HEAP_BUFFER_HANDLE_IS_ALREADY_USED,
334 AllocateHeapParams->BufferHandle, 0, 0, 0, StdHeader);
335 return AGESA_BOUNDS_CHK;
337 CurrentBufferNode = (BUFFER_NODE *) (BaseAddress + CurrentBufferNode->OffsetOfNextNode);
340 if (CurrentBufferNode->BufferHandle == AllocateHeapParams->BufferHandle) {
341 PutEventLog (AGESA_BOUNDS_CHK,
342 CPU_ERROR_HEAP_BUFFER_HANDLE_IS_ALREADY_USED,
343 AllocateHeapParams->BufferHandle, 0, 0, 0, StdHeader);
344 return AGESA_BOUNDS_CHK;
348 // Find the buffer size that first matches the requested buffer size (i.e. the first free buffer of greater size).
349 OffsetOfNode = HeapManager->FirstFreeSpaceOffset;
350 FreeSpaceNode = (BUFFER_NODE *) (BaseAddress + OffsetOfNode);
351 while (OffsetOfNode != AMD_HEAP_INVALID_HEAP_OFFSET) {
352 AlignTo16Byte = (UINT8) ((0x10 - (((UINTN) (VOID *) FreeSpaceNode + sizeof (BUFFER_NODE) + SIZE_OF_SENTINEL) & 0xF)) & 0xF);
353 AllocateHeapParams->RequestedBufferSize = (UINT32) (AllocateHeapParams->RequestedBufferSize + AlignTo16Byte);
354 if (FreeSpaceNode->BufferSize >= AllocateHeapParams->RequestedBufferSize) {
357 AllocateHeapParams->RequestedBufferSize = (UINT32) (AllocateHeapParams->RequestedBufferSize - AlignTo16Byte);
358 OffsetOfNode = FreeSpaceNode->OffsetOfNextNode;
359 FreeSpaceNode = (BUFFER_NODE *) (BaseAddress + OffsetOfNode);
361 if (OffsetOfNode == AMD_HEAP_INVALID_HEAP_OFFSET) {
362 // We don't find any free space buffer that matches the requested buffer size.
363 PutEventLog (AGESA_BOUNDS_CHK,
364 CPU_ERROR_HEAP_IS_FULL,
365 AllocateHeapParams->BufferHandle, 0, 0, 0, StdHeader);
366 return AGESA_BOUNDS_CHK;
368 // We find one matched free space buffer.
369 DeleteFreeSpaceNode (StdHeader, OffsetOfNode);
370 NewBufferNode = FreeSpaceNode;
371 // Add new buffer node to the buffer chain
372 if (HeapManager->FirstActiveBufferOffset == AMD_HEAP_INVALID_HEAP_OFFSET) {
373 HeapManager->FirstActiveBufferOffset = sizeof (HEAP_MANAGER);
375 CurrentBufferNode->OffsetOfNextNode = OffsetOfNode;
378 RemainSize = FreeSpaceNode->BufferSize - AllocateHeapParams->RequestedBufferSize;
379 if (RemainSize > sizeof (BUFFER_NODE)) {
380 NewBufferNode->BufferSize = AllocateHeapParams->RequestedBufferSize;
381 OffsetOfSplitNode = OffsetOfNode + sizeof (BUFFER_NODE) + NewBufferNode->BufferSize;
382 SplitFreeSpaceNode = (BUFFER_NODE *) (BaseAddress + OffsetOfSplitNode);
383 SplitFreeSpaceNode->BufferSize = RemainSize - sizeof (BUFFER_NODE);
384 InsertFreeSpaceNode (StdHeader, OffsetOfSplitNode);
386 // Remain size is less than BUFFER_NODE, we use whole size instead of requested size.
387 NewBufferNode->BufferSize = FreeSpaceNode->BufferSize;
391 // Initialize BUFFER_NODE structure of NewBufferNode
392 NewBufferNode->BufferHandle = AllocateHeapParams->BufferHandle;
393 if ((AllocateHeapParams->Persist == HEAP_TEMP_MEM) || (AllocateHeapParams->Persist == HEAP_SYSTEM_MEM)) {
394 NewBufferNode->Persist = AllocateHeapParams->Persist;
396 NewBufferNode->Persist = HEAP_LOCAL_CACHE;
398 NewBufferNode->OffsetOfNextNode = AMD_HEAP_INVALID_HEAP_OFFSET;
399 NewBufferNode->PadSize = AlignTo16Byte;
402 LibAmdMemFill ((VOID *) ((UINT8 *) NewBufferNode + sizeof (BUFFER_NODE)), 0x00, NewBufferNode->BufferSize, StdHeader);
405 SET_SENTINEL_BEFORE (NewBufferNode, AlignTo16Byte);
406 SET_SENTINEL_AFTER (NewBufferNode);
408 // Update global variables
409 HeapManager->UsedSize += NewBufferNode->BufferSize + sizeof (BUFFER_NODE);
411 // Now fill in the incoming structure
412 AllocateHeapParams->BufferPtr = (UINT8 *) ((UINT8 *) NewBufferNode + sizeof (BUFFER_NODE) + SIZE_OF_SENTINEL + AlignTo16Byte);
413 AllocateHeapParams->RequestedBufferSize -= (NUM_OF_SENTINEL * SIZE_OF_SENTINEL + AlignTo16Byte);
415 return AGESA_SUCCESS;
419 /*---------------------------------------------------------------------------------------*/
421 * Deallocates a previously allocated buffer in the heap
423 * This function will deallocate buffer either by using internal 'AGESA' heapmanager
424 * or by using externa (IBV) heapmanager.
426 * @param[in] BufferHandle Handle of the buffer to free.
427 * @param[in] StdHeader Config handle for library and services.
429 * @retval AGESA_SUCCESS No error
430 * @retval AGESA_BOUNDS_CHK Handle does not exist on the heap
434 HeapDeallocateBuffer (
435 IN UINT32 BufferHandle,
436 IN AMD_CONFIG_PARAMS *StdHeader
441 UINT32 OffsetOfFreeSpaceNode;
442 UINT32 OffsetOfPreviousNode;
443 UINT32 OffsetOfCurrentNode;
444 BOOLEAN HeapLocateFlag;
445 HEAP_MANAGER *HeapManager;
446 BUFFER_NODE *CurrentNode;
447 BUFFER_NODE *PreviousNode;
448 BUFFER_NODE *FreeSpaceNode;
449 AGESA_BUFFER_PARAMS AgesaBuffer;
451 ASSERT (StdHeader != NULL);
453 HeapLocateFlag = TRUE;
454 BaseAddress = (UINT8 *) StdHeader->HeapBasePtr;
455 HeapManager = (HEAP_MANAGER *) BaseAddress;
457 // Check Heap database is valid
458 if ((BaseAddress == NULL) || (HeapManager->Signature != HEAP_SIGNATURE_VALID)) {
459 // The base address in StdHeader is incorrect, get base address by itself
460 BaseAddress = (UINT8 *) HeapGetBaseAddress (StdHeader);
461 HeapManager = (HEAP_MANAGER *) BaseAddress;
462 if ((BaseAddress == NULL) || (HeapManager->Signature != HEAP_SIGNATURE_VALID)) {
463 // Heap is not available, ASSERT here
467 StdHeader->HeapBasePtr = (UINT64) BaseAddress;
470 OffsetOfPreviousNode = AMD_HEAP_INVALID_HEAP_OFFSET;
471 OffsetOfCurrentNode = HeapManager->FirstActiveBufferOffset;
472 CurrentNode = (BUFFER_NODE *) (BaseAddress + OffsetOfCurrentNode);
475 if ((BaseAddress != NULL) && (HeapManager->Signature == HEAP_SIGNATURE_VALID)) {
476 if (OffsetOfCurrentNode == AMD_HEAP_INVALID_HEAP_OFFSET) {
477 HeapLocateFlag = FALSE;
479 while (CurrentNode->BufferHandle != BufferHandle) {
480 if (CurrentNode->OffsetOfNextNode == AMD_HEAP_INVALID_HEAP_OFFSET) {
481 HeapLocateFlag = FALSE;
484 OffsetOfPreviousNode = OffsetOfCurrentNode;
485 OffsetOfCurrentNode = CurrentNode->OffsetOfNextNode;
486 CurrentNode = (BUFFER_NODE *) (BaseAddress + OffsetOfCurrentNode);
491 HeapLocateFlag = FALSE;
494 if (HeapLocateFlag == TRUE) {
495 // CurrentNode points to the buffer which wanted to be deallocated.
496 // Remove deallocated heap from active buffer chain.
497 if (OffsetOfPreviousNode == AMD_HEAP_INVALID_HEAP_OFFSET) {
498 HeapManager->FirstActiveBufferOffset = CurrentNode->OffsetOfNextNode;
500 PreviousNode = (BUFFER_NODE *) (BaseAddress + OffsetOfPreviousNode);
501 PreviousNode->OffsetOfNextNode = CurrentNode->OffsetOfNextNode;
503 // Now, CurrentNode become a free space node.
504 HeapManager->UsedSize -= CurrentNode->BufferSize + sizeof (BUFFER_NODE);
505 // Loop free space chain to see if any free space node is just before/after CurrentNode, then merge them.
506 OffsetOfFreeSpaceNode = HeapManager->FirstFreeSpaceOffset;
507 FreeSpaceNode = (BUFFER_NODE *) (BaseAddress + OffsetOfFreeSpaceNode);
508 while (OffsetOfFreeSpaceNode != AMD_HEAP_INVALID_HEAP_OFFSET) {
509 if ((OffsetOfFreeSpaceNode + sizeof (BUFFER_NODE) + FreeSpaceNode->BufferSize) == OffsetOfCurrentNode) {
510 DeleteFreeSpaceNode (StdHeader, OffsetOfFreeSpaceNode);
511 NodeSize = FreeSpaceNode->BufferSize + CurrentNode->BufferSize + sizeof (BUFFER_NODE);
512 OffsetOfCurrentNode = OffsetOfFreeSpaceNode;
513 CurrentNode = FreeSpaceNode;
514 CurrentNode->BufferSize = NodeSize;
515 } else if (OffsetOfFreeSpaceNode == (OffsetOfCurrentNode + sizeof (BUFFER_NODE) + CurrentNode->BufferSize)) {
516 DeleteFreeSpaceNode (StdHeader, OffsetOfFreeSpaceNode);
517 NodeSize = FreeSpaceNode->BufferSize + CurrentNode->BufferSize + sizeof (BUFFER_NODE);
518 CurrentNode->BufferSize = NodeSize;
520 OffsetOfFreeSpaceNode = FreeSpaceNode->OffsetOfNextNode;
521 FreeSpaceNode = (BUFFER_NODE *) (BaseAddress + OffsetOfFreeSpaceNode);
523 InsertFreeSpaceNode (StdHeader, OffsetOfCurrentNode);
524 return AGESA_SUCCESS;
526 // If HeapStatus == HEAP_SYSTEM_MEM, try callout function
527 if (StdHeader->HeapStatus == HEAP_SYSTEM_MEM) {
528 AgesaBuffer.StdHeader = *StdHeader;
529 AgesaBuffer.BufferHandle = BufferHandle;
531 AGESA_TESTPOINT (TpIfBeforeDeallocateHeapBuffer, StdHeader);
532 if (AgesaDeallocateBuffer (0, &AgesaBuffer) != AGESA_SUCCESS) {
535 AGESA_TESTPOINT (TpIfAfterDeallocateHeapBuffer, StdHeader);
537 return AGESA_SUCCESS;
539 // If we are still unable to locate the buffer handle, return AGESA_BOUNDS_CHK
540 if ((BaseAddress != NULL) && (HeapManager->Signature == HEAP_SIGNATURE_VALID)) {
541 PutEventLog (AGESA_BOUNDS_CHK,
542 CPU_ERROR_HEAP_BUFFER_HANDLE_IS_NOT_PRESENT,
543 BufferHandle, 0, 0, 0, StdHeader);
547 return AGESA_BOUNDS_CHK;
551 /*---------------------------------------------------------------------------------------*/
553 * Locates a previously allocated buffer on the heap.
555 * This function searches the heap for a buffer with the desired handle, and
556 * returns a pointer to the buffer.
558 * @param[in,out] LocateHeap Structure containing the buffer's handle,
559 * and the return pointer.
560 * @param[in] StdHeader Config handle for library and services.
562 * @retval AGESA_SUCCESS No error
563 * @retval AGESA_BOUNDS_CHK Handle does not exist on the heap
568 IN OUT LOCATE_HEAP_PTR *LocateHeap,
569 IN AMD_CONFIG_PARAMS *StdHeader
574 UINT32 OffsetOfCurrentNode;
575 BOOLEAN HeapLocateFlag;
576 HEAP_MANAGER *HeapManager;
577 BUFFER_NODE *CurrentNode;
578 AGESA_BUFFER_PARAMS AgesaBuffer;
580 ASSERT (StdHeader != NULL);
582 HeapLocateFlag = TRUE;
583 BaseAddress = (UINT8 *) StdHeader->HeapBasePtr;
584 HeapManager = (HEAP_MANAGER *) BaseAddress;
586 // Check Heap database is valid
587 if ((BaseAddress == NULL) || (HeapManager->Signature != HEAP_SIGNATURE_VALID)) {
588 // The base address in StdHeader is incorrect, get base address by itself
589 BaseAddress = (UINT8 *) HeapGetBaseAddress (StdHeader);
590 HeapManager = (HEAP_MANAGER *) BaseAddress;
591 if ((BaseAddress == NULL) || (HeapManager->Signature != HEAP_SIGNATURE_VALID)) {
592 // Heap is not available, ASSERT here
596 StdHeader->HeapBasePtr = (UINT64) BaseAddress;
598 OffsetOfCurrentNode = HeapManager->FirstActiveBufferOffset;
599 CurrentNode = (BUFFER_NODE *) (BaseAddress + OffsetOfCurrentNode);
601 // Find buffer using internal heap manager
602 // Locate the heap using handle = LocateHeap-> BufferHandle
603 // If HeapStatus != HEAP_SYSTEM_ MEM
604 if ((BaseAddress != NULL) && (HeapManager->Signature == HEAP_SIGNATURE_VALID)) {
605 if (OffsetOfCurrentNode == AMD_HEAP_INVALID_HEAP_OFFSET) {
606 HeapLocateFlag = FALSE;
608 while (CurrentNode->BufferHandle != LocateHeap->BufferHandle) {
609 if (CurrentNode->OffsetOfNextNode == AMD_HEAP_INVALID_HEAP_OFFSET) {
610 HeapLocateFlag = FALSE;
613 OffsetOfCurrentNode = CurrentNode->OffsetOfNextNode;
614 CurrentNode = (BUFFER_NODE *) (BaseAddress + OffsetOfCurrentNode);
619 HeapLocateFlag = FALSE;
622 if (HeapLocateFlag) {
623 AlignTo16Byte = CurrentNode->PadSize;
624 LocateHeap->BufferPtr = (UINT8 *) ((UINT8 *) CurrentNode + sizeof (BUFFER_NODE) + SIZE_OF_SENTINEL + AlignTo16Byte);
625 LocateHeap->BufferSize = CurrentNode->BufferSize - NUM_OF_SENTINEL * SIZE_OF_SENTINEL - AlignTo16Byte;
626 return AGESA_SUCCESS;
628 // If HeapStatus == HEAP_SYSTEM_MEM, try callout function
629 if (StdHeader->HeapStatus == HEAP_SYSTEM_MEM) {
630 AgesaBuffer.StdHeader = *StdHeader;
631 AgesaBuffer.BufferHandle = LocateHeap->BufferHandle;
633 AGESA_TESTPOINT (TpIfBeforeLocateHeapBuffer, StdHeader);
634 if (AgesaLocateBuffer (0, &AgesaBuffer) != AGESA_SUCCESS) {
635 LocateHeap->BufferPtr = NULL;
638 LocateHeap->BufferSize = AgesaBuffer.BufferLength;
639 AGESA_TESTPOINT (TpIfAfterLocateHeapBuffer, StdHeader);
641 LocateHeap->BufferPtr = (UINT8 *) (AgesaBuffer.BufferPointer);
642 return AGESA_SUCCESS;
645 // If we are still unable to deallocate the buffer handle, return AGESA_BOUNDS_CHK
646 LocateHeap->BufferPtr = NULL;
647 LocateHeap->BufferSize = 0;
648 if ((BaseAddress != NULL) && (HeapManager->Signature == HEAP_SIGNATURE_VALID)) {
649 PutEventLog (AGESA_BOUNDS_CHK,
650 CPU_ERROR_HEAP_BUFFER_HANDLE_IS_NOT_PRESENT,
651 LocateHeap->BufferHandle, 0, 0, 0, StdHeader);
655 return AGESA_BOUNDS_CHK;
659 /*---------------------------------------------------------------------------------------*/
661 * Get the heap base address
663 * This function will try to locate heap from cache, temp memory, main memory.
664 * The heap signature will be checked for validity on each possible location.
665 * Firstly, try if heap base is in cache by calling the function HeapGetCurrentBase.
666 * Secondly, try if heap base is temp memory by UserOptoions.CfgHeapDramAddress.
667 * Thirdly, try if heap base is in main memory by doing a buffer locate with buffer handle
668 * AMD_HEAP_IN_MAIN_MEMORY_HANDLE.
669 * If no valid heap signature is found in each possible location above, a NULL pointer is returned.
671 * @param[in] StdHeader Config handle for library and services.
673 * @return Heap base address of the executing core's heap.
678 IN AMD_CONFIG_PARAMS *StdHeader
682 HEAP_MANAGER *HeapManager;
683 AGESA_BUFFER_PARAMS AgesaBuffer;
685 // Firstly, we try to see if heap is in cache
686 BaseAddress = HeapGetCurrentBase (StdHeader);
687 HeapManager = (HEAP_MANAGER *) BaseAddress;
689 if ((HeapManager->Signature != HEAP_SIGNATURE_VALID) &&
690 (StdHeader->HeapStatus != HEAP_DO_NOT_EXIST_YET) &&
691 (StdHeader->HeapStatus != HEAP_LOCAL_CACHE)) {
692 // Secondly, we try to see if heap is in temp memory
693 BaseAddress = UserOptions.CfgHeapDramAddress;
694 HeapManager = (HEAP_MANAGER *) BaseAddress;
695 if (HeapManager->Signature != HEAP_SIGNATURE_VALID) {
696 // Thirdly, we try to see if heap in main memory
697 // by locating with external buffer manager (IBV)
698 AgesaBuffer.StdHeader = *StdHeader;
699 AgesaBuffer.BufferHandle = AMD_HEAP_IN_MAIN_MEMORY_HANDLE;
700 if (AgesaLocateBuffer (0, &AgesaBuffer) == AGESA_SUCCESS) {
701 BaseAddress = (UINT64) AgesaBuffer.BufferPointer;
702 HeapManager = (HEAP_MANAGER *) BaseAddress;
703 if (HeapManager->Signature != HEAP_SIGNATURE_VALID) {
704 // No valid heap signature ever found, return a NULL pointer
708 // No heap buffer is allocated by external manager (IBV), return a NULL pointer
717 /*---------------------------------------------------------------------------------------
718 * L O C A L F U N C T I O N S
719 *---------------------------------------------------------------------------------------
721 /* -----------------------------------------------------------------------------*/
724 * DeleteFreeSpaceNode
727 * Delete a free space node from free space chain
730 * @param[in] StdHeader Config handle for library and services.
731 * @param[in] OffsetOfDeletedNode Offset of deleted node.
738 DeleteFreeSpaceNode (
739 IN AMD_CONFIG_PARAMS *StdHeader,
740 IN UINT32 OffsetOfDeletedNode
744 UINT32 OffsetOfPreviousNode;
745 UINT32 OffsetOfCurrentNode;
746 HEAP_MANAGER *HeapManager;
747 BUFFER_NODE *CurrentFreeSpaceNode;
748 BUFFER_NODE *PreviousFreeSpaceNode;
751 BaseAddress = (UINT8 *) StdHeader->HeapBasePtr;
752 HeapManager = (HEAP_MANAGER *) BaseAddress;
754 OffsetOfPreviousNode = AMD_HEAP_INVALID_HEAP_OFFSET;
755 OffsetOfCurrentNode = HeapManager->FirstFreeSpaceOffset;
757 // After AmdInitEnv, there is no free space provided for HeapAllocateBuffer.
758 // Hence if the FirstFreeSpaceOffset is AMD_HEAP_INVALID_HEAP_OFFSET, then
759 // no need to do more on delete node.
761 if (OffsetOfCurrentNode != AMD_HEAP_INVALID_HEAP_OFFSET) {
762 CurrentFreeSpaceNode = (BUFFER_NODE *) (BaseAddress + OffsetOfCurrentNode);
763 while ((OffsetOfCurrentNode != AMD_HEAP_INVALID_HEAP_OFFSET) && (OffsetOfCurrentNode != OffsetOfDeletedNode)) {
764 OffsetOfPreviousNode = OffsetOfCurrentNode;
765 OffsetOfCurrentNode = CurrentFreeSpaceNode->OffsetOfNextNode;
766 CurrentFreeSpaceNode = (BUFFER_NODE *) (BaseAddress + OffsetOfCurrentNode);
768 if (OffsetOfCurrentNode != AMD_HEAP_INVALID_HEAP_OFFSET) {
769 if (OffsetOfPreviousNode == AMD_HEAP_INVALID_HEAP_OFFSET) {
770 HeapManager->FirstFreeSpaceOffset = CurrentFreeSpaceNode->OffsetOfNextNode;
772 PreviousFreeSpaceNode = (BUFFER_NODE *) (BaseAddress + OffsetOfPreviousNode);
773 PreviousFreeSpaceNode->OffsetOfNextNode = CurrentFreeSpaceNode->OffsetOfNextNode;
780 /* -----------------------------------------------------------------------------*/
783 * InsertFreeSpaceNode
786 * Insert a free space node to free space chain, size order
789 * @param[in] StdHeader Config handle for library and services.
790 * @param[in] OffsetOfInsertNode Offset of inserted node.
797 InsertFreeSpaceNode (
798 IN AMD_CONFIG_PARAMS *StdHeader,
799 IN UINT32 OffsetOfInsertNode
803 UINT32 OffsetOfPreviousNode;
804 UINT32 OffsetOfCurrentNode;
805 HEAP_MANAGER *HeapManager;
806 BUFFER_NODE *CurrentFreeSpaceNode;
807 BUFFER_NODE *PreviousFreeSpaceNode;
808 BUFFER_NODE *LocalInsertFreeSpaceNode;
810 BaseAddress = (UINT8 *) StdHeader->HeapBasePtr;
811 HeapManager = (HEAP_MANAGER *) BaseAddress;
813 OffsetOfPreviousNode = AMD_HEAP_INVALID_HEAP_OFFSET;
814 OffsetOfCurrentNode = HeapManager->FirstFreeSpaceOffset;
815 CurrentFreeSpaceNode = (BUFFER_NODE *) (BaseAddress + OffsetOfCurrentNode);
816 LocalInsertFreeSpaceNode = (BUFFER_NODE *) (BaseAddress + OffsetOfInsertNode);
817 while ((OffsetOfCurrentNode != AMD_HEAP_INVALID_HEAP_OFFSET) &&
818 (CurrentFreeSpaceNode->BufferSize < LocalInsertFreeSpaceNode->BufferSize)) {
819 OffsetOfPreviousNode = OffsetOfCurrentNode;
820 OffsetOfCurrentNode = CurrentFreeSpaceNode->OffsetOfNextNode;
821 CurrentFreeSpaceNode = (BUFFER_NODE *) (BaseAddress + OffsetOfCurrentNode);
823 LocalInsertFreeSpaceNode->OffsetOfNextNode = OffsetOfCurrentNode;
824 if (OffsetOfPreviousNode == AMD_HEAP_INVALID_HEAP_OFFSET) {
825 HeapManager->FirstFreeSpaceOffset = OffsetOfInsertNode;
827 PreviousFreeSpaceNode = (BUFFER_NODE *) (BaseAddress + OffsetOfPreviousNode);
828 PreviousFreeSpaceNode->OffsetOfNextNode = OffsetOfInsertNode;
833 /*---------------------------------------------------------------------------------------*/
835 * Determines the base address of the executing core's heap.
837 * This function uses the executing core's socket/core numbers to determine
838 * where it's heap should be located.
840 * @param[in] StdHeader Config handle for library and services.
842 * @return A pointer to the executing core's heap.
848 IN AMD_CONFIG_PARAMS *StdHeader
851 UINT32 SystemCoreNumber;
853 AGESA_STATUS IgnoredStatus;
854 CPU_SPECIFIC_SERVICES *FamilyServices;
856 if (IsBsp (StdHeader, &IgnoredStatus)) {
857 ReturnPtr = AMD_HEAP_START_ADDRESS;
859 GetCpuServicesOfCurrentCore ((const CPU_SPECIFIC_SERVICES **)&FamilyServices, StdHeader);
860 ASSERT (FamilyServices != NULL);
862 SystemCoreNumber = FamilyServices->GetApCoreNumber (FamilyServices, StdHeader);
863 ASSERT (SystemCoreNumber != 0);
864 ASSERT (SystemCoreNumber < 64);
865 ReturnPtr = ((SystemCoreNumber * AMD_HEAP_SIZE_PER_CORE) + AMD_HEAP_START_ADDRESS);
867 ASSERT (ReturnPtr <= ((AMD_HEAP_REGION_END_ADDRESS + 1) - AMD_HEAP_SIZE_PER_CORE));