/*1* Copyright 2008-2012 Freescale Semiconductor Inc.2*3* Redistribution and use in source and binary forms, with or without4* modification, are permitted provided that the following conditions are met:5* * Redistributions of source code must retain the above copyright6* notice, this list of conditions and the following disclaimer.7* * Redistributions in binary form must reproduce the above copyright8* notice, this list of conditions and the following disclaimer in the9* documentation and/or other materials provided with the distribution.10* * Neither the name of Freescale Semiconductor nor the11* names of its contributors may be used to endorse or promote products12* derived from this software without specific prior written permission.13*14*15* ALTERNATIVELY, this software may be distributed under the terms of the16* GNU General Public License ("GPL") as published by the Free Software17* Foundation, either version 2 of that License or (at your option) any18* later version.19*20* THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``AS IS'' AND ANY21* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED22* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE23* DISCLAIMED. IN NO EVENT SHALL Freescale Semiconductor BE LIABLE FOR ANY24* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES25* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;26* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND27* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT28* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS29* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.30*/313233#include "string_ext.h"34#include "error_ext.h"35#include "std_ext.h"36#include "part_ext.h"37#include "xx_ext.h"3839#include "mm.h"4041424344/**********************************************************************45* MM internal routines set *46**********************************************************************/4748/****************************************************************49* Routine: CreateBusyBlock50*51* Description:52* Initializes a new busy block of "size" bytes and started53* rom "base" address. Each busy block has a name that54* specified the purpose of the memory allocation.55*56* Arguments:57* base - base address of the busy block58* size - size of the busy block59* name - name that specified the busy block60*61* Return value:62* A pointer to new created structure returned on success;63* Otherwise, NULL.64****************************************************************/65static t_BusyBlock * CreateBusyBlock(uint64_t base, uint64_t size, char *name)66{67t_BusyBlock *p_BusyBlock;68uint32_t n;6970p_BusyBlock = (t_BusyBlock *)XX_Malloc(sizeof(t_BusyBlock));71if ( !p_BusyBlock )72{73REPORT_ERROR(MAJOR, E_NO_MEMORY, NO_MSG);74return NULL;75}7677p_BusyBlock->base = base;78p_BusyBlock->end = base + size;7980n = strlen(name);81if (n >= MM_MAX_NAME_LEN)82n = MM_MAX_NAME_LEN - 1;83strncpy(p_BusyBlock->name, name, MM_MAX_NAME_LEN-1);84p_BusyBlock->name[n] = '\0';85p_BusyBlock->p_Next = 0;8687return p_BusyBlock;88}8990/****************************************************************91* Routine: CreateNewBlock92*93* Description:94* Initializes a new memory block of "size" bytes and started95* from "base" address.96*97* Arguments:98* base - base address of the memory block99* size - size of the memory block100*101* Return value:102* A pointer to new created structure returned on success;103* Otherwise, NULL.104****************************************************************/105static t_MemBlock * CreateNewBlock(uint64_t base, uint64_t size)106{107t_MemBlock *p_MemBlock;108109p_MemBlock = (t_MemBlock *)XX_Malloc(sizeof(t_MemBlock));110if ( !p_MemBlock )111{112REPORT_ERROR(MAJOR, E_NO_MEMORY, NO_MSG);113return NULL;114}115116p_MemBlock->base = base;117p_MemBlock->end = base+size;118p_MemBlock->p_Next = 0;119120return p_MemBlock;121}122123/****************************************************************124* Routine: CreateFreeBlock125*126* Description:127* Initializes a new free block of of "size" bytes and128* started from "base" address.129*130* Arguments:131* base - base address of the free block132* size - size of the free block133*134* Return value:135* A pointer to new created structure returned on success;136* Otherwise, NULL.137****************************************************************/138static t_FreeBlock * CreateFreeBlock(uint64_t base, uint64_t size)139{140t_FreeBlock *p_FreeBlock;141142p_FreeBlock = (t_FreeBlock *)XX_Malloc(sizeof(t_FreeBlock));143if ( !p_FreeBlock )144{145REPORT_ERROR(MAJOR, E_NO_MEMORY, NO_MSG);146return NULL;147}148149p_FreeBlock->base = base;150p_FreeBlock->end = base + size;151p_FreeBlock->p_Next = 0;152153return p_FreeBlock;154}155156/****************************************************************157* Routine: AddFree158*159* Description:160* Adds a new free block to the free lists. It updates each161* free list to include a new free block.162* Note, that all free block in each free list are ordered163* by their base address.164*165* Arguments:166* p_MM - pointer to the MM object167* base - base address of a given free block168* end - end address of a given free block169*170* Return value:171*172*173****************************************************************/174static t_Error AddFree(t_MM *p_MM, uint64_t base, uint64_t end)175{176t_FreeBlock *p_PrevB, *p_CurrB, *p_NewB;177uint64_t alignment;178uint64_t alignBase;179int i;180181/* Updates free lists to include a just released block */182for (i=0; i <= MM_MAX_ALIGNMENT; i++)183{184p_PrevB = p_NewB = 0;185p_CurrB = p_MM->freeBlocks[i];186187alignment = (uint64_t)(0x1 << i);188alignBase = MAKE_ALIGNED(base, alignment);189190/* Goes to the next free list if there is no block to free */191if (alignBase >= end)192continue;193194/* Looks for a free block that should be updated */195while ( p_CurrB )196{197if ( alignBase <= p_CurrB->end )198{199if ( end > p_CurrB->end )200{201t_FreeBlock *p_NextB;202while ( p_CurrB->p_Next && end > p_CurrB->p_Next->end )203{204p_NextB = p_CurrB->p_Next;205p_CurrB->p_Next = p_CurrB->p_Next->p_Next;206XX_Free(p_NextB);207}208209p_NextB = p_CurrB->p_Next;210if ( !p_NextB || (p_NextB && end < p_NextB->base) )211{212p_CurrB->end = end;213}214else215{216p_CurrB->end = p_NextB->end;217p_CurrB->p_Next = p_NextB->p_Next;218XX_Free(p_NextB);219}220}221else if ( (end < p_CurrB->base) && ((end-alignBase) >= alignment) )222{223if ((p_NewB = CreateFreeBlock(alignBase, end-alignBase)) == NULL)224RETURN_ERROR(MAJOR, E_NO_MEMORY, NO_MSG);225226p_NewB->p_Next = p_CurrB;227if (p_PrevB)228p_PrevB->p_Next = p_NewB;229else230p_MM->freeBlocks[i] = p_NewB;231break;232}233234if ((alignBase < p_CurrB->base) && (end >= p_CurrB->base))235{236p_CurrB->base = alignBase;237}238239/* if size of the free block is less then alignment240* deletes that free block from the free list. */241if ( (p_CurrB->end - p_CurrB->base) < alignment)242{243if ( p_PrevB )244p_PrevB->p_Next = p_CurrB->p_Next;245else246p_MM->freeBlocks[i] = p_CurrB->p_Next;247XX_Free(p_CurrB);248p_CurrB = NULL;249}250break;251}252else253{254p_PrevB = p_CurrB;255p_CurrB = p_CurrB->p_Next;256}257}258259/* If no free block found to be updated, insert a new free block260* to the end of the free list.261*/262if ( !p_CurrB && ((((uint64_t)(end-base)) & ((uint64_t)(alignment-1))) == 0) )263{264if ((p_NewB = CreateFreeBlock(alignBase, end-base)) == NULL)265RETURN_ERROR(MAJOR, E_NO_MEMORY, NO_MSG);266267if (p_PrevB)268p_PrevB->p_Next = p_NewB;269else270p_MM->freeBlocks[i] = p_NewB;271}272273/* Update boundaries of the new free block */274if ((alignment == 1) && !p_NewB)275{276if ( p_CurrB && base > p_CurrB->base )277base = p_CurrB->base;278if ( p_CurrB && end < p_CurrB->end )279end = p_CurrB->end;280}281}282283return (E_OK);284}285286/****************************************************************287* Routine: CutFree288*289* Description:290* Cuts a free block from holdBase to holdEnd from the free lists.291* That is, it updates all free lists of the MM object do292* not include a block of memory from holdBase to holdEnd.293* For each free lists it seek for a free block that holds294* either holdBase or holdEnd. If such block is found it updates it.295*296* Arguments:297* p_MM - pointer to the MM object298* holdBase - base address of the allocated block299* holdEnd - end address of the allocated block300*301* Return value:302* E_OK is returned on success,303* otherwise returns an error code.304*305****************************************************************/306static t_Error CutFree(t_MM *p_MM, uint64_t holdBase, uint64_t holdEnd)307{308t_FreeBlock *p_PrevB, *p_CurrB, *p_NewB;309uint64_t alignBase, base, end;310uint64_t alignment;311int i;312313for (i=0; i <= MM_MAX_ALIGNMENT; i++)314{315p_PrevB = p_NewB = 0;316p_CurrB = p_MM->freeBlocks[i];317318alignment = (uint64_t)(0x1 << i);319alignBase = MAKE_ALIGNED(holdEnd, alignment);320321while ( p_CurrB )322{323base = p_CurrB->base;324end = p_CurrB->end;325326if ( (holdBase <= base) && (holdEnd <= end) && (holdEnd > base) )327{328if ( alignBase >= end ||329(alignBase < end && ((end-alignBase) < alignment)) )330{331if (p_PrevB)332p_PrevB->p_Next = p_CurrB->p_Next;333else334p_MM->freeBlocks[i] = p_CurrB->p_Next;335XX_Free(p_CurrB);336}337else338{339p_CurrB->base = alignBase;340}341break;342}343else if ( (holdBase > base) && (holdEnd <= end) )344{345if ( (holdBase-base) >= alignment )346{347if ( (alignBase < end) && ((end-alignBase) >= alignment) )348{349if ((p_NewB = CreateFreeBlock(alignBase, end-alignBase)) == NULL)350RETURN_ERROR(MAJOR, E_NO_MEMORY, NO_MSG);351p_NewB->p_Next = p_CurrB->p_Next;352p_CurrB->p_Next = p_NewB;353}354p_CurrB->end = holdBase;355}356else if ( (alignBase < end) && ((end-alignBase) >= alignment) )357{358p_CurrB->base = alignBase;359}360else361{362if (p_PrevB)363p_PrevB->p_Next = p_CurrB->p_Next;364else365p_MM->freeBlocks[i] = p_CurrB->p_Next;366XX_Free(p_CurrB);367}368break;369}370else371{372p_PrevB = p_CurrB;373p_CurrB = p_CurrB->p_Next;374}375}376}377378return (E_OK);379}380381/****************************************************************382* Routine: AddBusy383*384* Description:385* Adds a new busy block to the list of busy blocks. Note,386* that all busy blocks are ordered by their base address in387* the busy list.388*389* Arguments:390* MM - handler to the MM object391* p_NewBusyB - pointer to the a busy block392*393* Return value:394* None.395*396****************************************************************/397static void AddBusy(t_MM *p_MM, t_BusyBlock *p_NewBusyB)398{399t_BusyBlock *p_CurrBusyB, *p_PrevBusyB;400401/* finds a place of a new busy block in the list of busy blocks */402p_PrevBusyB = 0;403p_CurrBusyB = p_MM->busyBlocks;404405while ( p_CurrBusyB && p_NewBusyB->base > p_CurrBusyB->base )406{407p_PrevBusyB = p_CurrBusyB;408p_CurrBusyB = p_CurrBusyB->p_Next;409}410411/* insert the new busy block into the list of busy blocks */412if ( p_CurrBusyB )413p_NewBusyB->p_Next = p_CurrBusyB;414if ( p_PrevBusyB )415p_PrevBusyB->p_Next = p_NewBusyB;416else417p_MM->busyBlocks = p_NewBusyB;418}419420/****************************************************************421* Routine: CutBusy422*423* Description:424* Cuts a block from base to end from the list of busy blocks.425* This is done by updating the list of busy blocks do not426* include a given block, that block is going to be free. If a427* given block is a part of some other busy block, so that428* busy block is updated. If there are number of busy blocks429* included in the given block, so all that blocks are removed430* from the busy list and the end blocks are updated.431* If the given block devides some block into two parts, a new432* busy block is added to the busy list.433*434* Arguments:435* p_MM - pointer to the MM object436* base - base address of a given busy block437* end - end address of a given busy block438*439* Return value:440* E_OK on success, E_NOMEMORY otherwise.441*442****************************************************************/443static t_Error CutBusy(t_MM *p_MM, uint64_t base, uint64_t end)444{445t_BusyBlock *p_CurrB, *p_PrevB, *p_NewB;446447p_CurrB = p_MM->busyBlocks;448p_PrevB = p_NewB = 0;449450while ( p_CurrB )451{452if ( base < p_CurrB->end )453{454if ( end > p_CurrB->end )455{456t_BusyBlock *p_NextB;457while ( p_CurrB->p_Next && end >= p_CurrB->p_Next->end )458{459p_NextB = p_CurrB->p_Next;460p_CurrB->p_Next = p_CurrB->p_Next->p_Next;461XX_Free(p_NextB);462}463464p_NextB = p_CurrB->p_Next;465if ( p_NextB && end > p_NextB->base )466{467p_NextB->base = end;468}469}470471if ( base <= p_CurrB->base )472{473if ( end < p_CurrB->end && end > p_CurrB->base )474{475p_CurrB->base = end;476}477else if ( end >= p_CurrB->end )478{479if ( p_PrevB )480p_PrevB->p_Next = p_CurrB->p_Next;481else482p_MM->busyBlocks = p_CurrB->p_Next;483XX_Free(p_CurrB);484}485}486else487{488if ( end < p_CurrB->end && end > p_CurrB->base )489{490if ((p_NewB = CreateBusyBlock(end,491p_CurrB->end-end,492p_CurrB->name)) == NULL)493RETURN_ERROR(MAJOR, E_NO_MEMORY, NO_MSG);494p_NewB->p_Next = p_CurrB->p_Next;495p_CurrB->p_Next = p_NewB;496}497p_CurrB->end = base;498}499break;500}501else502{503p_PrevB = p_CurrB;504p_CurrB = p_CurrB->p_Next;505}506}507508return (E_OK);509}510511/****************************************************************512* Routine: MmGetGreaterAlignment513*514* Description:515* Allocates a block of memory according to the given size516* and the alignment. That routine is called from the MM_Get517* routine if the required alignment is greater then MM_MAX_ALIGNMENT.518* In that case, it goes over free blocks of 64 byte align list519* and checks if it has the required size of bytes of the required520* alignment. If no blocks found returns ILLEGAL_BASE.521* After the block is found and data is allocated, it calls522* the internal CutFree routine to update all free lists523* do not include a just allocated block. Of course, each524* free list contains a free blocks with the same alignment.525* It is also creates a busy block that holds526* information about an allocated block.527*528* Arguments:529* MM - handle to the MM object530* size - size of the MM531* alignment - index as a power of two defines532* a required alignment that is greater then 64.533* name - the name that specifies an allocated block.534*535* Return value:536* base address of an allocated block.537* ILLEGAL_BASE if can't allocate a block538*539****************************************************************/540static uint64_t MmGetGreaterAlignment(t_MM *p_MM, uint64_t size, uint64_t alignment, char* name)541{542t_FreeBlock *p_FreeB;543t_BusyBlock *p_NewBusyB;544uint64_t holdBase, holdEnd, alignBase = 0;545546/* goes over free blocks of the 64 byte alignment list547and look for a block of the suitable size and548base address according to the alignment. */549p_FreeB = p_MM->freeBlocks[MM_MAX_ALIGNMENT];550551while ( p_FreeB )552{553alignBase = MAKE_ALIGNED(p_FreeB->base, alignment);554555/* the block is found if the aligned base inside the block556* and has the anough size. */557if ( alignBase >= p_FreeB->base &&558alignBase < p_FreeB->end &&559size <= (p_FreeB->end - alignBase) )560break;561else562p_FreeB = p_FreeB->p_Next;563}564565/* If such block isn't found */566if ( !p_FreeB )567return (uint64_t)(ILLEGAL_BASE);568569holdBase = alignBase;570holdEnd = alignBase + size;571572/* init a new busy block */573if ((p_NewBusyB = CreateBusyBlock(holdBase, size, name)) == NULL)574return (uint64_t)(ILLEGAL_BASE);575576/* calls Update routine to update a lists of free blocks */577if ( CutFree ( p_MM, holdBase, holdEnd ) != E_OK )578{579XX_Free(p_NewBusyB);580return (uint64_t)(ILLEGAL_BASE);581}582583/* insert the new busy block into the list of busy blocks */584AddBusy ( p_MM, p_NewBusyB );585586return (holdBase);587}588589590/**********************************************************************591* MM API routines set *592**********************************************************************/593594/*****************************************************************************/595t_Error MM_Init(t_Handle *h_MM, uint64_t base, uint64_t size)596{597t_MM *p_MM;598uint64_t newBase, newSize;599int i;600601if (!size)602{603RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("Size (should be positive)"));604}605606/* Initializes a new MM object */607p_MM = (t_MM *)XX_Malloc(sizeof(t_MM));608if (!p_MM)609{610RETURN_ERROR(MAJOR, E_NO_MEMORY, NO_MSG);611}612613p_MM->h_Spinlock = XX_InitSpinlock();614if (!p_MM->h_Spinlock)615{616XX_Free(p_MM);617RETURN_ERROR(MAJOR, E_NO_MEMORY, ("MM spinlock!"));618}619620/* Initializes counter of free memory to total size */621p_MM->freeMemSize = size;622623/* A busy list is empty */624p_MM->busyBlocks = 0;625626/* Initializes a new memory block */627if ((p_MM->memBlocks = CreateNewBlock(base, size)) == NULL)628{629MM_Free(p_MM);630RETURN_ERROR(MAJOR, E_NO_MEMORY, NO_MSG);631}632633/* Initializes a new free block for each free list*/634for (i=0; i <= MM_MAX_ALIGNMENT; i++)635{636newBase = MAKE_ALIGNED( base, (0x1 << i) );637newSize = size - (newBase - base);638639if ((p_MM->freeBlocks[i] = CreateFreeBlock(newBase, newSize)) == NULL)640{641MM_Free(p_MM);642RETURN_ERROR(MAJOR, E_NO_MEMORY, NO_MSG);643}644}645646*h_MM = p_MM;647648return (E_OK);649}650651/*****************************************************************************/652void MM_Free(t_Handle h_MM)653{654t_MM *p_MM = (t_MM *)h_MM;655t_MemBlock *p_MemBlock;656t_BusyBlock *p_BusyBlock;657t_FreeBlock *p_FreeBlock;658void *p_Block;659int i;660661ASSERT_COND(p_MM);662663/* release memory allocated for busy blocks */664p_BusyBlock = p_MM->busyBlocks;665while ( p_BusyBlock )666{667p_Block = p_BusyBlock;668p_BusyBlock = p_BusyBlock->p_Next;669XX_Free(p_Block);670}671672/* release memory allocated for free blocks */673for (i=0; i <= MM_MAX_ALIGNMENT; i++)674{675p_FreeBlock = p_MM->freeBlocks[i];676while ( p_FreeBlock )677{678p_Block = p_FreeBlock;679p_FreeBlock = p_FreeBlock->p_Next;680XX_Free(p_Block);681}682}683684/* release memory allocated for memory blocks */685p_MemBlock = p_MM->memBlocks;686while ( p_MemBlock )687{688p_Block = p_MemBlock;689p_MemBlock = p_MemBlock->p_Next;690XX_Free(p_Block);691}692693if (p_MM->h_Spinlock)694XX_FreeSpinlock(p_MM->h_Spinlock);695696/* release memory allocated for MM object itself */697XX_Free(p_MM);698}699700/*****************************************************************************/701uint64_t MM_Get(t_Handle h_MM, uint64_t size, uint64_t alignment, char* name)702{703t_MM *p_MM = (t_MM *)h_MM;704t_FreeBlock *p_FreeB;705t_BusyBlock *p_NewBusyB;706uint64_t holdBase, holdEnd, j, i = 0;707uint32_t intFlags;708709SANITY_CHECK_RETURN_VALUE(p_MM, E_INVALID_HANDLE, (uint64_t)ILLEGAL_BASE);710711/* checks that alignment value is greater then zero */712if (alignment == 0)713{714alignment = 1;715}716717j = alignment;718719/* checks if alignment is a power of two, if it correct and if the720required size is multiple of the given alignment. */721while ((j & 0x1) == 0)722{723i++;724j = j >> 1;725}726727/* if the given alignment isn't power of two, returns an error */728if (j != 1)729{730REPORT_ERROR(MAJOR, E_INVALID_VALUE, ("alignment (should be power of 2)"));731return (uint64_t)ILLEGAL_BASE;732}733734if (i > MM_MAX_ALIGNMENT)735{736return (MmGetGreaterAlignment(p_MM, size, alignment, name));737}738739intFlags = XX_LockIntrSpinlock(p_MM->h_Spinlock);740/* look for a block of the size greater or equal to the required size. */741p_FreeB = p_MM->freeBlocks[i];742while ( p_FreeB && (p_FreeB->end - p_FreeB->base) < size )743p_FreeB = p_FreeB->p_Next;744745/* If such block is found */746if ( !p_FreeB )747{748XX_UnlockIntrSpinlock(p_MM->h_Spinlock, intFlags);749return (uint64_t)(ILLEGAL_BASE);750}751752holdBase = p_FreeB->base;753holdEnd = holdBase + size;754755/* init a new busy block */756if ((p_NewBusyB = CreateBusyBlock(holdBase, size, name)) == NULL)757{758XX_UnlockIntrSpinlock(p_MM->h_Spinlock, intFlags);759return (uint64_t)(ILLEGAL_BASE);760}761762/* calls Update routine to update a lists of free blocks */763if ( CutFree ( p_MM, holdBase, holdEnd ) != E_OK )764{765XX_UnlockIntrSpinlock(p_MM->h_Spinlock, intFlags);766XX_Free(p_NewBusyB);767return (uint64_t)(ILLEGAL_BASE);768}769770/* Decreasing the allocated memory size from free memory size */771p_MM->freeMemSize -= size;772773/* insert the new busy block into the list of busy blocks */774AddBusy ( p_MM, p_NewBusyB );775XX_UnlockIntrSpinlock(p_MM->h_Spinlock, intFlags);776777return (holdBase);778}779780/*****************************************************************************/781uint64_t MM_GetForce(t_Handle h_MM, uint64_t base, uint64_t size, char* name)782{783t_MM *p_MM = (t_MM *)h_MM;784t_FreeBlock *p_FreeB;785t_BusyBlock *p_NewBusyB;786uint32_t intFlags;787bool blockIsFree = FALSE;788789ASSERT_COND(p_MM);790791intFlags = XX_LockIntrSpinlock(p_MM->h_Spinlock);792p_FreeB = p_MM->freeBlocks[0]; /* The biggest free blocks are in the793free list with alignment 1 */794795while ( p_FreeB )796{797if ( base >= p_FreeB->base && (base+size) <= p_FreeB->end )798{799blockIsFree = TRUE;800break;801}802else803p_FreeB = p_FreeB->p_Next;804}805806if ( !blockIsFree )807{808XX_UnlockIntrSpinlock(p_MM->h_Spinlock, intFlags);809return (uint64_t)(ILLEGAL_BASE);810}811812/* init a new busy block */813if ((p_NewBusyB = CreateBusyBlock(base, size, name)) == NULL)814{815XX_UnlockIntrSpinlock(p_MM->h_Spinlock, intFlags);816return (uint64_t)(ILLEGAL_BASE);817}818819/* calls Update routine to update a lists of free blocks */820if ( CutFree ( p_MM, base, base+size ) != E_OK )821{822XX_UnlockIntrSpinlock(p_MM->h_Spinlock, intFlags);823XX_Free(p_NewBusyB);824return (uint64_t)(ILLEGAL_BASE);825}826827/* Decreasing the allocated memory size from free memory size */828p_MM->freeMemSize -= size;829830/* insert the new busy block into the list of busy blocks */831AddBusy ( p_MM, p_NewBusyB );832XX_UnlockIntrSpinlock(p_MM->h_Spinlock, intFlags);833834return (base);835}836837/*****************************************************************************/838uint64_t MM_GetForceMin(t_Handle h_MM, uint64_t size, uint64_t alignment, uint64_t min, char* name)839{840t_MM *p_MM = (t_MM *)h_MM;841t_FreeBlock *p_FreeB;842t_BusyBlock *p_NewBusyB;843uint64_t holdBase, holdEnd, j = alignment, i=0;844uint32_t intFlags;845846ASSERT_COND(p_MM);847848/* checks if alignment is a power of two, if it correct and if the849required size is multiple of the given alignment. */850while ((j & 0x1) == 0)851{852i++;853j = j >> 1;854}855856if ( (j != 1) || (i > MM_MAX_ALIGNMENT) )857{858return (uint64_t)(ILLEGAL_BASE);859}860861intFlags = XX_LockIntrSpinlock(p_MM->h_Spinlock);862p_FreeB = p_MM->freeBlocks[i];863864/* look for the first block that contains the minimum865base address. If the whole required size may be fit866into it, use that block, otherwise look for the next867block of size greater or equal to the required size. */868while ( p_FreeB && (min >= p_FreeB->end))869p_FreeB = p_FreeB->p_Next;870871/* If such block is found */872if ( !p_FreeB )873{874XX_UnlockIntrSpinlock(p_MM->h_Spinlock, intFlags);875return (uint64_t)(ILLEGAL_BASE);876}877878/* if this block is large enough, use this block */879holdBase = ( min <= p_FreeB->base ) ? p_FreeB->base : min;880if ((holdBase + size) <= p_FreeB->end )881{882holdEnd = holdBase + size;883}884else885{886p_FreeB = p_FreeB->p_Next;887while ( p_FreeB && ((p_FreeB->end - p_FreeB->base) < size) )888p_FreeB = p_FreeB->p_Next;889890/* If such block is found */891if ( !p_FreeB )892{893XX_UnlockIntrSpinlock(p_MM->h_Spinlock, intFlags);894return (uint64_t)(ILLEGAL_BASE);895}896897holdBase = p_FreeB->base;898holdEnd = holdBase + size;899}900901/* init a new busy block */902if ((p_NewBusyB = CreateBusyBlock(holdBase, size, name)) == NULL)903{904XX_UnlockIntrSpinlock(p_MM->h_Spinlock, intFlags);905return (uint64_t)(ILLEGAL_BASE);906}907908/* calls Update routine to update a lists of free blocks */909if ( CutFree( p_MM, holdBase, holdEnd ) != E_OK )910{911XX_UnlockIntrSpinlock(p_MM->h_Spinlock, intFlags);912XX_Free(p_NewBusyB);913return (uint64_t)(ILLEGAL_BASE);914}915916/* Decreasing the allocated memory size from free memory size */917p_MM->freeMemSize -= size;918919/* insert the new busy block into the list of busy blocks */920AddBusy( p_MM, p_NewBusyB );921XX_UnlockIntrSpinlock(p_MM->h_Spinlock, intFlags);922923return (holdBase);924}925926/*****************************************************************************/927uint64_t MM_Put(t_Handle h_MM, uint64_t base)928{929t_MM *p_MM = (t_MM *)h_MM;930t_BusyBlock *p_BusyB, *p_PrevBusyB;931uint64_t size;932uint32_t intFlags;933934ASSERT_COND(p_MM);935936/* Look for a busy block that have the given base value.937* That block will be returned back to the memory.938*/939p_PrevBusyB = 0;940941intFlags = XX_LockIntrSpinlock(p_MM->h_Spinlock);942p_BusyB = p_MM->busyBlocks;943while ( p_BusyB && base != p_BusyB->base )944{945p_PrevBusyB = p_BusyB;946p_BusyB = p_BusyB->p_Next;947}948949if ( !p_BusyB )950{951XX_UnlockIntrSpinlock(p_MM->h_Spinlock, intFlags);952return (uint64_t)(0);953}954955if ( AddFree( p_MM, p_BusyB->base, p_BusyB->end ) != E_OK )956{957XX_UnlockIntrSpinlock(p_MM->h_Spinlock, intFlags);958return (uint64_t)(0);959}960961/* removes a busy block form the list of busy blocks */962if ( p_PrevBusyB )963p_PrevBusyB->p_Next = p_BusyB->p_Next;964else965p_MM->busyBlocks = p_BusyB->p_Next;966967size = p_BusyB->end - p_BusyB->base;968969/* Adding the deallocated memory size to free memory size */970p_MM->freeMemSize += size;971972XX_Free(p_BusyB);973XX_UnlockIntrSpinlock(p_MM->h_Spinlock, intFlags);974975return (size);976}977978/*****************************************************************************/979uint64_t MM_PutForce(t_Handle h_MM, uint64_t base, uint64_t size)980{981t_MM *p_MM = (t_MM *)h_MM;982uint64_t end = base + size;983uint32_t intFlags;984985ASSERT_COND(p_MM);986987intFlags = XX_LockIntrSpinlock(p_MM->h_Spinlock);988989if ( CutBusy( p_MM, base, end ) != E_OK )990{991XX_UnlockIntrSpinlock(p_MM->h_Spinlock, intFlags);992return (uint64_t)(0);993}994995if ( AddFree ( p_MM, base, end ) != E_OK )996{997XX_UnlockIntrSpinlock(p_MM->h_Spinlock, intFlags);998return (uint64_t)(0);999}10001001/* Adding the deallocated memory size to free memory size */1002p_MM->freeMemSize += size;10031004XX_UnlockIntrSpinlock(p_MM->h_Spinlock, intFlags);10051006return (size);1007}10081009/*****************************************************************************/1010t_Error MM_Add(t_Handle h_MM, uint64_t base, uint64_t size)1011{1012t_MM *p_MM = (t_MM *)h_MM;1013t_MemBlock *p_MemB, *p_NewMemB;1014t_Error errCode;1015uint32_t intFlags;10161017ASSERT_COND(p_MM);10181019/* find a last block in the list of memory blocks to insert a new1020* memory block1021*/1022intFlags = XX_LockIntrSpinlock(p_MM->h_Spinlock);10231024p_MemB = p_MM->memBlocks;1025while ( p_MemB->p_Next )1026{1027if ( base >= p_MemB->base && base < p_MemB->end )1028{1029XX_UnlockIntrSpinlock(p_MM->h_Spinlock, intFlags);1030RETURN_ERROR(MAJOR, E_ALREADY_EXISTS, NO_MSG);1031}1032p_MemB = p_MemB->p_Next;1033}1034/* check for a last memory block */1035if ( base >= p_MemB->base && base < p_MemB->end )1036{1037XX_UnlockIntrSpinlock(p_MM->h_Spinlock, intFlags);1038RETURN_ERROR(MAJOR, E_ALREADY_EXISTS, NO_MSG);1039}10401041/* create a new memory block */1042if ((p_NewMemB = CreateNewBlock(base, size)) == NULL)1043{1044XX_UnlockIntrSpinlock(p_MM->h_Spinlock, intFlags);1045RETURN_ERROR(MAJOR, E_NO_MEMORY, NO_MSG);1046}10471048/* append a new memory block to the end of the list of memory blocks */1049p_MemB->p_Next = p_NewMemB;10501051/* add a new free block to the free lists */1052errCode = AddFree(p_MM, base, base+size);1053if (errCode)1054{1055XX_UnlockIntrSpinlock(p_MM->h_Spinlock, intFlags);1056p_MemB->p_Next = 0;1057XX_Free(p_NewMemB);1058return ((t_Error)errCode);1059}10601061/* Adding the new block size to free memory size */1062p_MM->freeMemSize += size;10631064XX_UnlockIntrSpinlock(p_MM->h_Spinlock, intFlags);10651066return (E_OK);1067}10681069/*****************************************************************************/1070uint64_t MM_GetMemBlock(t_Handle h_MM, int index)1071{1072t_MM *p_MM = (t_MM*)h_MM;1073t_MemBlock *p_MemBlock;1074int i;10751076ASSERT_COND(p_MM);10771078p_MemBlock = p_MM->memBlocks;1079for (i=0; i < index; i++)1080p_MemBlock = p_MemBlock->p_Next;10811082if ( p_MemBlock )1083return (p_MemBlock->base);1084else1085return (uint64_t)ILLEGAL_BASE;1086}10871088/*****************************************************************************/1089uint64_t MM_GetBase(t_Handle h_MM)1090{1091t_MM *p_MM = (t_MM*)h_MM;1092t_MemBlock *p_MemBlock;10931094ASSERT_COND(p_MM);10951096p_MemBlock = p_MM->memBlocks;1097return p_MemBlock->base;1098}10991100/*****************************************************************************/1101bool MM_InRange(t_Handle h_MM, uint64_t addr)1102{1103t_MM *p_MM = (t_MM*)h_MM;1104t_MemBlock *p_MemBlock;11051106ASSERT_COND(p_MM);11071108p_MemBlock = p_MM->memBlocks;11091110if ((addr >= p_MemBlock->base) && (addr < p_MemBlock->end))1111return TRUE;1112else1113return FALSE;1114}11151116/*****************************************************************************/1117uint64_t MM_GetFreeMemSize(t_Handle h_MM)1118{1119t_MM *p_MM = (t_MM*)h_MM;11201121ASSERT_COND(p_MM);11221123return p_MM->freeMemSize;1124}11251126/*****************************************************************************/1127void MM_Dump(t_Handle h_MM)1128{1129t_MM *p_MM = (t_MM *)h_MM;1130t_FreeBlock *p_FreeB;1131t_BusyBlock *p_BusyB;1132int i;11331134p_BusyB = p_MM->busyBlocks;1135XX_Print("List of busy blocks:\n");1136while (p_BusyB)1137{1138XX_Print("\t0x%p: (%s: b=0x%llx, e=0x%llx)\n", p_BusyB, p_BusyB->name, p_BusyB->base, p_BusyB->end );1139p_BusyB = p_BusyB->p_Next;1140}11411142XX_Print("\nLists of free blocks according to alignment:\n");1143for (i=0; i <= MM_MAX_ALIGNMENT; i++)1144{1145XX_Print("%d alignment:\n", (0x1 << i));1146p_FreeB = p_MM->freeBlocks[i];1147while (p_FreeB)1148{1149XX_Print("\t0x%p: (b=0x%llx, e=0x%llx)\n", p_FreeB, p_FreeB->base, p_FreeB->end);1150p_FreeB = p_FreeB->p_Next;1151}1152XX_Print("\n");1153}1154}115511561157