libc: set up memory partitions
* Newlib now defines a special z_newlib_partition containing all globals relevant to newlib. Most of these are in libc.a with a heap tracking variable in newlib's hooks. * Both C libraries now expose a k_mem_partition containing the bounds of the malloc heap arena. Threads that want to use libc malloc() will need to add this to their memory domain. * z_newlib_get_heap_bounds has been removed, in favor of the memory partition for the heap arena * ztest now includes the C library partitions in its memory domain. * The mem_alloc test now runs in user mode to prove that this all works for both C libraries. Signed-off-by: Andrew Boie <andrew.p.boie@intel.com>
This commit is contained in:
parent
71a3b53504
commit
4b4f773484
9 changed files with 90 additions and 50 deletions
|
@ -1228,12 +1228,16 @@ if(CONFIG_APP_SHARED_MEM AND CONFIG_USERSPACE)
|
||||||
kernel ${ZEPHYR_LIBS_PROPERTY}
|
kernel ${ZEPHYR_LIBS_PROPERTY}
|
||||||
)
|
)
|
||||||
|
|
||||||
|
if(CONFIG_NEWLIB_LIBC)
|
||||||
|
set(NEWLIB_PART -l libc.a z_newlib_partition)
|
||||||
|
endif()
|
||||||
add_custom_command(
|
add_custom_command(
|
||||||
TARGET ${APP_SMEM_DEP}
|
TARGET ${APP_SMEM_DEP}
|
||||||
COMMAND ${PYTHON_EXECUTABLE}
|
COMMAND ${PYTHON_EXECUTABLE}
|
||||||
${ZEPHYR_BASE}/scripts/gen_app_partitions.py
|
${ZEPHYR_BASE}/scripts/gen_app_partitions.py
|
||||||
-d ${OBJ_FILE_DIR}
|
-d ${OBJ_FILE_DIR}
|
||||||
-o ${APP_SMEM_LD}
|
-o ${APP_SMEM_LD}
|
||||||
|
${NEWLIB_PART}
|
||||||
$<$<BOOL:${CMAKE_VERBOSE_MAKEFILE}>:--verbose>
|
$<$<BOOL:${CMAKE_VERBOSE_MAKEFILE}>:--verbose>
|
||||||
WORKING_DIRECTORY ${PROJECT_BINARY_DIR}/
|
WORKING_DIRECTORY ${PROJECT_BINARY_DIR}/
|
||||||
COMMENT "Generating app_smem linker section"
|
COMMENT "Generating app_smem linker section"
|
||||||
|
|
|
@ -27,6 +27,13 @@ __syscall int _zephyr_read(char *buf, int nbytes);
|
||||||
|
|
||||||
__syscall int _zephyr_write(const void *buf, int nbytes);
|
__syscall int _zephyr_write(const void *buf, int nbytes);
|
||||||
|
|
||||||
|
#ifdef CONFIG_APP_SHARED_MEM
|
||||||
|
/* Memory partition containing newlib's globals. This includes all the globals
|
||||||
|
* within libc.a and the supporting zephyr hooks, but not the malloc arena.
|
||||||
|
*/
|
||||||
|
extern struct k_mem_partition z_newlib_partition;
|
||||||
|
#endif /* CONFIG_APP_SHARED_MEM */
|
||||||
|
|
||||||
#else
|
#else
|
||||||
/* Minimal libc */
|
/* Minimal libc */
|
||||||
|
|
||||||
|
@ -34,9 +41,13 @@ __syscall int _zephyr_fputc(int c, FILE *stream);
|
||||||
|
|
||||||
__syscall size_t _zephyr_fwrite(const void *_MLIBC_RESTRICT ptr, size_t size,
|
__syscall size_t _zephyr_fwrite(const void *_MLIBC_RESTRICT ptr, size_t size,
|
||||||
size_t nitems, FILE *_MLIBC_RESTRICT stream);
|
size_t nitems, FILE *_MLIBC_RESTRICT stream);
|
||||||
|
|
||||||
#endif /* CONFIG_NEWLIB_LIBC */
|
#endif /* CONFIG_NEWLIB_LIBC */
|
||||||
|
|
||||||
|
#ifdef CONFIG_APP_SHARED_MEM
|
||||||
|
/* Memory partition containing the libc malloc arena */
|
||||||
|
extern struct k_mem_partition z_malloc_partition;
|
||||||
|
#endif
|
||||||
|
|
||||||
#include <syscalls/libc-hooks.h>
|
#include <syscalls/libc-hooks.h>
|
||||||
|
|
||||||
#endif /* ZEPHYR_INCLUDE_MISC_LIBC_HOOKS_H_ */
|
#endif /* ZEPHYR_INCLUDE_MISC_LIBC_HOOKS_H_ */
|
||||||
|
|
|
@ -206,21 +206,6 @@ extern void smp_init(void);
|
||||||
|
|
||||||
extern void smp_timer_init(void);
|
extern void smp_timer_init(void);
|
||||||
|
|
||||||
#ifdef CONFIG_NEWLIB_LIBC
|
|
||||||
/**
|
|
||||||
* @brief Fetch dimentions of newlib heap area for _sbrk()
|
|
||||||
*
|
|
||||||
* This memory region is used for heap allocations by the newlib C library.
|
|
||||||
* If user threads need to have access to this, the results returned can be
|
|
||||||
* used to program memory protection hardware appropriately.
|
|
||||||
*
|
|
||||||
* @param base Pointer to void pointer, filled in with the heap starting
|
|
||||||
* address
|
|
||||||
* @param size Pointer to a size_y, filled in with the maximum heap size
|
|
||||||
*/
|
|
||||||
extern void z_newlib_get_heap_bounds(void **base, size_t *size);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
extern u32_t z_early_boot_rand32_get(void);
|
extern u32_t z_early_boot_rand32_get(void);
|
||||||
|
|
||||||
#if CONFIG_STACK_POINTER_RANDOM
|
#if CONFIG_STACK_POINTER_RANDOM
|
||||||
|
|
|
@ -10,15 +10,26 @@
|
||||||
#include <errno.h>
|
#include <errno.h>
|
||||||
#include <misc/mempool.h>
|
#include <misc/mempool.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
#include <app_memory/app_memdomain.h>
|
||||||
|
|
||||||
#define LOG_LEVEL CONFIG_KERNEL_LOG_LEVEL
|
#define LOG_LEVEL CONFIG_KERNEL_LOG_LEVEL
|
||||||
#include <logging/log.h>
|
#include <logging/log.h>
|
||||||
LOG_MODULE_DECLARE(os);
|
LOG_MODULE_DECLARE(os);
|
||||||
|
|
||||||
|
#ifdef CONFIG_APP_SHARED_MEM
|
||||||
|
K_APPMEM_PARTITION_DEFINE(z_malloc_partition);
|
||||||
|
#endif
|
||||||
|
|
||||||
#if (CONFIG_MINIMAL_LIBC_MALLOC_ARENA_SIZE > 0)
|
#if (CONFIG_MINIMAL_LIBC_MALLOC_ARENA_SIZE > 0)
|
||||||
|
#ifdef CONFIG_APP_SHARED_MEM
|
||||||
|
#define POOL_SECTION K_APP_DMEM_SECTION(z_malloc_partition)
|
||||||
|
#else
|
||||||
|
#define POOL_SECTION .data
|
||||||
|
#endif /* CONFIG_APP_SHARED_MEM */
|
||||||
|
|
||||||
K_MUTEX_DEFINE(malloc_mutex);
|
K_MUTEX_DEFINE(malloc_mutex);
|
||||||
SYS_MEM_POOL_DEFINE(z_malloc_mem_pool, &malloc_mutex, 16,
|
SYS_MEM_POOL_DEFINE(z_malloc_mem_pool, &malloc_mutex, 16,
|
||||||
CONFIG_MINIMAL_LIBC_MALLOC_ARENA_SIZE, 1, 4, .data);
|
CONFIG_MINIMAL_LIBC_MALLOC_ARENA_SIZE, 1, 4, POOL_SECTION);
|
||||||
|
|
||||||
void *malloc(size_t size)
|
void *malloc(size_t size)
|
||||||
{
|
{
|
||||||
|
|
|
@ -14,12 +14,30 @@
|
||||||
#include <misc/errno_private.h>
|
#include <misc/errno_private.h>
|
||||||
#include <misc/libc-hooks.h>
|
#include <misc/libc-hooks.h>
|
||||||
#include <syscall_handler.h>
|
#include <syscall_handler.h>
|
||||||
|
#include <app_memory/app_memdomain.h>
|
||||||
|
#include <init.h>
|
||||||
|
|
||||||
|
#ifdef CONFIG_APP_SHARED_MEM
|
||||||
|
K_APPMEM_PARTITION_DEFINE(z_newlib_partition);
|
||||||
|
#define LIBC_BSS K_APP_BMEM(z_newlib_partition)
|
||||||
|
#define LIBC_DATA K_APP_DMEM(z_newlib_partition)
|
||||||
|
|
||||||
|
#if CONFIG_NEWLIB_LIBC_ALIGNED_HEAP_SIZE
|
||||||
|
K_APPMEM_PARTITION_DEFINE(z_malloc_partition);
|
||||||
|
#define MALLOC_BSS K_APP_BMEM(z_malloc_partition)
|
||||||
|
#endif /* CONFIG_NEWLIB_LIBC_ALIGNED_HEAP_SIZE */
|
||||||
|
|
||||||
|
#else
|
||||||
|
#define LIBC_BSS
|
||||||
|
#define LIBC_DATA
|
||||||
|
#define MALLOC_BSS
|
||||||
|
#endif /* CONFIG_APP_SHARED_MEM */
|
||||||
|
|
||||||
#define USED_RAM_END_ADDR POINTER_TO_UINT(&_end)
|
#define USED_RAM_END_ADDR POINTER_TO_UINT(&_end)
|
||||||
|
|
||||||
#if CONFIG_NEWLIB_LIBC_ALIGNED_HEAP_SIZE
|
#if CONFIG_NEWLIB_LIBC_ALIGNED_HEAP_SIZE
|
||||||
/* Compiler will throw an error if the provided value isn't a power of two */
|
/* Compiler will throw an error if the provided value isn't a power of two */
|
||||||
static unsigned char __kernel __aligned(CONFIG_NEWLIB_LIBC_ALIGNED_HEAP_SIZE)
|
MALLOC_BSS static unsigned char __kernel __aligned(CONFIG_NEWLIB_LIBC_ALIGNED_HEAP_SIZE)
|
||||||
heap_base[CONFIG_NEWLIB_LIBC_ALIGNED_HEAP_SIZE];
|
heap_base[CONFIG_NEWLIB_LIBC_ALIGNED_HEAP_SIZE];
|
||||||
#define MAX_HEAP_SIZE CONFIG_NEWLIB_LIBC_ALIGNED_HEAP_SIZE
|
#define MAX_HEAP_SIZE CONFIG_NEWLIB_LIBC_ALIGNED_HEAP_SIZE
|
||||||
#else
|
#else
|
||||||
|
@ -48,9 +66,25 @@ extern void *_heap_sentry;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
static unsigned char *heap_base = UINT_TO_POINTER(USED_RAM_END_ADDR);
|
static unsigned char *heap_base = UINT_TO_POINTER(USED_RAM_END_ADDR);
|
||||||
|
|
||||||
|
#ifdef CONFIG_APP_SHARED_MEM
|
||||||
|
struct k_mem_partition z_malloc_partition;
|
||||||
|
|
||||||
|
static int malloc_prepare(struct device *unused)
|
||||||
|
{
|
||||||
|
ARG_UNUSED(unused);
|
||||||
|
|
||||||
|
z_malloc_partition.start = (u32_t)heap_base;
|
||||||
|
z_malloc_partition.size = MAX_HEAP_SIZE;
|
||||||
|
z_malloc_partition.attr = K_MEM_PARTITION_P_RW_U_RW;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
SYS_INIT(malloc_prepare, APPLICATION, CONFIG_KERNEL_INIT_PRIORITY_DEFAULT);
|
||||||
|
#endif
|
||||||
#endif /* CONFIG_NEWLIB_LIBC_ALIGNED_HEAP_SIZE */
|
#endif /* CONFIG_NEWLIB_LIBC_ALIGNED_HEAP_SIZE */
|
||||||
|
|
||||||
static unsigned int heap_sz;
|
LIBC_BSS static unsigned int heap_sz;
|
||||||
|
|
||||||
static int _stdout_hook_default(int c)
|
static int _stdout_hook_default(int c)
|
||||||
{
|
{
|
||||||
|
@ -207,12 +241,6 @@ void *_sbrk(int count)
|
||||||
}
|
}
|
||||||
FUNC_ALIAS(_sbrk, sbrk, void *);
|
FUNC_ALIAS(_sbrk, sbrk, void *);
|
||||||
|
|
||||||
void z_newlib_get_heap_bounds(void **base, size_t *size)
|
|
||||||
{
|
|
||||||
*base = heap_base;
|
|
||||||
*size = MAX_HEAP_SIZE;
|
|
||||||
}
|
|
||||||
|
|
||||||
int *__errno(void)
|
int *__errno(void)
|
||||||
{
|
{
|
||||||
return z_errno();
|
return z_errno();
|
||||||
|
|
|
@ -1,3 +1,4 @@
|
||||||
CONFIG_ZTEST=y
|
CONFIG_ZTEST=y
|
||||||
CONFIG_NEWLIB_LIBC=y
|
CONFIG_NEWLIB_LIBC=y
|
||||||
CONFIG_MAIN_STACK_SIZE=1024
|
CONFIG_MAIN_STACK_SIZE=1024
|
||||||
|
CONFIG_NEWLIB_LIBC_ALIGNED_HEAP_SIZE=512
|
||||||
|
|
|
@ -24,10 +24,6 @@
|
||||||
|
|
||||||
#define BUF_LEN 10
|
#define BUF_LEN 10
|
||||||
|
|
||||||
#ifdef CONFIG_MINIMAL_LIBC_MALLOC_ARENA_SIZE
|
|
||||||
#define MAX_HEAP_SIZE CONFIG_MINIMAL_LIBC_MALLOC_ARENA_SIZE
|
|
||||||
#endif
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Test dynamic memory allocation using malloc
|
* @brief Test dynamic memory allocation using malloc
|
||||||
*
|
*
|
||||||
|
@ -40,6 +36,7 @@ void test_malloc(void)
|
||||||
|
|
||||||
iptr = malloc(BUF_LEN * sizeof(int));
|
iptr = malloc(BUF_LEN * sizeof(int));
|
||||||
zassert_not_null((iptr), "malloc failed, errno: %d", errno);
|
zassert_not_null((iptr), "malloc failed, errno: %d", errno);
|
||||||
|
memset(iptr, 'p', BUF_LEN * sizeof(int));
|
||||||
free(iptr);
|
free(iptr);
|
||||||
iptr = NULL;
|
iptr = NULL;
|
||||||
}
|
}
|
||||||
|
@ -64,7 +61,7 @@ void test_free(void)
|
||||||
* @see calloc(), free()
|
* @see calloc(), free()
|
||||||
*/
|
*/
|
||||||
#define CALLOC_BUFLEN (200)
|
#define CALLOC_BUFLEN (200)
|
||||||
static unsigned char zerobuf[CALLOC_BUFLEN];
|
ZTEST_BMEM static unsigned char zerobuf[CALLOC_BUFLEN];
|
||||||
|
|
||||||
void test_calloc(void)
|
void test_calloc(void)
|
||||||
{
|
{
|
||||||
|
@ -74,6 +71,7 @@ void test_calloc(void)
|
||||||
zassert_not_null((cptr), "calloc failed, errno: %d", errno);
|
zassert_not_null((cptr), "calloc failed, errno: %d", errno);
|
||||||
zassert_true(((memcmp(cptr, zerobuf, CALLOC_BUFLEN)) == 0),
|
zassert_true(((memcmp(cptr, zerobuf, CALLOC_BUFLEN)) == 0),
|
||||||
"calloc failed to set zero value, errno: %d", errno);
|
"calloc failed to set zero value, errno: %d", errno);
|
||||||
|
memset(cptr, 'p', CALLOC_BUFLEN);
|
||||||
free(cptr);
|
free(cptr);
|
||||||
cptr = NULL;
|
cptr = NULL;
|
||||||
}
|
}
|
||||||
|
@ -83,7 +81,7 @@ void test_calloc(void)
|
||||||
*
|
*
|
||||||
* @see malloc(), realloc(), free()
|
* @see malloc(), realloc(), free()
|
||||||
*/
|
*/
|
||||||
unsigned char filled_buf[BUF_LEN];
|
ZTEST_BMEM unsigned char filled_buf[BUF_LEN];
|
||||||
|
|
||||||
void test_realloc(void)
|
void test_realloc(void)
|
||||||
{
|
{
|
||||||
|
@ -191,17 +189,9 @@ void test_memalloc_all(void)
|
||||||
|
|
||||||
void test_memalloc_max(void)
|
void test_memalloc_max(void)
|
||||||
{
|
{
|
||||||
size_t max_heap_size = 0;
|
|
||||||
char *ptr = NULL;
|
char *ptr = NULL;
|
||||||
|
|
||||||
#ifdef CONFIG_NEWLIB_LIBC
|
ptr = malloc(0xF0000000);
|
||||||
void *heap_base = NULL;
|
|
||||||
|
|
||||||
z_newlib_get_heap_bounds(&heap_base, &max_heap_size);
|
|
||||||
#else
|
|
||||||
max_heap_size = MAX_HEAP_SIZE;
|
|
||||||
#endif
|
|
||||||
ptr = malloc(max_heap_size + 1);
|
|
||||||
zassert_is_null(ptr, "malloc passed unexpectedly");
|
zassert_is_null(ptr, "malloc passed unexpectedly");
|
||||||
free(ptr);
|
free(ptr);
|
||||||
ptr = NULL;
|
ptr = NULL;
|
||||||
|
@ -210,13 +200,13 @@ void test_memalloc_max(void)
|
||||||
void test_main(void)
|
void test_main(void)
|
||||||
{
|
{
|
||||||
ztest_test_suite(test_c_lib_dynamic_memalloc,
|
ztest_test_suite(test_c_lib_dynamic_memalloc,
|
||||||
ztest_unit_test(test_malloc),
|
ztest_user_unit_test(test_malloc),
|
||||||
ztest_unit_test(test_free),
|
ztest_user_unit_test(test_free),
|
||||||
ztest_unit_test(test_calloc),
|
ztest_user_unit_test(test_calloc),
|
||||||
ztest_unit_test(test_realloc),
|
ztest_user_unit_test(test_realloc),
|
||||||
ztest_unit_test(test_reallocarray),
|
ztest_user_unit_test(test_reallocarray),
|
||||||
ztest_unit_test(test_memalloc_all),
|
ztest_user_unit_test(test_memalloc_all),
|
||||||
ztest_unit_test(test_memalloc_max)
|
ztest_user_unit_test(test_memalloc_max)
|
||||||
);
|
);
|
||||||
ztest_run_test_suite(test_c_lib_dynamic_memalloc);
|
ztest_run_test_suite(test_c_lib_dynamic_memalloc);
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,9 +2,9 @@ tests:
|
||||||
libraries.libc.minimal:
|
libraries.libc.minimal:
|
||||||
extra_args: CONF_FILE=prj.conf
|
extra_args: CONF_FILE=prj.conf
|
||||||
arch_exclude: posix
|
arch_exclude: posix
|
||||||
tags: clib minimal_libc
|
tags: clib minimal_libc userspace
|
||||||
libraries.libc.newlib:
|
libraries.libc.newlib:
|
||||||
extra_args: CONF_FILE=prj_newlib.conf
|
extra_args: CONF_FILE=prj_newlib.conf
|
||||||
arch_exclude: posix
|
arch_exclude: posix
|
||||||
filter: TOOLCHAIN_HAS_NEWLIB == 1
|
filter: TOOLCHAIN_HAS_NEWLIB == 1
|
||||||
tags: clib newlib
|
tags: clib newlib userspace
|
||||||
|
|
|
@ -7,6 +7,10 @@
|
||||||
#include <ztest.h>
|
#include <ztest.h>
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <app_memory/app_memdomain.h>
|
#include <app_memory/app_memdomain.h>
|
||||||
|
#ifdef CONFIG_APP_SHARED_MEM
|
||||||
|
#include <misc/libc-hooks.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
#ifdef KERNEL
|
#ifdef KERNEL
|
||||||
__kernel static struct k_thread ztest_thread;
|
__kernel static struct k_thread ztest_thread;
|
||||||
#endif
|
#endif
|
||||||
|
@ -297,7 +301,13 @@ void main(void)
|
||||||
{
|
{
|
||||||
#ifdef CONFIG_APP_SHARED_MEM
|
#ifdef CONFIG_APP_SHARED_MEM
|
||||||
struct k_mem_partition *parts[] = {
|
struct k_mem_partition *parts[] = {
|
||||||
&ztest_mem_partition
|
&ztest_mem_partition,
|
||||||
|
#ifdef CONFIG_NEWLIB_LIBC
|
||||||
|
/* Newlib libc.a library and hooks globals */
|
||||||
|
&z_newlib_partition,
|
||||||
|
#endif
|
||||||
|
/* Both minimal and newlib libc expose this for malloc arena */
|
||||||
|
&z_malloc_partition
|
||||||
};
|
};
|
||||||
|
|
||||||
/* Ztests just have one memory domain with one partition.
|
/* Ztests just have one memory domain with one partition.
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue