AMD Agesa macro expansion fix
[coreboot.git] / src / vendorcode / amd / agesa / f12 / Proc / CPU / heapManager.c
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: 44324 $   @e \$Date: 2010-12-22 17:16:51 +0800 (Wed, 22 Dec 2010) $
13  *
14  */
15 /*******************************************************************************
16  *
17  * Copyright (c) 2011, Advanced Micro Devices, Inc.
18  * All rights reserved.
19  *
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.
30  *
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  ******************************************************************************
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);
158   HeapBufferPtr = (UINT8 *) StdHeader->HeapBasePtr;
159
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;
175       }
176     }
177   }
178
179   // Set variable MTRR base and mask
180   MsrData = ((UINT64) HeapBufferPtr & CacheInfoPtr->HeapBaseMask);
181   MsrMask = CacheInfoPtr->VariableMtrrHeapMask & (UINT64) 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
191   // Enable variable MTTRs
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_ERROR       Heap is invaild
257  *
258  */
259 AGESA_STATUS
260 HeapAllocateBuffer (
261   IN OUT   ALLOCATE_HEAP_PARAMS *AllocateHeapParams,
262   IN OUT   AMD_CONFIG_PARAMS *StdHeader
263   )
264 {
265   UINT8 *BaseAddress;
266   UINT8  AlignTo16Byte;
267   UINT32 RemainSize;
268   UINT32 OffsetOfSplitNode;
269   UINT32 OffsetOfNode;
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;
276
277   ASSERT (StdHeader != NULL);
278
279   // At this stage we will decide to either use external (IBV) heap manger
280   // or internal (AGESA) heap manager.
281
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;
288
289     AGESA_TESTPOINT (TpIfBeforeAllocateHeapBuffer, StdHeader);
290     if (AgesaAllocateBuffer (0, &AgesaBuffer) != AGESA_SUCCESS) {
291       AllocateHeapParams->BufferPtr = NULL;
292       return AGESA_ERROR;
293     }
294     AGESA_TESTPOINT (TpIfAfterAllocateHeapBuffer, StdHeader);
295
296     AllocateHeapParams->BufferPtr = (UINT8 *) (AgesaBuffer.BufferPointer);
297     return AGESA_SUCCESS;
298   }
299
300   // If (StdHeader->HeapStatus != HEAP_SYSTEM_MEM), then allocated buffer
301   // using following AGESA Heap Manager code.
302
303   // Buffer pointer is NULL unless we return a buffer.
304   AlignTo16Byte = 0;
305   AllocateHeapParams->BufferPtr = NULL;
306   AllocateHeapParams->RequestedBufferSize += NUM_OF_SENTINEL * SIZE_OF_SENTINEL;
307
308   // Get base address
309   BaseAddress = (UINT8 *) StdHeader->HeapBasePtr;
310   HeapManager = (HEAP_MANAGER *) BaseAddress;
311
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
319       ASSERT (FALSE);
320       return AGESA_ERROR;
321     }
322     StdHeader->HeapBasePtr = (UINT64) BaseAddress;
323   }
324
325   // Allocate
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;
336       } else {
337         CurrentBufferNode = (BUFFER_NODE *) (BaseAddress + CurrentBufferNode->OffsetOfNextNode);
338       }
339     }
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;
345     }
346   }
347
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) {
355       break;
356     }
357     AllocateHeapParams->RequestedBufferSize = (UINT32) (AllocateHeapParams->RequestedBufferSize - AlignTo16Byte);
358     OffsetOfNode = FreeSpaceNode->OffsetOfNextNode;
359     FreeSpaceNode = (BUFFER_NODE *) (BaseAddress + OffsetOfNode);
360   }
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;
367   } else {
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);
374     } else {
375       CurrentBufferNode->OffsetOfNextNode = OffsetOfNode;
376     }
377     // New buffer size
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);
385     } else {
386       // Remain size is less than BUFFER_NODE, we use whole size instead of requested size.
387       NewBufferNode->BufferSize = FreeSpaceNode->BufferSize;
388     }
389   }
390
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;
395   } else {
396     NewBufferNode->Persist = HEAP_LOCAL_CACHE;
397   }
398   NewBufferNode->OffsetOfNextNode = AMD_HEAP_INVALID_HEAP_OFFSET;
399   NewBufferNode->PadSize = AlignTo16Byte;
400
401   // Clear to 0x00
402   LibAmdMemFill ((VOID *) ((UINT8 *) NewBufferNode + sizeof (BUFFER_NODE)), 0x00, NewBufferNode->BufferSize, StdHeader);
403
404   // Debug feature
405   SET_SENTINEL_BEFORE (NewBufferNode, AlignTo16Byte);
406   SET_SENTINEL_AFTER (NewBufferNode);
407
408   // Update global variables
409   HeapManager->UsedSize += NewBufferNode->BufferSize + sizeof (BUFFER_NODE);
410
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);
414
415   return AGESA_SUCCESS;
416 }
417
418
419 /*---------------------------------------------------------------------------------------*/
420 /**
421  * Deallocates a previously allocated buffer in the heap
422  *
423  * This function will deallocate buffer either by using internal 'AGESA' heapmanager
424  * or by using externa (IBV) heapmanager.
425  *
426  * @param[in]      BufferHandle      Handle of the buffer to free.
427  * @param[in]      StdHeader         Config handle for library and services.
428  *
429  * @retval         AGESA_SUCCESS     No error
430  * @retval         AGESA_BOUNDS_CHK  Handle does not exist on the heap
431  *
432  */
433 AGESA_STATUS
434 HeapDeallocateBuffer (
435   IN       UINT32 BufferHandle,
436   IN       AMD_CONFIG_PARAMS *StdHeader
437   )
438 {
439   UINT8 *BaseAddress;
440   UINT32 NodeSize;
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;
450
451   ASSERT (StdHeader != NULL);
452
453   HeapLocateFlag = TRUE;
454   BaseAddress = (UINT8 *) StdHeader->HeapBasePtr;
455   HeapManager = (HEAP_MANAGER *) BaseAddress;
456
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
464       ASSERT (FALSE);
465       return AGESA_ERROR;
466     }
467     StdHeader->HeapBasePtr = (UINT64) BaseAddress;
468   }
469
470   OffsetOfPreviousNode = AMD_HEAP_INVALID_HEAP_OFFSET;
471   OffsetOfCurrentNode =  HeapManager->FirstActiveBufferOffset;
472   CurrentNode = (BUFFER_NODE *) (BaseAddress + OffsetOfCurrentNode);
473
474   // Locate heap
475   if ((BaseAddress != NULL) && (HeapManager->Signature == HEAP_SIGNATURE_VALID)) {
476     if (OffsetOfCurrentNode == AMD_HEAP_INVALID_HEAP_OFFSET) {
477       HeapLocateFlag = FALSE;
478     } else {
479       while (CurrentNode->BufferHandle != BufferHandle) {
480         if (CurrentNode->OffsetOfNextNode == AMD_HEAP_INVALID_HEAP_OFFSET) {
481           HeapLocateFlag = FALSE;
482           break;
483         } else {
484           OffsetOfPreviousNode = OffsetOfCurrentNode;
485           OffsetOfCurrentNode = CurrentNode->OffsetOfNextNode;
486           CurrentNode = (BUFFER_NODE *) (BaseAddress + OffsetOfCurrentNode);
487         }
488       }
489     }
490   } else {
491     HeapLocateFlag = FALSE;
492   }
493
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;
499     } else {
500       PreviousNode = (BUFFER_NODE *) (BaseAddress + OffsetOfPreviousNode);
501       PreviousNode->OffsetOfNextNode = CurrentNode->OffsetOfNextNode;
502     }
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;
519       }
520       OffsetOfFreeSpaceNode = FreeSpaceNode->OffsetOfNextNode;
521       FreeSpaceNode = (BUFFER_NODE *) (BaseAddress + OffsetOfFreeSpaceNode);
522     }
523     InsertFreeSpaceNode (StdHeader, OffsetOfCurrentNode);
524     return AGESA_SUCCESS;
525   } else {
526     // If HeapStatus == HEAP_SYSTEM_MEM, try callout function
527     if (StdHeader->HeapStatus == HEAP_SYSTEM_MEM) {
528       AgesaBuffer.StdHeader = *StdHeader;
529       AgesaBuffer.BufferHandle = BufferHandle;
530
531       AGESA_TESTPOINT (TpIfBeforeDeallocateHeapBuffer, StdHeader);
532       if (AgesaDeallocateBuffer (0, &AgesaBuffer) != AGESA_SUCCESS) {
533         return AGESA_ERROR;
534       }
535       AGESA_TESTPOINT (TpIfAfterDeallocateHeapBuffer, StdHeader);
536
537       return AGESA_SUCCESS;
538     }
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);
544     } else {
545       ASSERT (FALSE);
546     }
547     return AGESA_BOUNDS_CHK;
548   }
549 }
550
551 /*---------------------------------------------------------------------------------------*/
552 /**
553  * Locates a previously allocated buffer on the heap.
554  *
555  * This function searches the heap for a buffer with the desired handle, and
556  * returns a pointer to the buffer.
557  *
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.
561  *
562  * @retval         AGESA_SUCCESS     No error
563  * @retval         AGESA_BOUNDS_CHK  Handle does not exist on the heap
564  *
565  */
566 AGESA_STATUS
567 HeapLocateBuffer (
568   IN OUT   LOCATE_HEAP_PTR *LocateHeap,
569   IN       AMD_CONFIG_PARAMS *StdHeader
570   )
571 {
572   UINT8 *BaseAddress;
573   UINT8  AlignTo16Byte;
574   UINT32 OffsetOfCurrentNode;
575   BOOLEAN HeapLocateFlag;
576   HEAP_MANAGER *HeapManager;
577   BUFFER_NODE *CurrentNode;
578   AGESA_BUFFER_PARAMS  AgesaBuffer;
579
580   ASSERT (StdHeader != NULL);
581
582   HeapLocateFlag = TRUE;
583   BaseAddress = (UINT8 *) StdHeader->HeapBasePtr;
584   HeapManager = (HEAP_MANAGER *) BaseAddress;
585
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
593       ASSERT (FALSE);
594       return AGESA_ERROR;
595     }
596     StdHeader->HeapBasePtr = (UINT64) BaseAddress;
597   }
598   OffsetOfCurrentNode =  HeapManager->FirstActiveBufferOffset;
599   CurrentNode = (BUFFER_NODE *) (BaseAddress + OffsetOfCurrentNode);
600
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;
607     } else {
608       while (CurrentNode->BufferHandle != LocateHeap->BufferHandle) {
609         if (CurrentNode->OffsetOfNextNode == AMD_HEAP_INVALID_HEAP_OFFSET) {
610           HeapLocateFlag = FALSE;
611           break;
612         } else {
613           OffsetOfCurrentNode = CurrentNode->OffsetOfNextNode;
614           CurrentNode = (BUFFER_NODE *) (BaseAddress + OffsetOfCurrentNode);
615         }
616       }
617     }
618   } else {
619     HeapLocateFlag = FALSE;
620   }
621
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;
627   } else {
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;
632
633       AGESA_TESTPOINT (TpIfBeforeLocateHeapBuffer, StdHeader);
634       if (AgesaLocateBuffer (0, &AgesaBuffer) != AGESA_SUCCESS) {
635         LocateHeap->BufferPtr = NULL;
636         return AGESA_ERROR;
637       }
638       LocateHeap->BufferSize = AgesaBuffer.BufferLength;
639       AGESA_TESTPOINT (TpIfAfterLocateHeapBuffer, StdHeader);
640
641       LocateHeap->BufferPtr = (UINT8 *) (AgesaBuffer.BufferPointer);
642       return AGESA_SUCCESS;
643     }
644
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);
652     } else {
653       ASSERT (FALSE);
654     }
655     return AGESA_BOUNDS_CHK;
656   }
657 }
658
659 /*---------------------------------------------------------------------------------------*/
660 /**
661  * Get the heap base address
662  *
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.
670  *
671  * @param[in]      StdHeader      Config handle for library and services.
672  *
673  * @return         Heap base address of the executing core's heap.
674  *
675  */
676 UINT64
677 HeapGetBaseAddress (
678   IN       AMD_CONFIG_PARAMS *StdHeader
679   )
680 {
681   UINT64 BaseAddress;
682   HEAP_MANAGER *HeapManager;
683   AGESA_BUFFER_PARAMS AgesaBuffer;
684
685   // Firstly, we try to see if heap is in cache
686   BaseAddress = HeapGetCurrentBase (StdHeader);
687   HeapManager = (HEAP_MANAGER *) BaseAddress;
688
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
705           BaseAddress = NULL;
706         }
707       } else {
708         // No heap buffer is allocated by external manager (IBV), return a NULL pointer
709         BaseAddress = NULL;
710       }
711     }
712   }
713
714   return BaseAddress;
715 }
716
717 /*---------------------------------------------------------------------------------------
718  *                          L O C A L    F U N C T I O N S
719  *---------------------------------------------------------------------------------------
720  */
721 /* -----------------------------------------------------------------------------*/
722 /**
723  *
724  *  DeleteFreeSpaceNode
725  *
726  *  Description:
727  *    Delete a free space node from free space chain
728  *
729  *  Parameters:
730  * @param[in]      StdHeader             Config handle for library and services.
731  * @param[in]      OffsetOfDeletedNode   Offset of deleted node.
732  *
733  *  Processing:
734  *
735  */
736 VOID
737 STATIC
738 DeleteFreeSpaceNode (
739   IN       AMD_CONFIG_PARAMS *StdHeader,
740   IN       UINT32            OffsetOfDeletedNode
741   )
742 {
743   UINT8 *BaseAddress;
744   UINT32 OffsetOfPreviousNode;
745   UINT32 OffsetOfCurrentNode;
746   HEAP_MANAGER *HeapManager;
747   BUFFER_NODE *CurrentFreeSpaceNode;
748   BUFFER_NODE *PreviousFreeSpaceNode;
749
750
751   BaseAddress = (UINT8 *) StdHeader->HeapBasePtr;
752   HeapManager = (HEAP_MANAGER *) BaseAddress;
753
754   OffsetOfPreviousNode = AMD_HEAP_INVALID_HEAP_OFFSET;
755   OffsetOfCurrentNode = HeapManager->FirstFreeSpaceOffset;
756   //
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.
760   //
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);
767     }
768     if (OffsetOfCurrentNode != AMD_HEAP_INVALID_HEAP_OFFSET) {
769       if (OffsetOfPreviousNode == AMD_HEAP_INVALID_HEAP_OFFSET) {
770         HeapManager->FirstFreeSpaceOffset = CurrentFreeSpaceNode->OffsetOfNextNode;
771       } else {
772         PreviousFreeSpaceNode = (BUFFER_NODE *) (BaseAddress + OffsetOfPreviousNode);
773         PreviousFreeSpaceNode->OffsetOfNextNode = CurrentFreeSpaceNode->OffsetOfNextNode;
774       }
775     }
776   }
777   return;
778 }
779
780 /* -----------------------------------------------------------------------------*/
781 /**
782  *
783  *  InsertFreeSpaceNode
784  *
785  *  Description:
786  *    Insert a free space node to free space chain, size order
787  *
788  *  Parameters:
789  * @param[in]      StdHeader             Config handle for library and services.
790  * @param[in]      OffsetOfInsertNode    Offset of inserted node.
791  *
792  *  Processing:
793  *
794  */
795 VOID
796 STATIC
797 InsertFreeSpaceNode (
798   IN       AMD_CONFIG_PARAMS *StdHeader,
799   IN       UINT32            OffsetOfInsertNode
800   )
801 {
802   UINT8 *BaseAddress;
803   UINT32 OffsetOfPreviousNode;
804   UINT32 OffsetOfCurrentNode;
805   HEAP_MANAGER *HeapManager;
806   BUFFER_NODE *CurrentFreeSpaceNode;
807   BUFFER_NODE *PreviousFreeSpaceNode;
808   BUFFER_NODE *LocalInsertFreeSpaceNode;
809
810   BaseAddress = (UINT8 *) StdHeader->HeapBasePtr;
811   HeapManager = (HEAP_MANAGER *) BaseAddress;
812
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);
822   }
823   LocalInsertFreeSpaceNode->OffsetOfNextNode = OffsetOfCurrentNode;
824   if (OffsetOfPreviousNode == AMD_HEAP_INVALID_HEAP_OFFSET) {
825     HeapManager->FirstFreeSpaceOffset = OffsetOfInsertNode;
826   } else {
827     PreviousFreeSpaceNode = (BUFFER_NODE *) (BaseAddress + OffsetOfPreviousNode);
828     PreviousFreeSpaceNode->OffsetOfNextNode = OffsetOfInsertNode;
829   }
830   return;
831 }
832
833 /*---------------------------------------------------------------------------------------*/
834 /**
835  * Determines the base address of the executing core's heap.
836  *
837  * This function uses the executing core's socket/core numbers to determine
838  * where it's heap should be located.
839  *
840  * @param[in]      StdHeader      Config handle for library and services.
841  *
842  * @return         A pointer to the executing core's heap.
843  *
844  */
845 UINT64
846 STATIC
847 HeapGetCurrentBase (
848   IN       AMD_CONFIG_PARAMS *StdHeader
849   )
850 {
851   UINT32      SystemCoreNumber;
852   UINT64      ReturnPtr;
853   AGESA_STATUS          IgnoredStatus;
854   CPU_SPECIFIC_SERVICES *FamilyServices;
855
856   if (IsBsp (StdHeader, &IgnoredStatus)) {
857     ReturnPtr = AMD_HEAP_START_ADDRESS;
858   } else {
859     GetCpuServicesOfCurrentCore ((const CPU_SPECIFIC_SERVICES **)&FamilyServices, StdHeader);
860     ASSERT (FamilyServices != NULL);
861
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);
866   }
867   ASSERT (ReturnPtr <= ((AMD_HEAP_REGION_END_ADDRESS + 1) - AMD_HEAP_SIZE_PER_CORE));
868   return ReturnPtr;
869 }
870
871