/* * Copyright (C) 2017 Imagination Technologies * * 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 * @{ * * @file * @brief Newlib system call implementation for use with the mips-mti-elf * toolchain newlib incorporating as semi-hosting interface called 'UHI' * * @author Neil Jones * * @} */ #include #include #include #include #include #include #include #include #include #include #include #include "cpu.h" #include "board.h" #include "sched.h" #include "thread.h" #include "irq.h" #include "log.h" #include "periph/pm.h" /** * * @brief manage the heap * */ extern char _sheap; /* start of the heap */ extern char _eheap; /* end of the heap */ char *heap_top = &_sheap + 4; /** * @brief Free resources on NewLib de-initialization, not used for RIOT */ /* __attribute__((used)) fixes linker errors when building with LTO, but without nano.specs */ __attribute__((used)) void _fini(void) { /* nothing to do here */ } /** * @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 _exit(int n) { exit(n); /* * Disable unreachableCode cppcheck as pm_off spins indefinately after * pulling the plug */ /* cppcheck-suppress unreachableCode */ pm_off(); } /** * @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; } /** * @brief Get the process-ID of the current thread * * @return the process ID of the current thread */ pid_t _getpid(void) { return sched_active_pid; } /** * @brief Get the process-ID of the current thread * * @return the process ID of the current thread */ pid_t _getpid_r(struct _reent *ptr) { (void) ptr; return sched_active_pid; } /** * @brief Send a signal to a given thread * * @param r pointer to reent structure * @param pid process ID to kill * @param sig signal number to pass to process * * @return -1 on error * @return 0 on sucess */ __attribute__ ((weak)) int _kill_r(struct _reent *r, pid_t pid, int sig) { (void) pid; (void) sig; r->_errno = ESRCH; /* not implemented yet */ return -1; } /** * @brief Open a file * * This is a wrapper around @c _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 */ int _open_r(struct _reent *r, const char *name, int flags, int mode) { return open(name, flags, mode); } /** * @brief Read bytes from an open file * * This is a wrapper around @c _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, */ _ssize_t _read_r(struct _reent *r, int fd, void *dest, size_t count) { return read(fd,dest,count); } /** * @brief Write bytes to an open file * * This is a wrapper around @c _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 */ _ssize_t _write_r(struct _reent *r, int fd, const void *src, size_t count) { int res = write(fd, src, count); return res; } /** * @brief Close an open file * * This is a wrapper around @c _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 */ int _close_r(struct _reent *r, int fd) { int res = close(fd); return res; } /** * @brief Query or set options on an open file * * This is a wrapper around @c _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 */ int _fcntl_r (struct _reent *r, int fd, int cmd, int arg) { int res = fcntl(fd, cmd, arg); return res; } /** * @brief Seek to position in file * * This is a wrapper around @c _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 */ _off_t _lseek_r(struct _reent *r, int fd, _off_t off, int whence) { int res = lseek(fd, off, whence); return res; } /** * @brief Get status of an open file * * This is a wrapper around @c _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 */ int _fstat_r(struct _reent *r, int fd, struct stat *buf) { int res = fstat(fd, buf); return res; } /* * @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 */ int _unlink_r(struct _reent *r, const char *path) { int res = unlink(path); return res; } /** * @brief Query whether output stream is a terminal * * @param r pointer to reent structure * @param fd descriptor of stream to query * * @return 0 for none tty * @return 1 for tty * */ int _isatty_r(struct _reent *r, int fd) { r->_errno = 0; if(fd == STDIN_FILENO || fd == STDOUT_FILENO || fd == STDERR_FILENO) { return 1; } return 0; } /** * @brief Send a signal to a thread * * @param[in] pid the pid to send to * @param[in] sig the signal to send * * @return 0 on success * @return -1 on error * */ __attribute__ ((weak)) int _kill(pid_t pid, int sig) { (void) pid; (void) sig; errno = ESRCH; /* not implemented yet */ return -1; }