From 59e915a5eb1897ef3498dc920e9148be188890b3 Mon Sep 17 00:00:00 2001 From: Keith Packard Date: Fri, 1 Apr 2022 16:51:58 -0700 Subject: [PATCH 1/8] [netdev] Don't define htons et al. if already defined Picolibc defines these network macro functions, which conflict with the definitions in netdev_ipaddr.h. Signed-off-by: Keith Packard --- components/net/netdev/include/netdev_ipaddr.h | 2 ++ 1 file changed, 2 insertions(+) diff --git a/components/net/netdev/include/netdev_ipaddr.h b/components/net/netdev/include/netdev_ipaddr.h index 08ea50ed9df..7342261c357 100644 --- a/components/net/netdev/include/netdev_ipaddr.h +++ b/components/net/netdev/include/netdev_ipaddr.h @@ -78,10 +78,12 @@ enum netdev_ip_addr_type { (((x) & 0xff000000UL) >> 24)) #define PP_NTOHL(x) PP_HTONL(x) +#ifndef htons #define htons(x) (uint16_t)PP_HTONS(x) #define ntohs(x) (uint16_t)PP_NTOHS(x) #define htonl(x) (uint32_t)PP_HTONL(x) #define ntohl(x) (uint32_t)PP_NTOHL(x) +#endif /* If your port already typedef's in_addr_t, define IN_ADDR_T_DEFINED to prevent this code from redefining it. */ From 82bfb118eb6576554bb960e423f5cad98120fac1 Mon Sep 17 00:00:00 2001 From: Keith Packard Date: Fri, 1 Apr 2022 18:12:10 -0700 Subject: [PATCH 2/8] [serial] Move putc/getc undefs outside the RT_USING_POSIX_STDIO block We may have included stdio.h elsewhere in the system. Signed-off-by: Keith Packard --- components/drivers/serial/serial.c | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/components/drivers/serial/serial.c b/components/drivers/serial/serial.c index c749897a089..8b0b5309d10 100644 --- a/components/drivers/serial/serial.c +++ b/components/drivers/serial/serial.c @@ -36,6 +36,15 @@ #define DBG_LVL DBG_INFO #include +/* it's possible the 'getc/putc' is defined by stdio.h in gcc/newlib. */ +#ifdef getc +#undef getc +#endif + +#ifdef putc +#undef putc +#endif + #ifdef RT_USING_POSIX_STDIO #include #include @@ -47,15 +56,6 @@ #include #endif -/* it's possible the 'getc/putc' is defined by stdio.h in gcc/newlib. */ -#ifdef getc -#undef getc -#endif - -#ifdef putc -#undef putc -#endif - static rt_err_t serial_fops_rx_ind(rt_device_t dev, rt_size_t size) { rt_wqueue_wakeup(&(dev->wait_queue), (void*)POLLIN); From 44f74044ccedf038a76412ac2ee849eafe0ab54d Mon Sep 17 00:00:00 2001 From: Keith Packard Date: Fri, 1 Apr 2022 16:40:17 -0700 Subject: [PATCH 3/8] [libc] Add support for picolibc This allows projects to set the LIBC variable to either 'newlib' or 'picolibc' to select between these two libraries. RT-Thread expects picolibc to have been built with TLS support, and that requires a small change to the project linker script to set up TLS symbols, inserting this section: . = ALIGN(8); .tdata : { *(.tdata) *(.tdata.*) *(.gnu.linkonce.td.*) } .tbss (NOLOAD) : { *(.tbss .tbss.* .gnu.linkonce.tb.*) *(.tcommon) } __tdata_source = ADDR(.tdata); __tdata_size = SIZEOF(.tdata); __tbss_size = SIZEOF(.tbss); __tls_size = SIZEOF(.tdata) + SIZEOF(.tbss); These should go with the section defining ROM contents as the '.tdata' section will place initialization values for the TLS block in memory. Signed-off-by: Keith Packard --- components/libc/compilers/newlib/SConscript | 2 +- components/libc/compilers/picolibc/README.md | 4 + components/libc/compilers/picolibc/SConscript | 33 ++++ components/libc/compilers/picolibc/fcntl.h | 24 +++ .../libc/compilers/picolibc/machine/time.h | 17 ++ components/libc/compilers/picolibc/syscalls.c | 148 ++++++++++++++++++ include/rtdef.h | 17 ++ include/rtthread.h | 11 ++ src/kservice.c | 9 +- src/scheduler.c | 5 + src/thread.c | 14 +- tools/gcc.py | 101 ++++++++++-- 12 files changed, 369 insertions(+), 16 deletions(-) create mode 100644 components/libc/compilers/picolibc/README.md create mode 100644 components/libc/compilers/picolibc/SConscript create mode 100644 components/libc/compilers/picolibc/fcntl.h create mode 100644 components/libc/compilers/picolibc/machine/time.h create mode 100644 components/libc/compilers/picolibc/syscalls.c diff --git a/components/libc/compilers/newlib/SConscript b/components/libc/compilers/newlib/SConscript index 8076a737279..e3bdd3b6d3f 100644 --- a/components/libc/compilers/newlib/SConscript +++ b/components/libc/compilers/newlib/SConscript @@ -9,7 +9,7 @@ group = [] LIBS = ['m'] # link libm CPPPATH = [cwd] -if rtconfig.PLATFORM == 'gcc': +if rtconfig.PLATFORM == 'gcc' and GetGCCLibc(rtconfig) == None: LIBS += ['c'] # link libc src += Glob('*.c') diff --git a/components/libc/compilers/picolibc/README.md b/components/libc/compilers/picolibc/README.md new file mode 100644 index 00000000000..c55be73a0a8 --- /dev/null +++ b/components/libc/compilers/picolibc/README.md @@ -0,0 +1,4 @@ +# Picolibc (GCC) porting for RT-Thread + +https://keithp.com/picolibc + diff --git a/components/libc/compilers/picolibc/SConscript b/components/libc/compilers/picolibc/SConscript new file mode 100644 index 00000000000..81eea2347f1 --- /dev/null +++ b/components/libc/compilers/picolibc/SConscript @@ -0,0 +1,33 @@ +import os +from building import * +from gcc import * +Import('rtconfig') + +src = [] +cwd = GetCurrentDir() +group = [] +CPPPATH = [cwd] +LIBS = [] +CCFLAGS = '--specs=picolibc.specs' +LINKFLAGS = ' --specs=picolibc.specs' + +if rtconfig.PLATFORM == 'gcc' and GetGCCLibc(rtconfig) == 'picolibc': + LIBS += ['c'] # link libc + src += Glob('*.c') + + #report picolibc version + print('Picolibc version:' + GetPicolibcVersion(rtconfig)) + + # identify this is Picolibc + CPPDEFINES = ['RT_USING_PICOLIBC', 'LWIP_DONT_PROVIDE_BYTEORDER_FUNCTIONS'] + + group = DefineGroup('Compiler', src, depend = [''], CPPPATH = CPPPATH, CPPDEFINES = CPPDEFINES, LIBS = LIBS, CCFLAGS = CCFLAGS, LINKFLAGS = LINKFLAGS) + + +list = os.listdir(cwd) +for d in list: + path = os.path.join(cwd, d) + if os.path.isfile(os.path.join(path, 'SConscript')): + group = group + SConscript(os.path.join(d, 'SConscript')) + +Return('group') diff --git a/components/libc/compilers/picolibc/fcntl.h b/components/libc/compilers/picolibc/fcntl.h new file mode 100644 index 00000000000..847ae3d35bc --- /dev/null +++ b/components/libc/compilers/picolibc/fcntl.h @@ -0,0 +1,24 @@ +/* + * Copyright (c) 2006-2021, RT-Thread Development Team + * + * SPDX-License-Identifier: Apache-2.0 + * + * Change Logs: + * Date Author Notes + * 2021-09-02 Meco Man First version + */ + +#ifndef __FCNTL_H__ +#define __FCNTL_H__ + +#include + +#ifndef O_DIRECTORY +#define O_DIRECTORY 0x200000 +#endif + +#ifndef O_BINARY +#define O_BINARY 0x10000 +#endif + +#endif diff --git a/components/libc/compilers/picolibc/machine/time.h b/components/libc/compilers/picolibc/machine/time.h new file mode 100644 index 00000000000..805b061aea0 --- /dev/null +++ b/components/libc/compilers/picolibc/machine/time.h @@ -0,0 +1,17 @@ +/* + * Copyright (c) 2006-2021, RT-Thread Development Team + * + * SPDX-License-Identifier: Apache-2.0 + * + * Change Logs: + * Date Author Notes + * 2021-02-16 Meco Man The first version + */ + +#ifndef _MACHTIME_H_ +#define _MACHTIME_H_ + +#include +#define _CLOCKS_PER_SEC_ RT_TICK_PER_SECOND + +#endif /* _MACHTIME_H_ */ diff --git a/components/libc/compilers/picolibc/syscalls.c b/components/libc/compilers/picolibc/syscalls.c new file mode 100644 index 00000000000..f1ed4b4c164 --- /dev/null +++ b/components/libc/compilers/picolibc/syscalls.c @@ -0,0 +1,148 @@ +/* + * Copyright (c) 2006-2021, RT-Thread Development Team + * + * SPDX-License-Identifier: Apache-2.0 + * + * Change Logs: + * Date Author Notes + * 2022-04-01 Keith Packard Port to picolibc + * 2021-02-11 Meco Man remove _gettimeofday_r() and _times_r() + * 2020-02-13 Meco Man re-implement exit() and abort() + * 2020-02-21 Meco Man improve and beautify syscalls + * 2020-02-24 Meco Man fix bug of _isatty_r() + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#ifdef RT_USING_POSIX_STDIO +#include "libc.h" +#endif /* RT_USING_POSIX_STDIO */ +#ifdef RT_USING_MODULE +#include +#endif /* RT_USING_MODULE */ +#include +#define DBG_TAG "picolibc.syscalls" +#define DBG_LVL DBG_INFO +#include + +#ifdef RT_USING_HEAP /* Memory routine */ +void *malloc (size_t size) +{ + void* result; + + result = (void*)rt_malloc (size); + if (result == RT_NULL) + { + errno = ENOMEM; + } + + return result; +} + +void *realloc (void *old, size_t newlen) +{ + void* result; + + result = (void*)rt_realloc (old, newlen); + if (result == RT_NULL) + { + errno = ENOMEM; + } + + return result; +} + +void *calloc (size_t size, size_t len) +{ + void* result; + + result = (void*)rt_calloc (size, len); + if (result == RT_NULL) + { + errno = ENOMEM; + } + + return result; +} + +void free (void *addr) +{ + rt_free (addr); +} + +#else +void * +sbrk(ptrdiff_t incr) +{ + LOG_E("Please enable RT_USING_HEAP"); + RT_ASSERT(0); + return RT_NULL; +} +#endif /*RT_USING_HEAP*/ + +void __libc_init_array(void) +{ + /* we not use __libc init_aray to initialize C++ objects */ + /* __libc_init_array is ARM code, not Thumb; it will cause a hardfault. */ +} + +mode_t umask(mode_t mask) +{ + return 022; +} + +int flock(int fd, int operation) +{ + return 0; +} + +#include + +#ifdef RT_USING_CONSOLE +int +rt_getc(FILE *file) +{ + (void) file; + rt_size_t len = 0; + char c = 0; +#ifdef RT_USING_DEVICE + rt_device_t console = rt_console_get_device(); + if (console != RT_NULL) + len = rt_device_read(console, 0, &c, 1); +#endif + if (len != 1) + { + return _FDEV_ERR; + } + return (int) (unsigned char) c; +} + +int +rt_putc(char c, FILE *file) +{ + (void) file; +#ifdef RT_USING_DEVICE + rt_device_t console = rt_console_get_device(); + if (console != RT_NULL) { + rt_device_write(console, 0, &c, 1); + return 0; + } +#endif + char buf[2] = { c, 0 }; + rt_hw_console_output(buf); + return 0; +} + +static FILE __stdio = FDEV_SETUP_STREAM(rt_putc, rt_getc, NULL, __SRD|__SWR); + +FILE *const stdin = &__stdio; +FILE *const stdout = &__stdio; +FILE *const stderr = &__stdio; + +#endif diff --git a/include/rtdef.h b/include/rtdef.h index f74d781cb16..f497a9a1390 100644 --- a/include/rtdef.h +++ b/include/rtdef.h @@ -606,6 +606,20 @@ struct rt_cpu #endif +#if defined(RT_USING_PICOLIBC) && defined(_HAVE_PICOLIBC_TLS_API) +#define RT_USING_TLS +#include +#define rt_set_tls(thread) _set_tls((thread)->tls) +#define rt_init_tls(thread) _init_tls((thread)->tls) +#define rt_tls_size(thread) _tls_size() +#endif + +#ifndef RT_USING_TLS +#define rt_set_tls(thread) ((void) (thread)) +#define rt_init_tls(thread) ((void) (thread)) +#define rt_tls_size(thread) (0) +#endif + /** * Thread structure */ @@ -629,6 +643,9 @@ struct rt_thread void *parameter; /**< parameter */ void *stack_addr; /**< stack address */ rt_uint32_t stack_size; /**< stack size */ +#ifdef RT_USING_TLS + void *tls; /**< tls address */ +#endif /* error code */ rt_err_t error; /**< error code */ diff --git a/include/rtthread.h b/include/rtthread.h index 729ee4c4057..8f267335fb3 100644 --- a/include/rtthread.h +++ b/include/rtthread.h @@ -588,6 +588,16 @@ rt_device_t rt_console_set_device(const char *name); rt_device_t rt_console_get_device(void); #endif +#ifdef RT_USING_PICOLIBC +#define RT_KSERVICE_USING_LIBC_ERRNO +#endif + +#ifdef RT_KSERVICE_USING_LIBC_ERRNO +#include +static inline int *_rt_errno(void) { return &errno; } +static inline rt_err_t rt_get_errno(void) { return errno; } +static inline void rt_set_errno(rt_err_t no) { errno = no; } +#else rt_err_t rt_get_errno(void); void rt_set_errno(rt_err_t no); int *_rt_errno(void); @@ -596,6 +606,7 @@ int *_rt_errno(void); #define errno *_rt_errno() #endif #endif +#endif int __rt_ffs(int value); diff --git a/src/kservice.c b/src/kservice.c index 4d3aea67095..99372337733 100644 --- a/src/kservice.c +++ b/src/kservice.c @@ -38,13 +38,14 @@ /**@{*/ -/* global errno in RT-Thread */ -static volatile int __rt_errno; - #if defined(RT_USING_DEVICE) && defined(RT_USING_CONSOLE) static rt_device_t _console_device = RT_NULL; #endif +#ifndef RT_KSERVICE_USING_LIBC_ERRNO +/* global errno in RT-Thread */ +static volatile int __rt_errno; + /** * This function gets the global errno for the current thread. * @@ -117,6 +118,8 @@ int *_rt_errno(void) } RTM_EXPORT(_rt_errno); +#endif + #ifndef RT_KSERVICE_USING_STDLIB_MEMSET /** * This function will set the content of memory to specified value. diff --git a/src/scheduler.c b/src/scheduler.c index 6123aaf42a0..5e930921a51 100644 --- a/src/scheduler.c +++ b/src/scheduler.c @@ -261,6 +261,7 @@ void rt_system_scheduler_start(void) rt_schedule_remove_thread(to_thread); to_thread->stat = RT_THREAD_RUNNING; + rt_set_tls(to_thread); /* switch to new thread */ #ifdef RT_USING_SMP rt_hw_context_switch_to((rt_ubase_t)&to_thread->sp, to_thread); @@ -383,6 +384,7 @@ void rt_schedule(void) RT_OBJECT_HOOK_CALL(rt_scheduler_switch_hook, (current_thread)); + rt_set_tls(to_thread); rt_hw_context_switch((rt_ubase_t)¤t_thread->sp, (rt_ubase_t)&to_thread->sp, to_thread); } @@ -494,6 +496,7 @@ void rt_schedule(void) RT_OBJECT_HOOK_CALL(rt_scheduler_switch_hook, (from_thread)); + rt_set_tls(to_thread); rt_hw_context_switch((rt_ubase_t)&from_thread->sp, (rt_ubase_t)&to_thread->sp); @@ -525,6 +528,7 @@ void rt_schedule(void) { RT_DEBUG_LOG(RT_DEBUG_SCHEDULER, ("switch in interrupt\n")); + rt_set_tls(to_thread); rt_hw_context_switch_interrupt((rt_ubase_t)&from_thread->sp, (rt_ubase_t)&to_thread->sp); } @@ -632,6 +636,7 @@ void rt_scheduler_do_irq_switch(void *context) RT_OBJECT_HOOK_CALL(rt_scheduler_switch_hook, (current_thread)); + rt_set_tls(to_thread); rt_hw_context_switch_interrupt(context, (rt_ubase_t)¤t_thread->sp, (rt_ubase_t)&to_thread->sp, to_thread); } diff --git a/src/thread.c b/src/thread.c index d0cdc4043a4..6aaae1f1248 100755 --- a/src/thread.c +++ b/src/thread.c @@ -177,12 +177,22 @@ static rt_err_t _thread_init(struct rt_thread *thread, /* init thread stack */ rt_memset(thread->stack_addr, '#', thread->stack_size); #ifdef ARCH_CPU_STACK_GROWS_UPWARD +#ifdef RT_USING_TLS + thread->tls = stack_start; + stack_start = ((char *) stack_start) + rt_tls_size(); + rt_init_tls(thread); +#endif thread->sp = (void *)rt_hw_stack_init(thread->entry, thread->parameter, - (void *)((char *)thread->stack_addr), + (void *)((char *)stack_start), (void *)_thread_exit); #else +#ifdef RT_USING_TLS + stack_size = stack_size - rt_tls_size(thread); + thread->tls = (char *) stack_start + stack_size; + rt_init_tls(thread); +#endif thread->sp = (void *)rt_hw_stack_init(thread->entry, thread->parameter, - (rt_uint8_t *)((char *)thread->stack_addr + thread->stack_size - sizeof(rt_ubase_t)), + (rt_uint8_t *)((char *)stack_start + stack_size - sizeof(rt_ubase_t)), (void *)_thread_exit); #endif /* ARCH_CPU_STACK_GROWS_UPWARD */ diff --git a/tools/gcc.py b/tools/gcc.py index 1b31d5d549d..0465e4bfc2a 100644 --- a/tools/gcc.py +++ b/tools/gcc.py @@ -24,20 +24,76 @@ import os import re import platform +import subprocess + +def GetGCCLibc(rtconfig): + try: + return rtconfig.LIBC + except AttributeError: + return None + +def GetGCCSysroot(rtconfig): + gcc_cmd = os.path.join(rtconfig.EXEC_PATH, rtconfig.CC) + + if(platform.system() == 'Windows'): + child = subprocess.Popen([gcc_cmd, '-print-sysroot'], stdout=subprocess.PIPE, stderr=subprocess.PIPE, shell=True) + else: + child = subprocess.Popen(gcc_cmd + ' -print-sysroot', stdout=subprocess.PIPE, stderr=subprocess.PIPE, shell=True) + + stdout, stderr = child.communicate() + if stderr: + print(stderr) + + return stdout.split(b'\n')[0].decode() def GetGCCRoot(rtconfig): - exec_path = rtconfig.EXEC_PATH prefix = rtconfig.PREFIX if prefix.endswith('-'): prefix = prefix[:-1] - if exec_path == '/usr/bin': - root_path = os.path.join('/usr/lib', prefix) + # Check to see if GCC was configured with sysroot, + # in that case, the library header files will be + # found beneath that + + sysroot = GetGCCSysroot(rtconfig) + + # Check to see if we're using a non-standard libc + + libc = GetGCCLibc(rtconfig) + + # four cases: sysroot/non-sysroot + standard-libc/non-standard-libc + + if sysroot: + if libc: + # sysroot + non-standard libc: sysroot/libc/prefix + # e.g. /opt/gcc-arm-none-eabi-10-2020-q4-major/arm-none-eabi/picolibc/arm-none-eabi + return os.path.join(sysroot, libc, prefix) + else: + # sysroot + standard libc: sysroot + # e.g. /opt/gcc-arm-none-eabi-10-2020-q4-major/arm-none-eabi + return sysroot else: - root_path = os.path.join(exec_path, '..', prefix) + # Otherwise, libc header files should + # be under exec_path/.., *unless* exec_path + # is /usr/bin, in which case they'll be under + # /usr/lib. + exec_path = rtconfig.EXEC_PATH + + if exec_path == '/usr/bin': + lib_path = '/usr/lib' + else: + lib_path = os.path.join(exec_path, '..') - return root_path + # tack on the prefix to find the header files + if libc: + # non sysroot + non-standard libc: lib/libc/prefix + # e.g. /usr/lib/picolibc/arm-none-eabi + return os.path.join(lib_path, libc, prefix) + else: + # non sysroot + standard libc: lib/prefix + # e.g. /usr/lib/arm-none-eabi + return os.path.join(lib_path, prefix) def CheckHeader(rtconfig, filename): root = GetGCCRoot(rtconfig) @@ -86,9 +142,20 @@ def GetNewLibVersion(rtconfig): f.close() return version -def GCCResult(rtconfig, str): - import subprocess +def GetPicolibcVersion(rtconfig): + version = 'unknown' + root = GetGCCRoot(rtconfig) + + if CheckHeader(rtconfig, 'picolibc.h'): # get version from picolibc.h file + f = open(os.path.join(root, 'include', 'picolibc.h'), 'r') + if f: + for line in f: + if line.find('_PICOLIBC_VERSION') != -1 and line.find('"') != -1: + version = re.search(r'\"([^"]+)\"', line).groups()[0] + f.close() + return version +def GCCResult(rtconfig, str): result = '' def checkAndGetResult(pattern, string): @@ -104,11 +171,21 @@ def checkAndGetResult(pattern, string): f.write(str) f.close() + libc = GetGCCLibc(rtconfig) + + libc_specs = '--specs=' + libc + '.specs' + # '-fdirectives-only', if(platform.system() == 'Windows'): - child = subprocess.Popen([gcc_cmd, '-E', '-P', '__tmp.c'], stdout=subprocess.PIPE, stderr=subprocess.PIPE, shell=True) + specs = [] + if libc != None: + specs = [libc_specs] + child = subprocess.Popen([gcc_cmd, '-E', '-P', '__tmp.c'] + specs, stdout=subprocess.PIPE, stderr=subprocess.PIPE, shell=True) else: - child = subprocess.Popen(gcc_cmd + ' -E -P __tmp.c', stdout=subprocess.PIPE, stderr=subprocess.PIPE, shell=True) + specs = '' + if libc != None: + specs = ' ' + libc_specs + child = subprocess.Popen(gcc_cmd + ' -E -P __tmp.c' + specs, stdout=subprocess.PIPE, stderr=subprocess.PIPE, shell=True) stdout, stderr = child.communicate() @@ -180,7 +257,11 @@ def GenerateGCCConfig(rtconfig): cc_header += '/* Automatically generated file; DO NOT EDIT. */\n' cc_header += '/* compiler configure file for RT-Thread in GCC*/\n\n' - if CheckHeader(rtconfig, 'newlib.h'): + if CheckHeader(rtconfig, 'picolibc.h'): + str += '#include \n' + cc_header += '#define HAVE_PICOLIBC_H 1\n' + cc_header += '#define LIBC_VERSION "picolibc %s"\n\n' % GetPicolibcVersion(rtconfig) + elif CheckHeader(rtconfig, 'newlib.h'): str += '#include \n' cc_header += '#define HAVE_NEWLIB_H 1\n' cc_header += '#define LIBC_VERSION "newlib %s"\n\n' % GetNewLibVersion(rtconfig) From 781533e36ec88e6d61b57c77bcd0b771e5ebca50 Mon Sep 17 00:00:00 2001 From: Keith Packard Date: Fri, 1 Apr 2022 16:48:27 -0700 Subject: [PATCH 4/8] [src] Allow use of native libc printf functions This adds a configuration option to replace the RT output functions with macros that refer to the underlying stdio versions from libc. Signed-off-by: Keith Packard --- include/rtthread.h | 10 ++++++++++ src/Kconfig | 4 ++++ src/kservice.c | 8 ++++++++ 3 files changed, 22 insertions(+) diff --git a/include/rtthread.h b/include/rtthread.h index 8f267335fb3..1fa8860045f 100644 --- a/include/rtthread.h +++ b/include/rtthread.h @@ -578,10 +578,20 @@ int rt_kprintf(const char *fmt, ...); void rt_kputs(const char *str); #endif +#ifdef RT_KSERVICE_USING_PRINTF +#include +#define rt_vsprintf(d,f,a) vsprintf(d,f,a) +#define rt_vsnprintf(b,s,f,a) vsnprintf(b,s,f,a) +#define rt_sprintf(b,f,...) sprintf(b,f,__VA_ARGS__) +#define rt_snprintf(b,s,f,...) snprintf(b,s,f,__VA_ARGS__) +#define rt_kprintf(...) printf(__VA_ARGS__) +#define rt_kputs(s) fputs(s, stdout) +#else int rt_vsprintf(char *dest, const char *format, va_list arg_ptr); int rt_vsnprintf(char *buf, rt_size_t size, const char *fmt, va_list args); int rt_sprintf(char *buf, const char *format, ...); int rt_snprintf(char *buf, rt_size_t size, const char *format, ...); +#endif #if defined(RT_USING_DEVICE) && defined(RT_USING_CONSOLE) rt_device_t rt_console_set_device(const char *name); diff --git a/src/Kconfig b/src/Kconfig index 6dc73bc400d..43cde1d60f8 100644 --- a/src/Kconfig +++ b/src/Kconfig @@ -149,6 +149,10 @@ menu "kservice optimization" bool "Enable kservice to use tiny finding first bit set method" default n + config RT_KSERVICE_USING_PRINTF + bool "Enable kservice to use libc printf" + default n + config RT_PRINTF_LONGLONG bool "Enable rt_printf-family functions to support long long format" default n diff --git a/src/kservice.c b/src/kservice.c index 99372337733..cc9b8c30192 100644 --- a/src/kservice.c +++ b/src/kservice.c @@ -620,6 +620,8 @@ void rt_show_version(void) } RTM_EXPORT(rt_show_version); +#ifndef RT_KSERVICE_USING_PRINTF + /* private function */ #define _ISDIGIT(c) ((unsigned)((c) - '0') < 10) @@ -1182,6 +1184,8 @@ int rt_sprintf(char *buf, const char *format, ...) } RTM_EXPORT(rt_sprintf); +#endif + #ifdef RT_USING_CONSOLE #ifdef RT_USING_DEVICE @@ -1242,6 +1246,7 @@ RT_WEAK void rt_hw_console_output(const char *str) } RTM_EXPORT(rt_hw_console_output); +#ifndef RT_KSERVICE_USING_PRINTF /** * This function will put string to the console. * @@ -1304,6 +1309,9 @@ RT_WEAK int rt_kprintf(const char *fmt, ...) return length; } RTM_EXPORT(rt_kprintf); + +#endif /* RT_KSERVICE_USING_PRINTF */ + #endif /* RT_USING_CONSOLE */ #if defined(RT_USING_HEAP) && !defined(RT_USING_USERHEAP) From 6e4979e2e9b9917aab6def16cfef8cc7a115daf0 Mon Sep 17 00:00:00 2001 From: Keith Packard Date: Fri, 1 Apr 2022 18:46:45 -0700 Subject: [PATCH 5/8] [libc] Add option to use integer-only printf from picolibc Signed-off-by: Keith Packard --- components/libc/compilers/picolibc/SConscript | 4 ++++ src/Kconfig | 4 ++++ 2 files changed, 8 insertions(+) diff --git a/components/libc/compilers/picolibc/SConscript b/components/libc/compilers/picolibc/SConscript index 81eea2347f1..4fd2e0776bd 100644 --- a/components/libc/compilers/picolibc/SConscript +++ b/components/libc/compilers/picolibc/SConscript @@ -21,6 +21,10 @@ if rtconfig.PLATFORM == 'gcc' and GetGCCLibc(rtconfig) == 'picolibc': # identify this is Picolibc CPPDEFINES = ['RT_USING_PICOLIBC', 'LWIP_DONT_PROVIDE_BYTEORDER_FUNCTIONS'] + if GetDepend('RT_PRINTF_FLOAT') == False: + CPPDEFINES += ['-DPICOLIBC_INTEGER_PRINTF_SCANF'] + LINKFLAGS += ' -DPICOLIBC_INTEGER_PRINTF_SCANF' + group = DefineGroup('Compiler', src, depend = [''], CPPPATH = CPPPATH, CPPDEFINES = CPPDEFINES, LIBS = LIBS, CCFLAGS = CCFLAGS, LINKFLAGS = LINKFLAGS) diff --git a/src/Kconfig b/src/Kconfig index 43cde1d60f8..f0479e3c8ef 100644 --- a/src/Kconfig +++ b/src/Kconfig @@ -157,6 +157,10 @@ menu "kservice optimization" bool "Enable rt_printf-family functions to support long long format" default n + config RT_PRINTF_FLOAT + bool "Enable libc printf functions to support float" + default n + endmenu menuconfig RT_DEBUG From a358a0e6aa9d133a2ba02c32d8424bc96ab3dabd Mon Sep 17 00:00:00 2001 From: Keith Packard Date: Sat, 2 Apr 2022 10:48:59 -0700 Subject: [PATCH 6/8] [github] Install picolibc for CI tests Signed-off-by: Keith Packard --- .github/workflows/action.yml | 2 ++ .github/workflows/action_tools.yml | 2 ++ .github/workflows/action_utest.yml | 4 +++- 3 files changed, 7 insertions(+), 1 deletion(-) diff --git a/.github/workflows/action.yml b/.github/workflows/action.yml index 778989e5b7a..34107ed0235 100644 --- a/.github/workflows/action.yml +++ b/.github/workflows/action.yml @@ -193,6 +193,8 @@ jobs: run: | wget -q https://github.com/RT-Thread/toolchains-ci/releases/download/v1.3/gcc-arm-none-eabi-10-2020-q4-major-x86_64-linux.tar.bz2 sudo tar xjf gcc-arm-none-eabi-10-2020-q4-major-x86_64-linux.tar.bz2 -C /opt + wget -q https://github.com/picolibc/picolibc/releases/download/1.7.6/picolibc-1.7.6-10-2020-q4-major.zip + sudo unzip picolibc-1.7.6-10-2020-q4-major.zip -d /opt/gcc-arm-none-eabi-10-2020-q4-major /opt/gcc-arm-none-eabi-10-2020-q4-major/bin/arm-none-eabi-gcc --version echo "RTT_EXEC_PATH=/opt/gcc-arm-none-eabi-10-2020-q4-major/bin" >> $GITHUB_ENV diff --git a/.github/workflows/action_tools.yml b/.github/workflows/action_tools.yml index 098f7ea4826..9415a445ea4 100644 --- a/.github/workflows/action_tools.yml +++ b/.github/workflows/action_tools.yml @@ -50,6 +50,8 @@ jobs: run: | wget -q https://github.com/RT-Thread/toolchains-ci/releases/download/v1.3/gcc-arm-none-eabi-10-2020-q4-major-x86_64-linux.tar.bz2 sudo tar xjf gcc-arm-none-eabi-10-2020-q4-major-x86_64-linux.tar.bz2 -C /opt + wget -q https://github.com/picolibc/picolibc/releases/download/1.7.6/picolibc-1.7.6-10-2020-q4-major.zip + sudo unzip picolibc-1.7.6-10-2020-q4-major.zip -d /opt/gcc-arm-none-eabi-10-2020-q4-major /opt/gcc-arm-none-eabi-10-2020-q4-major/bin/arm-none-eabi-gcc --version echo "RTT_EXEC_PATH=/opt/gcc-arm-none-eabi-10-2020-q4-major/bin" >> $GITHUB_ENV diff --git a/.github/workflows/action_utest.yml b/.github/workflows/action_utest.yml index 94f4245d4d3..2426e7169b5 100644 --- a/.github/workflows/action_utest.yml +++ b/.github/workflows/action_utest.yml @@ -57,6 +57,8 @@ jobs: run: | wget -q https://github.com/RT-Thread/toolchains-ci/releases/download/v1.3/gcc-arm-none-eabi-10-2020-q4-major-x86_64-linux.tar.bz2 sudo tar xjf gcc-arm-none-eabi-10-2020-q4-major-x86_64-linux.tar.bz2 -C /opt + wget -q https://github.com/picolibc/picolibc/releases/download/1.7.6/picolibc-1.7.6-10-2020-q4-major.zip + sudo unzip picolibc-1.7.6-10-2020-q4-major.zip -d /opt/gcc-arm-none-eabi-10-2020-q4-major /opt/gcc-arm-none-eabi-10-2020-q4-major/bin/arm-none-eabi-gcc --version echo "RTT_EXEC_PATH=/opt/gcc-arm-none-eabi-10-2020-q4-major/bin" >> $GITHUB_ENV @@ -89,4 +91,4 @@ jobs: python3 qemu_runner.py --system $TEST_QEMU_ARCH --machine $TEST_QEMU_MACHINE --elf ../$TEST_BSP_ROOT/rtthread.elf fi cat rtt_console.log - popd \ No newline at end of file + popd From a56afaa222a7e3f9f18f925f142fed3b008603cb Mon Sep 17 00:00:00 2001 From: Keith Packard Date: Fri, 1 Apr 2022 16:45:49 -0700 Subject: [PATCH 7/8] [bsp] Switch qemu-vexpress-a9 sample to picolibc This adds the necessary changes to the linker script and then selects picolibc instead of the default (newlib). Before: text data bss dec hex filename 561638 2100 84928 648666 9e5da rtthread.elf After: text data bss dec hex filename 525009 692 86844 612545 958c1 rtthread.elf Signed-off-by: Keith Packard --- bsp/qemu-vexpress-a9/.config | 5 ++++- bsp/qemu-vexpress-a9/link.lds | 17 +++++++++++++++++ bsp/qemu-vexpress-a9/rtconfig.h | 4 ++++ bsp/qemu-vexpress-a9/rtconfig.py | 1 + 4 files changed, 26 insertions(+), 1 deletion(-) diff --git a/bsp/qemu-vexpress-a9/.config b/bsp/qemu-vexpress-a9/.config index 3dc3ff6ce3f..cb5d4d69e2b 100644 --- a/bsp/qemu-vexpress-a9/.config +++ b/bsp/qemu-vexpress-a9/.config @@ -30,9 +30,12 @@ CONFIG_RT_TIMER_THREAD_STACK_SIZE=1024 # # kservice optimization # -# CONFIG_RT_KSERVICE_USING_STDLIB is not set +CONFIG_RT_KSERVICE_USING_STDLIB=y +CONFIG_RT_KSERVICE_USING_STDLIB_MEMCPY=y +CONFIG_RT_KSERVICE_USING_STDLIB_MEMSET=y # CONFIG_RT_KSERVICE_USING_TINY_SIZE is not set # CONFIG_RT_USING_TINY_FFS is not set +CONFIG_RT_KSERVICE_USING_PRINTF=y # CONFIG_RT_PRINTF_LONGLONG is not set CONFIG_RT_DEBUG=y CONFIG_RT_DEBUG_COLOR=y diff --git a/bsp/qemu-vexpress-a9/link.lds b/bsp/qemu-vexpress-a9/link.lds index 8e4f65b454e..c8c4c62c697 100644 --- a/bsp/qemu-vexpress-a9/link.lds +++ b/bsp/qemu-vexpress-a9/link.lds @@ -72,6 +72,23 @@ SECTIONS PROVIDE(__dtors_end__ = .); } + . = ALIGN(8); + .tdata : { + *(.tdata) + *(.tdata.*) + *(.gnu.linkonce.td.*) + } + + .tbss (NOLOAD) : { + *(.tbss .tbss.* .gnu.linkonce.tb.*) + *(.tcommon) + } + + __tdata_source = ADDR(.tdata); + __tdata_size = SIZEOF(.tdata); + __tbss_size = SIZEOF(.tbss); + __tls_size = SIZEOF(.tdata) + SIZEOF(.tbss); + . = ALIGN(8); __data_start = .; .data : diff --git a/bsp/qemu-vexpress-a9/rtconfig.h b/bsp/qemu-vexpress-a9/rtconfig.h index 3671b026822..6a4dede1a73 100644 --- a/bsp/qemu-vexpress-a9/rtconfig.h +++ b/bsp/qemu-vexpress-a9/rtconfig.h @@ -26,6 +26,10 @@ /* kservice optimization */ +#define RT_KSERVICE_USING_STDLIB +#define RT_KSERVICE_USING_STDLIB_MEMCPY +#define RT_KSERVICE_USING_STDLIB_MEMSET +#define RT_KSERVICE_USING_PRINTF #define RT_DEBUG #define RT_DEBUG_COLOR diff --git a/bsp/qemu-vexpress-a9/rtconfig.py b/bsp/qemu-vexpress-a9/rtconfig.py index edd1b6aab7f..54f031029e8 100644 --- a/bsp/qemu-vexpress-a9/rtconfig.py +++ b/bsp/qemu-vexpress-a9/rtconfig.py @@ -35,6 +35,7 @@ def get_mac_address(): # only support GNU GCC compiler. PLATFORM = 'gcc' +LIBC = 'picolibc' EXEC_PATH = r'/usr/bin' if os.getenv('RTT_EXEC_PATH'): From 87271c8a14a3643d0ca443e045ff99f575b48ff4 Mon Sep 17 00:00:00 2001 From: Keith Packard Date: Fri, 1 Apr 2022 18:50:09 -0700 Subject: [PATCH 8/8] [bsp] Switch qemu-vexpress-gemini sample to picolibc Before: text data bss dec hex filename 165330 2256 14256 181842 2c652 rtthread-vexpress.elf After: text data bss dec hex filename 156747 1200 14128 172075 2a02b rtthread-vexpress.elf Signed-off-by: Keith Packard --- bsp/qemu-vexpress-gemini/.config | 6 +++++- bsp/qemu-vexpress-gemini/rtconfig.h | 4 ++++ bsp/qemu-vexpress-gemini/rtconfig.py | 1 + bsp/qemu-vexpress-gemini/vexpress.lds | 17 +++++++++++++++++ 4 files changed, 27 insertions(+), 1 deletion(-) diff --git a/bsp/qemu-vexpress-gemini/.config b/bsp/qemu-vexpress-gemini/.config index b61e1e3f0af..614198047d6 100644 --- a/bsp/qemu-vexpress-gemini/.config +++ b/bsp/qemu-vexpress-gemini/.config @@ -26,10 +26,14 @@ CONFIG_IDLE_THREAD_STACK_SIZE=512 # # kservice optimization # -# CONFIG_RT_KSERVICE_USING_STDLIB is not set +CONFIG_RT_KSERVICE_USING_STDLIB=y +CONFIG_RT_KSERVICE_USING_STDLIB_MEMCPY=y +CONFIG_RT_KSERVICE_USING_STDLIB_MEMSET=y # CONFIG_RT_KSERVICE_USING_TINY_SIZE is not set # CONFIG_RT_USING_TINY_FFS is not set +CONFIG_RT_KSERVICE_USING_PRINTF=y # CONFIG_RT_PRINTF_LONGLONG is not set +# CONFIG_RT_PRINTF_FLOAT is not set CONFIG_RT_DEBUG=y CONFIG_RT_DEBUG_COLOR=y # CONFIG_RT_DEBUG_INIT_CONFIG is not set diff --git a/bsp/qemu-vexpress-gemini/rtconfig.h b/bsp/qemu-vexpress-gemini/rtconfig.h index 9150ac56fd1..c22e38c7bd2 100644 --- a/bsp/qemu-vexpress-gemini/rtconfig.h +++ b/bsp/qemu-vexpress-gemini/rtconfig.h @@ -20,6 +20,10 @@ /* kservice optimization */ +#define RT_KSERVICE_USING_STDLIB +#define RT_KSERVICE_USING_STDLIB_MEMCPY +#define RT_KSERVICE_USING_STDLIB_MEMSET +#define RT_KSERVICE_USING_PRINTF #define RT_DEBUG #define RT_DEBUG_COLOR diff --git a/bsp/qemu-vexpress-gemini/rtconfig.py b/bsp/qemu-vexpress-gemini/rtconfig.py index a7d31ae73e9..7935fa18e1b 100644 --- a/bsp/qemu-vexpress-gemini/rtconfig.py +++ b/bsp/qemu-vexpress-gemini/rtconfig.py @@ -4,6 +4,7 @@ ARCH='arm' CPU='vexpress-a9' CROSS_TOOL='gcc' +LIBC='picolibc' if os.getenv('RTT_CC'): CROSS_TOOL = os.getenv('RTT_CC') diff --git a/bsp/qemu-vexpress-gemini/vexpress.lds b/bsp/qemu-vexpress-gemini/vexpress.lds index 2e631aa4ae4..d424f667ffe 100644 --- a/bsp/qemu-vexpress-gemini/vexpress.lds +++ b/bsp/qemu-vexpress-gemini/vexpress.lds @@ -36,6 +36,23 @@ SECTIONS } =0 __text_end = .; + . = ALIGN(8); + .tdata : { + *(.tdata) + *(.tdata.*) + *(.gnu.linkonce.td.*) + } + + .tbss (NOLOAD) : { + *(.tbss .tbss.* .gnu.linkonce.tb.*) + *(.tcommon) + } + + __tdata_source = ADDR(.tdata); + __tdata_size = SIZEOF(.tdata); + __tbss_size = SIZEOF(.tbss); + __tls_size = SIZEOF(.tdata) + SIZEOF(.tbss); + __rodata_start = .; .rodata : { *(.rodata) *(.rodata.*) } __rodata_end = .;