xref: /optee_os/lib/libutils/isoc/bget_malloc.c (revision bc420748bfc44a9e09000a3966fc59e9e0219df4)
1 /*
2  * Copyright (c) 2014, STMicroelectronics International N.V.
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions are met:
7  *
8  * 1. Redistributions of source code must retain the above copyright notice,
9  * this list of conditions and the following disclaimer.
10  *
11  * 2. Redistributions in binary form must reproduce the above copyright notice,
12  * this list of conditions and the following disclaimer in the documentation
13  * and/or other materials provided with the distribution.
14  *
15  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
16  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18  * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
19  * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
20  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
21  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
22  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
23  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
24  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
25  * POSSIBILITY OF SUCH DAMAGE.
26  */
27 
28 #define PROTOTYPES
29 
30 /*
31  *  BGET CONFIGURATION
32  *  ==================
33  */
34 /* #define BGET_ENABLE_ALL_OPTIONS */
35 #ifdef BGET_ENABLE_OPTION
36 #define TestProg    20000	/* Generate built-in test program
37 				   if defined.  The value specifies
38 				   how many buffer allocation attempts
39 				   the test program should make. */
40 #endif
41 
42 
43 #define SizeQuant   8		/* Buffer allocation size quantum:
44 				   all buffers allocated are a
45 				   multiple of this size.  This
46 				   MUST be a power of two. */
47 
48 #ifdef BGET_ENABLE_OPTION
49 #define BufDump     1		/* Define this symbol to enable the
50 				   bpoold() function which dumps the
51 				   buffers in a buffer pool. */
52 
53 #define BufValid    1		/* Define this symbol to enable the
54 				   bpoolv() function for validating
55 				   a buffer pool. */
56 
57 #define DumpData    1		/* Define this symbol to enable the
58 				   bufdump() function which allows
59 				   dumping the contents of an allocated
60 				   or free buffer. */
61 
62 #define BufStats    1		/* Define this symbol to enable the
63 				   bstats() function which calculates
64 				   the total free space in the buffer
65 				   pool, the largest available
66 				   buffer, and the total space
67 				   currently allocated. */
68 
69 #define FreeWipe    1		/* Wipe free buffers to a guaranteed
70 				   pattern of garbage to trip up
71 				   miscreants who attempt to use
72 				   pointers into released buffers. */
73 
74 #define BestFit     1		/* Use a best fit algorithm when
75 				   searching for space for an
76 				   allocation request.  This uses
77 				   memory more efficiently, but
78 				   allocation will be much slower. */
79 
80 #define BECtl       1		/* Define this symbol to enable the
81 				   bectl() function for automatic
82 				   pool space control.  */
83 #endif
84 
85 #ifdef MEM_DEBUG
86 #undef NDEBUG
87 #define DumpData    1
88 #define BufValid    1
89 #define FreeWipe    1
90 #endif
91 
92 #if defined(CFG_TEE_CORE_DEBUG) && CFG_TEE_CORE_DEBUG != 0
93 #define BufStats    1
94 #endif
95 
96 #include <stdlib.h>
97 #include <stdint.h>
98 #include <stdbool.h>
99 #include <malloc.h>
100 #include "bget.c"		/* this is ugly, but this is bget */
101 #include <util.h>
102 
103 struct malloc_pool {
104 	void *buf;
105 	size_t len;
106 };
107 
108 static struct malloc_pool *malloc_pool;
109 static size_t malloc_pool_len;
110 
111 #ifdef BufStats
112 static size_t max_alloc_heap;
113 
114 static void raw_malloc_save_max_alloced_size(void)
115 {
116 	if (totalloc > max_alloc_heap)
117 		max_alloc_heap = totalloc;
118 }
119 
120 void malloc_reset_max_allocated(void)
121 {
122 	max_alloc_heap = 0;
123 }
124 
125 size_t malloc_get_max_allocated(void)
126 {
127 	return max_alloc_heap;
128 }
129 
130 size_t malloc_get_allocated(void)
131 {
132 	return totalloc;
133 }
134 
135 #else /* BufStats */
136 
137 static void raw_malloc_save_max_alloced_size(void)
138 {
139 }
140 
141 void malloc_reset_max_allocated(void)
142 {
143 }
144 
145 size_t malloc_get_max_allocated(void)
146 {
147 	return 0;
148 }
149 
150 size_t malloc_get_allocated(void)
151 {
152 	return 0;
153 }
154 #endif /* BufStats */
155 
156 size_t malloc_get_heap_size(void)
157 {
158 	size_t n;
159 	size_t s = 0;
160 
161 	for (n = 0; n < malloc_pool_len; n++)
162 		s += malloc_pool[n].len;
163 
164 	return s;
165 }
166 
167 #ifdef BufValid
168 static void raw_malloc_validate_pools(void)
169 {
170 	size_t n;
171 
172 	for (n = 0; n < malloc_pool_len; n++)
173 		bpoolv(malloc_pool[n].buf);
174 }
175 #else
176 static void raw_malloc_validate_pools(void)
177 {
178 }
179 #endif
180 
181 struct bpool_iterator {
182 	struct bfhead *next_buf;
183 	size_t pool_idx;
184 };
185 
186 static void bpool_foreach_iterator_init(struct bpool_iterator *iterator)
187 {
188 	iterator->pool_idx = 0;
189 	iterator->next_buf = BFH(malloc_pool[0].buf);
190 }
191 
192 static bool bpool_foreach_pool(struct bpool_iterator *iterator, void **buf,
193 		size_t *len, bool *isfree)
194 {
195 	struct bfhead *b = iterator->next_buf;
196 	bufsize bs = b->bh.bsize;
197 
198 	if (bs == ESent)
199 		return false;
200 
201 	if (bs < 0) {
202 		/* Allocated buffer */
203 		bs = -bs;
204 
205 		*isfree = false;
206 	} else {
207 		/* Free Buffer */
208 		*isfree = true;
209 
210 		/* Assert that the free list links are intact */
211 		assert(b->ql.blink->ql.flink == b);
212 		assert(b->ql.flink->ql.blink == b);
213 	}
214 
215 	*buf = (uint8_t *)b + sizeof(struct bhead);
216 	*len = bs - sizeof(struct bhead);
217 
218 	iterator->next_buf = BFH((uint8_t *)b + bs);
219 	return true;
220 }
221 
222 static bool bpool_foreach(struct bpool_iterator *iterator, void **buf)
223 {
224 	while (true) {
225 		size_t len;
226 		bool isfree;
227 
228 		if (bpool_foreach_pool(iterator, buf, &len, &isfree)) {
229 			if (isfree)
230 				continue;
231 			return true;
232 		}
233 
234 		if ((iterator->pool_idx + 1) >= malloc_pool_len)
235 			return false;
236 
237 		iterator->pool_idx++;
238 		iterator->next_buf = BFH(malloc_pool[iterator->pool_idx].buf);
239 	}
240 }
241 
242 /* Convenience macro for looping over all allocated buffers */
243 #define BPOOL_FOREACH(iterator, bp) \
244 		for (bpool_foreach_iterator_init((iterator)); \
245 			bpool_foreach((iterator), (bp));)
246 
247 static void *raw_malloc(size_t hdr_size, size_t ftr_size, size_t pl_size)
248 {
249 	void *ptr;
250 	size_t s = hdr_size + ftr_size + pl_size;
251 
252 	/*
253 	 * Make sure that malloc has correct alignment of returned buffers.
254 	 * The assumption is that uintptr_t will be as wide as the largest
255 	 * required alignment of any type.
256 	 */
257 	COMPILE_TIME_ASSERT(SizeQuant >= sizeof(uintptr_t));
258 
259 	raw_malloc_validate_pools();
260 
261 	/* Check wrapping */
262 	if (s < pl_size)
263 		return NULL;
264 
265 	/* BGET doesn't like 0 sized allocations */
266 	if (!s)
267 		s++;
268 
269 	ptr = bget(s);
270 	raw_malloc_save_max_alloced_size();
271 	return ptr;
272 }
273 
274 static void raw_free(void *ptr)
275 {
276 	raw_malloc_validate_pools();
277 
278 	if (ptr)
279 		brel(ptr);
280 }
281 
282 static void *raw_calloc(size_t hdr_size, size_t ftr_size, size_t pl_nmemb,
283 		size_t pl_size)
284 {
285 	size_t s = hdr_size + ftr_size + pl_nmemb * pl_size;
286 	void *ptr;
287 
288 	raw_malloc_validate_pools();
289 
290 	/* Check wrapping */
291 	if (s < pl_nmemb || s < pl_size)
292 		return NULL;
293 
294 	/* BGET doesn't like 0 sized allocations */
295 	if (!s)
296 		s++;
297 
298 	ptr = bgetz(s);
299 	raw_malloc_save_max_alloced_size();
300 	return ptr;
301 }
302 
303 static void *raw_realloc(void *ptr, size_t hdr_size, size_t ftr_size,
304 		size_t pl_size)
305 {
306 	size_t s = hdr_size + ftr_size + pl_size;
307 	void *p;
308 
309 	raw_malloc_validate_pools();
310 
311 	/* Check wrapping */
312 	if (s < pl_size)
313 		return NULL;
314 
315 	/* BGET doesn't like 0 sized allocations */
316 	if (!s)
317 		s++;
318 
319 	p = bgetr(ptr, s);
320 	raw_malloc_save_max_alloced_size();
321 	return p;
322 }
323 
324 static void create_free_block(struct bfhead *bf, bufsize size, struct bhead *bn)
325 {
326 	assert(BH((char *)bf + size) == bn);
327 	assert(bn->bsize < 0); /* Next block should be allocated */
328 	/* Next block shouldn't already have free block in front */
329 	assert(bn->prevfree == 0);
330 
331 	/* Create the free buf header */
332 	bf->bh.bsize = size;
333 	bf->bh.prevfree = 0;
334 
335 	/* Update next block to point to the new free buf header */
336 	bn->prevfree = size;
337 
338 	/* Insert the free buffer on the free list */
339 	assert(freelist.ql.blink->ql.flink == &freelist);
340 	assert(freelist.ql.flink->ql.blink == &freelist);
341 	bf->ql.flink = &freelist;
342 	bf->ql.blink = freelist.ql.blink;
343 	freelist.ql.blink = bf;
344 	bf->ql.blink->ql.flink = bf;
345 }
346 
347 static void brel_before(char *orig_buf, char *new_buf)
348 {
349 	struct bfhead *bf;
350 	struct bhead *b;
351 	bufsize size;
352 	bufsize orig_size;
353 
354 	assert(orig_buf < new_buf);
355 	/* There has to be room for the freebuf header */
356 	size = (bufsize)(new_buf - orig_buf);
357 	assert(size >= (SizeQ + sizeof(struct bhead)));
358 
359 	/* Point to head of original buffer */
360 	bf = BFH(orig_buf - sizeof(struct bhead));
361 	orig_size = -bf->bh.bsize; /* negative since it's an allocated buffer */
362 
363 	/* Point to head of the becoming new allocated buffer */
364 	b = BH(new_buf - sizeof(struct bhead));
365 
366 	if (bf->bh.prevfree != 0) {
367 		/* Previous buffer is free, consolidate with that buffer */
368 		struct bfhead *bfp;
369 
370 		/* Update the previous free buffer */
371 		bfp = BFH((char *)bf - bf->bh.prevfree);
372 		assert(bfp->bh.bsize == bf->bh.prevfree);
373 		bfp->bh.bsize += size;
374 
375 		/* Make a new allocated buffer header */
376 		b->prevfree = bfp->bh.bsize;
377 		/* Make it negative since it's an allocated buffer */
378 		b->bsize = -(orig_size - size);
379 	} else {
380 		/*
381 		 * Previous buffer is allocated, create a new buffer and
382 		 * insert on the free list.
383 		 */
384 
385 		/* Make it negative since it's an allocated buffer */
386 		b->bsize = -(orig_size - size);
387 
388 		create_free_block(bf, size, b);
389 	}
390 
391 #ifdef BufStats
392 	totalloc -= size;
393 	assert(totalloc >= 0);
394 #endif
395 }
396 
397 static void brel_after(char *buf, bufsize size)
398 {
399 	struct bhead *b = BH(buf - sizeof(struct bhead));
400 	struct bhead *bn;
401 	bufsize new_size = size;
402 	bufsize free_size;
403 
404 	/* Select the size in the same way as in bget() */
405 	if (new_size < SizeQ)
406 		new_size = SizeQ;
407 #ifdef SizeQuant
408 #if SizeQuant > 1
409 	new_size = (new_size + (SizeQuant - 1)) & (~(SizeQuant - 1));
410 #endif
411 #endif
412 	new_size += sizeof(struct bhead);
413 	assert(new_size <= -b->bsize);
414 
415 	/*
416 	 * Check if there's enough space at the end of the buffer to be
417 	 * able to free anything.
418 	 */
419 	free_size = -b->bsize - new_size;
420 	if (free_size < SizeQ + sizeof(struct bhead))
421 		return;
422 
423 	bn = BH((char *)b - b->bsize);
424 	/*
425 	 * Set the new size of the buffer;
426 	 */
427 	b->bsize = -new_size;
428 	if (bn->bsize > 0) {
429 		/* Next buffer is free, consolidate with that buffer */
430 		struct bfhead *bfn = BFH(bn);
431 		struct bfhead *nbf = BFH((char *)b + new_size);
432 		struct bhead *bnn = BH((char *)bn + bn->bsize);
433 
434 		assert(bfn->bh.prevfree == 0);
435 		assert(bnn->prevfree == bfn->bh.bsize);
436 
437 		/* Construct the new free header */
438 		nbf->bh.prevfree = 0;
439 		nbf->bh.bsize = bfn->bh.bsize + free_size;
440 
441 		/* Update the buffer after this to point to this header */
442 		bnn->prevfree += free_size;
443 
444 		/*
445 		 * Unlink the previous free buffer and link the new free
446 		 * buffer.
447 		 */
448 		assert(bfn->ql.blink->ql.flink == bfn);
449 		assert(bfn->ql.flink->ql.blink == bfn);
450 
451 		/* Assing blink and flink from old free buffer */
452 		nbf->ql.blink = bfn->ql.blink;
453 		nbf->ql.flink = bfn->ql.flink;
454 
455 		/* Replace the old free buffer with the new one */
456 		nbf->ql.blink->ql.flink = nbf;
457 		nbf->ql.flink->ql.blink = nbf;
458 	} else {
459 		/* New buffer is allocated, create a new free buffer */
460 		create_free_block(BFH((char *)b + new_size), free_size, bn);
461 	}
462 
463 #ifdef BufStats
464 	totalloc -= free_size;
465 	assert(totalloc >= 0);
466 #endif
467 
468 }
469 
470 static void *raw_memalign(size_t hdr_size, size_t ftr_size, size_t alignment,
471 		size_t size)
472 {
473 	size_t s;
474 	uintptr_t b;
475 
476 	raw_malloc_validate_pools();
477 
478 	if (!IS_POWER_OF_TWO(alignment))
479 		return NULL;
480 
481 	/*
482 	 * Normal malloc with headers always returns something SizeQuant
483 	 * aligned.
484 	 */
485 	if (alignment <= SizeQuant)
486 		return raw_malloc(hdr_size, ftr_size, size);
487 
488 	s = hdr_size + ftr_size + alignment + size +
489 	    SizeQ + sizeof(struct bhead);
490 
491 	/* Check wapping */
492 	if (s < alignment || s < size)
493 		return NULL;
494 
495 	b = (uintptr_t)bget(s);
496 	if (!b)
497 		return NULL;
498 
499 	if ((b + hdr_size) & (alignment - 1)) {
500 		/*
501 		 * Returned buffer is not aligned as requested if the
502 		 * hdr_size is added. Find an offset into the buffer
503 		 * that is far enough in to the buffer to be able to free
504 		 * what's in front.
505 		 */
506 		uintptr_t p;
507 
508 		/*
509 		 * Find the point where the buffer including supplied
510 		 * header size should start.
511 		 */
512 		p = b + hdr_size + alignment;
513 		p &= ~(alignment - 1);
514 		p -= hdr_size;
515 		if ((p - b) < (SizeQ + sizeof(struct bhead)))
516 			p += alignment;
517 		assert((p + hdr_size + ftr_size + size) <= (b + s));
518 
519 		/* Free the front part of the buffer */
520 		brel_before((void *)b, (void *)p);
521 
522 		/* Set the new start of the buffer */
523 		b = p;
524 	}
525 
526 	/*
527 	 * Since b is now aligned, release what we don't need at the end of
528 	 * the buffer.
529 	 */
530 	brel_after((void *)b, hdr_size + ftr_size + size);
531 
532 	raw_malloc_save_max_alloced_size();
533 
534 	return (void *)b;
535 }
536 
537 /* Most of the stuff in this function is copied from bgetr() in bget.c */
538 static bufsize bget_buf_size(void *buf)
539 {
540 	bufsize osize;          /* Old size of buffer */
541 	struct bhead *b;
542 
543 	b = BH(((char *)buf) - sizeof(struct bhead));
544 	osize = -b->bsize;
545 #ifdef BECtl
546 	if (osize == 0) {
547 		/*  Buffer acquired directly through acqfcn. */
548 		struct bdhead *bd;
549 
550 		bd = BDH(((char *)buf) - sizeof(struct bdhead));
551 		osize = bd->tsize - sizeof(struct bdhead);
552 	} else
553 #endif
554 		osize -= sizeof(struct bhead);
555 	assert(osize > 0);
556 	return osize;
557 }
558 
559 #ifdef ENABLE_MDBG
560 
561 struct mdbg_hdr {
562 	const char *fname;
563 	uint16_t line;
564 	bool ignore;
565 	uint32_t pl_size;
566 	uint32_t magic;
567 };
568 
569 #define MDBG_HEADER_MAGIC	0xadadadad
570 #define MDBG_FOOTER_MAGIC	0xecececec
571 
572 /* TODO make this a per thread variable */
573 static enum mdbg_mode mdbg_mode = MDBG_MODE_DYNAMIC;
574 
575 static size_t mdbg_get_ftr_size(size_t pl_size)
576 {
577 	size_t ftr_pad = ROUNDUP(pl_size, sizeof(uint32_t)) - pl_size;
578 
579 	return ftr_pad + sizeof(uint32_t);
580 }
581 
582 
583 static uint32_t *mdbg_get_footer(struct mdbg_hdr *hdr)
584 {
585 	uint32_t *footer;
586 
587 	footer = (uint32_t *)((uint8_t *)(hdr + 1) + hdr->pl_size +
588 			      mdbg_get_ftr_size(hdr->pl_size));
589 	footer--;
590 	return footer;
591 }
592 
593 static void mdbg_update_hdr(struct mdbg_hdr *hdr, const char *fname,
594 		int lineno, size_t pl_size)
595 {
596 	uint32_t *footer;
597 
598 	hdr->fname = fname;
599 	hdr->line = lineno;
600 	hdr->pl_size = pl_size;
601 	hdr->magic = MDBG_HEADER_MAGIC;
602 	hdr->ignore = mdbg_mode == MDBG_MODE_STATIC;
603 
604 	footer = mdbg_get_footer(hdr);
605 	*footer = MDBG_FOOTER_MAGIC;
606 }
607 
608 void *mdbg_malloc(const char *fname, int lineno, size_t size)
609 {
610 	struct mdbg_hdr *hdr;
611 
612 	COMPILE_TIME_ASSERT(sizeof(struct mdbg_hdr) == sizeof(uint32_t) * 4);
613 
614 	hdr = raw_malloc(sizeof(struct mdbg_hdr),
615 			  mdbg_get_ftr_size(size), size);
616 	if (hdr) {
617 		mdbg_update_hdr(hdr, fname, lineno, size);
618 		hdr++;
619 	}
620 	return hdr;
621 }
622 
623 static void assert_header(struct mdbg_hdr *hdr)
624 {
625 	assert(hdr->magic == MDBG_HEADER_MAGIC);
626 	assert(*mdbg_get_footer(hdr) == MDBG_FOOTER_MAGIC);
627 }
628 
629 void mdbg_free(void *ptr)
630 {
631 	struct mdbg_hdr *hdr = ptr;
632 
633 	if (hdr) {
634 		hdr--;
635 		assert_header(hdr);
636 		hdr->magic = 0;
637 		*mdbg_get_footer(hdr) = 0;
638 		raw_free(hdr);
639 	}
640 }
641 
642 void *mdbg_calloc(const char *fname, int lineno, size_t nmemb, size_t size)
643 {
644 	struct mdbg_hdr *hdr;
645 
646 	hdr = raw_calloc(sizeof(struct mdbg_hdr),
647 			  mdbg_get_ftr_size(nmemb * size), nmemb, size);
648 	if (hdr) {
649 		mdbg_update_hdr(hdr, fname, lineno, nmemb * size);
650 		hdr++;
651 	}
652 	return hdr;
653 }
654 
655 void *mdbg_realloc(const char *fname, int lineno, void *ptr, size_t size)
656 {
657 	struct mdbg_hdr *hdr = ptr;
658 
659 	if (hdr) {
660 		hdr--;
661 		assert_header(hdr);
662 	}
663 	hdr = raw_realloc(hdr, sizeof(struct mdbg_hdr),
664 			   mdbg_get_ftr_size(size), size);
665 	if (hdr) {
666 		mdbg_update_hdr(hdr, fname, lineno, size);
667 		hdr++;
668 	}
669 	return hdr;
670 }
671 
672 void *mdbg_memalign(const char *fname, int lineno, size_t alignment,
673 		size_t size)
674 {
675 	struct mdbg_hdr *hdr;
676 
677 	hdr = raw_memalign(sizeof(struct mdbg_hdr), mdbg_get_ftr_size(size),
678 			   alignment, size);
679 	if (hdr) {
680 		mdbg_update_hdr(hdr, fname, lineno, size);
681 		hdr++;
682 	}
683 	return hdr;
684 }
685 
686 
687 static void *get_payload_start_size(void *raw_buf, size_t *size)
688 {
689 	struct mdbg_hdr *hdr = raw_buf;
690 
691 	assert(bget_buf_size(hdr) >= hdr->pl_size);
692 	*size = hdr->pl_size;
693 	return hdr + 1;
694 }
695 
696 void mdbg_check(int bufdump)
697 {
698 	struct bpool_iterator itr;
699 	void *b;
700 
701 	raw_malloc_validate_pools();
702 
703 	BPOOL_FOREACH(&itr, &b) {
704 		struct mdbg_hdr *hdr = (struct mdbg_hdr *)b;
705 
706 		assert_header(hdr);
707 
708 		if (bufdump > 0 || !hdr->ignore) {
709 			const char *fname = hdr->fname;
710 
711 			if (!fname)
712 				fname = "unknown";
713 
714 			DMSG("%s buffer: %d bytes %s:%d\n",
715 				hdr->ignore ? "Ignore" : "Orphaned",
716 				hdr->pl_size, fname, hdr->line);
717 		}
718 	}
719 
720 }
721 
722 enum mdbg_mode mdbg_set_mode(enum mdbg_mode mode)
723 {
724 	enum mdbg_mode old_mode = mdbg_mode;
725 
726 	mdbg_mode = mode;
727 	return old_mode;
728 }
729 
730 #else
731 
732 void *malloc(size_t size)
733 {
734 	return raw_malloc(0, 0, size);
735 }
736 
737 void free(void *ptr)
738 {
739 	raw_free(ptr);
740 }
741 
742 void *calloc(size_t nmemb, size_t size)
743 {
744 	return raw_calloc(0, 0, nmemb, size);
745 }
746 
747 void *realloc(void *ptr, size_t size)
748 {
749 	return raw_realloc(ptr, 0, 0, size);
750 }
751 
752 void *memalign(size_t alignment, size_t size)
753 {
754 	return raw_memalign(0, 0, alignment, size);
755 }
756 
757 static void *get_payload_start_size(void *ptr, size_t *size)
758 {
759 	*size = bget_buf_size(ptr);
760 	return ptr;
761 }
762 
763 #endif
764 
765 
766 
767 void malloc_init(void *buf, size_t len)
768 {
769 	/* Must not be called twice */
770 	assert(!malloc_pool);
771 
772 	malloc_add_pool(buf, len);
773 }
774 
775 void malloc_add_pool(void *buf, size_t len)
776 {
777 	void *p;
778 	size_t l;
779 	uintptr_t start = (uintptr_t)buf;
780 	uintptr_t end = start + len;
781 	enum mdbg_mode old_mode = mdbg_set_mode(MDBG_MODE_STATIC);
782 
783 	start = ROUNDUP(start, SizeQuant);
784 	end = ROUNDDOWN(end, SizeQuant);
785 	assert(start < end);
786 
787 	bpool((void *)start, end - start);
788 
789 	l = malloc_pool_len + 1;
790 	p = realloc(malloc_pool, sizeof(struct malloc_pool) * l);
791 	assert(p);
792 	malloc_pool = p;
793 	malloc_pool[malloc_pool_len].buf = (void *)start;
794 	malloc_pool[malloc_pool_len].len = end - start;
795 	malloc_pool_len = l;
796 	mdbg_set_mode(old_mode);
797 }
798 
799 bool malloc_buffer_is_within_alloced(void *buf, size_t len)
800 {
801 	struct bpool_iterator itr;
802 	void *b;
803 	uint8_t *start_buf = buf;
804 	uint8_t *end_buf = start_buf + len;
805 
806 	raw_malloc_validate_pools();
807 
808 	/* Check for wrapping */
809 	if (start_buf > end_buf)
810 		return false;
811 
812 	BPOOL_FOREACH(&itr, &b) {
813 		uint8_t *start_b;
814 		uint8_t *end_b;
815 		size_t s;
816 
817 		start_b = get_payload_start_size(b, &s);
818 		end_b = start_b + s;
819 
820 		if (start_buf >= start_b && end_buf <= end_b)
821 			return true;
822 	}
823 	return false;
824 }
825 
826 bool malloc_buffer_overlaps_heap(void *buf, size_t len)
827 {
828 	uintptr_t buf_start = (uintptr_t) buf;
829 	uintptr_t buf_end = buf_start + len;
830 	size_t n;
831 
832 	raw_malloc_validate_pools();
833 
834 	for (n = 0; n < malloc_pool_len; n++) {
835 		uintptr_t pool_start = (uintptr_t)malloc_pool[n].buf;
836 		uintptr_t pool_end = pool_start + malloc_pool[n].len;
837 
838 		if (buf_start > buf_end || pool_start > pool_end)
839 			return true;	/* Wrapping buffers, shouldn't happen */
840 
841 		if (buf_end > pool_start || buf_start < pool_end)
842 			return true;
843 	}
844 
845 	return false;
846 }
847