diff --git a/CMakeLists.txt b/CMakeLists.txt index d754ff98eac31a..282fbb91158d2c 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -917,6 +917,9 @@ if(CONFIG_USERSPACE) if(CONFIG_NEWLIB_LIBC_NANO) set(NEWLIB_PART -l libc_nano.a z_libc_partition -l libm_nano.a z_libc_partition) endif() + if(CONFIG_PICOLIBC) + set(NEWLIB_PART -l libc.a z_libc_partition) + endif() add_custom_command( OUTPUT ${APP_SMEM_UNALIGNED_LD} ${APP_SMEM_PINNED_UNALIGNED_LD} diff --git a/arch/Kconfig b/arch/Kconfig index a679897889e154..c67e59600b7e3f 100644 --- a/arch/Kconfig +++ b/arch/Kconfig @@ -33,7 +33,7 @@ config ARM # FIXME: current state of the code for all ARM requires this, but # is really only necessary for Cortex-M with ARM MPU! select GEN_PRIV_STACKS - select ARCH_HAS_THREAD_LOCAL_STORAGE if CPU_AARCH32_CORTEX_R || CPU_CORTEX_M + select ARCH_HAS_THREAD_LOCAL_STORAGE if CPU_AARCH32_CORTEX_R || CPU_CORTEX_M || CPU_AARCH32_CORTEX_A help ARM architecture diff --git a/arch/arm/core/aarch32/cortex_a_r/CMakeLists.txt b/arch/arm/core/aarch32/cortex_a_r/CMakeLists.txt index a044a2b20bb85f..d03d53680fc781 100644 --- a/arch/arm/core/aarch32/cortex_a_r/CMakeLists.txt +++ b/arch/arm/core/aarch32/cortex_a_r/CMakeLists.txt @@ -15,3 +15,4 @@ zephyr_library_sources( ) zephyr_library_sources_ifdef(CONFIG_USERSPACE thread.c) +zephyr_library_sources_ifdef(CONFIG_THREAD_LOCAL_STORAGE __aeabi_read_tp.S) diff --git a/arch/arm/core/aarch32/cortex_a_r/__aeabi_read_tp.S b/arch/arm/core/aarch32/cortex_a_r/__aeabi_read_tp.S new file mode 100644 index 00000000000000..7b5bb5c1bf61b0 --- /dev/null +++ b/arch/arm/core/aarch32/cortex_a_r/__aeabi_read_tp.S @@ -0,0 +1,20 @@ +/* + * Copyright (c) 2020 Intel Corporation + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include + +_ASM_FILE_PROLOGUE + +GTEXT(__aeabi_read_tp) + +SECTION_FUNC(text, __aeabi_read_tp) + /* + * Load TLS base address, which is stored in the TPIDRURO register, also + * known as the "Process ID" register. Refer to the code in z_arm_pendsv + * to see where this register is set. + */ + mrc 15, 0, r0, c13, c0, 3 + bx lr diff --git a/arch/arm/core/aarch32/swap_helper.S b/arch/arm/core/aarch32/swap_helper.S index 90452186e46c5a..2f9518af26573b 100644 --- a/arch/arm/core/aarch32/swap_helper.S +++ b/arch/arm/core/aarch32/swap_helper.S @@ -186,7 +186,7 @@ out_fp_endif: adds r4, r2, r4 ldr r0, [r4] -#if defined(CONFIG_CPU_AARCH32_CORTEX_R) +#if defined(CONFIG_CPU_AARCH32_CORTEX_R) || defined(CONFIG_CPU_AARCH32_CORTEX_A) /* Store TLS pointer in the "Process ID" register. * This register is used as a base pointer to all * thread variables with offsets added by toolchain. diff --git a/cmake/toolchain/gnuarmemb/generic.cmake b/cmake/toolchain/gnuarmemb/generic.cmake index 1ea30ab70debcd..97bff4272f6b17 100644 --- a/cmake/toolchain/gnuarmemb/generic.cmake +++ b/cmake/toolchain/gnuarmemb/generic.cmake @@ -28,5 +28,6 @@ set(SYSROOT_TARGET arm-none-eabi) set(CROSS_COMPILE ${TOOLCHAIN_HOME}/bin/${CROSS_COMPILE_TARGET}-) set(SYSROOT_DIR ${TOOLCHAIN_HOME}/${SYSROOT_TARGET}) set(TOOLCHAIN_HAS_NEWLIB ON CACHE BOOL "True if toolchain supports newlib") +set(TOOLCHAIN_HAS_PICOLIBC ON CACHE BOOL "True if toolchain supports picolibc") message(STATUS "Found toolchain: gnuarmemb (${GNUARMEMB_TOOLCHAIN_PATH})") diff --git a/cmake/toolchain/xtools/generic.cmake b/cmake/toolchain/xtools/generic.cmake index f4836eb5775de4..b6ff678c6722db 100644 --- a/cmake/toolchain/xtools/generic.cmake +++ b/cmake/toolchain/xtools/generic.cmake @@ -33,6 +33,7 @@ set(SYSROOT_TARGET ${CROSS_COMPILE_TARGET}) set(CROSS_COMPILE ${some_toolchain_root}/${CROSS_COMPILE_TARGET}/bin/${CROSS_COMPILE_TARGET}-) set(SYSROOT_DIR ${some_toolchain_root}/${SYSROOT_TARGET}/${SYSROOT_TARGET}) set(TOOLCHAIN_HAS_NEWLIB ON CACHE BOOL "True if toolchain supports newlib") +set(TOOLCHAIN_HAS_PICOLIBC ON CACHE BOOL "True if toolchain supports picolibc") unset(some_toolchain_root) unset(some_toolchain) diff --git a/include/sys/libc-hooks.h b/include/sys/libc-hooks.h index afa3554ed87c09..6bfd379151cc3b 100644 --- a/include/sys/libc-hooks.h +++ b/include/sys/libc-hooks.h @@ -16,7 +16,7 @@ * that need to call into the kernel as system calls */ -#if defined(CONFIG_NEWLIB_LIBC) || defined(CONFIG_ARCMWDT_LIBC) +#if defined(CONFIG_NEWLIB_LIBC) || defined(CONFIG_ARCMWDT_LIBC) || defined(CONFIG_PICOLIBC) /* syscall generation ignores preprocessor, ensure this is defined to ensure * we don't have compile errors @@ -56,7 +56,21 @@ extern struct k_mem_partition z_malloc_partition; */ #define Z_MALLOC_PARTITION_EXISTS 1 #endif /* CONFIG_MINIMAL_LIBC_MALLOC_ARENA_SIZE > 0 */ -#endif /* CONFIG_MINIMAL_LIBC */ +#elif defined(CONFIG_PICOLIBC) +/* If we are using picolibc, the heap arena is in one of two areas: + * - If we have an MPU that requires power of two alignment, the heap bounds + * must be specified in Kconfig via CONFIG_PICOLIBC_ALIGNED_HEAP_SIZE. + * - Otherwise, the heap arena on most arches starts at a suitably + * aligned base addreess after the `_end` linker symbol, through to the end + * of system RAM. + */ +#if (!defined(CONFIG_MPU_REQUIRES_POWER_OF_TWO_ALIGNMENT) || \ +(defined(CONFIG_MPU_REQUIRES_POWER_OF_TWO_ALIGNMENT) && \ +CONFIG_PICOLIBC_ALIGNED_HEAP_SIZE)) +#define Z_MALLOC_PARTITION_EXISTS 1 +extern struct k_mem_partition z_malloc_partition; +#endif +#endif /* CONFIG_PICOLIBC */ #ifdef Z_MALLOC_PARTITION_EXISTS /* Memory partition containing the libc malloc arena. Configuration controls @@ -66,7 +80,7 @@ extern struct k_mem_partition z_malloc_partition; #endif #if defined(CONFIG_NEWLIB_LIBC) || defined(CONFIG_STACK_CANARIES) || \ - defined(CONFIG_NEED_LIBC_MEM_PARTITION) +defined(CONFIG_PICOLIBC) || defined(CONFIG_NEED_LIBC_MEM_PARTITION) /* - All newlib globals will be placed into z_libc_partition. * - Minimal C library globals, if any, will be placed into * z_libc_partition. diff --git a/include/sys/printk.h b/include/sys/printk.h index 34529f877de1fb..cd1b162d6d4ab4 100644 --- a/include/sys/printk.h +++ b/include/sys/printk.h @@ -60,11 +60,22 @@ static inline __printf_like(1, 0) void vprintk(const char *fmt, va_list ap) } #endif +#ifdef _PICOLIBC__ + +#include + +#define snprintk(...) snprintf(__VA_ARGS__) +#define vsnprintk(str, size, fmt, ap) vsnprintf(str, size, fmt, ap) + +#else + extern __printf_like(3, 4) int snprintk(char *str, size_t size, const char *fmt, ...); extern __printf_like(3, 0) int vsnprintk(char *str, size_t size, const char *fmt, va_list ap); +#endif + #ifdef __cplusplus } #endif diff --git a/kernel/Kconfig b/kernel/Kconfig index 559cc05f37c8c7..4db82ffcc0213e 100644 --- a/kernel/Kconfig +++ b/kernel/Kconfig @@ -202,9 +202,17 @@ config THREAD_USERSPACE_LOCAL_DATA depends on USERSPACE default y if ERRNO && !ERRNO_IN_TLS +config LIBC_ERRNO + bool + help + Use external libc errno, not the internal one. This makes sure that + ERRNO is not set for libc configurations that provide their own + implementation. + config ERRNO bool "Errno support" default y + depends on !LIBC_ERRNO help Enable per-thread errno in the kernel. Application and library code must include errno.h provided by the C library (libc) to use the errno diff --git a/kernel/errno.c b/kernel/errno.c index 84f78593dc1763..07a8684ddd6c8c 100644 --- a/kernel/errno.c +++ b/kernel/errno.c @@ -44,10 +44,13 @@ static inline int *z_vrfy_z_errno(void) #include #else +#ifndef CONFIG_LIBC_ERRNO int *z_impl_z_errno(void) { return &_current->errno_var; } +#endif /* CONFIG_PICOLIBC */ + #endif /* CONFIG_USERSPACE */ #endif /* CONFIG_ERRNO_IN_TLS */ diff --git a/lib/libc/CMakeLists.txt b/lib/libc/CMakeLists.txt index fe72c26f7aa7dc..f8600b62c45e7c 100644 --- a/lib/libc/CMakeLists.txt +++ b/lib/libc/CMakeLists.txt @@ -8,4 +8,6 @@ elseif(CONFIG_MINIMAL_LIBC) add_subdirectory(minimal) elseif(CONFIG_ARMCLANG_STD_LIBC) add_subdirectory(armstdc) +elseif(CONFIG_PICOLIBC) + add_subdirectory(picolibc) endif() diff --git a/lib/libc/Kconfig b/lib/libc/Kconfig index 1bb1f87e747ef7..1098b52d24866f 100644 --- a/lib/libc/Kconfig +++ b/lib/libc/Kconfig @@ -29,6 +29,15 @@ config MINIMAL_LIBC help Build with minimal C library. +config PICOLIBC + bool "Picolibc library" + depends on !NATIVE_APPLICATION + select THREAD_LOCAL_STORAGE if ARCH_HAS_THREAD_LOCAL_STORAGE + select LIBC_ERRNO + help + Build with picolibc library. The picolibc library is expected to be + part of the SDK in this case. + config NEWLIB_LIBC bool "Newlib C library" depends on !NATIVE_APPLICATION @@ -53,6 +62,30 @@ endchoice # LIBC_IMPLEMENTATION config HAS_NEWLIB_LIBC_NANO bool +if PICOLIBC + +config PICOLIBC_INTEGER_PRINTF + bool "Build with picolibc integer-only printf" + help + Build with floating point printf disabled. This will reduce the size + of the image. + +config PICOLIBC_ALIGNED_HEAP_SIZE + int "Picolibc aligned heap size (bytes)" + depends on MPU_REQUIRES_POWER_OF_TWO_ALIGNMENT + depends on USERSPACE + default 0 + help + If user mode is enabled, and MPU hardware has requirements that + regions be sized to a power of two and aligned to their size, + and user mode threads need to access this heap, then this is necessary + to properly define an MPU region for the heap. + + If this is left at 0, then remaining system RAM will be used for this + area and it may not be possible to program it as an MPU region. + +endif # PICOLIBC + if NEWLIB_LIBC config NEWLIB_LIBC_NANO diff --git a/lib/libc/picolibc/CMakeLists.txt b/lib/libc/picolibc/CMakeLists.txt new file mode 100644 index 00000000000000..ff57fcfde31862 --- /dev/null +++ b/lib/libc/picolibc/CMakeLists.txt @@ -0,0 +1,41 @@ +# SPDX-License-Identifier: Apache-2.0 + +zephyr_library() +zephyr_library_sources(libc-hooks.c) + +# Zephyr normally uses -ffreestanding, which with current GNU toolchains +# means that the flag macros used by picolibc to signal +# support for PRI.64 macros are not present. To make them available we +# need to hook into the include path before the system files and +# explicitly include the picolibc header that provides those macros. +zephyr_include_directories(include) + +# define __LINUX_ERRNO_EXTENSIONS__ so we get errno defines like -ESHUTDOWN +# used by the network stack +zephyr_compile_definitions(__LINUX_ERRNO_EXTENSIONS__) + +zephyr_link_libraries( + m + c + gcc # Lib C depends on libgcc. + ) + +# The -T/dev/null avoids pulling in picolibc.ld +zephyr_link_libraries( + --specs=picolibc.specs + -T/dev/null + ) + +zephyr_compile_options( + --specs=picolibc.specs + -D_GNU_SOURCE + ) + +if(CONFIG_PICOLIBC_INTEGER_PRINTF) + zephyr_compile_options( + -DPICOLIBC_INTEGER_PRINTF_SCANF + ) + zephyr_link_libraries( + -DPICOLIBC_INTEGER_PRINTF_SCANF + ) +endif() diff --git a/lib/libc/picolibc/libc-hooks.c b/lib/libc/picolibc/libc-hooks.c new file mode 100644 index 00000000000000..2a57e613976d35 --- /dev/null +++ b/lib/libc/picolibc/libc-hooks.c @@ -0,0 +1,319 @@ +/* + * Copyright © 2021, Keith Packard + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define LIBC_BSS K_APP_BMEM(z_libc_partition) +#define LIBC_DATA K_APP_DMEM(z_libc_partition) + +#if CONFIG_PICOLIBC_ALIGNED_HEAP_SIZE +K_APPMEM_PARTITION_DEFINE(z_malloc_partition); +#define MALLOC_BSS K_APP_BMEM(z_malloc_partition) + +/* Compiler will throw an error if the provided value isn't a power of two */ +MALLOC_BSS static unsigned char __aligned(CONFIG_PICOLIBC_ALIGNED_HEAP_SIZE) + heap_base[CONFIG_PICOLIBC_ALIGNED_HEAP_SIZE]; +#define MAX_HEAP_SIZE CONFIG_PICOLIBC_ALIGNED_HEAP_SIZE + +#else /* CONFIG_PICOLIBC_ALIGNED_HEAP_SIZE */ +/* 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) + +#ifdef Z_MALLOC_PARTITION_EXISTS +/* Need to be able to program a memory protection region from HEAP_BASE + * to the end of RAM so that user threads can get at it. + * Implies that the base address needs to be suitably aligned since the + * bounds have to go in a k_mem_partition. + */ +#ifdef CONFIG_MMU +/* Linker script may already have done this, but just to be safe */ +#define HEAP_BASE ROUND_UP(USED_RAM_END_ADDR, CONFIG_MMU_PAGE_SIZE) +#else /* MPU-based systems */ +/* TODO: Need a generic Kconfig for the MPU region granularity */ +#if defined(CONFIG_ARM) +#define HEAP_BASE ROUND_UP(USED_RAM_END_ADDR, \ + CONFIG_ARM_MPU_REGION_MIN_ALIGN_AND_SIZE) +#elif defined(CONFIG_ARC) +#define HEAP_BASE ROUND_UP(USED_RAM_END_ADDR, Z_ARC_MPU_ALIGN) +#else +#error "Unsupported platform" +#endif /* CONFIG_ */ +#endif /* !CONFIG_MMU */ +#else /* !Z_MALLOC_PARTITION_EXISTS */ +/* No partition, heap can just start wherever _end is */ +#define HEAP_BASE USED_RAM_END_ADDR +#endif /* Z_MALLOC_PARTITION_EXISTS */ + +#ifdef CONFIG_XTENSA +extern void *_heap_sentry; +#define MAX_HEAP_SIZE (POINTER_TO_UINT(&_heap_sentry) - HEAP_BASE) +#else +#define MAX_HEAP_SIZE (KB(CONFIG_SRAM_SIZE) - \ + (HEAP_BASE - CONFIG_SRAM_BASE_ADDRESS)) +#endif + +#if Z_MALLOC_PARTITION_EXISTS +struct k_mem_partition z_malloc_partition; + +static int malloc_prepare(const struct device *unused) +{ + ARG_UNUSED(unused); + + z_malloc_partition.start = 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 /* CONFIG_USERSPACE */ +#endif /* CONFIG_PICOLIBC_ALIGNED_HEAP_SIZE */ + +LIBC_BSS static unsigned int heap_sz; + +static int (*put_hook)(int); + +static int picolibc_put(char a, FILE *out) +{ + (*put_hook)(a); + return 0; +} + +static FILE __stdio = FDEV_SETUP_STREAM(picolibc_put, NULL, NULL, 0); + +#ifdef __strong_reference +#define STDIO_ALIAS(x) __strong_reference(stdin, x); +#else +#define STDIO_ALIAS(x) FILE *const x = &__stdio; +#endif + +FILE *const stdin = &__stdio; +STDIO_ALIAS(stdout); +STDIO_ALIAS(stderr); + +void __stdout_hook_install(int (*hook)(int)) +{ + put_hook = hook; + __stdio.flags |= _FDEV_SETUP_WRITE; +} + +void __stdin_hook_install(unsigned char (*hook)(void)) +{ + __stdio.get = (int (*)(FILE *)) hook; + __stdio.flags |= _FDEV_SETUP_READ; +} + +int z_impl_zephyr_read_stdin(char *buf, int nbytes) +{ + int i = 0; + + for (i = 0; i < nbytes; i++) { + *(buf + i) = getchar(); + if ((*(buf + i) == '\n') || (*(buf + i) == '\r')) { + i++; + break; + } + } + return i; +} + +int z_impl_zephyr_write_stdout(const void *buffer, int nbytes) +{ + const char *buf = buffer; + int i; + + for (i = 0; i < nbytes; i++) { + if (*(buf + i) == '\n') { + putchar('\r'); + } + putchar(*(buf + i)); + } + return nbytes; +} + +static FILE __console = FDEV_SETUP_STREAM(NULL, NULL, NULL, 0); + +void __printk_hook_install(int (*fn)(int)) +{ + __console.put = (int(*)(char, FILE *)) fn; + __console.flags |= _FDEV_SETUP_WRITE; +} + +void vprintk(const char *fmt, va_list ap) +{ + vfprintf(&__console, fmt, ap); +} + +void printk(const char *fmt, ...) +{ + va_list ap; + + va_start(ap, fmt); + vfprintf(&__console, fmt, ap); + va_end(ap); +} + +#include + +struct cb_bits { + FILE f; + cbprintf_cb out; + void *ctx; +}; + +static int cbputc(char c, FILE *_s) +{ + struct cb_bits *s = (struct cb_bits *) _s; + + (*s->out) (c, s->ctx); + return 0; +} + +int cbvprintf(cbprintf_cb out, void *ctx, const char *fp, va_list ap) +{ + struct cb_bits s = { + .f = FDEV_SETUP_STREAM(cbputc, NULL, NULL, _FDEV_SETUP_WRITE), + .out = out, + .ctx = ctx, + }; + return vfprintf(&s.f, fp, ap); +} + +#ifndef CONFIG_POSIX_API +int _read(int fd, char *buf, int nbytes) +{ + ARG_UNUSED(fd); + + return z_impl_zephyr_read_stdin(buf, nbytes); +} +__weak FUNC_ALIAS(_read, read, int); + +int _write(int fd, const void *buf, int nbytes) +{ + ARG_UNUSED(fd); + + return z_impl_zephyr_write_stdout(buf, nbytes); +} +__weak FUNC_ALIAS(_write, write, int); + +int _open(const char *name, int mode) +{ + return -1; +} +__weak FUNC_ALIAS(_open, open, int); + +int _close(int file) +{ + return -1; +} +__weak FUNC_ALIAS(_close, close, int); + +int _lseek(int file, int ptr, int dir) +{ + return 0; +} +__weak FUNC_ALIAS(_lseek, lseek, int); +#else +extern ssize_t write(int file, const char *buffer, size_t count); +#define _write write +#endif + +int _isatty(int file) +{ + return 1; +} +__weak FUNC_ALIAS(_isatty, isatty, int); + +int _kill(int i, int j) +{ + return 0; +} +__weak FUNC_ALIAS(_kill, kill, int); + +int _getpid(void) +{ + return 0; +} +__weak FUNC_ALIAS(_getpid, getpid, int); + +int _fstat(int file, struct stat *st) +{ + st->st_mode = S_IFCHR; + return 0; +} +__weak FUNC_ALIAS(_fstat, fstat, int); + +__weak void _exit(int status) +{ + _write(1, "exit\n", 5); + while (1) { + ; + } +} + +static LIBC_DATA SYS_SEM_DEFINE(heap_sem, 1, 1); + +void *_sbrk(int count) +{ + void *ret, *ptr; + + sys_sem_take(&heap_sem, K_FOREVER); + +#if CONFIG_PICOLIBC_ALIGNED_HEAP_SIZE + ptr = heap_base + heap_sz; +#else + ptr = ((char *)HEAP_BASE) + heap_sz; +#endif + + if ((heap_sz + count) < MAX_HEAP_SIZE) { + heap_sz += count; + ret = ptr; + } else { + ret = (void *)-1; + } + + /* coverity[CHECKED_RETURN] */ + sys_sem_give(&heap_sem); + + return ret; +} +__weak FUNC_ALIAS(_sbrk, sbrk, void *); + +/* This function gets called if static buffer overflow detection is enabled on + * stdlib side (Picolibc here), in case such an overflow is detected. Picolibc + * provides an implementation not suitable for us, so we override it here. + */ +__weak FUNC_NORETURN void __chk_fail(void) +{ + static const char chk_fail_msg[] = "* buffer overflow detected *\n"; + + _write(2, chk_fail_msg, sizeof(chk_fail_msg) - 1); + k_oops(); + CODE_UNREACHABLE; +} + +int _gettimeofday(struct timeval *__tp, void *__tzp) +{ + ARG_UNUSED(__tp); + ARG_UNUSED(__tzp); + + return -1; +} diff --git a/lib/os/CMakeLists.txt b/lib/os/CMakeLists.txt index 78202bbb7b4f06..207e17a84de589 100644 --- a/lib/os/CMakeLists.txt +++ b/lib/os/CMakeLists.txt @@ -14,7 +14,6 @@ zephyr_sources( fdtable.c hex.c notify.c - printk.c onoff.c rb.c sem.c @@ -26,8 +25,11 @@ zephyr_sources( multi_heap.c ) -zephyr_sources_ifdef(CONFIG_CBPRINTF_COMPLETE cbprintf_complete.c) -zephyr_sources_ifdef(CONFIG_CBPRINTF_NANO cbprintf_nano.c) +if(NOT CONFIG_PICOLIBC) + zephyr_sources(printk.c) + zephyr_sources_ifdef(CONFIG_CBPRINTF_COMPLETE cbprintf_complete.c) + zephyr_sources_ifdef(CONFIG_CBPRINTF_NANO cbprintf_nano.c) +endif() zephyr_sources_ifdef(CONFIG_JSON_LIBRARY json.c) diff --git a/lib/os/Kconfig.cbprintf b/lib/os/Kconfig.cbprintf index 4a4296c038d0ed..dd8a11d1172e04 100644 --- a/lib/os/Kconfig.cbprintf +++ b/lib/os/Kconfig.cbprintf @@ -3,6 +3,7 @@ choice CBPRINTF_IMPLEMENTATION prompt "Capabilities of cbprintf implementation" + depends on !PICOLIBC default CBPRINTF_COMPLETE config CBPRINTF_COMPLETE @@ -26,6 +27,7 @@ endchoice # CBPRINTF_IMPLEMENTATION choice CBPRINTF_INTEGRAL_CONV prompt "Control range of convertible integer values" + depends on !PICOLIBC default CBPRINTF_FULL_INTEGRAL # 01: 0% / 0 B (01 / 00) @@ -85,6 +87,7 @@ config CBPRINTF_FP_A_SUPPORT # 40: -15% / -508 B (46 / 06) config CBPRINTF_FP_ALWAYS_A bool "Select %a format for all floating point specifications" + depends on !PICOLIBC select CBPRINTF_FP_A_SUPPORT help The %a format for floats requires significantly less code than the @@ -107,6 +110,7 @@ config CBPRINTF_N_SPECIFIER # 180: 18% / 138 B (180 / 80) [NANO] config CBPRINTF_LIBC_SUBSTS bool "Generate C-library compatible functions using cbprintf" + depends on !PICOLIBC help If selected wrappers are generated for various C library functions using the cbprintf formatter underneath. The wrappers use the C diff --git a/tests/lib/c_lib/testcase.yaml b/tests/lib/c_lib/testcase.yaml index 33dfe0983a9b64..f63cb476533151 100644 --- a/tests/lib/c_lib/testcase.yaml +++ b/tests/lib/c_lib/testcase.yaml @@ -2,3 +2,9 @@ tests: libraries.libc: tags: clib ignore_faults platform_exclude: native_posix native_posix_64 nrf52_bsim + libraries.picolibc: + tags: clib picolibc ignore_faults + platform_exclude: native_posix native_posix_64 nrf52_bsim + extra_configs: + - CONFIG_PICOLIBC=y + - CONFIG_PICOLIBC_ALIGNED_HEAP_SIZE=8192 diff --git a/tests/lib/mem_alloc/prj_picolibc.conf b/tests/lib/mem_alloc/prj_picolibc.conf new file mode 100644 index 00000000000000..bca686c990bd6f --- /dev/null +++ b/tests/lib/mem_alloc/prj_picolibc.conf @@ -0,0 +1,4 @@ +CONFIG_ZTEST=y +CONFIG_PICOLIBC=y +CONFIG_PICOLIBC_ALIGNED_HEAP_SIZE=8192 +CONFIG_TEST_USERSPACE=y diff --git a/tests/lib/mem_alloc/testcase.yaml b/tests/lib/mem_alloc/testcase.yaml index 8738372cae9047..32d1619501c31b 100644 --- a/tests/lib/mem_alloc/testcase.yaml +++ b/tests/lib/mem_alloc/testcase.yaml @@ -20,3 +20,9 @@ tests: arch_exclude: posix platform_exclude: twr_ke18f native_posix_64 nrf52_bsim tags: clib minimal_libc userspace + libraries.libc.picolibc: + extra_args: CONF_FILE=prj_picolibc.conf + arch_exclude: posix + platform_exclude: twr_ke18f native_posix_64 nrf52_bsim + tags: clib picolibc userspace + filter: TOOLCHAIN_HAS_PICOLIBC == 1 diff --git a/tests/lib/sprintf/prj_picolibc.conf b/tests/lib/sprintf/prj_picolibc.conf new file mode 100644 index 00000000000000..fd34803103ff01 --- /dev/null +++ b/tests/lib/sprintf/prj_picolibc.conf @@ -0,0 +1,3 @@ +CONFIG_ZTEST=y +CONFIG_PICOLIBC=y +CONFIG_PICOLIBC_ALIGNED_HEAP_SIZE=8192 diff --git a/tests/lib/sprintf/src/main.c b/tests/lib/sprintf/src/main.c index aaa1e7ceafa895..21b094db58927c 100644 --- a/tests/lib/sprintf/src/main.c +++ b/tests/lib/sprintf/src/main.c @@ -537,6 +537,7 @@ void test_sprintf_misc(void) if (IS_MINIMAL_LIBC_NANO) { TC_PRINT(" MINIMAL_LIBC+CPBPRINTF skipped tests\n"); } else { +#ifndef CONFIG_PICOLIBC sprintf(buffer, "test data %n test data", &count); zassert_false((count != 10), "sprintf(%%n). Expected count to be %d, not %d", @@ -545,6 +546,13 @@ void test_sprintf_misc(void) zassert_false((strcmp(buffer, "test data test data") != 0), "sprintf(%%p). Expected '%s', got '%s'", "test data test data", buffer); +#else + /* + * Picolibc doesn't include %n support as it makes format string + * bugs a more serious security issue + */ + (void) count; +#endif /*******************/ diff --git a/tests/lib/sprintf/testcase.yaml b/tests/lib/sprintf/testcase.yaml index aff5053617bf0c..2e841ccb4b7964 100644 --- a/tests/lib/sprintf/testcase.yaml +++ b/tests/lib/sprintf/testcase.yaml @@ -10,3 +10,7 @@ tests: extra_args: CONF_FILE=prj_new.conf tags: libc platform_exclude: native_posix native_posix_64 nrf52_bsim + libraries.picolibc.sprintf: + extra_args: CONF_FILE=prj_picolibc.conf + tags: clib ignore_faults picolibc + platform_exclude: native_posix native_posix_64 nrf52_bsim diff --git a/tests/posix/common/testcase.yaml b/tests/posix/common/testcase.yaml index 9d875d4a38c6c5..ceab1c307eba60 100644 --- a/tests/posix/common/testcase.yaml +++ b/tests/posix/common/testcase.yaml @@ -43,3 +43,8 @@ tests: extra_configs: - CONFIG_NEWLIB_LIBC=y - CONFIG_TEST_HW_STACK_PROTECTION=n + portability.posix.common.picolibc: + platform_exclude: nsim_sem_mpu_stack_guard nsim_em_mpu_stack_guard + extra_configs: + - CONFIG_PICOLIBC=y + - CONFIG_PICOLIBC_ALIGNED_HEAP_SIZE=8192