// 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 #include #include #include #include #include #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; }