/* * Copyright (C) 2015 Kaspar Schleiser * 2014 Freie Universität Berlin * * 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 implementations * * @author Michael Baar * @author Stefan Pfeiffer * @author Hauke Petersen * @author Kaspar Schleiser * * @} */ #include #include #include #include #include #include #include #include #include #include "cpu.h" #include "board.h" #include "sched.h" #include "thread.h" #include "reboot.h" #include "irq.h" #include "log.h" #include "uart_stdio.h" #ifdef MODULE_XTIMER #include #include "div.h" #include "xtimer.h" #endif /** * @brief manage the heap */ extern char _sheap; /* start of the heap */ extern char _eheap; /* end of the heap */ char *heap_top = &_sheap + 4; /** * @brief Initialize NewLib, called by __libc_init_array() from the startup script */ void _init(void) { uart_stdio_init(); } /** * @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) { LOG_INFO("#! exit %i: resetting\n", n); reboot(); while(1); } /** * @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 TODO * @param pid TODO * @param sig TODO * * @return TODO */ __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 * * @param r TODO * @param name TODO * @param mode TODO * * @return TODO */ int _open_r(struct _reent *r, const char *name, int flags, int mode) { (void) name; (void) flags; (void) mode; r->_errno = ENODEV; /* not implemented yet */ return -1; } /** * @brief Read from a file * * All input is read from UART_0. The function will block until a byte is actually read. * * Note: the read function does not buffer - data will be lost if the function is not * called fast enough. * * TODO: implement more sophisticated read call. * * @param r TODO * @param fd TODO * @param buffer TODO * @param int TODO * * @return TODO */ _ssize_t _read_r(struct _reent *r, int fd, void *buffer, size_t count) { (void)r; (void)fd; return uart_stdio_read(buffer, count); } /** * @brief Write characters to a file * * All output is currently directed to UART_0, independent of the given file descriptor. * The write call will further block until the byte is actually written to the UART. * * TODO: implement more sophisticated write call. * * @param r TODO * @param fd TODO * @param data TODO * @param int TODO * * @return TODO */ _ssize_t _write_r(struct _reent *r, int fd, const void *data, size_t count) { (void) r; (void) fd; return uart_stdio_write(data, count); } /** * @brief Close a file * * @param r TODO * @param fd TODO * * @return TODO */ int _close_r(struct _reent *r, int fd) { (void) fd; r->_errno = ENODEV; /* not implemented yet */ return -1; } /** * @brief Set position in a file * * @param r TODO * @param fd TODO * @param pos TODO * @param dir TODO * * @return TODO */ _off_t _lseek_r(struct _reent *r, int fd, _off_t pos, int dir) { (void) fd; (void) pos; (void) dir; r->_errno = ENODEV; /* not implemented yet */ return -1; } /** * @brief Status of an open file * * @param r TODO * @param fd TODO * @param stat TODO * * @return TODO */ int _fstat_r(struct _reent *r, int fd, struct stat *st) { (void) fd; (void) st; r->_errno = ENODEV; /* not implemented yet */ return -1; } /** * @brief Status of a file (by name) * * @param r TODO * @param name TODO * @param stat TODO * * @return TODO */ int _stat_r(struct _reent *r, const char *name, struct stat *st) { (void) name; (void) st; r->_errno = ENODEV; /* not implemented yet */ return -1; } /** * @brief Query whether output stream is a terminal * * @param r TODO * @param fd TODO * * @return TODO */ 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 Remove a file's directory entry * * @param r TODO * @param path TODO * * @return TODO */ int _unlink_r(struct _reent *r, const char *path) { (void) path; r->_errno = ENODEV; /* not implemented yet */ return -1; } /** * @brief Send a signal to a thread * * @param[in] pid the pid to send to * @param[in] sig the signal to send * * @return TODO */ __attribute__ ((weak)) int _kill(pid_t pid, int sig) { (void) pid; (void) sig; errno = ESRCH; /* not implemented yet */ return -1; } #ifdef MODULE_XTIMER int _gettimeofday_r(struct _reent *r, struct timeval *restrict tp, void *restrict tzp) { (void)tzp; (void) r; uint64_t now = xtimer_now_usec64(); tp->tv_sec = div_u64_by_1000000(now); tp->tv_usec = now - (tp->tv_sec * SEC_IN_USEC); return 0; } #endif