📄 heapman.c
字号:
/*
Kernel manager code relies on the fact that calling AllicHostMem()
with a zero size will pass back a NULL linear address and return PVRSRV_OK
*/
if (ui32Size==0)
{
return (PVRSRV_OK);
}
if (ui32HeapIndex == PVRSRV_HOST_PAGEABLE_HEAP)
{
pvLinAddr=HostPageableByteAlloc(ui32Size);
bAllocDone=TRUE;
}
/* If alloc was done by OS function */
if (bAllocDone == TRUE)
{
if (pvLinAddr == NULL)
{
PVR_DPF((PVR_DBG_ERROR, "HostAllocMem : OS byte alloc failed, if using special pool on NT then you may need from RAM!!!!\n"));
return(PVRSRV_ERROR_OUT_OF_MEMORY);
}
*ppvLinAddr=pvLinAddr;
return (PVRSRV_OK);
}
/* Check the heap requested is valid, and find which heap we will use */
if (ui32HeapIndex > PVRSRV_HOST_MAX_HEAP)
{
PVR_DPF((PVR_DBG_ERROR, "Invalid heap (%lx) passed to HostAllocMem()\n", ui32HeapIndex));
return (PVRSRV_ERROR_OUT_OF_MEMORY);
}
/* Attempt to alloc memory and store linear address if successful */
if ((pvLinAddr=MemHeapAlloc(psEnvData->psHeap, ui32Size, 4, NULL, ui32OwnerAddr)) == NULL)
{
#ifdef DEBUG
/* Check heap */
CheckHostHeaps();
#endif
return PVRSRV_ERROR_OUT_OF_MEMORY;
}
*ppvLinAddr=pvLinAddr;
#ifdef DEBUG
/*Check heap*/
CheckHostHeaps();
#endif
PVR_DPF((PVR_DBG_MESSAGE, "HostAllocMem() alloced the memory at 0x%lx", pvLinAddr));
return (PVRSRV_OK);
}
/*!
******************************************************************************
@Function HostFreeMem
@Description Allocates host memory from one of the host heaps
@Input pvLinAddr - address to memory to free
@Input ui32Flags - allocation flags to identify alloc heap
@Return PVRSRV_OK on success else PVRSRV_ERROR_OUT_OF_MEMORY
******************************************************************************/
PVRSRV_ERROR HostFreeMem(IMG_UINT32 ui32Flags, IMG_PVOID pvLinAddr)
{
IMG_UINT32 ui32HeapIndex=ui32Flags & PVRSRV_HOST_HEAP_MASK;
IMG_BOOL bFreeDone=FALSE;
PVR_DPF((PVR_DBG_MESSAGE, "HostFreeMem() called to free block at 0x%lx with alloc flags of %lx", pvLinAddr, ui32Flags));
#ifdef DEBUG
/*Check heap*/
CheckHostHeaps();
#endif
if (pvLinAddr == NULL)
{
PVR_DPF((PVR_DBG_ERROR, "HostFreeMem() Caller tried to free NULL!!!\n"));
return PVRSRV_ERROR_OUT_OF_MEMORY;
}
if (ui32HeapIndex == PVRSRV_HOST_PAGEABLE_HEAP)
{
HostPageableByteFree(pvLinAddr);
bFreeDone=TRUE;
}
if (bFreeDone == TRUE)
{
return PVRSRV_OK;
}
/* Free memory */
if (MemHeapFree(pvLinAddr, NULL) == FALSE)
{
#ifdef DEBUG
/*Check heap*/
CheckHostHeaps();
#endif
return PVRSRV_ERROR_OUT_OF_MEMORY;
}
#ifdef DEBUG
/*Check heap*/
CheckHostHeaps();
#endif
return PVRSRV_OK;
}
/**************************************************************************
* Function Name : HostNonPageablePageAlloc()
* Inputs : ui32NumPages - number of pages to alloc
* pvHeapContext - context pointer passed to MemHeapAlloc()
* Outputs : None
* Returns : Pointer to linear address of allocated non-cached memory
* if success, returns NULL on failure
* Globals Used : None
* Description : Wrapper function to alloc paged
**************************************************************************/
IMG_PVOID HostNonPageablePageAlloc(IMG_UINT32 ui32NumPages, IMG_PVOID pvHeapContext, IMG_PVOID *ppvAllocContext, IMG_PVOID pvLinAddr)
{
return VirtualAlloc(pvLinAddr, ui32NumPages << 12, MEM_COMMIT, PAGE_READWRITE);
}
/**************************************************************************
* Function Name : HostNonPageablePageFree
* Inputs : pvLinAddr - linear address of buffer to be freed
* ui32NumPages - number of pages to free NOT USED
* pvHeapContext - context that was passed to MemHeapFree() NOT USED
* Outputs : None
* Returns : None
* Globals Used : None
* Description : Free pages allocated via HostNonPageablePageAlloc()
**************************************************************************/
IMG_VOID HostNonPageablePageFree(IMG_PVOID pvLinAddr, IMG_UINT32 ui32NumPages, IMG_PVOID pvHeapContext, IMG_PVOID pvAllocContext)
{
VirtualFree(pvLinAddr, ui32NumPages << 12, MEM_DECOMMIT);
}
/**************************************************************************
* Function Name : CheckHostHeaps
* Inputs : None
* Outputs : None
* Returns : None
* Globals Used : Reads asHostHeaps table
* Description : Walks through all the heaps checking for corruptions
**************************************************************************/
IMG_VOID CheckHostHeaps(IMG_VOID)
{
SYS_DATA *psSysData;
PVRSRV_ERROR eError = PVRSRV_OK;
eError = SysAcquireData(&psSysData);
if (eError != PVRSRV_OK)
{
return;
}
CheckSingleHeap((PHOST_HEAP)psSysData->pvEnvSpecificData, FALSE);
/* Can't check cache coherant heap as its per-device */
return;
}
IMG_UINT32 AddHostHeapBlockAllocCallback(PFN_HEAPBLOCK_CALLBACK pfnFunc)
{
SYS_DATA *psSysData;
PVRSRV_ERROR eError = PVRSRV_OK;
ENV_DATA *psEnvData;
eError = SysAcquireData(&psSysData);
if (eError != PVRSRV_OK)
{
return eError;
}
psEnvData = (ENV_DATA*)psSysData->pvEnvSpecificData;
/* Install callback */
if (AddBlockAllocCallback(pfnFunc) == FALSE)
{
PVR_DPF((PVR_DBG_ERROR, "AddHostHeapBlockAllocCallback : Failed to register callback"));
return PVRSRV_ERROR_CANT_REGISTER_CALLBACK;
}
/* Now create callback for non-paged heap */
DoBlockCallbacksForHeap(psEnvData->psHeap);
return PVRSRV_OK;
}
IMG_UINT32 RemoveHostHeapBlockAllocCallback(PFN_HEAPBLOCK_CALLBACK pfnFunc)
{
RemoveBlockAllocCallback(pfnFunc);
return PVRSRV_OK;
}
PPAGE_STATE AcquirePages (HOST_HEAP *psHeap, IMG_UINT32 ui32RequiredPages)
{
PPAGE_STATE psPageState = psHeap->psPageState;
IMG_UINT32 i, ui32PageCount = 0;
for (i=0; i<psHeap->ui32MaxHeapSizeInPages; i++)
{
if (psPageState[i].bPageCommitted == IMG_FALSE)
{
ui32PageCount++;
if (ui32PageCount == ui32RequiredPages)
{
psPageState = &psPageState[i];
psPageState -= ui32PageCount-1;
/* mark in use, walking backwards */
for(i=0; i<ui32PageCount; i++)
{
psPageState[i].bPageCommitted = IMG_TRUE;
}
/* return base page */
return psPageState;
}
}
else
{
ui32PageCount = 0;
}
}
return NULL;
}
IMG_VOID ReleasePages (PPAGE_STATE psPageState, IMG_UINT32 ui32Pages)
{
while(ui32Pages--)
{
psPageState->bPageCommitted = IMG_FALSE;
psPageState++;
}
}
/**************************************************************************
* Function Name : MemHeapAlloc()
* Inputs : psHostHeap - pointer to which host heap to use for alloc
* ui32Size - size of block to alloc
* ui32Alignment - alignment required for this allocation
* must be a power of two
* pvHeapContext - context pointer passed onto the page allocate
* routine
* ui32OwnerAddr - addr of allocating code
* Outputs : None
* Returns : Linear address of buffer alloced on success else NULL
* Globals Used : None
* Description : Alloc memory from the given host heap
**************************************************************************/
IMG_PVOID MemHeapAlloc(HOST_HEAP *psHostHeap, IMG_UINT32 ui32Size, IMG_UINT32 ui32Alignment, IMG_PVOID pvHeapContext, IMG_UINT32 ui32OwnerAddr)
{
IMG_PVOID pvLinAddr;
/*Check for zero sized allocations*/
if (ui32Size == 0)
{
PVR_DPF((PVR_DBG_ERROR, "MemHeapAlloc() got a request for a zero sized allocations!\n"));
return NULL;
}
/*Check that alignment is a power of two because calc of alignment
buffer relies on this, also why should anyone want to do anything else????*/
if (IsValidAlignment(ui32Alignment) == FALSE)
{
PVR_DPF((PVR_DBG_ERROR, "MemHeapAlloc() alignment value is not a power of two!!!!\n"));
return NULL;
}
/*Check if requested size is bigger than we can allow from within the heap*/
if (ui32Size > psHostHeap->ui32MaxSingleHeapAllocInBytes)
{
/*Check if we are allowed to do single allocations*/
if (psHostHeap->bAllowLargeSingleAllocs == TRUE)
{
PGLOB_HEAP_HEAD psBlock;
IMG_UINT32 ui32HeaderSize;
IMG_UINT32 ui32AllocSizeInPages;
IMG_PVOID pvAllocContext;
PPAGE_STATE psPageState;
/*Alloc host pages*/
ui32AllocSizeInPages=(ui32Size + ui32Alignment + sizeof(GLOB_HEAP_HEAD) + HOST_PAGESIZE() - 1) / HOST_PAGESIZE();
psPageState = AcquirePages(psHostHeap, ui32AllocSizeInPages);
if (psPageState == NULL)
{
PVR_DPF((PVR_DBG_ERROR, "MemHeapAlloc() could not allocate a page block!\n"));
return(NULL);
}
psBlock=(PGLOB_HEAP_HEAD)(psHostHeap->pfnHostAllocPage)(ui32AllocSizeInPages, pvHeapContext, &pvAllocContext, psPageState->pvLinearAddr);
if (psBlock == NULL)
{
PVR_DPF((PVR_DBG_ERROR, "MemHeapAlloc() could not allocate single block!\n"));
return(NULL);
}
ProcessAllocCallbacks(TRUE, &psBlock->sGlobHeap, ui32AllocSizeInPages * HOST_PAGESIZE());
/*Set block structure*/
psBlock->sGlobHeap.ui32Signiture=HOST_HEAP_SIGNITURE;
psBlock->sGlobHeap.ui32Flags =GHEAP_BLOCK_ALLOCATED | GHEAP_SINGLE;
psBlock->sGlobHeap.ui32BlockSize = ui32AllocSizeInPages * HOST_PAGESIZE();
psBlock->sGlobHeap.psNext = (PGLOB_HEAP) 0;
psBlock->sGlobHeap.psPrev = (PGLOB_HEAP) 0;
psBlock->sGlobHeap.psHeap = psHostHeap;
psBlock->sGlobHeap.psPageState = psPageState;
psBlock->pvBlkAllocContext=pvAllocContext;
#if defined(DEBUG) && !defined(NO_ALLOC_TRACKING)
psBlock->sGlobHeap.pfnOwner=(POWNER_FN)ui32OwnerAddr;
#endif /* #if defined(DEBUG) && !defined(NO_ALLOC_TRACKING) */
/*Calc alignment buf size so that memory would have correct alignment*/
CalcBufAlignment((PGLOB_HEAP)&psBlock->sGlobHeap, ui32Alignment, &ui32HeaderSize);
/*Calc linear address to return to caller*/
pvLinAddr=(BYTE *)psBlock + ui32HeaderSize;
/*Setup back pointer to point back to begining of the block*/
*((IMG_UINT32 *)pvLinAddr-1)=(IMG_UINT32)psBlock;
/* Check that the allocate block is big enough */
PVR_ASSERT((PBYTE)pvLinAddr+ui32Size <= (PBYTE)psBlock + ui32Size + ui32Alignment + sizeof(GLOB_HEAP_HEAD));
#ifdef DEBUG
/*On debug builds init memory to known value (not zero)*/
HostMemSet(pvLinAddr, (IMG_UINT8)DBG_MEMORY_INITIALIZER, ui32Size);
#endif /*DEBUG*/
return pvLinAddr;
}
else
{
/*Alloc size is too big for alloc from heap BUT we
are not allowed to use single host allocs*/
PVR_DPF((PVR_DBG_ERROR, "MemHeapAlloc() Alloc size to big for this heap, and we are not allowed to use single allocs!!!!\n"));
return NULL;
}
}
/* Traverse existings blocks before allocating any more pages.*/
pvLinAddr = AllocFromExistingBlocks(psHostHeap, ui32Size, ui32Alignment, ui32OwnerAddr);
if (pvLinAddr == NULL)
{
PGLOB_HEAP_HEAD psNew;
IMG_PVOID pvAllocContext;
PPAGE_STATE psPageState;
/*Check if we are allowed to grow the heap again*/
if (psHostHeap->ui32MaxHeapSizeInPages != 0 && (psHostHeap->ui32CurHeapSizeInPages + psHostHeap->ui32ExpandSizeInPages) > psHostHeap->ui32MaxHeapSizeInPages)
{
PVR_DPF((PVR_DBG_ERROR, "MemHeapAlloc() heap size has reached its limit!!!!\n"));
return NULL;
}
psPageState = AcquirePages(psHostHeap, psHostHeap->ui32ExpandSizeInPages);
if (psPageState == NULL)
{
PVR_DPF((PVR_DBG_ERROR, "MemHeapAlloc() could not allocate a page block!\n"));
return(NULL);
}
/*
If we get to this point we have failed to find space in any existing
blocks, its time to grow our heap.
*/
psNew = (PGLOB_HEAP_HEAD)(psHostHeap->pfnHostAllocPage)(psHostHeap->ui32ExpandSizeInPages, pvHeapContext, &pvAllocContext, psPageState->pvLinearAddr);
if (psNew == NULL)
{
PVR_DPF((PVR_DBG_ERROR, "MemHeapAlloc() failed to expand heap!!\n"));
return(NULL);
}
psHostHeap->ui32CurHeapSizeInPages+=psHostHeap->ui32ExpandSizeInPages;
ProcessAllocCallbacks(TRUE, &psNew->sGlobHeap, psHostHeap->ui32ExpandSizeInPages * HOST_PAGESIZE());
#ifdef DEBUG
/* Init unallocated memory to known value */
HostMemSet(&psNew->sGlobHeap, (IMG_UINT8)DBG_MEMORY_DEALLOC_INITIALIZER, psHostHeap->ui32ExpandSizeInPages * HOST_PAGESIZE());
#endif /* #ifdef DEBUG */
/*
Set structure up. Well Derr..
*/
psNew->sGlobHeap.ui32Signiture=HOST_HEAP_SIGNITURE;
psNew->sGlobHeap.ui32Flags =GHEAP_BLOCK_HEAD;
psNew->sGlobHeap.ui32BlockSize = psHostHeap->ui32ExpandSizeInPages * HOST_PAGESIZE();
psNew->sGlobHeap.psPageState = psPageState;
psNew->sGlobHeap.psHeap=psHostHeap;
psNew->pvBlkAllocContext=pvAllocContext;
/*
Insert at head of list.
*/
psNew->sGlobHeap.psNext = (PGLOB_HEAP) psHostHeap->psHeapStart;
psNew->sGlobHeap.psPrev = (PGLOB_HEAP) NULL;
if (psHostHeap->psHeapStart != NULL)
{
psHostHeap->psHeapStart->psPrev=(PGLOB_HEAP)psNew;
}
psHostHeap->psHeapStart=(PGLOB_HEAP)psNew;
/* Insert new block at front of free list */
HeapAddBlockToFreeList(psHostHeap, (PGLOB_HEAP)psNew);
/*
Allocation will succeed this time
*/
pvLinAddr = AllocFromExistingBlocks(psHostHeap, ui32Size, ui32Alignment, ui32OwnerAddr);
}
#ifdef DEBUG
/*On debug builds init memory to known value (not zero)*/
if (pvLinAddr != NULL)
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -