AGESA F15: AMD family15 AGESA code
[coreboot.git] / src / vendorcode / amd / agesa / f15 / 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: 56322 $   @e \$Date: 2011-07-11 16:51:42 -0600 (Mon, 11 Jul 2011) $
13  *
14  */
15 /*******************************************************************************
16  *
17  * Copyright (C) 2012 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 /*----------------------------------------------------------------------------------------
46  *                             M O D U L E S    U S E D
47  *----------------------------------------------------------------------------------------
48  */
49
50 #include "AGESA.h"
51 #include "amdlib.h"
52 #include "Ids.h"
53 #include "cpuRegisters.h"
54 #include "cpuServices.h"
55 #include "GeneralServices.h"
56 #include "heapManager.h"
57 #include "cpuCacheInit.h"
58 #include "cpuFamilyTranslation.h"
59 #include "Filecode.h"
60 CODE_GROUP (G1_PEICC)
61 RDATA_GROUP (G2_PEI)
62
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  *----------------------------------------------------------------------------------------
67  */
68
69
70 /*----------------------------------------------------------------------------------------
71  *                  T Y P E D E F S     A N D     S T R U C T U  R E S
72  *----------------------------------------------------------------------------------------
73  */
74
75
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  *----------------------------------------------------------------------------------------
79  */
80 UINT64
81 STATIC
82 HeapGetCurrentBase (
83   IN       AMD_CONFIG_PARAMS *StdHeader
84   );
85
86 VOID
87 STATIC
88 DeleteFreeSpaceNode (
89   IN       AMD_CONFIG_PARAMS *StdHeader,
90   IN       UINT32            OffsetOfDeletedNode
91   );
92
93 VOID
94 STATIC
95 InsertFreeSpaceNode (
96   IN       AMD_CONFIG_PARAMS *StdHeader,
97   IN       UINT32            OffsetOfInsertNode
98   );
99
100 /*----------------------------------------------------------------------------------------
101  *                          P U B L I C     F U N C T I O N S
102  *----------------------------------------------------------------------------------------
103  */
104
105 /*----------------------------------------------------------------------------------------
106  *                          E X P O R T E D    F U N C T I O N S
107  *----------------------------------------------------------------------------------------
108  */
109 extern BUILD_OPT_CFG UserOptions;
110
111 /*---------------------------------------------------------------------------------------*/
112 /**
113  *  This function initializes the heap for each CPU core.
114  *
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.
119  *
120  *  @param[in]  StdHeader          Handle of Header for calling lib functions and services.
121  *
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.
125  *
126  */
127 AGESA_STATUS
128 HeapManagerInit (
129   IN       AMD_CONFIG_PARAMS *StdHeader
130   )
131 {
132   // First Time Initialization
133   // Note: First 16 bytes of buffer is reserved for Heap Manager use
134   UINT16                HeapAlreadyInitSizeDword;
135   UINT32                HeapAlreadyRead;
136   UINT8                 L2LineSize;
137   UINT8                 *HeapBufferPtr;
138   UINT8                 *HeapInitPtr;
139   UINT32                *HeapDataPtr;
140   UINT64                MsrData;
141   UINT64                MsrMask;
142   UINT8                 Ignored;
143   CPUID_DATA            CpuId;
144   BUFFER_NODE           *FreeSpaceNode;
145   CACHE_INFO            *CacheInfoPtr;
146   AGESA_STATUS          IgnoredSts;
147   CPU_SPECIFIC_SERVICES *FamilySpecificServices;
148   CPU_LOGICAL_ID        CpuFamilyRevision;
149
150   // Check whether this is a known processor family.
151   GetLogicalIdOfCurrentCore (&CpuFamilyRevision, StdHeader);
152   if ((CpuFamilyRevision.Family == 0) && (CpuFamilyRevision.Revision == 0)) {
153     IDS_ERROR_TRAP;
154     return AGESA_FATAL;
155   }
156
157   GetCpuServicesOfCurrentCore ((CONST CPU_SPECIFIC_SERVICES **)&FamilySpecificServices, StdHeader);
158   FamilySpecificServices->GetCacheInfo (FamilySpecificServices, (CONST VOID **) &CacheInfoPtr, &Ignored, StdHeader);
159   HeapBufferPtr = (UINT8 *) StdHeader->HeapBasePtr;
160
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;
176       }
177     }
178   }
179
180   // Set variable MTRR base and mask
181   MsrData = ((UINT64) HeapBufferPtr & CacheInfoPtr->HeapBaseMask);
182   MsrMask = CacheInfoPtr->VariableMtrrHeapMask & AMD_HEAP_MTRR_MASK;
183
184   MsrData |= 0x06;
185   LibAmdMsrWrite (AMD_MTRR_VARIABLE_HEAP_BASE, &MsrData, StdHeader);
186   LibAmdMsrWrite (AMD_MTRR_VARIABLE_HEAP_MASK, &MsrMask, StdHeader);
187
188   // Set top of memory to a temp value
189   MsrData = (UINT64) (AMD_TEMP_TOM);
190   LibAmdMsrWrite (TOP_MEM, &MsrData, StdHeader);
191
192   // Enable variable MTTRs
193   LibAmdMsrRead (SYS_CFG, &MsrData, StdHeader);
194   MsrData |= AMD_VAR_MTRR_ENABLE_BIT;
195   LibAmdMsrWrite (SYS_CFG, &MsrData, StdHeader);
196
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;
206   }
207
208   HeapDataPtr = (UINT32 *) HeapBufferPtr;
209   for (HeapAlreadyInitSizeDword = 0; HeapAlreadyInitSizeDword < AMD_HEAP_SIZE_DWORD_PER_CORE; HeapAlreadyInitSizeDword++) {
210     *HeapDataPtr = 0;
211     HeapDataPtr++;
212   }
213
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;
228
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);
234   }
235   EventLogInitialization (StdHeader);
236   return AGESA_SUCCESS;
237 }
238
239
240 /*---------------------------------------------------------------------------------------*/
241 /**
242  * Allocates space for a new buffer in the heap
243  *
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.
248  *
249  * @param[in,out]  AllocateHeapParams structure pointer containing the size of the
250  *                                   desired new region, its handle, and the
251  *                                   return pointer.
252  * @param[in,out]  StdHeader         Config handle for library and services.
253  *
254  * @retval         AGESA_SUCCESS     No error
255  * @retval         AGESA_BOUNDS_CHK  Handle already exists, or not enough
256  *                                   free space
257  * @retval         AGESA_UNSUPPORTED Do not support this kind of heap allocation
258  * @retval         AGESA_ERROR       Heap is invaild
259  *
260  */
261 AGESA_STATUS
262 HeapAllocateBuffer (
263   IN OUT   ALLOCATE_HEAP_PARAMS *AllocateHeapParams,
264   IN OUT   AMD_CONFIG_PARAMS *StdHeader
265   )
266 {
267   UINT8 *BaseAddress;
268   UINT8  AlignTo16Byte;
269   UINT8  CalloutFcnData;
270   UINT32 RemainSize;
271   UINT32 OffsetOfSplitNode;
272   UINT32 OffsetOfNode;
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;
279
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;
285     }
286   }
287
288   // At this stage we will decide to either use external (IBV) heap manger
289   // or internal (AGESA) heap manager.
290
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;
297
298     if (AllocateHeapParams->Persist == HEAP_RUNTIME_SYSTEM_MEM) {
299       CalloutFcnData = HEAP_CALLOUT_RUNTIME;
300     } else {
301       CalloutFcnData = HEAP_CALLOUT_BOOTTIME;
302     }
303     AGESA_TESTPOINT (TpIfBeforeAllocateHeapBuffer, StdHeader);
304     if (AgesaAllocateBuffer (CalloutFcnData, &AgesaBuffer) != AGESA_SUCCESS) {
305       AllocateHeapParams->BufferPtr = NULL;
306       return AGESA_ERROR;
307     }
308     AGESA_TESTPOINT (TpIfAfterAllocateHeapBuffer, StdHeader);
309
310     AllocateHeapParams->BufferPtr = (UINT8 *) (AgesaBuffer.BufferPointer);
311     return AGESA_SUCCESS;
312   }
313
314   // If (StdHeader->HeapStatus != HEAP_SYSTEM_MEM), then allocated buffer
315   // using following AGESA Heap Manager code.
316
317   // Buffer pointer is NULL unless we return a buffer.
318   AlignTo16Byte = 0;
319   AllocateHeapParams->BufferPtr = NULL;
320   AllocateHeapParams->RequestedBufferSize += NUM_OF_SENTINEL * SIZE_OF_SENTINEL;
321
322   // Get base address
323   BaseAddress = (UINT8 *) StdHeader->HeapBasePtr;
324   HeapManager = (HEAP_MANAGER *) BaseAddress;
325
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
333       ASSERT (FALSE);
334       return AGESA_ERROR;
335     }
336     StdHeader->HeapBasePtr = (UINT64) BaseAddress;
337   }
338
339   // Allocate
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;
350       } else {
351         CurrentBufferNode = (BUFFER_NODE *) (BaseAddress + CurrentBufferNode->OffsetOfNextNode);
352       }
353     }
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;
359     }
360   }
361
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) {
369       break;
370     }
371     AllocateHeapParams->RequestedBufferSize = (UINT32) (AllocateHeapParams->RequestedBufferSize - AlignTo16Byte);
372     OffsetOfNode = FreeSpaceNode->OffsetOfNextNode;
373     FreeSpaceNode = (BUFFER_NODE *) (BaseAddress + OffsetOfNode);
374   }
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;
381   } else {
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);
388     } else {
389       CurrentBufferNode->OffsetOfNextNode = OffsetOfNode;
390     }
391     // New buffer size
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);
399     } else {
400       // Remain size is less than BUFFER_NODE, we use whole size instead of requested size.
401       NewBufferNode->BufferSize = FreeSpaceNode->BufferSize;
402     }
403   }
404
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;
409   } else {
410     NewBufferNode->Persist = HEAP_LOCAL_CACHE;
411   }
412   NewBufferNode->OffsetOfNextNode = AMD_HEAP_INVALID_HEAP_OFFSET;
413   NewBufferNode->PadSize = AlignTo16Byte;
414
415   // Clear to 0x00
416   LibAmdMemFill ((VOID *) ((UINT8 *) NewBufferNode + sizeof (BUFFER_NODE)), 0x00, NewBufferNode->BufferSize, StdHeader);
417
418   // Debug feature
419   SET_SENTINEL_BEFORE (NewBufferNode, AlignTo16Byte);
420   SET_SENTINEL_AFTER (NewBufferNode);
421
422   // Update global variables
423   HeapManager->UsedSize += NewBufferNode->BufferSize + sizeof (BUFFER_NODE);
424
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);
428
429   return AGESA_SUCCESS;
430 }
431
432
433 /*---------------------------------------------------------------------------------------*/
434 /**
435  * Deallocates a previously allocated buffer in the heap
436  *
437  * This function will deallocate buffer either by using internal 'AGESA' heapmanager
438  * or by using externa (IBV) heapmanager.
439  *
440  * @param[in]      BufferHandle      Handle of the buffer to free.
441  * @param[in]      StdHeader         Config handle for library and services.
442  *
443  * @retval         AGESA_SUCCESS     No error
444  * @retval         AGESA_BOUNDS_CHK  Handle does not exist on the heap
445  *
446  */
447 AGESA_STATUS
448 HeapDeallocateBuffer (
449   IN       UINT32 BufferHandle,
450   IN       AMD_CONFIG_PARAMS *StdHeader
451   )
452 {
453   UINT8 *BaseAddress;
454   UINT32 NodeSize;
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;
464
465   ASSERT (StdHeader != NULL);
466
467   HeapLocateFlag = TRUE;
468   BaseAddress = (UINT8 *) StdHeader->HeapBasePtr;
469   HeapManager = (HEAP_MANAGER *) BaseAddress;
470
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
478       ASSERT (FALSE);
479       return AGESA_ERROR;
480     }
481     StdHeader->HeapBasePtr = (UINT64) BaseAddress;
482   }
483
484   OffsetOfPreviousNode = AMD_HEAP_INVALID_HEAP_OFFSET;
485   OffsetOfCurrentNode =  HeapManager->FirstActiveBufferOffset;
486   CurrentNode = (BUFFER_NODE *) (BaseAddress + OffsetOfCurrentNode);
487
488   // Locate heap
489   if ((BaseAddress != NULL) && (HeapManager->Signature == HEAP_SIGNATURE_VALID)) {
490     if (OffsetOfCurrentNode == AMD_HEAP_INVALID_HEAP_OFFSET) {
491       HeapLocateFlag = FALSE;
492     } else {
493       while (CurrentNode->BufferHandle != BufferHandle) {
494         if (CurrentNode->OffsetOfNextNode == AMD_HEAP_INVALID_HEAP_OFFSET) {
495           HeapLocateFlag = FALSE;
496           break;
497         } else {
498           OffsetOfPreviousNode = OffsetOfCurrentNode;
499           OffsetOfCurrentNode = CurrentNode->OffsetOfNextNode;
500           CurrentNode = (BUFFER_NODE *) (BaseAddress + OffsetOfCurrentNode);
501         }
502       }
503     }
504   } else {
505     HeapLocateFlag = FALSE;
506   }
507
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;
513     } else {
514       PreviousNode = (BUFFER_NODE *) (BaseAddress + OffsetOfPreviousNode);
515       PreviousNode->OffsetOfNextNode = CurrentNode->OffsetOfNextNode;
516     }
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;
533       }
534       OffsetOfFreeSpaceNode = FreeSpaceNode->OffsetOfNextNode;
535       FreeSpaceNode = (BUFFER_NODE *) (BaseAddress + OffsetOfFreeSpaceNode);
536     }
537     InsertFreeSpaceNode (StdHeader, OffsetOfCurrentNode);
538     return AGESA_SUCCESS;
539   } else {
540     // If HeapStatus == HEAP_SYSTEM_MEM, try callout function
541     if (StdHeader->HeapStatus == HEAP_SYSTEM_MEM) {
542       AgesaBuffer.StdHeader = *StdHeader;
543       AgesaBuffer.BufferHandle = BufferHandle;
544
545       AGESA_TESTPOINT (TpIfBeforeDeallocateHeapBuffer, StdHeader);
546       if (AgesaDeallocateBuffer (0, &AgesaBuffer) != AGESA_SUCCESS) {
547         return AGESA_ERROR;
548       }
549       AGESA_TESTPOINT (TpIfAfterDeallocateHeapBuffer, StdHeader);
550
551       return AGESA_SUCCESS;
552     }
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);
558     } else {
559       ASSERT (FALSE);
560     }
561     return AGESA_BOUNDS_CHK;
562   }
563 }
564
565 /*---------------------------------------------------------------------------------------*/
566 /**
567  * Locates a previously allocated buffer on the heap.
568  *
569  * This function searches the heap for a buffer with the desired handle, and
570  * returns a pointer to the buffer.
571  *
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.
575  *
576  * @retval         AGESA_SUCCESS     No error
577  * @retval         AGESA_BOUNDS_CHK  Handle does not exist on the heap
578  *
579  */
580 AGESA_STATUS
581 HeapLocateBuffer (
582   IN OUT   LOCATE_HEAP_PTR *LocateHeap,
583   IN       AMD_CONFIG_PARAMS *StdHeader
584   )
585 {
586   UINT8 *BaseAddress;
587   UINT8  AlignTo16Byte;
588   UINT32 OffsetOfCurrentNode;
589   BOOLEAN HeapLocateFlag;
590   HEAP_MANAGER *HeapManager;
591   BUFFER_NODE *CurrentNode;
592   AGESA_BUFFER_PARAMS  AgesaBuffer;
593
594   ASSERT (StdHeader != NULL);
595
596   HeapLocateFlag = TRUE;
597   BaseAddress = (UINT8 *) StdHeader->HeapBasePtr;
598   HeapManager = (HEAP_MANAGER *) BaseAddress;
599
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
607       ASSERT (FALSE);
608       return AGESA_ERROR;
609     }
610     StdHeader->HeapBasePtr = (UINT64) BaseAddress;
611   }
612   OffsetOfCurrentNode =  HeapManager->FirstActiveBufferOffset;
613   CurrentNode = (BUFFER_NODE *) (BaseAddress + OffsetOfCurrentNode);
614
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;
621     } else {
622       while (CurrentNode->BufferHandle != LocateHeap->BufferHandle) {
623         if (CurrentNode->OffsetOfNextNode == AMD_HEAP_INVALID_HEAP_OFFSET) {
624           HeapLocateFlag = FALSE;
625           break;
626         } else {
627           OffsetOfCurrentNode = CurrentNode->OffsetOfNextNode;
628           CurrentNode = (BUFFER_NODE *) (BaseAddress + OffsetOfCurrentNode);
629         }
630       }
631     }
632   } else {
633     HeapLocateFlag = FALSE;
634   }
635
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;
641   } else {
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;
646
647       AGESA_TESTPOINT (TpIfBeforeLocateHeapBuffer, StdHeader);
648       if (AgesaLocateBuffer (0, &AgesaBuffer) != AGESA_SUCCESS) {
649         LocateHeap->BufferPtr = NULL;
650         return AGESA_ERROR;
651       }
652       LocateHeap->BufferSize = AgesaBuffer.BufferLength;
653       AGESA_TESTPOINT (TpIfAfterLocateHeapBuffer, StdHeader);
654
655       LocateHeap->BufferPtr = (UINT8 *) (AgesaBuffer.BufferPointer);
656       return AGESA_SUCCESS;
657     }
658
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);
666     } else {
667       ASSERT (FALSE);
668     }
669     return AGESA_BOUNDS_CHK;
670   }
671 }
672
673 /*---------------------------------------------------------------------------------------*/
674 /**
675  * Get the heap base address
676  *
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.
684  *
685  * @param[in]      StdHeader      Config handle for library and services.
686  *
687  * @return         Heap base address of the executing core's heap.
688  *
689  */
690 UINT64
691 HeapGetBaseAddress (
692   IN       AMD_CONFIG_PARAMS *StdHeader
693   )
694 {
695   UINT64 BaseAddress;
696   HEAP_MANAGER *HeapManager;
697   AGESA_BUFFER_PARAMS AgesaBuffer;
698
699   // Firstly, we try to see if heap is in cache
700   BaseAddress = HeapGetCurrentBase (StdHeader);
701   HeapManager = (HEAP_MANAGER *) BaseAddress;
702
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
719           BaseAddress = 0;
720         }
721       } else {
722         // No heap buffer is allocated by external manager (IBV), return a NULL pointer
723         BaseAddress = 0;
724       }
725     }
726   }
727
728   return BaseAddress;
729 }
730
731 /*---------------------------------------------------------------------------------------
732  *                          L O C A L    F U N C T I O N S
733  *---------------------------------------------------------------------------------------
734  */
735 /* -----------------------------------------------------------------------------*/
736 /**
737  *
738  *  DeleteFreeSpaceNode
739  *
740  *  Description:
741  *    Delete a free space node from free space chain
742  *
743  *  Parameters:
744  * @param[in]      StdHeader             Config handle for library and services.
745  * @param[in]      OffsetOfDeletedNode   Offset of deleted node.
746  *
747  *  Processing:
748  *
749  */
750 VOID
751 STATIC
752 DeleteFreeSpaceNode (
753   IN       AMD_CONFIG_PARAMS *StdHeader,
754   IN       UINT32            OffsetOfDeletedNode
755   )
756 {
757   UINT8 *BaseAddress;
758   UINT32 OffsetOfPreviousNode;
759   UINT32 OffsetOfCurrentNode;
760   HEAP_MANAGER *HeapManager;
761   BUFFER_NODE *CurrentFreeSpaceNode;
762   BUFFER_NODE *PreviousFreeSpaceNode;
763
764
765   BaseAddress = (UINT8 *) StdHeader->HeapBasePtr;
766   HeapManager = (HEAP_MANAGER *) BaseAddress;
767
768   OffsetOfPreviousNode = AMD_HEAP_INVALID_HEAP_OFFSET;
769   OffsetOfCurrentNode = HeapManager->FirstFreeSpaceOffset;
770   //
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.
774   //
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);
781     }
782     if (OffsetOfCurrentNode != AMD_HEAP_INVALID_HEAP_OFFSET) {
783       if (OffsetOfPreviousNode == AMD_HEAP_INVALID_HEAP_OFFSET) {
784         HeapManager->FirstFreeSpaceOffset = CurrentFreeSpaceNode->OffsetOfNextNode;
785       } else {
786         PreviousFreeSpaceNode = (BUFFER_NODE *) (BaseAddress + OffsetOfPreviousNode);
787         PreviousFreeSpaceNode->OffsetOfNextNode = CurrentFreeSpaceNode->OffsetOfNextNode;
788       }
789     }
790   }
791   return;
792 }
793
794 /* -----------------------------------------------------------------------------*/
795 /**
796  *
797  *  InsertFreeSpaceNode
798  *
799  *  Description:
800  *    Insert a free space node to free space chain, size order
801  *
802  *  Parameters:
803  * @param[in]      StdHeader             Config handle for library and services.
804  * @param[in]      OffsetOfInsertNode    Offset of inserted node.
805  *
806  *  Processing:
807  *
808  */
809 VOID
810 STATIC
811 InsertFreeSpaceNode (
812   IN       AMD_CONFIG_PARAMS *StdHeader,
813   IN       UINT32            OffsetOfInsertNode
814   )
815 {
816   UINT8 *BaseAddress;
817   UINT32 OffsetOfPreviousNode;
818   UINT32 OffsetOfCurrentNode;
819   HEAP_MANAGER *HeapManager;
820   BUFFER_NODE *CurrentFreeSpaceNode;
821   BUFFER_NODE *PreviousFreeSpaceNode;
822   BUFFER_NODE *InsertedFreeSpaceNode;
823
824   BaseAddress = (UINT8 *) StdHeader->HeapBasePtr;
825   HeapManager = (HEAP_MANAGER *) BaseAddress;
826
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);
836   }
837   InsertedFreeSpaceNode->OffsetOfNextNode = OffsetOfCurrentNode;
838   if (OffsetOfPreviousNode == AMD_HEAP_INVALID_HEAP_OFFSET) {
839     HeapManager->FirstFreeSpaceOffset = OffsetOfInsertNode;
840   } else {
841     PreviousFreeSpaceNode = (BUFFER_NODE *) (BaseAddress + OffsetOfPreviousNode);
842     PreviousFreeSpaceNode->OffsetOfNextNode = OffsetOfInsertNode;
843   }
844   return;
845 }
846
847 /*---------------------------------------------------------------------------------------*/
848 /**
849  * Determines the base address of the executing core's heap.
850  *
851  * This function uses the executing core's socket/core numbers to determine
852  * where it's heap should be located.
853  *
854  * @param[in]      StdHeader      Config handle for library and services.
855  *
856  * @return         A pointer to the executing core's heap.
857  *
858  */
859 UINT64
860 STATIC
861 HeapGetCurrentBase (
862   IN       AMD_CONFIG_PARAMS *StdHeader
863   )
864 {
865   UINT32      SystemCoreNumber;
866   UINT64      ReturnPtr;
867   AGESA_STATUS          IgnoredStatus;
868   CPU_SPECIFIC_SERVICES *FamilyServices;
869
870   if (IsBsp (StdHeader, &IgnoredStatus)) {
871     ReturnPtr = AMD_HEAP_START_ADDRESS;
872   } else {
873     GetCpuServicesOfCurrentCore ((CONST CPU_SPECIFIC_SERVICES **)&FamilyServices, StdHeader);
874     ASSERT (FamilyServices != NULL);
875
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);
880   }
881   ASSERT (ReturnPtr <= ((AMD_HEAP_REGION_END_ADDRESS + 1) - AMD_HEAP_SIZE_PER_CORE));
882   return ReturnPtr;
883 }
884
885