1 /******************************************************************************
3 © 1995-2003, 2004, 2005-2011 Freescale Semiconductor, Inc.
6 This is proprietary source code of Freescale Semiconductor Inc.,
7 and its use is subject to the NetComm Device Drivers EULA.
8 The copyright notice above does not evidence any actual or intended
9 publication of such source code.
11 ALTERNATIVELY, redistribution and use in source and binary forms, with
12 or without modification, are permitted provided that the following
14 * Redistributions of source code must retain the above copyright
15 notice, this list of conditions and the following disclaimer.
16 * Redistributions in binary form must reproduce the above copyright
17 notice, this list of conditions and the following disclaimer in the
18 documentation and/or other materials provided with the distribution.
19 * Neither the name of Freescale Semiconductor nor the
20 names of its contributors may be used to endorse or promote products
21 derived from this software without specific prior written permission.
23 THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``AS IS'' AND ANY
24 EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
25 WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
26 DISCLAIMED. IN NO EVENT SHALL Freescale Semiconductor BE LIABLE FOR ANY
27 DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
28 (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
29 LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
30 ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
31 (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
32 SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
35 **************************************************************************/
36 #include "error_ext.h"
39 #include "string_ext.h"
46 #define PAD_ALIGNMENT(align, x) (((x)%(align)) ? ((align)-((x)%(align))) : 0)
48 #define ALIGN_BLOCK(p_Block, prefixSize, alignment) \
50 p_Block += (prefixSize); \
51 p_Block += PAD_ALIGNMENT((alignment), (uintptr_t)(p_Block)); \
55 #define GET_CALLER_ADDR \
56 __asm__ ("mflr %0" : "=r" (callerAddr))
57 #elif defined(__MWERKS__)
58 /* NOTE: This implementation is only valid for CodeWarrior for PowerPC */
59 #define GET_CALLER_ADDR \
60 __asm__("add %0, 0, %0" : : "r" (callerAddr))
61 #endif /* defined(__GNUC__) */
64 /*****************************************************************************/
65 static __inline__ void * MemGet(t_MemorySegment *p_Mem)
69 /* check if there is an available block */
70 if (p_Mem->current == p_Mem->num)
77 p_Block = p_Mem->p_BlocksStack[p_Mem->current];
79 p_Mem->p_BlocksStack[p_Mem->current] = NULL;
81 /* advance current index */
84 return (void *)p_Block;
87 /*****************************************************************************/
88 static __inline__ t_Error MemPut(t_MemorySegment *p_Mem, void *p_Block)
90 /* check if blocks stack is full */
91 if (p_Mem->current > 0)
93 /* decrease current index */
96 p_Mem->p_BlocksStack[p_Mem->current] = (uint8_t *)p_Block;
100 RETURN_ERROR(MAJOR, E_FULL, NO_MSG);
104 #ifdef DEBUG_MEM_LEAKS
106 /*****************************************************************************/
107 static t_Error InitMemDebugDatabase(t_MemorySegment *p_Mem)
109 p_Mem->p_MemDbg = (void *)XX_Malloc(sizeof(t_MemDbg) * p_Mem->num);
110 if (!p_Mem->p_MemDbg)
112 RETURN_ERROR(MAJOR, E_NO_MEMORY, ("Memory debug object"));
115 memset(p_Mem->p_MemDbg, ILLEGAL_BASE, sizeof(t_MemDbg) * p_Mem->num);
121 /*****************************************************************************/
122 static t_Error DebugMemGet(t_Handle h_Mem, void *p_Block, uintptr_t ownerAddress)
124 t_MemorySegment *p_Mem = (t_MemorySegment *)h_Mem;
125 t_MemDbg *p_MemDbg = (t_MemDbg *)p_Mem->p_MemDbg;
128 ASSERT_COND(ownerAddress != ILLEGAL_BASE);
131 if (p_Mem->consecutiveMem)
134 (((uint8_t *)p_Block - (p_Mem->p_Bases[0] + p_Mem->blockOffset)) / p_Mem->blockSize);
138 blockIndex = *(uint32_t *)((uint8_t *)p_Block - 4);
141 ASSERT_COND(blockIndex < p_Mem->num);
142 ASSERT_COND(p_MemDbg[blockIndex].ownerAddress == ILLEGAL_BASE);
144 p_MemDbg[blockIndex].ownerAddress = ownerAddress;
149 /*****************************************************************************/
150 static t_Error DebugMemPut(t_Handle h_Mem, void *p_Block)
152 t_MemorySegment *p_Mem = (t_MemorySegment *)h_Mem;
153 t_MemDbg *p_MemDbg = (t_MemDbg *)p_Mem->p_MemDbg;
158 if (p_Mem->consecutiveMem)
161 (((uint8_t *)p_Block - (p_Mem->p_Bases[0] + p_Mem->blockOffset)) / p_Mem->blockSize);
163 if (blockIndex >= p_Mem->num)
165 RETURN_ERROR(MAJOR, E_INVALID_ADDRESS,
166 ("Freed address (0x%08x) does not belong to this pool", p_Block));
171 blockIndex = *(uint32_t *)((uint8_t *)p_Block - 4);
173 if (blockIndex >= p_Mem->num)
175 RETURN_ERROR(MAJOR, E_INVALID_ADDRESS,
176 ("Freed address (0x%08x) does not belong to this pool", p_Block));
179 /* Verify that the block matches the corresponding base */
180 p_Temp = p_Mem->p_Bases[blockIndex];
182 ALIGN_BLOCK(p_Temp, p_Mem->prefixSize, p_Mem->alignment);
184 if (p_Temp == p_Mem->p_Bases[blockIndex])
185 p_Temp += p_Mem->alignment;
187 if (p_Temp != p_Block)
189 RETURN_ERROR(MAJOR, E_INVALID_ADDRESS,
190 ("Freed address (0x%08x) does not belong to this pool", p_Block));
194 if (p_MemDbg[blockIndex].ownerAddress == ILLEGAL_BASE)
196 RETURN_ERROR(MAJOR, E_ALREADY_FREE,
197 ("Attempt to free unallocated address (0x%08x)", p_Block));
200 p_MemDbg[blockIndex].ownerAddress = (uintptr_t)ILLEGAL_BASE;
205 #endif /* DEBUG_MEM_LEAKS */
208 /*****************************************************************************/
209 uint32_t MEM_ComputePartitionSize(uint32_t num,
212 uint16_t postfixSize,
215 uint32_t blockSize = 0, pad1 = 0, pad2 = 0;
217 /* Make sure that the alignment is at least 4 */
223 pad1 = (uint32_t)PAD_ALIGNMENT(4, prefixSize);
224 /* Block size not including 2nd padding */
225 blockSize = pad1 + prefixSize + dataSize + postfixSize;
226 pad2 = PAD_ALIGNMENT(alignment, blockSize);
227 /* Block size including 2nd padding */
230 return ((num * blockSize) + alignment);
233 /*****************************************************************************/
234 t_Error MEM_Init(char name[],
239 uint16_t postfixSize,
246 allocSize = MEM_ComputePartitionSize(num,
252 p_Memory = (uint8_t *)XX_Malloc(allocSize);
255 RETURN_ERROR(MAJOR, E_NO_MEMORY, ("Memory segment"));
258 errCode = MEM_InitByAddress(name,
268 RETURN_ERROR(MAJOR, errCode, NO_MSG);
271 ((t_MemorySegment *)(*p_Handle))->allocOwner = e_MEM_ALLOC_OWNER_LOCAL;
277 /*****************************************************************************/
278 t_Error MEM_InitByAddress(char name[],
283 uint16_t postfixSize,
287 t_MemorySegment *p_Mem;
288 uint32_t i, blockSize;
289 uint16_t alignPad, endPad;
292 /* prepare in case of error */
297 RETURN_ERROR(MAJOR, E_NULL_POINTER, ("Memory blocks"));
302 /* make sure that the alignment is at least 4 and power of 2 */
307 else if (!POWER_OF_2(alignment))
309 RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("Alignment (should be power of 2)"));
312 /* first allocate the segment descriptor */
313 p_Mem = (t_MemorySegment *)XX_Malloc(sizeof(t_MemorySegment));
316 RETURN_ERROR(MAJOR, E_NO_MEMORY, ("Memory segment structure"));
319 /* allocate the blocks stack */
320 p_Mem->p_BlocksStack = (uint8_t **)XX_Malloc(num * sizeof(uint8_t*));
321 if (!p_Mem->p_BlocksStack)
324 RETURN_ERROR(MAJOR, E_NO_MEMORY, ("Memory segment block pointers stack"));
327 /* allocate the blocks bases array */
328 p_Mem->p_Bases = (uint8_t **)XX_Malloc(sizeof(uint8_t*));
332 RETURN_ERROR(MAJOR, E_NO_MEMORY, ("Memory segment base pointers array"));
334 memset(p_Mem->p_Bases, 0, sizeof(uint8_t*));
336 /* store info about this segment */
339 p_Mem->dataSize = dataSize;
340 p_Mem->p_Bases[0] = p_Blocks;
341 p_Mem->getFailures = 0;
342 p_Mem->allocOwner = e_MEM_ALLOC_OWNER_EXTERNAL;
343 p_Mem->consecutiveMem = TRUE;
344 p_Mem->prefixSize = prefixSize;
345 p_Mem->postfixSize = postfixSize;
346 p_Mem->alignment = alignment;
348 strncpy(p_Mem->name, name, MEM_MAX_NAME_LENGTH-1);
350 p_Mem->h_Spinlock = XX_InitSpinlock();
351 if (!p_Mem->h_Spinlock)
354 RETURN_ERROR(MAJOR, E_INVALID_STATE, ("Can't create spinlock!"));
357 alignPad = (uint16_t)PAD_ALIGNMENT(4, prefixSize);
358 /* Make sure the entire size is a multiple of alignment */
359 endPad = (uint16_t)PAD_ALIGNMENT(alignment, (alignPad + prefixSize + dataSize + postfixSize));
361 /* The following manipulation places the data of block[0] in an aligned address,
362 since block size is aligned the following block datas will all be aligned */
363 ALIGN_BLOCK(p_Blocks, prefixSize, alignment);
365 blockSize = (uint32_t)(alignPad + prefixSize + dataSize + postfixSize + endPad);
367 /* initialize the blocks */
368 for (i=0; i < num; i++)
370 p_Mem->p_BlocksStack[i] = p_Blocks;
371 p_Blocks += blockSize;
374 /* return handle to caller */
375 *p_Handle = (t_Handle)p_Mem;
377 #ifdef DEBUG_MEM_LEAKS
379 t_Error errCode = InitMemDebugDatabase(p_Mem);
382 RETURN_ERROR(MAJOR, errCode, NO_MSG);
384 p_Mem->blockOffset = (uint32_t)(p_Mem->p_BlocksStack[0] - p_Mem->p_Bases[0]);
385 p_Mem->blockSize = blockSize;
387 #endif /* DEBUG_MEM_LEAKS */
393 /*****************************************************************************/
394 t_Error MEM_InitSmart(char name[],
399 uint16_t postfixSize,
401 uint8_t memPartitionId,
404 t_MemorySegment *p_Mem;
405 uint32_t i, blockSize;
406 uint16_t alignPad, endPad;
408 /* prepare in case of error */
411 /* make sure that size is always a multiple of 4 */
418 /* make sure that the alignment is at least 4 and power of 2 */
423 else if (!POWER_OF_2(alignment))
425 RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("Alignment (should be power of 2)"));
428 /* first allocate the segment descriptor */
429 p_Mem = (t_MemorySegment *)XX_Malloc(sizeof(t_MemorySegment));
432 RETURN_ERROR(MAJOR, E_NO_MEMORY, ("Memory segment structure"));
435 /* allocate the blocks stack */
436 p_Mem->p_BlocksStack = (uint8_t **)XX_Malloc(num * sizeof(uint8_t*));
437 if (!p_Mem->p_BlocksStack)
440 RETURN_ERROR(MAJOR, E_NO_MEMORY, ("Memory segment block pointers stack"));
443 /* allocate the blocks bases array */
444 p_Mem->p_Bases = (uint8_t **)XX_Malloc((consecutiveMem ? 1 : num) * sizeof(uint8_t*));
448 RETURN_ERROR(MAJOR, E_NO_MEMORY, ("Memory segment base pointers array"));
450 memset(p_Mem->p_Bases, 0, (consecutiveMem ? 1 : num) * sizeof(uint8_t*));
452 /* store info about this segment */
455 p_Mem->dataSize = dataSize;
456 p_Mem->getFailures = 0;
457 p_Mem->allocOwner = e_MEM_ALLOC_OWNER_LOCAL_SMART;
458 p_Mem->consecutiveMem = consecutiveMem;
459 p_Mem->prefixSize = prefixSize;
460 p_Mem->postfixSize = postfixSize;
461 p_Mem->alignment = alignment;
463 p_Mem->h_Spinlock = XX_InitSpinlock();
464 if (!p_Mem->h_Spinlock)
467 RETURN_ERROR(MAJOR, E_INVALID_STATE, ("Can't create spinlock!"));
470 alignPad = (uint16_t)PAD_ALIGNMENT(4, prefixSize);
471 /* Make sure the entire size is a multiple of alignment */
472 endPad = (uint16_t)PAD_ALIGNMENT(alignment, alignPad + prefixSize + dataSize + postfixSize);
474 /* Calculate blockSize */
475 blockSize = (uint32_t)(alignPad + prefixSize + dataSize + postfixSize + endPad);
477 /* Now allocate the blocks */
478 if (p_Mem->consecutiveMem)
480 /* |alignment - 1| bytes at most will be discarded in the beginning of the
481 received segment for alignment reasons, therefore the allocation is of:
482 (alignment + (num * block size)). */
483 uint8_t *p_Blocks = (uint8_t *)
484 XX_MallocSmart((uint32_t)((num * blockSize) + alignment), memPartitionId, 1);
488 RETURN_ERROR(MAJOR, E_NO_MEMORY, ("Memory segment blocks"));
491 /* Store the memory segment address */
492 p_Mem->p_Bases[0] = p_Blocks;
494 /* The following manipulation places the data of block[0] in an aligned address,
495 since block size is aligned the following block datas will all be aligned.*/
496 ALIGN_BLOCK(p_Blocks, prefixSize, alignment);
498 /* initialize the blocks */
499 for (i = 0; i < num; i++)
501 p_Mem->p_BlocksStack[i] = p_Blocks;
502 p_Blocks += blockSize;
505 #ifdef DEBUG_MEM_LEAKS
506 p_Mem->blockOffset = (uint32_t)(p_Mem->p_BlocksStack[0] - p_Mem->p_Bases[0]);
507 p_Mem->blockSize = blockSize;
508 #endif /* DEBUG_MEM_LEAKS */
512 /* |alignment - 1| bytes at most will be discarded in the beginning of the
513 received segment for alignment reasons, therefore the allocation is of:
514 (alignment + block size). */
515 for (i = 0; i < num; i++)
517 uint8_t *p_Block = (uint8_t *)
518 XX_MallocSmart((uint32_t)(blockSize + alignment), memPartitionId, 1);
522 RETURN_ERROR(MAJOR, E_NO_MEMORY, ("Memory segment blocks"));
525 /* Store the memory segment address */
526 p_Mem->p_Bases[i] = p_Block;
528 /* The following places the data of each block in an aligned address */
529 ALIGN_BLOCK(p_Block, prefixSize, alignment);
531 #ifdef DEBUG_MEM_LEAKS
532 /* Need 4 bytes before the meaningful bytes to store the block index.
533 We know we have them because alignment is at least 4 bytes. */
534 if (p_Block == p_Mem->p_Bases[i])
535 p_Block += alignment;
537 *(uint32_t *)(p_Block - 4) = i;
538 #endif /* DEBUG_MEM_LEAKS */
540 p_Mem->p_BlocksStack[i] = p_Block;
545 strncpy(p_Mem->name, name, MEM_MAX_NAME_LENGTH-1);
547 /* return handle to caller */
548 *p_Handle = (t_Handle)p_Mem;
550 #ifdef DEBUG_MEM_LEAKS
552 t_Error errCode = InitMemDebugDatabase(p_Mem);
555 RETURN_ERROR(MAJOR, errCode, NO_MSG);
557 #endif /* DEBUG_MEM_LEAKS */
563 /*****************************************************************************/
564 void MEM_Free(t_Handle h_Mem)
566 t_MemorySegment *p_Mem = (t_MemorySegment*)h_Mem;
569 /* Check MEM leaks */
570 MEM_CheckLeaks(h_Mem);
574 num = p_Mem->consecutiveMem ? 1 : p_Mem->num;
576 if (p_Mem->allocOwner == e_MEM_ALLOC_OWNER_LOCAL_SMART)
578 for (i=0; i < num; i++)
580 if (p_Mem->p_Bases[i])
582 XX_FreeSmart(p_Mem->p_Bases[i]);
586 else if (p_Mem->allocOwner == e_MEM_ALLOC_OWNER_LOCAL)
588 for (i=0; i < num; i++)
590 if (p_Mem->p_Bases[i])
592 XX_Free(p_Mem->p_Bases[i]);
597 if (p_Mem->h_Spinlock)
598 XX_FreeSpinlock(p_Mem->h_Spinlock);
601 XX_Free(p_Mem->p_Bases);
603 if (p_Mem->p_BlocksStack)
604 XX_Free(p_Mem->p_BlocksStack);
606 #ifdef DEBUG_MEM_LEAKS
608 XX_Free(p_Mem->p_MemDbg);
609 #endif /* DEBUG_MEM_LEAKS */
616 /*****************************************************************************/
617 void * MEM_Get(t_Handle h_Mem)
619 t_MemorySegment *p_Mem = (t_MemorySegment *)h_Mem;
622 #ifdef DEBUG_MEM_LEAKS
623 uintptr_t callerAddr = 0;
626 #endif /* DEBUG_MEM_LEAKS */
630 intFlags = XX_LockIntrSpinlock(p_Mem->h_Spinlock);
631 /* check if there is an available block */
632 if ((p_Block = (uint8_t *)MemGet(p_Mem)) == NULL)
634 XX_UnlockIntrSpinlock(p_Mem->h_Spinlock, intFlags);
638 #ifdef DEBUG_MEM_LEAKS
639 DebugMemGet(p_Mem, p_Block, callerAddr);
640 #endif /* DEBUG_MEM_LEAKS */
641 XX_UnlockIntrSpinlock(p_Mem->h_Spinlock, intFlags);
643 return (void *)p_Block;
647 /*****************************************************************************/
648 uint16_t MEM_GetN(t_Handle h_Mem, uint32_t num, void *array[])
650 t_MemorySegment *p_Mem = (t_MemorySegment *)h_Mem;
651 uint32_t availableBlocks;
654 #ifdef DEBUG_MEM_LEAKS
655 uintptr_t callerAddr = 0;
658 #endif /* DEBUG_MEM_LEAKS */
662 intFlags = XX_LockIntrSpinlock(p_Mem->h_Spinlock);
663 /* check how many blocks are available */
664 availableBlocks = (uint32_t)(p_Mem->num - p_Mem->current);
665 if (num > availableBlocks)
667 num = availableBlocks;
670 for (i=0; i < num; i++)
672 /* get pointer to block */
673 if ((array[i] = MemGet(p_Mem)) == NULL)
678 #ifdef DEBUG_MEM_LEAKS
679 DebugMemGet(p_Mem, array[i], callerAddr);
680 #endif /* DEBUG_MEM_LEAKS */
682 XX_UnlockIntrSpinlock(p_Mem->h_Spinlock, intFlags);
688 /*****************************************************************************/
689 t_Error MEM_Put(t_Handle h_Mem, void *p_Block)
691 t_MemorySegment *p_Mem = (t_MemorySegment *)h_Mem;
697 intFlags = XX_LockIntrSpinlock(p_Mem->h_Spinlock);
698 /* check if blocks stack is full */
699 if ((rc = MemPut(p_Mem, p_Block)) != E_OK)
701 XX_UnlockIntrSpinlock(p_Mem->h_Spinlock, intFlags);
702 RETURN_ERROR(MAJOR, rc, NO_MSG);
705 #ifdef DEBUG_MEM_LEAKS
706 DebugMemPut(p_Mem, p_Block);
707 #endif /* DEBUG_MEM_LEAKS */
708 XX_UnlockIntrSpinlock(p_Mem->h_Spinlock, intFlags);
714 #ifdef DEBUG_MEM_LEAKS
716 /*****************************************************************************/
717 void MEM_CheckLeaks(t_Handle h_Mem)
719 t_MemorySegment *p_Mem = (t_MemorySegment *)h_Mem;
720 t_MemDbg *p_MemDbg = (t_MemDbg *)p_Mem->p_MemDbg;
726 if (p_Mem->consecutiveMem)
728 for (i=0; i < p_Mem->num; i++)
730 if (p_MemDbg[i].ownerAddress != ILLEGAL_BASE)
732 /* Find the block address */
733 p_Block = ((p_Mem->p_Bases[0] + p_Mem->blockOffset) +
734 (i * p_Mem->blockSize));
736 XX_Print("MEM leak: 0x%08x, Caller address: 0x%08x\n",
737 p_Block, p_MemDbg[i].ownerAddress);
743 for (i=0; i < p_Mem->num; i++)
745 if (p_MemDbg[i].ownerAddress != ILLEGAL_BASE)
747 /* Find the block address */
748 p_Block = p_Mem->p_Bases[i];
750 ALIGN_BLOCK(p_Block, p_Mem->prefixSize, p_Mem->alignment);
752 if (p_Block == p_Mem->p_Bases[i])
753 p_Block += p_Mem->alignment;
755 XX_Print("MEM leak: 0x%08x, Caller address: 0x%08x\n",
756 p_Block, p_MemDbg[i].ownerAddress);
762 #endif /* DEBUG_MEM_LEAKS */