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: 56322 $ @e \$Date: 2011-07-11 16:51:42 -0600 (Mon, 11 Jul 2011) $
15 /*******************************************************************************
17 * Copyright (C) 2012 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.
42 ******************************************************************************
45 /*----------------------------------------------------------------------------------------
46 * M O D U L E S U S E D
47 *----------------------------------------------------------------------------------------
53 #include "cpuRegisters.h"
54 #include "cpuServices.h"
55 #include "GeneralServices.h"
56 #include "heapManager.h"
57 #include "cpuCacheInit.h"
58 #include "cpuFamilyTranslation.h"
63 #define FILECODE PROC_CPU_HEAPMANAGER_FILECODE
64 /*----------------------------------------------------------------------------------------
65 * D E F I N I T I O N S A N D M A C R O S
66 *----------------------------------------------------------------------------------------
70 /*----------------------------------------------------------------------------------------
71 * T Y P E D E F S A N D S T R U C T U R E S
72 *----------------------------------------------------------------------------------------
76 /*----------------------------------------------------------------------------------------
77 * 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
78 *----------------------------------------------------------------------------------------
83 IN AMD_CONFIG_PARAMS *StdHeader
89 IN AMD_CONFIG_PARAMS *StdHeader,
90 IN UINT32 OffsetOfDeletedNode
96 IN AMD_CONFIG_PARAMS *StdHeader,
97 IN UINT32 OffsetOfInsertNode
100 /*----------------------------------------------------------------------------------------
101 * P U B L I C F U N C T I O N S
102 *----------------------------------------------------------------------------------------
105 /*----------------------------------------------------------------------------------------
106 * E X P O R T E D F U N C T I O N S
107 *----------------------------------------------------------------------------------------
109 extern BUILD_OPT_CFG UserOptions;
111 /*---------------------------------------------------------------------------------------*/
113 * This function initializes the heap for each CPU core.
115 * Check for already initialized. If not, determine offset of local heap in CAS and
116 * setup initial heap markers and bookkeeping status. Initialize a couple heap items
117 * all cores need, for convenience. Currently these are caching the AP mailbox info and
118 * an initial event log.
120 * @param[in] StdHeader Handle of Header for calling lib functions and services.
122 * @retval AGESA_SUCCESS This core's heap is initialized
123 * @retval AGESA_FATAL This core's heap cannot be initialized due to any reasons below:
124 * - current processor family cannot be identified.
129 IN AMD_CONFIG_PARAMS *StdHeader
132 // First Time Initialization
133 // Note: First 16 bytes of buffer is reserved for Heap Manager use
134 UINT16 HeapAlreadyInitSizeDword;
135 UINT32 HeapAlreadyRead;
137 UINT8 *HeapBufferPtr;
144 BUFFER_NODE *FreeSpaceNode;
145 CACHE_INFO *CacheInfoPtr;
146 AGESA_STATUS IgnoredSts;
147 CPU_SPECIFIC_SERVICES *FamilySpecificServices;
148 CPU_LOGICAL_ID CpuFamilyRevision;
150 // Check whether this is a known processor family.
151 GetLogicalIdOfCurrentCore (&CpuFamilyRevision, StdHeader);
152 if ((CpuFamilyRevision.Family == 0) && (CpuFamilyRevision.Revision == 0)) {
157 GetCpuServicesOfCurrentCore ((CONST CPU_SPECIFIC_SERVICES **)&FamilySpecificServices, StdHeader);
158 FamilySpecificServices->GetCacheInfo (FamilySpecificServices, (CONST VOID **) &CacheInfoPtr, &Ignored, StdHeader);
159 HeapBufferPtr = (UINT8 *) StdHeader->HeapBasePtr;
161 // Check whether the heap manager is already initialized
162 LibAmdMsrRead (AMD_MTRR_VARIABLE_HEAP_MASK, &MsrData, StdHeader);
163 if (MsrData == (CacheInfoPtr->VariableMtrrMask & AMD_HEAP_MTRR_MASK)) {
164 LibAmdMsrRead (AMD_MTRR_VARIABLE_HEAP_BASE, &MsrData, StdHeader);
165 if ((MsrData & CacheInfoPtr->HeapBaseMask) == ((UINT64) HeapBufferPtr & CacheInfoPtr->HeapBaseMask)) {
166 if (((HEAP_MANAGER *) HeapBufferPtr)->Signature == HEAP_SIGNATURE_VALID) {
167 // This is not a bug, there are multiple premem basic entry points,
168 // and each will call heap init to make sure create struct will succeed.
169 // If that is later deemed a problem, there needs to be a reasonable test
170 // for the calling code to make to determine if it needs to init heap or not.
171 // In the mean time, add this to the event log
172 PutEventLog (AGESA_SUCCESS,
173 CPU_ERROR_HEAP_IS_ALREADY_INITIALIZED,
174 0, 0, 0, 0, StdHeader);
175 return AGESA_SUCCESS;
180 // Set variable MTRR base and mask
181 MsrData = ((UINT64) HeapBufferPtr & CacheInfoPtr->HeapBaseMask);
182 MsrMask = CacheInfoPtr->VariableMtrrHeapMask & AMD_HEAP_MTRR_MASK;
185 LibAmdMsrWrite (AMD_MTRR_VARIABLE_HEAP_BASE, &MsrData, StdHeader);
186 LibAmdMsrWrite (AMD_MTRR_VARIABLE_HEAP_MASK, &MsrMask, StdHeader);
188 // Set top of memory to a temp value
189 MsrData = (UINT64) (AMD_TEMP_TOM);
190 LibAmdMsrWrite (TOP_MEM, &MsrData, StdHeader);
192 // Enable variable MTTRs
193 LibAmdMsrRead (SYS_CFG, &MsrData, StdHeader);
194 MsrData |= AMD_VAR_MTRR_ENABLE_BIT;
195 LibAmdMsrWrite (SYS_CFG, &MsrData, StdHeader);
197 // Initialize Heap Space
198 // BIOS may store to a line only after it has been allocated by a load
199 LibAmdCpuidRead (AMD_CPUID_L2L3Cache_L2TLB, &CpuId, StdHeader);
200 L2LineSize = (UINT8) (CpuId.ECX_Reg);
201 HeapInitPtr = HeapBufferPtr ;
202 for (HeapAlreadyRead = 0; HeapAlreadyRead < AMD_HEAP_SIZE_PER_CORE;
203 (HeapAlreadyRead = HeapAlreadyRead + L2LineSize)) {
204 Ignored = *HeapInitPtr;
205 HeapInitPtr += L2LineSize;
208 HeapDataPtr = (UINT32 *) HeapBufferPtr;
209 for (HeapAlreadyInitSizeDword = 0; HeapAlreadyInitSizeDword < AMD_HEAP_SIZE_DWORD_PER_CORE; HeapAlreadyInitSizeDword++) {
214 // Note: We are reserving the first 16 bytes for Heap Manager use
215 // UsedSize indicates the size of heap spaced is used for HEAP_MANAGER, BUFFER_NODE,
216 // Pad for 16-byte alignment, buffer data, and IDS SENTINEL.
217 // FirstActiveBufferOffset is initalized as invalid heap offset, AMD_HEAP_INVALID_HEAP_OFFSET.
218 // FirstFreeSpaceOffset is initalized as the byte right after HEAP_MANAGER header.
219 // Then we set Signature of HEAP_MANAGER header as valid, HEAP_SIGNATURE_VALID.
220 ((HEAP_MANAGER*) HeapBufferPtr)->UsedSize = sizeof (HEAP_MANAGER);
221 ((HEAP_MANAGER*) HeapBufferPtr)->FirstActiveBufferOffset = AMD_HEAP_INVALID_HEAP_OFFSET;
222 ((HEAP_MANAGER*) HeapBufferPtr)->FirstFreeSpaceOffset = sizeof (HEAP_MANAGER);
223 ((HEAP_MANAGER*) HeapBufferPtr)->Signature = HEAP_SIGNATURE_VALID;
224 // Create free space link
225 FreeSpaceNode = (BUFFER_NODE *) (HeapBufferPtr + sizeof (HEAP_MANAGER));
226 FreeSpaceNode->BufferSize = AMD_HEAP_SIZE_PER_CORE - sizeof (HEAP_MANAGER) - sizeof (BUFFER_NODE);
227 FreeSpaceNode->OffsetOfNextNode = AMD_HEAP_INVALID_HEAP_OFFSET;
229 StdHeader->HeapStatus = HEAP_LOCAL_CACHE;
230 if (!IsBsp (StdHeader, &IgnoredSts)) {
231 // The BSP's hardware mailbox has not been initialized, so only APs
232 // can do this at this point.
233 CacheApMailbox (StdHeader);
235 EventLogInitialization (StdHeader);
236 return AGESA_SUCCESS;
240 /*---------------------------------------------------------------------------------------*/
242 * Allocates space for a new buffer in the heap
244 * This function will allocate new buffer either by using internal 'AGESA' heapmanager
245 * or by using externa (IBV) heapmanager. This function will also determine if whether or not
246 * there is enough space for the new structure. If so, it will zero out the buffer,
247 * and return a pointer to the region.
249 * @param[in,out] AllocateHeapParams structure pointer containing the size of the
250 * desired new region, its handle, and the
252 * @param[in,out] StdHeader Config handle for library and services.
254 * @retval AGESA_SUCCESS No error
255 * @retval AGESA_BOUNDS_CHK Handle already exists, or not enough
257 * @retval AGESA_UNSUPPORTED Do not support this kind of heap allocation
258 * @retval AGESA_ERROR Heap is invaild
263 IN OUT ALLOCATE_HEAP_PARAMS *AllocateHeapParams,
264 IN OUT AMD_CONFIG_PARAMS *StdHeader
269 UINT8 CalloutFcnData;
271 UINT32 OffsetOfSplitNode;
273 HEAP_MANAGER *HeapManager;
274 BUFFER_NODE *FreeSpaceNode;
275 BUFFER_NODE *SplitFreeSpaceNode;
276 BUFFER_NODE *CurrentBufferNode;
277 BUFFER_NODE *NewBufferNode;
278 AGESA_BUFFER_PARAMS AgesaBuffer;
280 ASSERT (StdHeader != NULL);
281 if (AllocateHeapParams->Persist == HEAP_RUNTIME_SYSTEM_MEM) {
282 ASSERT (StdHeader->HeapStatus == HEAP_SYSTEM_MEM);
283 if (StdHeader->HeapStatus != HEAP_SYSTEM_MEM) {
284 return AGESA_UNSUPPORTED;
288 // At this stage we will decide to either use external (IBV) heap manger
289 // or internal (AGESA) heap manager.
291 // If (HeapStatus == HEAP_SYSTEM_MEM), then use the call function to call
292 // external heap manager
293 if (StdHeader->HeapStatus == HEAP_SYSTEM_MEM) {
294 AgesaBuffer.StdHeader = *StdHeader;
295 AgesaBuffer.BufferHandle = AllocateHeapParams->BufferHandle;
296 AgesaBuffer.BufferLength = AllocateHeapParams->RequestedBufferSize;
298 if (AllocateHeapParams->Persist == HEAP_RUNTIME_SYSTEM_MEM) {
299 CalloutFcnData = HEAP_CALLOUT_RUNTIME;
301 CalloutFcnData = HEAP_CALLOUT_BOOTTIME;
303 AGESA_TESTPOINT (TpIfBeforeAllocateHeapBuffer, StdHeader);
304 if (AgesaAllocateBuffer (CalloutFcnData, &AgesaBuffer) != AGESA_SUCCESS) {
305 AllocateHeapParams->BufferPtr = NULL;
308 AGESA_TESTPOINT (TpIfAfterAllocateHeapBuffer, StdHeader);
310 AllocateHeapParams->BufferPtr = (UINT8 *) (AgesaBuffer.BufferPointer);
311 return AGESA_SUCCESS;
314 // If (StdHeader->HeapStatus != HEAP_SYSTEM_MEM), then allocated buffer
315 // using following AGESA Heap Manager code.
317 // Buffer pointer is NULL unless we return a buffer.
319 AllocateHeapParams->BufferPtr = NULL;
320 AllocateHeapParams->RequestedBufferSize += NUM_OF_SENTINEL * SIZE_OF_SENTINEL;
323 BaseAddress = (UINT8 *) StdHeader->HeapBasePtr;
324 HeapManager = (HEAP_MANAGER *) BaseAddress;
326 // Check Heap database is valid
327 if ((BaseAddress == NULL) || (HeapManager->Signature != HEAP_SIGNATURE_VALID)) {
328 // The base address in StdHeader is incorrect, get base address by itself
329 BaseAddress = (UINT8 *) HeapGetBaseAddress (StdHeader);
330 HeapManager = (HEAP_MANAGER *) BaseAddress;
331 if ((BaseAddress == NULL) || (HeapManager->Signature != HEAP_SIGNATURE_VALID)) {
332 // Heap is not available, ASSERT here
336 StdHeader->HeapBasePtr = (UINT64) BaseAddress;
340 CurrentBufferNode = (BUFFER_NODE *) (BaseAddress + sizeof (HEAP_MANAGER));
341 // If there already has been a heap with the incoming BufferHandle, we return AGESA_BOUNDS_CHK.
342 if (HeapManager->FirstActiveBufferOffset != AMD_HEAP_INVALID_HEAP_OFFSET) {
343 CurrentBufferNode = (BUFFER_NODE *) (BaseAddress + HeapManager->FirstActiveBufferOffset);
344 while (CurrentBufferNode->OffsetOfNextNode != AMD_HEAP_INVALID_HEAP_OFFSET) {
345 if (CurrentBufferNode->BufferHandle == AllocateHeapParams->BufferHandle) {
346 PutEventLog (AGESA_BOUNDS_CHK,
347 CPU_ERROR_HEAP_BUFFER_HANDLE_IS_ALREADY_USED,
348 AllocateHeapParams->BufferHandle, 0, 0, 0, StdHeader);
349 return AGESA_BOUNDS_CHK;
351 CurrentBufferNode = (BUFFER_NODE *) (BaseAddress + CurrentBufferNode->OffsetOfNextNode);
354 if (CurrentBufferNode->BufferHandle == AllocateHeapParams->BufferHandle) {
355 PutEventLog (AGESA_BOUNDS_CHK,
356 CPU_ERROR_HEAP_BUFFER_HANDLE_IS_ALREADY_USED,
357 AllocateHeapParams->BufferHandle, 0, 0, 0, StdHeader);
358 return AGESA_BOUNDS_CHK;
362 // Find the buffer size that first matches the requested buffer size (i.e. the first free buffer of greater size).
363 OffsetOfNode = HeapManager->FirstFreeSpaceOffset;
364 FreeSpaceNode = (BUFFER_NODE *) (BaseAddress + OffsetOfNode);
365 while (OffsetOfNode != AMD_HEAP_INVALID_HEAP_OFFSET) {
366 AlignTo16Byte = (UINT8) ((0x10 - (((UINTN) (VOID *) FreeSpaceNode + sizeof (BUFFER_NODE) + SIZE_OF_SENTINEL) & 0xF)) & 0xF);
367 AllocateHeapParams->RequestedBufferSize = (UINT32) (AllocateHeapParams->RequestedBufferSize + AlignTo16Byte);
368 if (FreeSpaceNode->BufferSize >= AllocateHeapParams->RequestedBufferSize) {
371 AllocateHeapParams->RequestedBufferSize = (UINT32) (AllocateHeapParams->RequestedBufferSize - AlignTo16Byte);
372 OffsetOfNode = FreeSpaceNode->OffsetOfNextNode;
373 FreeSpaceNode = (BUFFER_NODE *) (BaseAddress + OffsetOfNode);
375 if (OffsetOfNode == AMD_HEAP_INVALID_HEAP_OFFSET) {
376 // We don't find any free space buffer that matches the requested buffer size.
377 PutEventLog (AGESA_BOUNDS_CHK,
378 CPU_ERROR_HEAP_IS_FULL,
379 AllocateHeapParams->BufferHandle, 0, 0, 0, StdHeader);
380 return AGESA_BOUNDS_CHK;
382 // We find one matched free space buffer.
383 DeleteFreeSpaceNode (StdHeader, OffsetOfNode);
384 NewBufferNode = FreeSpaceNode;
385 // Add new buffer node to the buffer chain
386 if (HeapManager->FirstActiveBufferOffset == AMD_HEAP_INVALID_HEAP_OFFSET) {
387 HeapManager->FirstActiveBufferOffset = sizeof (HEAP_MANAGER);
389 CurrentBufferNode->OffsetOfNextNode = OffsetOfNode;
392 RemainSize = FreeSpaceNode->BufferSize - AllocateHeapParams->RequestedBufferSize;
393 if (RemainSize > sizeof (BUFFER_NODE)) {
394 NewBufferNode->BufferSize = AllocateHeapParams->RequestedBufferSize;
395 OffsetOfSplitNode = OffsetOfNode + sizeof (BUFFER_NODE) + NewBufferNode->BufferSize;
396 SplitFreeSpaceNode = (BUFFER_NODE *) (BaseAddress + OffsetOfSplitNode);
397 SplitFreeSpaceNode->BufferSize = RemainSize - sizeof (BUFFER_NODE);
398 InsertFreeSpaceNode (StdHeader, OffsetOfSplitNode);
400 // Remain size is less than BUFFER_NODE, we use whole size instead of requested size.
401 NewBufferNode->BufferSize = FreeSpaceNode->BufferSize;
405 // Initialize BUFFER_NODE structure of NewBufferNode
406 NewBufferNode->BufferHandle = AllocateHeapParams->BufferHandle;
407 if ((AllocateHeapParams->Persist == HEAP_TEMP_MEM) || (AllocateHeapParams->Persist == HEAP_SYSTEM_MEM)) {
408 NewBufferNode->Persist = AllocateHeapParams->Persist;
410 NewBufferNode->Persist = HEAP_LOCAL_CACHE;
412 NewBufferNode->OffsetOfNextNode = AMD_HEAP_INVALID_HEAP_OFFSET;
413 NewBufferNode->PadSize = AlignTo16Byte;
416 LibAmdMemFill ((VOID *) ((UINT8 *) NewBufferNode + sizeof (BUFFER_NODE)), 0x00, NewBufferNode->BufferSize, StdHeader);
419 SET_SENTINEL_BEFORE (NewBufferNode, AlignTo16Byte);
420 SET_SENTINEL_AFTER (NewBufferNode);
422 // Update global variables
423 HeapManager->UsedSize += NewBufferNode->BufferSize + sizeof (BUFFER_NODE);
425 // Now fill in the incoming structure
426 AllocateHeapParams->BufferPtr = (UINT8 *) ((UINT8 *) NewBufferNode + sizeof (BUFFER_NODE) + SIZE_OF_SENTINEL + AlignTo16Byte);
427 AllocateHeapParams->RequestedBufferSize -= (NUM_OF_SENTINEL * SIZE_OF_SENTINEL + AlignTo16Byte);
429 return AGESA_SUCCESS;
433 /*---------------------------------------------------------------------------------------*/
435 * Deallocates a previously allocated buffer in the heap
437 * This function will deallocate buffer either by using internal 'AGESA' heapmanager
438 * or by using externa (IBV) heapmanager.
440 * @param[in] BufferHandle Handle of the buffer to free.
441 * @param[in] StdHeader Config handle for library and services.
443 * @retval AGESA_SUCCESS No error
444 * @retval AGESA_BOUNDS_CHK Handle does not exist on the heap
448 HeapDeallocateBuffer (
449 IN UINT32 BufferHandle,
450 IN AMD_CONFIG_PARAMS *StdHeader
455 UINT32 OffsetOfFreeSpaceNode;
456 UINT32 OffsetOfPreviousNode;
457 UINT32 OffsetOfCurrentNode;
458 BOOLEAN HeapLocateFlag;
459 HEAP_MANAGER *HeapManager;
460 BUFFER_NODE *CurrentNode;
461 BUFFER_NODE *PreviousNode;
462 BUFFER_NODE *FreeSpaceNode;
463 AGESA_BUFFER_PARAMS AgesaBuffer;
465 ASSERT (StdHeader != NULL);
467 HeapLocateFlag = TRUE;
468 BaseAddress = (UINT8 *) StdHeader->HeapBasePtr;
469 HeapManager = (HEAP_MANAGER *) BaseAddress;
471 // Check Heap database is valid
472 if ((BaseAddress == NULL) || (HeapManager->Signature != HEAP_SIGNATURE_VALID)) {
473 // The base address in StdHeader is incorrect, get base address by itself
474 BaseAddress = (UINT8 *) HeapGetBaseAddress (StdHeader);
475 HeapManager = (HEAP_MANAGER *) BaseAddress;
476 if ((BaseAddress == NULL) || (HeapManager->Signature != HEAP_SIGNATURE_VALID)) {
477 // Heap is not available, ASSERT here
481 StdHeader->HeapBasePtr = (UINT64) BaseAddress;
484 OffsetOfPreviousNode = AMD_HEAP_INVALID_HEAP_OFFSET;
485 OffsetOfCurrentNode = HeapManager->FirstActiveBufferOffset;
486 CurrentNode = (BUFFER_NODE *) (BaseAddress + OffsetOfCurrentNode);
489 if ((BaseAddress != NULL) && (HeapManager->Signature == HEAP_SIGNATURE_VALID)) {
490 if (OffsetOfCurrentNode == AMD_HEAP_INVALID_HEAP_OFFSET) {
491 HeapLocateFlag = FALSE;
493 while (CurrentNode->BufferHandle != BufferHandle) {
494 if (CurrentNode->OffsetOfNextNode == AMD_HEAP_INVALID_HEAP_OFFSET) {
495 HeapLocateFlag = FALSE;
498 OffsetOfPreviousNode = OffsetOfCurrentNode;
499 OffsetOfCurrentNode = CurrentNode->OffsetOfNextNode;
500 CurrentNode = (BUFFER_NODE *) (BaseAddress + OffsetOfCurrentNode);
505 HeapLocateFlag = FALSE;
508 if (HeapLocateFlag == TRUE) {
509 // CurrentNode points to the buffer which wanted to be deallocated.
510 // Remove deallocated heap from active buffer chain.
511 if (OffsetOfPreviousNode == AMD_HEAP_INVALID_HEAP_OFFSET) {
512 HeapManager->FirstActiveBufferOffset = CurrentNode->OffsetOfNextNode;
514 PreviousNode = (BUFFER_NODE *) (BaseAddress + OffsetOfPreviousNode);
515 PreviousNode->OffsetOfNextNode = CurrentNode->OffsetOfNextNode;
517 // Now, CurrentNode become a free space node.
518 HeapManager->UsedSize -= CurrentNode->BufferSize + sizeof (BUFFER_NODE);
519 // Loop free space chain to see if any free space node is just before/after CurrentNode, then merge them.
520 OffsetOfFreeSpaceNode = HeapManager->FirstFreeSpaceOffset;
521 FreeSpaceNode = (BUFFER_NODE *) (BaseAddress + OffsetOfFreeSpaceNode);
522 while (OffsetOfFreeSpaceNode != AMD_HEAP_INVALID_HEAP_OFFSET) {
523 if ((OffsetOfFreeSpaceNode + sizeof (BUFFER_NODE) + FreeSpaceNode->BufferSize) == OffsetOfCurrentNode) {
524 DeleteFreeSpaceNode (StdHeader, OffsetOfFreeSpaceNode);
525 NodeSize = FreeSpaceNode->BufferSize + CurrentNode->BufferSize + sizeof (BUFFER_NODE);
526 OffsetOfCurrentNode = OffsetOfFreeSpaceNode;
527 CurrentNode = FreeSpaceNode;
528 CurrentNode->BufferSize = NodeSize;
529 } else if (OffsetOfFreeSpaceNode == (OffsetOfCurrentNode + sizeof (BUFFER_NODE) + CurrentNode->BufferSize)) {
530 DeleteFreeSpaceNode (StdHeader, OffsetOfFreeSpaceNode);
531 NodeSize = FreeSpaceNode->BufferSize + CurrentNode->BufferSize + sizeof (BUFFER_NODE);
532 CurrentNode->BufferSize = NodeSize;
534 OffsetOfFreeSpaceNode = FreeSpaceNode->OffsetOfNextNode;
535 FreeSpaceNode = (BUFFER_NODE *) (BaseAddress + OffsetOfFreeSpaceNode);
537 InsertFreeSpaceNode (StdHeader, OffsetOfCurrentNode);
538 return AGESA_SUCCESS;
540 // If HeapStatus == HEAP_SYSTEM_MEM, try callout function
541 if (StdHeader->HeapStatus == HEAP_SYSTEM_MEM) {
542 AgesaBuffer.StdHeader = *StdHeader;
543 AgesaBuffer.BufferHandle = BufferHandle;
545 AGESA_TESTPOINT (TpIfBeforeDeallocateHeapBuffer, StdHeader);
546 if (AgesaDeallocateBuffer (0, &AgesaBuffer) != AGESA_SUCCESS) {
549 AGESA_TESTPOINT (TpIfAfterDeallocateHeapBuffer, StdHeader);
551 return AGESA_SUCCESS;
553 // If we are still unable to locate the buffer handle, return AGESA_BOUNDS_CHK
554 if ((BaseAddress != NULL) && (HeapManager->Signature == HEAP_SIGNATURE_VALID)) {
555 PutEventLog (AGESA_BOUNDS_CHK,
556 CPU_ERROR_HEAP_BUFFER_HANDLE_IS_NOT_PRESENT,
557 BufferHandle, 0, 0, 0, StdHeader);
561 return AGESA_BOUNDS_CHK;
565 /*---------------------------------------------------------------------------------------*/
567 * Locates a previously allocated buffer on the heap.
569 * This function searches the heap for a buffer with the desired handle, and
570 * returns a pointer to the buffer.
572 * @param[in,out] LocateHeap Structure containing the buffer's handle,
573 * and the return pointer.
574 * @param[in] StdHeader Config handle for library and services.
576 * @retval AGESA_SUCCESS No error
577 * @retval AGESA_BOUNDS_CHK Handle does not exist on the heap
582 IN OUT LOCATE_HEAP_PTR *LocateHeap,
583 IN AMD_CONFIG_PARAMS *StdHeader
588 UINT32 OffsetOfCurrentNode;
589 BOOLEAN HeapLocateFlag;
590 HEAP_MANAGER *HeapManager;
591 BUFFER_NODE *CurrentNode;
592 AGESA_BUFFER_PARAMS AgesaBuffer;
594 ASSERT (StdHeader != NULL);
596 HeapLocateFlag = TRUE;
597 BaseAddress = (UINT8 *) StdHeader->HeapBasePtr;
598 HeapManager = (HEAP_MANAGER *) BaseAddress;
600 // Check Heap database is valid
601 if ((BaseAddress == NULL) || (HeapManager->Signature != HEAP_SIGNATURE_VALID)) {
602 // The base address in StdHeader is incorrect, get base address by itself
603 BaseAddress = (UINT8 *) HeapGetBaseAddress (StdHeader);
604 HeapManager = (HEAP_MANAGER *) BaseAddress;
605 if ((BaseAddress == NULL) || (HeapManager->Signature != HEAP_SIGNATURE_VALID)) {
606 // Heap is not available, ASSERT here
610 StdHeader->HeapBasePtr = (UINT64) BaseAddress;
612 OffsetOfCurrentNode = HeapManager->FirstActiveBufferOffset;
613 CurrentNode = (BUFFER_NODE *) (BaseAddress + OffsetOfCurrentNode);
615 // Find buffer using internal heap manager
616 // Locate the heap using handle = LocateHeap-> BufferHandle
617 // If HeapStatus != HEAP_SYSTEM_ MEM
618 if ((BaseAddress != NULL) && (HeapManager->Signature == HEAP_SIGNATURE_VALID)) {
619 if (OffsetOfCurrentNode == AMD_HEAP_INVALID_HEAP_OFFSET) {
620 HeapLocateFlag = FALSE;
622 while (CurrentNode->BufferHandle != LocateHeap->BufferHandle) {
623 if (CurrentNode->OffsetOfNextNode == AMD_HEAP_INVALID_HEAP_OFFSET) {
624 HeapLocateFlag = FALSE;
627 OffsetOfCurrentNode = CurrentNode->OffsetOfNextNode;
628 CurrentNode = (BUFFER_NODE *) (BaseAddress + OffsetOfCurrentNode);
633 HeapLocateFlag = FALSE;
636 if (HeapLocateFlag) {
637 AlignTo16Byte = CurrentNode->PadSize;
638 LocateHeap->BufferPtr = (UINT8 *) ((UINT8 *) CurrentNode + sizeof (BUFFER_NODE) + SIZE_OF_SENTINEL + AlignTo16Byte);
639 LocateHeap->BufferSize = CurrentNode->BufferSize - NUM_OF_SENTINEL * SIZE_OF_SENTINEL - AlignTo16Byte;
640 return AGESA_SUCCESS;
642 // If HeapStatus == HEAP_SYSTEM_MEM, try callout function
643 if (StdHeader->HeapStatus == HEAP_SYSTEM_MEM) {
644 AgesaBuffer.StdHeader = *StdHeader;
645 AgesaBuffer.BufferHandle = LocateHeap->BufferHandle;
647 AGESA_TESTPOINT (TpIfBeforeLocateHeapBuffer, StdHeader);
648 if (AgesaLocateBuffer (0, &AgesaBuffer) != AGESA_SUCCESS) {
649 LocateHeap->BufferPtr = NULL;
652 LocateHeap->BufferSize = AgesaBuffer.BufferLength;
653 AGESA_TESTPOINT (TpIfAfterLocateHeapBuffer, StdHeader);
655 LocateHeap->BufferPtr = (UINT8 *) (AgesaBuffer.BufferPointer);
656 return AGESA_SUCCESS;
659 // If we are still unable to deallocate the buffer handle, return AGESA_BOUNDS_CHK
660 LocateHeap->BufferPtr = NULL;
661 LocateHeap->BufferSize = 0;
662 if ((BaseAddress != NULL) && (HeapManager->Signature == HEAP_SIGNATURE_VALID)) {
663 PutEventLog (AGESA_BOUNDS_CHK,
664 CPU_ERROR_HEAP_BUFFER_HANDLE_IS_NOT_PRESENT,
665 LocateHeap->BufferHandle, 0, 0, 0, StdHeader);
669 return AGESA_BOUNDS_CHK;
673 /*---------------------------------------------------------------------------------------*/
675 * Get the heap base address
677 * This function will try to locate heap from cache, temp memory, main memory.
678 * The heap signature will be checked for validity on each possible location.
679 * Firstly, try if heap base is in cache by calling the function HeapGetCurrentBase.
680 * Secondly, try if heap base is temp memory by UserOptoions.CfgHeapDramAddress.
681 * Thirdly, try if heap base is in main memory by doing a buffer locate with buffer handle
682 * AMD_HEAP_IN_MAIN_MEMORY_HANDLE.
683 * If no valid heap signature is found in each possible location above, a NULL pointer is returned.
685 * @param[in] StdHeader Config handle for library and services.
687 * @return Heap base address of the executing core's heap.
692 IN AMD_CONFIG_PARAMS *StdHeader
696 HEAP_MANAGER *HeapManager;
697 AGESA_BUFFER_PARAMS AgesaBuffer;
699 // Firstly, we try to see if heap is in cache
700 BaseAddress = HeapGetCurrentBase (StdHeader);
701 HeapManager = (HEAP_MANAGER *) BaseAddress;
703 if ((HeapManager->Signature != HEAP_SIGNATURE_VALID) &&
704 (StdHeader->HeapStatus != HEAP_DO_NOT_EXIST_YET) &&
705 (StdHeader->HeapStatus != HEAP_LOCAL_CACHE)) {
706 // Secondly, we try to see if heap is in temp memory
707 BaseAddress = UserOptions.CfgHeapDramAddress;
708 HeapManager = (HEAP_MANAGER *) BaseAddress;
709 if (HeapManager->Signature != HEAP_SIGNATURE_VALID) {
710 // Thirdly, we try to see if heap in main memory
711 // by locating with external buffer manager (IBV)
712 AgesaBuffer.StdHeader = *StdHeader;
713 AgesaBuffer.BufferHandle = AMD_HEAP_IN_MAIN_MEMORY_HANDLE;
714 if (AgesaLocateBuffer (0, &AgesaBuffer) == AGESA_SUCCESS) {
715 BaseAddress = (UINT64) AgesaBuffer.BufferPointer;
716 HeapManager = (HEAP_MANAGER *) BaseAddress;
717 if (HeapManager->Signature != HEAP_SIGNATURE_VALID) {
718 // No valid heap signature ever found, return a NULL pointer
722 // No heap buffer is allocated by external manager (IBV), return a NULL pointer
731 /*---------------------------------------------------------------------------------------
732 * L O C A L F U N C T I O N S
733 *---------------------------------------------------------------------------------------
735 /* -----------------------------------------------------------------------------*/
738 * DeleteFreeSpaceNode
741 * Delete a free space node from free space chain
744 * @param[in] StdHeader Config handle for library and services.
745 * @param[in] OffsetOfDeletedNode Offset of deleted node.
752 DeleteFreeSpaceNode (
753 IN AMD_CONFIG_PARAMS *StdHeader,
754 IN UINT32 OffsetOfDeletedNode
758 UINT32 OffsetOfPreviousNode;
759 UINT32 OffsetOfCurrentNode;
760 HEAP_MANAGER *HeapManager;
761 BUFFER_NODE *CurrentFreeSpaceNode;
762 BUFFER_NODE *PreviousFreeSpaceNode;
765 BaseAddress = (UINT8 *) StdHeader->HeapBasePtr;
766 HeapManager = (HEAP_MANAGER *) BaseAddress;
768 OffsetOfPreviousNode = AMD_HEAP_INVALID_HEAP_OFFSET;
769 OffsetOfCurrentNode = HeapManager->FirstFreeSpaceOffset;
771 // After AmdInitEnv, there is no free space provided for HeapAllocateBuffer.
772 // Hence if the FirstFreeSpaceOffset is AMD_HEAP_INVALID_HEAP_OFFSET, then
773 // no need to do more on delete node.
775 if (OffsetOfCurrentNode != AMD_HEAP_INVALID_HEAP_OFFSET) {
776 CurrentFreeSpaceNode = (BUFFER_NODE *) (BaseAddress + OffsetOfCurrentNode);
777 while ((OffsetOfCurrentNode != AMD_HEAP_INVALID_HEAP_OFFSET) && (OffsetOfCurrentNode != OffsetOfDeletedNode)) {
778 OffsetOfPreviousNode = OffsetOfCurrentNode;
779 OffsetOfCurrentNode = CurrentFreeSpaceNode->OffsetOfNextNode;
780 CurrentFreeSpaceNode = (BUFFER_NODE *) (BaseAddress + OffsetOfCurrentNode);
782 if (OffsetOfCurrentNode != AMD_HEAP_INVALID_HEAP_OFFSET) {
783 if (OffsetOfPreviousNode == AMD_HEAP_INVALID_HEAP_OFFSET) {
784 HeapManager->FirstFreeSpaceOffset = CurrentFreeSpaceNode->OffsetOfNextNode;
786 PreviousFreeSpaceNode = (BUFFER_NODE *) (BaseAddress + OffsetOfPreviousNode);
787 PreviousFreeSpaceNode->OffsetOfNextNode = CurrentFreeSpaceNode->OffsetOfNextNode;
794 /* -----------------------------------------------------------------------------*/
797 * InsertFreeSpaceNode
800 * Insert a free space node to free space chain, size order
803 * @param[in] StdHeader Config handle for library and services.
804 * @param[in] OffsetOfInsertNode Offset of inserted node.
811 InsertFreeSpaceNode (
812 IN AMD_CONFIG_PARAMS *StdHeader,
813 IN UINT32 OffsetOfInsertNode
817 UINT32 OffsetOfPreviousNode;
818 UINT32 OffsetOfCurrentNode;
819 HEAP_MANAGER *HeapManager;
820 BUFFER_NODE *CurrentFreeSpaceNode;
821 BUFFER_NODE *PreviousFreeSpaceNode;
822 BUFFER_NODE *InsertedFreeSpaceNode;
824 BaseAddress = (UINT8 *) StdHeader->HeapBasePtr;
825 HeapManager = (HEAP_MANAGER *) BaseAddress;
827 OffsetOfPreviousNode = AMD_HEAP_INVALID_HEAP_OFFSET;
828 OffsetOfCurrentNode = HeapManager->FirstFreeSpaceOffset;
829 CurrentFreeSpaceNode = (BUFFER_NODE *) (BaseAddress + OffsetOfCurrentNode);
830 InsertedFreeSpaceNode = (BUFFER_NODE *) (BaseAddress + OffsetOfInsertNode);
831 while ((OffsetOfCurrentNode != AMD_HEAP_INVALID_HEAP_OFFSET) &&
832 (CurrentFreeSpaceNode->BufferSize < InsertedFreeSpaceNode->BufferSize)) {
833 OffsetOfPreviousNode = OffsetOfCurrentNode;
834 OffsetOfCurrentNode = CurrentFreeSpaceNode->OffsetOfNextNode;
835 CurrentFreeSpaceNode = (BUFFER_NODE *) (BaseAddress + OffsetOfCurrentNode);
837 InsertedFreeSpaceNode->OffsetOfNextNode = OffsetOfCurrentNode;
838 if (OffsetOfPreviousNode == AMD_HEAP_INVALID_HEAP_OFFSET) {
839 HeapManager->FirstFreeSpaceOffset = OffsetOfInsertNode;
841 PreviousFreeSpaceNode = (BUFFER_NODE *) (BaseAddress + OffsetOfPreviousNode);
842 PreviousFreeSpaceNode->OffsetOfNextNode = OffsetOfInsertNode;
847 /*---------------------------------------------------------------------------------------*/
849 * Determines the base address of the executing core's heap.
851 * This function uses the executing core's socket/core numbers to determine
852 * where it's heap should be located.
854 * @param[in] StdHeader Config handle for library and services.
856 * @return A pointer to the executing core's heap.
862 IN AMD_CONFIG_PARAMS *StdHeader
865 UINT32 SystemCoreNumber;
867 AGESA_STATUS IgnoredStatus;
868 CPU_SPECIFIC_SERVICES *FamilyServices;
870 if (IsBsp (StdHeader, &IgnoredStatus)) {
871 ReturnPtr = AMD_HEAP_START_ADDRESS;
873 GetCpuServicesOfCurrentCore ((CONST CPU_SPECIFIC_SERVICES **)&FamilyServices, StdHeader);
874 ASSERT (FamilyServices != NULL);
876 SystemCoreNumber = FamilyServices->GetApCoreNumber (FamilyServices, StdHeader);
877 ASSERT (SystemCoreNumber != 0);
878 ASSERT (SystemCoreNumber < 64);
879 ReturnPtr = ((SystemCoreNumber * AMD_HEAP_SIZE_PER_CORE) + AMD_HEAP_START_ADDRESS);
881 ASSERT (ReturnPtr <= ((AMD_HEAP_REGION_END_ADDRESS + 1) - AMD_HEAP_SIZE_PER_CORE));