From a43c509d4ba769ffc4d9c679c7cd32c9ec50eb4a Mon Sep 17 00:00:00 2001 From: Alexey Lapshin Date: Wed, 9 Aug 2023 12:11:54 +0400 Subject: [PATCH] change(newlib): update newlib according to new internal structures --- components/esp_system/startup.c | 26 ++----- components/newlib/newlib_init.c | 67 +++++++++++++++++-- .../newlib/platform_include/esp_newlib.h | 13 +++- .../newlib/platform_include/sys/reent.h | 29 +++++++- components/newlib/reent_init.c | 55 +++++---------- components/vfs/include/esp_vfs_console.h | 2 + components/vfs/vfs_console.c | 2 +- 7 files changed, 124 insertions(+), 70 deletions(-) diff --git a/components/esp_system/startup.c b/components/esp_system/startup.c index 240e2f20e2..6db1f77d02 100644 --- a/components/esp_system/startup.c +++ b/components/esp_system/startup.c @@ -305,28 +305,10 @@ static void do_core_init(void) #endif #if defined(CONFIG_VFS_SUPPORT_IO) && !defined(CONFIG_ESP_CONSOLE_NONE) - const static char *default_stdio_dev = "/dev/console/"; - esp_reent_init(_GLOBAL_REENT); - _GLOBAL_REENT->_stdin = fopen(default_stdio_dev, "r"); - _GLOBAL_REENT->_stdout = fopen(default_stdio_dev, "w"); - _GLOBAL_REENT->_stderr = fopen(default_stdio_dev, "w"); -#if ESP_ROM_NEEDS_SWSETUP_WORKAROUND - /* - - This workaround for printf functions using 32-bit time_t after the 64-bit time_t upgrade - - The 32-bit time_t usage is triggered through ROM Newlib functions printf related functions calling __swsetup_r() on - the first call to a particular file pointer (i.e., stdin, stdout, stderr) - - Thus, we call the toolchain version of __swsetup_r() now (before any printf calls are made) to setup all of the - file pointers. Thus, the ROM newlib code will never call the ROM version of __swsetup_r(). - - See IDFGH-7728 for more details - */ - extern int __swsetup_r(struct _reent *, FILE *); - __swsetup_r(_GLOBAL_REENT, _GLOBAL_REENT->_stdout); - __swsetup_r(_GLOBAL_REENT, _GLOBAL_REENT->_stderr); - __swsetup_r(_GLOBAL_REENT, _GLOBAL_REENT->_stdin); -#endif // ESP_ROM_NEEDS_SWSETUP_WORKAROUND -#else // defined(CONFIG_VFS_SUPPORT_IO) && !defined(CONFIG_ESP_CONSOLE_NONE) - _REENT_SMALL_CHECK_INIT(_GLOBAL_REENT); -#endif // defined(CONFIG_VFS_SUPPORT_IO) && !defined(CONFIG_ESP_CONSOLE_NONE) + esp_newlib_init_global_stdio(ESP_VFS_DEV_CONSOLE); +#else + esp_newlib_init_global_stdio(NULL); +#endif esp_err_t err __attribute__((unused)); diff --git a/components/newlib/newlib_init.c b/components/newlib/newlib_init.c index f966b790ed..2c9b798c74 100644 --- a/components/newlib/newlib_init.c +++ b/components/newlib/newlib_init.c @@ -39,8 +39,6 @@ #include "esp32p4/rom/libc_stubs.h" #endif -static struct _reent s_reent; - extern int _printf_float(struct _reent *rptr, void *pdata, FILE * fp, @@ -58,6 +56,21 @@ static void raise_r_stub(struct _reent *rptr) _raise_r(rptr, 0); } +static void esp_cleanup_r (struct _reent *rptr) +{ + if (_REENT_STDIN(rptr) != _REENT_STDIN(_GLOBAL_REENT)) { + _fclose_r(rptr, _REENT_STDIN(rptr)); + } + + if (_REENT_STDOUT(rptr) != _REENT_STDOUT(_GLOBAL_REENT)) { + _fclose_r(rptr, _REENT_STDOUT(rptr)); + } + + if (_REENT_STDERR(rptr) !=_REENT_STDERR(_GLOBAL_REENT)) { + _fclose_r(rptr, _REENT_STDERR(rptr)); + } +} + static struct syscall_stub_table s_stub_table = { .__getreent = &__getreent, ._malloc_r = &_malloc_r, @@ -120,14 +133,14 @@ static struct syscall_stub_table s_stub_table = { */ .__assert_func = __assert_func, - /* We don't expect either ROM code or IDF to ever call __sinit, so it's implemented as abort() for now. + /* We don't expect either ROM code to ever call __sinit, so it's implemented as abort() for now. - esp_reent_init() does this job inside IDF. - - Kept in the syscall table in case we find a need for it later. + __sinit may be called in IDF side only if /dev/console used as input/output. It called only + once for _GLOBAL_REENT. Then reuse std file pointers from _GLOBAL_REENT in another reents. + See esp_newlib_init() and esp_reent_init() for details. */ .__sinit = (void *)abort, - ._cleanup_r = &_cleanup_r, + ._cleanup_r = &esp_cleanup_r, #endif }; @@ -141,7 +154,17 @@ void esp_newlib_init(void) syscall_table_ptr = &s_stub_table; #endif +#if __NEWLIB__ > 4 || ( __NEWLIB__ == 4 && __NEWLIB_MINOR__ > 1 ) /* TODO: IDF-8134 */ + memset(&__sglue, 0, sizeof(__sglue)); + _global_impure_ptr = _GLOBAL_REENT; +#else + static struct _reent s_reent; _GLOBAL_REENT = &s_reent; +#endif + + /* Ensure that the initialization of sfp is prevented until esp_newlib_init_global_stdio() is explicitly invoked. */ + _GLOBAL_REENT->__cleanup = esp_cleanup_r; + _REENT_SDIDINIT(_GLOBAL_REENT) = 1; environ = malloc(sizeof(char*)); if (environ == 0) { @@ -154,3 +177,33 @@ void esp_newlib_init(void) } void esp_setup_newlib_syscalls(void) __attribute__((alias("esp_newlib_init"))); + +void esp_newlib_init_global_stdio(const char *stdio_dev) +{ + if (stdio_dev == NULL) + { + _GLOBAL_REENT->__cleanup = NULL; + _REENT_SDIDINIT(_GLOBAL_REENT) = 0; + __sinit(_GLOBAL_REENT); + _GLOBAL_REENT->__cleanup = esp_cleanup_r; + _REENT_SDIDINIT(_GLOBAL_REENT) = 1; + } else { + _REENT_STDIN(_GLOBAL_REENT) = fopen(stdio_dev, "r"); + _REENT_STDOUT(_GLOBAL_REENT) = fopen(stdio_dev, "w"); + _REENT_STDERR(_GLOBAL_REENT) = fopen(stdio_dev, "w"); +#if ESP_ROM_NEEDS_SWSETUP_WORKAROUND + /* + - This workaround for printf functions using 32-bit time_t after the 64-bit time_t upgrade + - The 32-bit time_t usage is triggered through ROM Newlib functions printf related functions calling __swsetup_r() on + the first call to a particular file pointer (i.e., stdin, stdout, stderr) + - Thus, we call the toolchain version of __swsetup_r() now (before any printf calls are made) to setup all of the + file pointers. Thus, the ROM newlib code will never call the ROM version of __swsetup_r(). + - See IDFGH-7728 for more details + */ + extern int __swsetup_r (struct _reent *, FILE *); + __swsetup_r(_GLOBAL_REENT, _REENT_STDIN(_GLOBAL_REENT)); + __swsetup_r(_GLOBAL_REENT, _REENT_STDOUT(_GLOBAL_REENT)); + __swsetup_r(_GLOBAL_REENT, _REENT_STDERR(_GLOBAL_REENT)); +#endif /* ESP_ROM_NEEDS_SWSETUP_WORKAROUND */ + } +} diff --git a/components/newlib/platform_include/esp_newlib.h b/components/newlib/platform_include/esp_newlib.h index 7912100b51..fe5e4cf343 100644 --- a/components/newlib/platform_include/esp_newlib.h +++ b/components/newlib/platform_include/esp_newlib.h @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: 2015-2022 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2015-2023 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ @@ -25,6 +25,17 @@ void esp_newlib_time_init(void); */ void esp_reent_init(struct _reent* r); +/** + * Postponed _GLOBAL_REENT stdio FPs initialization. + * + * Can not be a part of esp_reent_init() because stdio device may not initialized yet. + * + * Called from startup code and FreeRTOS, not intended to be called from + * application code. + * + */ +void esp_newlib_init_global_stdio(const char* stdio_dev); + /** * Clean up some of lazily allocated buffers in REENT structures. */ diff --git a/components/newlib/platform_include/sys/reent.h b/components/newlib/platform_include/sys/reent.h index 845f66161e..0be3983d27 100644 --- a/components/newlib/platform_include/sys/reent.h +++ b/components/newlib/platform_include/sys/reent.h @@ -1,22 +1,47 @@ /* - * SPDX-FileCopyrightText: 2020-2022 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2020-2023 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ #pragma once +#if __NEWLIB__ > 4 || ( __NEWLIB__ == 4 && __NEWLIB_MINOR__ > 1 ) /* TODO: IDF-8134 */ +#define _REENT_BACKWARD_BINARY_COMPAT +#define _REENT_SDIDINIT(_ptr) ((_ptr)->_reserved_0) +#define _REENT_SGLUE(_ptr) (__sglue) +#else +#define _REENT_CLEANUP(_ptr) ((_ptr)->__cleanup) +#define _REENT_STDIN(_ptr) ((_ptr)->_stdin) +#define _REENT_STDOUT(_ptr) ((_ptr)->_stdout) +#define _REENT_STDERR(_ptr) ((_ptr)->_stderr) +#define _REENT_SDIDINIT(_ptr) ((_ptr)->__sdidinit) +#define _REENT_SGLUE(_ptr) ((_ptr)->__sglue) +#endif + #include_next + #ifdef __cplusplus extern "C" { #endif +#if __NEWLIB__ > 4 || ( __NEWLIB__ == 4 && __NEWLIB_MINOR__ > 1 ) /* TODO: IDF-8134 */ + +extern void __sinit (struct _reent *); + +extern struct _glue __sglue; +extern struct _reent * _global_impure_ptr; + +#else /* __NEWLIB__ > 4 || ( __NEWLIB__ == 4 && __NEWLIB_MINOR__ > 1 ) */ + /* This function is not part of the newlib API, it is defined in libc/stdio/local.h * There is no nice way to get __cleanup member populated while avoiding __sinit, * so extern declaration is used here. */ -extern void _cleanup_r(struct _reent* r); +extern void _cleanup_r(struct _reent *); + +#endif /* __NEWLIB__ > 4 || ( __NEWLIB__ == 4 && __NEWLIB_MINOR__ > 1 ) */ #ifdef __cplusplus } diff --git a/components/newlib/reent_init.c b/components/newlib/reent_init.c index 9f6ee0d546..7d8ade98f8 100644 --- a/components/newlib/reent_init.c +++ b/components/newlib/reent_init.c @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: 2015-2022 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2015-2023 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ @@ -22,14 +22,11 @@ void IRAM_ATTR esp_reent_init(struct _reent* r) { memset(r, 0, sizeof(*r)); - r->_stdout = _GLOBAL_REENT->_stdout; - r->_stderr = _GLOBAL_REENT->_stderr; - r->_stdin = _GLOBAL_REENT->_stdin; - r->__cleanup = &_cleanup_r; - r->__sdidinit = 1; - r->__sglue._next = NULL; - r->__sglue._niobs = 0; - r->__sglue._iobs = NULL; + _REENT_STDIN(r) = _REENT_STDIN(_GLOBAL_REENT); + _REENT_STDOUT(r) = _REENT_STDOUT(_GLOBAL_REENT); + _REENT_STDERR(r) = _REENT_STDERR(_GLOBAL_REENT); + _REENT_CLEANUP(r) = _REENT_CLEANUP(_GLOBAL_REENT); + _REENT_SDIDINIT(r) = _REENT_SDIDINIT(_GLOBAL_REENT); } /* only declared in private stdio header file, local.h */ @@ -39,26 +36,20 @@ extern void __sfp_lock_release(void); void esp_reent_cleanup(void) { struct _reent* r = __getreent(); - /* Clean up storage used by mprec functions */ - if (r->_mp) { - if (_REENT_MP_FREELIST(r)) { - for (unsigned int i = 0; i < _Kmax; ++i) { - struct _Bigint *cur, *next; - next = _REENT_MP_FREELIST(r)[i]; - while (next) { - cur = next; - next = next->_next; - free(cur); - } - } - } - free(_REENT_MP_FREELIST(r)); - free(_REENT_MP_RESULT(r)); - } + _reclaim_reent(r); + + r->_emergency = NULL; + r->_mp = NULL; + r->_r48 = NULL; + r->_localtime_buf = NULL; + r->_asctime_buf = NULL; + r->_signal_buf = NULL; + r->_misc = NULL; + r->_cvtbuf = NULL; /* Clean up "glue" (lazily-allocated FILE objects) */ - struct _glue* prev = &_GLOBAL_REENT->__sglue; - for (struct _glue* cur = _GLOBAL_REENT->__sglue._next; cur != NULL;) { + struct _glue* prev = &_REENT_SGLUE(_GLOBAL_REENT); + for (struct _glue* cur = _REENT_SGLUE(_GLOBAL_REENT)._next; cur != NULL;) { if (cur->_niobs == 0) { cur = cur->_next; continue; @@ -81,14 +72,4 @@ void esp_reent_cleanup(void) free(cur); cur = next; } - - /* Clean up various other buffers */ - free(r->_mp); - r->_mp = NULL; - free(r->_r48); - r->_r48 = NULL; - free(r->_localtime_buf); - r->_localtime_buf = NULL; - free(r->_asctime_buf); - r->_asctime_buf = NULL; } diff --git a/components/vfs/include/esp_vfs_console.h b/components/vfs/include/esp_vfs_console.h index bc5ce6733d..3ac6e31add 100644 --- a/components/vfs/include/esp_vfs_console.h +++ b/components/vfs/include/esp_vfs_console.h @@ -8,6 +8,8 @@ #include "esp_err.h" +#define ESP_VFS_DEV_CONSOLE "/dev/console" + #ifdef __cplusplus extern "C" { #endif diff --git a/components/vfs/vfs_console.c b/components/vfs/vfs_console.c index caf2ec1aaf..1360be33cc 100644 --- a/components/vfs/vfs_console.c +++ b/components/vfs/vfs_console.c @@ -188,7 +188,7 @@ static const esp_vfs_t vfs = { esp_err_t esp_vfs_dev_console_register(void) { - return esp_vfs_register("/dev/console", &vfs, NULL); + return esp_vfs_register(ESP_VFS_DEV_CONSOLE, &vfs, NULL); } esp_err_t esp_vfs_console_register(void)