AGESA_STATUS agesa_LocateBuffer (UINT32 Func, UINT32 Data, VOID *ConfigPtr) { UINT32 AllocNodeOffset; UINT8 *BiosHeapBaseAddr; BIOS_BUFFER_NODE *AllocNodePtr; BIOS_HEAP_MANAGER *BiosHeapBasePtr; AGESA_BUFFER_PARAMS *AllocParams; AllocParams = (AGESA_BUFFER_PARAMS *) ConfigPtr; BiosHeapBaseAddr = (UINT8 *) GetHeapBase(&(AllocParams->StdHeader)); BiosHeapBasePtr = (BIOS_HEAP_MANAGER *) BiosHeapBaseAddr; AllocNodeOffset = BiosHeapBasePtr->StartOfAllocatedNodes; AllocNodePtr = (BIOS_BUFFER_NODE *) (BiosHeapBaseAddr + AllocNodeOffset); while (AllocParams->BufferHandle != AllocNodePtr->BufferHandle) { if (AllocNodePtr->NextNodeOffset == 0) { AllocParams->BufferPointer = NULL; AllocParams->BufferLength = 0; return AGESA_BOUNDS_CHK; } else { AllocNodeOffset = AllocNodePtr->NextNodeOffset; AllocNodePtr = (BIOS_BUFFER_NODE *) (BiosHeapBaseAddr + AllocNodeOffset); } } AllocParams->BufferPointer = (UINT8 *) ((UINT8 *) AllocNodePtr + sizeof (BIOS_BUFFER_NODE)); AllocParams->BufferLength = AllocNodePtr->BufferSize; return AGESA_SUCCESS; }
AGESA_STATUS agesawrapper_fchs3earlyrestore(void) { AGESA_STATUS status = AGESA_SUCCESS; FCH_DATA_BLOCK FchParams; AMD_CONFIG_PARAMS StdHeader; StdHeader.HeapStatus = HEAP_SYSTEM_MEM; StdHeader.HeapBasePtr = GetHeapBase(&StdHeader) + 0x10; StdHeader.AltImageBasePtr = 0; StdHeader.CalloutPtr = &GetBiosCallout; StdHeader.Func = 0; StdHeader.ImageBasePtr = 0; LibAmdMemFill (&FchParams, 0, sizeof (FchParams), &StdHeader); FchParams.StdHeader = &StdHeader; s3_resume_init_data(&FchParams); FchInitS3EarlyRestore(&FchParams); return status; }
AGESA_STATUS agesawrapper_fchs3laterestore (void) { FCH_DATA_BLOCK FchParams; AMD_CONFIG_PARAMS StdHeader; UINT8 byte; StdHeader.HeapStatus = HEAP_SYSTEM_MEM; StdHeader.HeapBasePtr = (uintptr_t) GetHeapBase() + 0x10; StdHeader.AltImageBasePtr = 0; StdHeader.CalloutPtr = &GetBiosCallout; StdHeader.Func = 0; StdHeader.ImageBasePtr = 0; FchParams.StdHeader = &StdHeader; s3_resume_init_data(&FchParams); FchInitS3LateRestore(&FchParams); /* PIC IRQ routine */ for (byte = 0x0; byte < sizeof(picr_data); byte ++) { outb(byte, 0xC00); outb(picr_data[byte], 0xC01); } /* APIC IRQ routine */ for (byte = 0x0; byte < sizeof(intr_data); byte ++) { outb(byte | 0x80, 0xC00); outb(intr_data[byte], 0xC01); } return AGESA_SUCCESS; }
void EmptyHeap(void) { void *base = GetHeapBase(); memset(base, 0, BIOS_HEAP_SIZE); printk(BIOS_DEBUG, "Wiped HEAP at [%08x - %08x]\n", (unsigned int)(uintptr_t) base, (unsigned int)(uintptr_t) base + BIOS_HEAP_SIZE - 1); }
AGESA_STATUS HeapManagerCallout(UINT32 Func, UINTN Data, VOID *ConfigPtr) { AGESA_BUFFER_PARAMS *AllocParams = ConfigPtr; #if defined(HEAP_CALLOUT_RUNTIME) && ENV_RAMSTAGE if (Func == AGESA_ALLOCATE_BUFFER && Data == HEAP_CALLOUT_RUNTIME) return alloc_cbmem(AllocParams); #endif /* Must not call GetHeapBase() in AGESA_UNSUPPORTED path. */ if (Func == AGESA_LOCATE_BUFFER) return agesa_LocateBuffer(GetHeapBase(), AllocParams); else if (Func == AGESA_ALLOCATE_BUFFER) return agesa_AllocateBuffer(GetHeapBase(), AllocParams); else if (Func == AGESA_DEALLOCATE_BUFFER) return agesa_DeallocateBuffer(GetHeapBase(), AllocParams); return AGESA_UNSUPPORTED; }
void OemAgesaGetS3Info(S3_DATA_TYPE S3DataType, u32 *DataSize, void **Data) { AMD_CONFIG_PARAMS StdHeader; if (S3DataType == S3DataTypeNonVolatile) { *Data = (void *)S3_DATA_NONVOLATILE_POS; *DataSize = *(UINTN *) (*Data); *Data += 4; } else { *DataSize = *(UINTN *) S3_DATA_VOLATILE_POS; *Data = (void *) GetHeapBase(&StdHeader); memcpy((void *)(*Data), (void *)(S3_DATA_VOLATILE_POS + 4), *DataSize); } }
AGESA_STATUS agesawrapper_fchs3earlyrestore (void) { FCH_DATA_BLOCK FchParams; AMD_CONFIG_PARAMS StdHeader; StdHeader.HeapStatus = HEAP_SYSTEM_MEM; StdHeader.HeapBasePtr = (uintptr_t) GetHeapBase() + 0x10; StdHeader.AltImageBasePtr = 0; StdHeader.CalloutPtr = &GetBiosCallout; StdHeader.Func = 0; StdHeader.ImageBasePtr = 0; FchParams.StdHeader = &StdHeader; s3_resume_init_data(&FchParams); FchInitS3EarlyRestore(&FchParams); return AGESA_SUCCESS; }
BOOL CheckGlobalHeap( ) { PGHI32 pghi; DWORD offset; DWORD count; DWORD p; GNODE32 gnode; PBYTE pFault = NULL; BOOL bError = FALSE; pghi = (PGHI32)GetHeapBase(); offset = (DWORD) ReadWord(&pghi->hi_first); // // If we get here, the caller wants us to scan the heap // count = ReadWord(&pghi->hi_count); while ((offset != 0) && (count)) { p = (DWORD)pghi + offset; if (!ReadGNode32(p, &gnode)) { PRINTF("Error reading global heap!\n"); return FALSE; } count--; if (offset == gnode.pga_next) { return TRUE; } offset = gnode.pga_next; } PRINTF("Error: Kernel heap is corrupt!\n"); return FALSE; }
AGESA_STATUS agesawrapper_fchs3laterestore(void) { AGESA_STATUS status = AGESA_SUCCESS; AMD_CONFIG_PARAMS StdHeader; FCH_DATA_BLOCK FchParams; StdHeader.HeapStatus = HEAP_SYSTEM_MEM; StdHeader.HeapBasePtr = GetHeapBase(&StdHeader) + 0x10; StdHeader.AltImageBasePtr = 0; StdHeader.CalloutPtr = (CALLOUT_ENTRY) &GetBiosCallout; StdHeader.Func = 0; StdHeader.ImageBasePtr = 0; LibAmdMemFill (&FchParams, 0, sizeof (FchParams), &StdHeader); FchParams.StdHeader = &StdHeader; s3_resume_init_data(&FchParams); FchInitS3LateRestore(&FchParams); /* PIC IRQ routine */ for (byte = 0x0; byte < sizeof(picr_data); byte ++) { outb(byte, 0xC00); outb(picr_data[byte], 0xC01); } /* APIC IRQ routine */ for (byte = 0x0; byte < sizeof(intr_data); byte ++) { outb(byte | 0x80, 0xC00); outb(intr_data[byte], 0xC01); } return status; }
AGESA_STATUS agesa_AllocateBuffer (UINT32 Func, UINT32 Data, VOID *ConfigPtr) { UINT32 AvailableHeapSize; UINT8 *BiosHeapBaseAddr; UINT32 CurrNodeOffset; UINT32 PrevNodeOffset; UINT32 FreedNodeOffset; UINT32 BestFitNodeOffset; UINT32 BestFitPrevNodeOffset; UINT32 NextFreeOffset; BIOS_BUFFER_NODE *CurrNodePtr; BIOS_BUFFER_NODE *FreedNodePtr; BIOS_BUFFER_NODE *BestFitNodePtr; BIOS_BUFFER_NODE *BestFitPrevNodePtr; BIOS_BUFFER_NODE *NextFreePtr; BIOS_HEAP_MANAGER *BiosHeapBasePtr; AGESA_BUFFER_PARAMS *AllocParams; AllocParams = ((AGESA_BUFFER_PARAMS *) ConfigPtr); AllocParams->BufferPointer = NULL; #if IS_ENABLED(CONFIG_NORTHBRIDGE_AMD_PI_00630F01) && !defined(__PRE_RAM__) /* if the allocation is for runtime use simple CBMEM data */ if (Data == HEAP_CALLOUT_RUNTIME) return alloc_cbmem(AllocParams); #endif AvailableHeapSize = BIOS_HEAP_SIZE - sizeof (BIOS_HEAP_MANAGER); BiosHeapBaseAddr = (UINT8 *) GetHeapBase(&(AllocParams->StdHeader)); BiosHeapBasePtr = (BIOS_HEAP_MANAGER *) BiosHeapBaseAddr; if (BiosHeapBasePtr->StartOfAllocatedNodes == 0) { /* First allocation */ CurrNodeOffset = sizeof (BIOS_HEAP_MANAGER); CurrNodePtr = (BIOS_BUFFER_NODE *) (BiosHeapBaseAddr + CurrNodeOffset); CurrNodePtr->BufferHandle = AllocParams->BufferHandle; CurrNodePtr->BufferSize = AllocParams->BufferLength; CurrNodePtr->NextNodeOffset = 0; AllocParams->BufferPointer = (UINT8 *) CurrNodePtr + sizeof (BIOS_BUFFER_NODE); /* Update the remaining free space */ FreedNodeOffset = CurrNodeOffset + CurrNodePtr->BufferSize + sizeof (BIOS_BUFFER_NODE); FreedNodePtr = (BIOS_BUFFER_NODE *) (BiosHeapBaseAddr + FreedNodeOffset); FreedNodePtr->BufferSize = AvailableHeapSize - sizeof (BIOS_BUFFER_NODE) - CurrNodePtr->BufferSize; FreedNodePtr->NextNodeOffset = 0; /* Update the offsets for Allocated and Freed nodes */ BiosHeapBasePtr->StartOfAllocatedNodes = CurrNodeOffset; BiosHeapBasePtr->StartOfFreedNodes = FreedNodeOffset; } else { /* Find out whether BufferHandle has been allocated on the heap. * If it has, return AGESA_BOUNDS_CHK. */ CurrNodeOffset = BiosHeapBasePtr->StartOfAllocatedNodes; CurrNodePtr = (BIOS_BUFFER_NODE *) (BiosHeapBaseAddr + CurrNodeOffset); while (CurrNodeOffset != 0) { CurrNodePtr = (BIOS_BUFFER_NODE *) (BiosHeapBaseAddr + CurrNodeOffset); if (CurrNodePtr->BufferHandle == AllocParams->BufferHandle) { return AGESA_BOUNDS_CHK; } CurrNodeOffset = CurrNodePtr->NextNodeOffset; /* If BufferHandle has not been allocated on the heap, CurrNodePtr here points * to the end of the allocated nodes list. */ } /* Find the node that best fits the requested buffer size */ FreedNodeOffset = BiosHeapBasePtr->StartOfFreedNodes; PrevNodeOffset = FreedNodeOffset; BestFitNodeOffset = 0; BestFitPrevNodeOffset = 0; while (FreedNodeOffset != 0) { FreedNodePtr = (BIOS_BUFFER_NODE *) (BiosHeapBaseAddr + FreedNodeOffset); if (FreedNodePtr->BufferSize >= (AllocParams->BufferLength + sizeof (BIOS_BUFFER_NODE))) { if (BestFitNodeOffset == 0) { /* First node that fits the requested buffer size */ BestFitNodeOffset = FreedNodeOffset; BestFitPrevNodeOffset = PrevNodeOffset; } else { /* Find out whether current node is a better fit than the previous nodes */ BestFitNodePtr = (BIOS_BUFFER_NODE *) (BiosHeapBaseAddr + BestFitNodeOffset); if (BestFitNodePtr->BufferSize > FreedNodePtr->BufferSize) { BestFitNodeOffset = FreedNodeOffset; BestFitPrevNodeOffset = PrevNodeOffset; } } } PrevNodeOffset = FreedNodeOffset; FreedNodeOffset = FreedNodePtr->NextNodeOffset; } /* end of while loop */ if (BestFitNodeOffset == 0) { /* If we could not find a node that fits the requested buffer * size, return AGESA_BOUNDS_CHK. */ return AGESA_BOUNDS_CHK; } else { BestFitNodePtr = (BIOS_BUFFER_NODE *) (BiosHeapBaseAddr + BestFitNodeOffset); BestFitPrevNodePtr = (BIOS_BUFFER_NODE *) (BiosHeapBaseAddr + BestFitPrevNodeOffset); /* If BestFitNode is larger than the requested buffer, fragment the node further */ if (BestFitNodePtr->BufferSize > (AllocParams->BufferLength + sizeof (BIOS_BUFFER_NODE))) { NextFreeOffset = BestFitNodeOffset + AllocParams->BufferLength + sizeof (BIOS_BUFFER_NODE); NextFreePtr = (BIOS_BUFFER_NODE *) (BiosHeapBaseAddr + NextFreeOffset); NextFreePtr->BufferSize = BestFitNodePtr->BufferSize - (AllocParams->BufferLength + sizeof (BIOS_BUFFER_NODE)); NextFreePtr->NextNodeOffset = BestFitNodePtr->NextNodeOffset; } else { /* Otherwise, next free node is NextNodeOffset of BestFitNode */ NextFreeOffset = BestFitNodePtr->NextNodeOffset; } /* If BestFitNode is the first buffer in the list, then update * StartOfFreedNodes to reflect the new free node. */ if (BestFitNodeOffset == BiosHeapBasePtr->StartOfFreedNodes) { BiosHeapBasePtr->StartOfFreedNodes = NextFreeOffset; } else { BestFitPrevNodePtr->NextNodeOffset = NextFreeOffset; } /* Add BestFitNode to the list of Allocated nodes */ CurrNodePtr->NextNodeOffset = BestFitNodeOffset; BestFitNodePtr->BufferSize = AllocParams->BufferLength; BestFitNodePtr->BufferHandle = AllocParams->BufferHandle; BestFitNodePtr->NextNodeOffset = 0; /* Remove BestFitNode from list of Freed nodes */ AllocParams->BufferPointer = (UINT8 *) BestFitNodePtr + sizeof (BIOS_BUFFER_NODE); } } return AGESA_SUCCESS; }
void EmptyHeap(void) { void *BiosManagerPtr = (void *) GetHeapBase(NULL); memset(BiosManagerPtr, 0, BIOS_HEAP_SIZE); }
AGESA_STATUS agesa_DeallocateBuffer (UINT32 Func, UINT32 Data, VOID *ConfigPtr) { UINT8 *BiosHeapBaseAddr; UINT32 AllocNodeOffset; UINT32 PrevNodeOffset; UINT32 NextNodeOffset; UINT32 FreedNodeOffset; UINT32 EndNodeOffset; BIOS_BUFFER_NODE *AllocNodePtr; BIOS_BUFFER_NODE *PrevNodePtr; BIOS_BUFFER_NODE *FreedNodePtr; BIOS_BUFFER_NODE *NextNodePtr; BIOS_HEAP_MANAGER *BiosHeapBasePtr; AGESA_BUFFER_PARAMS *AllocParams; AllocParams = (AGESA_BUFFER_PARAMS *) ConfigPtr; BiosHeapBaseAddr = (UINT8 *) GetHeapBase(&(AllocParams->StdHeader)); BiosHeapBasePtr = (BIOS_HEAP_MANAGER *) BiosHeapBaseAddr; /* Find target node to deallocate in list of allocated nodes. * Return AGESA_BOUNDS_CHK if the BufferHandle is not found. */ AllocNodeOffset = BiosHeapBasePtr->StartOfAllocatedNodes; AllocNodePtr = (BIOS_BUFFER_NODE *) (BiosHeapBaseAddr + AllocNodeOffset); PrevNodeOffset = AllocNodeOffset; while (AllocNodePtr->BufferHandle != AllocParams->BufferHandle) { if (AllocNodePtr->NextNodeOffset == 0) { return AGESA_BOUNDS_CHK; } PrevNodeOffset = AllocNodeOffset; AllocNodeOffset = AllocNodePtr->NextNodeOffset; AllocNodePtr = (BIOS_BUFFER_NODE *) (BiosHeapBaseAddr + AllocNodeOffset); } /* Remove target node from list of allocated nodes */ PrevNodePtr = (BIOS_BUFFER_NODE *) (BiosHeapBaseAddr + PrevNodeOffset); PrevNodePtr->NextNodeOffset = AllocNodePtr->NextNodeOffset; /* Zero out the buffer, and clear the BufferHandle */ LibAmdMemFill ((UINT8 *)AllocNodePtr + sizeof (BIOS_BUFFER_NODE), 0, AllocNodePtr->BufferSize, &(AllocParams->StdHeader)); AllocNodePtr->BufferHandle = 0; AllocNodePtr->BufferSize += sizeof (BIOS_BUFFER_NODE); /* Add deallocated node in order to the list of freed nodes */ FreedNodeOffset = BiosHeapBasePtr->StartOfFreedNodes; FreedNodePtr = (BIOS_BUFFER_NODE *) (BiosHeapBaseAddr + FreedNodeOffset); EndNodeOffset = AllocNodeOffset + AllocNodePtr->BufferSize; if (AllocNodeOffset < FreedNodeOffset) { /* Add to the start of the freed list */ if (EndNodeOffset == FreedNodeOffset) { /* If the freed node is adjacent to the first node in the list, concatenate both nodes */ AllocNodePtr->BufferSize += FreedNodePtr->BufferSize; AllocNodePtr->NextNodeOffset = FreedNodePtr->NextNodeOffset; /* Clear the BufferSize and NextNodeOffset of the previous first node */ FreedNodePtr->BufferSize = 0; FreedNodePtr->NextNodeOffset = 0; } else { /* Otherwise, add freed node to the start of the list * Update NextNodeOffset and BufferSize to include the * size of BIOS_BUFFER_NODE. */ AllocNodePtr->NextNodeOffset = FreedNodeOffset; } /* Update StartOfFreedNodes to the new first node */ BiosHeapBasePtr->StartOfFreedNodes = AllocNodeOffset; } else { /* Traverse list of freed nodes to find where the deallocated node * should be placed. */ NextNodeOffset = FreedNodeOffset; NextNodePtr = FreedNodePtr; while (AllocNodeOffset > NextNodeOffset) { PrevNodeOffset = NextNodeOffset; if (NextNodePtr->NextNodeOffset == 0) { break; } NextNodeOffset = NextNodePtr->NextNodeOffset; NextNodePtr = (BIOS_BUFFER_NODE *) (BiosHeapBaseAddr + NextNodeOffset); } /* If deallocated node is adjacent to the next node, * concatenate both nodes. */ if (NextNodeOffset == EndNodeOffset) { NextNodePtr = (BIOS_BUFFER_NODE *) (BiosHeapBaseAddr + NextNodeOffset); AllocNodePtr->BufferSize += NextNodePtr->BufferSize; AllocNodePtr->NextNodeOffset = NextNodePtr->NextNodeOffset; NextNodePtr->BufferSize = 0; NextNodePtr->NextNodeOffset = 0; } else { /*AllocNodePtr->NextNodeOffset = FreedNodePtr->NextNodeOffset; */ AllocNodePtr->NextNodeOffset = NextNodeOffset; } /* If deallocated node is adjacent to the previous node, * concatenate both nodes. */ PrevNodePtr = (BIOS_BUFFER_NODE *) (BiosHeapBaseAddr + PrevNodeOffset); EndNodeOffset = PrevNodeOffset + PrevNodePtr->BufferSize; if (AllocNodeOffset == EndNodeOffset) { PrevNodePtr->NextNodeOffset = AllocNodePtr->NextNodeOffset; PrevNodePtr->BufferSize += AllocNodePtr->BufferSize; AllocNodePtr->BufferSize = 0; AllocNodePtr->NextNodeOffset = 0; } else { PrevNodePtr->NextNodeOffset = AllocNodeOffset; } } return AGESA_SUCCESS; }
void ResumeHeap(void **heap, size_t *len) { void *base = GetHeapBase(); *heap = base; *len = BIOS_HEAP_SIZE; }
void EmptyHeap(void) { void *base = GetHeapBase(); memset(base, 0, BIOS_HEAP_SIZE); }
BOOL FindHeapEntry( HEAPENTRY *he, BOOL bFindAny ) { PGHI32 pghi; DWORD offset; DWORD MaxEntries, count; DWORD p; PBYTE pFault = NULL; BOOL bError = FALSE; pghi = (PGHI32)GetHeapBase(); // // The caller has requested that we return the next heap // entry since the last invocation, or the first entry. // if (he->CurrentEntry == 0) { // get first entry offset = (DWORD) ReadWord(&pghi->hi_first); } else { if (he->CurrentEntry == he->NextEntry) { return FALSE; } // get next entry offset = he->NextEntry; } he->CurrentEntry = offset; if (he->Selector == 0) { p = (DWORD)pghi + offset; if (!ReadGNode32(p, &he->gnode)) { PRINTF("Error reading global heap!\n"); return FALSE; } he->NextEntry = he->gnode.pga_next; GetSegmentOwnerInfo(he); return TRUE; } // // If we get here, the caller wants us to scan the heap // MaxEntries = ReadWord(&pghi->hi_count); count = 0; while ((offset != 0) && (count <= MaxEntries)) { p = (DWORD)pghi + offset; if (!ReadGNode32(p, &he->gnode)) { PRINTF("Error reading global heap!\n"); return FALSE; } else { if (bFindAny) { WORD sel = he->Selector; if (((sel|1)==((WORD)he->gnode.pga_handle|1)) || ((sel|1)==((WORD)he->gnode.pga_owner|1))) { he->NextEntry = he->gnode.pga_next; GetSegmentOwnerInfo(he); return TRUE; } } else { if ((he->Selector|1)==((WORD)he->gnode.pga_handle|1)) { he->NextEntry = he->gnode.pga_next; GetSegmentOwnerInfo(he); return TRUE; } } } count++; if (offset == he->gnode.pga_next) { break; } offset = he->gnode.pga_next; he->CurrentEntry = offset; } return FALSE; }
AGESA_STATUS BiosAllocateBuffer (UINT32 Func, UINT32 Data, VOID *ConfigPtr) { UINT32 AvailableHeapSize; UINT8 *BiosHeapBaseAddr; UINT32 CurrNodeOffset; UINT32 PrevNodeOffset; UINT32 FreedNodeOffset; UINT32 BestFitNodeOffset; UINT32 BestFitPrevNodeOffset; UINT32 NextFreeOffset; BIOS_BUFFER_NODE *CurrNodePtr; BIOS_BUFFER_NODE *FreedNodePtr; BIOS_BUFFER_NODE *BestFitNodePtr; BIOS_BUFFER_NODE *BestFitPrevNodePtr; BIOS_BUFFER_NODE *NextFreePtr; BIOS_HEAP_MANAGER *BiosHeapBasePtr; AGESA_BUFFER_PARAMS *AllocParams; AllocParams = ((AGESA_BUFFER_PARAMS *) ConfigPtr); AllocParams->BufferPointer = NULL; AvailableHeapSize = BIOS_HEAP_SIZE - sizeof (BIOS_HEAP_MANAGER); BiosHeapBaseAddr = (UINT8 *) GetHeapBase(&(AllocParams->StdHeader)); BiosHeapBasePtr = (BIOS_HEAP_MANAGER *) BiosHeapBaseAddr; printk(BIOS_SPEW, "%s BiosHeapBaseAddr: %x\n", __func__, (u32) BiosHeapBaseAddr); if (BiosHeapBasePtr->StartOfAllocatedNodes == 0) { /* First allocation */ CurrNodeOffset = sizeof (BIOS_HEAP_MANAGER); CurrNodePtr = (BIOS_BUFFER_NODE *) (BiosHeapBaseAddr + CurrNodeOffset); CurrNodePtr->BufferHandle = AllocParams->BufferHandle; CurrNodePtr->BufferSize = AllocParams->BufferLength; CurrNodePtr->NextNodeOffset = 0; AllocParams->BufferPointer = (UINT8 *) CurrNodePtr + sizeof (BIOS_BUFFER_NODE); /* Update the remaining free space */ FreedNodeOffset = CurrNodeOffset + CurrNodePtr->BufferSize + sizeof (BIOS_BUFFER_NODE); FreedNodePtr = (BIOS_BUFFER_NODE *) (BiosHeapBaseAddr + FreedNodeOffset); FreedNodePtr->BufferSize = AvailableHeapSize - sizeof (BIOS_BUFFER_NODE) - CurrNodePtr->BufferSize; FreedNodePtr->NextNodeOffset = 0; /* Update the offsets for Allocated and Freed nodes */ BiosHeapBasePtr->StartOfAllocatedNodes = CurrNodeOffset; BiosHeapBasePtr->StartOfFreedNodes = FreedNodeOffset; } else { /* Find out whether BufferHandle has been allocated on the heap. */ /* If it has, return AGESA_BOUNDS_CHK */ CurrNodeOffset = BiosHeapBasePtr->StartOfAllocatedNodes; CurrNodePtr = (BIOS_BUFFER_NODE *) (BiosHeapBaseAddr + CurrNodeOffset); while (CurrNodeOffset != 0) { CurrNodePtr = (BIOS_BUFFER_NODE *) (BiosHeapBaseAddr + CurrNodeOffset); if (CurrNodePtr->BufferHandle == AllocParams->BufferHandle) { return AGESA_BOUNDS_CHK; } CurrNodeOffset = CurrNodePtr->NextNodeOffset; /* If BufferHandle has not been allocated on the heap, CurrNodePtr here points to the end of the allocated nodes list. */ } /* Find the node that best fits the requested buffer size */ FreedNodeOffset = BiosHeapBasePtr->StartOfFreedNodes; PrevNodeOffset = FreedNodeOffset; BestFitNodeOffset = 0; BestFitPrevNodeOffset = 0; while (FreedNodeOffset != 0) { FreedNodePtr = (BIOS_BUFFER_NODE *) (BiosHeapBaseAddr + FreedNodeOffset); if (FreedNodePtr->BufferSize >= (AllocParams->BufferLength + sizeof (BIOS_BUFFER_NODE))) { if (BestFitNodeOffset == 0) { /* First node that fits the requested buffer size */ BestFitNodeOffset = FreedNodeOffset; BestFitPrevNodeOffset = PrevNodeOffset; } else { /* Find out whether current node is a better fit than the previous nodes */ BestFitNodePtr = (BIOS_BUFFER_NODE *) (BiosHeapBaseAddr + BestFitNodeOffset); if (BestFitNodePtr->BufferSize > FreedNodePtr->BufferSize) { BestFitNodeOffset = FreedNodeOffset; BestFitPrevNodeOffset = PrevNodeOffset; } } } PrevNodeOffset = FreedNodeOffset; FreedNodeOffset = FreedNodePtr->NextNodeOffset; } /* end of while loop */ if (BestFitNodeOffset == 0) { /* If we could not find a node that fits the requested buffer */ /* size, return AGESA_BOUNDS_CHK */ return AGESA_BOUNDS_CHK; } else { BestFitNodePtr = (BIOS_BUFFER_NODE *) (BiosHeapBaseAddr + BestFitNodeOffset); BestFitPrevNodePtr = (BIOS_BUFFER_NODE *) (BiosHeapBaseAddr + BestFitPrevNodeOffset); /* If BestFitNode is larger than the requested buffer, fragment the node further */ if (BestFitNodePtr->BufferSize > (AllocParams->BufferLength + sizeof (BIOS_BUFFER_NODE))) { NextFreeOffset = BestFitNodeOffset + AllocParams->BufferLength + sizeof (BIOS_BUFFER_NODE); NextFreePtr = (BIOS_BUFFER_NODE *) (BiosHeapBaseAddr + NextFreeOffset); NextFreePtr->BufferSize = BestFitNodePtr->BufferSize - (AllocParams->BufferLength + sizeof (BIOS_BUFFER_NODE)); NextFreePtr->NextNodeOffset = BestFitNodePtr->NextNodeOffset; } else { /* Otherwise, next free node is NextNodeOffset of BestFitNode */ NextFreeOffset = BestFitNodePtr->NextNodeOffset; } /* If BestFitNode is the first buffer in the list, then update StartOfFreedNodes to reflect the new free node */ if (BestFitNodeOffset == BiosHeapBasePtr->StartOfFreedNodes) { BiosHeapBasePtr->StartOfFreedNodes = NextFreeOffset; } else { BestFitPrevNodePtr->NextNodeOffset = NextFreeOffset; } /* Add BestFitNode to the list of Allocated nodes */ CurrNodePtr->NextNodeOffset = BestFitNodeOffset; BestFitNodePtr->BufferSize = AllocParams->BufferLength; BestFitNodePtr->BufferHandle = AllocParams->BufferHandle; BestFitNodePtr->NextNodeOffset = 0; /* Remove BestFitNode from list of Freed nodes */ AllocParams->BufferPointer = (UINT8 *) BestFitNodePtr + sizeof (BIOS_BUFFER_NODE); } } return AGESA_SUCCESS; }