mirror of
https://github.com/espressif/esp-idf.git
synced 2026-10-01 18:50:34 +03:00
feat(esp_libc): add full support for picolibc
This commit is contained in:
@@ -17,9 +17,9 @@
|
||||
#include "sdkconfig.h"
|
||||
|
||||
#if CONFIG_LIBC_LOCKS_PLACE_IN_IRAM
|
||||
#define NEWLIB_LOCKS_IRAM_ATTR IRAM_ATTR
|
||||
#define LIBC_LOCKS_IRAM_ATTR IRAM_ATTR
|
||||
#else
|
||||
#define NEWLIB_LOCKS_IRAM_ATTR
|
||||
#define LIBC_LOCKS_IRAM_ATTR
|
||||
#endif
|
||||
|
||||
/* Notes on our newlib lock implementation:
|
||||
@@ -50,7 +50,7 @@ static portMUX_TYPE lock_init_spinlock = portMUX_INITIALIZER_UNLOCKED;
|
||||
Called by _lock_init*, also called by _lock_acquire* to lazily initialize locks that might have
|
||||
been initialised (to zero only) before the RTOS scheduler started.
|
||||
*/
|
||||
static void NEWLIB_LOCKS_IRAM_ATTR lock_init_generic(_lock_t *lock, uint8_t mutex_type)
|
||||
static void LIBC_LOCKS_IRAM_ATTR lock_init_generic(_lock_t *lock, uint8_t mutex_type)
|
||||
{
|
||||
portENTER_CRITICAL(&lock_init_spinlock);
|
||||
if (*lock) {
|
||||
@@ -81,13 +81,13 @@ static void NEWLIB_LOCKS_IRAM_ATTR lock_init_generic(_lock_t *lock, uint8_t mute
|
||||
portEXIT_CRITICAL(&lock_init_spinlock);
|
||||
}
|
||||
|
||||
void NEWLIB_LOCKS_IRAM_ATTR _lock_init(_lock_t *lock)
|
||||
void LIBC_LOCKS_IRAM_ATTR _lock_init(_lock_t *lock)
|
||||
{
|
||||
*lock = 0; // In case lock's memory is uninitialized
|
||||
lock_init_generic(lock, queueQUEUE_TYPE_MUTEX);
|
||||
}
|
||||
|
||||
void NEWLIB_LOCKS_IRAM_ATTR _lock_init_recursive(_lock_t *lock)
|
||||
void LIBC_LOCKS_IRAM_ATTR _lock_init_recursive(_lock_t *lock)
|
||||
{
|
||||
*lock = 0; // In case lock's memory is uninitialized
|
||||
lock_init_generic(lock, queueQUEUE_TYPE_RECURSIVE_MUTEX);
|
||||
@@ -103,7 +103,7 @@ void NEWLIB_LOCKS_IRAM_ATTR _lock_init_recursive(_lock_t *lock)
|
||||
re-initialised if it is used again. Caller has to avoid doing
|
||||
this!
|
||||
*/
|
||||
void NEWLIB_LOCKS_IRAM_ATTR _lock_close(_lock_t *lock)
|
||||
void LIBC_LOCKS_IRAM_ATTR _lock_close(_lock_t *lock)
|
||||
{
|
||||
portENTER_CRITICAL(&lock_init_spinlock);
|
||||
if (*lock) {
|
||||
@@ -122,7 +122,7 @@ void _lock_close_recursive(_lock_t *lock) __attribute__((alias("_lock_close")));
|
||||
/* Acquire the mutex semaphore for lock. wait up to delay ticks.
|
||||
mutex_type is queueQUEUE_TYPE_RECURSIVE_MUTEX or queueQUEUE_TYPE_MUTEX
|
||||
*/
|
||||
static int NEWLIB_LOCKS_IRAM_ATTR lock_acquire_generic(_lock_t *lock, uint32_t delay, uint8_t mutex_type)
|
||||
static int LIBC_LOCKS_IRAM_ATTR lock_acquire_generic(_lock_t *lock, uint32_t delay, uint8_t mutex_type)
|
||||
{
|
||||
SemaphoreHandle_t h = (SemaphoreHandle_t)(*lock);
|
||||
if (!h) {
|
||||
@@ -164,22 +164,22 @@ static int NEWLIB_LOCKS_IRAM_ATTR lock_acquire_generic(_lock_t *lock, uint32_t d
|
||||
return (success == pdTRUE) ? 0 : -1;
|
||||
}
|
||||
|
||||
void NEWLIB_LOCKS_IRAM_ATTR _lock_acquire(_lock_t *lock)
|
||||
void LIBC_LOCKS_IRAM_ATTR _lock_acquire(_lock_t *lock)
|
||||
{
|
||||
lock_acquire_generic(lock, portMAX_DELAY, queueQUEUE_TYPE_MUTEX);
|
||||
}
|
||||
|
||||
void NEWLIB_LOCKS_IRAM_ATTR _lock_acquire_recursive(_lock_t *lock)
|
||||
void LIBC_LOCKS_IRAM_ATTR _lock_acquire_recursive(_lock_t *lock)
|
||||
{
|
||||
lock_acquire_generic(lock, portMAX_DELAY, queueQUEUE_TYPE_RECURSIVE_MUTEX);
|
||||
}
|
||||
|
||||
int NEWLIB_LOCKS_IRAM_ATTR _lock_try_acquire(_lock_t *lock)
|
||||
int LIBC_LOCKS_IRAM_ATTR _lock_try_acquire(_lock_t *lock)
|
||||
{
|
||||
return lock_acquire_generic(lock, 0, queueQUEUE_TYPE_MUTEX);
|
||||
}
|
||||
|
||||
int NEWLIB_LOCKS_IRAM_ATTR _lock_try_acquire_recursive(_lock_t *lock)
|
||||
int LIBC_LOCKS_IRAM_ATTR _lock_try_acquire_recursive(_lock_t *lock)
|
||||
{
|
||||
return lock_acquire_generic(lock, 0, queueQUEUE_TYPE_RECURSIVE_MUTEX);
|
||||
}
|
||||
@@ -187,7 +187,7 @@ int NEWLIB_LOCKS_IRAM_ATTR _lock_try_acquire_recursive(_lock_t *lock)
|
||||
/* Release the mutex semaphore for lock.
|
||||
mutex_type is queueQUEUE_TYPE_RECURSIVE_MUTEX or queueQUEUE_TYPE_MUTEX
|
||||
*/
|
||||
static void NEWLIB_LOCKS_IRAM_ATTR lock_release_generic(_lock_t *lock, uint8_t mutex_type)
|
||||
static void LIBC_LOCKS_IRAM_ATTR lock_release_generic(_lock_t *lock, uint8_t mutex_type)
|
||||
{
|
||||
if (xTaskGetSchedulerState() == taskSCHEDULER_NOT_STARTED) {
|
||||
return; /* locking is a no-op before scheduler is up */
|
||||
@@ -213,12 +213,12 @@ static void NEWLIB_LOCKS_IRAM_ATTR lock_release_generic(_lock_t *lock, uint8_t m
|
||||
}
|
||||
}
|
||||
|
||||
void NEWLIB_LOCKS_IRAM_ATTR _lock_release(_lock_t *lock)
|
||||
void LIBC_LOCKS_IRAM_ATTR _lock_release(_lock_t *lock)
|
||||
{
|
||||
lock_release_generic(lock, queueQUEUE_TYPE_MUTEX);
|
||||
}
|
||||
|
||||
void NEWLIB_LOCKS_IRAM_ATTR _lock_release_recursive(_lock_t *lock)
|
||||
void LIBC_LOCKS_IRAM_ATTR _lock_release_recursive(_lock_t *lock)
|
||||
{
|
||||
lock_release_generic(lock, queueQUEUE_TYPE_RECURSIVE_MUTEX);
|
||||
}
|
||||
@@ -291,69 +291,69 @@ static StaticSemaphore_t s_common_recursive_mutex;
|
||||
#define MAYBE_OVERRIDE_LOCK(_lock, _lock_to_use_instead)
|
||||
#endif // ROM_NEEDS_MUTEX_OVERRIDE
|
||||
|
||||
void NEWLIB_LOCKS_IRAM_ATTR __retarget_lock_init(_LOCK_T *lock)
|
||||
void LIBC_LOCKS_IRAM_ATTR __retarget_lock_init(_LOCK_T *lock)
|
||||
{
|
||||
*lock = NULL; /* In case lock's memory is uninitialized */
|
||||
lock_init_generic(lock, queueQUEUE_TYPE_MUTEX);
|
||||
}
|
||||
|
||||
void NEWLIB_LOCKS_IRAM_ATTR __retarget_lock_init_recursive(_LOCK_T *lock)
|
||||
void LIBC_LOCKS_IRAM_ATTR __retarget_lock_init_recursive(_LOCK_T *lock)
|
||||
{
|
||||
*lock = NULL; /* In case lock's memory is uninitialized */
|
||||
lock_init_generic(lock, queueQUEUE_TYPE_RECURSIVE_MUTEX);
|
||||
}
|
||||
|
||||
void NEWLIB_LOCKS_IRAM_ATTR __retarget_lock_close(_LOCK_T lock)
|
||||
void LIBC_LOCKS_IRAM_ATTR __retarget_lock_close(_LOCK_T lock)
|
||||
{
|
||||
_lock_close(&lock);
|
||||
}
|
||||
|
||||
void NEWLIB_LOCKS_IRAM_ATTR __retarget_lock_close_recursive(_LOCK_T lock)
|
||||
void LIBC_LOCKS_IRAM_ATTR __retarget_lock_close_recursive(_LOCK_T lock)
|
||||
{
|
||||
_lock_close_recursive(&lock);
|
||||
}
|
||||
|
||||
/* Separate function, to prevent generating multiple assert strings */
|
||||
static void NEWLIB_LOCKS_IRAM_ATTR check_lock_nonzero(_LOCK_T lock)
|
||||
static void LIBC_LOCKS_IRAM_ATTR check_lock_nonzero(_LOCK_T lock)
|
||||
{
|
||||
assert(lock != NULL && "Uninitialized lock used");
|
||||
}
|
||||
|
||||
void NEWLIB_LOCKS_IRAM_ATTR __retarget_lock_acquire(_LOCK_T lock)
|
||||
void LIBC_LOCKS_IRAM_ATTR __retarget_lock_acquire(_LOCK_T lock)
|
||||
{
|
||||
check_lock_nonzero(lock);
|
||||
MAYBE_OVERRIDE_LOCK(lock, &s_common_mutex);
|
||||
_lock_acquire(&lock);
|
||||
}
|
||||
|
||||
void NEWLIB_LOCKS_IRAM_ATTR __retarget_lock_acquire_recursive(_LOCK_T lock)
|
||||
void LIBC_LOCKS_IRAM_ATTR __retarget_lock_acquire_recursive(_LOCK_T lock)
|
||||
{
|
||||
check_lock_nonzero(lock);
|
||||
MAYBE_OVERRIDE_LOCK(lock, &s_common_recursive_mutex);
|
||||
_lock_acquire_recursive(&lock);
|
||||
}
|
||||
|
||||
int NEWLIB_LOCKS_IRAM_ATTR __retarget_lock_try_acquire(_LOCK_T lock)
|
||||
int LIBC_LOCKS_IRAM_ATTR __retarget_lock_try_acquire(_LOCK_T lock)
|
||||
{
|
||||
check_lock_nonzero(lock);
|
||||
MAYBE_OVERRIDE_LOCK(lock, &s_common_mutex);
|
||||
return _lock_try_acquire(&lock);
|
||||
}
|
||||
|
||||
int NEWLIB_LOCKS_IRAM_ATTR __retarget_lock_try_acquire_recursive(_LOCK_T lock)
|
||||
int LIBC_LOCKS_IRAM_ATTR __retarget_lock_try_acquire_recursive(_LOCK_T lock)
|
||||
{
|
||||
check_lock_nonzero(lock);
|
||||
MAYBE_OVERRIDE_LOCK(lock, &s_common_recursive_mutex);
|
||||
return _lock_try_acquire_recursive(&lock);
|
||||
}
|
||||
|
||||
void NEWLIB_LOCKS_IRAM_ATTR __retarget_lock_release(_LOCK_T lock)
|
||||
void LIBC_LOCKS_IRAM_ATTR __retarget_lock_release(_LOCK_T lock)
|
||||
{
|
||||
check_lock_nonzero(lock);
|
||||
_lock_release(&lock);
|
||||
}
|
||||
|
||||
void NEWLIB_LOCKS_IRAM_ATTR __retarget_lock_release_recursive(_LOCK_T lock)
|
||||
void LIBC_LOCKS_IRAM_ATTR __retarget_lock_release_recursive(_LOCK_T lock)
|
||||
{
|
||||
check_lock_nonzero(lock);
|
||||
_lock_release_recursive(&lock);
|
||||
|
||||
@@ -0,0 +1,22 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2025 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
#include <errno.h>
|
||||
|
||||
/*
|
||||
* Picolibc does not initialize 'errno' and places it in the TBSS section.
|
||||
*
|
||||
* To allow convenient initialization and support interoperability with Newlib,
|
||||
* 'errno' is defined in the TDATA section. The linker script ensures that
|
||||
* it is positioned at the beginning of the TDATA segment.
|
||||
*/
|
||||
__thread int errno __attribute__((section(".tdata.errno"))) = 0;
|
||||
|
||||
#if CONFIG_LIBC_PICOLIBC_NEWLIB_COMPATIBILITY
|
||||
int *__errno(void)
|
||||
{
|
||||
return &errno;
|
||||
}
|
||||
#endif
|
||||
@@ -0,0 +1,19 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2025 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
#include <stdint.h>
|
||||
#include "esp_cpu.h"
|
||||
|
||||
void *__getreent(void)
|
||||
{
|
||||
/*
|
||||
* The linker script provides the basic _reent fields
|
||||
* used to access errno and stdin/stdout/stderr.
|
||||
*
|
||||
* Note: if code accesses other fields in struct _reent
|
||||
* that are not intended to be "public," data corruption may occur.
|
||||
*/
|
||||
return esp_cpu_get_threadptr();
|
||||
}
|
||||
@@ -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
|
||||
*/
|
||||
@@ -33,17 +33,8 @@ static void esp_cleanup_r(struct _reent *rptr)
|
||||
#endif
|
||||
|
||||
#if ESP_ROM_HAS_RETARGETABLE_LOCKING
|
||||
static int __retarget_lock_try_acquire(struct __lock * p)
|
||||
{
|
||||
__retarget_lock_acquire(p);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int __retarget_lock_try_acquire_recursive(struct __lock *p)
|
||||
{
|
||||
__retarget_lock_acquire_recursive(p);
|
||||
return 0;
|
||||
}
|
||||
int __retarget_lock_try_acquire(struct __lock * p);
|
||||
int __retarget_lock_try_acquire_recursive(struct __lock *p);
|
||||
#endif
|
||||
|
||||
static struct syscall_stub_table s_stub_table = {
|
||||
@@ -143,20 +134,10 @@ void esp_reent_cleanup(void)
|
||||
return;
|
||||
}
|
||||
|
||||
#if CONFIG_VFS_SUPPORT_IO
|
||||
FILE *stdin;
|
||||
FILE *stdout;
|
||||
FILE *stderr;
|
||||
void esp_libc_init_global_stdio(const char *stdio_dev)
|
||||
{
|
||||
stdin = fopen(stdio_dev, "r");
|
||||
stdout = fopen(stdio_dev, "w");
|
||||
assert(stdin);
|
||||
assert(stdout);
|
||||
setlinebuf(stdout);
|
||||
stderr = stdout;
|
||||
}
|
||||
#else /* CONFIG_VFS_SUPPORT_IO */
|
||||
/*
|
||||
* Initialize stdin, stdout, and stderr using static memory allocation.
|
||||
* Creating them with fopen() would call malloc() internally.
|
||||
*/
|
||||
static char write_buf[BUFSIZ];
|
||||
static char read_buf[BUFSIZ];
|
||||
|
||||
@@ -166,10 +147,28 @@ static struct __file_bufio __stdout = FDEV_SETUP_BUFIO(1, write_buf, BUFSIZ, rea
|
||||
FILE *stdin = &__stdin.xfile.cfile.file;
|
||||
FILE *stdout = &__stdout.xfile.cfile.file;
|
||||
FILE *stderr = &__stdout.xfile.cfile.file;
|
||||
|
||||
#if CONFIG_LIBC_PICOLIBC_NEWLIB_COMPATIBILITY
|
||||
__thread FILE* tls_stdin = &__stdin.xfile.cfile.file;
|
||||
__thread FILE* tls_stdout = &__stdout.xfile.cfile.file;
|
||||
__thread FILE* tls_stderr = &__stdout.xfile.cfile.file;
|
||||
#endif
|
||||
|
||||
#if CONFIG_VFS_SUPPORT_IO
|
||||
void esp_libc_init_global_stdio(const char *stdio_dev)
|
||||
{
|
||||
int stdin_fd = open(stdio_dev, O_RDONLY);
|
||||
assert(stdin_fd > 0);
|
||||
__stdin.ptr = (void *)(intptr_t)(stdin_fd);
|
||||
|
||||
int stdout_fd = open(stdio_dev, O_WRONLY);
|
||||
assert(stdout_fd > 0);
|
||||
__stdout.ptr = (void *)(intptr_t)(stdout_fd);
|
||||
}
|
||||
#else /* CONFIG_VFS_SUPPORT_IO */
|
||||
void esp_libc_init_global_stdio(void)
|
||||
{
|
||||
__lock_init_recursive(stdin->lock);
|
||||
__lock_init_recursive(stdout->lock);
|
||||
/* Nothing to do. */
|
||||
}
|
||||
#endif /* CONFIG_VFS_SUPPORT_IO */
|
||||
|
||||
|
||||
@@ -105,6 +105,10 @@ int fcntl(int fd, int cmd, ...)
|
||||
return _fcntl_r(__getreent(), fd, cmd, arg);
|
||||
}
|
||||
|
||||
int getpid()
|
||||
{
|
||||
return _getpid_r(__getreent());
|
||||
}
|
||||
#endif // CONFIG_LIBC_PICOLIBC
|
||||
|
||||
void _exit(int __status)
|
||||
|
||||
Reference in New Issue
Block a user