LibXenon
Bare-metal Xbox 360 homebrew library
Loading...
Searching...
No Matches
lib_malloc.c
Go to the documentation of this file.
1/* *********************************************************************
2 * Broadcom Common Firmware Environment (CFE)
3 *
4 * Local memory manager File: cfe_malloc.c
5 *
6 * This routine is used to manage memory allocated within the
7 * firmware. You give it a chunk of memory to manage, and then
8 * these routines manage suballocations from there.
9 *
10 * Author: Mitch Lichtenberg (mpl@broadcom.com)
11 *
12 *********************************************************************
13 *
14 * Copyright 2000,2001
15 * Broadcom Corporation. All rights reserved.
16 *
17 * This software is furnished under license and may be used and
18 * copied only in accordance with the following terms and
19 * conditions. Subject to these conditions, you may download,
20 * copy, install, use, modify and distribute modified or unmodified
21 * copies of this software in source and/or binary form. No title
22 * or ownership is transferred hereby.
23 *
24 * 1) Any source code used, modified or distributed must reproduce
25 * and retain this copyright notice and list of conditions as
26 * they appear in the source file.
27 *
28 * 2) No right is granted to use any trade name, trademark, or
29 * logo of Broadcom Corporation. Neither the "Broadcom
30 * Corporation" name nor any trademark or logo of Broadcom
31 * Corporation may be used to endorse or promote products
32 * derived from this software without the prior written
33 * permission of Broadcom Corporation.
34 *
35 * 3) THIS SOFTWARE IS PROVIDED "AS-IS" AND ANY EXPRESS OR
36 * IMPLIED WARRANTIES, INCLUDING BUT NOT LIMITED TO, ANY IMPLIED
37 * WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
38 * PURPOSE, OR NON-INFRINGEMENT ARE DISCLAIMED. IN NO EVENT
39 * SHALL BROADCOM BE LIABLE FOR ANY DAMAGES WHATSOEVER, AND IN
40 * PARTICULAR, BROADCOM SHALL NOT BE LIABLE FOR DIRECT, INDIRECT,
41 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
42 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
43 * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
44 * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
45 * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
46 * TORT (INCLUDING NEGLIGENCE OR OTHERWISE), EVEN IF ADVISED OF
47 * THE POSSIBILITY OF SUCH DAMAGE.
48 ********************************************************************* */
49
50#ifdef TESTPROG
51#include <stdio.h>
52#include <malloc.h>
53#include <stdlib.h>
54#endif
55
56#include <stdio.h>
57#include <stdlib.h>
58#include "lib_types.h"
59#include "lib_malloc.h"
60
61#define memnode_data(t,m) (t) (((memnode_t *) (m))+1)
62
63/* *********************************************************************
64 * Constants
65 ********************************************************************* */
66
67#define MEMNODE_SEAL 0xFAAFA123 /* just some random constant */
68#define MINBLKSIZE 64
69
70/* *********************************************************************
71 * Globals
72 ********************************************************************* */
73
74mempool_t kmempool; /* default pool */
75
76/* *********************************************************************
77 * kmeminit(pool,buffer,length)
78 *
79 * Initialize the memory manager, given a pointer to an area
80 * of memory and a size. This routine simply initializes the
81 * root node to be a single block of empty space.
82 *
83 * Input parameters:
84 * pool - pool pointer
85 * buffer - beginning of buffer area, must be pointer-aligned
86 * length - length of buffer area
87 *
88 * Return value:
89 * nothing
90 ********************************************************************* */
91
92
93void kmeminit(mempool_t *pool,unsigned char *buffer,int length)
94{
95 pool->root = (memnode_t *) buffer;
96 pool->root->seal = MEMNODE_SEAL;
97 pool->root->length = length - sizeof(memnode_t);
98 pool->root->data = memnode_data(unsigned char *,pool->root);
99 pool->root->status = memnode_free;
100 pool->root->next = NULL;
101
102 pool->base = buffer;
103 pool->length = length;
104}
105
106
107/* *********************************************************************
108 * kmempoolbase(pool)
109 *
110 * Returns the base address of the specified memory pool
111 *
112 * Input parameters:
113 * pool - pool pointer
114 *
115 * Return value:
116 * pointer to beginning of pool's memory
117 ********************************************************************* */
119{
120 return pool->base;
121}
122
123/* *********************************************************************
124 * kmempoolsize(pool)
125 *
126 * Returns the total size of the specified memory pool
127 *
128 * Input parameters:
129 * pool - pool pointer
130 *
131 * Return value:
132 * size of pool in bytes
133 ********************************************************************* */
134
136{
137 return pool->length;
138}
139
140/* *********************************************************************
141 * kmemcompact(pool)
142 *
143 * Compact the memory blocks, coalescing consectutive free blocks
144 * on the list.
145 *
146 * Input parameters:
147 * pool - pool descriptor
148 *
149 * Return value:
150 * nothing
151 ********************************************************************* */
152
153static void kmemcompact(mempool_t *pool)
154{
155 memnode_t *m;
156 int compacted;
157
158 do {
159 compacted = 0;
160
161 for (m = pool->root; m; m = m->next) {
162
163 /* Check seal to be sure that we're doing ok */
164
165 if (m->seal != MEMNODE_SEAL) {
166#ifdef TESTPROG
167 printf("Memory list corrupted!\n");
168#endif
169 return;
170 }
171
172 /*
173 * If we're not on the last block and both this
174 * block and the next one are free, combine them
175 */
176
177 if (m->next &&
178 (m->status == memnode_free) &&
179 (m->next->status == memnode_free)) {
180 m->length += sizeof(memnode_t) + m->next->length;
181 m->next->seal = 0;
182 m->next = m->next->next;
183 compacted++;
184 }
185
186 /* Keep going till we make a pass without doing anything. */
187 }
188
189 } while (compacted > 0);
190}
191
192
193/* *********************************************************************
194 * kfree(ptr)
195 *
196 * Return some memory to the pool.
197 *
198 * Input parameters:
199 * ptr - pointer to something allocated via kmalloc()
200 *
201 * Return value:
202 * nothing
203 ********************************************************************* */
204
205void kfree(mempool_t *pool,void *ptr)
206{
207 memnode_t **backptr;
208 memnode_t *m;
209
210 if (((unsigned char *) ptr < pool->base) ||
211 ((unsigned char *) ptr >= (pool->base+pool->length))) {
212#ifdef TESTPROG
213 printf("Pointer %08X does not belong to pool %08X\n",ptr,pool);
214#endif
215 return;
216 }
217
218 backptr = (memnode_t **) (((unsigned char *) ptr) - sizeof(memnode_t *));
219 m = *backptr;
220
221 if (m->seal != MEMNODE_SEAL) {
222#ifdef TESTPROG
223 printf("Invalid node freed: %08X\n",m);
224#endif
225 return;
226 }
227
228 m->status = memnode_free;
229
230 kmemcompact(pool);
231}
232
233/* *********************************************************************
234 * lib_outofmemory()
235 *
236 * Called when we run out of memory.
237 * XXX replace with something real someday
238 *
239 * Input parameters:
240 * nothing
241 *
242 * Return value:
243 * nothing
244 ********************************************************************* */
245
246void lib_outofmemory(void);
248{
249 printf("PANIC: out of memory!\n");
250}
251
252/* *********************************************************************
253 * kmalloc(pool,size,align)
254 *
255 * Allocate some memory from the pool.
256 *
257 * Input parameters:
258 * pool - pool structure
259 * size - size of item to allocate
260 * align - alignment (must be zero or a power of 2)
261 *
262 * Return value:
263 * pointer to data, or NULL if no memory left
264 ********************************************************************* */
265
266void *kmalloc(mempool_t *pool,unsigned int size,unsigned int align)
267{
268 memnode_t *m;
269 memnode_t *newm;
270 memnode_t **backptr;
271 uintptr_t daddr = 0;
272 uintptr_t realsize = 0;
273 uintptr_t extra;
274 uintptr_t blkend;
275 uintptr_t ptralign;
276
277 /*
278 * Everything should be aligned by at least the
279 * size of an int64
280 */
281
282 ptralign = (uintptr_t) align;
283 if (ptralign < sizeof(void *)) ptralign = sizeof(uint64_t);
284
285 /*
286 * Everything should be at least a multiple of the
287 * size of a pointer.
288 */
289
290 if (size == 0) size = sizeof(void *);
291 if (size & (sizeof(void *)-1)) {
292 size += sizeof(void *);
293 size &= ~(sizeof(void *)-1);
294 }
295
296 /*
297 * Find a memnode at least big enough to hold the storage we
298 * want.
299 */
300
301 for (m = pool->root; m; m = m->next) {
302
303 if (m->status == memnode_alloc) continue;
304
305 /*
306 * If we wanted a particular alignment, we will
307 * need to adjust the size.
308 */
309
310 daddr = memnode_data(uintptr_t,m);
311 extra = 0;
312 if (daddr & (ptralign-1)) {
313 extra = size + (ptralign - (daddr & (ptralign-1)));
314 }
315 realsize = size + extra;
316
317 if (m->length < realsize) continue;
318 break;
319 }
320
321 /*
322 * If m is null, there's no memory left.
323 */
324
325 if (m == NULL) {
327 return NULL;
328 }
329
330 /*
331 * Otherwise, use this block. Calculate the address of the data
332 * to preserve the alignment.
333 */
334
335 if (daddr & (ptralign-1)) {
336 daddr += ptralign;
337 daddr &= ~(ptralign-1);
338 }
339
340 /* Mark this node as allocated. */
341
342 m->data = (unsigned char *) daddr;
343 m->status = memnode_alloc;
344
345 /*
346 * Okay, this is ugly. Store a pointer to the original
347 * memnode just before what we've allocated. It's guaranteed
348 * to be aligned at least well enough for this pointer.
349 * If for some reason the memnode was already exactly
350 * aligned, backing up will put us inside the memnode
351 * structure itself... that's why the memnodeptr field
352 * is there, as a placeholder for this eventuality.
353 */
354
355 backptr = (memnode_t **) (m->data - sizeof(memnode_t *));
356 *backptr = m;
357
358 /*
359 * See if we need to split it.
360 * Don't bother to split if the resulting size will be
361 * less than MINBLKSIZE bytes
362 */
363
364 if (m->length - realsize < MINBLKSIZE) {
365 return m->data;
366 }
367
368 /*
369 * Split this block. Align the address on a pointer-size
370 * boundary.
371 */
372
373 daddr += size;
374 if (daddr & (uintptr_t)(sizeof(void *)-1)) {
375 daddr += (uintptr_t)sizeof(void *);
376 daddr &= ~(uintptr_t)(sizeof(void *)-1);
377 }
378
379 blkend = memnode_data(uintptr_t,m) + (uintptr_t)(m->length);
380
381 newm = (memnode_t *) daddr;
382
383 newm->next = m->next;
384 m->length = (unsigned int) (daddr - memnode_data(uintptr_t,m));
385 m->next = newm;
386 m->status = memnode_alloc;
387 newm->seal = MEMNODE_SEAL;
388 newm->data = memnode_data(unsigned char *,newm);
389 newm->length = (unsigned int) (blkend - memnode_data(uintptr_t,newm));
390 newm->status = memnode_free;
391
392 return m->data;
393}
394
395
397{
398 memnode_t *m;
399 memnode_t **backptr;
400 uintptr_t daddr;
401
402 stats->mem_totalbytes = pool->length;
403 stats->mem_allocbytes = 0;
404 stats->mem_freebytes = 0;
405 stats->mem_allocnodes = 0;
406 stats->mem_freenodes = 0;
407 stats->mem_largest = 0;
408
409 for (m = pool->root; m; m = m->next) {
410 if (m->status) {
411 stats->mem_allocnodes++;
412 stats->mem_allocbytes += m->length;
413 }
414 else {
415 stats->mem_freenodes++;
416 stats->mem_freebytes += m->length;
417 if (m->length > stats->mem_largest) {
418 stats->mem_largest = m->length;
419 }
420 }
421
422 daddr = memnode_data(uintptr_t,m);
423 if (m->seal != MEMNODE_SEAL) {
424 return -1;
425 }
426 if (m->next && ((daddr + m->length) != (uintptr_t) m->next)) {
427 return -1;
428 }
429 if (m->next && (m->next < m)) {
430 return -1;
431 }
432 if (m->data < (unsigned char *) m) {
433 return -1;
434 }
435 if (m->status == memnode_alloc) {
436 backptr = (memnode_t **) (m->data - sizeof(void *));
437 if (*backptr != m) {
438 return -1;
439 }
440 }
441 }
442
443 return 0;
444}
445
446
447/* *********************************************************************
448 * kmemchk()
449 *
450 * Check the consistency of the memory pool.
451 *
452 * Input parameters:
453 * pool - pool pointer
454 *
455 * Return value:
456 * 0 - pool is consistent
457 * -1 - pool is corrupt
458 ********************************************************************* */
459
460#ifdef TESTPROG
461int kmemchk(mempool_t *pool,int verbose)
462{
463 memnode_t *m;
464 memnode_t **backptr;
465 unsigned int daddr;
466
467 for (m = pool->root; m; m = m->next) {
468 if (verbose) {
469 printf("%08X: Next=%08X Len=%5u %s Data=%08X ",
470 m,m->next,m->length,
471 m->status ? "alloc" : "free ",
472 m->data);
473 }
474 daddr = memnode_data(uintptr_t,m);
475 if (m->seal != MEMNODE_SEAL) {
476 if (verbose) printf("BadSeal ");
477 else return -1;
478 }
479 if (m->next && (daddr + m->length != (unsigned int) m->next)) {
480 if (verbose) printf("BadLength ");
481 else return -1;
482 }
483 if (m->next && (m->next < m)) {
484 if (verbose) printf("BadOrder ");
485 else return -1;
486 }
487 if (m->data < (unsigned char *) m) {
488 if (verbose) printf("BadData ");
489 else return -1;
490 }
491 if (m->status == memnode_alloc) {
492 backptr = (memnode_t **) (m->data - sizeof(void *));
493 if (*backptr != m) {
494 if (verbose) printf("BadBackPtr ");
495 else return -1;
496 }
497 }
498 if (verbose) printf("\n");
499 }
500
501 return 0;
502}
503
504
505#define MEMSIZE 1024*1024
506
507unsigned char *ptrs[4096];
508unsigned int sizes[4096];
509
510/* *********************************************************************
511 * main(argc,argv)
512 *
513 * Test program for the memory allocator
514 *
515 * Input parameters:
516 * argc,argv
517 *
518 * Return value:
519 * nothing
520 ********************************************************************* */
521
522
523void main(int argc,char *argv[])
524{
525 unsigned char *mem;
526 int items = 0;
527 int idx;
528 int size;
529 int totalsize = 0;
530 int nfree,freecnt;
531 mempool_t *pool = &kmempool;
532
533 mem = malloc(MEMSIZE);
534 kmeminit(pool,mem,MEMSIZE);
535
536 items = 0;
537
538 for (;;) {
539
540 for (;;) {
541 if (items == 4096) break;
542 size = rand() % 1024;
543 ptrs[items] = kmalloc(pool,size,1<<(rand() & 7));
544 if (!ptrs[items]) break;
545 sizes[items] = size;
546 items++;
547 totalsize += size;
548 }
549
550 printf("%d items allocated, %d total bytes\n",items,totalsize);
551
552 if (kmemchk(pool,0) < 0) {
553 kmemchk(pool,1);
554 exit(1);
555 }
556
557 /* Scramble the pointers */
558 idx = items - 1;
559
560 while (idx) {
561 if (rand() & 2) {
562 mem = ptrs[0];
563 ptrs[0] = ptrs[idx];
564 ptrs[idx] = mem;
565
566 nfree = sizes[0];
567 sizes[0] = sizes[idx];
568 sizes[idx] = nfree;
569 }
570 idx--;
571 }
572
573 /* now free a random number of elements */
574
575 nfree = rand() % items;
576 freecnt = 0;
577
578 for (idx = nfree; idx < items; idx++) {
579 kfree(pool,ptrs[idx]);
580 totalsize -= sizes[idx];
581 freecnt++;
582 ptrs[idx] = NULL;
583 sizes[idx] = 0;
584 if (kmemchk(pool,0) < 0) {
585 kmemchk(pool,1);
586 exit(1);
587 }
588 }
589
590 items -= freecnt;
591
592 printf(".");
593
594 }
595
596 kmemchk(pool,1);
597
598 exit(0);
599}
600
601#endif /* TESTPROG */
602
603
604static unsigned char heap[1*1024*1024];
605static int kmem_init_done=0;
606
607void kmem_init(void)
608{
609 if(kmem_init_done){
610 printf("Calling kmem_init() before usb_init() is deprecated.\n");
611 return;
612 }
613 kmem_init_done=1;
614
615 mempool_t *pool = &kmempool;
616 kmeminit(pool, heap, sizeof(heap));
617}
uint16_t length
Definition: ata.h:4
#define base
#define NULL
Definition: def.h:47
u32 ptr
Definition: iso9660.c:536
u32 size
Definition: iso9660.c:537
void lib_outofmemory(void)
Definition: lib_malloc.c:247
void kfree(mempool_t *pool, void *ptr)
Definition: lib_malloc.c:205
int kmempoolsize(mempool_t *pool)
Definition: lib_malloc.c:135
int kmemstats(mempool_t *pool, memstats_t *stats)
Definition: lib_malloc.c:396
#define MEMNODE_SEAL
Definition: lib_malloc.c:67
void kmem_init(void)
Definition: lib_malloc.c:607
#define memnode_data(t, m)
Definition: lib_malloc.c:61
void * kmalloc(mempool_t *pool, unsigned int size, unsigned int align)
Definition: lib_malloc.c:266
void * kmempoolbase(mempool_t *pool)
Definition: lib_malloc.c:118
mempool_t kmempool
Definition: lib_malloc.c:74
#define MINBLKSIZE
Definition: lib_malloc.c:68
void kmeminit(mempool_t *pool, unsigned char *buffer, int length)
Definition: lib_malloc.c:93
int kmemchk(mempool_t *pool, int verbose)
struct memnode_s memnode_t
@ memnode_free
Definition: lib_malloc.h:62
@ memnode_alloc
Definition: lib_malloc.h:62
__SIZE_TYPE__ uintptr_t
Definition: lib_types.h:64
u64 uint64_t
Definition: libfdt_env.h:12
Definition: mem.c:156
memnode_status_t status
Definition: lib_malloc.h:68
unsigned int seal
Definition: lib_malloc.h:65
unsigned int length
Definition: lib_malloc.h:67
unsigned char * data
Definition: lib_malloc.h:69
struct memnode_s * next
Definition: lib_malloc.h:66
unsigned char * base
Definition: lib_malloc.h:75
memnode_t * root
Definition: lib_malloc.h:74
unsigned int length
Definition: lib_malloc.h:76
int mem_allocbytes
Definition: lib_malloc.h:55
int mem_totalbytes
Definition: lib_malloc.h:54
int mem_freebytes
Definition: lib_malloc.h:56
int mem_freenodes
Definition: lib_malloc.h:58
int mem_largest
Definition: lib_malloc.h:59
int mem_allocnodes
Definition: lib_malloc.h:57
int main(int argc, char *argv[])
Definition: usbhack.c:423
__le16 m
Definition: xenos_edid.h:8