diff options
Diffstat (limited to 'sim/rx/syscalls.c')
-rw-r--r-- | sim/rx/syscalls.c | 306 |
1 files changed, 306 insertions, 0 deletions
diff --git a/sim/rx/syscalls.c b/sim/rx/syscalls.c new file mode 100644 index 0000000..6a6c724 --- /dev/null +++ b/sim/rx/syscalls.c @@ -0,0 +1,306 @@ +/* syscalls.c --- implement system calls for the RX simulator. + +Copyright (C) 2005, 2007, 2008, 2009 Free Software Foundation, Inc. +Contributed by Red Hat, Inc. + +This file is part of the GNU simulators. + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 3 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program. If not, see <http://www.gnu.org/licenses/>. */ + + +#include <stdio.h> +#include <stdlib.h> +#include <fcntl.h> +#include <unistd.h> +#include <sys/time.h> + +#include "gdb/callback.h" + +#include "cpu.h" +#include "mem.h" +#include "syscalls.h" + +#include "syscall.h" + +/* The current syscall callbacks we're using. */ +static struct host_callback_struct *callbacks; + +void +set_callbacks (struct host_callback_struct *cb) +{ + callbacks = cb; +} + + +/* Arguments 1..4 are in R1..R4, remainder on stack. + + Return value in R1..R4 as needed. + structs bigger than 16 bytes: pointer pushed on stack last + + We only support arguments that fit in general registers. + + The system call number is in R5. We expect ssycalls to look like + this in libgloss: + + _exit: + mov #SYS_exit, r5 + int #255 + rts +*/ + +int argp, stackp; + +static int +arg () +{ + int rv = 0; + argp++; + + if (argp < 4) + return get_reg (argp); + + rv = mem_get_si (get_reg (sp) + stackp); + stackp += 4; + return rv; +} + +static void +read_target (char *buffer, int address, int count, int asciiz) +{ + char byte; + while (count > 0) + { + byte = mem_get_qi (address++); + *buffer++ = byte; + if (asciiz && (byte == 0)) + return; + count--; + } +} + +static void +write_target (char *buffer, int address, int count, int asciiz) +{ + char byte; + while (count > 0) + { + byte = *buffer++; + mem_put_qi (address++, byte); + if (asciiz && (byte == 0)) + return; + count--; + } +} + +#define PTRSZ (A16 ? 2 : 3) + +static char *callnames[] = { + "SYS_zero", + "SYS_exit", + "SYS_open", + "SYS_close", + "SYS_read", + "SYS_write", + "SYS_lseek", + "SYS_unlink", + "SYS_getpid", + "SYS_kill", + "SYS_fstat", + "SYS_sbrk", + "SYS_argvlen", + "SYS_argv", + "SYS_chdir", + "SYS_stat", + "SYS_chmod", + "SYS_utime", + "SYS_time", + "SYS_gettimeofday", + "SYS_times", + "SYS_link" +}; + +int +rx_syscall (int id) +{ + static char buf[256]; + int rv; + + argp = 0; + stackp = 4; + if (trace) + printf ("\033[31m/* SYSCALL(%d) = %s */\033[0m\n", id, id <= SYS_link ? callnames[id] : "unknown"); + switch (id) + { + case SYS_exit: + { + int ec = arg (); + if (verbose) + printf ("[exit %d]\n", ec); + return RX_MAKE_EXITED (ec); + } + break; + + case SYS_open: + { + int path = arg (); + /* The open function is defined as taking a variable number of arguments + because the third parameter to it is optional: + open (const char * filename, int flags, ...); + Hence the oflags and cflags arguments will be on the stack and we need + to skip the (empty) argument registers r3 and r4. */ + argp = 4; + int oflags = arg (); + int cflags = arg (); + + read_target (buf, path, 256, 1); + if (trace) + printf ("open(\"%s\",0x%x,%#o) = ", buf, oflags, cflags); + + if (callbacks) + /* The callback vector ignores CFLAGS. */ + rv = callbacks->open (callbacks, buf, oflags); + else + { + int h_oflags = 0; + + if (oflags & 0x0001) + h_oflags |= O_WRONLY; + if (oflags & 0x0002) + h_oflags |= O_RDWR; + if (oflags & 0x0200) + h_oflags |= O_CREAT; + if (oflags & 0x0008) + h_oflags |= O_APPEND; + if (oflags & 0x0400) + h_oflags |= O_TRUNC; + rv = open (buf, h_oflags, cflags); + } + if (trace) + printf ("%d\n", rv); + put_reg (1, rv); + } + break; + + case SYS_close: + { + int fd = arg (); + + if (callbacks) + rv = callbacks->close (callbacks, fd); + else if (fd > 2) + rv = close (fd); + else + rv = 0; + if (trace) + printf ("close(%d) = %d\n", fd, rv); + put_reg (1, rv); + } + break; + + case SYS_read: + { + int fd = arg (); + int addr = arg (); + int count = arg (); + + if (count > sizeof (buf)) + count = sizeof (buf); + if (callbacks) + rv = callbacks->read (callbacks, fd, buf, count); + else + rv = read (fd, buf, count); + if (trace) + printf ("read(%d,%d) = %d\n", fd, count, rv); + if (rv > 0) + write_target (buf, addr, rv, 0); + put_reg (1, rv); + } + break; + + case SYS_write: + { + int fd = arg (); + int addr = arg (); + int count = arg (); + + if (count > sizeof (buf)) + count = sizeof (buf); + if (trace) + printf ("write(%d,0x%x,%d)\n", fd, addr, count); + read_target (buf, addr, count, 0); + if (trace) + fflush (stdout); + if (callbacks) + rv = callbacks->write (callbacks, fd, buf, count); + else + rv = write (fd, buf, count); + if (trace) + printf ("write(%d,%d) = %d\n", fd, count, rv); + put_reg (1, rv); + } + break; + + case SYS_getpid: + put_reg (1, 42); + break; + + case SYS_gettimeofday: + { + int tvaddr = arg (); + struct timeval tv; + + rv = gettimeofday (&tv, 0); + if (trace) + printf ("gettimeofday: %ld sec %ld usec to 0x%x\n", tv.tv_sec, + tv.tv_usec, tvaddr); + mem_put_si (tvaddr, tv.tv_sec); + mem_put_si (tvaddr + 4, tv.tv_usec); + put_reg (1, rv); + } + break; + + case SYS_kill: + { + int pid = arg (); + int sig = arg (); + if (pid == 42) + { + if (verbose) + printf ("[signal %d]\n", sig); + return RX_MAKE_STOPPED (sig); + } + } + break; + + case 11: + { + int heaptop_arg = arg (); + if (trace) + printf ("sbrk: heap top set to %x\n", heaptop_arg); + heaptop = heaptop_arg; + if (heapbottom == 0) + heapbottom = heaptop_arg; + } + break; + + case 255: + { + int addr = arg (); + mem_put_si (addr, rx_cycles + mem_usage_cycles()); + } + break; + + } + return RX_MAKE_STEPPED (); +} |