diff options
Diffstat (limited to 'libgloss/visium/syscalls.c')
-rw-r--r-- | libgloss/visium/syscalls.c | 341 |
1 files changed, 341 insertions, 0 deletions
diff --git a/libgloss/visium/syscalls.c b/libgloss/visium/syscalls.c new file mode 100644 index 000000000..de0ec16fb --- /dev/null +++ b/libgloss/visium/syscalls.c @@ -0,0 +1,341 @@ +/* system calls for the Visium processor. + + Copyright (c) 2015 Rolls-Royce Controls and Data Services Limited. + 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 Rolls-Royce Controls and Data Services Limited 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 THE COPYRIGHT HOLDERS AND CONTRIBUTORS "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 THE COPYRIGHT OWNER OR CONTRIBUTORS 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 <sys/types.h> +#include <sys/stat.h> +#include <sys/time.h> +#include <fcntl.h> +#include <unistd.h> +#include <errno.h> +#include <stdarg.h> +#include <string.h> +#include "io.h" +#include "syscall.h" + +#ifdef TARGET_SIM +struct file_register2 +{ + unsigned action; + unsigned p1, p2, p3, p4; + unsigned error; + unsigned retval; +}; + +extern struct file_register2 _sim_fileio_register; + +static volatile struct file_register2 *const fileio = &_sim_fileio_register; + +static int +do_syscall (unsigned action, unsigned p1, unsigned p2, + unsigned p3, unsigned p4, int *error) +{ + fileio->p1 = p1; + fileio->p2 = p2; + fileio->p3 = p3; + fileio->p4 = p4; + fileio->action = action; + + *error = (int) fileio->error; + return (int) fileio->retval; +} +#else +static int +do_syscall (unsigned action, unsigned p1, unsigned p2, + unsigned p3, unsigned p4, int *error) +{ + int ret; + int err; + + /* There is a two instruction delay after the software interrupt is + initiated, to allow it to take effect. */ + + asm volatile ("\n\ + move.l r1,%3\n\ + move.l r2,%4\n\ + move.l r3,%5\n\ + moviu r5,%%u 0x20002208\n\ + movil r5,%%l 0x20002208\n\ + move.l r4,%6\n\ + write.l (r5),%2\n\ + nop\n\ + nop\n\ + move.l %0,r1\n\ + move.l %1,r2" + : "=r" (ret), "=r" (err) + : "r" (action), "r" (p1), "r" (p2), "r" (p3), "r" (p4) + : "r1", "r2", "r3", "r4", "r5"); + + *error = err; + return ret; +} +#endif + +int +close (int fildes) +{ + int status; + int error; + + status = do_syscall (SYS_close, fildes, 0, 0, 0, &error); + + if (status < 0) + errno = __hosted_from_gdb_errno (error); + + return status; +} + +void _exit (int) __attribute ((__noreturn__)); + +void +_exit (int code) +{ +#ifdef TARGET_SIM + asm volatile ("stop 0,%0" : : "r" (code & 0xff)); +#else + int error; + do_syscall (SYS_exit, code, 0, 0, 0, &error); +#endif + + /* Should never reach this point. Since this function is not supposed to + return, pretend to get stuck in a loop. */ + while (1) + ; +} + +#ifdef TARGET_SIM +extern long long _sim_cmdline_header; + +long long +_get_cmdline (void) +{ + return _sim_cmdline_header; +} +#endif + +int +fstat (int fildes, struct stat *st) +{ + struct gdb_stat gst; + int status; + int error; + + status = do_syscall (SYS_fstat, fildes, (unsigned) &gst, 0, 0, &error); + + if (status < 0) + errno = __hosted_from_gdb_errno (error); + else + __hosted_from_gdb_stat (&gst, st); + + return status; +} + +int +gettimeofday (struct timeval *__p, void *__tz) +{ + struct timeval *tv = __p; + struct timezone *tz = __tz; + struct gdb_timeval gtv; + int status; + int error; + + status = do_syscall (SYS_gettimeofday, (unsigned) >v, 0, 0, 0, &error); + + /* The timezone argument is not really supported so: + Local time is GMT, no daylight saving */ + if (tz) + { + tz->tz_minuteswest = 0; + tz->tz_dsttime = 0; + } + + if (status < 0) + errno = __hosted_from_gdb_errno (error); + else + __hosted_from_gdb_timeval (>v, tv); + + return status; +} + +int +isatty (int fildes) +{ + int status; + int error; + + status = do_syscall (SYS_isatty, fildes, 0, 0, 0, &error); + + if (status == 0) + errno = __hosted_from_gdb_errno (error); + + return status; +} + +off_t +lseek (int fildes, off_t offset, int whence) +{ + off_t ret; + int error; + + ret = do_syscall (SYS_lseek, fildes, offset, + __hosted_to_gdb_lseek_flags (whence), 0, &error); + + if (ret == (off_t)-1) + errno = __hosted_from_gdb_errno (error); + + return ret; +} + +int +open (const char *path, int oflag, ...) +{ + mode_t mode = 0; + int status; + int error; + int len = strlen (path) + 1; + + if (oflag & O_CREAT) + { + va_list ap; + va_start (ap, oflag); + mode = va_arg (ap, mode_t); + va_end (ap); + } + + status = do_syscall (SYS_open, (unsigned) path, len, + __hosted_to_gdb_open_flags (oflag), + __hosted_to_gdb_mode_t (mode), &error); + + if (status < 0) + errno = __hosted_from_gdb_errno (error); + + return status; +} + +int +read (int fildes, void *buf, size_t nbyte) +{ + int status; + int error; + + status = do_syscall (SYS_read, fildes, (unsigned) buf, nbyte, 0, &error); + + if (status < 0) + errno = __hosted_from_gdb_errno (error); + + return status; +} + +int +rename (const char *old, const char *new) +{ + int status; + int error; + int oldlen = strlen (old) + 1; + int newlen = strlen (new) + 1; + + status = do_syscall (SYS_rename, (unsigned) old, oldlen, (unsigned) new, + newlen, &error); + + if (status < 0) + errno = __hosted_from_gdb_errno (error); + + return status; +} + +int +stat (const char *path, struct stat *st) +{ + struct gdb_stat gst; + int status; + int error; + int len = strlen (path) + 1; + + status = do_syscall (SYS_stat, (unsigned) path, len, (unsigned) &gst, 0, + &error); + + if (status < 0) + errno = __hosted_from_gdb_errno (error); + else + __hosted_from_gdb_stat (&gst, st); + + return status; +} + +int +system (const char *string) +{ + int status; + int error; + int len = strlen (string) + 1; + + status = do_syscall (SYS_system, (unsigned) string, len, 0, 0, &error); + + return status; +} + +int +unlink (const char *path) +{ + int status; + int error; + int len = strlen (path) + 1; + + status = do_syscall (SYS_unlink, (unsigned) path, len, 0, 0, &error); + + if (status < 0) + errno = __hosted_from_gdb_errno (error); + + return status; +} + +int +write (int fildes, const void *buf, size_t nbyte) +{ + int status; + int error; + + status = do_syscall (SYS_write, fildes, (unsigned) buf, nbyte, 0, &error); + + if (status < 0) + errno = __hosted_from_gdb_errno (error); + + return status; +} + +extern clock_t _sim_clock; + +clock_t +clock (void) +{ +#ifdef TARGET_SIM + return _sim_clock; +#else + return (clock_t) -1; +#endif +} |