/* * Copyright (c) 2021-2022 Amlogic, Inc. All rights reserved. * * SPDX-License-Identifier: MIT */ #include #include #include #include #include #include #include #include #if CONFIG_VFS #include #else #include #endif #if defined(CONFIG_LOG_BUFFER) #include "logbuffer.h" #endif #if defined(CONFIG_ARM64) || defined(CONFIG_ARM) #include #else #include #endif #ifdef CONFIG_CHERRYUSB_DEVICE_ADB #include "FreeRTOS_CLI_Console.h" #endif #include "common.h" #include #include #if !defined(_COMPILING_NEWLIB) && !defined(_LIBC) #define _COMPILING_NEWLIB #endif #define UNUSED(x) ((void)(x)) int _isatty(int); int _stat(const char *, struct stat *); int _fstat(int, struct stat *); int _close(int); int _open(const char *, int, ...); int _write(int, const void *, size_t); _off_t _lseek(int, _off_t, int); int _read(int, void *, size_t); #ifdef _REENT_SMALL_CHECK_INIT #define CHECK_INIT(ptr) _REENT_SMALL_CHECK_INIT(ptr) #else #define CHECK_INIT(ptr) ((void)(ptr)) #endif #define FILE_TYPE_MASK 0xFF #define FILE_TYPE_STDIO 0x00 #define FILE_TYPE_VFS 0x01 #define FILE_TYPE_SOCKET 0x02 #define FILE_VALID 0x80000000 struct poslog { int handle; unsigned int flg; }; /* Modified the MAX_OPEN_FILES from 512 to 8 inorder to reduce size */ #define MAX_OPEN_FILES 512 static struct poslog openfiles[MAX_OPEN_FILES]; static inline int _is_stdio(int fh) { if (fh == STDERR_FILENO || fh == STDOUT_FILENO || fh == STDIN_FILENO) return 1; return 0; } static inline unsigned int _file_type(int fh) { return (openfiles[fh].flg & FILE_TYPE_MASK); } static inline int remap_handle(int fh) { CHECK_INIT(_REENT); if (_is_stdio(fh)) return fh; if (fh < 0 || fh >= MAX_OPEN_FILES) return -1; if ((openfiles[fh].flg & FILE_VALID) == 0) return -1; return openfiles[fh].handle; } static inline int remap_handle_r(int fh, unsigned int type) { int i; if (_is_stdio(fh)) return fh; for (i = 0; i < MAX_OPEN_FILES; i++) { if (_is_stdio(i)) continue; if ((openfiles[i].flg & FILE_VALID) && _file_type(i) == type && (openfiles[i].handle == fh)) return i; } return -1; } static inline int alloc_file(unsigned int type) { int i = 0; for (i = 0; i < MAX_OPEN_FILES; i++) { if (_is_stdio(i)) continue; if ((openfiles[i].flg & FILE_VALID) == 0) { openfiles[i].flg = (FILE_VALID | (type & FILE_TYPE_MASK)); goto _exit_fun; } } i = -1; _exit_fun: return i; } static inline void free_file(int fh) { if (fh > 0 && fh < MAX_OPEN_FILES) { openfiles[fh].flg = 0; openfiles[fh].handle = 0; } } int _fstat(int file, struct stat *st) { int myhan = remap_handle(file); if (myhan < 0) { errno = EBADF; return -1; } memset(st, 0, sizeof(*st)); if (_isatty(file)) { st->st_mode = S_IFCHR; if (file == STDIN_FILENO) st->st_mode |= S_IRUSR; else st->st_mode |= S_IWUSR; st->st_blksize = 1024; return 0; } #if CONFIG_VFS if (_file_type(file) == FILE_TYPE_VFS) return vfs_fstat(myhan, st); #endif return -1; } int _stat(const char *fname, struct stat *st) { #if CONFIG_VFS return vfs_stat(fname, st); #else UNUSED(fname); UNUSED(st); return -1; #endif } off_t _lseek(int file, off_t ptr, int dir) { int myhan = remap_handle(file); UNUSED(ptr); UNUSED(dir); if (myhan < 0) { errno = EBADF; return -1; } if (_isatty(file)) { return 0; } #if CONFIG_VFS if (_file_type(file) == FILE_TYPE_VFS) return vfs_lseek(myhan, ptr, dir); #endif return -1; } int _isatty(int fd) { return _is_stdio(fd); } int _read(int file, void *ptr, size_t len) { int myhan = remap_handle(file); UNUSED(ptr); UNUSED(len); if (myhan < 0) { errno = EBADF; return -1; } if (file == STDERR_FILENO || file == STDOUT_FILENO) { errno = EBADF; return -1; } if (file == STDIN_FILENO) { errno = EBADF; return -1; } #if CONFIG_VFS if (_file_type(file) == FILE_TYPE_VFS) return vfs_read(myhan, ptr, len); #endif #if ENABLE_MODULE_LWIP if (_file_type(file) == FILE_TYPE_SOCKET) return lwip_read(myhan, ptr, len); #endif return -1; } int _open(const char *path, int flags, ...) { int _fhandle = -1; int i = alloc_file(FILE_TYPE_VFS); va_list args; UNUSED(path); UNUSED(flags); if (i < 0) { errno = ENFILE; return -1; } va_start(args, flags); #if CONFIG_VFS _fhandle = vfs_open(path, flags, va_arg(args, int)); #endif va_end(args); if (_fhandle < 0) { free_file(i); return -1; } openfiles[i].handle = _fhandle; return i; } int _write(int file, const void *ptr, size_t len) { int myhan = remap_handle(file); signed char *pxNext = NULL; size_t i = 0; #ifdef CONFIG_CHERRYUSB_DEVICE_ADB signed char tmp = '\r'; #endif #ifdef CONFIG_CHERRYUSB_DEVICE_ADB xConsoleIO_t *ConsoleIO; ConsoleIO = getConsoleIO(getCLIUartConsoleId()); #endif if (myhan < 0) { errno = EBADF; return -1; } if (file == STDIN_FILENO) { errno = EBADF; return -1; } if (file == STDERR_FILENO || file == STDOUT_FILENO) { #if CONFIG_LOG_BUFFER if (logbuf_is_enable()) { return logbuf_output_len(ptr, len); } #endif /* Send each character in the string, one at a time. */ pxNext = (signed char *)ptr; while (i < len && *pxNext) { #if defined(CONFIG_ARM64) || defined(CONFIG_ARM) if (*pxNext == '\n') { #ifdef CONFIG_CHERRYUSB_DEVICE_ADB if (ConsoleIO) ConsoleIO->write((const char * const)&tmp, 1); else #endif vSerialPutChar(ConsoleSerial, '\r'); } #ifdef CONFIG_CHERRYUSB_DEVICE_ADB if (ConsoleIO) ConsoleIO->write((const char * const)pxNext, 1); else #endif vSerialPutChar(ConsoleSerial, *pxNext); #else if (*pxNext == '\n') vUartPutc('\r'); vUartPutc(*pxNext); #endif pxNext++; i++; } return i; } #if CONFIG_VFS if (_file_type(file) == FILE_TYPE_VFS) return vfs_write(myhan, ptr, len); #endif #if ENABLE_MODULE_LWIP if (_file_type(file) == FILE_TYPE_SOCKET) return lwip_write(myhan, ptr, len); #endif return -1; } int _close(int file) { int myhan = remap_handle(file); if (myhan < 0) return 0; if (_isatty(file)) { return 0; } #if CONFIG_VFS if (_file_type(file) == FILE_TYPE_VFS) vfs_close(myhan); #endif #if ENABLE_MODULE_LWIP if (_file_type(file) == FILE_TYPE_SOCKET) lwip_close(myhan); #endif free_file(file); return 0; } #if defined(_COMPILING_NEWLIB) || defined(_LIBC) #define SECOND_TO_MICROSEC (1000000ULL) #define MILISEC_TO_MICROSEC (1000UL) static struct timeval real_tv = {.tv_sec = 0, .tv_usec = 0}; static struct timezone real_tz = {.tz_dsttime = DST_NONE, .tz_minuteswest = 0}; static inline int _settimeofday_imp(const struct timeval *tv, const struct timezone *tz) { uint64_t ullTickCount = 0ULL; uint64_t ullMicroseconds = 0ULL; TimeOut_t xCurrentTime = { 0 }; uint32_t shift_bit = 0; if ((NULL == tv) && (NULL == tz)) return -1; if (NULL != tv) { vTaskSetTimeOutState(&xCurrentTime); if ( sizeof( TickType_t ) < 8 ) shift_bit = sizeof( TickType_t ) * 8; ullTickCount = ( uint64_t ) ( xCurrentTime.xOverflowCount ) << shift_bit; ullTickCount += xCurrentTime.xTimeOnEntering; ullMicroseconds = (tv->tv_sec * SECOND_TO_MICROSEC + tv->tv_usec) - pdTICKS_TO_MS(ullTickCount) * MILISEC_TO_MICROSEC; real_tv.tv_sec = ullMicroseconds / SECOND_TO_MICROSEC; real_tv.tv_usec = ullMicroseconds % SECOND_TO_MICROSEC; } if (NULL != tz) { real_tz.tz_dsttime = tz->tz_dsttime; real_tz.tz_minuteswest = tz->tz_minuteswest; } return 0; } static inline int _gettimeofday_imp(struct timeval *tv, struct timezone *tz) { TimeOut_t xCurrentTime = { 0 }; uint64_t ullTickCount = 0ULL; uint64_t ullMicroseconds = 0ULL; uint32_t shift_bit = 0; if (0 == configTICK_RATE_HZ) return -1; if ((NULL == tv) && (NULL == tz)) return -1; if (NULL != tv) { vTaskSetTimeOutState( &xCurrentTime ); if ( sizeof( TickType_t ) < 8 ) shift_bit = sizeof( TickType_t ) * 8; ullTickCount = ( uint64_t ) ( xCurrentTime.xOverflowCount ) << shift_bit; ullTickCount += xCurrentTime.xTimeOnEntering; ullMicroseconds = (real_tv.tv_sec * SECOND_TO_MICROSEC + real_tv.tv_usec) + pdTICKS_TO_MS(ullTickCount) * MILISEC_TO_MICROSEC; tv->tv_sec = ullMicroseconds / SECOND_TO_MICROSEC; tv->tv_usec = ullMicroseconds % SECOND_TO_MICROSEC; } if (NULL != tz) { tz->tz_dsttime = real_tz.tz_dsttime; tz->tz_minuteswest = real_tz.tz_minuteswest; } return 0; } #endif #ifdef _COMPILING_NEWLIB int settimeofday(const struct timeval *tv, const struct timezone *tz) { return _settimeofday_imp(tv, tz); } int _settimeofday(const struct timeval *tv, const struct timezone *tz) { return _settimeofday_imp(tv, tz); } int _gettimeofday(struct timeval *tv, struct timezone *tz) { return _gettimeofday_imp(tv, tz); } #endif #ifdef _LIBC int settimeofday(const struct timeval *tv, const struct void *tz) { return _settimeofday_imp(tv, (const struct timezone *)tz); } int _settimeofday(const struct timeval *tv, const struct void *tz) { return _settimeofday_imp(tv, (const struct timezone *)tz); } int _gettimeofday(struct timeval *tv, void *tz) { return _gettimeofday_imp(tv, (struct timezone *)tz); } #endif int fcntl(int fd, int cmd, ...) { int ret = -1; int myhan = remap_handle(fd); va_list args; if (myhan < 0) { errno = EBADF; return -1; } if (_isatty(fd)) { errno = EBADF; return -1; } va_start(args, cmd); #if CONFIG_VFS if (_file_type(fd) == FILE_TYPE_VFS) ret = vfs_vfcntl(myhan, cmd, args); #endif #if ENABLE_MODULE_LWIP if (_file_type(fd) == FILE_TYPE_SOCKET) ret = lwip_fcntl(myhan, cmd, va_arg(args, int)); #endif va_end(args); return ret; } int ioctl(int fd, int cmd, ...) { int ret = -1; int myhan = remap_handle(fd); va_list args; if (myhan < 0) { errno = EBADF; return -1; } if (_isatty(fd)) { errno = EBADF; return -1; } va_start(args, cmd); #if CONFIG_VFS if (_file_type(fd) == FILE_TYPE_VFS) ret = vfs_vioctl(myhan, cmd, args); #endif #if ENABLE_MODULE_LWIP if (_file_type(fd) == FILE_TYPE_SOCKET) ret = lwip_ioctl(myhan, cmd, va_arg(args, void *)); #endif va_end(args); return ret; } int fsync(int fd) { int ret = -1; int myhan = remap_handle(fd); if (myhan < 0) { errno = EBADF; return -1; } if (_isatty(fd)) return 0; #if CONFIG_VFS if (_file_type(fd) == FILE_TYPE_VFS) ret = vfs_fsync(myhan); #endif return ret; } #if CONFIG_VFS int statfs(const char *path, struct statfs *buf) { return vfs_statfs(path, buf); } #endif pid_t _getpid(void) { return (pid_t)1; } pid_t __wrap__getpid_r(void) { return (pid_t)1; } int _kill(pid_t pid, int sig) { UNUSED(pid); UNUSED(sig); errno = ENOTSUP; return -1; } int __wrap__kill_r(int pid, int sig) { UNUSED(pid); UNUSED(sig); errno = ENOTSUP; return -1; } #if CONFIG_LIBC_STD_MEMALIGN static inline void *memalign(size_t alignment, size_t size) { uintptr_t start_addr; uintptr_t aligned_addr; size_t total_size; void *real_ptr; total_size = size + alignment - 1 + sizeof(void *); real_ptr = pvPortMalloc(total_size); if (!real_ptr) { errno = ENOMEM; return NULL; } start_addr = (uintptr_t)real_ptr + sizeof(void *); aligned_addr = (start_addr + alignment - 1) & ~(alignment - 1); void *aligned_ptr = (void *)aligned_addr; ((void **)aligned_ptr)[-1] = real_ptr; return aligned_ptr; } void *__wrap_memalign(size_t alignment, size_t size) { return memalign(alignment, size); } void *__wrap__memalign_r(struct _reent *reent, size_t alignment, size_t size) { UNUSED(reent); return memalign(alignment, size); } #endif void *__wrap_malloc(size_t size) { return pvPortMalloc(size); } void *__wrap__malloc_r(struct _reent *reent, size_t size) { UNUSED(reent); return pvPortMalloc(size); } void *__wrap_calloc(size_t nmemb, size_t size) { size_t total = nmemb * size; void *p; if (total <= 0) return NULL; p = pvPortMalloc(total); if (!p) return NULL; return memset(p, 0, total); } void *__wrap__calloc_r(struct _reent *reent, size_t nmemb, size_t size) { size_t total = nmemb * size; void *p; UNUSED(reent); if (!total) return NULL; p = pvPortMalloc(total); if (!p) return NULL; return memset(p, 0, total); } void *__wrap_realloc(void *ptr, size_t size) { return pvPortRealloc(ptr, size); } void *__wrap__realloc_r(struct _reent *reent, void *ptr, size_t size) { UNUSED(reent); return pvPortRealloc(ptr, size); } void __wrap_free(void *ptr) { #if CONFIG_LIBC_STD_MEMALIGN extern uint32_t is_memalign_ptr(void *ptr); if (is_memalign_ptr(ptr)) vPortFree(((void **)ptr)[-1]); else vPortFree(ptr); #else vPortFree(ptr); #endif } void __wrap__free_r(struct _reent *reent, void *ptr) { UNUSED(reent); #if CONFIG_LIBC_STD_MEMALIGN extern uint32_t is_memalign_ptr(void *ptr); if (is_memalign_ptr(ptr)) vPortFree(((void **)ptr)[-1]); else vPortFree(ptr); #else vPortFree(ptr); #endif } int _link(const char *oldpath, const char *newpath) { #if CONFIG_VFS return vfs_link(oldpath, newpath); #else UNUSED_PARAM(oldpath); UNUSED_PARAM(newpath); errno = ENOENT; return -1; #endif } int _unlink(const char *__path) { #if CONFIG_VFS return vfs_remove(__path); #else UNUSED_PARAM(__path); errno = ENOENT; return -1; #endif } void _exit(int status) { UNUSED_PARAM(status); /* infinity loop for exit syscall */ while (1) ; } #if CONFIG_BACKTRACE_UT void __wrap___aeabi_unwind_cpp_pr0(void) { /* C++ exception and backtrace not supported */ } void __wrap___aeabi_unwind_cpp_pr1(void) { /* C++ exception and backtrace not supported */ } void __wrap___aeabi_unwind_cpp_pr2(void) { /* C++ exception and backtrace not supported */ } #endif