xref: /netbsd-src/external/gpl3/gdb/dist/sim/rx/syscalls.c (revision 1f4e7eb9e5e045e008f1894823a8e4e6c9f46890)
14e98e3e1Schristos /* syscalls.c --- implement system calls for the RX simulator.
24e98e3e1Schristos 
3*1f4e7eb9Schristos Copyright (C) 2005-2024 Free Software Foundation, Inc.
44e98e3e1Schristos Contributed by Red Hat, Inc.
54e98e3e1Schristos 
64e98e3e1Schristos This file is part of the GNU simulators.
74e98e3e1Schristos 
84e98e3e1Schristos This program is free software; you can redistribute it and/or modify
94e98e3e1Schristos it under the terms of the GNU General Public License as published by
104e98e3e1Schristos the Free Software Foundation; either version 3 of the License, or
114e98e3e1Schristos (at your option) any later version.
124e98e3e1Schristos 
134e98e3e1Schristos This program is distributed in the hope that it will be useful,
144e98e3e1Schristos but WITHOUT ANY WARRANTY; without even the implied warranty of
154e98e3e1Schristos MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
164e98e3e1Schristos GNU General Public License for more details.
174e98e3e1Schristos 
184e98e3e1Schristos You should have received a copy of the GNU General Public License
194e98e3e1Schristos along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
204e98e3e1Schristos 
214b169a6bSchristos /* This must come before any other includes.  */
224b169a6bSchristos #include "defs.h"
234e98e3e1Schristos 
244e98e3e1Schristos #include <stdio.h>
254e98e3e1Schristos #include <stdlib.h>
264e98e3e1Schristos #include <fcntl.h>
274e98e3e1Schristos #include <unistd.h>
284e98e3e1Schristos #include <sys/time.h>
294e98e3e1Schristos 
304b169a6bSchristos #include "sim/callback.h"
314e98e3e1Schristos 
324e98e3e1Schristos #include "cpu.h"
334e98e3e1Schristos #include "mem.h"
344e98e3e1Schristos #include "syscalls.h"
354b169a6bSchristos #include "target-newlib-syscall.h"
364e98e3e1Schristos 
374e98e3e1Schristos /* The current syscall callbacks we're using.  */
384e98e3e1Schristos static struct host_callback_struct *callbacks;
394e98e3e1Schristos 
404e98e3e1Schristos void
414e98e3e1Schristos set_callbacks (struct host_callback_struct *cb)
424e98e3e1Schristos {
434e98e3e1Schristos   callbacks = cb;
444e98e3e1Schristos }
454e98e3e1Schristos 
46a2e2270fSchristos struct host_callback_struct *
47a2e2270fSchristos get_callbacks (void)
48a2e2270fSchristos {
49a2e2270fSchristos   return callbacks;
50a2e2270fSchristos }
51a2e2270fSchristos 
524e98e3e1Schristos 
534e98e3e1Schristos /* Arguments 1..4 are in R1..R4, remainder on stack.
544e98e3e1Schristos 
554e98e3e1Schristos    Return value in R1..R4 as needed.
564e98e3e1Schristos      structs bigger than 16 bytes: pointer pushed on stack last
574e98e3e1Schristos 
584e98e3e1Schristos    We only support arguments that fit in general registers.
594e98e3e1Schristos 
604e98e3e1Schristos    The system call number is in R5.  We expect ssycalls to look like
614e98e3e1Schristos    this in libgloss:
624e98e3e1Schristos 
634e98e3e1Schristos    _exit:
644e98e3e1Schristos    	mov	#SYS_exit, r5
654e98e3e1Schristos 	int	#255
664e98e3e1Schristos 	rts
674e98e3e1Schristos */
684e98e3e1Schristos 
694e98e3e1Schristos int argp, stackp;
704e98e3e1Schristos 
714e98e3e1Schristos static int
724b169a6bSchristos arg (void)
734e98e3e1Schristos {
744e98e3e1Schristos   int rv = 0;
754e98e3e1Schristos   argp++;
764e98e3e1Schristos 
774e98e3e1Schristos   if (argp < 4)
784e98e3e1Schristos     return get_reg (argp);
794e98e3e1Schristos 
804e98e3e1Schristos   rv = mem_get_si (get_reg (sp) + stackp);
814e98e3e1Schristos   stackp += 4;
824e98e3e1Schristos   return rv;
834e98e3e1Schristos }
844e98e3e1Schristos 
854e98e3e1Schristos static void
864e98e3e1Schristos read_target (char *buffer, int address, int count, int asciiz)
874e98e3e1Schristos {
884e98e3e1Schristos   char byte;
894e98e3e1Schristos   while (count > 0)
904e98e3e1Schristos     {
914e98e3e1Schristos       byte = mem_get_qi (address++);
924e98e3e1Schristos       *buffer++ = byte;
934e98e3e1Schristos       if (asciiz && (byte == 0))
944e98e3e1Schristos 	return;
954e98e3e1Schristos       count--;
964e98e3e1Schristos     }
974e98e3e1Schristos }
984e98e3e1Schristos 
994e98e3e1Schristos static void
1004e98e3e1Schristos write_target (char *buffer, int address, int count, int asciiz)
1014e98e3e1Schristos {
1024e98e3e1Schristos   char byte;
1034e98e3e1Schristos   while (count > 0)
1044e98e3e1Schristos     {
1054e98e3e1Schristos       byte = *buffer++;
1064e98e3e1Schristos       mem_put_qi (address++, byte);
1074e98e3e1Schristos       if (asciiz && (byte == 0))
1084e98e3e1Schristos 	return;
1094e98e3e1Schristos       count--;
1104e98e3e1Schristos     }
1114e98e3e1Schristos }
1124e98e3e1Schristos 
1134e98e3e1Schristos #define PTRSZ (A16 ? 2 : 3)
1144e98e3e1Schristos 
1154e98e3e1Schristos static char *callnames[] = {
1164e98e3e1Schristos   "SYS_zero",
1174e98e3e1Schristos   "SYS_exit",
1184e98e3e1Schristos   "SYS_open",
1194e98e3e1Schristos   "SYS_close",
1204e98e3e1Schristos   "SYS_read",
1214e98e3e1Schristos   "SYS_write",
1224e98e3e1Schristos   "SYS_lseek",
1234e98e3e1Schristos   "SYS_unlink",
1244e98e3e1Schristos   "SYS_getpid",
1254e98e3e1Schristos   "SYS_kill",
1264e98e3e1Schristos   "SYS_fstat",
1274e98e3e1Schristos   "SYS_sbrk",
1284e98e3e1Schristos   "SYS_argvlen",
1294e98e3e1Schristos   "SYS_argv",
1304e98e3e1Schristos   "SYS_chdir",
1314e98e3e1Schristos   "SYS_stat",
1324e98e3e1Schristos   "SYS_chmod",
1334e98e3e1Schristos   "SYS_utime",
1344e98e3e1Schristos   "SYS_time",
1354e98e3e1Schristos   "SYS_gettimeofday",
1364e98e3e1Schristos   "SYS_times",
1374e98e3e1Schristos   "SYS_link"
1384e98e3e1Schristos };
1394e98e3e1Schristos 
1404e98e3e1Schristos int
1414e98e3e1Schristos rx_syscall (int id)
1424e98e3e1Schristos {
1434e98e3e1Schristos   static char buf[256];
1444e98e3e1Schristos   int rv;
1454e98e3e1Schristos 
1464e98e3e1Schristos   argp = 0;
1474e98e3e1Schristos   stackp = 4;
1484e98e3e1Schristos   if (trace)
1494b169a6bSchristos     printf ("\033[31m/* SYSCALL(%d) = %s */\033[0m\n", id, id <= TARGET_NEWLIB_SYS_link ? callnames[id] : "unknown");
1504e98e3e1Schristos   switch (id)
1514e98e3e1Schristos     {
1524b169a6bSchristos     case TARGET_NEWLIB_SYS_exit:
1534e98e3e1Schristos       {
1544e98e3e1Schristos 	int ec = arg ();
1554e98e3e1Schristos 	if (verbose)
1564e98e3e1Schristos 	  printf ("[exit %d]\n", ec);
1574e98e3e1Schristos 	return RX_MAKE_EXITED (ec);
1584e98e3e1Schristos       }
1594e98e3e1Schristos       break;
1604e98e3e1Schristos 
1614b169a6bSchristos     case TARGET_NEWLIB_SYS_open:
1624e98e3e1Schristos       {
1634b169a6bSchristos 	int oflags, cflags;
1644e98e3e1Schristos 	int path = arg ();
1654e98e3e1Schristos 	/* The open function is defined as taking a variable number of arguments
1664e98e3e1Schristos 	   because the third parameter to it is optional:
1674e98e3e1Schristos 	     open (const char * filename, int flags, ...);
1684e98e3e1Schristos 	   Hence the oflags and cflags arguments will be on the stack and we need
1694e98e3e1Schristos 	   to skip the (empty) argument registers r3 and r4.  */
1704e98e3e1Schristos 	argp = 4;
1714b169a6bSchristos 	oflags = arg ();
1724b169a6bSchristos 	cflags = arg ();
1734e98e3e1Schristos 
1744e98e3e1Schristos 	read_target (buf, path, 256, 1);
1754e98e3e1Schristos 	if (trace)
1764e98e3e1Schristos 	  printf ("open(\"%s\",0x%x,%#o) = ", buf, oflags, cflags);
1774e98e3e1Schristos 
1784e98e3e1Schristos 	if (callbacks)
1794e98e3e1Schristos 	  /* The callback vector ignores CFLAGS.  */
1804e98e3e1Schristos 	  rv = callbacks->open (callbacks, buf, oflags);
1814e98e3e1Schristos 	else
1824e98e3e1Schristos 	  {
1834e98e3e1Schristos 	    int h_oflags = 0;
1844e98e3e1Schristos 
1854e98e3e1Schristos 	    if (oflags & 0x0001)
1864e98e3e1Schristos 	      h_oflags |= O_WRONLY;
1874e98e3e1Schristos 	    if (oflags & 0x0002)
1884e98e3e1Schristos 	      h_oflags |= O_RDWR;
1894e98e3e1Schristos 	    if (oflags & 0x0200)
1904e98e3e1Schristos 	      h_oflags |= O_CREAT;
1914e98e3e1Schristos 	    if (oflags & 0x0008)
1924e98e3e1Schristos 	      h_oflags |= O_APPEND;
1934e98e3e1Schristos 	    if (oflags & 0x0400)
1944e98e3e1Schristos 	      h_oflags |= O_TRUNC;
1954e98e3e1Schristos 	    rv = open (buf, h_oflags, cflags);
1964e98e3e1Schristos 	  }
1974e98e3e1Schristos 	if (trace)
1984e98e3e1Schristos 	  printf ("%d\n", rv);
1994e98e3e1Schristos 	put_reg (1, rv);
2004e98e3e1Schristos       }
2014e98e3e1Schristos       break;
2024e98e3e1Schristos 
2034b169a6bSchristos     case TARGET_NEWLIB_SYS_close:
2044e98e3e1Schristos       {
2054e98e3e1Schristos 	int fd = arg ();
2064e98e3e1Schristos 
2074e98e3e1Schristos 	if (callbacks)
2084e98e3e1Schristos 	  rv = callbacks->close (callbacks, fd);
2094e98e3e1Schristos 	else if (fd > 2)
2104e98e3e1Schristos 	  rv = close (fd);
2114e98e3e1Schristos 	else
2124e98e3e1Schristos 	  rv = 0;
2134e98e3e1Schristos 	if (trace)
2144e98e3e1Schristos 	  printf ("close(%d) = %d\n", fd, rv);
2154e98e3e1Schristos 	put_reg (1, rv);
2164e98e3e1Schristos       }
2174e98e3e1Schristos       break;
2184e98e3e1Schristos 
2194b169a6bSchristos     case TARGET_NEWLIB_SYS_read:
2204e98e3e1Schristos       {
2214e98e3e1Schristos 	int fd = arg ();
2224e98e3e1Schristos 	int addr = arg ();
2234e98e3e1Schristos 	int count = arg ();
2244e98e3e1Schristos 
2254e98e3e1Schristos 	if (count > sizeof (buf))
2264e98e3e1Schristos 	  count = sizeof (buf);
2274e98e3e1Schristos 	if (callbacks)
2284e98e3e1Schristos 	  rv = callbacks->read (callbacks, fd, buf, count);
2294e98e3e1Schristos 	else
2304e98e3e1Schristos 	  rv = read (fd, buf, count);
2314e98e3e1Schristos 	if (trace)
2324e98e3e1Schristos 	  printf ("read(%d,%d) = %d\n", fd, count, rv);
2334e98e3e1Schristos 	if (rv > 0)
2344e98e3e1Schristos 	  write_target (buf, addr, rv, 0);
2354e98e3e1Schristos 	put_reg (1, rv);
2364e98e3e1Schristos       }
2374e98e3e1Schristos       break;
2384e98e3e1Schristos 
2394b169a6bSchristos     case TARGET_NEWLIB_SYS_write:
2404e98e3e1Schristos       {
2414e98e3e1Schristos 	int fd = arg ();
2424e98e3e1Schristos 	int addr = arg ();
2434e98e3e1Schristos 	int count = arg ();
2444e98e3e1Schristos 
2454e98e3e1Schristos 	if (count > sizeof (buf))
2464e98e3e1Schristos 	  count = sizeof (buf);
2474e98e3e1Schristos 	if (trace)
2484e98e3e1Schristos 	  printf ("write(%d,0x%x,%d)\n", fd, addr, count);
2494e98e3e1Schristos 	read_target (buf, addr, count, 0);
2504e98e3e1Schristos 	if (trace)
2514e98e3e1Schristos 	  fflush (stdout);
2524e98e3e1Schristos 	if (callbacks)
2534e98e3e1Schristos 	  rv = callbacks->write (callbacks, fd, buf, count);
2544e98e3e1Schristos 	else
2554e98e3e1Schristos 	  rv = write (fd, buf, count);
2564e98e3e1Schristos 	if (trace)
2574e98e3e1Schristos 	  printf ("write(%d,%d) = %d\n", fd, count, rv);
2584e98e3e1Schristos 	put_reg (1, rv);
2594e98e3e1Schristos       }
2604e98e3e1Schristos       break;
2614e98e3e1Schristos 
2624b169a6bSchristos     case TARGET_NEWLIB_SYS_getpid:
2634e98e3e1Schristos       put_reg (1, 42);
2644e98e3e1Schristos       break;
2654e98e3e1Schristos 
2664b169a6bSchristos     case TARGET_NEWLIB_SYS_gettimeofday:
2674e98e3e1Schristos       {
2684e98e3e1Schristos 	int tvaddr = arg ();
2694e98e3e1Schristos 	struct timeval tv;
2704e98e3e1Schristos 
2714e98e3e1Schristos 	rv = gettimeofday (&tv, 0);
2724e98e3e1Schristos 	if (trace)
2734b169a6bSchristos 	  printf ("gettimeofday: %" PRId64 " sec %" PRId64 " usec to 0x%x\n",
2744b169a6bSchristos 		  (int64_t)tv.tv_sec, (int64_t)tv.tv_usec, tvaddr);
2754e98e3e1Schristos 	mem_put_si (tvaddr, tv.tv_sec);
2764e98e3e1Schristos 	mem_put_si (tvaddr + 4, tv.tv_usec);
2774e98e3e1Schristos 	put_reg (1, rv);
2784e98e3e1Schristos       }
2794e98e3e1Schristos       break;
2804e98e3e1Schristos 
2814b169a6bSchristos     case TARGET_NEWLIB_SYS_kill:
2824e98e3e1Schristos       {
2834e98e3e1Schristos 	int pid = arg ();
2844e98e3e1Schristos 	int sig = arg ();
2854e98e3e1Schristos 	if (pid == 42)
2864e98e3e1Schristos 	  {
2874e98e3e1Schristos 	    if (verbose)
2884e98e3e1Schristos 	      printf ("[signal %d]\n", sig);
2894e98e3e1Schristos 	    return RX_MAKE_STOPPED (sig);
2904e98e3e1Schristos 	  }
2914e98e3e1Schristos       }
2924e98e3e1Schristos       break;
2934e98e3e1Schristos 
2944e98e3e1Schristos     case 11:
2954e98e3e1Schristos       {
2964e98e3e1Schristos 	int heaptop_arg = arg ();
2974e98e3e1Schristos 	if (trace)
2984e98e3e1Schristos 	  printf ("sbrk: heap top set to %x\n", heaptop_arg);
2994e98e3e1Schristos 	heaptop = heaptop_arg;
3004e98e3e1Schristos 	if (heapbottom == 0)
3014e98e3e1Schristos 	  heapbottom = heaptop_arg;
3024e98e3e1Schristos       }
3034e98e3e1Schristos       break;
3044e98e3e1Schristos 
3054e98e3e1Schristos     case 255:
3064e98e3e1Schristos       {
3074e98e3e1Schristos 	int addr = arg ();
3084e98e3e1Schristos 	mem_put_si (addr, rx_cycles + mem_usage_cycles());
3094e98e3e1Schristos       }
3104e98e3e1Schristos       break;
3114e98e3e1Schristos 
3124e98e3e1Schristos     }
3134e98e3e1Schristos   return RX_MAKE_STEPPED ();
3144e98e3e1Schristos }
315