From 92fed2c1422e628b92b02681f7642dab16d0ca8d Mon Sep 17 00:00:00 2001 From: Juan Carrano Date: Mon, 28 May 2018 10:04:35 +0200 Subject: [PATCH 1/7] sys/newlib_syscalls_riot_clock: Implement clock() using xtimer. Newlib's clock() depends on times() (which has to be supplied by the os). This patch add two new (sub)modules: - newlib_syscalls_riot_clock uses xtimer to provide for the clock() function. - newlib_stubs_clock provides a stub implementation for _times_r() in case xtimer is not available and a stub is acceptable. The new modules `newlib_syscalls_riot` and `newlib_stubs` are meant to contain the rest of the system calls that will be split from newlib_syscalls_default by groups. For ease of use, if xtimer is used, the newlib_syscalls_riot_clock is automatically included. This can be prevented by explicitly adding newlib_stubs_clock to USEMODULE. The test, tests/libc_time_h_relative, can be compiled with or without USEMODULE=newlib_stubs_clock to see the difference. --- Makefile.dep | 19 ++++++++- makefiles/pseudomodules.inc.mk | 4 ++ sys/Makefile.include | 8 ++++ sys/newlib_stubs/Makefile | 3 ++ sys/newlib_stubs/Makefile.include | 4 ++ sys/newlib_stubs/clock.c | 41 ++++++++++++++++++ sys/newlib_stubs/doc.txt | 22 ++++++++++ sys/newlib_syscalls_default/syscalls.c | 15 ------- sys/newlib_syscalls_riot/Makefile | 3 ++ sys/newlib_syscalls_riot/Makefile.include | 3 ++ sys/newlib_syscalls_riot/clock.c | 52 +++++++++++++++++++++++ sys/newlib_syscalls_riot/doc.txt | 27 ++++++++++++ sys/xtimer/xtimer.c | 1 - tests/libc_time_h_relative/Makefile | 6 +++ tests/libc_time_h_relative/main.c | 52 +++++++++++++++++++++++ 15 files changed, 243 insertions(+), 17 deletions(-) create mode 100644 sys/newlib_stubs/Makefile create mode 100644 sys/newlib_stubs/Makefile.include create mode 100644 sys/newlib_stubs/clock.c create mode 100644 sys/newlib_stubs/doc.txt create mode 100644 sys/newlib_syscalls_riot/Makefile create mode 100644 sys/newlib_syscalls_riot/Makefile.include create mode 100644 sys/newlib_syscalls_riot/clock.c create mode 100644 sys/newlib_syscalls_riot/doc.txt create mode 100644 tests/libc_time_h_relative/Makefile create mode 100644 tests/libc_time_h_relative/main.c diff --git a/Makefile.dep b/Makefile.dep index 4011310d126b..7fabcb7138d8 100644 --- a/Makefile.dep +++ b/Makefile.dep @@ -369,14 +369,31 @@ endif ifneq (,$(filter newlib,$(USEMODULE))) # allow custom newlib syscalls implementations by adding # newlib_syscalls_XXX to USEMODULE - ifeq (,$(filter newlib_syscalls_%,$(USEMODULE))) + # Once all syscall are split into "real" implementations and stubs, this + # module should go away + ifeq (,$(filter-out newlib_syscalls_riot_%,$(filter newlib_syscalls_%,$(USEMODULE)))) USEMODULE += newlib_syscalls_default endif + # If xtimer is available, use it to provide the clock function, but only if + # the stub module was not explicitly selected + ifeq (,$(filter newlib_stubs_clock,$(USEMODULE))) + ifneq (,$(filter xtimer,$(USEMODULE))) + USEMODULE += newlib_syscalls_riot_clock + endif + endif ifeq (,$(filter stdio_rtt,$(USEMODULE))) USEMODULE += stdio_uart endif endif +ifneq (,$(filter newlib_syscalls_riot_%,$(USEMODULE))) + USEMODULE += newlib_syscalls_riot +endif + +ifneq (,$(filter newlib_stubs_%,$(USEMODULE))) + USEMODULE += newlib_stubs +endif + ifneq (,$(filter posix_sockets,$(USEMODULE))) USEMODULE += bitfield USEMODULE += random diff --git a/makefiles/pseudomodules.inc.mk b/makefiles/pseudomodules.inc.mk index 6a4551ad06a2..53e09c02b873 100644 --- a/makefiles/pseudomodules.inc.mk +++ b/makefiles/pseudomodules.inc.mk @@ -132,4 +132,8 @@ PSEUDOMODULES += crypto_aes_precalculated # This pseudomodule causes a loop in AES to be unrolled (more flash, less CPU) PSEUDOMODULES += crypto_aes_unroll +# Newlib system call implementation and stubs are submodules +PSEUDOMODULES += newlib_syscalls_riot_% +PSEUDOMODULES += newlib_stubs_% + # Packages may also add modules to PSEUDOMODULES in their `Makefile.include`. diff --git a/sys/Makefile.include b/sys/Makefile.include index b87126c5388f..2ae6ba5a5abe 100644 --- a/sys/Makefile.include +++ b/sys/Makefile.include @@ -68,6 +68,14 @@ ifneq (,$(filter newlib_syscalls_default,$(USEMODULE))) include $(RIOTBASE)/sys/newlib_syscalls_default/Makefile.include endif +ifneq (,$(filter newlib_stubs_%,$(USEMODULE))) + include $(RIOTBASE)/sys/newlib_stubs/Makefile.include +endif + +ifneq (,$(filter newlib_syscalls_riot_%,$(USEMODULE))) + include $(RIOTBASE)/sys/newlib_syscalls_riot/Makefile.include +endif + ifneq (,$(filter arduino,$(USEMODULE))) include $(RIOTBASE)/sys/arduino/Makefile.include endif diff --git a/sys/newlib_stubs/Makefile b/sys/newlib_stubs/Makefile new file mode 100644 index 000000000000..af0d9326a5f0 --- /dev/null +++ b/sys/newlib_stubs/Makefile @@ -0,0 +1,3 @@ +SUBMODULES = 1 + +include $(RIOTBASE)/Makefile.base diff --git a/sys/newlib_stubs/Makefile.include b/sys/newlib_stubs/Makefile.include new file mode 100644 index 000000000000..4b7d4af4ab11 --- /dev/null +++ b/sys/newlib_stubs/Makefile.include @@ -0,0 +1,4 @@ +ifneq (,$(filter newlib_stubs_clock,$(USEMODULE))) + UNDEF += $(BINDIR)/newlib_stubs/clock.o +endif + diff --git a/sys/newlib_stubs/clock.c b/sys/newlib_stubs/clock.c new file mode 100644 index 000000000000..e1cdc22a4f7a --- /dev/null +++ b/sys/newlib_stubs/clock.c @@ -0,0 +1,41 @@ +/* + * Copyright (C) 2018 FU Berlin + * + * This file is subject to the terms and conditions of the GNU Lesser + * General Public License v2.1. See the file LICENSE in the top level + * directory for more details. + */ + +/** + * @ingroup sys_newlib_stubs + * @{ + * + * @file + * @brief Provide stub for _times_r (process' CPU time). + * + * By providing _times_r this module indirectly provides a stub for clock(). + * If a real implementation is needed, see the newlib_syscalls_clock module. + * + * @author Juan Carrano + * + * @} + */ + +#include +#include +#include + +/** + * Current process times (not implemented). + * + * @param[out] ptms Not modified. + * + * @return -1, this function always fails. errno is set to ENOSYS. + */ +clock_t _times_r(struct _reent *ptr, struct tms *ptms) +{ + (void)ptms; + ptr->_errno = ENOSYS; + + return (-1); +} diff --git a/sys/newlib_stubs/doc.txt b/sys/newlib_stubs/doc.txt new file mode 100644 index 000000000000..9d4ac1079b22 --- /dev/null +++ b/sys/newlib_stubs/doc.txt @@ -0,0 +1,22 @@ +/** + * @ingroup sys + * @defgroup sys_newlib_stubs Newlib system call stubs + * + * + * These module provide stubs (functions that always return an error) for the + * system calls required by newlib: + * + * - File handling: _open_r, _close_r, _lseek_r, _read_r, _write_r, _stat_r, + * _fstat_r, _link_r, _unlink_r, _fcntl_r + * - Process control: _execve_r, _wait_r, _fork_r, _getpid_r + * - Memory management: _sbrk_r + * - Timekeeping: _gettimeofday_r, _times_r + * + * Stubs for these functions can be found in the newlib source, under newlib/libc/reent/. + * + * Stubs may be needed if an external module uses a standard library function + * that depends on a syscall, but it is not desired to pull in the code needed + * to support it (for example, there is no point in having VFS if there is no + * storage support.) In many of these cases it is perfectly acceptable if those + * functions do nothing but fail. + */ diff --git a/sys/newlib_syscalls_default/syscalls.c b/sys/newlib_syscalls_default/syscalls.c index 7eebf5010994..f5ab96c99391 100644 --- a/sys/newlib_syscalls_default/syscalls.c +++ b/sys/newlib_syscalls_default/syscalls.c @@ -537,18 +537,3 @@ int _gettimeofday_r(struct _reent *r, struct timeval *restrict tp, void *restric return -1; } #endif - -/** - * Current process times (not implemented). - * - * @param[out] ptms Not modified. - * - * @return -1, this function always fails. errno is set to ENOSYS. - */ -clock_t _times_r(struct _reent *ptr, struct tms *ptms) -{ - (void)ptms; - ptr->_errno = ENOSYS; - - return (-1); -} diff --git a/sys/newlib_syscalls_riot/Makefile b/sys/newlib_syscalls_riot/Makefile new file mode 100644 index 000000000000..cd1af2456e05 --- /dev/null +++ b/sys/newlib_syscalls_riot/Makefile @@ -0,0 +1,3 @@ +SUBMODULES := 1 + +include $(RIOTBASE)/Makefile.base diff --git a/sys/newlib_syscalls_riot/Makefile.include b/sys/newlib_syscalls_riot/Makefile.include new file mode 100644 index 000000000000..7f261677666d --- /dev/null +++ b/sys/newlib_syscalls_riot/Makefile.include @@ -0,0 +1,3 @@ +ifneq (,$(filter newlib_syscalls_riot_clock,$(USEMODULE))) + UNDEF += $(BINDIR)/newlib_syscalls_riot/clock.o +endif diff --git a/sys/newlib_syscalls_riot/clock.c b/sys/newlib_syscalls_riot/clock.c new file mode 100644 index 000000000000..f917100554b3 --- /dev/null +++ b/sys/newlib_syscalls_riot/clock.c @@ -0,0 +1,52 @@ +/* + * Copyright (C) 2018 FU Berlin + * + * This file is subject to the terms and conditions of the GNU Lesser + * General Public License v2.1. See the file LICENSE in the top level + * directory for more details. + */ + +/** + * @ingroup sys_newlib_syscalls_riot + * @file + * + * @author Juan Carrano + * + * @brief clock() system call (using xtimer) + * + * This module uses xtimer to implement the clock() system call, that is, + * relative timings. If the functionality is not required, but only that the + * symbol is present to avoid a linking error, use the stub in the + * newlib_stub_clock module. + * + */ + +#include + +#include "xtimer.h" + +/** + * @brief Get the processor time used by the program. + * + * This implements the C standard function clock(). The return value must be + * divided by CLOCKS_PER_SEC to give a value in seconds. + * + * To use this function you should include + * + * @note Since RIOT is a single process (with multiple threads), this function is + * equivalent to the wall time elapsed since boot. Idle time is also considered + * as time used by the program. + * + * @return Time used by RIOT (in arbitrary units of "CLOCKS") + */ +clock_t clock(void) +{ + timex_t now; + + /* By using a timex_t we have two 32 bit values and that makes it easier to + * convert to clock_t without overflow */ + xtimer_now_timex(&now); + + return ((clock_t)now.seconds) * CLOCKS_PER_SEC + + ((clock_t)now.microseconds) * CLOCKS_PER_SEC / US_PER_SEC; +} diff --git a/sys/newlib_syscalls_riot/doc.txt b/sys/newlib_syscalls_riot/doc.txt new file mode 100644 index 000000000000..4c20db892e99 --- /dev/null +++ b/sys/newlib_syscalls_riot/doc.txt @@ -0,0 +1,27 @@ +/** + * @ingroup sys + * @defgroup sys_newlib_syscalls_riot RIOT-Newlib system calls + * + * + * @brief Implementation if system calls for newlib using RIOT functionality. + * + * The submodules in here use RIOT modules to provide a portable set of system + * calls for newlib. + * + * System calls are split into submodules according to which of RIOT's module + * they require. Special logic in Makefile.dep causes the correct system calls + * to be enabled automatically whenever the required modules are enabled. + * + * For example, using xtimer automatically causes newlib_syscalls_riot_clock to + * be used. + * + * If the functionality of these system calls is not needed, but only their + * existence, to avoid a linking error the newlib_stubs module can be used. + * This can be useful if one has a package that uses functionality in the + * standard library that requires the system calls, but it is not a problem if + * those calls always fail. + * + * Submodules: + * + * - sys_newlib_syscalls_riot_clock + */ diff --git a/sys/xtimer/xtimer.c b/sys/xtimer/xtimer.c index ff6dccf0f492..aff9a31b98b6 100644 --- a/sys/xtimer/xtimer.c +++ b/sys/xtimer/xtimer.c @@ -20,7 +20,6 @@ #include #include -#include #include "xtimer.h" #include "mutex.h" diff --git a/tests/libc_time_h_relative/Makefile b/tests/libc_time_h_relative/Makefile new file mode 100644 index 000000000000..bcf7d32bb7c0 --- /dev/null +++ b/tests/libc_time_h_relative/Makefile @@ -0,0 +1,6 @@ +include ../Makefile.tests_common + +USEMODULE += xtimer +USEMODULE += newlib + +include $(RIOTBASE)/Makefile.include diff --git a/tests/libc_time_h_relative/main.c b/tests/libc_time_h_relative/main.c new file mode 100644 index 000000000000..a4b6ddca9f6b --- /dev/null +++ b/tests/libc_time_h_relative/main.c @@ -0,0 +1,52 @@ +/* + * Copyright (C) 2018 FU Berlin + * + * This file is subject to the terms and conditions of the GNU Lesser + * General Public License v2.1. See the file LICENSE in the top level + * directory for more details. + */ +/** + * @ingroup tests + * @{ + * + * @file + * @brief Test standard C functions for getting relative time (i.e. no RTC) + * + * @author Juan Carrano + * + * @} + */ + +#include +#include + +#include "xtimer.h" + +int main(void) +{ + printf("Hello"); + + while (1) { + clock_t t0, t1, td; + int i; + + t0 = clock(); + printf("time: raw=%lu, seconds=%lu\n", t0, t0/CLOCKS_PER_SEC); + + for(i=0; i<100; i++) { + putchar('.'); + fflush(stdout); + xtimer_usleep(50000); + } + putchar('\n'); + + t1 = clock(); + td = t1 - t0; + + printf("time difference: raw=%lu, seconds=%lu final=%lu\n", + td, td/CLOCKS_PER_SEC, t1/CLOCKS_PER_SEC); + + xtimer_usleep(1000000); + } + return 0; +} From 2e7311ac04140227c0a2a9df7d5c68fe8297ec09 Mon Sep 17 00:00:00 2001 From: Juan Carrano Date: Thu, 31 May 2018 16:29:30 +0200 Subject: [PATCH 2/7] sys/newlib_syscalls_riot_time: Implement standard time() using the RTC. Add a new "time" submodule to newlib_syscalls_riot that implements the C standard library function "time()" using the RTC. A stub module "newlib_stubs_time" is also provided for those cases where an RTC is not present but some package requires time() in order to link properly. The prvious implementation in newlib_syscalls_default was buggy in that it provided CPU time. If periph_rtc is used, and newlib_stubs_time was not explicitly selected, then the newlib_syscalls_riot_time module will be used automatically. libc_time_h_absolute provides a test compile with: ``` USEMODULE=newlib_stubs_time BOARD=saml21-xpro make -C tests/libc_time_h_absolute all flash term ``` To use the stub and remove the USEMODULE thing to use the real rtc implemetation. --- Makefile.dep | 5 ++ sys/newlib_stubs/Makefile.include | 3 ++ sys/newlib_stubs/time.c | 43 +++++++++++++++++ sys/newlib_syscalls_default/syscalls.c | 26 ----------- sys/newlib_syscalls_riot/Makefile.include | 4 ++ sys/newlib_syscalls_riot/doc.txt | 1 + sys/newlib_syscalls_riot/time.c | 56 +++++++++++++++++++++++ tests/libc_time_h_absolute/Makefile | 6 +++ tests/libc_time_h_absolute/main.c | 36 +++++++++++++++ 9 files changed, 154 insertions(+), 26 deletions(-) create mode 100644 sys/newlib_stubs/time.c create mode 100644 sys/newlib_syscalls_riot/time.c create mode 100644 tests/libc_time_h_absolute/Makefile create mode 100644 tests/libc_time_h_absolute/main.c diff --git a/Makefile.dep b/Makefile.dep index 7fabcb7138d8..7917342d1af4 100644 --- a/Makefile.dep +++ b/Makefile.dep @@ -381,6 +381,11 @@ ifneq (,$(filter newlib,$(USEMODULE))) USEMODULE += newlib_syscalls_riot_clock endif endif + ifeq (,$(filter newlib_stubs_time,$(USEMODULE))) + ifneq (,$(filter periph_rtc,$(USEMODULE))) + USEMODULE += newlib_syscalls_riot_time + endif + endif ifeq (,$(filter stdio_rtt,$(USEMODULE))) USEMODULE += stdio_uart endif diff --git a/sys/newlib_stubs/Makefile.include b/sys/newlib_stubs/Makefile.include index 4b7d4af4ab11..df733e9589c1 100644 --- a/sys/newlib_stubs/Makefile.include +++ b/sys/newlib_stubs/Makefile.include @@ -2,3 +2,6 @@ ifneq (,$(filter newlib_stubs_clock,$(USEMODULE))) UNDEF += $(BINDIR)/newlib_stubs/clock.o endif +ifneq (,$(filter newlib_stubs_time,$(USEMODULE))) + UNDEF += $(BINDIR)/newlib_stubs/time.o +endif diff --git a/sys/newlib_stubs/time.c b/sys/newlib_stubs/time.c new file mode 100644 index 000000000000..c1388d41ebc0 --- /dev/null +++ b/sys/newlib_stubs/time.c @@ -0,0 +1,43 @@ +/* + * Copyright (C) 2018 FU Berlin + * + * This file is subject to the terms and conditions of the GNU Lesser + * General Public License v2.1. See the file LICENSE in the top level + * directory for more details. + */ + +/** + * @ingroup sys_newlib_stubs + * @{ + * + * @file + * @brief Provide stub for _gettimeofday_r (wall time). + * + * @author Juan Carrano + * + * @} + */ + +#include +#include +#include + +/** + * Get wall time in milliseconds since the epoch (not implemented). + * + * This is a stub that always fails for systems without RTC. + * + * @param[out] r Reentrant structure. + * @param[out] tp Not modified. + * @param tpz Not used. + * + * @return -1, this function always fails. errno is set to ENOSYS. + */ +int _gettimeofday_r(struct _reent *r, struct timeval *restrict tp, + void *restrict tzp) +{ + (void) tp; + (void) tzp; + r->_errno = ENOSYS; + return -1; +} diff --git a/sys/newlib_syscalls_default/syscalls.c b/sys/newlib_syscalls_default/syscalls.c index f5ab96c99391..bf45284baa13 100644 --- a/sys/newlib_syscalls_default/syscalls.c +++ b/sys/newlib_syscalls_default/syscalls.c @@ -49,12 +49,6 @@ #include -#ifdef MODULE_XTIMER -#include -#include "div.h" -#include "xtimer.h" -#endif - /** * @brief manage the heap */ @@ -517,23 +511,3 @@ int _kill(pid_t pid, int sig) errno = ESRCH; /* not implemented yet */ return -1; } - -#ifdef MODULE_XTIMER -int _gettimeofday_r(struct _reent *r, struct timeval *restrict tp, void *restrict tzp) -{ - (void) r; - (void) tzp; - uint64_t now = xtimer_now_usec64(); - tp->tv_sec = div_u64_by_1000000(now); - tp->tv_usec = now - (tp->tv_sec * US_PER_SEC); - return 0; -} -#else -int _gettimeofday_r(struct _reent *r, struct timeval *restrict tp, void *restrict tzp) -{ - (void) tp; - (void) tzp; - r->_errno = ENOSYS; - return -1; -} -#endif diff --git a/sys/newlib_syscalls_riot/Makefile.include b/sys/newlib_syscalls_riot/Makefile.include index 7f261677666d..48777c4c6e12 100644 --- a/sys/newlib_syscalls_riot/Makefile.include +++ b/sys/newlib_syscalls_riot/Makefile.include @@ -1,3 +1,7 @@ ifneq (,$(filter newlib_syscalls_riot_clock,$(USEMODULE))) UNDEF += $(BINDIR)/newlib_syscalls_riot/clock.o endif + +ifneq (,$(filter newlib_syscalls_riot_time,$(USEMODULE))) + UNDEF += $(BINDIR)/newlib_syscalls_riot/time.o +endif diff --git a/sys/newlib_syscalls_riot/doc.txt b/sys/newlib_syscalls_riot/doc.txt index 4c20db892e99..de52d59794a8 100644 --- a/sys/newlib_syscalls_riot/doc.txt +++ b/sys/newlib_syscalls_riot/doc.txt @@ -24,4 +24,5 @@ * Submodules: * * - sys_newlib_syscalls_riot_clock + * - sys_newlib_syscalls_riot_time */ diff --git a/sys/newlib_syscalls_riot/time.c b/sys/newlib_syscalls_riot/time.c new file mode 100644 index 000000000000..3bcceeda470f --- /dev/null +++ b/sys/newlib_syscalls_riot/time.c @@ -0,0 +1,56 @@ +/* + * Copyright (C) 2018 FU Berlin + * + * This file is subject to the terms and conditions of the GNU Lesser + * General Public License v2.1. See the file LICENSE in the top level + * directory for more details. + */ + +/** + * @ingroup sys_newlib_syscalls_riot + * @{ + * + * @file + * @brief Implement standard C's time() using the RTC. + * + * @author Juan Carrano + * + * @} + */ + +#include + +#include "periph/rtc.h" + +/** + * Seconds since the epoch. + * + * This function oveerides the standard libraries time(). It gets the time + * directly from the RTC. It is compiled automatically if the RTC peripheral + * is enabled. + * + * time() is implemented instead of the lower level _gettimeofday_r because + * _gettimeofday_r is defined in microseconds, which RIOT's RTC does not provide. + * + * @param[out] tloc If tloc is non-NULL, the return value is also stored in + * the memory pointed to by tloc. Note that this parameter is + * deprecated and must be set to null in new code. + * + * @return Number of seconds since 1970-01-01 00:00:00 +0000 (UTC). + */ +time_t time(time_t *tloc) +{ + struct tm t; + time_t r; + + if (rtc_get_time(&t) >= 0) { + r = mktime(&t); + } else { + r = (time_t)(-1); + } + + if (tloc) + *tloc = r; + + return r; +} diff --git a/tests/libc_time_h_absolute/Makefile b/tests/libc_time_h_absolute/Makefile new file mode 100644 index 000000000000..56c339cc3c36 --- /dev/null +++ b/tests/libc_time_h_absolute/Makefile @@ -0,0 +1,6 @@ +include ../Makefile.tests_common + +USEMODULE += newlib +USEMODULE += periph_rtc + +include $(RIOTBASE)/Makefile.include diff --git a/tests/libc_time_h_absolute/main.c b/tests/libc_time_h_absolute/main.c new file mode 100644 index 000000000000..b9804ad0848d --- /dev/null +++ b/tests/libc_time_h_absolute/main.c @@ -0,0 +1,36 @@ +/* + * Copyright (C) 2018 FU Berlin + * + * This file is subject to the terms and conditions of the GNU Lesser + * General Public License v2.1. See the file LICENSE in the top level + * directory for more details. + */ +/** + * @ingroup tests + * @{ + * + * @file + * @brief Test standard C functions for getting absolute time (using RTC) + * + * @author Juan Carrano + * + * @} + */ + +#include +#include + +int main(void) +{ + while (1) { + time_t t; + + puts("Current time: "); + t = time(NULL); + puts(ctime(&t)); + putchar('\n'); + + getchar(); + } + return 0; +} From 9a844807b293fc8e4c3f919825cc33898f290577 Mon Sep 17 00:00:00 2001 From: Juan Carrano Date: Wed, 19 Dec 2018 18:34:34 +0100 Subject: [PATCH 3/7] sys/newlib_syscalls: split filesystem syscalls. The implementation of read/write/close, etc using VFS is moved to it's own submodule, newlib_syscalls_riot_vfs. The stubs for those functions (with the exception of read and write) now live in newlib_stubs_fs. The implementaion of read and write that maps every file to the UART is in newlib_syscalls_riot_serial_rw. --- Makefile.dep | 12 + sys/newlib_stubs/Makefile.include | 4 + sys/newlib_stubs/fs.c | 91 ++++++ sys/newlib_syscalls_default/syscalls.c | 324 ---------------------- sys/newlib_syscalls_riot/Makefile.include | 8 + sys/newlib_syscalls_riot/doc.txt | 2 + sys/newlib_syscalls_riot/serial_rw.c | 62 +++++ sys/newlib_syscalls_riot/vfs.c | 263 ++++++++++++++++++ 8 files changed, 442 insertions(+), 324 deletions(-) create mode 100644 sys/newlib_stubs/fs.c create mode 100644 sys/newlib_syscalls_riot/serial_rw.c create mode 100644 sys/newlib_syscalls_riot/vfs.c diff --git a/Makefile.dep b/Makefile.dep index 7917342d1af4..66349d59f19a 100644 --- a/Makefile.dep +++ b/Makefile.dep @@ -386,11 +386,23 @@ ifneq (,$(filter newlib,$(USEMODULE))) USEMODULE += newlib_syscalls_riot_time endif endif + ifeq (,$(filter newlib_stubs_fs,$(USEMODULE))) + ifneq (,$(filter vfs,$(USEMODULE))) + USEMODULE += newlib_syscalls_riot_vfs + endif + endif + ifeq (,$(filter vfs,$(USEMODULE))) + USEMODULE += newlib_syscalls_riot_serial_rw + endif ifeq (,$(filter stdio_rtt,$(USEMODULE))) USEMODULE += stdio_uart endif endif +ifneq (,$(filter newlib_syscalls_riot_serial_rw,$(USEMODULE))) + USEMODULE += stdio_uart +endif + ifneq (,$(filter newlib_syscalls_riot_%,$(USEMODULE))) USEMODULE += newlib_syscalls_riot endif diff --git a/sys/newlib_stubs/Makefile.include b/sys/newlib_stubs/Makefile.include index df733e9589c1..f676c4e029e1 100644 --- a/sys/newlib_stubs/Makefile.include +++ b/sys/newlib_stubs/Makefile.include @@ -5,3 +5,7 @@ endif ifneq (,$(filter newlib_stubs_time,$(USEMODULE))) UNDEF += $(BINDIR)/newlib_stubs/time.o endif + +ifneq (,$(filter newlib_stubs_fs,$(USEMODULE))) + UNDEF += $(BINDIR)/newlib_stubs/fs.o +endif diff --git a/sys/newlib_stubs/fs.c b/sys/newlib_stubs/fs.c new file mode 100644 index 000000000000..1e030c8e5d02 --- /dev/null +++ b/sys/newlib_stubs/fs.c @@ -0,0 +1,91 @@ +/* + * Copyright (C) 2018 Freie Universität Berlin + * 2015 Kaspar Schleiser + * 2014 Freie Universität Berlin + * + * This file is subject to the terms and conditions of the GNU Lesser General + * Public License v2.1. See the file LICENSE in the top level directory for more + * details. + */ + +/** + * @ingroup sys_newlib_stubs + * @{ + * + * @file + * @brief Stubs for filesystem routines. + * + * @author Michael Baar + * @author Stefan Pfeiffer + * @author Hauke Petersen + * @author Kaspar Schleiser + * @author Juan I Carrano + * + * @} + */ + +#include +#include + +/* Stubs to avoid linking errors, these functions do not have any effect */ +int _open_r(struct _reent *r, const char *name, int flags, int mode) +{ + (void) name; + (void) flags; + (void) mode; + r->_errno = ENODEV; + return -1; +} + +int _close_r(struct _reent *r, int fd) +{ + (void) fd; + r->_errno = ENODEV; + return -1; +} + +_off_t _lseek_r(struct _reent *r, int fd, _off_t pos, int dir) +{ + (void) fd; + (void) pos; + (void) dir; + r->_errno = ENODEV; + return -1; +} + +int _fstat_r(struct _reent *r, int fd, struct stat *st) +{ + (void) fd; + (void) st; + r->_errno = ENODEV; + return -1; +} + +int _stat_r(struct _reent *r, const char *name, struct stat *st) +{ + (void) name; + (void) st; + r->_errno = ENODEV; + return -1; +} + +int _unlink_r(struct _reent *r, const char *path) +{ + (void) path; + r->_errno = ENODEV; + return -1; +} + +/* + * Riot does not support hard links (that's why the error is ENOSYS instead + * of ENODEV. + */ +int _link_r(struct _reent *ptr, const char *old_name, const char *new_name) +{ + (void)old_name; + (void)new_name; + + ptr->_errno = ENOSYS; + + return -1; +} diff --git a/sys/newlib_syscalls_default/syscalls.c b/sys/newlib_syscalls_default/syscalls.c index bf45284baa13..26c3f6b6855c 100644 --- a/sys/newlib_syscalls_default/syscalls.c +++ b/sys/newlib_syscalls_default/syscalls.c @@ -41,14 +41,9 @@ #include "irq.h" #include "log.h" #include "periph/pm.h" -#if MODULE_VFS -#include "vfs.h" -#endif #include "stdio_base.h" -#include - /** * @brief manage the heap */ @@ -157,325 +152,6 @@ int _kill_r(struct _reent *r, pid_t pid, int sig) return -1; } -#if MODULE_VFS -/** - * @brief Open a file - * - * This is a wrapper around @c vfs_open - * - * @param r pointer to reent structure - * @param name file name to open - * @param flags flags, see man 3p open - * @param mode mode, file creation mode if the file is created when opening - * - * @return fd number (>= 0) on success - * @return -1 on error, @c r->_errno set to a constant from errno.h to indicate the error - */ -int _open_r(struct _reent *r, const char *name, int flags, int mode) -{ - int fd = vfs_open(name, flags, mode); - if (fd < 0) { - /* vfs returns negative error codes */ - r->_errno = -fd; - return -1; - } - return fd; -} - -/** - * @brief Read bytes from an open file - * - * This is a wrapper around @c vfs_read - * - * @param[in] r pointer to reent structure - * @param[in] fd open file descriptor obtained from @c open() - * @param[out] dest destination buffer - * @param[in] count maximum number of bytes to read - * - * @return number of bytes read on success - * @return -1 on error, @c r->_errno set to a constant from errno.h to indicate the error - */ -_ssize_t _read_r(struct _reent *r, int fd, void *dest, size_t count) -{ - int res = vfs_read(fd, dest, count); - if (res < 0) { - /* vfs returns negative error codes */ - r->_errno = -res; - return -1; - } - return res; -} - -/** - * @brief Write bytes to an open file - * - * This is a wrapper around @c vfs_write - * - * @param[in] r pointer to reent structure - * @param[in] fd open file descriptor obtained from @c open() - * @param[in] src source data buffer - * @param[in] count maximum number of bytes to write - * - * @return number of bytes written on success - * @return -1 on error, @c r->_errno set to a constant from errno.h to indicate the error - */ -_ssize_t _write_r(struct _reent *r, int fd, const void *src, size_t count) -{ - int res = vfs_write(fd, src, count); - if (res < 0) { - /* vfs returns negative error codes */ - r->_errno = -res; - return -1; - } - return res; -} - -/** - * @brief Close an open file - * - * This is a wrapper around @c vfs_close - * - * If this call returns an error, the fd should still be considered invalid and - * no further attempt to use it shall be made, not even to retry @c close() - * - * @param[in] r pointer to reent structure - * @param[in] fd open file descriptor obtained from @c open() - * - * @return 0 on success - * @return -1 on error, @c r->_errno set to a constant from errno.h to indicate the error - */ -int _close_r(struct _reent *r, int fd) -{ - int res = vfs_close(fd); - if (res < 0) { - /* vfs returns negative error codes */ - r->_errno = -res; - return -1; - } - return res; -} - -/** - * @brief Query or set options on an open file - * - * This is a wrapper around @c vfs_fcntl - * - * @param[in] r pointer to reent structure - * @param[in] fd open file descriptor obtained from @c open() - * @param[in] cmd fcntl command, see man 3p fcntl - * @param[in] arg argument to fcntl command, see man 3p fcntl - * - * @return 0 on success - * @return -1 on error, @c r->_errno set to a constant from errno.h to indicate the error - */ -int _fcntl_r (struct _reent *r, int fd, int cmd, int arg) -{ - int res = vfs_fcntl(fd, cmd, arg); - if (res < 0) { - /* vfs returns negative error codes */ - r->_errno = -res; - return -1; - } - return res; -} - -/** - * @brief Seek to position in file - * - * This is a wrapper around @c vfs_lseek - * - * @p whence determines the function of the seek and should be set to one of - * the following values: - * - * - @c SEEK_SET: Seek to absolute offset @p off - * - @c SEEK_CUR: Seek to current location + @p off - * - @c SEEK_END: Seek to end of file + @p off - * - * @param[in] r pointer to reent structure - * @param[in] fd open file descriptor obtained from @c open() - * @param[in] off seek offset - * @param[in] whence determines the seek method, see detailed description - * - * @return the new seek location in the file on success - * @return -1 on error, @c r->_errno set to a constant from errno.h to indicate the error - */ -_off_t _lseek_r(struct _reent *r, int fd, _off_t off, int whence) -{ - int res = vfs_lseek(fd, off, whence); - if (res < 0) { - /* vfs returns negative error codes */ - r->_errno = -res; - return -1; - } - return res; -} - -/** - * @brief Get status of an open file - * - * This is a wrapper around @c vfs_fstat - * - * @param[in] r pointer to reent structure - * @param[in] fd open file descriptor obtained from @c open() - * @param[out] buf pointer to stat struct to fill - * - * @return 0 on success - * @return -1 on error, @c r->_errno set to a constant from errno.h to indicate the error - */ -int _fstat_r(struct _reent *r, int fd, struct stat *buf) -{ - int res = vfs_fstat(fd, buf); - if (res < 0) { - /* vfs returns negative error codes */ - r->_errno = -res; - return -1; - } - return 0; -} - -/** - * @brief Status of a file (by name) - * - * This is a wrapper around @c vfs_fstat - * - * @param[in] r pointer to reent structure - * @param[in] name path to file - * @param[out] buf pointer to stat struct to fill - * - * @return 0 on success - * @return -1 on error, @c r->_errno set to a constant from errno.h to indicate the error - */ -int _stat_r(struct _reent *r, const char *name, struct stat *st) -{ - int res = vfs_stat(name, st); - if (res < 0) { - /* vfs returns negative error codes */ - r->_errno = -res; - return -1; - } - return 0; -} - -/** - * @brief Unlink (delete) a file - * - * @param[in] r pointer to reent structure - * @param[in] path path to file to be deleted - * - * @return 0 on success - * @return -1 on error, @c r->_errno set to a constant from errno.h to indicate the error - */ -int _unlink_r(struct _reent *r, const char *path) -{ - int res = vfs_unlink(path); - if (res < 0) { - /* vfs returns negative error codes */ - r->_errno = -res; - return -1; - } - return 0; -} - -#else /* MODULE_VFS */ - -/* Fallback stdio_uart wrappers for when VFS is not used, does not allow any - * other file access */ -/* - * Fallback read function - * - * All input is read from stdio_uart regardless of fd number. The function will - * block until a byte is actually read. - * - * Note: the read function does not buffer - data will be lost if the function is not - * called fast enough. - */ -_ssize_t _read_r(struct _reent *r, int fd, void *buffer, size_t count) -{ - (void)r; - (void)fd; - return stdio_read(buffer, count); -} - -/* - * Fallback write function - * - * All output is directed to stdio_uart, independent of the given file descriptor. - * The write call will further block until the byte is actually written to the UART. - */ -_ssize_t _write_r(struct _reent *r, int fd, const void *data, size_t count) -{ - (void) r; - (void) fd; - return stdio_write(data, count); -} - -/* Stubs to avoid linking errors, these functions do not have any effect */ -int _open_r(struct _reent *r, const char *name, int flags, int mode) -{ - (void) name; - (void) flags; - (void) mode; - r->_errno = ENODEV; - return -1; -} - -int _close_r(struct _reent *r, int fd) -{ - (void) fd; - r->_errno = ENODEV; - return -1; -} - -_off_t _lseek_r(struct _reent *r, int fd, _off_t pos, int dir) -{ - (void) fd; - (void) pos; - (void) dir; - r->_errno = ENODEV; - return -1; -} - -int _fstat_r(struct _reent *r, int fd, struct stat *st) -{ - (void) fd; - (void) st; - r->_errno = ENODEV; - return -1; -} - -int _stat_r(struct _reent *r, const char *name, struct stat *st) -{ - (void) name; - (void) st; - r->_errno = ENODEV; - return -1; -} - -int _unlink_r(struct _reent *r, const char *path) -{ - (void) path; - r->_errno = ENODEV; - return -1; -} -#endif /* MODULE_VFS */ - -/** - * Create a hard link (not implemented). - * - * @todo Not implemented. - * - * @return -1. Sets errno to ENOSYS. - */ -int _link_r(struct _reent *ptr, const char *old_name, const char *new_name) -{ - (void)old_name; - (void)new_name; - - ptr->_errno = ENOSYS; - - return -1; -} - /** * @brief Query whether output stream is a terminal * diff --git a/sys/newlib_syscalls_riot/Makefile.include b/sys/newlib_syscalls_riot/Makefile.include index 48777c4c6e12..3a5bc324682b 100644 --- a/sys/newlib_syscalls_riot/Makefile.include +++ b/sys/newlib_syscalls_riot/Makefile.include @@ -5,3 +5,11 @@ endif ifneq (,$(filter newlib_syscalls_riot_time,$(USEMODULE))) UNDEF += $(BINDIR)/newlib_syscalls_riot/time.o endif + +ifneq (,$(filter newlib_syscalls_riot_vfs,$(USEMODULE))) + UNDEF += $(BINDIR)/newlib_syscalls_riot/vfs.o +endif + +ifneq (,$(filter newlib_syscalls_riot_serial_rw,$(USEMODULE))) + UNDEF += $(BINDIR)/newlib_syscalls_riot/serial_rw.o +endif diff --git a/sys/newlib_syscalls_riot/doc.txt b/sys/newlib_syscalls_riot/doc.txt index de52d59794a8..afb6f141d4fb 100644 --- a/sys/newlib_syscalls_riot/doc.txt +++ b/sys/newlib_syscalls_riot/doc.txt @@ -25,4 +25,6 @@ * * - sys_newlib_syscalls_riot_clock * - sys_newlib_syscalls_riot_time + * - sys_newlib_syscalls_riot_vfs + * - sys_newlib_syscalls_riot_serial_rw */ diff --git a/sys/newlib_syscalls_riot/serial_rw.c b/sys/newlib_syscalls_riot/serial_rw.c new file mode 100644 index 000000000000..00770a128c57 --- /dev/null +++ b/sys/newlib_syscalls_riot/serial_rw.c @@ -0,0 +1,62 @@ +/* + * Copyright (C) 2018 Freie Universität Berlin + * 2015 Kaspar Schleiser + * 2014 Freie Universität Berlin + * + * This file is subject to the terms and conditions of the GNU Lesser General + * Public License v2.1. See the file LICENSE in the top level directory for more + * details. + */ + +/** + * @ingroup sys_newlib_syscalls_riot + * @{ + * + * @file + * @brief Simple read and write to serial + * + * This modules makes every file descriptor refer to the default serial port. + * It is a fallback for when VFS is not used. + * + * @author Michael Baar + * @author Stefan Pfeiffer + * @author Hauke Petersen + * @author Kaspar Schleiser + * @author Juan I Carrano + * + * @} + */ + +#include +#include + +#include "stdio_base.h" + +/** + * Fallback read function + * + * All input is read from stdio_uart regardless of fd number. The function will + * block until a byte is actually read. + * + * Note: the read function does not buffer - data will be lost if the function is not + * called fast enough. + */ +_ssize_t _read_r(struct _reent *r, int fd, void *buffer, size_t count) +{ + (void)r; + (void)fd; + return stdio_read(buffer, count); +} + +/** + * Fallback write function + * + * All output is directed to stdio_uart, independent of the given file descriptor. + * The write call will further block until the byte is actually written to the UART. + */ +_ssize_t _write_r(struct _reent *r, int fd, const void *data, size_t count) +{ + (void) r; + (void) fd; + return stdio_write(data, count); +} diff --git a/sys/newlib_syscalls_riot/vfs.c b/sys/newlib_syscalls_riot/vfs.c new file mode 100644 index 000000000000..32b5ebe35a02 --- /dev/null +++ b/sys/newlib_syscalls_riot/vfs.c @@ -0,0 +1,263 @@ +/* + * Copyright (C) 2018 Freie Universität Berlin + * 2015 Kaspar Schleiser + * 2014 Freie Universität Berlin + * + * This file is subject to the terms and conditions of the GNU Lesser General + * Public License v2.1. See the file LICENSE in the top level directory for more + * details. + */ + +/** + * @ingroup sys_newlib_syscalls_riot + * @{ + * + * @file + * @brief Newlib <-> VFS translation layer. + * + * @author Michael Baar + * @author Stefan Pfeiffer + * @author Hauke Petersen + * @author Kaspar Schleiser + * @author Juan I Carrano + * + * @} + */ + +#include +#include + +#include "vfs.h" +#include "stdio_base.h" + +/** + * @brief Open a file + * + * This is a wrapper around @c vfs_open + * + * @param r pointer to reent structure + * @param name file name to open + * @param flags flags, see man 3p open + * @param mode mode, file creation mode if the file is created when opening + * + * @return fd number (>= 0) on success + * @return -1 on error, @c r->_errno set to a constant from errno.h to indicate the error + */ +int _open_r(struct _reent *r, const char *name, int flags, int mode) +{ + int fd = vfs_open(name, flags, mode); + if (fd < 0) { + /* vfs returns negative error codes */ + r->_errno = -fd; + return -1; + } + return fd; +} + +/** + * @brief Read bytes from an open file + * + * This is a wrapper around @c vfs_read + * + * @param[in] r pointer to reent structure + * @param[in] fd open file descriptor obtained from @c open() + * @param[out] dest destination buffer + * @param[in] count maximum number of bytes to read + * + * @return number of bytes read on success + * @return -1 on error, @c r->_errno set to a constant from errno.h to indicate the error + */ +_ssize_t _read_r(struct _reent *r, int fd, void *dest, size_t count) +{ + int res = vfs_read(fd, dest, count); + if (res < 0) { + /* vfs returns negative error codes */ + r->_errno = -res; + return -1; + } + return res; +} + +/** + * @brief Write bytes to an open file + * + * This is a wrapper around @c vfs_write + * + * @param[in] r pointer to reent structure + * @param[in] fd open file descriptor obtained from @c open() + * @param[in] src source data buffer + * @param[in] count maximum number of bytes to write + * + * @return number of bytes written on success + * @return -1 on error, @c r->_errno set to a constant from errno.h to indicate the error + */ +_ssize_t _write_r(struct _reent *r, int fd, const void *src, size_t count) +{ + int res = vfs_write(fd, src, count); + if (res < 0) { + /* vfs returns negative error codes */ + r->_errno = -res; + return -1; + } + return res; +} + +/** + * @brief Close an open file + * + * This is a wrapper around @c vfs_close + * + * If this call returns an error, the fd should still be considered invalid and + * no further attempt to use it shall be made, not even to retry @c close() + * + * @param[in] r pointer to reent structure + * @param[in] fd open file descriptor obtained from @c open() + * + * @return 0 on success + * @return -1 on error, @c r->_errno set to a constant from errno.h to indicate the error + */ +int _close_r(struct _reent *r, int fd) +{ + int res = vfs_close(fd); + if (res < 0) { + /* vfs returns negative error codes */ + r->_errno = -res; + return -1; + } + return res; +} + +/** + * @brief Query or set options on an open file + * + * This is a wrapper around @c vfs_fcntl + * + * @param[in] r pointer to reent structure + * @param[in] fd open file descriptor obtained from @c open() + * @param[in] cmd fcntl command, see man 3p fcntl + * @param[in] arg argument to fcntl command, see man 3p fcntl + * + * @return 0 on success + * @return -1 on error, @c r->_errno set to a constant from errno.h to indicate the error + */ +int _fcntl_r (struct _reent *r, int fd, int cmd, int arg) +{ + int res = vfs_fcntl(fd, cmd, arg); + if (res < 0) { + /* vfs returns negative error codes */ + r->_errno = -res; + return -1; + } + return res; +} + +/** + * @brief Seek to position in file + * + * This is a wrapper around @c vfs_lseek + * + * @p whence determines the function of the seek and should be set to one of + * the following values: + * + * - @c SEEK_SET: Seek to absolute offset @p off + * - @c SEEK_CUR: Seek to current location + @p off + * - @c SEEK_END: Seek to end of file + @p off + * + * @param[in] r pointer to reent structure + * @param[in] fd open file descriptor obtained from @c open() + * @param[in] off seek offset + * @param[in] whence determines the seek method, see detailed description + * + * @return the new seek location in the file on success + * @return -1 on error, @c r->_errno set to a constant from errno.h to indicate the error + */ +_off_t _lseek_r(struct _reent *r, int fd, _off_t off, int whence) +{ + int res = vfs_lseek(fd, off, whence); + if (res < 0) { + /* vfs returns negative error codes */ + r->_errno = -res; + return -1; + } + return res; +} + +/** + * @brief Get status of an open file + * + * This is a wrapper around @c vfs_fstat + * + * @param[in] r pointer to reent structure + * @param[in] fd open file descriptor obtained from @c open() + * @param[out] buf pointer to stat struct to fill + * + * @return 0 on success + * @return -1 on error, @c r->_errno set to a constant from errno.h to indicate the error + */ +int _fstat_r(struct _reent *r, int fd, struct stat *buf) +{ + int res = vfs_fstat(fd, buf); + if (res < 0) { + /* vfs returns negative error codes */ + r->_errno = -res; + return -1; + } + return 0; +} + +/** + * @brief Status of a file (by name) + * + * This is a wrapper around @c vfs_fstat + * + * @param[in] r pointer to reent structure + * @param[in] name path to file + * @param[out] buf pointer to stat struct to fill + * + * @return 0 on success + * @return -1 on error, @c r->_errno set to a constant from errno.h to indicate the error + */ +int _stat_r(struct _reent *r, const char *name, struct stat *st) +{ + int res = vfs_stat(name, st); + if (res < 0) { + /* vfs returns negative error codes */ + r->_errno = -res; + return -1; + } + return 0; +} + +/** + * @brief Unlink (delete) a file + * + * @param[in] r pointer to reent structure + * @param[in] path path to file to be deleted + * + * @return 0 on success + * @return -1 on error, @c r->_errno set to a constant from errno.h to indicate the error + */ +int _unlink_r(struct _reent *r, const char *path) +{ + int res = vfs_unlink(path); + if (res < 0) { + /* vfs returns negative error codes */ + r->_errno = -res; + return -1; + } + return 0; +} + +/* + * VFS does not (yet) support hard links (that's why the error is ENOSYS instead + * of ENODEV. + */ +int _link_r(struct _reent *ptr, const char *old_name, const char *new_name) +{ + (void)old_name; + (void)new_name; + + ptr->_errno = ENOSYS; + + return -1; +} From dd1ab99c5ddde4a5bf602f680a3077e77cc41201 Mon Sep 17 00:00:00 2001 From: Juan Carrano Date: Mon, 14 Jan 2019 18:01:01 +0100 Subject: [PATCH 4/7] newlib_stubs/rw: Add stubs for read() and write(). This allows to save space by not compiling in serial support, provided application do not check the exit status of IO functions. If a program checks the exit status, it will realize it is a stub, but such a program probably has REAL I/O as part of it's specification, and therefore it should not be using stubs in the same place. --- Makefile.dep | 6 +-- sys/newlib_stubs/Makefile.include | 4 ++ sys/newlib_stubs/rw.c | 56 ++++++++++++++++++++++++++ sys/newlib_syscalls_default/syscalls.c | 4 ++ 4 files changed, 67 insertions(+), 3 deletions(-) create mode 100644 sys/newlib_stubs/rw.c diff --git a/Makefile.dep b/Makefile.dep index 66349d59f19a..e52ef870fa9f 100644 --- a/Makefile.dep +++ b/Makefile.dep @@ -386,15 +386,15 @@ ifneq (,$(filter newlib,$(USEMODULE))) USEMODULE += newlib_syscalls_riot_time endif endif - ifeq (,$(filter newlib_stubs_fs,$(USEMODULE))) + ifeq (,$(filter newlib_stubs_rw newlib_stubs_fs,$(USEMODULE))) ifneq (,$(filter vfs,$(USEMODULE))) USEMODULE += newlib_syscalls_riot_vfs endif endif - ifeq (,$(filter vfs,$(USEMODULE))) + ifeq (,$(filter newlib_stubs_rw vfs,$(USEMODULE))) USEMODULE += newlib_syscalls_riot_serial_rw endif - ifeq (,$(filter stdio_rtt,$(USEMODULE))) + ifeq (,$(filter newlib_stubs_rw stdio_rtt,$(USEMODULE))) USEMODULE += stdio_uart endif endif diff --git a/sys/newlib_stubs/Makefile.include b/sys/newlib_stubs/Makefile.include index f676c4e029e1..e972f926b754 100644 --- a/sys/newlib_stubs/Makefile.include +++ b/sys/newlib_stubs/Makefile.include @@ -9,3 +9,7 @@ endif ifneq (,$(filter newlib_stubs_fs,$(USEMODULE))) UNDEF += $(BINDIR)/newlib_stubs/fs.o endif + +ifneq (,$(filter newlib_stubs_rw,$(USEMODULE))) + UNDEF += $(BINDIR)/newlib_stubs/rw.o +endif diff --git a/sys/newlib_stubs/rw.c b/sys/newlib_stubs/rw.c new file mode 100644 index 000000000000..3c2b8703f4b6 --- /dev/null +++ b/sys/newlib_stubs/rw.c @@ -0,0 +1,56 @@ +/* + * Copyright (C) 2018 Freie Universität Berlin + * 2015 Kaspar Schleiser + * 2014 Freie Universität Berlin + * + * This file is subject to the terms and conditions of the GNU Lesser General + * Public License v2.1. See the file LICENSE in the top level directory for more + * details. + */ + +/** + * @ingroup sys_newlib_stubs + * @{ + * + * @file + * @brief Stubs for read() and write() + * + * This modules makes reads and write to any file descriptor fail with EBADF. + * + * @author Juan I Carrano + * + * @} + */ + +#include +#include + +/** + * Stub for read(). + * + * Always fails with errno = EBADF. + */ +_ssize_t _read_r(struct _reent *r, int fd, void *buffer, size_t count) +{ + (void)r; + (void)fd; + (void)buffer; + (void)count; + r->_errno = EBADF; + return -1; +} + +/** + * Stub for write(). + * + * Always fails with errno = EBADF. + */ +_ssize_t _write_r(struct _reent *r, int fd, const void *data, size_t count) +{ + (void)r; + (void)fd; + (void)data; + (void)count; + r->_errno = EBADF; + return -1; +} diff --git a/sys/newlib_syscalls_default/syscalls.c b/sys/newlib_syscalls_default/syscalls.c index 26c3f6b6855c..20f69ac8f5a1 100644 --- a/sys/newlib_syscalls_default/syscalls.c +++ b/sys/newlib_syscalls_default/syscalls.c @@ -58,7 +58,11 @@ char *heap_top = &_sheap + 4; */ void _init(void) { + /* FIXME: this logic should be moved to newlib_syscalls_riot_serial_rw, + * newlib_syscalls_riot_serial_vfs, or even better, a separate submodule*/ +#if !(MODULE_NEWLIB_STUBS_RW) stdio_init(); +#endif } /** From 312b56158fa121e5ac7c5061f46a0212021b36c6 Mon Sep 17 00:00:00 2001 From: Juan Carrano Date: Wed, 20 Mar 2019 16:54:13 +0100 Subject: [PATCH 5/7] fixup! add newlib_stubs_fs by default --- Makefile.dep | 3 +++ 1 file changed, 3 insertions(+) diff --git a/Makefile.dep b/Makefile.dep index e52ef870fa9f..d823ab695377 100644 --- a/Makefile.dep +++ b/Makefile.dep @@ -397,6 +397,9 @@ ifneq (,$(filter newlib,$(USEMODULE))) ifeq (,$(filter newlib_stubs_rw stdio_rtt,$(USEMODULE))) USEMODULE += stdio_uart endif + ifeq (,$(filter vfs newlib_syscalls_riot_vfs,$(USEMODULE))) + USEMODULE += newlib_stubs_fs + endif endif ifneq (,$(filter newlib_syscalls_riot_serial_rw,$(USEMODULE))) From e894cfed8bf815e1f1a6f9dc166826fc7600b933 Mon Sep 17 00:00:00 2001 From: Juan Carrano Date: Fri, 22 Mar 2019 16:04:25 +0100 Subject: [PATCH 6/7] fixup! implement _gettimeofday_r in terms of time. some code in pkg claims to be written in C99, yet uses some POSIX functions. --- sys/newlib_syscalls_riot/time.c | 40 +++++++++++++++++++++++++++++++++ 1 file changed, 40 insertions(+) diff --git a/sys/newlib_syscalls_riot/time.c b/sys/newlib_syscalls_riot/time.c index 3bcceeda470f..660d1b38279b 100644 --- a/sys/newlib_syscalls_riot/time.c +++ b/sys/newlib_syscalls_riot/time.c @@ -18,6 +18,9 @@ * @} */ +#include +#include +#include #include #include "periph/rtc.h" @@ -37,6 +40,7 @@ * deprecated and must be set to null in new code. * * @return Number of seconds since 1970-01-01 00:00:00 +0000 (UTC). + * On error, return -1, cast to time_t. */ time_t time(time_t *tloc) { @@ -54,3 +58,39 @@ time_t time(time_t *tloc) return r; } + +/** + * Current time in seconds since epoch. + * + * This call is provided so gettimeofday() works. This is because some code + * in pkg claims to be written in C99, yet uses some POSIX functions. + * + * Note that according to POSIX: + * "The gettimeofday() function shall return 0 and no value shall be reserved + * to indicate an error." + * + * @param[out] r Reentrant structure. + * @param[out] tp Wall time. Because of limitations of the RIOT RTC, the + * tv_usec component will always be zero. + * @param tpz Timezone. MUST be NULL. If it is not, EINVAL will result. + * + * @return 0 on success, -1 on failure. The only failure is if tpz is not + * null. + */ +int _gettimeofday_r(struct _reent *r, struct timeval *restrict tp, + void *restrict tzp) +{ + if (tzp) { + r->_errno = EINVAL; + return -1; + } + + /* The linux docs seem to imply that it is not an error if tp is null, so + * let's do the same for compatibility .*/ + if (tp) { + tp->tv_sec = time(NULL); + tp->tv_usec = 0; + } + + return 0; +} From 0e99fb5f0151b885570408df63674954982f7e2a Mon Sep 17 00:00:00 2001 From: Juan Carrano Date: Fri, 22 Mar 2019 16:05:28 +0100 Subject: [PATCH 7/7] sys/newlib_syscalls_riot/sbrk: Split sbrk syscall. Take sbrk() out of newlib_syscalls_default This should make it easier for BSP providers to change the implementation without having to edit newlib_syscalls_default or fiddle with preprocessor macros. TODO: figure out if it makes sense to provide a stub for this one. --- Makefile.dep | 1 + sys/newlib_syscalls_default/syscalls.c | 33 ----------- sys/newlib_syscalls_riot/Makefile.include | 4 ++ sys/newlib_syscalls_riot/doc.txt | 1 + sys/newlib_syscalls_riot/sbrk.c | 67 +++++++++++++++++++++++ 5 files changed, 73 insertions(+), 33 deletions(-) create mode 100644 sys/newlib_syscalls_riot/sbrk.c diff --git a/Makefile.dep b/Makefile.dep index d823ab695377..5095712c93e4 100644 --- a/Makefile.dep +++ b/Makefile.dep @@ -400,6 +400,7 @@ ifneq (,$(filter newlib,$(USEMODULE))) ifeq (,$(filter vfs newlib_syscalls_riot_vfs,$(USEMODULE))) USEMODULE += newlib_stubs_fs endif + USEMODULE += newlib_syscalls_riot_sbrk endif ifneq (,$(filter newlib_syscalls_riot_serial_rw,$(USEMODULE))) diff --git a/sys/newlib_syscalls_default/syscalls.c b/sys/newlib_syscalls_default/syscalls.c index 20f69ac8f5a1..3f699a83b811 100644 --- a/sys/newlib_syscalls_default/syscalls.c +++ b/sys/newlib_syscalls_default/syscalls.c @@ -44,13 +44,6 @@ #include "stdio_base.h" -/** - * @brief manage the heap - */ -extern char _sheap; /* start of the heap */ -extern char _eheap; /* end of the heap */ -char *heap_top = &_sheap + 4; - /* MIPS newlib crt implements _init,_fini and _exit and manages the heap */ #ifndef __mips__ /** @@ -89,32 +82,6 @@ void _exit(int n) while(1); } -/** - * @brief Allocate memory from the heap. - * - * The current heap implementation is very rudimentary, it is only able to allocate - * memory. But it does not have any means to free memory again - * - * @return pointer to the newly allocated memory on success - * @return pointer set to address `-1` on failure - */ -void *_sbrk_r(struct _reent *r, ptrdiff_t incr) -{ - unsigned int state = irq_disable(); - void *res = heap_top; - - if ((heap_top + incr > &_eheap) || (heap_top + incr < &_sheap)) { - r->_errno = ENOMEM; - res = (void *)-1; - } - else { - heap_top += incr; - } - - irq_restore(state); - return res; -} - #endif /*__mips__*/ /** diff --git a/sys/newlib_syscalls_riot/Makefile.include b/sys/newlib_syscalls_riot/Makefile.include index 3a5bc324682b..85999df6a42d 100644 --- a/sys/newlib_syscalls_riot/Makefile.include +++ b/sys/newlib_syscalls_riot/Makefile.include @@ -13,3 +13,7 @@ endif ifneq (,$(filter newlib_syscalls_riot_serial_rw,$(USEMODULE))) UNDEF += $(BINDIR)/newlib_syscalls_riot/serial_rw.o endif + +ifneq (,$(filter newlib_syscalls_riot_sbrk,$(USEMODULE))) + UNDEF += $(BINDIR)/newlib_syscalls_riot/sbrk.o +endif diff --git a/sys/newlib_syscalls_riot/doc.txt b/sys/newlib_syscalls_riot/doc.txt index afb6f141d4fb..4a814635baf2 100644 --- a/sys/newlib_syscalls_riot/doc.txt +++ b/sys/newlib_syscalls_riot/doc.txt @@ -27,4 +27,5 @@ * - sys_newlib_syscalls_riot_time * - sys_newlib_syscalls_riot_vfs * - sys_newlib_syscalls_riot_serial_rw + * - sys_newlib_syscalls_riot_sbrk */ diff --git a/sys/newlib_syscalls_riot/sbrk.c b/sys/newlib_syscalls_riot/sbrk.c new file mode 100644 index 000000000000..50baf6930a39 --- /dev/null +++ b/sys/newlib_syscalls_riot/sbrk.c @@ -0,0 +1,67 @@ +/* + * Copyright (C) 2019 Freie Universität Berlin + * 2015 Kaspar Schleiser + * 2014 Freie Universität Berlin + * + * This file is subject to the terms and conditions of the GNU Lesser General + * Public License v2.1. See the file LICENSE in the top level directory for more + * details. + */ + +/** + * @ingroup sys_newlib_syscalls_sbrk + * @{ + * + * @file + * @brief Implement data segment resizing + * + * Simple implementation of the sbrk function. This is usually needed by malloc + * implementations to extend the heap. + * + * @author Michael Baar + * @author Stefan Pfeiffer + * @author Hauke Petersen + * @author Kaspar Schleiser + * + * @} + */ + + /** + * @brief Allocate memory from the heap. + * + * The current heap implementation is very rudimentary, it is only able to allocate + * memory. But it does not have any means to free memory again + * + * @return pointer to the newly allocated memory on success + * @return pointer set to address `-1` on failure + */ + +#include +#include +#include + +#include "irq.h" + +/** + * @brief manage the heap + */ +extern char _sheap; /* start of the heap */ +extern char _eheap; /* end of the heap */ +char *heap_top = &_sheap + 4; + +void *_sbrk_r(struct _reent *r, ptrdiff_t incr) +{ + unsigned int state = irq_disable(); + void *res = heap_top; + + if ((heap_top + incr > &_eheap) || (heap_top + incr < &_sheap)) { + r->_errno = ENOMEM; + res = (void *)-1; + } + else { + heap_top += incr; + } + + irq_restore(state); + return res; +}