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