aboutsummaryrefslogtreecommitdiff
path: root/sim/rx/syscalls.c
diff options
context:
space:
mode:
Diffstat (limited to 'sim/rx/syscalls.c')
-rw-r--r--sim/rx/syscalls.c306
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 ();
+}