100 lines
2.1 KiB
C
100 lines
2.1 KiB
C
// SPDX-License-Identifier: Apache-2.0 OR GPL-2.0-or-later
|
|
/*
|
|
* Implement malloc()/free() etc on top of our memory region allocator,
|
|
* which provides mem_alloc()/mem_free().
|
|
*
|
|
* Copyright 2013-2015 IBM Corp.
|
|
*/
|
|
|
|
#include <mem_region.h>
|
|
#include <lock.h>
|
|
#include <skiboot.h>
|
|
#include <stack.h>
|
|
#include <string.h>
|
|
#include <mem_region-malloc.h>
|
|
|
|
#define DEFAULT_ALIGN __alignof__(long)
|
|
|
|
void *__memalign(size_t blocksize, size_t bytes, const char *location)
|
|
{
|
|
void *p;
|
|
|
|
lock(&skiboot_heap.free_list_lock);
|
|
p = mem_alloc(&skiboot_heap, bytes, blocksize, location);
|
|
unlock(&skiboot_heap.free_list_lock);
|
|
|
|
return p;
|
|
}
|
|
|
|
void *__malloc(size_t bytes, const char *location)
|
|
{
|
|
return __memalign(DEFAULT_ALIGN, bytes, location);
|
|
}
|
|
|
|
static bool check_heap_ptr(const void *p)
|
|
{
|
|
struct mem_region *region = &skiboot_heap;
|
|
unsigned long ptr = (unsigned long)p;
|
|
|
|
if (!ptr)
|
|
return true;
|
|
|
|
if (ptr < region->start || ptr > region->start + region->len) {
|
|
prerror("Trying to free() a pointer outside heap. Possibly local_alloc().\n");
|
|
backtrace();
|
|
return false;
|
|
}
|
|
return true;
|
|
}
|
|
|
|
void __free(void *p, const char *location)
|
|
{
|
|
if (!check_heap_ptr(p))
|
|
return;
|
|
|
|
lock(&skiboot_heap.free_list_lock);
|
|
mem_free(&skiboot_heap, p, location);
|
|
unlock(&skiboot_heap.free_list_lock);
|
|
}
|
|
|
|
void *__realloc(void *ptr, size_t size, const char *location)
|
|
{
|
|
void *newptr;
|
|
|
|
if (!check_heap_ptr(ptr))
|
|
return NULL;
|
|
|
|
/* Two classic malloc corner cases. */
|
|
if (!size) {
|
|
__free(ptr, location);
|
|
return NULL;
|
|
}
|
|
if (!ptr)
|
|
return __malloc(size, location);
|
|
|
|
lock(&skiboot_heap.free_list_lock);
|
|
if (mem_resize(&skiboot_heap, ptr, size, location)) {
|
|
newptr = ptr;
|
|
} else {
|
|
newptr = mem_alloc(&skiboot_heap, size, DEFAULT_ALIGN,
|
|
location);
|
|
if (newptr) {
|
|
size_t copy = mem_allocated_size(ptr);
|
|
if (copy > size)
|
|
copy = size;
|
|
memcpy(newptr, ptr, copy);
|
|
mem_free(&skiboot_heap, ptr, location);
|
|
}
|
|
}
|
|
unlock(&skiboot_heap.free_list_lock);
|
|
return newptr;
|
|
}
|
|
|
|
void *__zalloc(size_t bytes, const char *location)
|
|
{
|
|
void *p = __malloc(bytes, location);
|
|
|
|
if (p)
|
|
memset(p, 0, bytes);
|
|
return p;
|
|
}
|