342 lines
		
	
	
		
			7.1 KiB
		
	
	
	
		
			C
		
	
	
	
			
		
		
	
	
			342 lines
		
	
	
		
			7.1 KiB
		
	
	
	
		
			C
		
	
	
	
| /* 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
 | |
| }
 |