diff options
Diffstat (limited to 'libgloss/tic6x/syscalls.c')
-rw-r--r-- | libgloss/tic6x/syscalls.c | 361 |
1 files changed, 361 insertions, 0 deletions
diff --git a/libgloss/tic6x/syscalls.c b/libgloss/tic6x/syscalls.c new file mode 100644 index 000000000..dc0633ba6 --- /dev/null +++ b/libgloss/tic6x/syscalls.c @@ -0,0 +1,361 @@ +/* Copyright (c) 2010 CodeSourcery, Inc. + All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are met: + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + * Neither the name of CodeSourcery nor the + names of its contributors may be used to endorse or promote products + derived from this software without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY CODESOURCERY, INC. ``AS IS'' AND ANY + EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL CODESOURCERY BE LIABLE + FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT + OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR + BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE + USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH + DAMAGE. */ + +#include <stdio.h> +#include <string.h> +#include <time.h> +#include <sys/time.h> +#include <sys/stat.h> +#include <errno.h> + +#define _DTOPEN 0xf0 +#define _DTCLOSE 0xf1 +#define _DTREAD 0xf2 +#define _DTWRITE 0xf3 +#define _DTLSEEK 0xf4 +#define _DTUNLINK 0xf5 +#define _DTGETENV 0xf6 +#define _DTRENAME 0xf7 +#define _DTGETTIME 0xf8 +#define _DTGETCLK 0xf9 +#define _DTSYNC 0xff + +#define CIOBUFSIZ (BUFSIZ + 32) + +struct __attribute__((packed)) cio_open_to_host +{ + /* Suggested file descriptor (little endian). */ + short fd; + /* Flags (little endian). */ + short flags; +}; + +struct __attribute__((packed)) cio_open_from_host +{ + /* File descriptor (little endian). */ + short fd; +}; + +struct __attribute__((packed)) cio_close_to_host +{ + /* File descriptor (little endian). */ + short fd; +}; + +struct __attribute__((packed)) cio_close_from_host +{ + /* Result (little endian). */ + short result; +}; + +struct __attribute__((packed)) cio_read_to_host +{ + /* File descriptor (little endian). */ + short fd; + /* Length (little endian). */ + short length; +}; + +struct __attribute__((packed)) cio_read_from_host +{ + /* Result (little endian). */ + short result; +}; + +struct __attribute__((packed)) cio_write_to_host +{ + /* File descriptor (little endian). */ + short fd; + /* Length (little endian). */ + short length; +}; + +struct __attribute__((packed)) cio_write_from_host +{ + /* Result (little endian). */ + short result; +}; + +struct __attribute__((packed)) cio_lseek_to_host +{ + /* File descriptor (little endian). */ + short fd; + /* Offset (little endian). */ + int offset; + /* Whence (little endian). */ + short whence; +}; + +struct __attribute__((packed)) cio_lseek_from_host +{ + /* Result (little endian). */ + int result; +}; + +struct __attribute__((packed)) cio_unlink_to_host +{ + /* Empty. */ +}; + +struct __attribute__((packed)) cio_unlink_from_host +{ + /* Result (little endian). */ + short result; +}; + +struct __attribute__((packed)) cio_rename_to_host +{ + /* Empty. */ +}; + +struct __attribute__((packed)) cio_rename_from_host +{ + /* Result (little endian). */ + short result; +}; + +struct __attribute__((packed)) cio_gettime_to_host +{ + /* Empty. */ +}; + +struct __attribute__((packed)) cio_gettime_from_host +{ + /* Time (little endian). */ + int time; +}; + +struct __attribute__((packed)) cio_to_host +{ + /* Data length (target endian). */ + unsigned int length; + /* Command. */ + unsigned char command; + /* Parameters. */ + union + { + unsigned char buf[8]; + struct cio_open_to_host open; + struct cio_close_to_host close; + struct cio_read_to_host read; + struct cio_write_to_host write; + struct cio_lseek_to_host lseek; + struct cio_unlink_to_host unlink; + struct cio_rename_to_host rename; + struct cio_gettime_to_host gettime; + } parms; + /* Variable-length data. */ + unsigned char data[]; +}; + +struct __attribute__((packed)) cio_from_host +{ + /* Length (target endian). */ + unsigned int length; + /* Parameters. */ + union + { + unsigned char buf[8]; + struct cio_open_from_host open; + struct cio_close_from_host close; + struct cio_read_from_host read; + struct cio_write_from_host write; + struct cio_lseek_from_host lseek; + struct cio_unlink_from_host unlink; + struct cio_rename_from_host rename; + struct cio_gettime_from_host gettime; + } parms; + /* Data. */ + unsigned char data[]; +}; + +union +{ + unsigned char buf[CIOBUFSIZ]; + int align; + union + { + struct cio_to_host to_host; + struct cio_from_host from_host; + } u; +} _CIOBUF_ __attribute__((section(".cio"))); + +#ifdef _BIG_ENDIAN +#define SWAPSHORT(s) ((short)((((s) & 0xff) << 8) | (((s) & 0xff00) >> 8))) +#define SWAPINT(i) (__builtin_bswap32 (i)) +#else +#define SWAPSHORT(s) (s) +#define SWAPINT(i) (i) +#endif + +static void __attribute__((noinline)) +do_semi_call (void) +{ + asm volatile (".globl C$$IO$$\nnop\nC$$IO$$:nop" : "+m" (_CIOBUF_)); +} + +static inline void +semi_call_wrapper (unsigned char command, const char *data, + unsigned int length) +{ + _CIOBUF_.u.to_host.length = length; + _CIOBUF_.u.to_host.command = command; + if (data != NULL) + memcpy (_CIOBUF_.u.to_host.data, data, length); + do_semi_call (); +} + +static inline void +semi_call_wrapper2 (unsigned char command, const char *data1, + unsigned int length1, const char *data2, + unsigned int length2) +{ + _CIOBUF_.u.to_host.length = length1 + length2; + _CIOBUF_.u.to_host.command = command; + if (data1 != NULL) + memcpy (_CIOBUF_.u.to_host.data, data1, length1); + if (data2 != NULL) + memcpy (_CIOBUF_.u.to_host.data + length1, data2, length2); + do_semi_call (); +} + +void +_exit (int status) +{ + /* The semihosting interface appears to provide no way to return an + exit status. */ + asm volatile (".globl C$$EXIT\nnop\nC$$EXIT:nop"); +} + +int +open (const char *path, int flags, ...) +{ + /* ??? It's not clear what the suggested fd is for. */ + static short suggest_fd = 3; + short ret_fd; + ++suggest_fd; + _CIOBUF_.u.to_host.parms.open.fd = SWAPSHORT (suggest_fd); + _CIOBUF_.u.to_host.parms.open.flags = SWAPSHORT (flags); + semi_call_wrapper (_DTOPEN, path, strlen (path) + 1); + ret_fd = SWAPSHORT (_CIOBUF_.u.from_host.parms.open.fd); + if (ret_fd == -1) + return -1; + return suggest_fd; +} + +int +close (int fd) +{ + _CIOBUF_.u.to_host.parms.close.fd = SWAPSHORT (fd); + semi_call_wrapper (_DTCLOSE, NULL, 0); + return SWAPSHORT (_CIOBUF_.u.from_host.parms.close.result); +} + +int +read (int fd, char *ptr, int len) +{ + if (len > BUFSIZ) + len = BUFSIZ; + _CIOBUF_.u.to_host.parms.read.fd = SWAPSHORT (fd); + _CIOBUF_.u.to_host.parms.read.length = SWAPSHORT (len); + semi_call_wrapper (_DTREAD, NULL, 0); + memcpy (ptr, _CIOBUF_.u.from_host.data, _CIOBUF_.u.from_host.length); + return SWAPSHORT (_CIOBUF_.u.from_host.parms.read.result); +} + +int +write (int fd, char *ptr, int len) +{ + if (len > BUFSIZ) + len = BUFSIZ; + _CIOBUF_.u.to_host.parms.write.fd = SWAPSHORT (fd); + _CIOBUF_.u.to_host.parms.write.length = SWAPSHORT (len); + semi_call_wrapper (_DTWRITE, ptr, len); + return SWAPSHORT (_CIOBUF_.u.from_host.parms.write.result); +} + +int +lseek (int fd, int offset, int whence) +{ + _CIOBUF_.u.to_host.parms.lseek.fd = SWAPSHORT (fd); + _CIOBUF_.u.to_host.parms.lseek.offset = SWAPINT (offset); + _CIOBUF_.u.to_host.parms.lseek.whence = SWAPSHORT (whence); + semi_call_wrapper (_DTLSEEK, NULL, 0); + return SWAPINT (_CIOBUF_.u.from_host.parms.lseek.result); +} + +int +unlink (const char *path) +{ + semi_call_wrapper (_DTUNLINK, path, strlen (path) + 1); + return SWAPSHORT (_CIOBUF_.u.from_host.parms.unlink.result); +} + +int +rename (const char *oldpath, const char *newpath) +{ + semi_call_wrapper2 (_DTRENAME, oldpath, strlen (oldpath) + 1, + newpath, strlen (newpath) + 1); + return SWAPSHORT (_CIOBUF_.u.from_host.parms.rename.result); +} + +int +gettimeofday (struct timeval *tp, void *tzvp) +{ + struct timezone *tzp = tzvp; + + if (tp) + { + semi_call_wrapper (_DTGETTIME, NULL, 0); + tp->tv_sec = SWAPINT (_CIOBUF_.u.from_host.parms.gettime.time); + tp->tv_usec = 0; + } + + if (tzp) + { + tzp->tz_minuteswest = 0; + tzp->tz_dsttime = 0; + } + + return 0; +} + +int +isatty (int file __attribute__((unused))) +{ + errno = ENOSYS; + return 0; +} + +int +fstat (int fd, struct stat *buf) +{ + buf->st_mode = S_IFCHR; /* Always pretend to be a tty */ + buf->st_blksize = 0; + + return (0); +} |