xref: /optee_os/lib/libutils/isoc/bget_malloc.c (revision 3d3b05918ec9052ba13de82fbcaba204766eb636)
1 // SPDX-License-Identifier: BSD-2-Clause
2 /*
3  * Copyright (c) 2014, STMicroelectronics International N.V.
4  */
5 
6 #define PROTOTYPES
7 
8 /*
9  *  BGET CONFIGURATION
10  *  ==================
11  */
12 /* #define BGET_ENABLE_ALL_OPTIONS */
13 #ifdef BGET_ENABLE_OPTION
14 #define TestProg    20000	/* Generate built-in test program
15 				   if defined.  The value specifies
16 				   how many buffer allocation attempts
17 				   the test program should make. */
18 #endif
19 
20 
21 #ifdef __LP64__
22 #define SizeQuant   16
23 #endif
24 #ifdef __ILP32__
25 #define SizeQuant   8
26 #endif
27 				/* Buffer allocation size quantum:
28 				   all buffers allocated are a
29 				   multiple of this size.  This
30 				   MUST be a power of two. */
31 
32 #ifdef BGET_ENABLE_OPTION
33 #define BufDump     1		/* Define this symbol to enable the
34 				   bpoold() function which dumps the
35 				   buffers in a buffer pool. */
36 
37 #define BufValid    1		/* Define this symbol to enable the
38 				   bpoolv() function for validating
39 				   a buffer pool. */
40 
41 #define DumpData    1		/* Define this symbol to enable the
42 				   bufdump() function which allows
43 				   dumping the contents of an allocated
44 				   or free buffer. */
45 
46 #define BufStats    1		/* Define this symbol to enable the
47 				   bstats() function which calculates
48 				   the total free space in the buffer
49 				   pool, the largest available
50 				   buffer, and the total space
51 				   currently allocated. */
52 
53 #define FreeWipe    1		/* Wipe free buffers to a guaranteed
54 				   pattern of garbage to trip up
55 				   miscreants who attempt to use
56 				   pointers into released buffers. */
57 
58 #define BestFit     1		/* Use a best fit algorithm when
59 				   searching for space for an
60 				   allocation request.  This uses
61 				   memory more efficiently, but
62 				   allocation will be much slower. */
63 
64 #define BECtl       1		/* Define this symbol to enable the
65 				   bectl() function for automatic
66 				   pool space control.  */
67 #endif
68 
69 #ifdef MEM_DEBUG
70 #undef NDEBUG
71 #define DumpData    1
72 #define BufValid    1
73 #define FreeWipe    1
74 #endif
75 
76 #ifdef CFG_WITH_STATS
77 #define BufStats    1
78 #endif
79 
80 #include <compiler.h>
81 #include <malloc.h>
82 #include <stdbool.h>
83 #include <stdint.h>
84 #include <stdlib.h>
85 #include <string.h>
86 #include <trace.h>
87 #include <util.h>
88 
89 #if defined(__KERNEL__)
90 /* Compiling for TEE Core */
91 #include <kernel/asan.h>
92 #include <kernel/thread.h>
93 #include <kernel/spinlock.h>
94 
95 static void tag_asan_free(void *buf, size_t len)
96 {
97 	asan_tag_heap_free(buf, (uint8_t *)buf + len);
98 }
99 
100 static void tag_asan_alloced(void *buf, size_t len)
101 {
102 	asan_tag_access(buf, (uint8_t *)buf + len);
103 }
104 
105 static void *memset_unchecked(void *s, int c, size_t n)
106 {
107 	return asan_memset_unchecked(s, c, n);
108 }
109 
110 #else /*__KERNEL__*/
111 /* Compiling for TA */
112 
113 static void tag_asan_free(void *buf __unused, size_t len __unused)
114 {
115 }
116 
117 static void tag_asan_alloced(void *buf __unused, size_t len __unused)
118 {
119 }
120 
121 static void *memset_unchecked(void *s, int c, size_t n)
122 {
123 	return memset(s, c, n);
124 }
125 
126 #endif /*__KERNEL__*/
127 
128 #include "bget.c"		/* this is ugly, but this is bget */
129 
130 struct malloc_pool {
131 	void *buf;
132 	size_t len;
133 };
134 
135 struct malloc_ctx {
136 	struct bpoolset poolset;
137 	struct malloc_pool *pool;
138 	size_t pool_len;
139 #ifdef BufStats
140 	struct malloc_stats mstats;
141 #endif
142 #ifdef __KERNEL__
143 	unsigned int spinlock;
144 #endif
145 };
146 
147 #ifdef __KERNEL__
148 
149 static uint32_t malloc_lock(struct malloc_ctx *ctx)
150 {
151 	return cpu_spin_lock_xsave(&ctx->spinlock);
152 }
153 
154 static void malloc_unlock(struct malloc_ctx *ctx, uint32_t exceptions)
155 {
156 	cpu_spin_unlock_xrestore(&ctx->spinlock, exceptions);
157 }
158 
159 #else  /* __KERNEL__ */
160 
161 static uint32_t malloc_lock(struct malloc_ctx *ctx __unused)
162 {
163 	return 0;
164 }
165 
166 static void malloc_unlock(struct malloc_ctx *ctx __unused,
167 			  uint32_t exceptions __unused)
168 {
169 }
170 
171 #endif	/* __KERNEL__ */
172 
173 #define DEFINE_CTX(name) struct malloc_ctx name =		\
174 	{ .poolset = { .freelist = { {0, 0},			\
175 			{&name.poolset.freelist,		\
176 			 &name.poolset.freelist}}}}
177 
178 static DEFINE_CTX(malloc_ctx);
179 
180 #ifdef CFG_VIRTUALIZATION
181 static __nex_data DEFINE_CTX(nex_malloc_ctx);
182 #endif
183 
184 #ifdef BufStats
185 
186 static void raw_malloc_return_hook(void *p, size_t requested_size,
187 				   struct malloc_ctx *ctx)
188 {
189 	if (ctx->poolset.totalloc > ctx->mstats.max_allocated)
190 		ctx->mstats.max_allocated = ctx->poolset.totalloc;
191 
192 	if (!p) {
193 		ctx->mstats.num_alloc_fail++;
194 		if (requested_size > ctx->mstats.biggest_alloc_fail) {
195 			ctx->mstats.biggest_alloc_fail = requested_size;
196 			ctx->mstats.biggest_alloc_fail_used =
197 				ctx->poolset.totalloc;
198 		}
199 	}
200 }
201 
202 static void gen_malloc_reset_stats(struct malloc_ctx *ctx)
203 {
204 	uint32_t exceptions = malloc_lock(ctx);
205 
206 	ctx->mstats.max_allocated = 0;
207 	ctx->mstats.num_alloc_fail = 0;
208 	ctx->mstats.biggest_alloc_fail = 0;
209 	ctx->mstats.biggest_alloc_fail_used = 0;
210 	malloc_unlock(ctx, exceptions);
211 }
212 
213 void malloc_reset_stats(void)
214 {
215 	gen_malloc_reset_stats(&malloc_ctx);
216 }
217 
218 static void gen_malloc_get_stats(struct malloc_ctx *ctx,
219 				 struct malloc_stats *stats)
220 {
221 	uint32_t exceptions = malloc_lock(ctx);
222 
223 	memcpy(stats, &ctx->mstats, sizeof(*stats));
224 	stats->allocated = ctx->poolset.totalloc;
225 	malloc_unlock(ctx, exceptions);
226 }
227 
228 void malloc_get_stats(struct malloc_stats *stats)
229 {
230 	gen_malloc_get_stats(&malloc_ctx, stats);
231 }
232 
233 #else /* BufStats */
234 
235 static void raw_malloc_return_hook(void *p __unused,
236 				   size_t requested_size __unused,
237 				   struct malloc_ctx *ctx __unused)
238 {
239 }
240 
241 #endif /* BufStats */
242 
243 #ifdef BufValid
244 static void raw_malloc_validate_pools(struct malloc_ctx *ctx)
245 {
246 	size_t n;
247 
248 	for (n = 0; n < ctx->pool_len; n++)
249 		bpoolv(ctx->pool[n].buf);
250 }
251 #else
252 static void raw_malloc_validate_pools(struct malloc_ctx *ctx __unused)
253 {
254 }
255 #endif
256 
257 struct bpool_iterator {
258 	struct bfhead *next_buf;
259 	size_t pool_idx;
260 };
261 
262 static void bpool_foreach_iterator_init(struct malloc_ctx *ctx,
263 					struct bpool_iterator *iterator)
264 {
265 	iterator->pool_idx = 0;
266 	iterator->next_buf = BFH(ctx->pool[0].buf);
267 }
268 
269 static bool bpool_foreach_pool(struct bpool_iterator *iterator, void **buf,
270 		size_t *len, bool *isfree)
271 {
272 	struct bfhead *b = iterator->next_buf;
273 	bufsize bs = b->bh.bsize;
274 
275 	if (bs == ESent)
276 		return false;
277 
278 	if (bs < 0) {
279 		/* Allocated buffer */
280 		bs = -bs;
281 
282 		*isfree = false;
283 	} else {
284 		/* Free Buffer */
285 		*isfree = true;
286 
287 		/* Assert that the free list links are intact */
288 		assert(b->ql.blink->ql.flink == b);
289 		assert(b->ql.flink->ql.blink == b);
290 	}
291 
292 	*buf = (uint8_t *)b + sizeof(struct bhead);
293 	*len = bs - sizeof(struct bhead);
294 
295 	iterator->next_buf = BFH((uint8_t *)b + bs);
296 	return true;
297 }
298 
299 static bool bpool_foreach(struct malloc_ctx *ctx,
300 			  struct bpool_iterator *iterator, void **buf)
301 {
302 	while (true) {
303 		size_t len;
304 		bool isfree;
305 
306 		if (bpool_foreach_pool(iterator, buf, &len, &isfree)) {
307 			if (isfree)
308 				continue;
309 			return true;
310 		}
311 
312 		if ((iterator->pool_idx + 1) >= ctx->pool_len)
313 			return false;
314 
315 		iterator->pool_idx++;
316 		iterator->next_buf = BFH(ctx->pool[iterator->pool_idx].buf);
317 	}
318 }
319 
320 /* Convenience macro for looping over all allocated buffers */
321 #define BPOOL_FOREACH(ctx, iterator, bp)		      \
322 	for (bpool_foreach_iterator_init((ctx),(iterator));   \
323 	     bpool_foreach((ctx),(iterator), (bp));)
324 
325 static void *raw_malloc(size_t hdr_size, size_t ftr_size, size_t pl_size,
326 			struct malloc_ctx *ctx)
327 {
328 	void *ptr = NULL;
329 	bufsize s;
330 
331 	/*
332 	 * Make sure that malloc has correct alignment of returned buffers.
333 	 * The assumption is that uintptr_t will be as wide as the largest
334 	 * required alignment of any type.
335 	 */
336 	COMPILE_TIME_ASSERT(SizeQuant >= sizeof(uintptr_t));
337 
338 	raw_malloc_validate_pools(ctx);
339 
340 	/* Compute total size */
341 	if (ADD_OVERFLOW(pl_size, hdr_size, &s))
342 		goto out;
343 	if (ADD_OVERFLOW(s, ftr_size, &s))
344 		goto out;
345 
346 	/* BGET doesn't like 0 sized allocations */
347 	if (!s)
348 		s++;
349 
350 	ptr = bget(s, &ctx->poolset);
351 out:
352 	raw_malloc_return_hook(ptr, pl_size, ctx);
353 
354 	return ptr;
355 }
356 
357 static void raw_free(void *ptr, struct malloc_ctx *ctx)
358 {
359 	raw_malloc_validate_pools(ctx);
360 
361 	if (ptr)
362 		brel(ptr, &ctx->poolset);
363 }
364 
365 static void *raw_calloc(size_t hdr_size, size_t ftr_size, size_t pl_nmemb,
366 			size_t pl_size, struct malloc_ctx *ctx)
367 {
368 	void *ptr = NULL;
369 	bufsize s;
370 
371 	raw_malloc_validate_pools(ctx);
372 
373 	/* Compute total size */
374 	if (MUL_OVERFLOW(pl_nmemb, pl_size, &s))
375 		goto out;
376 	if (ADD_OVERFLOW(s, hdr_size, &s))
377 		goto out;
378 	if (ADD_OVERFLOW(s, ftr_size, &s))
379 		goto out;
380 
381 	/* BGET doesn't like 0 sized allocations */
382 	if (!s)
383 		s++;
384 
385 	ptr = bgetz(s, &ctx->poolset);
386 out:
387 	raw_malloc_return_hook(ptr, pl_nmemb * pl_size, ctx);
388 
389 	return ptr;
390 }
391 
392 static void *raw_realloc(void *ptr, size_t hdr_size, size_t ftr_size,
393 			 size_t pl_size, struct malloc_ctx *ctx)
394 {
395 	void *p = NULL;
396 	bufsize s;
397 
398 	/* Compute total size */
399 	if (ADD_OVERFLOW(pl_size, hdr_size, &s))
400 		goto out;
401 	if (ADD_OVERFLOW(s, ftr_size, &s))
402 		goto out;
403 
404 	raw_malloc_validate_pools(ctx);
405 
406 	/* BGET doesn't like 0 sized allocations */
407 	if (!s)
408 		s++;
409 
410 	p = bgetr(ptr, s, &ctx->poolset);
411 out:
412 	raw_malloc_return_hook(p, pl_size, ctx);
413 
414 	return p;
415 }
416 
417 /* Most of the stuff in this function is copied from bgetr() in bget.c */
418 static __maybe_unused bufsize bget_buf_size(void *buf)
419 {
420 	bufsize osize;          /* Old size of buffer */
421 	struct bhead *b;
422 
423 	b = BH(((char *)buf) - sizeof(struct bhead));
424 	osize = -b->bsize;
425 #ifdef BECtl
426 	if (osize == 0) {
427 		/*  Buffer acquired directly through acqfcn. */
428 		struct bdhead *bd;
429 
430 		bd = BDH(((char *)buf) - sizeof(struct bdhead));
431 		osize = bd->tsize - sizeof(struct bdhead);
432 	} else
433 #endif
434 		osize -= sizeof(struct bhead);
435 	assert(osize > 0);
436 	return osize;
437 }
438 
439 #ifdef ENABLE_MDBG
440 
441 struct mdbg_hdr {
442 	const char *fname;
443 	uint16_t line;
444 	uint32_t pl_size;
445 	uint32_t magic;
446 #if defined(ARM64)
447 	uint64_t pad;
448 #endif
449 };
450 
451 #define MDBG_HEADER_MAGIC	0xadadadad
452 #define MDBG_FOOTER_MAGIC	0xecececec
453 
454 static size_t mdbg_get_ftr_size(size_t pl_size)
455 {
456 	size_t ftr_pad = ROUNDUP(pl_size, sizeof(uint32_t)) - pl_size;
457 
458 	return ftr_pad + sizeof(uint32_t);
459 }
460 
461 static uint32_t *mdbg_get_footer(struct mdbg_hdr *hdr)
462 {
463 	uint32_t *footer;
464 
465 	footer = (uint32_t *)((uint8_t *)(hdr + 1) + hdr->pl_size +
466 			      mdbg_get_ftr_size(hdr->pl_size));
467 	footer--;
468 	return footer;
469 }
470 
471 static void mdbg_update_hdr(struct mdbg_hdr *hdr, const char *fname,
472 		int lineno, size_t pl_size)
473 {
474 	uint32_t *footer;
475 
476 	hdr->fname = fname;
477 	hdr->line = lineno;
478 	hdr->pl_size = pl_size;
479 	hdr->magic = MDBG_HEADER_MAGIC;
480 
481 	footer = mdbg_get_footer(hdr);
482 	*footer = MDBG_FOOTER_MAGIC;
483 }
484 
485 static void *gen_mdbg_malloc(struct malloc_ctx *ctx, const char *fname,
486 			     int lineno, size_t size)
487 {
488 	struct mdbg_hdr *hdr;
489 	uint32_t exceptions = malloc_lock(ctx);
490 
491 	/*
492 	 * Check struct mdbg_hdr doesn't get bad alignment.
493 	 * This is required by C standard: the buffer returned from
494 	 * malloc() should be aligned with a fundamental alignment.
495 	 * For ARM32, the required alignment is 8. For ARM64, it is 16.
496 	 */
497 	COMPILE_TIME_ASSERT(
498 		(sizeof(struct mdbg_hdr) % (__alignof(uintptr_t) * 2)) == 0);
499 
500 	hdr = raw_malloc(sizeof(struct mdbg_hdr),
501 			 mdbg_get_ftr_size(size), size, ctx);
502 	if (hdr) {
503 		mdbg_update_hdr(hdr, fname, lineno, size);
504 		hdr++;
505 	}
506 
507 	malloc_unlock(ctx, exceptions);
508 	return hdr;
509 }
510 
511 static void assert_header(struct mdbg_hdr *hdr __maybe_unused)
512 {
513 	assert(hdr->magic == MDBG_HEADER_MAGIC);
514 	assert(*mdbg_get_footer(hdr) == MDBG_FOOTER_MAGIC);
515 }
516 
517 static void gen_mdbg_free(struct malloc_ctx *ctx, void *ptr)
518 {
519 	struct mdbg_hdr *hdr = ptr;
520 
521 	if (hdr) {
522 		hdr--;
523 		assert_header(hdr);
524 		hdr->magic = 0;
525 		*mdbg_get_footer(hdr) = 0;
526 		raw_free(hdr, ctx);
527 	}
528 }
529 
530 void free(void *ptr)
531 {
532 	uint32_t exceptions = malloc_lock(&malloc_ctx);
533 
534 	gen_mdbg_free(&malloc_ctx, ptr);
535 	malloc_unlock(&malloc_ctx, exceptions);
536 }
537 
538 static void *gen_mdbg_calloc(struct malloc_ctx *ctx, const char *fname, int lineno,
539 		      size_t nmemb, size_t size)
540 {
541 	struct mdbg_hdr *hdr;
542 	uint32_t exceptions = malloc_lock(ctx);
543 
544 	hdr = raw_calloc(sizeof(struct mdbg_hdr),
545 			  mdbg_get_ftr_size(nmemb * size), nmemb, size,
546 			  ctx);
547 	if (hdr) {
548 		mdbg_update_hdr(hdr, fname, lineno, nmemb * size);
549 		hdr++;
550 	}
551 	malloc_unlock(ctx, exceptions);
552 	return hdr;
553 }
554 
555 static void *gen_mdbg_realloc_unlocked(struct malloc_ctx *ctx, const char *fname,
556 				       int lineno, void *ptr, size_t size)
557 {
558 	struct mdbg_hdr *hdr = ptr;
559 
560 	if (hdr) {
561 		hdr--;
562 		assert_header(hdr);
563 	}
564 	hdr = raw_realloc(hdr, sizeof(struct mdbg_hdr),
565 			   mdbg_get_ftr_size(size), size, ctx);
566 	if (hdr) {
567 		mdbg_update_hdr(hdr, fname, lineno, size);
568 		hdr++;
569 	}
570 	return hdr;
571 }
572 
573 static void *gen_mdbg_realloc(struct malloc_ctx *ctx, const char *fname,
574 			      int lineno, void *ptr, size_t size)
575 {
576 	void *p;
577 	uint32_t exceptions = malloc_lock(ctx);
578 
579 	p = gen_mdbg_realloc_unlocked(ctx, fname, lineno, ptr, size);
580 	malloc_unlock(ctx, exceptions);
581 	return p;
582 }
583 
584 #define realloc_unlocked(ctx, ptr, size)					\
585 		gen_mdbg_realloc_unlocked(ctx, __FILE__, __LINE__, (ptr), (size))
586 
587 static void *get_payload_start_size(void *raw_buf, size_t *size)
588 {
589 	struct mdbg_hdr *hdr = raw_buf;
590 
591 	assert(bget_buf_size(hdr) >= hdr->pl_size);
592 	*size = hdr->pl_size;
593 	return hdr + 1;
594 }
595 
596 static void gen_mdbg_check(struct malloc_ctx *ctx, int bufdump)
597 {
598 	struct bpool_iterator itr;
599 	void *b;
600 	uint32_t exceptions = malloc_lock(ctx);
601 
602 	raw_malloc_validate_pools(ctx);
603 
604 	BPOOL_FOREACH(ctx, &itr, &b) {
605 		struct mdbg_hdr *hdr = (struct mdbg_hdr *)b;
606 
607 		assert_header(hdr);
608 
609 		if (bufdump > 0) {
610 			const char *fname = hdr->fname;
611 
612 			if (!fname)
613 				fname = "unknown";
614 
615 			IMSG("buffer: %d bytes %s:%d\n",
616 				hdr->pl_size, fname, hdr->line);
617 		}
618 	}
619 
620 	malloc_unlock(ctx, exceptions);
621 }
622 
623 void *mdbg_malloc(const char *fname, int lineno, size_t size)
624 {
625 	return gen_mdbg_malloc(&malloc_ctx, fname, lineno, size);
626 }
627 
628 void *mdbg_calloc(const char *fname, int lineno, size_t nmemb, size_t size)
629 {
630 	return gen_mdbg_calloc(&malloc_ctx, fname, lineno, nmemb, size);
631 }
632 
633 void *mdbg_realloc(const char *fname, int lineno, void *ptr, size_t size)
634 {
635 	return gen_mdbg_realloc(&malloc_ctx, fname, lineno, ptr, size);
636 }
637 
638 void mdbg_check(int bufdump)
639 {
640 	gen_mdbg_check(&malloc_ctx, bufdump);
641 }
642 #else
643 
644 void *malloc(size_t size)
645 {
646 	void *p;
647 	uint32_t exceptions = malloc_lock(&malloc_ctx);
648 
649 	p = raw_malloc(0, 0, size, &malloc_ctx);
650 	malloc_unlock(&malloc_ctx, exceptions);
651 	return p;
652 }
653 
654 void free(void *ptr)
655 {
656 	uint32_t exceptions = malloc_lock(&malloc_ctx);
657 
658 	raw_free(ptr, &malloc_ctx);
659 	malloc_unlock(&malloc_ctx, exceptions);
660 }
661 
662 void *calloc(size_t nmemb, size_t size)
663 {
664 	void *p;
665 	uint32_t exceptions = malloc_lock(&malloc_ctx);
666 
667 	p = raw_calloc(0, 0, nmemb, size, &malloc_ctx);
668 	malloc_unlock(&malloc_ctx, exceptions);
669 	return p;
670 }
671 
672 static void *realloc_unlocked(struct malloc_ctx *ctx, void *ptr,
673 			      size_t size)
674 {
675 	return raw_realloc(ptr, 0, 0, size, ctx);
676 }
677 
678 void *realloc(void *ptr, size_t size)
679 {
680 	void *p;
681 	uint32_t exceptions = malloc_lock(&malloc_ctx);
682 
683 	p = realloc_unlocked(&malloc_ctx, ptr, size);
684 	malloc_unlock(&malloc_ctx, exceptions);
685 	return p;
686 }
687 
688 static void *get_payload_start_size(void *ptr, size_t *size)
689 {
690 	*size = bget_buf_size(ptr);
691 	return ptr;
692 }
693 
694 #endif
695 
696 static void gen_malloc_add_pool(struct malloc_ctx *ctx, void *buf, size_t len)
697 {
698 	void *p;
699 	size_t l;
700 	uint32_t exceptions;
701 	uintptr_t start = (uintptr_t)buf;
702 	uintptr_t end = start + len;
703 	const size_t min_len = ((sizeof(struct malloc_pool) + (SizeQuant - 1)) &
704 					(~(SizeQuant - 1))) +
705 				sizeof(struct bhead) * 2;
706 
707 
708 	start = ROUNDUP(start, SizeQuant);
709 	end = ROUNDDOWN(end, SizeQuant);
710 	assert(start < end);
711 
712 	if ((end - start) < min_len) {
713 		DMSG("Skipping too small pool");
714 		return;
715 	}
716 
717 	exceptions = malloc_lock(ctx);
718 
719 	tag_asan_free((void *)start, end - start);
720 	bpool((void *)start, end - start, &ctx->poolset);
721 	l = ctx->pool_len + 1;
722 	p = realloc_unlocked(ctx, ctx->pool, sizeof(struct malloc_pool) * l);
723 	assert(p);
724 	ctx->pool = p;
725 	ctx->pool[ctx->pool_len].buf = (void *)start;
726 	ctx->pool[ctx->pool_len].len = end - start;
727 #ifdef BufStats
728 	ctx->mstats.size += ctx->pool[ctx->pool_len].len;
729 #endif
730 	ctx->pool_len = l;
731 	malloc_unlock(ctx, exceptions);
732 }
733 
734 static bool gen_malloc_buffer_is_within_alloced(struct malloc_ctx *ctx,
735 						void *buf, size_t len)
736 {
737 	struct bpool_iterator itr;
738 	void *b;
739 	uint8_t *start_buf = buf;
740 	uint8_t *end_buf = start_buf + len;
741 	bool ret = false;
742 	uint32_t exceptions = malloc_lock(ctx);
743 
744 	raw_malloc_validate_pools(ctx);
745 
746 	/* Check for wrapping */
747 	if (start_buf > end_buf)
748 		goto out;
749 
750 	BPOOL_FOREACH(ctx, &itr, &b) {
751 		uint8_t *start_b;
752 		uint8_t *end_b;
753 		size_t s;
754 
755 		start_b = get_payload_start_size(b, &s);
756 		end_b = start_b + s;
757 
758 		if (start_buf >= start_b && end_buf <= end_b) {
759 			ret = true;
760 			goto out;
761 		}
762 	}
763 
764 out:
765 	malloc_unlock(ctx, exceptions);
766 
767 	return ret;
768 }
769 
770 static bool gen_malloc_buffer_overlaps_heap(struct malloc_ctx *ctx,
771 					    void *buf, size_t len)
772 {
773 	uintptr_t buf_start = (uintptr_t) buf;
774 	uintptr_t buf_end = buf_start + len;
775 	size_t n;
776 	bool ret = false;
777 	uint32_t exceptions = malloc_lock(ctx);
778 
779 	raw_malloc_validate_pools(ctx);
780 
781 	for (n = 0; n < ctx->pool_len; n++) {
782 		uintptr_t pool_start = (uintptr_t)ctx->pool[n].buf;
783 		uintptr_t pool_end = pool_start + ctx->pool[n].len;
784 
785 		if (buf_start > buf_end || pool_start > pool_end) {
786 			ret = true;	/* Wrapping buffers, shouldn't happen */
787 			goto out;
788 		}
789 
790 		if (buf_end > pool_start || buf_start < pool_end) {
791 			ret = true;
792 			goto out;
793 		}
794 	}
795 
796 out:
797 	malloc_unlock(ctx, exceptions);
798 	return ret;
799 }
800 
801 void malloc_add_pool(void *buf, size_t len)
802 {
803 	gen_malloc_add_pool(&malloc_ctx, buf, len);
804 }
805 
806 bool malloc_buffer_is_within_alloced(void *buf, size_t len)
807 {
808 	return gen_malloc_buffer_is_within_alloced(&malloc_ctx, buf, len);
809 }
810 
811 bool malloc_buffer_overlaps_heap(void *buf, size_t len)
812 {
813 	return gen_malloc_buffer_overlaps_heap(&malloc_ctx, buf, len);
814 }
815 
816 #ifdef CFG_VIRTUALIZATION
817 
818 #ifndef ENABLE_MDBG
819 
820 void *nex_malloc(size_t size)
821 {
822 	void *p;
823 	uint32_t exceptions = malloc_lock(&nex_malloc_ctx);
824 
825 	p = raw_malloc(0, 0, size, &nex_malloc_ctx);
826 	malloc_unlock(&nex_malloc_ctx, exceptions);
827 	return p;
828 }
829 
830 void *nex_calloc(size_t nmemb, size_t size)
831 {
832 	void *p;
833 	uint32_t exceptions = malloc_lock(&nex_malloc_ctx);
834 
835 	p = raw_calloc(0, 0, nmemb, size, &nex_malloc_ctx);
836 	malloc_unlock(&nex_malloc_ctx, exceptions);
837 	return p;
838 }
839 
840 void *nex_realloc(void *ptr, size_t size)
841 {
842 	void *p;
843 	uint32_t exceptions = malloc_lock(&nex_malloc_ctx);
844 
845 	p = realloc_unlocked(&nex_malloc_ctx, ptr, size);
846 	malloc_unlock(&nex_malloc_ctx, exceptions);
847 	return p;
848 }
849 
850 void nex_free(void *ptr)
851 {
852 	uint32_t exceptions = malloc_lock(&nex_malloc_ctx);
853 
854 	raw_free(ptr, &nex_malloc_ctx);
855 	malloc_unlock(&nex_malloc_ctx, exceptions);
856 }
857 
858 #else  /* ENABLE_MDBG */
859 
860 void *nex_mdbg_malloc(const char *fname, int lineno, size_t size)
861 {
862 	return gen_mdbg_malloc(&nex_malloc_ctx, fname, lineno, size);
863 }
864 
865 void *nex_mdbg_calloc(const char *fname, int lineno, size_t nmemb, size_t size)
866 {
867 	return gen_mdbg_calloc(&nex_malloc_ctx, fname, lineno, nmemb, size);
868 }
869 
870 void *nex_mdbg_realloc(const char *fname, int lineno, void *ptr, size_t size)
871 {
872 	return gen_mdbg_realloc(&nex_malloc_ctx, fname, lineno, ptr, size);
873 }
874 
875 void nex_mdbg_check(int bufdump)
876 {
877 	gen_mdbg_check(&nex_malloc_ctx, bufdump);
878 }
879 
880 void nex_free(void *ptr)
881 {
882 	uint32_t exceptions = malloc_lock(&nex_malloc_ctx);
883 
884 	gen_mdbg_free(&nex_malloc_ctx, ptr);
885 	malloc_unlock(&nex_malloc_ctx, exceptions);
886 }
887 
888 #endif	/* ENABLE_MDBG */
889 
890 void nex_malloc_add_pool(void *buf, size_t len)
891 {
892 	gen_malloc_add_pool(&nex_malloc_ctx, buf, len);
893 }
894 
895 bool nex_malloc_buffer_is_within_alloced(void *buf, size_t len)
896 {
897 	return gen_malloc_buffer_is_within_alloced(&nex_malloc_ctx, buf, len);
898 }
899 
900 bool nex_malloc_buffer_overlaps_heap(void *buf, size_t len)
901 {
902 	return gen_malloc_buffer_overlaps_heap(&nex_malloc_ctx, buf, len);
903 }
904 
905 #ifdef BufStats
906 
907 void nex_malloc_reset_stats(void)
908 {
909 	gen_malloc_reset_stats(&nex_malloc_ctx);
910 }
911 
912 void nex_malloc_get_stats(struct malloc_stats *stats)
913 {
914 	gen_malloc_get_stats(&nex_malloc_ctx, stats);
915 }
916 
917 #endif
918 
919 #endif
920