1 /* Copyright (c) 2008-2011 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.
33 #include "string_ext.h"
34 #include "error_ext.h"
36 #include "sprint_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;
255 p_CurrB = p_CurrB->p_Next;
259 /* If no free block found to be updated, insert a new free block
260 * to the end of the free list.
262 if ( !p_CurrB && ((((uint64_t)(end-base)) & ((uint64_t)(alignment-1))) == 0) )
264 if ((p_NewB = CreateFreeBlock(alignBase, end-base)) == NULL)
265 RETURN_ERROR(MAJOR, E_NO_MEMORY, NO_MSG);
268 p_PrevB->p_Next = p_NewB;
270 p_MM->freeBlocks[i] = p_NewB;
273 /* Update boundaries of the new free block */
274 if ((alignment == 1) && !p_NewB)
276 if ( p_CurrB && base > p_CurrB->base )
277 base = p_CurrB->base;
278 if ( p_CurrB && end < p_CurrB->end )
286 /****************************************************************
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 do
292 * not include a block of memory from holdBase to holdEnd.
293 * For each free lists it seek for a free block that holds
294 * either holdBase or holdEnd. If such block is found it updates it.
297 * p_MM - pointer to the MM object
298 * holdBase - base address of the allocated block
299 * holdEnd - end address of the allocated block
302 * E_OK is returned on success,
303 * otherwise returns an error code.
305 ****************************************************************/
306 static t_Error CutFree(t_MM *p_MM, uint64_t holdBase, uint64_t holdEnd)
308 t_FreeBlock *p_PrevB, *p_CurrB, *p_NewB;
309 uint64_t alignBase, base, end;
313 for (i=0; i <= MM_MAX_ALIGNMENT; i++)
315 p_PrevB = p_NewB = 0;
316 p_CurrB = p_MM->freeBlocks[i];
318 alignment = (uint64_t)(0x1 << i);
319 alignBase = MAKE_ALIGNED(holdEnd, alignment);
323 base = p_CurrB->base;
326 if ( (holdBase <= base) && (holdEnd <= end) && (holdEnd > base) )
328 if ( alignBase >= end ||
329 (alignBase < end && ((end-alignBase) < alignment)) )
332 p_PrevB->p_Next = p_CurrB->p_Next;
334 p_MM->freeBlocks[i] = p_CurrB->p_Next;
339 p_CurrB->base = alignBase;
343 else if ( (holdBase > base) && (holdEnd <= end) )
345 if ( (holdBase-base) >= alignment )
347 if ( (alignBase < end) && ((end-alignBase) >= alignment) )
349 if ((p_NewB = CreateFreeBlock(alignBase, end-alignBase)) == NULL)
350 RETURN_ERROR(MAJOR, E_NO_MEMORY, NO_MSG);
351 p_NewB->p_Next = p_CurrB->p_Next;
352 p_CurrB->p_Next = p_NewB;
354 p_CurrB->end = holdBase;
356 else if ( (alignBase < end) && ((end-alignBase) >= alignment) )
358 p_CurrB->base = alignBase;
363 p_PrevB->p_Next = p_CurrB->p_Next;
365 p_MM->freeBlocks[i] = p_CurrB->p_Next;
373 p_CurrB = p_CurrB->p_Next;
381 /****************************************************************
385 * Adds a new busy block to the list of busy blocks. Note,
386 * that all busy blocks are ordered by their base address in
390 * MM - handler to the MM object
391 * p_NewBusyB - pointer to the a busy block
396 ****************************************************************/
397 static void AddBusy(t_MM *p_MM, t_BusyBlock *p_NewBusyB)
399 t_BusyBlock *p_CurrBusyB, *p_PrevBusyB;
401 /* finds a place of a new busy block in the list of busy blocks */
403 p_CurrBusyB = p_MM->busyBlocks;
405 while ( p_CurrBusyB && p_NewBusyB->base > p_CurrBusyB->base )
407 p_PrevBusyB = p_CurrBusyB;
408 p_CurrBusyB = p_CurrBusyB->p_Next;
411 /* insert the new busy block into the list of busy blocks */
413 p_NewBusyB->p_Next = p_CurrBusyB;
415 p_PrevBusyB->p_Next = p_NewBusyB;
417 p_MM->busyBlocks = p_NewBusyB;
420 /****************************************************************
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 not
426 * include a given block, that block is going to be free. If a
427 * given block is a part of some other busy block, so that
428 * busy block is updated. If there are number of busy blocks
429 * included in the given block, so all that blocks are removed
430 * from the busy list and the end blocks are updated.
431 * If the given block devides some block into two parts, a new
432 * busy block is added to the busy list.
435 * p_MM - pointer to the MM object
436 * base - base address of a given busy block
437 * end - end address of a given busy block
440 * E_OK on success, E_NOMEMORY otherwise.
442 ****************************************************************/
443 static t_Error CutBusy(t_MM *p_MM, uint64_t base, uint64_t end)
445 t_BusyBlock *p_CurrB, *p_PrevB, *p_NewB;
447 p_CurrB = p_MM->busyBlocks;
448 p_PrevB = p_NewB = 0;
452 if ( base < p_CurrB->end )
454 if ( end > p_CurrB->end )
456 t_BusyBlock *p_NextB;
457 while ( p_CurrB->p_Next && end >= p_CurrB->p_Next->end )
459 p_NextB = p_CurrB->p_Next;
460 p_CurrB->p_Next = p_CurrB->p_Next->p_Next;
464 p_NextB = p_CurrB->p_Next;
465 if ( p_NextB && end > p_NextB->base )
471 if ( base <= p_CurrB->base )
473 if ( end < p_CurrB->end && end > p_CurrB->base )
477 else if ( end >= p_CurrB->end )
480 p_PrevB->p_Next = p_CurrB->p_Next;
482 p_MM->busyBlocks = p_CurrB->p_Next;
488 if ( end < p_CurrB->end && end > p_CurrB->base )
490 if ((p_NewB = CreateBusyBlock(end,
492 p_CurrB->name)) == NULL)
493 RETURN_ERROR(MAJOR, E_NO_MEMORY, NO_MSG);
494 p_NewB->p_Next = p_CurrB->p_Next;
495 p_CurrB->p_Next = p_NewB;
504 p_CurrB = p_CurrB->p_Next;
511 /****************************************************************
512 * Routine: MmGetGreaterAlignment
515 * Allocates a block of memory according to the given size
516 * and the alignment. That routine is called from the MM_Get
517 * routine if the required alignment is greater then MM_MAX_ALIGNMENT.
518 * In that case, it goes over free blocks of 64 byte align list
519 * and checks if it has the required size of bytes of the required
520 * alignment. If no blocks found returns ILLEGAL_BASE.
521 * After the block is found and data is allocated, it calls
522 * the internal CutFree routine to update all free lists
523 * do not include a just allocated block. Of course, each
524 * free list contains a free blocks with the same alignment.
525 * It is also creates a busy block that holds
526 * information about an allocated block.
529 * MM - handle to the MM object
530 * size - size of the MM
531 * alignment - index as a power of two defines
532 * a required alignment that is greater then 64.
533 * name - the name that specifies an allocated block.
536 * base address of an allocated block.
537 * ILLEGAL_BASE if can't allocate a block
539 ****************************************************************/
540 static uint64_t MmGetGreaterAlignment(t_MM *p_MM, uint64_t size, uint64_t alignment, char* name)
542 t_FreeBlock *p_FreeB;
543 t_BusyBlock *p_NewBusyB;
544 uint64_t holdBase, holdEnd, alignBase = 0;
546 /* goes over free blocks of the 64 byte alignment list
547 and look for a block of the suitable size and
548 base address according to the alignment. */
549 p_FreeB = p_MM->freeBlocks[MM_MAX_ALIGNMENT];
553 alignBase = MAKE_ALIGNED(p_FreeB->base, alignment);
555 /* the block is found if the aligned base inside the block
556 * and has the anough size. */
557 if ( alignBase >= p_FreeB->base &&
558 alignBase < p_FreeB->end &&
559 size <= (p_FreeB->end - alignBase) )
562 p_FreeB = p_FreeB->p_Next;
565 /* If such block isn't found */
567 return (uint64_t)(ILLEGAL_BASE);
569 holdBase = alignBase;
570 holdEnd = alignBase + size;
572 /* init a new busy block */
573 if ((p_NewBusyB = CreateBusyBlock(holdBase, size, name)) == NULL)
574 return (uint64_t)(ILLEGAL_BASE);
576 /* calls Update routine to update a lists of free blocks */
577 if ( CutFree ( p_MM, holdBase, holdEnd ) != E_OK )
578 return (uint64_t)(ILLEGAL_BASE);
580 /* insert the new busy block into the list of busy blocks */
581 AddBusy ( p_MM, p_NewBusyB );
587 /**********************************************************************
588 * MM API routines set *
589 **********************************************************************/
591 /*****************************************************************************/
592 t_Error MM_Init(t_Handle *h_MM, uint64_t base, uint64_t size)
595 uint64_t newBase, newSize;
600 RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("Size (should be positive)"));
603 /* Initializes a new MM object */
604 p_MM = (t_MM *)XX_Malloc(sizeof(t_MM));
607 RETURN_ERROR(MAJOR, E_NO_MEMORY, NO_MSG);
610 p_MM->h_Spinlock = XX_InitSpinlock();
611 if (!p_MM->h_Spinlock)
614 RETURN_ERROR(MAJOR, E_NO_MEMORY, ("MM spinlock!"));
617 /* initializes a new memory block */
618 if ((p_MM->memBlocks = CreateNewBlock(base, size)) == NULL)
619 RETURN_ERROR(MAJOR, E_NO_MEMORY, NO_MSG);
621 /* A busy list is empty */
622 p_MM->busyBlocks = 0;
624 /*Initializes a new free block for each free list*/
625 for (i=0; i <= MM_MAX_ALIGNMENT; i++)
627 newBase = MAKE_ALIGNED( base, (0x1 << i) );
628 newSize = size - (newBase - base);
630 if ((p_MM->freeBlocks[i] = CreateFreeBlock(newBase, newSize)) == NULL)
631 RETURN_ERROR(MAJOR, E_NO_MEMORY, NO_MSG);
639 /*****************************************************************************/
640 void MM_Free(t_Handle h_MM)
642 t_MM *p_MM = (t_MM *)h_MM;
643 t_MemBlock *p_MemBlock;
644 t_BusyBlock *p_BusyBlock;
645 t_FreeBlock *p_FreeBlock;
651 /* release memory allocated for busy blocks */
652 p_BusyBlock = p_MM->busyBlocks;
653 while ( p_BusyBlock )
655 p_Block = p_BusyBlock;
656 p_BusyBlock = p_BusyBlock->p_Next;
660 /* release memory allocated for free blocks */
661 for (i=0; i <= MM_MAX_ALIGNMENT; i++)
663 p_FreeBlock = p_MM->freeBlocks[i];
664 while ( p_FreeBlock )
666 p_Block = p_FreeBlock;
667 p_FreeBlock = p_FreeBlock->p_Next;
672 /* release memory allocated for memory blocks */
673 p_MemBlock = p_MM->memBlocks;
676 p_Block = p_MemBlock;
677 p_MemBlock = p_MemBlock->p_Next;
681 if (p_MM->h_Spinlock)
682 XX_FreeSpinlock(p_MM->h_Spinlock);
684 /* release memory allocated for MM object itself */
688 /*****************************************************************************/
689 uint64_t MM_Get(t_Handle h_MM, uint64_t size, uint64_t alignment, char* name)
691 t_MM *p_MM = (t_MM *)h_MM;
692 t_FreeBlock *p_FreeB;
693 t_BusyBlock *p_NewBusyB;
694 uint64_t holdBase, holdEnd, j, i = 0;
697 SANITY_CHECK_RETURN_VALUE(p_MM, E_INVALID_HANDLE, (uint64_t)ILLEGAL_BASE);
699 /* checks that alignment value is greater then zero */
707 /* checks if alignment is a power of two, if it correct and if the
708 required size is multiple of the given alignment. */
709 while ((j & 0x1) == 0)
715 /* if the given alignment isn't power of two, returns an error */
718 REPORT_ERROR(MAJOR, E_INVALID_VALUE, ("alignment (should be power of 2)"));
719 return (uint64_t)ILLEGAL_BASE;
722 if (i > MM_MAX_ALIGNMENT)
724 return (MmGetGreaterAlignment(p_MM, size, alignment, name));
727 intFlags = XX_LockIntrSpinlock(p_MM->h_Spinlock);
728 /* look for a block of the size greater or equal to the required size. */
729 p_FreeB = p_MM->freeBlocks[i];
730 while ( p_FreeB && (p_FreeB->end - p_FreeB->base) < size )
731 p_FreeB = p_FreeB->p_Next;
733 /* If such block is found */
736 XX_UnlockIntrSpinlock(p_MM->h_Spinlock, intFlags);
737 return (uint64_t)(ILLEGAL_BASE);
740 holdBase = p_FreeB->base;
741 holdEnd = holdBase + size;
743 /* init a new busy block */
744 if ((p_NewBusyB = CreateBusyBlock(holdBase, size, name)) == NULL)
746 XX_UnlockIntrSpinlock(p_MM->h_Spinlock, intFlags);
747 return (uint64_t)(ILLEGAL_BASE);
750 /* calls Update routine to update a lists of free blocks */
751 if ( CutFree ( p_MM, holdBase, holdEnd ) != E_OK )
753 XX_UnlockIntrSpinlock(p_MM->h_Spinlock, intFlags);
754 return (uint64_t)(ILLEGAL_BASE);
757 /* insert the new busy block into the list of busy blocks */
758 AddBusy ( p_MM, p_NewBusyB );
759 XX_UnlockIntrSpinlock(p_MM->h_Spinlock, intFlags);
764 /*****************************************************************************/
765 uint64_t MM_GetForce(t_Handle h_MM, uint64_t base, uint64_t size, char* name)
767 t_MM *p_MM = (t_MM *)h_MM;
768 t_FreeBlock *p_FreeB;
769 t_BusyBlock *p_NewBusyB;
771 bool blockIsFree = FALSE;
775 intFlags = XX_LockIntrSpinlock(p_MM->h_Spinlock);
776 p_FreeB = p_MM->freeBlocks[0]; /* The biggest free blocks are in the
777 free list with alignment 1 */
781 if ( base >= p_FreeB->base && (base+size) <= p_FreeB->end )
787 p_FreeB = p_FreeB->p_Next;
792 XX_UnlockIntrSpinlock(p_MM->h_Spinlock, intFlags);
793 return (uint64_t)(ILLEGAL_BASE);
796 /* init a new busy block */
797 if ((p_NewBusyB = CreateBusyBlock(base, size, name)) == NULL)
799 XX_UnlockIntrSpinlock(p_MM->h_Spinlock, intFlags);
800 return (uint64_t)(ILLEGAL_BASE);
803 /* calls Update routine to update a lists of free blocks */
804 if ( CutFree ( p_MM, base, base+size ) != E_OK )
806 XX_UnlockIntrSpinlock(p_MM->h_Spinlock, intFlags);
807 return (uint64_t)(ILLEGAL_BASE);
810 /* insert the new busy block into the list of busy blocks */
811 AddBusy ( p_MM, p_NewBusyB );
812 XX_UnlockIntrSpinlock(p_MM->h_Spinlock, intFlags);
817 /*****************************************************************************/
818 uint64_t MM_GetForceMin(t_Handle h_MM, uint64_t size, uint64_t alignment, uint64_t min, char* name)
820 t_MM *p_MM = (t_MM *)h_MM;
821 t_FreeBlock *p_FreeB;
822 t_BusyBlock *p_NewBusyB;
823 uint64_t holdBase, holdEnd, j = alignment, i=0;
828 /* checks if alignment is a power of two, if it correct and if the
829 required size is multiple of the given alignment. */
830 while ((j & 0x1) == 0)
836 if ( (j != 1) || (i > MM_MAX_ALIGNMENT) )
838 return (uint64_t)(ILLEGAL_BASE);
841 intFlags = XX_LockIntrSpinlock(p_MM->h_Spinlock);
842 p_FreeB = p_MM->freeBlocks[i];
844 /* look for the first block that contains the minimum
845 base address. If the whole required size may be fit
846 into it, use that block, otherwise look for the next
847 block of size greater or equal to the required size. */
848 while ( p_FreeB && (min >= p_FreeB->end))
849 p_FreeB = p_FreeB->p_Next;
851 /* If such block is found */
854 XX_UnlockIntrSpinlock(p_MM->h_Spinlock, intFlags);
855 return (uint64_t)(ILLEGAL_BASE);
858 /* if this block is large enough, use this block */
859 holdBase = ( min <= p_FreeB->base ) ? p_FreeB->base : min;
860 if ((holdBase + size) <= p_FreeB->end )
862 holdEnd = holdBase + size;
866 p_FreeB = p_FreeB->p_Next;
867 while ( p_FreeB && ((p_FreeB->end - p_FreeB->base) < size) )
868 p_FreeB = p_FreeB->p_Next;
870 /* If such block is found */
873 XX_UnlockIntrSpinlock(p_MM->h_Spinlock, intFlags);
874 return (uint64_t)(ILLEGAL_BASE);
877 holdBase = p_FreeB->base;
878 holdEnd = holdBase + size;
881 /* init a new busy block */
882 if ((p_NewBusyB = CreateBusyBlock(holdBase, size, name)) == NULL)
884 XX_UnlockIntrSpinlock(p_MM->h_Spinlock, intFlags);
885 return (uint64_t)(ILLEGAL_BASE);
888 /* calls Update routine to update a lists of free blocks */
889 if ( CutFree( p_MM, holdBase, holdEnd ) != E_OK )
891 XX_UnlockIntrSpinlock(p_MM->h_Spinlock, intFlags);
892 return (uint64_t)(ILLEGAL_BASE);
895 /* insert the new busy block into the list of busy blocks */
896 AddBusy( p_MM, p_NewBusyB );
897 XX_UnlockIntrSpinlock(p_MM->h_Spinlock, intFlags);
902 /*****************************************************************************/
903 uint64_t MM_Put(t_Handle h_MM, uint64_t base)
905 t_MM *p_MM = (t_MM *)h_MM;
906 t_BusyBlock *p_BusyB, *p_PrevBusyB;
912 /* Look for a busy block that have the given base value.
913 * That block will be returned back to the memory.
917 intFlags = XX_LockIntrSpinlock(p_MM->h_Spinlock);
918 p_BusyB = p_MM->busyBlocks;
919 while ( p_BusyB && base != p_BusyB->base )
921 p_PrevBusyB = p_BusyB;
922 p_BusyB = p_BusyB->p_Next;
927 XX_UnlockIntrSpinlock(p_MM->h_Spinlock, intFlags);
928 return (uint64_t)(0);
931 if ( AddFree( p_MM, p_BusyB->base, p_BusyB->end ) != E_OK )
933 XX_UnlockIntrSpinlock(p_MM->h_Spinlock, intFlags);
934 return (uint64_t)(0);
937 /* removes a busy block form the list of busy blocks */
939 p_PrevBusyB->p_Next = p_BusyB->p_Next;
941 p_MM->busyBlocks = p_BusyB->p_Next;
943 size = p_BusyB->end - p_BusyB->base;
946 XX_UnlockIntrSpinlock(p_MM->h_Spinlock, intFlags);
951 /*****************************************************************************/
952 uint64_t MM_PutForce(t_Handle h_MM, uint64_t base, uint64_t size)
954 t_MM *p_MM = (t_MM *)h_MM;
955 uint64_t end = base + size;
960 intFlags = XX_LockIntrSpinlock(p_MM->h_Spinlock);
961 if ( CutBusy( p_MM, base, end ) != E_OK )
963 XX_UnlockIntrSpinlock(p_MM->h_Spinlock, intFlags);
964 return (uint64_t)(0);
967 if ( AddFree ( p_MM, base, end ) != E_OK )
969 XX_UnlockIntrSpinlock(p_MM->h_Spinlock, intFlags);
970 return (uint64_t)(0);
972 XX_UnlockIntrSpinlock(p_MM->h_Spinlock, intFlags);
977 /*****************************************************************************/
978 t_Error MM_Add(t_Handle h_MM, uint64_t base, uint64_t size)
980 t_MM *p_MM = (t_MM *)h_MM;
981 t_MemBlock *p_MemB, *p_NewMemB;
987 /* find a last block in the list of memory blocks to insert a new
990 intFlags = XX_LockIntrSpinlock(p_MM->h_Spinlock);
991 p_MemB = p_MM->memBlocks;
992 while ( p_MemB->p_Next )
994 if ( base >= p_MemB->base && base < p_MemB->end )
996 XX_UnlockIntrSpinlock(p_MM->h_Spinlock, intFlags);
997 RETURN_ERROR(MAJOR, E_ALREADY_EXISTS, NO_MSG);
999 p_MemB = p_MemB->p_Next;
1001 /* check for a last memory block */
1002 if ( base >= p_MemB->base && base < p_MemB->end )
1004 XX_UnlockIntrSpinlock(p_MM->h_Spinlock, intFlags);
1005 RETURN_ERROR(MAJOR, E_ALREADY_EXISTS, NO_MSG);
1008 /* create a new memory block */
1009 if ((p_NewMemB = CreateNewBlock(base, size)) == NULL)
1011 XX_UnlockIntrSpinlock(p_MM->h_Spinlock, intFlags);
1012 RETURN_ERROR(MAJOR, E_NO_MEMORY, NO_MSG);
1015 /* append a new memory block to the end of the list of memory blocks */
1016 p_MemB->p_Next = p_NewMemB;
1018 /* add a new free block to the free lists */
1019 errCode = AddFree(p_MM, base, base+size);
1022 XX_UnlockIntrSpinlock(p_MM->h_Spinlock, intFlags);
1025 return ((t_Error)errCode);
1027 XX_UnlockIntrSpinlock(p_MM->h_Spinlock, intFlags);
1032 /*****************************************************************************/
1033 uint64_t MM_GetMemBlock(t_Handle h_MM, int index)
1035 t_MM *p_MM = (t_MM*)h_MM;
1036 t_MemBlock *p_MemBlock;
1041 p_MemBlock = p_MM->memBlocks;
1042 for (i=0; i < index; i++)
1043 p_MemBlock = p_MemBlock->p_Next;
1046 return (p_MemBlock->base);
1048 return (uint64_t)ILLEGAL_BASE;
1051 /*****************************************************************************/
1052 uint64_t MM_GetBase(t_Handle h_MM)
1054 t_MM *p_MM = (t_MM*)h_MM;
1055 t_MemBlock *p_MemBlock;
1059 p_MemBlock = p_MM->memBlocks;
1060 return p_MemBlock->base;
1063 /*****************************************************************************/
1064 bool MM_InRange(t_Handle h_MM, uint64_t addr)
1066 t_MM *p_MM = (t_MM*)h_MM;
1067 t_MemBlock *p_MemBlock;
1071 p_MemBlock = p_MM->memBlocks;
1073 if ((addr >= p_MemBlock->base) && (addr < p_MemBlock->end))
1079 /*****************************************************************************/
1080 void MM_Dump(t_Handle h_MM, void *buff)
1082 t_MM *p_MM = (t_MM *)h_MM;
1083 t_FreeBlock *p_FreeB;
1084 t_BusyBlock *p_BusyB;
1087 p_BusyB = p_MM->busyBlocks;
1088 Sprint(buff, "List of busy blocks:\n");
1091 Sprint(buff, "\t0x%p: (%s: b=0x%lx, e=0x%lx)\n",
1092 p_BusyB, p_BusyB->name, p_BusyB->base, p_BusyB->end );
1093 p_BusyB = p_BusyB->p_Next;
1096 Sprint(buff, "\nLists of free blocks according to alignment:\n");
1097 for (i=0; i <= MM_MAX_ALIGNMENT; i++)
1099 Sprint(buff, "%d alignment:\n", (0x1 << i));
1100 p_FreeB = p_MM->freeBlocks[i];
1103 Sprint(buff, "\t0x%p: (b=0x%lx, e=0x%lx)\n",
1104 p_FreeB, p_FreeB->base, p_FreeB->end);
1105 p_FreeB = p_FreeB->p_Next;