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"
45 #define PAD_ALIGNMENT(align, x) (((x)%(align)) ? ((align)-((x)%(align))) : 0)
47 #define ALIGN_BLOCK(p_Block, prefixSize, alignment) \
49 p_Block += (prefixSize); \
50 p_Block += PAD_ALIGNMENT((alignment), (uintptr_t)(p_Block)); \
54 #define GET_CALLER_ADDR \
55 __asm__ ("mflr %0" : "=r" (callerAddr))
56 #elif defined(__MWERKS__)
57 /* NOTE: This implementation is only valid for CodeWarrior for PowerPC */
58 #define GET_CALLER_ADDR \
59 __asm__("add %0, 0, %0" : : "r" (callerAddr))
60 #endif /* defined(__GNUC__) */
63 /*****************************************************************************/
64 static __inline__ void * MemGet(t_MemorySegment *p_Mem)
68 /* check if there is an available block */
69 if (p_Mem->current == p_Mem->num)
76 p_Block = p_Mem->p_BlocksStack[p_Mem->current];
78 p_Mem->p_BlocksStack[p_Mem->current] = NULL;
80 /* advance current index */
83 return (void *)p_Block;
86 /*****************************************************************************/
87 static __inline__ t_Error MemPut(t_MemorySegment *p_Mem, void *p_Block)
89 /* check if blocks stack is full */
90 if (p_Mem->current > 0)
92 /* decrease current index */
95 p_Mem->p_BlocksStack[p_Mem->current] = (uint8_t *)p_Block;
99 RETURN_ERROR(MAJOR, E_FULL, NO_MSG);
103 #ifdef DEBUG_MEM_LEAKS
105 /*****************************************************************************/
106 static t_Error InitMemDebugDatabase(t_MemorySegment *p_Mem)
108 p_Mem->p_MemDbg = (void *)XX_Malloc(sizeof(t_MemDbg) * p_Mem->num);
109 if (!p_Mem->p_MemDbg)
111 RETURN_ERROR(MAJOR, E_NO_MEMORY, ("Memory debug object"));
114 memset(p_Mem->p_MemDbg, ILLEGAL_BASE, sizeof(t_MemDbg) * p_Mem->num);
120 /*****************************************************************************/
121 static t_Error DebugMemGet(t_Handle h_Mem, void *p_Block, uintptr_t ownerAddress)
123 t_MemorySegment *p_Mem = (t_MemorySegment *)h_Mem;
124 t_MemDbg *p_MemDbg = (t_MemDbg *)p_Mem->p_MemDbg;
127 ASSERT_COND(ownerAddress != ILLEGAL_BASE);
130 if (p_Mem->consecutiveMem)
133 (((uint8_t *)p_Block - (p_Mem->p_Bases[0] + p_Mem->blockOffset)) / p_Mem->blockSize);
137 blockIndex = *(uint32_t *)((uint8_t *)p_Block - 4);
140 ASSERT_COND(blockIndex < p_Mem->num);
141 ASSERT_COND(p_MemDbg[blockIndex].ownerAddress == ILLEGAL_BASE);
143 p_MemDbg[blockIndex].ownerAddress = ownerAddress;
148 /*****************************************************************************/
149 static t_Error DebugMemPut(t_Handle h_Mem, void *p_Block)
151 t_MemorySegment *p_Mem = (t_MemorySegment *)h_Mem;
152 t_MemDbg *p_MemDbg = (t_MemDbg *)p_Mem->p_MemDbg;
157 if (p_Mem->consecutiveMem)
160 (((uint8_t *)p_Block - (p_Mem->p_Bases[0] + p_Mem->blockOffset)) / p_Mem->blockSize);
162 if (blockIndex >= p_Mem->num)
164 RETURN_ERROR(MAJOR, E_INVALID_ADDRESS,
165 ("Freed address (0x%08x) does not belong to this pool", p_Block));
170 blockIndex = *(uint32_t *)((uint8_t *)p_Block - 4);
172 if (blockIndex >= p_Mem->num)
174 RETURN_ERROR(MAJOR, E_INVALID_ADDRESS,
175 ("Freed address (0x%08x) does not belong to this pool", p_Block));
178 /* Verify that the block matches the corresponding base */
179 p_Temp = p_Mem->p_Bases[blockIndex];
181 ALIGN_BLOCK(p_Temp, p_Mem->prefixSize, p_Mem->alignment);
183 if (p_Temp == p_Mem->p_Bases[blockIndex])
184 p_Temp += p_Mem->alignment;
186 if (p_Temp != p_Block)
188 RETURN_ERROR(MAJOR, E_INVALID_ADDRESS,
189 ("Freed address (0x%08x) does not belong to this pool", p_Block));
193 if (p_MemDbg[blockIndex].ownerAddress == ILLEGAL_BASE)
195 RETURN_ERROR(MAJOR, E_ALREADY_FREE,
196 ("Attempt to free unallocated address (0x%08x)", p_Block));
199 p_MemDbg[blockIndex].ownerAddress = (uintptr_t)ILLEGAL_BASE;
204 #endif /* DEBUG_MEM_LEAKS */
207 /*****************************************************************************/
208 uint32_t MEM_ComputePartitionSize(uint32_t num,
211 uint16_t postfixSize,
214 uint32_t blockSize = 0, pad1 = 0, pad2 = 0;
216 /* Make sure that the alignment is at least 4 */
222 pad1 = (uint32_t)PAD_ALIGNMENT(4, prefixSize);
223 /* Block size not including 2nd padding */
224 blockSize = pad1 + prefixSize + dataSize + postfixSize;
225 pad2 = PAD_ALIGNMENT(alignment, blockSize);
226 /* Block size including 2nd padding */
229 return ((num * blockSize) + alignment);
232 /*****************************************************************************/
233 t_Error MEM_Init(char name[],
238 uint16_t postfixSize,
245 allocSize = MEM_ComputePartitionSize(num,
251 p_Memory = (uint8_t *)XX_Malloc(allocSize);
254 RETURN_ERROR(MAJOR, E_NO_MEMORY, ("Memory segment"));
257 errCode = MEM_InitByAddress(name,
267 RETURN_ERROR(MAJOR, errCode, NO_MSG);
270 ((t_MemorySegment *)(*p_Handle))->allocOwner = e_MEM_ALLOC_OWNER_LOCAL;
276 /*****************************************************************************/
277 t_Error MEM_InitByAddress(char name[],
282 uint16_t postfixSize,
286 t_MemorySegment *p_Mem;
287 uint32_t i, blockSize;
288 uint16_t alignPad, endPad;
291 /* prepare in case of error */
296 RETURN_ERROR(MAJOR, E_NULL_POINTER, ("Memory blocks"));
301 /* make sure that the alignment is at least 4 and power of 2 */
306 else if (!POWER_OF_2(alignment))
308 RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("Alignment (should be power of 2)"));
311 /* first allocate the segment descriptor */
312 p_Mem = (t_MemorySegment *)XX_Malloc(sizeof(t_MemorySegment));
315 RETURN_ERROR(MAJOR, E_NO_MEMORY, ("Memory segment structure"));
318 /* allocate the blocks stack */
319 p_Mem->p_BlocksStack = (uint8_t **)XX_Malloc(num * sizeof(uint8_t*));
320 if (!p_Mem->p_BlocksStack)
323 RETURN_ERROR(MAJOR, E_NO_MEMORY, ("Memory segment block pointers stack"));
326 /* allocate the blocks bases array */
327 p_Mem->p_Bases = (uint8_t **)XX_Malloc(sizeof(uint8_t*));
331 RETURN_ERROR(MAJOR, E_NO_MEMORY, ("Memory segment base pointers array"));
333 memset(p_Mem->p_Bases, 0, sizeof(uint8_t*));
335 /* store info about this segment */
338 p_Mem->dataSize = dataSize;
339 p_Mem->p_Bases[0] = p_Blocks;
340 p_Mem->getFailures = 0;
341 p_Mem->allocOwner = e_MEM_ALLOC_OWNER_EXTERNAL;
342 p_Mem->consecutiveMem = TRUE;
343 p_Mem->prefixSize = prefixSize;
344 p_Mem->postfixSize = postfixSize;
345 p_Mem->alignment = alignment;
347 strncpy(p_Mem->name, name, MEM_MAX_NAME_LENGTH-1);
349 p_Mem->h_Spinlock = XX_InitSpinlock();
350 if (!p_Mem->h_Spinlock)
353 RETURN_ERROR(MAJOR, E_INVALID_STATE, ("Can't create spinlock!"));
356 alignPad = (uint16_t)PAD_ALIGNMENT(4, prefixSize);
357 /* Make sure the entire size is a multiple of alignment */
358 endPad = (uint16_t)PAD_ALIGNMENT(alignment, (alignPad + prefixSize + dataSize + postfixSize));
360 /* The following manipulation places the data of block[0] in an aligned address,
361 since block size is aligned the following block datas will all be aligned */
362 ALIGN_BLOCK(p_Blocks, prefixSize, alignment);
364 blockSize = (uint32_t)(alignPad + prefixSize + dataSize + postfixSize + endPad);
366 /* initialize the blocks */
367 for (i=0; i < num; i++)
369 p_Mem->p_BlocksStack[i] = p_Blocks;
370 p_Blocks += blockSize;
373 /* return handle to caller */
374 *p_Handle = (t_Handle)p_Mem;
376 #ifdef DEBUG_MEM_LEAKS
378 t_Error errCode = InitMemDebugDatabase(p_Mem);
381 RETURN_ERROR(MAJOR, errCode, NO_MSG);
383 p_Mem->blockOffset = (uint32_t)(p_Mem->p_BlocksStack[0] - p_Mem->p_Bases[0]);
384 p_Mem->blockSize = blockSize;
386 #endif /* DEBUG_MEM_LEAKS */
392 /*****************************************************************************/
393 t_Error MEM_InitSmart(char name[],
398 uint16_t postfixSize,
400 uint8_t memPartitionId,
403 t_MemorySegment *p_Mem;
404 uint32_t i, blockSize;
405 uint16_t alignPad, endPad;
407 /* prepare in case of error */
410 /* make sure that size is always a multiple of 4 */
417 /* make sure that the alignment is at least 4 and power of 2 */
422 else if (!POWER_OF_2(alignment))
424 RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("Alignment (should be power of 2)"));
427 /* first allocate the segment descriptor */
428 p_Mem = (t_MemorySegment *)XX_Malloc(sizeof(t_MemorySegment));
431 RETURN_ERROR(MAJOR, E_NO_MEMORY, ("Memory segment structure"));
434 /* allocate the blocks stack */
435 p_Mem->p_BlocksStack = (uint8_t **)XX_Malloc(num * sizeof(uint8_t*));
436 if (!p_Mem->p_BlocksStack)
439 RETURN_ERROR(MAJOR, E_NO_MEMORY, ("Memory segment block pointers stack"));
442 /* allocate the blocks bases array */
443 p_Mem->p_Bases = (uint8_t **)XX_Malloc((consecutiveMem ? 1 : num) * sizeof(uint8_t*));
447 RETURN_ERROR(MAJOR, E_NO_MEMORY, ("Memory segment base pointers array"));
449 memset(p_Mem->p_Bases, 0, (consecutiveMem ? 1 : num) * sizeof(uint8_t*));
451 /* store info about this segment */
454 p_Mem->dataSize = dataSize;
455 p_Mem->getFailures = 0;
456 p_Mem->allocOwner = e_MEM_ALLOC_OWNER_LOCAL_SMART;
457 p_Mem->consecutiveMem = consecutiveMem;
458 p_Mem->prefixSize = prefixSize;
459 p_Mem->postfixSize = postfixSize;
460 p_Mem->alignment = alignment;
462 p_Mem->h_Spinlock = XX_InitSpinlock();
463 if (!p_Mem->h_Spinlock)
466 RETURN_ERROR(MAJOR, E_INVALID_STATE, ("Can't create spinlock!"));
469 alignPad = (uint16_t)PAD_ALIGNMENT(4, prefixSize);
470 /* Make sure the entire size is a multiple of alignment */
471 endPad = (uint16_t)PAD_ALIGNMENT(alignment, alignPad + prefixSize + dataSize + postfixSize);
473 /* Calculate blockSize */
474 blockSize = (uint32_t)(alignPad + prefixSize + dataSize + postfixSize + endPad);
476 /* Now allocate the blocks */
477 if (p_Mem->consecutiveMem)
479 /* |alignment - 1| bytes at most will be discarded in the beginning of the
480 received segment for alignment reasons, therefore the allocation is of:
481 (alignment + (num * block size)). */
482 uint8_t *p_Blocks = (uint8_t *)
483 XX_MallocSmart((uint32_t)((num * blockSize) + alignment), memPartitionId, 1);
487 RETURN_ERROR(MAJOR, E_NO_MEMORY, ("Memory segment blocks"));
490 /* Store the memory segment address */
491 p_Mem->p_Bases[0] = p_Blocks;
493 /* The following manipulation places the data of block[0] in an aligned address,
494 since block size is aligned the following block datas will all be aligned.*/
495 ALIGN_BLOCK(p_Blocks, prefixSize, alignment);
497 /* initialize the blocks */
498 for (i = 0; i < num; i++)
500 p_Mem->p_BlocksStack[i] = p_Blocks;
501 p_Blocks += blockSize;
504 #ifdef DEBUG_MEM_LEAKS
505 p_Mem->blockOffset = (uint32_t)(p_Mem->p_BlocksStack[0] - p_Mem->p_Bases[0]);
506 p_Mem->blockSize = blockSize;
507 #endif /* DEBUG_MEM_LEAKS */
511 /* |alignment - 1| bytes at most will be discarded in the beginning of the
512 received segment for alignment reasons, therefore the allocation is of:
513 (alignment + block size). */
514 for (i = 0; i < num; i++)
516 uint8_t *p_Block = (uint8_t *)
517 XX_MallocSmart((uint32_t)(blockSize + alignment), memPartitionId, 1);
521 RETURN_ERROR(MAJOR, E_NO_MEMORY, ("Memory segment blocks"));
524 /* Store the memory segment address */
525 p_Mem->p_Bases[i] = p_Block;
527 /* The following places the data of each block in an aligned address */
528 ALIGN_BLOCK(p_Block, prefixSize, alignment);
530 #ifdef DEBUG_MEM_LEAKS
531 /* Need 4 bytes before the meaningful bytes to store the block index.
532 We know we have them because alignment is at least 4 bytes. */
533 if (p_Block == p_Mem->p_Bases[i])
534 p_Block += alignment;
536 *(uint32_t *)(p_Block - 4) = i;
537 #endif /* DEBUG_MEM_LEAKS */
539 p_Mem->p_BlocksStack[i] = p_Block;
544 strncpy(p_Mem->name, name, MEM_MAX_NAME_LENGTH-1);
546 /* return handle to caller */
547 *p_Handle = (t_Handle)p_Mem;
549 #ifdef DEBUG_MEM_LEAKS
551 t_Error errCode = InitMemDebugDatabase(p_Mem);
554 RETURN_ERROR(MAJOR, errCode, NO_MSG);
556 #endif /* DEBUG_MEM_LEAKS */
562 /*****************************************************************************/
563 void MEM_Free(t_Handle h_Mem)
565 t_MemorySegment *p_Mem = (t_MemorySegment*)h_Mem;
568 /* Check MEM leaks */
569 MEM_CheckLeaks(h_Mem);
573 num = p_Mem->consecutiveMem ? 1 : p_Mem->num;
575 if (p_Mem->allocOwner == e_MEM_ALLOC_OWNER_LOCAL_SMART)
577 for (i=0; i < num; i++)
579 if (p_Mem->p_Bases[i])
581 XX_FreeSmart(p_Mem->p_Bases[i]);
585 else if (p_Mem->allocOwner == e_MEM_ALLOC_OWNER_LOCAL)
587 for (i=0; i < num; i++)
589 if (p_Mem->p_Bases[i])
591 XX_Free(p_Mem->p_Bases[i]);
596 if (p_Mem->h_Spinlock)
597 XX_FreeSpinlock(p_Mem->h_Spinlock);
600 XX_Free(p_Mem->p_Bases);
602 if (p_Mem->p_BlocksStack)
603 XX_Free(p_Mem->p_BlocksStack);
605 #ifdef DEBUG_MEM_LEAKS
607 XX_Free(p_Mem->p_MemDbg);
608 #endif /* DEBUG_MEM_LEAKS */
615 /*****************************************************************************/
616 void * MEM_Get(t_Handle h_Mem)
618 t_MemorySegment *p_Mem = (t_MemorySegment *)h_Mem;
621 #ifdef DEBUG_MEM_LEAKS
622 uintptr_t callerAddr = 0;
625 #endif /* DEBUG_MEM_LEAKS */
629 intFlags = XX_LockIntrSpinlock(p_Mem->h_Spinlock);
630 /* check if there is an available block */
631 if ((p_Block = (uint8_t *)MemGet(p_Mem)) == NULL)
633 XX_UnlockIntrSpinlock(p_Mem->h_Spinlock, intFlags);
637 #ifdef DEBUG_MEM_LEAKS
638 DebugMemGet(p_Mem, p_Block, callerAddr);
639 #endif /* DEBUG_MEM_LEAKS */
640 XX_UnlockIntrSpinlock(p_Mem->h_Spinlock, intFlags);
642 return (void *)p_Block;
646 /*****************************************************************************/
647 uint16_t MEM_GetN(t_Handle h_Mem, uint32_t num, void *array[])
649 t_MemorySegment *p_Mem = (t_MemorySegment *)h_Mem;
650 uint32_t availableBlocks;
653 #ifdef DEBUG_MEM_LEAKS
654 uintptr_t callerAddr = 0;
657 #endif /* DEBUG_MEM_LEAKS */
661 intFlags = XX_LockIntrSpinlock(p_Mem->h_Spinlock);
662 /* check how many blocks are available */
663 availableBlocks = (uint32_t)(p_Mem->num - p_Mem->current);
664 if (num > availableBlocks)
666 num = availableBlocks;
669 for (i=0; i < num; i++)
671 /* get pointer to block */
672 if ((array[i] = MemGet(p_Mem)) == NULL)
677 #ifdef DEBUG_MEM_LEAKS
678 DebugMemGet(p_Mem, array[i], callerAddr);
679 #endif /* DEBUG_MEM_LEAKS */
681 XX_UnlockIntrSpinlock(p_Mem->h_Spinlock, intFlags);
687 /*****************************************************************************/
688 t_Error MEM_Put(t_Handle h_Mem, void *p_Block)
690 t_MemorySegment *p_Mem = (t_MemorySegment *)h_Mem;
696 intFlags = XX_LockIntrSpinlock(p_Mem->h_Spinlock);
697 /* check if blocks stack is full */
698 if ((rc = MemPut(p_Mem, p_Block)) != E_OK)
700 XX_UnlockIntrSpinlock(p_Mem->h_Spinlock, intFlags);
701 RETURN_ERROR(MAJOR, rc, NO_MSG);
704 #ifdef DEBUG_MEM_LEAKS
705 DebugMemPut(p_Mem, p_Block);
706 #endif /* DEBUG_MEM_LEAKS */
707 XX_UnlockIntrSpinlock(p_Mem->h_Spinlock, intFlags);
713 #ifdef DEBUG_MEM_LEAKS
715 /*****************************************************************************/
716 void MEM_CheckLeaks(t_Handle h_Mem)
718 t_MemorySegment *p_Mem = (t_MemorySegment *)h_Mem;
719 t_MemDbg *p_MemDbg = (t_MemDbg *)p_Mem->p_MemDbg;
725 if (p_Mem->consecutiveMem)
727 for (i=0; i < p_Mem->num; i++)
729 if (p_MemDbg[i].ownerAddress != ILLEGAL_BASE)
731 /* Find the block address */
732 p_Block = ((p_Mem->p_Bases[0] + p_Mem->blockOffset) +
733 (i * p_Mem->blockSize));
735 XX_Print("MEM leak: 0x%08x, Caller address: 0x%08x\n",
736 p_Block, p_MemDbg[i].ownerAddress);
742 for (i=0; i < p_Mem->num; i++)
744 if (p_MemDbg[i].ownerAddress != ILLEGAL_BASE)
746 /* Find the block address */
747 p_Block = p_Mem->p_Bases[i];
749 ALIGN_BLOCK(p_Block, p_Mem->prefixSize, p_Mem->alignment);
751 if (p_Block == p_Mem->p_Bases[i])
752 p_Block += p_Mem->alignment;
754 XX_Print("MEM leak: 0x%08x, Caller address: 0x%08x\n",
755 p_Block, p_MemDbg[i].ownerAddress);
761 #endif /* DEBUG_MEM_LEAKS */