xref: /freebsd/sys/contrib/ncsw/etc/ncsw_mem.c (revision 852ba100)
1 /******************************************************************************
2 
3  � 1995-2003, 2004, 2005-2011 Freescale Semiconductor, Inc.
4  All rights reserved.
5 
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.
10 
11  ALTERNATIVELY, redistribution and use in source and binary forms, with
12  or without modification, are permitted provided that the following
13  conditions are met:
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.
22 
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.
33  *
34 
35  **************************************************************************/
36 #include "error_ext.h"
37 #include "part_ext.h"
38 #include "std_ext.h"
39 #include "string_ext.h"
40 #include "mem_ext.h"
41 #include "mem.h"
42 #include "xx_ext.h"
43 
44 
45 #if 0
46 #define PAD_ALIGNMENT(align, x) (((x)%(align)) ? ((align)-((x)%(align))) : 0)
47 
48 #define ALIGN_BLOCK(p_Block, prefixSize, alignment)                 \
49     do {                                                            \
50         p_Block += (prefixSize);                                    \
51         p_Block += PAD_ALIGNMENT((alignment), (uintptr_t)(p_Block)); \
52     } while (0)
53 
54 #if defined(__GNUC__)
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__) */
62 
63 
64 /*****************************************************************************/
65 static __inline__ void * MemGet(t_MemorySegment *p_Mem)
66 {
67     uint8_t *p_Block;
68 
69     /* check if there is an available block */
70     if (p_Mem->current == p_Mem->num)
71     {
72         p_Mem->getFailures++;
73         return NULL;
74     }
75 
76     /* get the block */
77     p_Block = p_Mem->p_BlocksStack[p_Mem->current];
78 #ifdef DEBUG
79     p_Mem->p_BlocksStack[p_Mem->current] = NULL;
80 #endif /* DEBUG */
81     /* advance current index */
82     p_Mem->current++;
83 
84     return (void *)p_Block;
85 }
86 
87 /*****************************************************************************/
88 static __inline__ t_Error MemPut(t_MemorySegment *p_Mem, void *p_Block)
89 {
90     /* check if blocks stack is full */
91     if (p_Mem->current > 0)
92     {
93         /* decrease current index */
94         p_Mem->current--;
95         /* put the block */
96         p_Mem->p_BlocksStack[p_Mem->current] = (uint8_t *)p_Block;
97         return E_OK;
98     }
99 
100     RETURN_ERROR(MAJOR, E_FULL, NO_MSG);
101 }
102 
103 
104 #ifdef DEBUG_MEM_LEAKS
105 
106 /*****************************************************************************/
107 static t_Error InitMemDebugDatabase(t_MemorySegment *p_Mem)
108 {
109     p_Mem->p_MemDbg = (void *)XX_Malloc(sizeof(t_MemDbg) * p_Mem->num);
110     if (!p_Mem->p_MemDbg)
111     {
112         RETURN_ERROR(MAJOR, E_NO_MEMORY, ("Memory debug object"));
113     }
114 
115     memset(p_Mem->p_MemDbg, ILLEGAL_BASE, sizeof(t_MemDbg) * p_Mem->num);
116 
117     return E_OK;
118 }
119 
120 
121 /*****************************************************************************/
122 static t_Error DebugMemGet(t_Handle h_Mem, void *p_Block, uintptr_t ownerAddress)
123 {
124     t_MemorySegment *p_Mem = (t_MemorySegment *)h_Mem;
125     t_MemDbg        *p_MemDbg = (t_MemDbg *)p_Mem->p_MemDbg;
126     uint32_t        blockIndex;
127 
128     ASSERT_COND(ownerAddress != ILLEGAL_BASE);
129 
130     /* Find block num */
131     if (p_Mem->consecutiveMem)
132     {
133         blockIndex =
134             (((uint8_t *)p_Block - (p_Mem->p_Bases[0] + p_Mem->blockOffset)) / p_Mem->blockSize);
135     }
136     else
137     {
138         blockIndex = *(uint32_t *)((uint8_t *)p_Block - 4);
139     }
140 
141     ASSERT_COND(blockIndex < p_Mem->num);
142     ASSERT_COND(p_MemDbg[blockIndex].ownerAddress == ILLEGAL_BASE);
143 
144     p_MemDbg[blockIndex].ownerAddress = ownerAddress;
145 
146     return E_OK;
147 }
148 
149 /*****************************************************************************/
150 static t_Error DebugMemPut(t_Handle h_Mem, void *p_Block)
151 {
152     t_MemorySegment *p_Mem = (t_MemorySegment *)h_Mem;
153     t_MemDbg        *p_MemDbg = (t_MemDbg *)p_Mem->p_MemDbg;
154     uint32_t        blockIndex;
155     uint8_t         *p_Temp;
156 
157     /* Find block num */
158     if (p_Mem->consecutiveMem)
159     {
160         blockIndex =
161             (((uint8_t *)p_Block - (p_Mem->p_Bases[0] + p_Mem->blockOffset)) / p_Mem->blockSize);
162 
163         if (blockIndex >= p_Mem->num)
164         {
165             RETURN_ERROR(MAJOR, E_INVALID_ADDRESS,
166                          ("Freed address (0x%08x) does not belong to this pool", p_Block));
167         }
168     }
169     else
170     {
171         blockIndex = *(uint32_t *)((uint8_t *)p_Block - 4);
172 
173         if (blockIndex >= p_Mem->num)
174         {
175             RETURN_ERROR(MAJOR, E_INVALID_ADDRESS,
176                          ("Freed address (0x%08x) does not belong to this pool", p_Block));
177         }
178 
179         /* Verify that the block matches the corresponding base */
180         p_Temp = p_Mem->p_Bases[blockIndex];
181 
182         ALIGN_BLOCK(p_Temp, p_Mem->prefixSize, p_Mem->alignment);
183 
184         if (p_Temp == p_Mem->p_Bases[blockIndex])
185             p_Temp += p_Mem->alignment;
186 
187         if (p_Temp != p_Block)
188         {
189             RETURN_ERROR(MAJOR, E_INVALID_ADDRESS,
190                          ("Freed address (0x%08x) does not belong to this pool", p_Block));
191         }
192     }
193 
194     if (p_MemDbg[blockIndex].ownerAddress == ILLEGAL_BASE)
195     {
196         RETURN_ERROR(MAJOR, E_ALREADY_FREE,
197                      ("Attempt to free unallocated address (0x%08x)", p_Block));
198     }
199 
200     p_MemDbg[blockIndex].ownerAddress = (uintptr_t)ILLEGAL_BASE;
201 
202     return E_OK;
203 }
204 
205 #endif /* DEBUG_MEM_LEAKS */
206 
207 
208 /*****************************************************************************/
209 uint32_t MEM_ComputePartitionSize(uint32_t num,
210                                   uint16_t dataSize,
211                                   uint16_t prefixSize,
212                                   uint16_t postfixSize,
213                                   uint16_t alignment)
214 {
215     uint32_t  blockSize = 0, pad1 = 0, pad2 = 0;
216 
217     /* Make sure that the alignment is at least 4 */
218     if (alignment < 4)
219     {
220         alignment = 4;
221     }
222 
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 */
228     blockSize += pad2;
229 
230     return ((num * blockSize) + alignment);
231 }
232 
233 /*****************************************************************************/
234 t_Error MEM_Init(char       name[],
235                  t_Handle   *p_Handle,
236                  uint32_t   num,
237                  uint16_t   dataSize,
238                  uint16_t   prefixSize,
239                  uint16_t   postfixSize,
240                  uint16_t   alignment)
241 {
242     uint8_t     *p_Memory;
243     uint32_t    allocSize;
244     t_Error     errCode;
245 
246     allocSize = MEM_ComputePartitionSize(num,
247                                          dataSize,
248                                          prefixSize,
249                                          postfixSize,
250                                          alignment);
251 
252     p_Memory = (uint8_t *)XX_Malloc(allocSize);
253     if (!p_Memory)
254     {
255         RETURN_ERROR(MAJOR, E_NO_MEMORY, ("Memory segment"));
256     }
257 
258     errCode = MEM_InitByAddress(name,
259                                 p_Handle,
260                                 num,
261                                 dataSize,
262                                 prefixSize,
263                                 postfixSize,
264                                 alignment,
265                                 p_Memory);
266     if (errCode != E_OK)
267     {
268         RETURN_ERROR(MAJOR, errCode, NO_MSG);
269     }
270 
271     ((t_MemorySegment *)(*p_Handle))->allocOwner = e_MEM_ALLOC_OWNER_LOCAL;
272 
273     return E_OK;
274 }
275 
276 
277 /*****************************************************************************/
278 t_Error MEM_InitByAddress(char      name[],
279                           t_Handle  *p_Handle,
280                           uint32_t  num,
281                           uint16_t  dataSize,
282                           uint16_t  prefixSize,
283                           uint16_t  postfixSize,
284                           uint16_t  alignment,
285                           uint8_t   *p_Memory)
286 {
287     t_MemorySegment *p_Mem;
288     uint32_t        i, blockSize;
289     uint16_t        alignPad, endPad;
290     uint8_t         *p_Blocks;
291 
292      /* prepare in case of error */
293     *p_Handle = NULL;
294 
295     if (!p_Memory)
296     {
297         RETURN_ERROR(MAJOR, E_NULL_POINTER, ("Memory blocks"));
298     }
299 
300     p_Blocks = p_Memory;
301 
302     /* make sure that the alignment is at least 4 and power of 2 */
303     if (alignment < 4)
304     {
305         alignment = 4;
306     }
307     else if (!POWER_OF_2(alignment))
308     {
309         RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("Alignment (should be power of 2)"));
310     }
311 
312     /* first allocate the segment descriptor */
313     p_Mem = (t_MemorySegment *)XX_Malloc(sizeof(t_MemorySegment));
314     if (!p_Mem)
315     {
316         RETURN_ERROR(MAJOR, E_NO_MEMORY, ("Memory segment structure"));
317     }
318 
319     /* allocate the blocks stack */
320     p_Mem->p_BlocksStack = (uint8_t **)XX_Malloc(num * sizeof(uint8_t*));
321     if (!p_Mem->p_BlocksStack)
322     {
323         XX_Free(p_Mem);
324         RETURN_ERROR(MAJOR, E_NO_MEMORY, ("Memory segment block pointers stack"));
325     }
326 
327     /* allocate the blocks bases array */
328     p_Mem->p_Bases = (uint8_t **)XX_Malloc(sizeof(uint8_t*));
329     if (!p_Mem->p_Bases)
330     {
331         MEM_Free(p_Mem);
332         RETURN_ERROR(MAJOR, E_NO_MEMORY, ("Memory segment base pointers array"));
333     }
334     memset(p_Mem->p_Bases, 0, sizeof(uint8_t*));
335 
336     /* store info about this segment */
337     p_Mem->num = num;
338     p_Mem->current = 0;
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;
347     /* store name */
348     strncpy(p_Mem->name, name, MEM_MAX_NAME_LENGTH-1);
349 
350     p_Mem->h_Spinlock = XX_InitSpinlock();
351     if (!p_Mem->h_Spinlock)
352     {
353         MEM_Free(p_Mem);
354         RETURN_ERROR(MAJOR, E_INVALID_STATE, ("Can't create spinlock!"));
355     }
356 
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));
360 
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);
364 
365     blockSize = (uint32_t)(alignPad + prefixSize + dataSize + postfixSize + endPad);
366 
367     /* initialize the blocks */
368     for (i=0; i < num; i++)
369     {
370         p_Mem->p_BlocksStack[i] = p_Blocks;
371         p_Blocks += blockSize;
372     }
373 
374     /* return handle to caller */
375     *p_Handle = (t_Handle)p_Mem;
376 
377 #ifdef DEBUG_MEM_LEAKS
378     {
379         t_Error errCode = InitMemDebugDatabase(p_Mem);
380 
381         if (errCode != E_OK)
382             RETURN_ERROR(MAJOR, errCode, NO_MSG);
383 
384         p_Mem->blockOffset = (uint32_t)(p_Mem->p_BlocksStack[0] - p_Mem->p_Bases[0]);
385         p_Mem->blockSize = blockSize;
386     }
387 #endif /* DEBUG_MEM_LEAKS */
388 
389     return E_OK;
390 }
391 
392 
393 /*****************************************************************************/
394 t_Error MEM_InitSmart(char      name[],
395                       t_Handle  *p_Handle,
396                       uint32_t  num,
397                       uint16_t  dataSize,
398                       uint16_t  prefixSize,
399                       uint16_t  postfixSize,
400                       uint16_t  alignment,
401                       uint8_t   memPartitionId,
402                       bool      consecutiveMem)
403 {
404     t_MemorySegment *p_Mem;
405     uint32_t        i, blockSize;
406     uint16_t        alignPad, endPad;
407 
408     /* prepare in case of error */
409     *p_Handle = NULL;
410 
411     /* make sure that size is always a multiple of 4 */
412     if (dataSize & 3)
413     {
414         dataSize &= ~3;
415         dataSize += 4;
416     }
417 
418     /* make sure that the alignment is at least 4 and power of 2 */
419     if (alignment < 4)
420     {
421         alignment = 4;
422     }
423     else if (!POWER_OF_2(alignment))
424     {
425         RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("Alignment (should be power of 2)"));
426     }
427 
428     /* first allocate the segment descriptor */
429     p_Mem = (t_MemorySegment *)XX_Malloc(sizeof(t_MemorySegment));
430     if (!p_Mem)
431     {
432         RETURN_ERROR(MAJOR, E_NO_MEMORY, ("Memory segment structure"));
433     }
434 
435     /* allocate the blocks stack */
436     p_Mem->p_BlocksStack = (uint8_t **)XX_Malloc(num * sizeof(uint8_t*));
437     if (!p_Mem->p_BlocksStack)
438     {
439         MEM_Free(p_Mem);
440         RETURN_ERROR(MAJOR, E_NO_MEMORY, ("Memory segment block pointers stack"));
441     }
442 
443     /* allocate the blocks bases array */
444     p_Mem->p_Bases = (uint8_t **)XX_Malloc((consecutiveMem ? 1 : num) * sizeof(uint8_t*));
445     if (!p_Mem->p_Bases)
446     {
447         MEM_Free(p_Mem);
448         RETURN_ERROR(MAJOR, E_NO_MEMORY, ("Memory segment base pointers array"));
449     }
450     memset(p_Mem->p_Bases, 0, (consecutiveMem ? 1 : num) * sizeof(uint8_t*));
451 
452     /* store info about this segment */
453     p_Mem->num = num;
454     p_Mem->current = 0;
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;
462 
463     p_Mem->h_Spinlock = XX_InitSpinlock();
464     if (!p_Mem->h_Spinlock)
465     {
466         MEM_Free(p_Mem);
467         RETURN_ERROR(MAJOR, E_INVALID_STATE, ("Can't create spinlock!"));
468     }
469 
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);
473 
474     /* Calculate blockSize */
475     blockSize = (uint32_t)(alignPad + prefixSize + dataSize + postfixSize + endPad);
476 
477     /* Now allocate the blocks */
478     if (p_Mem->consecutiveMem)
479     {
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);
485         if (!p_Blocks)
486         {
487             MEM_Free(p_Mem);
488             RETURN_ERROR(MAJOR, E_NO_MEMORY, ("Memory segment blocks"));
489         }
490 
491         /* Store the memory segment address */
492         p_Mem->p_Bases[0] = p_Blocks;
493 
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);
497 
498         /* initialize the blocks */
499         for (i = 0; i < num; i++)
500         {
501             p_Mem->p_BlocksStack[i] = p_Blocks;
502             p_Blocks += blockSize;
503         }
504 
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 */
509     }
510     else
511     {
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++)
516         {
517             uint8_t *p_Block = (uint8_t *)
518                 XX_MallocSmart((uint32_t)(blockSize + alignment), memPartitionId, 1);
519             if (!p_Block)
520             {
521                 MEM_Free(p_Mem);
522                 RETURN_ERROR(MAJOR, E_NO_MEMORY, ("Memory segment blocks"));
523             }
524 
525             /* Store the memory segment address */
526             p_Mem->p_Bases[i] = p_Block;
527 
528             /* The following places the data of each block in an aligned address */
529             ALIGN_BLOCK(p_Block, prefixSize, alignment);
530 
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;
536 
537             *(uint32_t *)(p_Block - 4) = i;
538 #endif /* DEBUG_MEM_LEAKS */
539 
540             p_Mem->p_BlocksStack[i] = p_Block;
541         }
542     }
543 
544     /* store name */
545     strncpy(p_Mem->name, name, MEM_MAX_NAME_LENGTH-1);
546 
547     /* return handle to caller */
548     *p_Handle = (t_Handle)p_Mem;
549 
550 #ifdef DEBUG_MEM_LEAKS
551     {
552         t_Error errCode = InitMemDebugDatabase(p_Mem);
553 
554         if (errCode != E_OK)
555             RETURN_ERROR(MAJOR, errCode, NO_MSG);
556     }
557 #endif /* DEBUG_MEM_LEAKS */
558 
559     return E_OK;
560 }
561 
562 
563 /*****************************************************************************/
564 void MEM_Free(t_Handle h_Mem)
565 {
566     t_MemorySegment *p_Mem = (t_MemorySegment*)h_Mem;
567     uint32_t        num, i;
568 
569     /* Check MEM leaks */
570     MEM_CheckLeaks(h_Mem);
571 
572     if (p_Mem)
573     {
574         num = p_Mem->consecutiveMem ? 1 : p_Mem->num;
575 
576         if (p_Mem->allocOwner == e_MEM_ALLOC_OWNER_LOCAL_SMART)
577         {
578             for (i=0; i < num; i++)
579             {
580                 if (p_Mem->p_Bases[i])
581                 {
582                     XX_FreeSmart(p_Mem->p_Bases[i]);
583                 }
584             }
585         }
586         else if (p_Mem->allocOwner == e_MEM_ALLOC_OWNER_LOCAL)
587         {
588             for (i=0; i < num; i++)
589             {
590                 if (p_Mem->p_Bases[i])
591                 {
592                     XX_Free(p_Mem->p_Bases[i]);
593                 }
594             }
595         }
596 
597         if (p_Mem->h_Spinlock)
598             XX_FreeSpinlock(p_Mem->h_Spinlock);
599 
600         if (p_Mem->p_Bases)
601             XX_Free(p_Mem->p_Bases);
602 
603         if (p_Mem->p_BlocksStack)
604             XX_Free(p_Mem->p_BlocksStack);
605 
606 #ifdef DEBUG_MEM_LEAKS
607         if (p_Mem->p_MemDbg)
608             XX_Free(p_Mem->p_MemDbg);
609 #endif /* DEBUG_MEM_LEAKS */
610 
611        XX_Free(p_Mem);
612     }
613 }
614 
615 
616 /*****************************************************************************/
617 void * MEM_Get(t_Handle h_Mem)
618 {
619     t_MemorySegment *p_Mem = (t_MemorySegment *)h_Mem;
620     uint8_t         *p_Block;
621     uint32_t        intFlags;
622 #ifdef DEBUG_MEM_LEAKS
623     uintptr_t       callerAddr = 0;
624 
625     GET_CALLER_ADDR;
626 #endif /* DEBUG_MEM_LEAKS */
627 
628     ASSERT_COND(h_Mem);
629 
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)
633     {
634         XX_UnlockIntrSpinlock(p_Mem->h_Spinlock, intFlags);
635         return NULL;
636     }
637 
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);
642 
643     return (void *)p_Block;
644 }
645 
646 
647 /*****************************************************************************/
648 uint16_t MEM_GetN(t_Handle h_Mem, uint32_t num, void *array[])
649 {
650     t_MemorySegment     *p_Mem = (t_MemorySegment *)h_Mem;
651     uint32_t            availableBlocks;
652     register uint32_t   i;
653     uint32_t            intFlags;
654 #ifdef DEBUG_MEM_LEAKS
655     uintptr_t           callerAddr = 0;
656 
657     GET_CALLER_ADDR;
658 #endif /* DEBUG_MEM_LEAKS */
659 
660     ASSERT_COND(h_Mem);
661 
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)
666     {
667         num = availableBlocks;
668     }
669 
670     for (i=0; i < num; i++)
671     {
672         /* get pointer to block */
673         if ((array[i] = MemGet(p_Mem)) == NULL)
674         {
675             break;
676         }
677 
678 #ifdef DEBUG_MEM_LEAKS
679         DebugMemGet(p_Mem, array[i], callerAddr);
680 #endif /* DEBUG_MEM_LEAKS */
681     }
682     XX_UnlockIntrSpinlock(p_Mem->h_Spinlock, intFlags);
683 
684     return (uint16_t)i;
685 }
686 
687 
688 /*****************************************************************************/
689 t_Error MEM_Put(t_Handle h_Mem, void *p_Block)
690 {
691     t_MemorySegment *p_Mem = (t_MemorySegment *)h_Mem;
692     t_Error         rc;
693     uint32_t        intFlags;
694 
695     ASSERT_COND(h_Mem);
696 
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)
700     {
701         XX_UnlockIntrSpinlock(p_Mem->h_Spinlock, intFlags);
702         RETURN_ERROR(MAJOR, rc, NO_MSG);
703     }
704 
705 #ifdef DEBUG_MEM_LEAKS
706     DebugMemPut(p_Mem, p_Block);
707 #endif /* DEBUG_MEM_LEAKS */
708     XX_UnlockIntrSpinlock(p_Mem->h_Spinlock, intFlags);
709 
710     return E_OK;
711 }
712 
713 
714 #ifdef DEBUG_MEM_LEAKS
715 
716 /*****************************************************************************/
717 void MEM_CheckLeaks(t_Handle h_Mem)
718 {
719     t_MemorySegment *p_Mem = (t_MemorySegment *)h_Mem;
720     t_MemDbg        *p_MemDbg = (t_MemDbg *)p_Mem->p_MemDbg;
721     uint8_t         *p_Block;
722     int             i;
723 
724     ASSERT_COND(h_Mem);
725 
726     if (p_Mem->consecutiveMem)
727     {
728         for (i=0; i < p_Mem->num; i++)
729         {
730             if (p_MemDbg[i].ownerAddress != ILLEGAL_BASE)
731             {
732                 /* Find the block address */
733                 p_Block = ((p_Mem->p_Bases[0] + p_Mem->blockOffset) +
734                            (i * p_Mem->blockSize));
735 
736                 XX_Print("MEM leak: 0x%08x, Caller address: 0x%08x\n",
737                          p_Block, p_MemDbg[i].ownerAddress);
738             }
739         }
740     }
741     else
742     {
743         for (i=0; i < p_Mem->num; i++)
744         {
745             if (p_MemDbg[i].ownerAddress != ILLEGAL_BASE)
746             {
747                 /* Find the block address */
748                 p_Block = p_Mem->p_Bases[i];
749 
750                 ALIGN_BLOCK(p_Block, p_Mem->prefixSize, p_Mem->alignment);
751 
752                 if (p_Block == p_Mem->p_Bases[i])
753                     p_Block += p_Mem->alignment;
754 
755                 XX_Print("MEM leak: 0x%08x, Caller address: 0x%08x\n",
756                          p_Block, p_MemDbg[i].ownerAddress);
757             }
758         }
759     }
760 }
761 
762 #endif /* DEBUG_MEM_LEAKS */
763 
764 
765 #endif
766