Track block size in lib/alloc.c and not in alloc_ops. alloc_ops->free gets the size from the malloc implementation. Signed-off-by: Paolo Bonzini <pbonzini@xxxxxxxxxx> --- arm/Makefile.common | 1 + lib/alloc.c | 66 +++++++++++++++++++++++++++++++++++++++++++++++++ lib/alloc.h | 33 ++++++------------------- lib/alloc_phys.c | 23 +++++++++-------- powerpc/Makefile.common | 1 + 5 files changed, 86 insertions(+), 38 deletions(-) create mode 100644 lib/alloc.c diff --git a/arm/Makefile.common b/arm/Makefile.common index 6979a24..e09c3e2 100644 --- a/arm/Makefile.common +++ b/arm/Makefile.common @@ -35,6 +35,7 @@ include $(SRCDIR)/scripts/asm-offsets.mak cflatobjs += lib/util.o cflatobjs += lib/alloc_phys.o +cflatobjs += lib/alloc.o cflatobjs += lib/devicetree.o cflatobjs += lib/pci.o cflatobjs += lib/pci-host-generic.o diff --git a/lib/alloc.c b/lib/alloc.c new file mode 100644 index 0000000..61cb292 --- /dev/null +++ b/lib/alloc.c @@ -0,0 +1,66 @@ +#include "alloc.h" + +void *malloc(size_t size) +{ + return memalign(sizeof(long), size); +} + +void *calloc(size_t nmemb, size_t size) +{ + void *ptr = malloc(nmemb * size); + if (ptr) + memset(ptr, 0, nmemb * size); + return ptr; +} + +#define METADATA_EXTRA (2 * sizeof(uintptr_t)) +#define OFS_SLACK (-2 * sizeof(uintptr_t)) +#define OFS_SIZE (-sizeof(uintptr_t)) + +static inline void *block_begin(void *mem) +{ + uintptr_t slack = *(uintptr_t *)(mem + OFS_SLACK); + return mem - slack; +} + +static inline uintptr_t block_size(void *mem) +{ + return *(uintptr_t *)(mem + OFS_SIZE); +} + +void free(void *ptr) +{ + if (!alloc_ops->free) + return; + + void *base = block_begin(ptr); + uintptr_t sz = block_size(ptr); + + alloc_ops->free(base, sz); +} + +void *memalign(size_t alignment, size_t size) +{ + void *p; + uintptr_t blkalign; + uintptr_t mem; + + assert(alloc_ops && alloc_ops->memalign); + if (alignment <= sizeof(uintptr_t)) + alignment = sizeof(uintptr_t); + else + size += alignment - 1; + + blkalign = MAX(alignment, alloc_ops->align_min); + size = ALIGN(size + METADATA_EXTRA, alloc_ops->align_min); + p = alloc_ops->memalign(blkalign, size); + + /* Leave room for metadata before aligning the result. */ + mem = (uintptr_t)p + METADATA_EXTRA; + mem = ALIGN(mem, alignment); + + /* Write the metadata */ + *(uintptr_t *)(mem + OFS_SLACK) = mem - (uintptr_t)p; + *(uintptr_t *)(mem + OFS_SIZE) = size; + return (void *)mem; +} diff --git a/lib/alloc.h b/lib/alloc.h index 24f85b4..f560c4a 100644 --- a/lib/alloc.h +++ b/lib/alloc.h @@ -24,36 +24,17 @@ struct alloc_ops { void *(*memalign)(size_t alignment, size_t size); + void (*free)(void *ptr, size_t size); + size_t align_min; }; extern struct alloc_ops *alloc_ops; -/* - * Our malloc implementation is currently so simple that it can just - * be inlined. :) - */ -static inline void *malloc(size_t size) -{ - assert(alloc_ops && alloc_ops->memalign); - return alloc_ops->memalign(sizeof(long), size); -} - -static inline void *calloc(size_t nmemb, size_t size) -{ - void *ptr = malloc(nmemb * size); - if (ptr) - memset(ptr, 0, nmemb * size); - return ptr; -} +void *malloc(size_t size); +void *calloc(size_t nmemb, size_t size); +void free(void *ptr); +void *memalign(size_t alignment, size_t size); -static inline void free(void *ptr) -{ -} - -static inline void *memalign(size_t alignment, size_t size) -{ - assert(alloc_ops && alloc_ops->memalign); - return alloc_ops->memalign(alignment, size); -} +extern struct alloc_ops *alloc_ops; #endif /* _ALLOC_H_ */ diff --git a/lib/alloc_phys.c b/lib/alloc_phys.c index 6befb5c..d09395d 100644 --- a/lib/alloc_phys.c +++ b/lib/alloc_phys.c @@ -23,7 +23,15 @@ static struct phys_alloc_region regions[PHYS_ALLOC_NR_REGIONS]; static int nr_regions; static struct spinlock lock; -static phys_addr_t base, top, align_min; +static phys_addr_t base, top; + +static void *early_memalign(size_t alignment, size_t size); +static struct alloc_ops early_alloc_ops = { + .memalign = early_memalign, + .align_min = DEFAULT_MINIMUM_ALIGNMENT +}; + +struct alloc_ops *alloc_ops = &early_alloc_ops; void phys_alloc_show(void) { @@ -31,7 +39,7 @@ void phys_alloc_show(void) spin_lock(&lock); printf("phys_alloc minimum alignment: %#" PRIx64 "\n", - (u64)align_min); + (u64)early_alloc_ops.align_min); for (i = 0; i < nr_regions; ++i) printf("%016" PRIx64 "-%016" PRIx64 " [%s]\n", (u64)regions[i].base, @@ -47,7 +55,6 @@ void phys_alloc_init(phys_addr_t base_addr, phys_addr_t size) spin_lock(&lock); base = base_addr; top = base + size; - align_min = DEFAULT_MINIMUM_ALIGNMENT; nr_regions = 0; spin_unlock(&lock); } @@ -56,7 +63,7 @@ void phys_alloc_set_minimum_alignment(phys_addr_t align) { assert(align && !(align & (align - 1))); spin_lock(&lock); - align_min = align; + early_alloc_ops.align_min = align; spin_unlock(&lock); } @@ -74,8 +81,6 @@ static phys_addr_t phys_alloc_aligned_safe(phys_addr_t size, if (safe && sizeof(long) == 4) top_safe = MIN(top_safe, 1ULL << 32); - align = MAX(align, align_min); - addr = ALIGN(base, align); size += addr - base; @@ -125,9 +130,3 @@ static void *early_memalign(size_t alignment, size_t size) return phys_to_virt(addr); } - -static struct alloc_ops early_alloc_ops = { - .memalign = early_memalign, -}; - -struct alloc_ops *alloc_ops = &early_alloc_ops; diff --git a/powerpc/Makefile.common b/powerpc/Makefile.common index 126590a..21dea40 100644 --- a/powerpc/Makefile.common +++ b/powerpc/Makefile.common @@ -31,6 +31,7 @@ include $(SRCDIR)/scripts/asm-offsets.mak cflatobjs += lib/util.o cflatobjs += lib/alloc_phys.o +cflatobjs += lib/alloc.o cflatobjs += lib/devicetree.o cflatobjs += lib/powerpc/io.o cflatobjs += lib/powerpc/hcall.o -- 2.14.2