diff --git a/lib/libc/common/source/stdlib/malloc.c b/lib/libc/common/source/stdlib/malloc.c index 6ad8ae109fb..21ac95c8521 100644 --- a/lib/libc/common/source/stdlib/malloc.c +++ b/lib/libc/common/source/stdlib/malloc.c @@ -15,6 +15,9 @@ #include #include #include +#ifdef CONFIG_MMU +#include +#endif #define LOG_LEVEL CONFIG_KERNEL_LOG_LEVEL #include @@ -22,19 +25,92 @@ LOG_MODULE_DECLARE(os, CONFIG_KERNEL_LOG_LEVEL); #ifdef CONFIG_COMMON_LIBC_MALLOC -#if (CONFIG_COMMON_LIBC_MALLOC_ARENA_SIZE > 0) -#ifdef CONFIG_USERSPACE +#if (CONFIG_COMMON_LIBC_MALLOC_ARENA_SIZE != 0) + +/* Figure out where the malloc variables live */ +# if Z_MALLOC_PARTITION_EXISTS K_APPMEM_PARTITION_DEFINE(z_malloc_partition); -#define POOL_SECTION K_APP_DMEM_SECTION(z_malloc_partition) -#else -#define POOL_SECTION .bss -#endif /* CONFIG_USERSPACE */ +# define POOL_SECTION Z_GENERIC_SECTION(K_APP_DMEM_SECTION(z_malloc_partition)) +# else +# define POOL_SECTION __noinit +# endif /* CONFIG_USERSPACE */ -#define HEAP_BYTES CONFIG_COMMON_LIBC_MALLOC_ARENA_SIZE +# if defined(CONFIG_MMU) && CONFIG_COMMON_LIBC_MALLOC_ARENA_SIZE < 0 +# define ALLOCATE_HEAP_AT_STARTUP +# endif -Z_GENERIC_SECTION(POOL_SECTION) static struct sys_heap z_malloc_heap; -Z_GENERIC_SECTION(POOL_SECTION) struct sys_mutex z_malloc_heap_mutex; -Z_GENERIC_SECTION(POOL_SECTION) static char z_malloc_heap_mem[HEAP_BYTES]; +# ifndef ALLOCATE_HEAP_AT_STARTUP + +/* Figure out alignment requirement */ +# ifdef Z_MALLOC_PARTITION_EXISTS + +# ifdef CONFIG_MMU +# define HEAP_ALIGN CONFIG_MMU_PAGE_SIZE +# elif defined(CONFIG_MPU) +# if defined(CONFIG_MPU_REQUIRES_POWER_OF_TWO_ALIGNMENT) && \ + (CONFIG_COMMON_LIBC_MALLOC_ARENA_SIZE > 0) +# if (CONFIG_COMMON_LIBC_MALLOC_ARENA_SIZE & (CONFIG_COMMON_LIBC_MALLOC_ARENA_SIZE - 1)) != 0 +# error CONFIG_COMMON_LIBC_MALLOC_ARENA_SIZE must be power of two on this target +# endif +# define HEAP_ALIGN CONFIG_COMMON_LIBC_MALLOC_ARENA_SIZE +# elif defined(CONFIG_ARM) || defined(CONFIG_ARM64) +# define HEAP_ALIGN CONFIG_ARM_MPU_REGION_MIN_ALIGN_AND_SIZE +# elif defined(CONFIG_ARC) +# define HEAP_ALIGN Z_ARC_MPU_ALIGN +# elif defined(CONFIG_RISCV) +# define HEAP_ALIGN Z_RISCV_STACK_GUARD_SIZE +# else +/* Default to 64-bytes; we'll get a run-time error if this doesn't work. */ +# define HEAP_ALIGN 64 +# endif /* CONFIG_ */ +# endif /* elif CONFIG_MPU */ + +# endif /* else Z_MALLOC_PARTITION_EXISTS */ + +# ifndef HEAP_ALIGN +# define HEAP_ALIGN sizeof(double) +# endif + +# if CONFIG_COMMON_LIBC_MALLOC_ARENA_SIZE > 0 + +/* Static allocation of heap in BSS */ + +# define HEAP_SIZE ROUND_UP(CONFIG_COMMON_LIBC_MALLOC_ARENA_SIZE, HEAP_ALIGN) +# define HEAP_BASE POINTER_TO_UINT(malloc_arena) + +static POOL_SECTION unsigned char __aligned(HEAP_ALIGN) malloc_arena[HEAP_SIZE]; + +# else /* CONFIG_COMMON_LIBC_MALLOC_ARENA_SIZE > 0 */ + +/* + * Heap base and size are determined based on the available unused SRAM, in the + * interval from a properly aligned address after the linker symbol `_end`, to + * the end of SRAM + */ + +# define USED_RAM_END_ADDR POINTER_TO_UINT(&_end) + +/* + * No partition, heap can just start wherever _end is, with + * suitable alignment + */ + +# define HEAP_BASE ROUND_UP(USED_RAM_END_ADDR, HEAP_ALIGN) + +# ifdef CONFIG_XTENSA +extern char _heap_sentry[]; +# define HEAP_SIZE ROUND_DOWN((POINTER_TO_UINT(_heap_sentry) - HEAP_BASE), HEAP_ALIGN) +# else +# define HEAP_SIZE ROUND_DOWN((KB((size_t) CONFIG_SRAM_SIZE) - \ + ((size_t) HEAP_BASE - (size_t) CONFIG_SRAM_BASE_ADDRESS)), HEAP_ALIGN) +# endif /* else CONFIG_XTENSA */ + +# endif /* else CONFIG_COMMON_LIBC_MALLOC_ARENA_SIZE > 0 */ + +# endif /* else ALLOCATE_HEAP_AT_STARTUP */ + +POOL_SECTION static struct sys_heap z_malloc_heap; +POOL_SECTION struct sys_mutex z_malloc_heap_mutex; void *malloc(size_t size) { @@ -79,8 +155,46 @@ void *aligned_alloc(size_t alignment, size_t size) static int malloc_prepare(void) { + void *heap_base = NULL; + size_t heap_size; - sys_heap_init(&z_malloc_heap, z_malloc_heap_mem, HEAP_BYTES); +#ifdef ALLOCATE_HEAP_AT_STARTUP + heap_size = k_mem_free_get(); + + if (heap_size != 0) { + heap_base = k_mem_map(heap_size, K_MEM_PERM_RW); + __ASSERT(heap_base != NULL, + "failed to allocate heap of size %zu", heap_size); + + } +#elif defined(Z_MALLOC_PARTITION_EXISTS) && \ + defined(CONFIG_MPU) && \ + defined(CONFIG_MPU_REQUIRES_POWER_OF_TWO_ALIGNMENT) + + /* Align size to power of two */ + heap_size = 1; + while (heap_size * 2 <= HEAP_SIZE) + heap_size *= 2; + + /* Search for an aligned heap that fits within the available space */ + while (heap_size >= HEAP_ALIGN) { + heap_base = UINT_TO_POINTER(ROUND_UP(HEAP_BASE, heap_size)); + if (POINTER_TO_UINT(heap_base) + heap_size <= HEAP_BASE + HEAP_SIZE) + break; + heap_size >>= 1; + } +#else + heap_base = UINT_TO_POINTER(HEAP_BASE); + heap_size = HEAP_SIZE; +#endif + +#if Z_MALLOC_PARTITION_EXISTS + z_malloc_partition.start = POINTER_TO_UINT(heap_base); + z_malloc_partition.size = heap_size; + z_malloc_partition.attr = K_MEM_PARTITION_P_RW_U_RW; +#endif + + sys_heap_init(&z_malloc_heap, heap_base, heap_size); sys_mutex_init(&z_malloc_heap_mutex); return 0; @@ -138,7 +252,7 @@ void *realloc(void *ptr, size_t size) ARG_UNUSED(ptr); return malloc(size); } -#endif +#endif /* else no malloc arena */ #endif /* CONFIG_COMMON_LIBC_MALLOC */