]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - sys/contrib/ncsw/etc/ncsw_mem.c
Import libxo-1.3.1:
[FreeBSD/FreeBSD.git] / sys / contrib / ncsw / etc / ncsw_mem.c
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