2 * Copyright 2008-2012 Freescale Semiconductor Inc.
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions are met:
6 * * Redistributions of source code must retain the above copyright
7 * notice, this list of conditions and the following disclaimer.
8 * * Redistributions in binary form must reproduce the above copyright
9 * notice, this list of conditions and the following disclaimer in the
10 * documentation and/or other materials provided with the distribution.
11 * * Neither the name of Freescale Semiconductor nor the
12 * names of its contributors may be used to endorse or promote products
13 * derived from this software without specific prior written permission.
16 * ALTERNATIVELY, this software may be distributed under the terms of the
17 * GNU General Public License ("GPL") as published by the Free Software
18 * Foundation, either version 2 of that License or (at your option) any
21 * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``AS IS'' AND ANY
22 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
23 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
24 * DISCLAIMED. IN NO EVENT SHALL Freescale Semiconductor BE LIABLE FOR ANY
25 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
26 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
27 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
28 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
29 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
30 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
34 #include "string_ext.h"
35 #include "error_ext.h"
45 /**********************************************************************
46 * MM internal routines set *
47 **********************************************************************/
49 /****************************************************************
50 * Routine: CreateBusyBlock
53 * Initializes a new busy block of "size" bytes and started
54 * rom "base" address. Each busy block has a name that
55 * specified the purpose of the memory allocation.
58 * base - base address of the busy block
59 * size - size of the busy block
60 * name - name that specified the busy block
63 * A pointer to new created structure returned on success;
65 ****************************************************************/
66 static t_BusyBlock * CreateBusyBlock(uint64_t base, uint64_t size, char *name)
68 t_BusyBlock *p_BusyBlock;
71 p_BusyBlock = (t_BusyBlock *)XX_Malloc(sizeof(t_BusyBlock));
74 REPORT_ERROR(MAJOR, E_NO_MEMORY, NO_MSG);
78 p_BusyBlock->base = base;
79 p_BusyBlock->end = base + size;
82 if (n >= MM_MAX_NAME_LEN)
83 n = MM_MAX_NAME_LEN - 1;
84 strncpy(p_BusyBlock->name, name, MM_MAX_NAME_LEN-1);
85 p_BusyBlock->name[n] = '\0';
86 p_BusyBlock->p_Next = 0;
91 /****************************************************************
92 * Routine: CreateNewBlock
95 * Initializes a new memory block of "size" bytes and started
96 * from "base" address.
99 * base - base address of the memory block
100 * size - size of the memory block
103 * A pointer to new created structure returned on success;
105 ****************************************************************/
106 static t_MemBlock * CreateNewBlock(uint64_t base, uint64_t size)
108 t_MemBlock *p_MemBlock;
110 p_MemBlock = (t_MemBlock *)XX_Malloc(sizeof(t_MemBlock));
113 REPORT_ERROR(MAJOR, E_NO_MEMORY, NO_MSG);
117 p_MemBlock->base = base;
118 p_MemBlock->end = base+size;
119 p_MemBlock->p_Next = 0;
124 /****************************************************************
125 * Routine: CreateFreeBlock
128 * Initializes a new free block of of "size" bytes and
129 * started from "base" address.
132 * base - base address of the free block
133 * size - size of the free block
136 * A pointer to new created structure returned on success;
138 ****************************************************************/
139 static t_FreeBlock * CreateFreeBlock(uint64_t base, uint64_t size)
141 t_FreeBlock *p_FreeBlock;
143 p_FreeBlock = (t_FreeBlock *)XX_Malloc(sizeof(t_FreeBlock));
146 REPORT_ERROR(MAJOR, E_NO_MEMORY, NO_MSG);
150 p_FreeBlock->base = base;
151 p_FreeBlock->end = base + size;
152 p_FreeBlock->p_Next = 0;
157 /****************************************************************
161 * Adds a new free block to the free lists. It updates each
162 * free list to include a new free block.
163 * Note, that all free block in each free list are ordered
164 * by their base address.
167 * p_MM - pointer to the MM object
168 * base - base address of a given free block
169 * end - end address of a given free block
174 ****************************************************************/
175 static t_Error AddFree(t_MM *p_MM, uint64_t base, uint64_t end)
177 t_FreeBlock *p_PrevB, *p_CurrB, *p_NewB;
182 /* Updates free lists to include a just released block */
183 for (i=0; i <= MM_MAX_ALIGNMENT; i++)
185 p_PrevB = p_NewB = 0;
186 p_CurrB = p_MM->freeBlocks[i];
188 alignment = (uint64_t)(0x1 << i);
189 alignBase = MAKE_ALIGNED(base, alignment);
191 /* Goes to the next free list if there is no block to free */
192 if (alignBase >= end)
195 /* Looks for a free block that should be updated */
198 if ( alignBase <= p_CurrB->end )
200 if ( end > p_CurrB->end )
202 t_FreeBlock *p_NextB;
203 while ( p_CurrB->p_Next && end > p_CurrB->p_Next->end )
205 p_NextB = p_CurrB->p_Next;
206 p_CurrB->p_Next = p_CurrB->p_Next->p_Next;
210 p_NextB = p_CurrB->p_Next;
211 if ( !p_NextB || (p_NextB && end < p_NextB->base) )
217 p_CurrB->end = p_NextB->end;
218 p_CurrB->p_Next = p_NextB->p_Next;
222 else if ( (end < p_CurrB->base) && ((end-alignBase) >= alignment) )
224 if ((p_NewB = CreateFreeBlock(alignBase, end-alignBase)) == NULL)
225 RETURN_ERROR(MAJOR, E_NO_MEMORY, NO_MSG);
227 p_NewB->p_Next = p_CurrB;
229 p_PrevB->p_Next = p_NewB;
231 p_MM->freeBlocks[i] = p_NewB;
235 if ((alignBase < p_CurrB->base) && (end >= p_CurrB->base))
237 p_CurrB->base = alignBase;
240 /* if size of the free block is less then alignment
241 * deletes that free block from the free list. */
242 if ( (p_CurrB->end - p_CurrB->base) < alignment)
245 p_PrevB->p_Next = p_CurrB->p_Next;
247 p_MM->freeBlocks[i] = p_CurrB->p_Next;
256 p_CurrB = p_CurrB->p_Next;
260 /* If no free block found to be updated, insert a new free block
261 * to the end of the free list.
263 if ( !p_CurrB && ((((uint64_t)(end-base)) & ((uint64_t)(alignment-1))) == 0) )
265 if ((p_NewB = CreateFreeBlock(alignBase, end-base)) == NULL)
266 RETURN_ERROR(MAJOR, E_NO_MEMORY, NO_MSG);
269 p_PrevB->p_Next = p_NewB;
271 p_MM->freeBlocks[i] = p_NewB;
274 /* Update boundaries of the new free block */
275 if ((alignment == 1) && !p_NewB)
277 if ( p_CurrB && base > p_CurrB->base )
278 base = p_CurrB->base;
279 if ( p_CurrB && end < p_CurrB->end )
287 /****************************************************************
291 * Cuts a free block from holdBase to holdEnd from the free lists.
292 * That is, it updates all free lists of the MM object do
293 * not include a block of memory from holdBase to holdEnd.
294 * For each free lists it seek for a free block that holds
295 * either holdBase or holdEnd. If such block is found it updates it.
298 * p_MM - pointer to the MM object
299 * holdBase - base address of the allocated block
300 * holdEnd - end address of the allocated block
303 * E_OK is returned on success,
304 * otherwise returns an error code.
306 ****************************************************************/
307 static t_Error CutFree(t_MM *p_MM, uint64_t holdBase, uint64_t holdEnd)
309 t_FreeBlock *p_PrevB, *p_CurrB, *p_NewB;
310 uint64_t alignBase, base, end;
314 for (i=0; i <= MM_MAX_ALIGNMENT; i++)
316 p_PrevB = p_NewB = 0;
317 p_CurrB = p_MM->freeBlocks[i];
319 alignment = (uint64_t)(0x1 << i);
320 alignBase = MAKE_ALIGNED(holdEnd, alignment);
324 base = p_CurrB->base;
327 if ( (holdBase <= base) && (holdEnd <= end) && (holdEnd > base) )
329 if ( alignBase >= end ||
330 (alignBase < end && ((end-alignBase) < alignment)) )
333 p_PrevB->p_Next = p_CurrB->p_Next;
335 p_MM->freeBlocks[i] = p_CurrB->p_Next;
340 p_CurrB->base = alignBase;
344 else if ( (holdBase > base) && (holdEnd <= end) )
346 if ( (holdBase-base) >= alignment )
348 if ( (alignBase < end) && ((end-alignBase) >= alignment) )
350 if ((p_NewB = CreateFreeBlock(alignBase, end-alignBase)) == NULL)
351 RETURN_ERROR(MAJOR, E_NO_MEMORY, NO_MSG);
352 p_NewB->p_Next = p_CurrB->p_Next;
353 p_CurrB->p_Next = p_NewB;
355 p_CurrB->end = holdBase;
357 else if ( (alignBase < end) && ((end-alignBase) >= alignment) )
359 p_CurrB->base = alignBase;
364 p_PrevB->p_Next = p_CurrB->p_Next;
366 p_MM->freeBlocks[i] = p_CurrB->p_Next;
374 p_CurrB = p_CurrB->p_Next;
382 /****************************************************************
386 * Adds a new busy block to the list of busy blocks. Note,
387 * that all busy blocks are ordered by their base address in
391 * MM - handler to the MM object
392 * p_NewBusyB - pointer to the a busy block
397 ****************************************************************/
398 static void AddBusy(t_MM *p_MM, t_BusyBlock *p_NewBusyB)
400 t_BusyBlock *p_CurrBusyB, *p_PrevBusyB;
402 /* finds a place of a new busy block in the list of busy blocks */
404 p_CurrBusyB = p_MM->busyBlocks;
406 while ( p_CurrBusyB && p_NewBusyB->base > p_CurrBusyB->base )
408 p_PrevBusyB = p_CurrBusyB;
409 p_CurrBusyB = p_CurrBusyB->p_Next;
412 /* insert the new busy block into the list of busy blocks */
414 p_NewBusyB->p_Next = p_CurrBusyB;
416 p_PrevBusyB->p_Next = p_NewBusyB;
418 p_MM->busyBlocks = p_NewBusyB;
421 /****************************************************************
425 * Cuts a block from base to end from the list of busy blocks.
426 * This is done by updating the list of busy blocks do not
427 * include a given block, that block is going to be free. If a
428 * given block is a part of some other busy block, so that
429 * busy block is updated. If there are number of busy blocks
430 * included in the given block, so all that blocks are removed
431 * from the busy list and the end blocks are updated.
432 * If the given block devides some block into two parts, a new
433 * busy block is added to the busy list.
436 * p_MM - pointer to the MM object
437 * base - base address of a given busy block
438 * end - end address of a given busy block
441 * E_OK on success, E_NOMEMORY otherwise.
443 ****************************************************************/
444 static t_Error CutBusy(t_MM *p_MM, uint64_t base, uint64_t end)
446 t_BusyBlock *p_CurrB, *p_PrevB, *p_NewB;
448 p_CurrB = p_MM->busyBlocks;
449 p_PrevB = p_NewB = 0;
453 if ( base < p_CurrB->end )
455 if ( end > p_CurrB->end )
457 t_BusyBlock *p_NextB;
458 while ( p_CurrB->p_Next && end >= p_CurrB->p_Next->end )
460 p_NextB = p_CurrB->p_Next;
461 p_CurrB->p_Next = p_CurrB->p_Next->p_Next;
465 p_NextB = p_CurrB->p_Next;
466 if ( p_NextB && end > p_NextB->base )
472 if ( base <= p_CurrB->base )
474 if ( end < p_CurrB->end && end > p_CurrB->base )
478 else if ( end >= p_CurrB->end )
481 p_PrevB->p_Next = p_CurrB->p_Next;
483 p_MM->busyBlocks = p_CurrB->p_Next;
489 if ( end < p_CurrB->end && end > p_CurrB->base )
491 if ((p_NewB = CreateBusyBlock(end,
493 p_CurrB->name)) == NULL)
494 RETURN_ERROR(MAJOR, E_NO_MEMORY, NO_MSG);
495 p_NewB->p_Next = p_CurrB->p_Next;
496 p_CurrB->p_Next = p_NewB;
505 p_CurrB = p_CurrB->p_Next;
512 /****************************************************************
513 * Routine: MmGetGreaterAlignment
516 * Allocates a block of memory according to the given size
517 * and the alignment. That routine is called from the MM_Get
518 * routine if the required alignment is greater then MM_MAX_ALIGNMENT.
519 * In that case, it goes over free blocks of 64 byte align list
520 * and checks if it has the required size of bytes of the required
521 * alignment. If no blocks found returns ILLEGAL_BASE.
522 * After the block is found and data is allocated, it calls
523 * the internal CutFree routine to update all free lists
524 * do not include a just allocated block. Of course, each
525 * free list contains a free blocks with the same alignment.
526 * It is also creates a busy block that holds
527 * information about an allocated block.
530 * MM - handle to the MM object
531 * size - size of the MM
532 * alignment - index as a power of two defines
533 * a required alignment that is greater then 64.
534 * name - the name that specifies an allocated block.
537 * base address of an allocated block.
538 * ILLEGAL_BASE if can't allocate a block
540 ****************************************************************/
541 static uint64_t MmGetGreaterAlignment(t_MM *p_MM, uint64_t size, uint64_t alignment, char* name)
543 t_FreeBlock *p_FreeB;
544 t_BusyBlock *p_NewBusyB;
545 uint64_t holdBase, holdEnd, alignBase = 0;
547 /* goes over free blocks of the 64 byte alignment list
548 and look for a block of the suitable size and
549 base address according to the alignment. */
550 p_FreeB = p_MM->freeBlocks[MM_MAX_ALIGNMENT];
554 alignBase = MAKE_ALIGNED(p_FreeB->base, alignment);
556 /* the block is found if the aligned base inside the block
557 * and has the anough size. */
558 if ( alignBase >= p_FreeB->base &&
559 alignBase < p_FreeB->end &&
560 size <= (p_FreeB->end - alignBase) )
563 p_FreeB = p_FreeB->p_Next;
566 /* If such block isn't found */
568 return (uint64_t)(ILLEGAL_BASE);
570 holdBase = alignBase;
571 holdEnd = alignBase + size;
573 /* init a new busy block */
574 if ((p_NewBusyB = CreateBusyBlock(holdBase, size, name)) == NULL)
575 return (uint64_t)(ILLEGAL_BASE);
577 /* calls Update routine to update a lists of free blocks */
578 if ( CutFree ( p_MM, holdBase, holdEnd ) != E_OK )
581 return (uint64_t)(ILLEGAL_BASE);
584 /* insert the new busy block into the list of busy blocks */
585 AddBusy ( p_MM, p_NewBusyB );
591 /**********************************************************************
592 * MM API routines set *
593 **********************************************************************/
595 /*****************************************************************************/
596 t_Error MM_Init(t_Handle *h_MM, uint64_t base, uint64_t size)
599 uint64_t newBase, newSize;
604 RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("Size (should be positive)"));
607 /* Initializes a new MM object */
608 p_MM = (t_MM *)XX_Malloc(sizeof(t_MM));
611 RETURN_ERROR(MAJOR, E_NO_MEMORY, NO_MSG);
614 p_MM->h_Spinlock = XX_InitSpinlock();
615 if (!p_MM->h_Spinlock)
618 RETURN_ERROR(MAJOR, E_NO_MEMORY, ("MM spinlock!"));
621 /* Initializes counter of free memory to total size */
622 p_MM->freeMemSize = size;
624 /* A busy list is empty */
625 p_MM->busyBlocks = 0;
627 /* Initializes a new memory block */
628 if ((p_MM->memBlocks = CreateNewBlock(base, size)) == NULL)
631 RETURN_ERROR(MAJOR, E_NO_MEMORY, NO_MSG);
634 /* Initializes a new free block for each free list*/
635 for (i=0; i <= MM_MAX_ALIGNMENT; i++)
637 newBase = MAKE_ALIGNED( base, (0x1 << i) );
638 newSize = size - (newBase - base);
640 if ((p_MM->freeBlocks[i] = CreateFreeBlock(newBase, newSize)) == NULL)
643 RETURN_ERROR(MAJOR, E_NO_MEMORY, NO_MSG);
652 /*****************************************************************************/
653 void MM_Free(t_Handle h_MM)
655 t_MM *p_MM = (t_MM *)h_MM;
656 t_MemBlock *p_MemBlock;
657 t_BusyBlock *p_BusyBlock;
658 t_FreeBlock *p_FreeBlock;
664 /* release memory allocated for busy blocks */
665 p_BusyBlock = p_MM->busyBlocks;
666 while ( p_BusyBlock )
668 p_Block = p_BusyBlock;
669 p_BusyBlock = p_BusyBlock->p_Next;
673 /* release memory allocated for free blocks */
674 for (i=0; i <= MM_MAX_ALIGNMENT; i++)
676 p_FreeBlock = p_MM->freeBlocks[i];
677 while ( p_FreeBlock )
679 p_Block = p_FreeBlock;
680 p_FreeBlock = p_FreeBlock->p_Next;
685 /* release memory allocated for memory blocks */
686 p_MemBlock = p_MM->memBlocks;
689 p_Block = p_MemBlock;
690 p_MemBlock = p_MemBlock->p_Next;
694 if (p_MM->h_Spinlock)
695 XX_FreeSpinlock(p_MM->h_Spinlock);
697 /* release memory allocated for MM object itself */
701 /*****************************************************************************/
702 uint64_t MM_Get(t_Handle h_MM, uint64_t size, uint64_t alignment, char* name)
704 t_MM *p_MM = (t_MM *)h_MM;
705 t_FreeBlock *p_FreeB;
706 t_BusyBlock *p_NewBusyB;
707 uint64_t holdBase, holdEnd, j, i = 0;
710 SANITY_CHECK_RETURN_VALUE(p_MM, E_INVALID_HANDLE, (uint64_t)ILLEGAL_BASE);
712 /* checks that alignment value is greater then zero */
720 /* checks if alignment is a power of two, if it correct and if the
721 required size is multiple of the given alignment. */
722 while ((j & 0x1) == 0)
728 /* if the given alignment isn't power of two, returns an error */
731 REPORT_ERROR(MAJOR, E_INVALID_VALUE, ("alignment (should be power of 2)"));
732 return (uint64_t)ILLEGAL_BASE;
735 if (i > MM_MAX_ALIGNMENT)
737 return (MmGetGreaterAlignment(p_MM, size, alignment, name));
740 intFlags = XX_LockIntrSpinlock(p_MM->h_Spinlock);
741 /* look for a block of the size greater or equal to the required size. */
742 p_FreeB = p_MM->freeBlocks[i];
743 while ( p_FreeB && (p_FreeB->end - p_FreeB->base) < size )
744 p_FreeB = p_FreeB->p_Next;
746 /* If such block is found */
749 XX_UnlockIntrSpinlock(p_MM->h_Spinlock, intFlags);
750 return (uint64_t)(ILLEGAL_BASE);
753 holdBase = p_FreeB->base;
754 holdEnd = holdBase + size;
756 /* init a new busy block */
757 if ((p_NewBusyB = CreateBusyBlock(holdBase, size, name)) == NULL)
759 XX_UnlockIntrSpinlock(p_MM->h_Spinlock, intFlags);
760 return (uint64_t)(ILLEGAL_BASE);
763 /* calls Update routine to update a lists of free blocks */
764 if ( CutFree ( p_MM, holdBase, holdEnd ) != E_OK )
766 XX_UnlockIntrSpinlock(p_MM->h_Spinlock, intFlags);
768 return (uint64_t)(ILLEGAL_BASE);
771 /* Decreasing the allocated memory size from free memory size */
772 p_MM->freeMemSize -= size;
774 /* insert the new busy block into the list of busy blocks */
775 AddBusy ( p_MM, p_NewBusyB );
776 XX_UnlockIntrSpinlock(p_MM->h_Spinlock, intFlags);
781 /*****************************************************************************/
782 uint64_t MM_GetForce(t_Handle h_MM, uint64_t base, uint64_t size, char* name)
784 t_MM *p_MM = (t_MM *)h_MM;
785 t_FreeBlock *p_FreeB;
786 t_BusyBlock *p_NewBusyB;
788 bool blockIsFree = FALSE;
792 intFlags = XX_LockIntrSpinlock(p_MM->h_Spinlock);
793 p_FreeB = p_MM->freeBlocks[0]; /* The biggest free blocks are in the
794 free list with alignment 1 */
798 if ( base >= p_FreeB->base && (base+size) <= p_FreeB->end )
804 p_FreeB = p_FreeB->p_Next;
809 XX_UnlockIntrSpinlock(p_MM->h_Spinlock, intFlags);
810 return (uint64_t)(ILLEGAL_BASE);
813 /* init a new busy block */
814 if ((p_NewBusyB = CreateBusyBlock(base, size, name)) == NULL)
816 XX_UnlockIntrSpinlock(p_MM->h_Spinlock, intFlags);
817 return (uint64_t)(ILLEGAL_BASE);
820 /* calls Update routine to update a lists of free blocks */
821 if ( CutFree ( p_MM, base, base+size ) != E_OK )
823 XX_UnlockIntrSpinlock(p_MM->h_Spinlock, intFlags);
825 return (uint64_t)(ILLEGAL_BASE);
828 /* Decreasing the allocated memory size from free memory size */
829 p_MM->freeMemSize -= size;
831 /* insert the new busy block into the list of busy blocks */
832 AddBusy ( p_MM, p_NewBusyB );
833 XX_UnlockIntrSpinlock(p_MM->h_Spinlock, intFlags);
838 /*****************************************************************************/
839 uint64_t MM_GetForceMin(t_Handle h_MM, uint64_t size, uint64_t alignment, uint64_t min, char* name)
841 t_MM *p_MM = (t_MM *)h_MM;
842 t_FreeBlock *p_FreeB;
843 t_BusyBlock *p_NewBusyB;
844 uint64_t holdBase, holdEnd, j = alignment, i=0;
849 /* checks if alignment is a power of two, if it correct and if the
850 required size is multiple of the given alignment. */
851 while ((j & 0x1) == 0)
857 if ( (j != 1) || (i > MM_MAX_ALIGNMENT) )
859 return (uint64_t)(ILLEGAL_BASE);
862 intFlags = XX_LockIntrSpinlock(p_MM->h_Spinlock);
863 p_FreeB = p_MM->freeBlocks[i];
865 /* look for the first block that contains the minimum
866 base address. If the whole required size may be fit
867 into it, use that block, otherwise look for the next
868 block of size greater or equal to the required size. */
869 while ( p_FreeB && (min >= p_FreeB->end))
870 p_FreeB = p_FreeB->p_Next;
872 /* If such block is found */
875 XX_UnlockIntrSpinlock(p_MM->h_Spinlock, intFlags);
876 return (uint64_t)(ILLEGAL_BASE);
879 /* if this block is large enough, use this block */
880 holdBase = ( min <= p_FreeB->base ) ? p_FreeB->base : min;
881 if ((holdBase + size) <= p_FreeB->end )
883 holdEnd = holdBase + size;
887 p_FreeB = p_FreeB->p_Next;
888 while ( p_FreeB && ((p_FreeB->end - p_FreeB->base) < size) )
889 p_FreeB = p_FreeB->p_Next;
891 /* If such block is found */
894 XX_UnlockIntrSpinlock(p_MM->h_Spinlock, intFlags);
895 return (uint64_t)(ILLEGAL_BASE);
898 holdBase = p_FreeB->base;
899 holdEnd = holdBase + size;
902 /* init a new busy block */
903 if ((p_NewBusyB = CreateBusyBlock(holdBase, size, name)) == NULL)
905 XX_UnlockIntrSpinlock(p_MM->h_Spinlock, intFlags);
906 return (uint64_t)(ILLEGAL_BASE);
909 /* calls Update routine to update a lists of free blocks */
910 if ( CutFree( p_MM, holdBase, holdEnd ) != E_OK )
912 XX_UnlockIntrSpinlock(p_MM->h_Spinlock, intFlags);
914 return (uint64_t)(ILLEGAL_BASE);
917 /* Decreasing the allocated memory size from free memory size */
918 p_MM->freeMemSize -= size;
920 /* insert the new busy block into the list of busy blocks */
921 AddBusy( p_MM, p_NewBusyB );
922 XX_UnlockIntrSpinlock(p_MM->h_Spinlock, intFlags);
927 /*****************************************************************************/
928 uint64_t MM_Put(t_Handle h_MM, uint64_t base)
930 t_MM *p_MM = (t_MM *)h_MM;
931 t_BusyBlock *p_BusyB, *p_PrevBusyB;
937 /* Look for a busy block that have the given base value.
938 * That block will be returned back to the memory.
942 intFlags = XX_LockIntrSpinlock(p_MM->h_Spinlock);
943 p_BusyB = p_MM->busyBlocks;
944 while ( p_BusyB && base != p_BusyB->base )
946 p_PrevBusyB = p_BusyB;
947 p_BusyB = p_BusyB->p_Next;
952 XX_UnlockIntrSpinlock(p_MM->h_Spinlock, intFlags);
953 return (uint64_t)(0);
956 if ( AddFree( p_MM, p_BusyB->base, p_BusyB->end ) != E_OK )
958 XX_UnlockIntrSpinlock(p_MM->h_Spinlock, intFlags);
959 return (uint64_t)(0);
962 /* removes a busy block form the list of busy blocks */
964 p_PrevBusyB->p_Next = p_BusyB->p_Next;
966 p_MM->busyBlocks = p_BusyB->p_Next;
968 size = p_BusyB->end - p_BusyB->base;
970 /* Adding the deallocated memory size to free memory size */
971 p_MM->freeMemSize += size;
974 XX_UnlockIntrSpinlock(p_MM->h_Spinlock, intFlags);
979 /*****************************************************************************/
980 uint64_t MM_PutForce(t_Handle h_MM, uint64_t base, uint64_t size)
982 t_MM *p_MM = (t_MM *)h_MM;
983 uint64_t end = base + size;
988 intFlags = XX_LockIntrSpinlock(p_MM->h_Spinlock);
990 if ( CutBusy( p_MM, base, end ) != E_OK )
992 XX_UnlockIntrSpinlock(p_MM->h_Spinlock, intFlags);
993 return (uint64_t)(0);
996 if ( AddFree ( p_MM, base, end ) != E_OK )
998 XX_UnlockIntrSpinlock(p_MM->h_Spinlock, intFlags);
999 return (uint64_t)(0);
1002 /* Adding the deallocated memory size to free memory size */
1003 p_MM->freeMemSize += size;
1005 XX_UnlockIntrSpinlock(p_MM->h_Spinlock, intFlags);
1010 /*****************************************************************************/
1011 t_Error MM_Add(t_Handle h_MM, uint64_t base, uint64_t size)
1013 t_MM *p_MM = (t_MM *)h_MM;
1014 t_MemBlock *p_MemB, *p_NewMemB;
1020 /* find a last block in the list of memory blocks to insert a new
1023 intFlags = XX_LockIntrSpinlock(p_MM->h_Spinlock);
1025 p_MemB = p_MM->memBlocks;
1026 while ( p_MemB->p_Next )
1028 if ( base >= p_MemB->base && base < p_MemB->end )
1030 XX_UnlockIntrSpinlock(p_MM->h_Spinlock, intFlags);
1031 RETURN_ERROR(MAJOR, E_ALREADY_EXISTS, NO_MSG);
1033 p_MemB = p_MemB->p_Next;
1035 /* check for a last memory block */
1036 if ( base >= p_MemB->base && base < p_MemB->end )
1038 XX_UnlockIntrSpinlock(p_MM->h_Spinlock, intFlags);
1039 RETURN_ERROR(MAJOR, E_ALREADY_EXISTS, NO_MSG);
1042 /* create a new memory block */
1043 if ((p_NewMemB = CreateNewBlock(base, size)) == NULL)
1045 XX_UnlockIntrSpinlock(p_MM->h_Spinlock, intFlags);
1046 RETURN_ERROR(MAJOR, E_NO_MEMORY, NO_MSG);
1049 /* append a new memory block to the end of the list of memory blocks */
1050 p_MemB->p_Next = p_NewMemB;
1052 /* add a new free block to the free lists */
1053 errCode = AddFree(p_MM, base, base+size);
1056 XX_UnlockIntrSpinlock(p_MM->h_Spinlock, intFlags);
1059 return ((t_Error)errCode);
1062 /* Adding the new block size to free memory size */
1063 p_MM->freeMemSize += size;
1065 XX_UnlockIntrSpinlock(p_MM->h_Spinlock, intFlags);
1070 /*****************************************************************************/
1071 uint64_t MM_GetMemBlock(t_Handle h_MM, int index)
1073 t_MM *p_MM = (t_MM*)h_MM;
1074 t_MemBlock *p_MemBlock;
1079 p_MemBlock = p_MM->memBlocks;
1080 for (i=0; i < index; i++)
1081 p_MemBlock = p_MemBlock->p_Next;
1084 return (p_MemBlock->base);
1086 return (uint64_t)ILLEGAL_BASE;
1089 /*****************************************************************************/
1090 uint64_t MM_GetBase(t_Handle h_MM)
1092 t_MM *p_MM = (t_MM*)h_MM;
1093 t_MemBlock *p_MemBlock;
1097 p_MemBlock = p_MM->memBlocks;
1098 return p_MemBlock->base;
1101 /*****************************************************************************/
1102 bool MM_InRange(t_Handle h_MM, uint64_t addr)
1104 t_MM *p_MM = (t_MM*)h_MM;
1105 t_MemBlock *p_MemBlock;
1109 p_MemBlock = p_MM->memBlocks;
1111 if ((addr >= p_MemBlock->base) && (addr < p_MemBlock->end))
1117 /*****************************************************************************/
1118 uint64_t MM_GetFreeMemSize(t_Handle h_MM)
1120 t_MM *p_MM = (t_MM*)h_MM;
1124 return p_MM->freeMemSize;
1127 /*****************************************************************************/
1128 void MM_Dump(t_Handle h_MM)
1130 t_MM *p_MM = (t_MM *)h_MM;
1131 t_FreeBlock *p_FreeB;
1132 t_BusyBlock *p_BusyB;
1135 p_BusyB = p_MM->busyBlocks;
1136 XX_Print("List of busy blocks:\n");
1139 XX_Print("\t0x%p: (%s: b=0x%llx, e=0x%llx)\n", p_BusyB, p_BusyB->name, p_BusyB->base, p_BusyB->end );
1140 p_BusyB = p_BusyB->p_Next;
1143 XX_Print("\nLists of free blocks according to alignment:\n");
1144 for (i=0; i <= MM_MAX_ALIGNMENT; i++)
1146 XX_Print("%d alignment:\n", (0x1 << i));
1147 p_FreeB = p_MM->freeBlocks[i];
1150 XX_Print("\t0x%p: (b=0x%llx, e=0x%llx)\n", p_FreeB, p_FreeB->base, p_FreeB->end);
1151 p_FreeB = p_FreeB->p_Next;