mirror of
https://github.com/RIOT-OS/RIOT.git
synced 2024-12-29 04:50:03 +01:00
Merge pull request #14827 from keith-packard/pr/libc/picolibc
Pr/libc/picolibc
This commit is contained in:
commit
f3e1032f6e
@ -479,6 +479,14 @@ ifneq (,$(filter posix_select,$(USEMODULE)))
|
||||
USEMODULE += xtimer
|
||||
endif
|
||||
|
||||
ifneq (,$(filter picolibc,$(USEMODULE)))
|
||||
# allow custom picolibc syscalls implementations by adding
|
||||
# picolibc_syscalls_XXX to USEMODULE
|
||||
ifeq (,$(filter picolibc_syscalls_%,$(USEMODULE)))
|
||||
USEMODULE += picolibc_syscalls_default
|
||||
endif
|
||||
endif
|
||||
|
||||
ifneq (,$(filter posix_sockets,$(USEMODULE)))
|
||||
USEMODULE += bitfield
|
||||
USEMODULE += random
|
||||
|
@ -176,6 +176,10 @@ struct _thread {
|
||||
const char *name; /**< thread's name */
|
||||
int stack_size; /**< thread's stack size */
|
||||
#endif
|
||||
/* enable TLS only when Picolibc is compiled with TLS enabled */
|
||||
#ifdef PICOLIBC_TLS
|
||||
void *tls; /**< thread local storage ptr */
|
||||
#endif
|
||||
#ifdef HAVE_THREAD_ARCH_T
|
||||
thread_arch_t arch; /**< architecture dependent part */
|
||||
#endif
|
||||
|
@ -40,6 +40,10 @@
|
||||
#include <inttypes.h>
|
||||
#endif
|
||||
|
||||
#ifdef PICOLIBC_TLS
|
||||
#include <picotls.h>
|
||||
#endif
|
||||
|
||||
/* Needed by OpenOCD to read sched_threads */
|
||||
#if defined(__APPLE__) && defined(__MACH__)
|
||||
#define FORCE_USED_SECTION __attribute__((used)) __attribute__((section( \
|
||||
@ -148,6 +152,9 @@ int __attribute__((used)) sched_run(void)
|
||||
next_thread->status = STATUS_RUNNING;
|
||||
sched_active_pid = next_thread->pid;
|
||||
sched_active_thread = next_thread;
|
||||
#ifdef PICOLIBC_TLS
|
||||
_set_tls(next_thread->tls);
|
||||
#endif
|
||||
|
||||
#ifdef MODULE_MPU_STACK_GUARD
|
||||
mpu_configure(
|
||||
|
@ -20,6 +20,9 @@
|
||||
|
||||
#include <errno.h>
|
||||
#include <stdio.h>
|
||||
#ifdef PICOLIBC_TLS
|
||||
#include <picotls.h>
|
||||
#endif
|
||||
|
||||
#include "assert.h"
|
||||
#include "thread.h"
|
||||
@ -215,6 +218,13 @@ kernel_pid_t thread_create(char *stack, int stacksize, uint8_t priority,
|
||||
/* allocate our thread control block at the top of our stackspace */
|
||||
thread_t *thread = (thread_t *)(stack + stacksize);
|
||||
|
||||
#ifdef PICOLIBC_TLS
|
||||
stacksize -= _tls_size();
|
||||
|
||||
thread->tls = stack + stacksize;
|
||||
_init_tls(thread->tls);
|
||||
#endif
|
||||
|
||||
#if defined(DEVELHELP) || defined(SCHED_TEST_STACK)
|
||||
if (flags & THREAD_CREATE_STACKTEST) {
|
||||
/* assign each int of the stack the value of it's address */
|
||||
|
@ -127,7 +127,7 @@ void bootloader(void)
|
||||
/* cpu specific setup of clocks, peripherals */
|
||||
cpu_init();
|
||||
|
||||
#ifdef MODULE_NEWLIB
|
||||
#if defined(MODULE_NEWLIB) || defined(MODULE_PICOLIBC)
|
||||
extern void __libc_init_array(void);
|
||||
__libc_init_array();
|
||||
#endif
|
||||
|
@ -4,11 +4,15 @@ USEMODULE += cortexm_common
|
||||
# include common periph code
|
||||
USEMODULE += cortexm_common_periph
|
||||
|
||||
# all cortex MCU's use newlib as libc
|
||||
USEMODULE += newlib
|
||||
|
||||
# use the nano-specs of Newlib when available
|
||||
USEMODULE += newlib_nano
|
||||
ifeq (1,$(PICOLIBC))
|
||||
# Use Picolibc when explicitly selected
|
||||
USEMODULE += picolibc
|
||||
else
|
||||
# all cortex MCU's use newlib as libc
|
||||
USEMODULE += newlib
|
||||
# use the nano-specs of Newlib when available
|
||||
USEMODULE += newlib_nano
|
||||
endif
|
||||
|
||||
# Export the peripheral drivers to be linked into the final binary:
|
||||
USEMODULE += periph
|
||||
|
@ -96,6 +96,42 @@ SECTIONS
|
||||
_efixed = .; /* End of text section */
|
||||
} > rom
|
||||
|
||||
/*
|
||||
* TLS relocations are offsets relative to the address
|
||||
* of the first TLS symbol. That means we just need to
|
||||
* allocate them all together so that the TLS region
|
||||
* is compact when allocated for each thread.
|
||||
*/
|
||||
|
||||
/*
|
||||
* TLS initialization data is loaded into ROM so that
|
||||
* each thread can get its values initialized from there
|
||||
* at startup
|
||||
*/
|
||||
.tdata :
|
||||
{
|
||||
__tdata_start = .;
|
||||
*(.tdata .tdata.* .gnu.linkonce.td.*)
|
||||
__tdata_end = .;
|
||||
} > rom
|
||||
__tdata_source = LOADADDR(.tdata);
|
||||
__tdata_size = SIZEOF(.tdata);
|
||||
|
||||
/*
|
||||
* TLS zeroed data is relocated as if it immediately followed
|
||||
* the tdata values. However, the linker 'magically' erases the
|
||||
* memory allocation so that no ROM is consumed by this
|
||||
* section
|
||||
*/
|
||||
.tbss :
|
||||
{
|
||||
*(.tbss .tbss.* .gnu.linkonce.tb.*)
|
||||
*(.tcommon)
|
||||
__tbss_end = .;
|
||||
} > rom
|
||||
__tls_size = __tbss_end - __tdata_start;
|
||||
__tbss_size = __tls_size - __tdata_size;
|
||||
|
||||
/* .ARM.exidx is sorted, so has to go in its own output section. */
|
||||
PROVIDE_HIDDEN (__exidx_start = .);
|
||||
.ARM.exidx :
|
||||
|
@ -174,7 +174,7 @@ void reset_handler_default(void)
|
||||
/* initialize the board (which also initiates CPU initialization) */
|
||||
board_init();
|
||||
|
||||
#if MODULE_NEWLIB
|
||||
#if MODULE_NEWLIB || MODULE_PICOLIBC
|
||||
/* initialize std-c library (this must be done after board_init) */
|
||||
extern void __libc_init_array(void);
|
||||
__libc_init_array();
|
||||
|
@ -2,6 +2,10 @@
|
||||
MODULE = cpu
|
||||
|
||||
# add a list of subdirectories, that should also be built
|
||||
DIRS = periph nano vendor
|
||||
DIRS = periph vendor
|
||||
|
||||
ifneq (1,$(PICOLIBC))
|
||||
DIRS += nano
|
||||
endif
|
||||
|
||||
include $(RIOTBASE)/Makefile.base
|
||||
|
@ -1,6 +1,10 @@
|
||||
USEMODULE += newlib_nano
|
||||
ifeq (1,$(PICOLIBC))
|
||||
USEMODULE += picolibc
|
||||
else
|
||||
USEMODULE += newlib_nano
|
||||
USEMODULE += newlib_syscalls_fe310
|
||||
endif
|
||||
|
||||
USEMODULE += newlib_syscalls_fe310
|
||||
USEMODULE += sifive_drivers_fe310
|
||||
|
||||
USEMODULE += periph
|
||||
|
@ -24,6 +24,8 @@
|
||||
#include "vendor/encoding.h"
|
||||
#include "vendor/plic_driver.h"
|
||||
|
||||
#include "stdio_uart.h"
|
||||
|
||||
/*
|
||||
* Configure the memory mapped flash for faster throughput
|
||||
* to minimize interrupt latency on an I-Cache miss and refill
|
||||
@ -110,8 +112,12 @@ void cpu_init(void)
|
||||
/* Initialize IRQs */
|
||||
irq_init();
|
||||
|
||||
/* Initialize stdio */
|
||||
stdio_init();
|
||||
#ifndef _PICOLIBC__
|
||||
/* Initialize newlib-nano library stubs */
|
||||
nanostubs_init();
|
||||
#endif /* PICOLIBC */
|
||||
|
||||
/* Initialize static peripheral */
|
||||
periph_init();
|
||||
|
@ -27,6 +27,7 @@ PHDRS
|
||||
flash PT_LOAD;
|
||||
ram_init PT_LOAD;
|
||||
ram PT_NULL;
|
||||
tls PT_TLS;
|
||||
}
|
||||
|
||||
SECTIONS
|
||||
@ -118,6 +119,42 @@ SECTIONS
|
||||
KEEP (*(.dtors))
|
||||
} >flash AT>flash :flash
|
||||
|
||||
/*
|
||||
* TLS relocations are offsets relative to the address
|
||||
* of the first TLS symbol. That means we just need to
|
||||
* allocate them all together so that the TLS region
|
||||
* is compact when allocated for each thread.
|
||||
*/
|
||||
|
||||
/*
|
||||
* TLS initialization data is loaded into ROM so that
|
||||
* each thread can get its values initialized from there
|
||||
* at startup
|
||||
*/
|
||||
.tdata :
|
||||
{
|
||||
__tdata_start = .;
|
||||
*(.tdata .tdata.* .gnu.linkonce.td.*)
|
||||
__tdata_end = .;
|
||||
} >flash AT>flash :tls
|
||||
__tdata_source = LOADADDR(.tdata);
|
||||
__tdata_size = SIZEOF(.tdata);
|
||||
|
||||
/*
|
||||
* TLS zeroed data is relocated as if it immediately followed
|
||||
* the tdata values. However, the linker 'magically' erases the
|
||||
* memory allocation so that no ROM is consumed by this
|
||||
* section
|
||||
*/
|
||||
.tbss :
|
||||
{
|
||||
*(.tbss .tbss.* .gnu.linkonce.tb.*)
|
||||
*(.tcommon)
|
||||
__tbss_end = .;
|
||||
} >flash : tls
|
||||
__tls_size = __tbss_end - __tdata_start;
|
||||
__tbss_size = __tls_size - __tdata_size;
|
||||
|
||||
.lalign :
|
||||
{
|
||||
. = ALIGN(4);
|
||||
|
@ -40,7 +40,6 @@ void nanostubs_init(void)
|
||||
{
|
||||
#if defined(MODULE_STDIO_UART)
|
||||
/* STDIO redirected to UART, no line buffering */
|
||||
stdio_init();
|
||||
setvbuf(stdout, NULL, _IONBF, 0);
|
||||
#endif
|
||||
}
|
||||
|
@ -43,8 +43,6 @@ _start:
|
||||
2:
|
||||
|
||||
/* Call global constructors */
|
||||
la a0, __libc_fini_array
|
||||
call atexit
|
||||
call __libc_init_array
|
||||
|
||||
|
||||
|
@ -240,9 +240,9 @@ static int _cat(int argc, char **argv)
|
||||
printf("Usage: %s <file>\n", argv[0]);
|
||||
return 1;
|
||||
}
|
||||
/* With newlib, low-level syscalls are plugged to RIOT vfs
|
||||
/* With newlib or picolibc, low-level syscalls are plugged to RIOT vfs
|
||||
* on native, open/read/write/close/... are plugged to RIOT vfs */
|
||||
#ifdef MODULE_NEWLIB
|
||||
#if defined(MODULE_NEWLIB) || defined(MODULE_PICOLIBC)
|
||||
FILE *f = fopen(argv[1], "r");
|
||||
if (f == NULL) {
|
||||
printf("file %s does not exist\n", argv[1]);
|
||||
@ -276,7 +276,7 @@ static int _tee(int argc, char **argv)
|
||||
return 1;
|
||||
}
|
||||
|
||||
#ifdef MODULE_NEWLIB
|
||||
#if defined(MODULE_NEWLIB) || defined(MODULE_PICOLIBC)
|
||||
FILE *f = fopen(argv[1], "w+");
|
||||
if (f == NULL) {
|
||||
printf("error while trying to create %s\n", argv[1]);
|
||||
|
@ -57,6 +57,7 @@ export DOCKER_ENV_VARS += \
|
||||
PREFIX \
|
||||
QUIET \
|
||||
WERROR \
|
||||
PICOLIBC \
|
||||
PROGRAMMER \
|
||||
RIOT_CI_BUILD \
|
||||
RIOT_VERSION \
|
||||
|
25
makefiles/libc/picolibc.mk
Normal file
25
makefiles/libc/picolibc.mk
Normal file
@ -0,0 +1,25 @@
|
||||
ifneq (,$(filter picolibc,$(USEMODULE)))
|
||||
# Test if picolibc.specs is available
|
||||
ifeq ($(shell $(LINK) -specs=picolibc.specs -E - 2>/dev/null >/dev/null </dev/null ; echo $$?),0)
|
||||
USE_PICOLIBC = 1
|
||||
ifeq ($(shell echo "int main(){} void _exit(int n) {(void)n;while(1);}" | LC_ALL=C $(CC) -xc - -o /dev/null -lc -specs=picolibc.specs -Wall -Wextra -pedantic 2>&1 | grep -q "use of wchar_t values across objects may fail" ; echo $$?),0)
|
||||
CFLAGS += -fshort-wchar
|
||||
LINKFLAGS += -Wl,--no-wchar-size-warning
|
||||
endif
|
||||
endif
|
||||
endif
|
||||
|
||||
ifeq (1,$(USE_PICOLIBC))
|
||||
LINKFLAGS += -specs=picolibc.specs
|
||||
# RIOT uses _sheap and _eheap for heap start and end, PicoLIBC uses
|
||||
# __heap_start and __heap_end. This glues these different names together.
|
||||
LINKFLAGS += -Wl,--defsym=__heap_end=_eheap
|
||||
LINKFLAGS += -Wl,--defsym=__heap_start=_sheap
|
||||
CFLAGS += -specs=picolibc.specs
|
||||
ifeq (,$(filter printf_float scanf_float,$(USEMODULE)))
|
||||
CFLAGS += -DPICOLIBC_INTEGER_PRINTF_SCANF
|
||||
LINKFLAGS += -DPICOLIBC_INTEGER_PRINTF_SCANF
|
||||
endif
|
||||
endif
|
||||
|
||||
LINKFLAGS += -lc
|
@ -85,6 +85,7 @@ PSEUDOMODULES += newlib
|
||||
PSEUDOMODULES += newlib_gnu_source
|
||||
PSEUDOMODULES += newlib_nano
|
||||
PSEUDOMODULES += openthread
|
||||
PSEUDOMODULES += picolibc
|
||||
PSEUDOMODULES += pktqueue
|
||||
PSEUDOMODULES += posix_headers
|
||||
PSEUDOMODULES += printf_float
|
||||
|
@ -8,7 +8,7 @@ STDIO_MODULES = \
|
||||
stdio_uart \
|
||||
#
|
||||
|
||||
ifneq (,$(filter newlib,$(USEMODULE)))
|
||||
ifneq (,$(filter newlib picolibc,$(USEMODULE)))
|
||||
ifeq (,$(filter $(STDIO_MODULES),$(USEMODULE)))
|
||||
USEMODULE += stdio_uart
|
||||
endif
|
||||
|
@ -68,10 +68,18 @@ ifneq (,$(filter newlib,$(USEMODULE)))
|
||||
include $(RIOTMAKE)/libc/newlib.mk
|
||||
endif
|
||||
|
||||
ifneq (,$(filter picolibc,$(USEMODULE)))
|
||||
include $(RIOTMAKE)/libc/picolibc.mk
|
||||
endif
|
||||
|
||||
ifneq (,$(filter newlib_syscalls_default,$(USEMODULE)))
|
||||
include $(RIOTBASE)/sys/newlib_syscalls_default/Makefile.include
|
||||
endif
|
||||
|
||||
ifneq (,$(filter picolibc_syscalls_default,$(USEMODULE)))
|
||||
include $(RIOTBASE)/sys/picolibc_syscalls_default/Makefile.include
|
||||
endif
|
||||
|
||||
ifneq (,$(filter arduino,$(USEMODULE)))
|
||||
include $(RIOTBASE)/sys/arduino/Makefile.include
|
||||
endif
|
||||
|
@ -110,7 +110,7 @@ static inline void log_write(unsigned level, const char *format, ...)
|
||||
va_end(args);
|
||||
printf(LOG_RESET_ANSI_COLOR_CODE);
|
||||
|
||||
#ifdef MODULE_NEWLIB
|
||||
#if defined(MODULE_NEWLIB) || defined(MODULE_PICOLIBC)
|
||||
/* no fflush on msp430 */
|
||||
fflush(stdout);
|
||||
#endif
|
||||
|
1
sys/picolibc_syscalls_default/Makefile
Normal file
1
sys/picolibc_syscalls_default/Makefile
Normal file
@ -0,0 +1 @@
|
||||
include $(RIOTBASE)/Makefile.base
|
1
sys/picolibc_syscalls_default/Makefile.include
Normal file
1
sys/picolibc_syscalls_default/Makefile.include
Normal file
@ -0,0 +1 @@
|
||||
UNDEF += $(BINDIR)/picolibc_syscalls_default/syscalls.o
|
357
sys/picolibc_syscalls_default/syscalls.c
Normal file
357
sys/picolibc_syscalls_default/syscalls.c
Normal file
@ -0,0 +1,357 @@
|
||||
/*
|
||||
* Copyright (C) 2019 Koen Zandberg
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @defgroup sys_picolibc PicoLibc system call
|
||||
* @ingroup sys
|
||||
* @brief PicoLibc system call
|
||||
* @{
|
||||
*
|
||||
* @file
|
||||
* @brief PicoLibc system call implementations
|
||||
*
|
||||
* @author Koen Zandberg <koen@bergzand.net>
|
||||
*
|
||||
* @}
|
||||
*/
|
||||
|
||||
#include <errno.h>
|
||||
#include <stdio.h>
|
||||
#include <sys/times.h>
|
||||
|
||||
#include "log.h"
|
||||
#include "periph/pm.h"
|
||||
#include "stdio_base.h"
|
||||
|
||||
/**
|
||||
* @brief Exit a program without cleaning up files
|
||||
*
|
||||
* If your system doesn't provide this, it is best to avoid linking with subroutines that
|
||||
* require it (exit, system).
|
||||
*
|
||||
* @param n the exit code, 0 for all OK, >0 for not OK
|
||||
*/
|
||||
void __attribute__((__noreturn__))
|
||||
_exit(int n)
|
||||
{
|
||||
LOG_INFO("#! exit %i: powering off\n", n);
|
||||
pm_off();
|
||||
while(1);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Send a signal to a thread
|
||||
*
|
||||
* @param[in] pid the pid to send to
|
||||
* @param[in] sig the signal to send
|
||||
*
|
||||
* @return always returns -1 to signal error
|
||||
*/
|
||||
__attribute__ ((weak))
|
||||
int kill(pid_t pid, int sig)
|
||||
{
|
||||
(void) pid;
|
||||
(void) sig;
|
||||
errno = ESRCH; /* not implemented yet */
|
||||
return -1;
|
||||
}
|
||||
|
||||
#include "mutex.h"
|
||||
|
||||
static mutex_t picolibc_put_mutex = MUTEX_INIT;
|
||||
|
||||
#define PICOLIBC_STDOUT_BUFSIZE 64
|
||||
|
||||
static char picolibc_stdout[PICOLIBC_STDOUT_BUFSIZE];
|
||||
static int picolibc_stdout_queued;
|
||||
|
||||
static void _picolibc_flush(void)
|
||||
{
|
||||
if (picolibc_stdout_queued) {
|
||||
stdio_write(picolibc_stdout, picolibc_stdout_queued);
|
||||
picolibc_stdout_queued = 0;
|
||||
}
|
||||
}
|
||||
|
||||
static int picolibc_put(char c, FILE *file)
|
||||
{
|
||||
(void)file;
|
||||
mutex_lock(&picolibc_put_mutex);
|
||||
picolibc_stdout[picolibc_stdout_queued++] = c;
|
||||
if (picolibc_stdout_queued == PICOLIBC_STDOUT_BUFSIZE || c == '\n')
|
||||
_picolibc_flush();
|
||||
mutex_unlock(&picolibc_put_mutex);
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int picolibc_flush(FILE *file)
|
||||
{
|
||||
(void)file;
|
||||
mutex_lock(&picolibc_put_mutex);
|
||||
_picolibc_flush();
|
||||
mutex_unlock(&picolibc_put_mutex);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int picolibc_get(FILE *file)
|
||||
{
|
||||
(void)file;
|
||||
picolibc_flush(NULL);
|
||||
char c = 0;
|
||||
stdio_read(&c, 1);
|
||||
return c;
|
||||
}
|
||||
|
||||
FILE picolibc_stdio =
|
||||
FDEV_SETUP_STREAM(picolibc_put, picolibc_get, picolibc_flush, _FDEV_SETUP_RW);
|
||||
|
||||
FILE *const __iob[] = {
|
||||
&picolibc_stdio, /* stdin */
|
||||
&picolibc_stdio, /* stdout */
|
||||
&picolibc_stdio, /* stderr */
|
||||
};
|
||||
|
||||
#include <thread.h>
|
||||
/**
|
||||
* @brief Get the process-ID of the current thread
|
||||
*
|
||||
* @return the process ID of the current thread
|
||||
*/
|
||||
pid_t getpid(void)
|
||||
{
|
||||
return thread_getpid();
|
||||
}
|
||||
|
||||
#if MODULE_VFS
|
||||
#include "vfs.h"
|
||||
|
||||
/**
|
||||
* @brief Open a file
|
||||
*
|
||||
* This is a wrapper around @c vfs_open
|
||||
*
|
||||
* @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 errno set to a constant from errno.h to indicate the error
|
||||
*/
|
||||
int open(const char *name, int flags, int mode)
|
||||
{
|
||||
int fd = vfs_open(name, flags, mode);
|
||||
if (fd < 0) {
|
||||
/* vfs returns negative error codes */
|
||||
errno = -fd;
|
||||
return -1;
|
||||
}
|
||||
return fd;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Read bytes from an open file
|
||||
*
|
||||
* This is a wrapper around @c vfs_read
|
||||
*
|
||||
* @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 errno set to a constant from errno.h to indicate the error
|
||||
*/
|
||||
_READ_WRITE_RETURN_TYPE read(int fd, void *dest, size_t count)
|
||||
{
|
||||
int res = vfs_read(fd, dest, count);
|
||||
if (res < 0) {
|
||||
/* vfs returns negative error codes */
|
||||
errno = -res;
|
||||
return -1;
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Write bytes to an open file
|
||||
*
|
||||
* This is a wrapper around @c vfs_write
|
||||
*
|
||||
* @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 errno set to a constant from errno.h to indicate the error
|
||||
*/
|
||||
_READ_WRITE_RETURN_TYPE write(int fd, const void *src, size_t count)
|
||||
{
|
||||
int res = vfs_write(fd, src, count);
|
||||
if (res < 0) {
|
||||
/* vfs returns negative error codes */
|
||||
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] fd open file descriptor obtained from @c open()
|
||||
*
|
||||
* @return 0 on success
|
||||
* @return -1 on error, @c errno set to a constant from errno.h to indicate the error
|
||||
*/
|
||||
int close(int fd)
|
||||
{
|
||||
int res = vfs_close(fd);
|
||||
if (res < 0) {
|
||||
/* vfs returns negative error codes */
|
||||
errno = -res;
|
||||
return -1;
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
/**
|
||||
* Current process times (not implemented).
|
||||
*
|
||||
* @param[out] ptms Not modified.
|
||||
*
|
||||
* @return -1, this function always fails. errno is set to ENOSYS.
|
||||
*/
|
||||
clock_t times(struct tms *ptms)
|
||||
{
|
||||
(void)ptms;
|
||||
errno = ENOSYS;
|
||||
|
||||
return (-1);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Query or set options on an open file
|
||||
*
|
||||
* This is a wrapper around @c vfs_fcntl
|
||||
*
|
||||
* @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 errno set to a constant from errno.h to indicate the error
|
||||
*/
|
||||
int fcntl (int fd, int cmd, int arg)
|
||||
{
|
||||
int res = vfs_fcntl(fd, cmd, arg);
|
||||
if (res < 0) {
|
||||
/* vfs returns negative error codes */
|
||||
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] 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 errno set to a constant from errno.h to indicate the error
|
||||
*/
|
||||
off_t lseek(int fd, _off_t off, int whence)
|
||||
{
|
||||
int res = vfs_lseek(fd, off, whence);
|
||||
if (res < 0) {
|
||||
/* vfs returns negative error codes */
|
||||
errno = -res;
|
||||
return -1;
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Get status of an open file
|
||||
*
|
||||
* This is a wrapper around @c vfs_fstat
|
||||
*
|
||||
* @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 errno set to a constant from errno.h to indicate the error
|
||||
*/
|
||||
int fstat(int fd, struct stat *buf)
|
||||
{
|
||||
int res = vfs_fstat(fd, buf);
|
||||
if (res < 0) {
|
||||
/* vfs returns negative error codes */
|
||||
errno = -res;
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Status of a file (by name)
|
||||
*
|
||||
* This is a wrapper around @c vfs_fstat
|
||||
*
|
||||
* @param[in] name path to file
|
||||
* @param[out] buf pointer to stat struct to fill
|
||||
*
|
||||
* @return 0 on success
|
||||
* @return -1 on error, @c errno set to a constant from errno.h to indicate the error
|
||||
*/
|
||||
int stat(const char *name, struct stat *st)
|
||||
{
|
||||
int res = vfs_stat(name, st);
|
||||
if (res < 0) {
|
||||
/* vfs returns negative error codes */
|
||||
errno = -res;
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Unlink (delete) a file
|
||||
*
|
||||
* @param[in] path path to file to be deleted
|
||||
*
|
||||
* @return 0 on success
|
||||
* @return -1 on error, @c errno set to a constant from errno.h to indicate the error
|
||||
*/
|
||||
int unlink(const char *path)
|
||||
{
|
||||
int res = vfs_unlink(path);
|
||||
if (res < 0) {
|
||||
/* vfs returns negative error codes */
|
||||
errno = -res;
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
#endif /* MODULE_VFS */
|
@ -16,7 +16,7 @@
|
||||
*/
|
||||
|
||||
#ifndef DOXYGEN
|
||||
#if defined(CPU_NATIVE) || MODULE_NEWLIB
|
||||
#if defined(CPU_NATIVE) || MODULE_NEWLIB || MODULE_PICOLIBC
|
||||
/* If building on native or newlib we need to use the system header instead */
|
||||
#pragma GCC system_header
|
||||
/* without the GCC pragma above #include_next will trigger a pedantic error */
|
||||
|
@ -30,8 +30,9 @@
|
||||
#define SYS_SELECT_H
|
||||
|
||||
#include <string.h>
|
||||
/* prevent cyclic dependency with newlib's `sys/types.h` */
|
||||
#if defined(MODULE_NEWLIB) && !defined(CPU_ESP32) && !defined(CPU_ESP8266)
|
||||
/* prevent cyclic dependency with newlib/picolibc's `sys/types.h` */
|
||||
#if (defined(MODULE_NEWLIB) || defined(MODULE_PICOLIBC)) && \
|
||||
!defined(CPU_ESP32) && !defined(CPU_ESP8266)
|
||||
#include <sys/_timeval.h>
|
||||
#else
|
||||
#include <sys/time.h>
|
||||
|
@ -72,7 +72,7 @@ void progress_bar_print(char *prefix, char *suffix, uint8_t value)
|
||||
/* show cursor */
|
||||
printf("\033[?25h");
|
||||
|
||||
#ifdef MODULE_NEWLIB
|
||||
#if defined(MODULE_NEWLIB) || defined(MODULE_PICOLIBC)
|
||||
fflush(stdout);
|
||||
#endif
|
||||
}
|
||||
|
@ -82,7 +82,7 @@ int _ntpdate(int argc, char **argv)
|
||||
puts("Error in synchronization");
|
||||
return 1;
|
||||
}
|
||||
#ifdef MODULE_NEWLIB
|
||||
#if defined(MODULE_NEWLIB) || defined(MODULE_PICOLIBC)
|
||||
struct tm *tm;
|
||||
time_t time = (time_t)(sntp_get_unix_usec() / US_PER_SEC);
|
||||
|
||||
|
@ -42,11 +42,11 @@
|
||||
#define BS '\x08' /** ASCII "Backspace" */
|
||||
#define DEL '\x7f' /** ASCII "Delete" */
|
||||
|
||||
#ifdef MODULE_NEWLIB
|
||||
#if defined(MODULE_NEWLIB) || defined(MODULE_PICOLIBC)
|
||||
#define flush_if_needed() fflush(stdout)
|
||||
#else
|
||||
#define flush_if_needed()
|
||||
#endif /* MODULE_NEWLIB */
|
||||
#endif /* MODULE_NEWLIB || MODULE_PICOLIBC */
|
||||
|
||||
#ifndef SHELL_NO_ECHO
|
||||
#define ECHO_ON 1
|
||||
|
@ -110,7 +110,7 @@ int main(void)
|
||||
double false_positive_rate = (double) in / (double) lenA;
|
||||
/* Use 'fmt/print_float' to work on all platforms (atmega)
|
||||
* Stdout should be flushed before to prevent garbled output. */
|
||||
#ifdef MODULE_NEWLIB
|
||||
#if defined(MODULE_NEWLIB) || defined(MODULE_PICOLIBC)
|
||||
fflush(stdout);
|
||||
#endif
|
||||
print_float(false_positive_rate, 6);
|
||||
|
@ -325,16 +325,16 @@ static void test_fstat(void)
|
||||
print_test_result("test_stat__umount", vfs_umount(&_test_vfs_mount) == 0);
|
||||
}
|
||||
|
||||
#ifdef MODULE_NEWLIB
|
||||
static void test_newlib(void)
|
||||
#if defined(MODULE_NEWLIB) || defined(MODULE_PICOLIBC)
|
||||
static void test_libc(void)
|
||||
{
|
||||
FILE* fl;
|
||||
char buf[sizeof(test_txt) + sizeof(test_txt2)];
|
||||
print_test_result("test_newlib__mount", vfs_mount(&_test_vfs_mount) == 0);
|
||||
print_test_result("test_libc__mount", vfs_mount(&_test_vfs_mount) == 0);
|
||||
|
||||
/* try to open file that doesn't exist */
|
||||
fl = fopen(FULL_FNAME_NXIST, "r");
|
||||
print_test_result("test_newlib__fopen", fl == NULL);
|
||||
print_test_result("test_libc__fopen", fl == NULL);
|
||||
if (fl) {
|
||||
fclose(fl);
|
||||
}
|
||||
@ -342,52 +342,52 @@ static void test_newlib(void)
|
||||
/* create new file write and check content */
|
||||
remove(FULL_FNAME2);
|
||||
fl = fopen(FULL_FNAME2, "w+");
|
||||
print_test_result("test_newlib__fopen_w", fl != NULL);
|
||||
print_test_result("test_libc__fopen_w", fl != NULL);
|
||||
if (fl) {
|
||||
print_test_result("test_newlib__fputs_w", fputs(test_txt, fl) >= 0);
|
||||
print_test_result("test_libc__fputs_w", fputs(test_txt, fl) >= 0);
|
||||
rewind(fl);
|
||||
print_test_result("test_newlib__fread_w",
|
||||
print_test_result("test_libc__fread_w",
|
||||
fread(buf, sizeof(*buf), sizeof(buf), fl) > 0);
|
||||
print_test_result("test_newlib__strcmp_w", strcmp(test_txt, buf) == 0);
|
||||
print_test_result("test_newlib__fclose_w", fclose(fl) == 0);
|
||||
print_test_result("test_libc__strcmp_w", strcmp(test_txt, buf) == 0);
|
||||
print_test_result("test_libc__fclose_w", fclose(fl) == 0);
|
||||
}
|
||||
|
||||
/* cppcheck-suppress resourceLeak
|
||||
* (reason: cppcheck <2.0 reports a false positive here) */
|
||||
fl = fopen(FULL_FNAME2, "r"); /* open file RO */
|
||||
print_test_result("test_newlib__fopen_r", fl != NULL);
|
||||
print_test_result("test_libc__fopen_r", fl != NULL);
|
||||
if (fl) {
|
||||
print_test_result("test_newlib__fclose_r", fclose(fl) == 0);
|
||||
print_test_result("test_libc__fclose_r", fclose(fl) == 0);
|
||||
}
|
||||
|
||||
/* remove file */
|
||||
print_test_result("test_newlib__remove", remove(FULL_FNAME2) == 0);
|
||||
print_test_result("test_libc__remove", remove(FULL_FNAME2) == 0);
|
||||
|
||||
/* append to non existing file */
|
||||
fl = fopen(FULL_FNAME2, "a");
|
||||
print_test_result("test_newlib__fopen_a", fl != NULL);
|
||||
print_test_result("test_libc__fopen_a", fl != NULL);
|
||||
if (fl) {
|
||||
print_test_result("test_newlib__fputs_a", fputs(test_txt, fl) >= 0);
|
||||
print_test_result("test_newlib__fclose_a", fclose(fl) == 0);
|
||||
print_test_result("test_libc__fputs_a", fputs(test_txt, fl) >= 0);
|
||||
print_test_result("test_libc__fclose_a", fclose(fl) == 0);
|
||||
}
|
||||
|
||||
/* append to existing file and check content */
|
||||
fl = fopen(FULL_FNAME2, "a+");
|
||||
print_test_result("test_newlib__fopen_a2", fl != NULL);
|
||||
print_test_result("test_libc__fopen_a2", fl != NULL);
|
||||
if (fl) {
|
||||
print_test_result("test_newlib__fputs_a2", fputs(test_txt2, fl) >= 0);
|
||||
print_test_result("test_libc__fputs_a2", fputs(test_txt2, fl) >= 0);
|
||||
rewind(fl);
|
||||
print_test_result("test_newlib__fread_a2",
|
||||
print_test_result("test_libc__fread_a2",
|
||||
fread(buf, sizeof(*buf), sizeof(buf), fl) > 0);
|
||||
print_test_result("test_newlib__strcmp_a2",
|
||||
print_test_result("test_libc__strcmp_a2",
|
||||
strncmp(test_txt, buf, strlen(test_txt)) == 0);
|
||||
print_test_result("test_newlib__strcmp_a2", strncmp(test_txt2,
|
||||
print_test_result("test_libc__strcmp_a2", strncmp(test_txt2,
|
||||
&buf[strlen(test_txt)], strlen(test_txt2)) == 0);
|
||||
print_test_result("test_newlib__fclose_a2", fclose(fl) == 0);
|
||||
print_test_result("test_libc__fclose_a2", fclose(fl) == 0);
|
||||
}
|
||||
print_test_result("test_newlib__remove", remove(FULL_FNAME2) == 0);
|
||||
print_test_result("test_libc__remove", remove(FULL_FNAME2) == 0);
|
||||
|
||||
print_test_result("test_newlib__umount", vfs_umount(&_test_vfs_mount) == 0);
|
||||
print_test_result("test_libc__umount", vfs_umount(&_test_vfs_mount) == 0);
|
||||
}
|
||||
#endif
|
||||
|
||||
@ -421,8 +421,8 @@ int main(void)
|
||||
test_mkrmdir();
|
||||
test_create();
|
||||
test_fstat();
|
||||
#ifdef MODULE_NEWLIB
|
||||
test_newlib();
|
||||
#if defined(MODULE_NEWLIB) || defined(MODULE_PICOLIBC)
|
||||
test_libc();
|
||||
#endif
|
||||
|
||||
printf("Test end.\n");
|
||||
|
@ -389,7 +389,7 @@ void test_entropy(uint32_t samples)
|
||||
/* Use 'fmt/print_float' to work on all platforms (atmega)
|
||||
* Stdout should be flushed before to prevent garbled output. */
|
||||
printf("Calculated ");
|
||||
#ifdef MODULE_NEWLIB
|
||||
#if defined(MODULE_NEWLIB) || defined(MODULE_PICOLIBC)
|
||||
/* no fflush on msp430 */
|
||||
fflush(stdout);
|
||||
#endif
|
||||
|
@ -171,7 +171,7 @@ static void test_vfs_constfs_read_lseek(void)
|
||||
TEST_ASSERT_EQUAL_INT(0, res);
|
||||
}
|
||||
|
||||
#if MODULE_NEWLIB || defined(BOARD_NATIVE)
|
||||
#if MODULE_NEWLIB || MODULE_PICOLIBC || defined(BOARD_NATIVE)
|
||||
static void test_vfs_constfs__posix(void)
|
||||
{
|
||||
int res;
|
||||
@ -210,7 +210,7 @@ Test *tests_vfs_mount_constfs_tests(void)
|
||||
new_TestFixture(test_vfs_umount__invalid_mount),
|
||||
new_TestFixture(test_vfs_constfs_open),
|
||||
new_TestFixture(test_vfs_constfs_read_lseek),
|
||||
#if MODULE_NEWLIB || defined(BOARD_NATIVE)
|
||||
#if MODULE_NEWLIB || MODULE_PICOLIBC || defined(BOARD_NATIVE)
|
||||
new_TestFixture(test_vfs_constfs__posix),
|
||||
#endif
|
||||
};
|
||||
|
Loading…
Reference in New Issue
Block a user