176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman/*
276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * malloc.c
376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman *
476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * Very simple linked-list based malloc()/free().
576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman */
676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman#include <syslinux/firmware.h>
876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman#include <stdio.h>
976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman#include <stdlib.h>
1076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman#include <errno.h>
1176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman#include <string.h>
1276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman#include <dprintf.h>
1376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman#include <minmax.h>
1476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
1576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman#include "malloc.h"
1676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman#include "thread.h"
1776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
1876d05dc695b06c4e987bb8078f78032441e1430cGreg HartmanDECLARE_INIT_SEMAPHORE(__malloc_semaphore, 1);
1976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
2076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmanstatic void *__malloc_from_block(struct free_arena_header *fp,
2176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman				 size_t size, malloc_tag_t tag)
2276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman{
2376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    size_t fsize;
2476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    struct free_arena_header *nfp, *na;
2576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    unsigned int heap = ARENA_HEAP_GET(fp->a.attrs);
2676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
2776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    fsize = ARENA_SIZE_GET(fp->a.attrs);
2876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
2976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    /* We need the 2* to account for the larger requirements of a free block */
3076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    if ( fsize >= size+2*sizeof(struct arena_header) ) {
3176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman        /* Bigger block than required -- split block */
3276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman        nfp = (struct free_arena_header *)((char *)fp + size);
3376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman        na = fp->a.next;
3476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
3576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman        ARENA_TYPE_SET(nfp->a.attrs, ARENA_TYPE_FREE);
3676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	ARENA_HEAP_SET(nfp->a.attrs, heap);
3776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman        ARENA_SIZE_SET(nfp->a.attrs, fsize-size);
3876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman        nfp->a.tag = MALLOC_FREE;
3976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman#ifdef DEBUG_MALLOC
4076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	nfp->a.magic = ARENA_MAGIC;
4176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman#endif
4276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman        ARENA_TYPE_SET(fp->a.attrs, ARENA_TYPE_USED);
4376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman        ARENA_SIZE_SET(fp->a.attrs, size);
4476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman        fp->a.tag = tag;
4576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
4676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman        /* Insert into all-block chain */
4776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman        nfp->a.prev = fp;
4876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman        nfp->a.next = na;
4976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman        na->a.prev = nfp;
5076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman        fp->a.next = nfp;
5176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
5276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman        /* Replace current block on free chain */
5376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman        nfp->next_free = fp->next_free;
5476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman        nfp->prev_free = fp->prev_free;
5576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman        fp->next_free->prev_free = nfp;
5676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman        fp->prev_free->next_free = nfp;
5776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    } else {
5876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman        /* Allocate the whole block */
5976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman        ARENA_TYPE_SET(fp->a.attrs, ARENA_TYPE_USED);
6076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman        fp->a.tag = tag;
6176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
6276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman        /* Remove from free chain */
6376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman        fp->next_free->prev_free = fp->prev_free;
6476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman        fp->prev_free->next_free = fp->next_free;
6576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    }
6676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
6776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    return (void *)(&fp->a + 1);
6876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman}
6976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
7076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmanvoid *bios_malloc(size_t size, enum heap heap, malloc_tag_t tag)
7176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman{
7276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    struct free_arena_header *fp;
7376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    struct free_arena_header *head = &__core_malloc_head[heap];
7476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    void *p = NULL;
7576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
7676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    if (size) {
7776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	/* Add the obligatory arena header, and round up */
7876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	size = (size + 2 * sizeof(struct arena_header) - 1) & ARENA_SIZE_MASK;
7976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
8076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	for ( fp = head->next_free ; fp != head ; fp = fp->next_free ) {
8176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	    if ( ARENA_SIZE_GET(fp->a.attrs) >= size ) {
8276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		/* Found fit -- allocate out of this block */
8376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		p = __malloc_from_block(fp, size, tag);
8476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		break;
8576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	    }
8676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman        }
8776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    }
8876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
8976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    return p;
9076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman}
9176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
9276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmanstatic void *_malloc(size_t size, enum heap heap, malloc_tag_t tag)
9376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman{
9476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    void *p;
9576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
9676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    dprintf("_malloc(%zu, %u, %u) @ %p = ",
9776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	size, heap, tag, __builtin_return_address(0));
9876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
9976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    sem_down(&__malloc_semaphore, 0);
10076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    p = firmware->mem->malloc(size, heap, tag);
10176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    sem_up(&__malloc_semaphore);
10276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
10376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    dprintf("%p\n", p);
10476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    return p;
10576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman}
10676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
10776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman__export void *malloc(size_t size)
10876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman{
10976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    return _malloc(size, HEAP_MAIN, MALLOC_CORE);
11076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman}
11176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
11276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman__export void *lmalloc(size_t size)
11376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman{
11476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    void *p;
11576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
11676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    p = _malloc(size, HEAP_LOWMEM, MALLOC_CORE);
11776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    if (!p)
11876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	errno = ENOMEM;
11976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    return p;
12076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman}
12176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
12276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmanvoid *pmapi_lmalloc(size_t size)
12376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman{
12476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    return _malloc(size, HEAP_LOWMEM, MALLOC_MODULE);
12576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman}
12676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
12776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmanvoid *bios_realloc(void *ptr, size_t size)
12876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman{
12976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    struct free_arena_header *ah, *nah;
13076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    struct free_arena_header *head;
13176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
13276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    void *newptr;
13376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    size_t newsize, oldsize, xsize;
13476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
13576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    if (!ptr)
13676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	return malloc(size);
13776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
13876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    if (size == 0) {
13976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	free(ptr);
14076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	return NULL;
14176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    }
14276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
14376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    ah = (struct free_arena_header *)
14476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	((struct arena_header *)ptr - 1);
14576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
14676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	head = &__core_malloc_head[ARENA_HEAP_GET(ah->a.attrs)];
14776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
14876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman#ifdef DEBUG_MALLOC
14976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    if (ah->a.magic != ARENA_MAGIC)
15076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	dprintf("failed realloc() magic check: %p\n", ptr);
15176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman#endif
15276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
15376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    /* Actual size of the old block */
15476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    //oldsize = ah->a.size;
15576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    oldsize = ARENA_SIZE_GET(ah->a.attrs);
15676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
15776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    /* Add the obligatory arena header, and round up */
15876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    newsize = (size + 2 * sizeof(struct arena_header) - 1) & ARENA_SIZE_MASK;
15976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
16076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    if (oldsize >= newsize && newsize >= (oldsize >> 2) &&
16176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	oldsize - newsize < 4096) {
16276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	/* This allocation is close enough already. */
16376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	return ptr;
16476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    } else {
16576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	xsize = oldsize;
16676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
16776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	nah = ah->a.next;
16876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	if ((char *)nah == (char *)ah + ARENA_SIZE_GET(ah->a.attrs) &&
16976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		ARENA_TYPE_GET(nah->a.attrs) == ARENA_TYPE_FREE &&
17076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		ARENA_SIZE_GET(nah->a.attrs) + oldsize >= newsize) {
17176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	    //nah->a.type == ARENA_TYPE_FREE &&
17276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	    //oldsize + nah->a.size >= newsize) {
17376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	    /* Merge in subsequent free block */
17476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	    ah->a.next = nah->a.next;
17576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	    ah->a.next->a.prev = ah;
17676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	    nah->next_free->prev_free = nah->prev_free;
17776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	    nah->prev_free->next_free = nah->next_free;
17876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	    ARENA_SIZE_SET(ah->a.attrs, ARENA_SIZE_GET(ah->a.attrs) +
17976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman			   ARENA_SIZE_GET(nah->a.attrs));
18076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	    xsize = ARENA_SIZE_GET(ah->a.attrs);
18176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	}
18276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
18376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	if (xsize >= newsize) {
18476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	    /* We can reallocate in place */
18576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	    if (xsize >= newsize + 2 * sizeof(struct arena_header)) {
18676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		/* Residual free block at end */
18776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		nah = (struct free_arena_header *)((char *)ah + newsize);
18876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		ARENA_TYPE_SET(nah->a.attrs, ARENA_TYPE_FREE);
18976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		ARENA_SIZE_SET(nah->a.attrs, xsize - newsize);
19076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		ARENA_SIZE_SET(ah->a.attrs, newsize);
19176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		ARENA_HEAP_SET(nah->a.attrs, ARENA_HEAP_GET(ah->a.attrs));
19276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
19376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman#ifdef DEBUG_MALLOC
19476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		nah->a.magic = ARENA_MAGIC;
19576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman#endif
19676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
19776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		//nah->a.type = ARENA_TYPE_FREE;
19876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		//nah->a.size = xsize - newsize;
19976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		//ah->a.size = newsize;
20076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
20176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		/* Insert into block list */
20276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		nah->a.next = ah->a.next;
20376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		ah->a.next = nah;
20476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		nah->a.next->a.prev = nah;
20576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		nah->a.prev = ah;
20676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
20776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		/* Insert into free list */
20876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		if (newsize > oldsize) {
20976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		    /* Hack: this free block is in the path of a memory object
21076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		       which has already been grown at least once.  As such, put
21176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		       it at the *end* of the freelist instead of the beginning;
21276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		       trying to save it for future realloc()s of the same block. */
21376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		    nah->prev_free = head->prev_free;
21476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		    nah->next_free = head;
21576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		    head->prev_free = nah;
21676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		    nah->prev_free->next_free = nah;
21776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		} else {
21876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		    nah->next_free = head->next_free;
21976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		    nah->prev_free = head;
22076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		    head->next_free = nah;
22176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		    nah->next_free->prev_free = nah;
22276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		}
22376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman   	    }
22476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	    /* otherwise, use up the whole block */
22576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	    return ptr;
22676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	} else {
22776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	    /* Last resort: need to allocate a new block and copy */
22876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	    oldsize -= sizeof(struct arena_header);
22976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	    newptr = malloc(size);
23076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	    if (newptr) {
23176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		memcpy(newptr, ptr, min(size, oldsize));
23276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		free(ptr);
23376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	    }
23476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	    return newptr;
23576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	}
23676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    }
23776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman}
23876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
23976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman__export void *realloc(void *ptr, size_t size)
24076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman{
24176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    return firmware->mem->realloc(ptr, size);
24276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman}
24376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
24476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman__export void *zalloc(size_t size)
24576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman{
24676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    void *ptr;
24776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
24876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    ptr = malloc(size);
24976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    if (ptr)
25076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	memset(ptr, 0, size);
25176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
25276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    return ptr;
25376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman}
254