Files

751 lines
13 KiB
C

/*
* Copyright (c) 2021-2022 Amlogic, Inc. All rights reserved.
*
* SPDX-License-Identifier: MIT
*/
#include <sys/stat.h>
#include <sys/time.h>
#include <stdio.h>
#include <errno.h>
#include <unistd.h>
#include <stdlib.h>
#include <string.h>
#include <math.h>
#if CONFIG_VFS
#include <sys_vfs.h>
#else
#include <stdarg.h>
#endif
#if defined(CONFIG_LOG_BUFFER)
#include "logbuffer.h"
#endif
#if defined(CONFIG_ARM64) || defined(CONFIG_ARM)
#include <serial.h>
#else
#include <uart.h>
#endif
#ifdef CONFIG_CHERRYUSB_DEVICE_ADB
#include "FreeRTOS_CLI_Console.h"
#endif
#include "common.h"
#include <FreeRTOS.h>
#include <task.h>
#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