2 * This file is part of the libpayload project.
4 * Copyright (C) 2008 Advanced Micro Devices, Inc.
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
9 * 1. Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 * 2. Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
14 * 3. The name of the author may not be used to endorse or promote products
15 * derived from this software without specific prior written permission.
17 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
18 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
21 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
23 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
30 /* This is a classically weak malloc() implmentation.
31 We have a relatively small and static heap, so we take
32 the easy route with an O(N) loop through the tree for
33 every malloc() and free(). Obviously, this doesn't scale
34 past a few hundred K (if that).
36 We're also susecptable to the usual buffer overun poisoning,
37 though the risk is within acceptable ranges for this
38 implementation (don't overrun your buffers, kids!)
41 #include <libpayload.h>
43 /* Defined in the ldscript */
44 extern char _heap, _eheap;
46 static void *hstart = (void *) &_heap;
47 static void *hend = (void *) &_eheap;
49 typedef unsigned int hdrtype_t;
51 #define MAGIC (0x2a << 26)
52 #define FLAG_FREE (1 << 25)
53 #define FLAG_USED (1 << 24)
55 #define SIZE(_h) ((_h) & 0xFFFFFF)
57 #define _HEADER(_s, _f) ((hdrtype_t) (MAGIC | (_f) | ((_s) & 0xFFFFFF)))
59 #define FREE_BLOCK(_s) _HEADER(_s, FLAG_FREE)
60 #define USED_BLOCK(_s) _HEADER(_s, FLAG_USED)
62 #define HDRSIZE (sizeof(hdrtype_t))
64 #define IS_FREE(_h) (((_h) & (MAGIC | FLAG_FREE)) == (MAGIC | FLAG_FREE))
65 #define HAS_MAGIC(_h) (((_h) & MAGIC) == MAGIC)
67 void print_malloc_map(void);
69 static void setup(void)
71 int size = (unsigned int) (_heap - _eheap) - HDRSIZE;
72 *((hdrtype_t *) hstart) = FREE_BLOCK(size);
75 static void *alloc(int len)
83 if (!len || len > 0xFFFFFF)
86 /* Make sure the region is setup correctly */
87 if (!HAS_MAGIC(*((hdrtype_t *) ptr)))
90 /* Find some free space */
93 header = *((hdrtype_t *) ptr);
94 int size = SIZE(header);
96 if (header & FLAG_FREE) {
99 void *nptr = ptr + HDRSIZE + len;
100 int nsize = size - (len + 8);
102 /* Mark the block as used */
103 *((hdrtype_t *) ptr) = USED_BLOCK(len);
105 /* If there is still room in this block,
106 * then mark it as such */
109 *((hdrtype_t *) nptr) =
110 FREE_BLOCK(nsize - 4);
112 return (void *) (ptr + HDRSIZE);
116 ptr += HDRSIZE + size;
120 /* Nothing available */
121 return (void *) NULL;
124 static void _consolidate(void)
130 hdrtype_t hdr = *((hdrtype_t *) ptr);
131 unsigned int size = 0;
134 ptr += HDRSIZE + SIZE(hdr);
139 nptr = ptr + HDRSIZE + SIZE(hdr);
141 while (nptr < hend) {
142 hdrtype_t nhdr = *((hdrtype_t *) nptr);
144 if (!(IS_FREE(nhdr)))
147 size += SIZE(nhdr) + HDRSIZE;
149 *((hdrtype_t *) nptr) = 0;
151 nptr += (HDRSIZE + SIZE(nhdr));
154 *((hdrtype_t *) ptr) = FREE_BLOCK(size);
166 if (ptr < hstart || ptr >= hend)
169 hdr = *((hdrtype_t *) ptr);
171 /* Not our header (we're probably poisoned) */
179 *((hdrtype_t *) ptr) = FREE_BLOCK(SIZE(hdr));
183 void *malloc(size_t size)
188 void *calloc(size_t nmemb, size_t size)
190 unsigned int total = (nmemb * size);
191 void *ptr = alloc(size);
194 memset(ptr, 0, total);
199 void *realloc(void *ptr, size_t size)
208 pptr = ptr - HDRSIZE;
210 if (!HAS_MAGIC(*((hdrtype_t *) pptr)))
213 /* Get the original size of the block */
214 osize = SIZE(*((hdrtype_t *) pptr));
216 /* Free the memory to update the tables - this
217 won't touch the actual memory, so we can still
218 use it for the copy after we have reallocated
225 /* if ret == NULL, then doh - failure.
226 if ret == ptr then woo-hoo! no copy needed */
228 if (ret == NULL || ret == ptr)
231 /* Copy the memory to the new location */
232 memcpy(ret, ptr, osize > size ? size : osize);
236 /* This is for debugging purposes */
239 void print_malloc_map(void)
244 hdrtype_t hdr = *((hdrtype_t *) ptr);
246 if (!HAS_MAGIC(hdr)) {
247 printf("Poisoned magic - we're toast\n");
251 /* FIXME: Verify the size of the block */
253 printf("%x: %s (%x bytes)\n",
254 (unsigned int) (ptr - hstart),
255 hdr & FLAG_FREE ? "FREE" : "USED",
258 ptr += HDRSIZE + SIZE(hdr);