From 7b1100db2d398e2c3ed7587f7d8f43fb85e8a349 Mon Sep 17 00:00:00 2001 From: Alexey Lapshin Date: Thu, 11 Dec 2025 10:13:30 +0700 Subject: [PATCH] fix(newlib): adapt changes --- .../include/esp32h21/rom/libc_stubs.h | 15 +- .../lwip/port/hooks/lwip_default_hooks.c | 2 + components/newlib/CMakeLists.txt | 49 ++++-- components/newlib/Kconfig | 20 ++- components/newlib/platform_include/ctype.h | 41 +++++ .../newlib/platform_include/stdatomic.h | 20 +++ .../newlib/platform_include/sys/dirent.h | 70 -------- components/newlib/platform_include/sys/lock.h | 8 +- .../newlib/platform_include/sys/select.h | 4 + .../{src => priv_include}/string/local.h | 2 + components/newlib/sbom.yml | 2 +- components/newlib/src/assert.c | 3 +- components/newlib/src/esp_libc.lf | 21 +++ components/newlib/src/getentropy.c | 1 + ...sp32-spiram-rom-functions-c.lf => libc.lf} | 4 - components/newlib/src/newlib.lf | 11 -- components/newlib/src/newlib_init.c | 2 +- ...sp32-spiram-rom-functions-c.lf => libc.lf} | 0 .../newlib/src/picolibc/picolibc_init.c | 3 +- components/newlib/src/port/riscv/memcpy.c | 96 ++++++++--- components/newlib/src/port/riscv/memmove.c | 150 ++++++++++++++++ components/newlib/src/port/riscv/strcpy.c | 4 +- components/newlib/src/pthread.c | 6 +- components/newlib/src/reent_syscalls.c | 1 + components/newlib/src/string/memcmp.c | 3 +- components/newlib/src/string/memmove.c | 88 ---------- components/newlib/src/string/strncmp.c | 3 +- components/newlib/src/string/strncpy.c | 4 +- components/newlib/src/syscalls.c | 6 +- .../newlib/test_apps/.build-test-rules.yml | 7 - .../newlib/main/test_misaligned_access.c | 162 ++++++++++++++++++ .../test_apps/newlib/main/test_newlib.c | 1 + .../test_apps/no_rvfplib/CMakeLists.txt | 10 ++ .../newlib/test_apps/no_rvfplib/README.md | 6 + .../test_apps/no_rvfplib/main/CMakeLists.txt | 2 + .../test_apps/no_rvfplib/main/test_main.c | 8 + .../test_apps/no_rvfplib/sdkconfig.ci.default | 2 + components/soc/project_include.cmake | 16 +- 38 files changed, 587 insertions(+), 266 deletions(-) create mode 100644 components/newlib/platform_include/ctype.h create mode 100644 components/newlib/platform_include/stdatomic.h delete mode 100644 components/newlib/platform_include/sys/dirent.h rename components/newlib/{src => priv_include}/string/local.h (98%) create mode 100644 components/newlib/src/esp_libc.lf rename components/newlib/src/{esp32-spiram-rom-functions-c.lf => libc.lf} (97%) delete mode 100644 components/newlib/src/newlib.lf rename components/newlib/src/picolibc/{esp32-spiram-rom-functions-c.lf => libc.lf} (100%) create mode 100644 components/newlib/src/port/riscv/memmove.c delete mode 100644 components/newlib/src/string/memmove.c delete mode 100644 components/newlib/test_apps/.build-test-rules.yml create mode 100644 components/newlib/test_apps/newlib/main/test_misaligned_access.c create mode 100644 components/newlib/test_apps/no_rvfplib/CMakeLists.txt create mode 100644 components/newlib/test_apps/no_rvfplib/README.md create mode 100644 components/newlib/test_apps/no_rvfplib/main/CMakeLists.txt create mode 100644 components/newlib/test_apps/no_rvfplib/main/test_main.c create mode 100644 components/newlib/test_apps/no_rvfplib/sdkconfig.ci.default diff --git a/components/esp_rom/esp32h21/include/esp32h21/rom/libc_stubs.h b/components/esp_rom/esp32h21/include/esp32h21/rom/libc_stubs.h index 8b2b9ebd63..3b6db54495 100644 --- a/components/esp_rom/esp32h21/include/esp32h21/rom/libc_stubs.h +++ b/components/esp_rom/esp32h21/include/esp32h21/rom/libc_stubs.h @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: 2024 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2024-2025 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ @@ -57,7 +57,6 @@ struct syscall_stub_table int (*_write_r)(struct _reent *r, int, const void *, int); int (*_lseek_r)(struct _reent *r, int, int, int); int (*_read_r)(struct _reent *r, int, void *, int); -#ifdef _RETARGETABLE_LOCKING void (*_retarget_lock_init)(_LOCK_T *lock); void (*_retarget_lock_init_recursive)(_LOCK_T *lock); void (*_retarget_lock_close)(_LOCK_T lock); @@ -68,18 +67,6 @@ struct syscall_stub_table int (*_retarget_lock_try_acquire_recursive)(_LOCK_T lock); void (*_retarget_lock_release)(_LOCK_T lock); void (*_retarget_lock_release_recursive)(_LOCK_T lock); -#else - void (*_lock_init)(_lock_t *lock); - void (*_lock_init_recursive)(_lock_t *lock); - void (*_lock_close)(_lock_t *lock); - void (*_lock_close_recursive)(_lock_t *lock); - void (*_lock_acquire)(_lock_t *lock); - void (*_lock_acquire_recursive)(_lock_t *lock); - int (*_lock_try_acquire)(_lock_t *lock); - int (*_lock_try_acquire_recursive)(_lock_t *lock); - void (*_lock_release)(_lock_t *lock); - void (*_lock_release_recursive)(_lock_t *lock); -#endif int (*_printf_float)(struct _reent *data, void *pdata, FILE * fp, int (*pfunc) (struct _reent *, FILE *, const char *, size_t len), va_list * ap); int (*_scanf_float) (struct _reent *rptr, void *pdata, FILE *fp, va_list *ap); void (*__assert_func) (const char *file, int line, const char * func, const char *failedexpr) __attribute__((noreturn)); diff --git a/components/lwip/port/hooks/lwip_default_hooks.c b/components/lwip/port/hooks/lwip_default_hooks.c index 180c15a632..1ec6e75814 100644 --- a/components/lwip/port/hooks/lwip_default_hooks.c +++ b/components/lwip/port/hooks/lwip_default_hooks.c @@ -11,7 +11,9 @@ #include "esp_log.h" #include +#ifndef __weak #define __weak __attribute__((weak)) +#endif /** * Default lwip behavior is to silence LWIP_ERROR() if LWIP_DEBUG is not set. diff --git a/components/newlib/CMakeLists.txt b/components/newlib/CMakeLists.txt index 29363db53e..658fa4c85f 100644 --- a/components/newlib/CMakeLists.txt +++ b/components/newlib/CMakeLists.txt @@ -39,18 +39,19 @@ endif() if(CONFIG_LIBC_OPTIMIZED_MISALIGNED_ACCESS) list(APPEND srcs - "src/string/memcmp.c" - "src/string/memmove.c" - "src/string/strncmp.c" - "src/string/strncpy.c" "src/port/riscv/memcpy.c" + "src/port/riscv/memmove.c" + "src/string/memcmp.c" "src/port/riscv/strcpy.c" + "src/string/strncpy.c" + "src/string/strncmp.c" "src/port/riscv/strcmp.S") - list(APPEND EXTRA_LINK_FLAGS "-u esp_libc_include_memcmp_impl") + list(APPEND EXTRA_LINK_FLAGS "-u esp_libc_include_memcpy_impl") list(APPEND EXTRA_LINK_FLAGS "-u esp_libc_include_memmove_impl") - list(APPEND EXTRA_LINK_FLAGS "-u esp_libc_include_strncmp_impl") - list(APPEND EXTRA_LINK_FLAGS "-u esp_libc_include_strncpy_impl") + list(APPEND EXTRA_LINK_FLAGS "-u esp_libc_include_memcmp_impl") list(APPEND EXTRA_LINK_FLAGS "-u esp_libc_include_strcpy_impl") + list(APPEND EXTRA_LINK_FLAGS "-u esp_libc_include_strncpy_impl") + list(APPEND EXTRA_LINK_FLAGS "-u esp_libc_include_strncmp_impl") list(APPEND EXTRA_LINK_FLAGS "-u esp_libc_include_strcmp_impl") endif() @@ -70,21 +71,28 @@ else() endif() endif() -list(APPEND ldfragments "src/newlib.lf" "src/system_libs.lf") +set(ldfragments "") +list(APPEND ldfragments "src/esp_libc.lf" "src/system_libs.lf") -if(CONFIG_SPIRAM_CACHE_WORKAROUND) - if(CONFIG_LIBC_NEWLIB) - list(APPEND ldfragments src/esp32-spiram-rom-functions-c.lf) - list(APPEND ldfragments src/libm.lf) - else() - list(APPEND ldfragments src/picolibc/esp32-spiram-rom-functions-c.lf) +if(CONFIG_LIBC_NEWLIB) + list(APPEND ldfragments src/libc.lf) + list(APPEND ldfragments src/libm.lf) +else() + list(APPEND ldfragments src/picolibc/libc.lf) +endif() + +set(priv_reqs soc spi_flash) + +if(IDF_BUILD_V2) + if(CONFIG_VFS_SUPPORT_IO) + list(APPEND priv_reqs vfs) endif() endif() idf_component_register(SRCS "${srcs}" INCLUDE_DIRS platform_include PRIV_INCLUDE_DIRS priv_include - PRIV_REQUIRES soc spi_flash + PRIV_REQUIRES "${priv_reqs}" LDFRAGMENTS "${ldfragments}") # Toolchain libraries require code defined in this component @@ -98,6 +106,17 @@ if(CONFIG_STDATOMIC_S32C1I_SPIRAM_WORKAROUND) PROPERTIES COMPILE_FLAGS "-mno-disable-hardware-atomics") endif() +if(CONFIG_LIBC_OPTIMIZED_MISALIGNED_ACCESS) + # TODO GCC-419 and IDF-13089: cleanup files + set_source_files_properties("src/string/memcmp.c" + "src/string/strncmp.c" + "src/string/strncpy.c" + "src/port/riscv/memcpy.c" + "src/port/riscv/memmove.c" + "src/port/riscv/strcpy.c" + PROPERTIES COMPILE_FLAGS -O2) +endif() + # Forces the linker to include heap, syscall, pthread, assert, and retargetable locks from this component, # instead of the implementations provided by newlib. list(APPEND EXTRA_LINK_FLAGS "-u esp_libc_include_heap_impl") diff --git a/components/newlib/Kconfig b/components/newlib/Kconfig index 17e9d38358..2b333eebed 100644 --- a/components/newlib/Kconfig +++ b/components/newlib/Kconfig @@ -174,13 +174,13 @@ menu "LibC" config LIBC_OPTIMIZED_MISALIGNED_ACCESS bool "Use performance-optimized memXXX/strXXX functions on misaligned memory access" - default n + default y depends on ESP_ROM_HAS_SUBOPTIMAL_NEWLIB_ON_MISALIGNED_MEMORY help Enables performance-optimized implementations of memory and string functions when handling misaligned memory. - This increases the image size by ~1000 bytes. + Require approximately 800–1000 bytes of IRAM. Optimized functions include: - memcpy @@ -189,6 +189,22 @@ menu "LibC" - str[n]cpy - str[n]cmp + config LIBC_ASSERT_BUFFER_SIZE + int "Assert message buffer size" + range 100 2048 + default 200 + help + Size of the buffer used to format assert failure messages. + + When assertions fail, the system formats a message containing the function name, + file name, line number, and the failed expression. This option controls the + maximum length of this message. + + If you encounter truncated assert messages (especially with C++ templates or + long function names), increase this value. The default value of 200 bytes + should be sufficient for most cases, but complex template expressions may + require larger buffers. + endmenu # LibC config STDATOMIC_S32C1I_SPIRAM_WORKAROUND diff --git a/components/newlib/platform_include/ctype.h b/components/newlib/platform_include/ctype.h new file mode 100644 index 0000000000..18eb252128 --- /dev/null +++ b/components/newlib/platform_include/ctype.h @@ -0,0 +1,41 @@ +/* + * SPDX-FileCopyrightText: 2025 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ +#include "sdkconfig.h" +#include_next + +#if CONFIG_LIBC_PICOLIBC_NEWLIB_COMPATIBILITY +#ifndef _U +#define _U __CTYPE_UPPER +#endif + +#ifndef _L +#define _L __CTYPE_LOWER +#endif + +#ifndef _N +#define _N __CTYPE_DIGIT +#endif + +#ifndef _S +#define _S __CTYPE_SPACE +#endif + +#ifndef _P +#define _P __CTYPE_PUNCT +#endif + +#ifndef _C +#define _C __CTYPE_CNTRL +#endif + +#ifndef _X +#define _X __CTYPE_HEX +#endif + +#ifndef _B +#define _B __CTYPE_BLANK +#endif +#endif diff --git a/components/newlib/platform_include/stdatomic.h b/components/newlib/platform_include/stdatomic.h new file mode 100644 index 0000000000..6ec881daab --- /dev/null +++ b/components/newlib/platform_include/stdatomic.h @@ -0,0 +1,20 @@ +/* + * SPDX-FileCopyrightText: 2025 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ +#pragma once +#include_next + +/* The ATOMIC_VAR_INIT macro was deprecated in: + * - C17 + * - C++20 + * and removed in subsequent standards. + * Since users may change the standard version for their projects, + * IDF should remain compatible across different standards. + */ +#if __STDC_VERSION__ > 201710L || __cplusplus > 202002L +# ifndef ATOMIC_VAR_INIT +# define ATOMIC_VAR_INIT(val) (val) +# endif +#endif diff --git a/components/newlib/platform_include/sys/dirent.h b/components/newlib/platform_include/sys/dirent.h deleted file mode 100644 index 2643ddc954..0000000000 --- a/components/newlib/platform_include/sys/dirent.h +++ /dev/null @@ -1,70 +0,0 @@ -/* - * SPDX-FileCopyrightText: 2015-2024 Espressif Systems (Shanghai) CO LTD - * - * SPDX-License-Identifier: Apache-2.0 - */ -#ifdef __clang__ // TODO LLVM-330 -#pragma once - -#include -#include -#include - -/** - * This header file provides POSIX-compatible definitions of directory - * access data types. Starting with newlib 3.3, related functions are defined - * in 'dirent.h' bundled with newlib. - * See http://pubs.opengroup.org/onlinepubs/7908799/xsh/dirent.h.html - * for reference. - */ - -#ifdef __cplusplus -extern "C" { -#endif - -/** - * @brief Opaque directory structure - */ -typedef struct { - uint16_t dd_vfs_idx; /*!< VFS index, not to be used by applications */ - uint16_t dd_rsv; /*!< field reserved for future extension */ - /* remaining fields are defined by VFS implementation */ -} DIR; - -/** - * @brief Directory entry structure - */ -struct dirent { - ino_t d_ino; /*!< file number */ - uint8_t d_type; /*!< not defined in POSIX, but present in BSD and Linux */ -#define DT_UNKNOWN 0 -#define DT_REG 1 -#define DT_DIR 2 -#if __BSD_VISIBLE -#define MAXNAMLEN 255 - char d_name[MAXNAMLEN + 1]; /*!< zero-terminated file name */ -#else - char d_name[256]; -#endif -}; - -DIR* opendir(const char* name); -struct dirent* readdir(DIR* pdir); -long telldir(DIR* pdir); -void seekdir(DIR* pdir, long loc); -void rewinddir(DIR* pdir); -int closedir(DIR* pdir); -int readdir_r(DIR* pdir, struct dirent* entry, struct dirent** out_dirent); -int scandir(const char *dirname, struct dirent ***out_dirlist, - int (*select_func)(const struct dirent *), - int (*cmp_func)(const struct dirent **, const struct dirent **)); -int alphasort(const struct dirent **d1, const struct dirent **d2); - -#ifdef __cplusplus -} -#endif - -#else // __clang__ TODO: IDF-10675 -#include_next -#include -#endif // __clang__ diff --git a/components/newlib/platform_include/sys/lock.h b/components/newlib/platform_include/sys/lock.h index aed4d2c183..9674232136 100644 --- a/components/newlib/platform_include/sys/lock.h +++ b/components/newlib/platform_include/sys/lock.h @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: 2022-2024 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2022-2025 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ @@ -12,7 +12,7 @@ extern "C" { #endif -#ifdef _RETARGETABLE_LOCKING +#if defined(_RETARGETABLE_LOCKING) || defined(CONFIG_LIBC_PICOLIBC) /* Actual platfrom-specific definition of struct __lock. * The size here should be sufficient for a FreeRTOS mutex. @@ -52,10 +52,6 @@ int _lock_try_acquire_recursive(_lock_t *plock); void _lock_release(_lock_t *plock); void _lock_release_recursive(_lock_t *plock); -#if CONFIG_LIBC_PICOLIBC -#define __lock_try_acquire(lock) _lock_try_acquire(&(lock)) -#define __lock_try_acquire_recursive(lock) _lock_try_acquire_recursive(&(lock)) -#endif // CONFIG_LIBC_PICOLIBC #endif // _RETARGETABLE_LOCKING #ifdef __cplusplus diff --git a/components/newlib/platform_include/sys/select.h b/components/newlib/platform_include/sys/select.h index e4d828b711..2eeab9092f 100644 --- a/components/newlib/platform_include/sys/select.h +++ b/components/newlib/platform_include/sys/select.h @@ -26,6 +26,10 @@ int select(int nfds, fd_set *readfds, fd_set *writefds, fd_set *errorfds, struct #endif // fd_set +#if __BSD_VISIBLE && !defined(fds_bits) +#define fds_bits __fds_bits +#endif + #if defined(FD_ISSET) || defined(FD_SET) || defined(FD_CLR) #undef FD_SET #undef FD_CLR diff --git a/components/newlib/src/string/local.h b/components/newlib/priv_include/string/local.h similarity index 98% rename from components/newlib/src/string/local.h rename to components/newlib/priv_include/string/local.h index bfc1260efc..d6df832838 100644 --- a/components/newlib/src/string/local.h +++ b/components/newlib/priv_include/string/local.h @@ -22,7 +22,9 @@ * to avoid small performance penalties (if they are not zero). */ #define UNALIGNED_X(X) ((long)X & (sizeof (long) - 1)) +#ifndef _HAVE_HW_MISALIGNED_ACCESS #define _HAVE_HW_MISALIGNED_ACCESS (__riscv_misaligned_fast || __riscv_misaligned_slow) +#endif #if _HAVE_HW_MISALIGNED_ACCESS /* Hardware performs unaligned operations with little diff --git a/components/newlib/sbom.yml b/components/newlib/sbom.yml index 6c88c6fa0c..a269a621e0 100644 --- a/components/newlib/sbom.yml +++ b/components/newlib/sbom.yml @@ -4,4 +4,4 @@ originator: 'Organization: Espressif Systems (Shanghai) CO LTD' description: An open-source C standard library implementation with additional features and patches from Espressif. virtpackages: - sbom_newlibc.yml - - sbom_picolibc.yml== + - sbom_picolibc.yml diff --git a/components/newlib/src/assert.c b/components/newlib/src/assert.c index 9bdb2f66cc..fbe3540d8e 100644 --- a/components/newlib/src/assert.c +++ b/components/newlib/src/assert.c @@ -9,6 +9,7 @@ #include "esp_system.h" #include "soc/soc_memory_layout.h" #include "esp_private/cache_utils.h" +#include "sdkconfig.h" #define ASSERT_STR "assert failed: " #define CACHE_DISABLED_STR "" @@ -39,7 +40,7 @@ void __attribute__((noreturn)) __assert_func(const char *file, int line, const c esp_system_abort(buff); #else char addr[11] = { 0 }; - char buff[200]; + char buff[CONFIG_LIBC_ASSERT_BUFFER_SIZE]; char lbuf[5]; uint32_t rem_len = sizeof(buff) - 1; uint32_t off = 0; diff --git a/components/newlib/src/esp_libc.lf b/components/newlib/src/esp_libc.lf new file mode 100644 index 0000000000..d111c364f4 --- /dev/null +++ b/components/newlib/src/esp_libc.lf @@ -0,0 +1,21 @@ +[mapping:esp_libc] +archive: libnewlib.a +entries: + if LIBC_OPTIMIZED_MISALIGNED_ACCESS = y: + memcpy (noflash) + memmove (noflash) + memcmp (noflash) + strcpy (noflash) + strncpy (noflash) + strcmp (noflash) + strncmp (noflash) + if LIBC_MISC_IN_IRAM = y: + if HEAP_PLACE_FUNCTION_INTO_FLASH = n: + heap (noflash) + abort (noflash) + assert (noflash) + stdatomic (noflash) + if STDATOMIC_S32C1I_SPIRAM_WORKAROUND = y: + stdatomic_s32c1i (noflash) + if STDATOMIC_S32C1I_SPIRAM_WORKAROUND = y: + stdatomic_s32c1i (noflash) diff --git a/components/newlib/src/getentropy.c b/components/newlib/src/getentropy.c index 530a5964cc..850ae4e1cf 100644 --- a/components/newlib/src/getentropy.c +++ b/components/newlib/src/getentropy.c @@ -6,6 +6,7 @@ #include #include +#include int getentropy(void *buffer, size_t length) { diff --git a/components/newlib/src/esp32-spiram-rom-functions-c.lf b/components/newlib/src/libc.lf similarity index 97% rename from components/newlib/src/esp32-spiram-rom-functions-c.lf rename to components/newlib/src/libc.lf index bd5b09fa81..05fdef2306 100644 --- a/components/newlib/src/esp32-spiram-rom-functions-c.lf +++ b/components/newlib/src/libc.lf @@ -3,10 +3,6 @@ # and/or applications may assume that because these functions normally are in ROM, they are accessible even when flash is # inaccessible. To work around this, this ld fragment places these functions in RAM instead. If the ROM functions are used, # these defines do nothing, so they can still be included in that situation. -# -# -# Note: the only difference between esp32-spiram-rom-functions-c.lf -# and esp32-spiram-rom-functions-psram-workaround.lf is the archive name. [mapping:libc] archive: diff --git a/components/newlib/src/newlib.lf b/components/newlib/src/newlib.lf deleted file mode 100644 index 7ca47a0b9b..0000000000 --- a/components/newlib/src/newlib.lf +++ /dev/null @@ -1,11 +0,0 @@ -[mapping:newlib] -archive: libnewlib.a -entries: - if LIBC_MISC_IN_IRAM = y: - if HEAP_PLACE_FUNCTION_INTO_FLASH = n: - heap (noflash) - abort (noflash) - assert (noflash) - stdatomic (noflash) - if STDATOMIC_S32C1I_SPIRAM_WORKAROUND = y: - stdatomic_s32c1i (noflash) diff --git a/components/newlib/src/newlib_init.c b/components/newlib/src/newlib_init.c index f4a250756f..f65d94d94e 100644 --- a/components/newlib/src/newlib_init.c +++ b/components/newlib/src/newlib_init.c @@ -101,7 +101,7 @@ static struct syscall_stub_table s_stub_table = { ._lock_release = &_lock_release, ._lock_release_recursive = &_lock_release_recursive, #endif -#ifdef CONFIG_NEWLIB_NANO_FORMAT +#ifdef CONFIG_LIBC_NEWLIB_NANO_FORMAT ._printf_float = &_printf_float, ._scanf_float = &_scanf_float, #else diff --git a/components/newlib/src/picolibc/esp32-spiram-rom-functions-c.lf b/components/newlib/src/picolibc/libc.lf similarity index 100% rename from components/newlib/src/picolibc/esp32-spiram-rom-functions-c.lf rename to components/newlib/src/picolibc/libc.lf diff --git a/components/newlib/src/picolibc/picolibc_init.c b/components/newlib/src/picolibc/picolibc_init.c index 07540a4e55..c623a815a2 100644 --- a/components/newlib/src/picolibc/picolibc_init.c +++ b/components/newlib/src/picolibc/picolibc_init.c @@ -13,9 +13,10 @@ #include #include #include -#include +#include #include #include +#include #include #include #include "esp_newlib.h" diff --git a/components/newlib/src/port/riscv/memcpy.c b/components/newlib/src/port/riscv/memcpy.c index bbee1d3f02..fbc6c1df9f 100644 --- a/components/newlib/src/port/riscv/memcpy.c +++ b/components/newlib/src/port/riscv/memcpy.c @@ -18,14 +18,11 @@ #include #include -#include "esp_attr.h" -#include "../../string/local.h" +#include "string/local.h" #define unlikely(X) __builtin_expect (!!(X), 0) -IRAM_ATTR void * -__attribute__((optimize("-Os"))) __inhibit_loop_to_libcall memcpy(void *__restrict aa, const void *__restrict bb, size_t n) { @@ -65,29 +62,80 @@ small: if (unlikely(lend - la > 8)) { while (lend - la > 8) { - long b0 = *lb++; - long b1 = *lb++; - long b2 = *lb++; - long b3 = *lb++; - long b4 = *lb++; - long b5 = *lb++; - long b6 = *lb++; - long b7 = *lb++; - long b8 = *lb++; - *la++ = b0; - *la++ = b1; - *la++ = b2; - *la++ = b3; - *la++ = b4; - *la++ = b5; - *la++ = b6; - *la++ = b7; - *la++ = b8; + /* + * long b0 = *lb++; + * long b1 = *lb++; + * long b2 = *lb++; + * long b3 = *lb++; + * long b4 = *lb++; + * long b5 = *lb++; + * long b6 = *lb++; + * long b7 = *lb++; + * long b8 = *lb++; + * *la++ = b0; + * *la++ = b1; + * *la++ = b2; + * *la++ = b3; + * *la++ = b4; + * *la++ = b5; + * *la++ = b6; + * *la++ = b7; + * *la++ = b8; + */ + long src0, src1, src2, src3; + long src4, src5, src6, src7; + long src8; + /* DIG-694: need at least 2 instructions between lw and sw */ + asm volatile("lw %0, 0(%10)\n" // scr0 = lb[0]; + "lw %1, 4(%10)\n" // scr1 = lb[1]; + "lw %2, 8(%10)\n" // scr2 = lb[2]; + "lw %3, 12(%10)\n" // scr3 = lb[3]; + "lw %4, 16(%10)\n" // scr4 = lb[4]; + "lw %5, 20(%10)\n" // scr5 = lb[5]; + "lw %6, 24(%10)\n" // scr6 = lb[6]; + "lw %7, 28(%10)\n" // scr7 = lb[7]; + "lw %8, 32(%10)\n" // scr8 = lb[8]; + "addi %9, %9, 36\n" // la += 8 * 9; + "addi %10, %10, 36\n" // lb += 8 * 9; + "sw %0, -36(%9)\n" // *(la - 9) = src; + "sw %1, -32(%9)\n" // *(la - 8) = src; + "sw %2, -28(%9)\n" // *(la - 7) = src; + "sw %3, -24(%9)\n" // *(la - 6) = src; + "sw %4, -20(%9)\n" // *(la - 5) = src; + "sw %5, -16(%9)\n" // *(la - 4) = src; + "sw %6, -12(%9)\n" // *(la - 3) = src; + "sw %7, -8(%9)\n" // *(la - 2) = src; + "sw %8, -4(%9)\n" // *(la - 1) = src; + : "=r"(src0), "=r"(src1), "=r"(src2), "=r"(src3), + "=r"(src4), "=r"(src5), "=r"(src6), "=r"(src7), + "=r"(src8), + "+r"(la), "+r"(lb) + :: "memory"); } } - while (la < lend) { - BODY(la, lb, long); + /* + * BODY(la, lb, long); + */ + long src0; +#ifdef __OPTIMIZE_SIZE__ +#error "Enabled Os optimization may not work properly for DIG-694" + /* + * Replacing the string: + * *la++ = tt; + * To: + * "addi %2, %4, 4\n" // la++; + * "sw %0, -4(%4)\n" // *(la-1) = src0; + * May break some optimizations and slightly reduce performance. + */ +#endif + /* DIG-694: need at least 2 instructions between lw and sw */ + asm volatile("lw %0, 0(%1)\n" // long src0 = *lb; + "addi %1, %1, 4\n" // lb++; + "addi %2, %2, 4\n" // la++; + "sw %0, -4(%2)\n" // *(la-1) = src0; + : "=&r"(src0), "+r"(lb), "+r"(la) + :: "memory"); } a = (char *)la; diff --git a/components/newlib/src/port/riscv/memmove.c b/components/newlib/src/port/riscv/memmove.c new file mode 100644 index 0000000000..3b5d5568a6 --- /dev/null +++ b/components/newlib/src/port/riscv/memmove.c @@ -0,0 +1,150 @@ +/* + * SPDX-FileCopyrightText: 1994-2009 Red Hat, Inc. + * + * SPDX-License-Identifier: BSD-2-Clause-FreeBSD AND Apache-2.0 + * + * SPDX-FileContributor: 2025 Espressif Systems (Shanghai) CO LTD + */ +#include +#include <_ansi.h> +#include +#include +#include "string/local.h" + +void * +__inhibit_loop_to_libcall +memmove(void *dst_void, + const void *src_void, + size_t length) +{ + char *dst = dst_void; + const char *src = src_void; + long *aligned_dst; + const long *aligned_src; + + if (src < dst && dst < src + length) { + /* Destructive overlap...have to copy backwards */ + src += length; + dst += length; + + if (!TOO_SMALL_LITTLE_BLOCK(length) && !UNALIGNED_X_Y(src, dst)) { + aligned_dst = (long*)dst; + aligned_src = (long*)src; + + /* Copy one long word at a time if possible. */ + while (!TOO_SMALL_LITTLE_BLOCK(length)) { + /* + * const long src0 = *--aligned_src; + * *--aligned_dst = src0; + * length -= LITTLE_BLOCK_SIZE; + */ + long src0; + /* DIG-694: need at least 2 instructions between lw and sw */ + asm volatile("lw %0, -4(%1)\n" // src0 = *(aligned_src - 1); + "addi %1, %1, -4\n" // aligned_src--; + "addi %2, %2, -4\n" // aligned_dst--; + "addi %3, %3, -4\n" // length -= LITTLE_BLOCK_SIZE; + "sw %0, 0(%2)\n" // aligned_dst = src0; + : "=&r"(src0), "+r"(aligned_src), "+r"(aligned_dst), "+r"(length) + :: "memory"); + } + + /* Pick up any residual with a byte copier. */ + dst = (char*)aligned_dst; + src = (char*)aligned_src; + } + + while (length--) { + *--dst = *--src; + } + } else { + /* Use optimizing algorithm for a non-destructive copy to closely + match memcpy. If the size is small or either SRC or DST is unaligned, + then punt into the byte copy loop. This should be rare. */ + if (!TOO_SMALL_LITTLE_BLOCK(length) && !UNALIGNED_X_Y(src, dst)) { + aligned_dst = (long*)dst; + aligned_src = (long*)src; + + /* Copy 8X long words at a time if possible. */ + while (length >= BIG_BLOCK_SIZE * 2) { + /* + * const long src0 = *aligned_src++; + * const long src1 = *aligned_src++; + * const long src2 = *aligned_src++; + * const long src3 = *aligned_src++; + * const long src4 = *aligned_src++; + * const long src5 = *aligned_src++; + * const long src6 = *aligned_src++; + * const long src7 = *aligned_src++; + * *aligned_dst++ = src0; + * *aligned_dst++ = src1; + * *aligned_dst++ = src2; + * *aligned_dst++ = src3; + * *aligned_dst++ = src4; + * *aligned_dst++ = src5; + * *aligned_dst++ = src6; + * *aligned_dst++ = src7; + */ + long src0, src1, src2, src3; + long src4, src5, src6, src7; + /* DIG-694: need at least 2 instructions between lw and sw */ + asm volatile("lw %0, 0(%8)\n" // src0 = aligned_src[0]; + "lw %1, 4(%8)\n" // src1 = aligned_src[1]; + "lw %2, 8(%8)\n" // src2 = aligned_src[2]; + "lw %3, 12(%8)\n" // src3 = aligned_src[3]; + "lw %4, 16(%8)\n" // src4 = aligned_src[4]; + "lw %5, 20(%8)\n" // src5 = aligned_src[5]; + "lw %6, 24(%8)\n" // src6 = aligned_src[6]; + "lw %7, 28(%8)\n" // src7 = aligned_src[7]; + "addi %8, %8, 32\n" // aligned_src += BIG_BLOCK_SIZE * 2; + "addi %9, %9, 32\n" // aligned_dst += BIG_BLOCK_SIZE * 2; + "addi %10, %10, -32\n" // length -= BIG_BLOCK_SIZE * 2; + "sw %0, -32(%9)\n" // *(aligned_dst - 8) = src0; + "sw %1, -28(%9)\n" // *(aligned_dst - 7) = src1; + "sw %2, -24(%9)\n" // *(aligned_dst - 6) = src2; + "sw %3, -20(%9)\n" // *(aligned_dst - 5) = src3; + "sw %4, -16(%9)\n" // *(aligned_dst - 4) = src4; + "sw %5, -12(%9)\n" // *(aligned_dst - 3) = src5; + "sw %6, -8(%9)\n" // *(aligned_dst - 2) = src6; + "sw %7, -4(%9)\n" // *(aligned_dst - 1) = src7; + : "=r"(src0), "=r"(src1), "=r"(src2), "=r"(src3), + "=r"(src4), "=r"(src5), "=r"(src6), "=r"(src7), + "+r"(aligned_src), "+r"(aligned_dst), "+r"(length) + :: "memory"); + } + + /* Copy one long word at a time if possible. */ + while (!TOO_SMALL_LITTLE_BLOCK(length)) { + /* + * const long src0 = *aligned_src++; + * *aligned_dst++ = src0; + * length -= LITTLE_BLOCK_SIZE; + */ + long src0; + /* DIG-694: need at least 2 instructions between lw and sw */ + asm volatile("lw %0, 0(%1)\n" // long src0 = *aligned_src; + "addi %1, %1, 4\n" // aligned_src++; + "addi %2, %2, 4\n" // aligned_dst++; + "addi %3, %3, -4\n" // length -= LITTLE_BLOCK_SIZE; + "sw %0, -4(%2)\n" // *(aligned_dst-1) = src0; + : "=&r"(src0), "+r"(aligned_src), "+r"(aligned_dst), "+r"(length) + :: "memory"); + } + + /* Pick up any residual with a byte copier. */ + dst = (char*)aligned_dst; + src = (char*)aligned_src; + } + + while (length--) { + *dst++ = *src++; + } + } + + return dst_void; +} + +// Hook to force the linker to include this file +void esp_libc_include_memmove_impl(void) +{ +} diff --git a/components/newlib/src/port/riscv/strcpy.c b/components/newlib/src/port/riscv/strcpy.c index 361a04baa1..76bda0d390 100644 --- a/components/newlib/src/port/riscv/strcpy.c +++ b/components/newlib/src/port/riscv/strcpy.c @@ -23,6 +23,7 @@ __attribute__((always_inline)) static inline unsigned long __newlib__libc_detect_null(unsigned long w) { + /* coverity[result_independent_of_operands] */ unsigned long mask = 0x7f7f7f7f; if (sizeof(long) == 8) { mask = ((mask << 16) << 16) | mask; @@ -30,7 +31,6 @@ unsigned long __newlib__libc_detect_null(unsigned long w) return ~(((w & mask) + mask) | w | mask); } -__attribute__((optimize("-Os"))) char *strcpy(char *dst, const char *src) { char *dst0 = dst; @@ -44,6 +44,7 @@ char *strcpy(char *dst, const char *src) const long *lsrc = (const long *)src; while (!__newlib__libc_detect_null(*lsrc)) { + /* DIG-694: there are enough instructions between lw and sw after compiler unrolls the loop */ *ldst++ = *lsrc++; } @@ -87,6 +88,7 @@ out: return dst0; } + /* coverity[unreachable] */ char ch; do { ch = *src; diff --git a/components/newlib/src/pthread.c b/components/newlib/src/pthread.c index 13da80d7d5..81ffb2c217 100644 --- a/components/newlib/src/pthread.c +++ b/components/newlib/src/pthread.c @@ -4,6 +4,7 @@ * SPDX-License-Identifier: Apache-2.0 */ #include +#include #include "esp_log.h" const static char *TAG = "esp32_asio_pthread"; @@ -13,7 +14,7 @@ int pthread_setcancelstate(int state, int *oldstate) return 0; } -// This functions (pthread_sigmask(), sigfillset) are called from ASIO::signal_blocker to temporarily silence signals +// This functions (pthread_sigmask(), sigfillset) might be called from external libs to temporarily silence signals // Since signals are not yet supported in ESP pthread these functions serve as no-ops // int pthread_sigmask(int how, const sigset_t *restrict set, sigset_t *restrict oset) @@ -22,6 +23,8 @@ int pthread_sigmask(int how, const sigset_t *restrict set, sigset_t *restrict os return 0; } +// picolibc has sigfillset macro in signal.h +#if !CONFIG_LIBC_PICOLIBC int sigfillset(sigset_t *what) { ESP_LOGD(TAG, "%s: Signals not supported in ESP pthread", __func__); @@ -30,6 +33,7 @@ int sigfillset(sigset_t *what) } return 0; } +#endif /* !CONFIG_LIBC_PICOLIBC */ void esp_libc_include_pthread_impl(void) { diff --git a/components/newlib/src/reent_syscalls.c b/components/newlib/src/reent_syscalls.c index 72f3a4ec18..a036222990 100644 --- a/components/newlib/src/reent_syscalls.c +++ b/components/newlib/src/reent_syscalls.c @@ -13,6 +13,7 @@ #include #include #include +#include #include "sdkconfig.h" #include "esp_rom_uart.h" #include "esp_system_console.h" diff --git a/components/newlib/src/string/memcmp.c b/components/newlib/src/string/memcmp.c index 0a26ca8cd4..4445d09da2 100644 --- a/components/newlib/src/string/memcmp.c +++ b/components/newlib/src/string/memcmp.c @@ -6,9 +6,8 @@ * SPDX-FileContributor: 2025 Espressif Systems (Shanghai) CO LTD */ #include -#include "local.h" +#include "string/local.h" -__attribute__((optimize("-Os"))) int memcmp(const void *m1, const void *m2, diff --git a/components/newlib/src/string/memmove.c b/components/newlib/src/string/memmove.c deleted file mode 100644 index 57071ddc09..0000000000 --- a/components/newlib/src/string/memmove.c +++ /dev/null @@ -1,88 +0,0 @@ -/* - * SPDX-FileCopyrightText: 1994-2009 Red Hat, Inc. - * - * SPDX-License-Identifier: BSD-2-Clause-FreeBSD AND Apache-2.0 - * - * SPDX-FileContributor: 2025 Espressif Systems (Shanghai) CO LTD - */ -#include -#include <_ansi.h> -#include -#include -#include "local.h" - -__attribute__((optimize("-Os"))) -void * -__inhibit_loop_to_libcall -memmove(void *dst_void, - const void *src_void, - size_t length) -{ - char *dst = dst_void; - const char *src = src_void; - long *aligned_dst; - const long *aligned_src; - - if (src < dst && dst < src + length) { - /* Destructive overlap...have to copy backwards */ - src += length; - dst += length; - - if (!TOO_SMALL_LITTLE_BLOCK(length) && !UNALIGNED_X_Y(src, dst)) { - aligned_dst = (long*)dst; - aligned_src = (long*)src; - - /* Copy one long word at a time if possible. */ - while (!TOO_SMALL_LITTLE_BLOCK(length)) { - *--aligned_dst = *--aligned_src; - length -= LITTLE_BLOCK_SIZE; - } - - /* Pick up any residual with a byte copier. */ - dst = (char*)aligned_dst; - src = (char*)aligned_src; - } - - while (length--) { - *--dst = *--src; - } - } else { - /* Use optimizing algorithm for a non-destructive copy to closely - match memcpy. If the size is small or either SRC or DST is unaligned, - then punt into the byte copy loop. This should be rare. */ - if (!TOO_SMALL_LITTLE_BLOCK(length) && !UNALIGNED_X_Y(src, dst)) { - aligned_dst = (long*)dst; - aligned_src = (long*)src; - - /* Copy 4X long words at a time if possible. */ - while (!TOO_SMALL_BIG_BLOCK(length)) { - *aligned_dst++ = *aligned_src++; - *aligned_dst++ = *aligned_src++; - *aligned_dst++ = *aligned_src++; - *aligned_dst++ = *aligned_src++; - length -= BIG_BLOCK_SIZE; - } - - /* Copy one long word at a time if possible. */ - while (!TOO_SMALL_LITTLE_BLOCK(length)) { - *aligned_dst++ = *aligned_src++; - length -= LITTLE_BLOCK_SIZE; - } - - /* Pick up any residual with a byte copier. */ - dst = (char*)aligned_dst; - src = (char*)aligned_src; - } - - while (length--) { - *dst++ = *src++; - } - } - - return dst_void; -} - -// Hook to force the linker to include this file -void esp_libc_include_memmove_impl(void) -{ -} diff --git a/components/newlib/src/string/strncmp.c b/components/newlib/src/string/strncmp.c index f0efd62189..ed71b484e7 100644 --- a/components/newlib/src/string/strncmp.c +++ b/components/newlib/src/string/strncmp.c @@ -7,9 +7,8 @@ */ #include #include -#include "local.h" +#include "string/local.h" -__attribute__((optimize("-Os"))) int strncmp(const char *s1, const char *s2, diff --git a/components/newlib/src/string/strncpy.c b/components/newlib/src/string/strncpy.c index 5821e1997b..0916244d35 100644 --- a/components/newlib/src/string/strncpy.c +++ b/components/newlib/src/string/strncpy.c @@ -7,9 +7,8 @@ */ #include #include -#include "local.h" +#include "string/local.h" -__attribute__((optimize("-Os"))) char * strncpy(char *__restrict dst0, const char *__restrict src0, @@ -29,6 +28,7 @@ strncpy(char *__restrict dst0, sized copies. */ while (!TOO_SMALL_LITTLE_BLOCK(count) && !DETECT_NULL(*aligned_src)) { count -= sizeof(long int); + /* DIG-694: there are enough instructions between lw and sw after compiler unrolls the loop */ *aligned_dst++ = *aligned_src++; } diff --git a/components/newlib/src/syscalls.c b/components/newlib/src/syscalls.c index d9dbe9e85a..b4ecf1f2fe 100644 --- a/components/newlib/src/syscalls.c +++ b/components/newlib/src/syscalls.c @@ -10,6 +10,7 @@ #include #include #include +#include #include "esp_attr.h" #if CONFIG_LIBC_PICOLIBC @@ -83,7 +84,7 @@ int rename(const char *src, const char *dst) int isatty(int fd) { - struct stat buf; + struct stat buf = {0}; if (_fstat_r(__getreent(), fd, &buf) < 0) { return 0; @@ -109,6 +110,7 @@ int getpid() { return _getpid_r(__getreent()); } + #endif // CONFIG_LIBC_PICOLIBC void _exit(int __status) @@ -121,6 +123,7 @@ int fstat(int fd, struct stat *st) return _fstat_r(__getreent(), fd, st); } +#if !CONFIG_LIBC_PICOLIBC #if CONFIG_SPIRAM_CACHE_LIBMISC_IN_IRAM IRAM_ATTR #endif @@ -128,6 +131,7 @@ int raise(int sig) { return _raise_r(__getreent(), sig); } +#endif #if CONFIG_SPIRAM_CACHE_LIBMISC_IN_IRAM IRAM_ATTR diff --git a/components/newlib/test_apps/.build-test-rules.yml b/components/newlib/test_apps/.build-test-rules.yml deleted file mode 100644 index 7e5c31fd38..0000000000 --- a/components/newlib/test_apps/.build-test-rules.yml +++ /dev/null @@ -1,7 +0,0 @@ -# Documentation: .gitlab/ci/README.md#manifest-file-to-control-the-buildtest-apps - -components/newlib/test_apps/newlib: - disable_test: - - if: IDF_TARGET == "esp32p4" - temporary: true - reason: p4 rev3 migration # TODO: IDF-14415 diff --git a/components/newlib/test_apps/newlib/main/test_misaligned_access.c b/components/newlib/test_apps/newlib/main/test_misaligned_access.c new file mode 100644 index 0000000000..0ee1f0f7b3 --- /dev/null +++ b/components/newlib/test_apps/newlib/main/test_misaligned_access.c @@ -0,0 +1,162 @@ +/* + * SPDX-FileCopyrightText: 2025 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Unlicense OR CC0-1.0 + */ +#include +#include +#include "esp_heap_caps.h" +#include "soc/soc.h" +#include "hal/cpu_ll.h" +#include "unity.h" + +#define MAX_MEMTEST_SIZE 4096 + +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wincompatible-pointer-types" +#pragma GCC diagnostic ignored "-Wstrict-prototypes" + +uint32_t test_function_dest_src_size(void (*foo)(...), bool pass_size) +{ + uint32_t ccount1, ccount2; + char* test_des = heap_caps_aligned_alloc(32, MAX_MEMTEST_SIZE, MALLOC_CAP_INTERNAL | MALLOC_CAP_8BIT); + char* test_src = heap_caps_aligned_alloc(32, MAX_MEMTEST_SIZE, MALLOC_CAP_INTERNAL | MALLOC_CAP_8BIT); + + TEST_ASSERT_NOT_NULL(test_des); + TEST_ASSERT_NOT_NULL(test_src); + + /* Prepare arrays for X-cmp functions to make the algorithm go through whole buffers. */ + memset(test_src, 'a', MAX_MEMTEST_SIZE); + test_src[MAX_MEMTEST_SIZE - 1] = 0; + memset(test_des, 'a', MAX_MEMTEST_SIZE); + test_des[MAX_MEMTEST_SIZE - 1] = 'b'; + test_des[MAX_MEMTEST_SIZE - 1] = 0; + + ccount1 = esp_cpu_get_cycle_count(); + if (pass_size) { + foo(test_des + 1, test_src + 2, MAX_MEMTEST_SIZE - 2); + } else { + foo(test_des + 1, test_src + 2); + } + ccount2 = esp_cpu_get_cycle_count(); + + heap_caps_free(test_des); + heap_caps_free(test_src); + + return ccount2 - ccount1; +} + +TEST_CASE("memcpy", "[misaligned_mem]") +{ + uint32_t ccount = test_function_dest_src_size(memcpy, true); + /* esp32c2: 4128 cycles instead 28676. */ + TEST_ASSERT_LESS_THAN(10000, ccount); +} + +TEST_CASE("memcmp", "[misaligned_mem]") +{ + uint32_t ccount = test_function_dest_src_size(memcmp, true); + /* esp32c2: 14259 cycles instead 49147. */ + TEST_ASSERT_LESS_THAN(20000, ccount); +} + +TEST_CASE("memmove", "[misaligned_mem]") +{ + uint32_t ccount = test_function_dest_src_size(memmove, true); + /* esp32c2: 8086 cycles instead 33896. */ + TEST_ASSERT_LESS_THAN(15000, ccount); +} + +TEST_CASE("memmove - overlapping", "[misaligned_mem]") +{ + uint32_t ccount1, ccount2; + char* buf = heap_caps_aligned_alloc(32, MAX_MEMTEST_SIZE, MALLOC_CAP_INTERNAL | MALLOC_CAP_8BIT); + + TEST_ASSERT_NOT_NULL(buf); + + ccount1 = esp_cpu_get_cycle_count(); + memmove(buf + 5, buf + 2, MAX_MEMTEST_SIZE - 5); + ccount2 = esp_cpu_get_cycle_count(); + + heap_caps_free(buf); + + /* esp32c2: 11503 cycles instead 45024. */ + TEST_ASSERT_LESS_THAN(20000, ccount2 - ccount1); +} + +TEST_CASE("strcpy", "[misaligned_mem]") +{ + uint32_t ccount = test_function_dest_src_size(strcpy, false); + /* esp32c2: 17313 cycles instead 32771. */ + TEST_ASSERT_LESS_THAN(22000, ccount); +} + +TEST_CASE("strcmp", "[misaligned_mem]") +{ + uint32_t ccount = test_function_dest_src_size(strcmp, false); + /* esp32c2: 13191 cycles instead 32775. */ + TEST_ASSERT_LESS_THAN(20000, ccount); +} + +TEST_CASE("strncpy", "[misaligned_mem]") +{ + uint32_t ccount = test_function_dest_src_size(strncpy, true); + /* esp32c2: 21475 cycles instead 36859. */ + TEST_ASSERT_LESS_THAN(25000, ccount); +} + +TEST_CASE("strncmp", "[misaligned_mem]") +{ + uint32_t ccount = test_function_dest_src_size(strncmp, true); + /* esp32c2: 24369 cycles instead 49141. */ + TEST_ASSERT_LESS_THAN(30000, ccount); +} +#pragma GCC diagnostic pop // "-Wincompatible-pointer-types" "-Wstrict-prototypes" + +static bool fn_in_ram(void *fn) +{ + const int fnaddr = (int)fn; + return (fnaddr >= SOC_IRAM_LOW && fnaddr < SOC_IRAM_HIGH); +} + +TEST_CASE("mem functions in IRAM", "[misaligned_mem]") +{ + TEST_ASSERT_TRUE(fn_in_ram(memcpy)); + TEST_ASSERT_TRUE(fn_in_ram(memcmp)); + TEST_ASSERT_TRUE(fn_in_ram(memmove)); + TEST_ASSERT_TRUE(fn_in_ram(strcpy)); + TEST_ASSERT_TRUE(fn_in_ram(strncpy)); + TEST_ASSERT_TRUE(fn_in_ram(strcmp)); + TEST_ASSERT_TRUE(fn_in_ram(strncmp)); +} + +#if CONFIG_ESP_SYSTEM_MEMPROT_PMP +TEST_CASE("access across different PMP regions", "[misaligned_mem]") +{ + /* + * PMP configurations for load and store addresses may + * have different permissions (e.g., "R" vs. "RW"). + * + * Due to the timing alignment of internal signals, the address + * permission check may be incorrectly applied during the second + * part of a misaligned access transaction. + * + * As a workaround, insert two instructions (e.g. ADDI/NOP) between + * accessing to different memory regions. This spacing avoids the + * false permission check caused by signal timing overlap. + * + * This test may help identify the root issue in affected chips. + */ + + const void *src = (void *) SOC_DROM_MASK_LOW; + asm volatile("addi sp, sp, -16\n" + "lw t0, 2(%0)\n" +#if CONFIG_SOC_CPU_MISALIGNED_ACCESS_ON_PMP_MISMATCH_ISSUE + "nop\n" + "nop\n" +#endif + "sw t0, 3(sp)\n" + "addi sp, sp, 16" + :: "r"(src) : "memory"); +} +#endif diff --git a/components/newlib/test_apps/newlib/main/test_newlib.c b/components/newlib/test_apps/newlib/main/test_newlib.c index 8632e8a094..f8e3a8f468 100644 --- a/components/newlib/test_apps/newlib/main/test_newlib.c +++ b/components/newlib/test_apps/newlib/main/test_newlib.c @@ -10,6 +10,7 @@ #include #include #include +#include #include #include #include diff --git a/components/newlib/test_apps/no_rvfplib/CMakeLists.txt b/components/newlib/test_apps/no_rvfplib/CMakeLists.txt new file mode 100644 index 0000000000..798a42d024 --- /dev/null +++ b/components/newlib/test_apps/no_rvfplib/CMakeLists.txt @@ -0,0 +1,10 @@ +# The following lines of boilerplate have to be in your project's +# CMakeLists in this exact order for cmake to work correctly +cmake_minimum_required(VERSION 3.22) + +include($ENV{IDF_PATH}/tools/cmake/project.cmake) + +# "Trim" the build. Include the minimal set of components, main, and anything it depends on. +idf_build_set_property(MINIMAL_BUILD ON) + +project(test_build) diff --git a/components/newlib/test_apps/no_rvfplib/README.md b/components/newlib/test_apps/no_rvfplib/README.md new file mode 100644 index 0000000000..ecf49aec4b --- /dev/null +++ b/components/newlib/test_apps/no_rvfplib/README.md @@ -0,0 +1,6 @@ +| Supported Targets | ESP32 | ESP32-C2 | ESP32-C3 | ESP32-C5 | ESP32-C6 | ESP32-C61 | ESP32-H2 | ESP32-H21 | ESP32-H4 | ESP32-P4 | ESP32-S2 | ESP32-S3 | +| ----------------- | ----- | -------- | -------- | -------- | -------- | --------- | -------- | --------- | -------- | -------- | -------- | -------- | + +This project tests building with the no_rvfplib configuration. + +This project uses MINIMAL_BUILD=y to reduce build time and dependencies. diff --git a/components/newlib/test_apps/no_rvfplib/main/CMakeLists.txt b/components/newlib/test_apps/no_rvfplib/main/CMakeLists.txt new file mode 100644 index 0000000000..1df31fac80 --- /dev/null +++ b/components/newlib/test_apps/no_rvfplib/main/CMakeLists.txt @@ -0,0 +1,2 @@ +idf_component_register(SRCS "test_main.c" + INCLUDE_DIRS ".") diff --git a/components/newlib/test_apps/no_rvfplib/main/test_main.c b/components/newlib/test_apps/no_rvfplib/main/test_main.c new file mode 100644 index 0000000000..b908720b32 --- /dev/null +++ b/components/newlib/test_apps/no_rvfplib/main/test_main.c @@ -0,0 +1,8 @@ +/* + * SPDX-FileCopyrightText: 2025 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Unlicense OR CC0-1.0 + */ +void app_main(void) +{ +} diff --git a/components/newlib/test_apps/no_rvfplib/sdkconfig.ci.default b/components/newlib/test_apps/no_rvfplib/sdkconfig.ci.default new file mode 100644 index 0000000000..09e782b75c --- /dev/null +++ b/components/newlib/test_apps/no_rvfplib/sdkconfig.ci.default @@ -0,0 +1,2 @@ +CONFIG_IDF_TARGET="esp32c2" +CONFIG_COMPILER_FLOAT_LIB_FROM_GCCLIB=y diff --git a/components/soc/project_include.cmake b/components/soc/project_include.cmake index ad2c6b6bc4..a2273ed302 100644 --- a/components/soc/project_include.cmake +++ b/components/soc/project_include.cmake @@ -13,11 +13,10 @@ if(CONFIG_IDF_TOOLCHAIN_GCC) CONFIG_IDF_TARGET_ESP32C61 OR CONFIG_IDF_TARGET_ESP32H2 OR CONFIG_IDF_TARGET_ESP32H21) - set(_march "rv32imac_zicsr_zifencei_zaamo_zalrsc") - elseif(CONFIG_IDF_TARGET_ESP32H4) - set(_march "rv32imafcb_zicsr_zifencei_zaamo_zalrsc") - elseif(CONFIG_IDF_TARGET_ESP32P4) - set(_march "rv32imafc_zicsr_zifencei_zaamo_zalrsc") + set(_march "rv32imac_zicsr_zifencei") + elseif(CONFIG_IDF_TARGET_ESP32H4 OR + CONFIG_IDF_TARGET_ESP32P4) + set(_march "rv32imafc_zicsr_zifencei") elseif(NOT(CONFIG_IDF_TARGET_ESP32S2 OR CONFIG_IDF_TARGET_ESP32S3)) message(FATAL_ERROR "Unknown Espressif target: ${CONFIG_IDF_TARGET}") endif() @@ -48,19 +47,12 @@ if(CONFIG_IDF_TOOLCHAIN_GCC) endif() endif() - if(CONFIG_SOC_CPU_HAS_DSP) - set(_march "${_march}_xespdsp") - endif() - # Set ABI and ARCH options if(CONFIG_SOC_CPU_HAS_FPU) idf_toolchain_add_flags(COMPILE_OPTIONS "-mabi=ilp32f") endif() idf_toolchain_add_flags(COMPILE_OPTIONS "-march=${_march}") - if(NOT CONFIG_SOC_CPU_MISALIGNED_ACCESS_ON_PMP_MISMATCH_ISSUE) - idf_toolchain_add_flags(COMPILE_OPTIONS "-mtune=esp-base") - endif() idf_toolchain_rerun_abi_detection() else() message(FATAL_ERROR "Unknown Espressif architecture: ${CONFIG_IDF_TARGET_ARCH}")