1 /* syscalls.c --- implement system calls for the RX simulator.
2 
3 Copyright (C) 2005-2024 Free Software Foundation, Inc.
4 Contributed by Red Hat, Inc.
5 
6 This file is part of the GNU simulators.
7 
8 This program is free software; you can redistribute it and/or modify
9 it under the terms of the GNU General Public License as published by
10 the Free Software Foundation; either version 3 of the License, or
11 (at your option) any later version.
12 
13 This program is distributed in the hope that it will be useful,
14 but WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16 GNU General Public License for more details.
17 
18 You should have received a copy of the GNU General Public License
19 along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
20 
21 /* This must come before any other includes.  */
22 #include "defs.h"
23 
24 #include <stdio.h>
25 #include <stdlib.h>
26 #include <fcntl.h>
27 #include <unistd.h>
28 #include <sys/time.h>
29 
30 #include "sim/callback.h"
31 
32 #include "cpu.h"
33 #include "mem.h"
34 #include "syscalls.h"
35 #include "target-newlib-syscall.h"
36 
37 /* The current syscall callbacks we're using.  */
38 static struct host_callback_struct *callbacks;
39 
40 void
set_callbacks(struct host_callback_struct * cb)41 set_callbacks (struct host_callback_struct *cb)
42 {
43   callbacks = cb;
44 }
45 
46 struct host_callback_struct *
get_callbacks(void)47 get_callbacks (void)
48 {
49   return callbacks;
50 }
51 
52 
53 /* Arguments 1..4 are in R1..R4, remainder on stack.
54 
55    Return value in R1..R4 as needed.
56      structs bigger than 16 bytes: pointer pushed on stack last
57 
58    We only support arguments that fit in general registers.
59 
60    The system call number is in R5.  We expect ssycalls to look like
61    this in libgloss:
62 
63    _exit:
64           mov       #SYS_exit, r5
65           int       #255
66           rts
67 */
68 
69 int argp, stackp;
70 
71 static int
arg(void)72 arg (void)
73 {
74   int rv = 0;
75   argp++;
76 
77   if (argp < 4)
78     return get_reg (argp);
79 
80   rv = mem_get_si (get_reg (sp) + stackp);
81   stackp += 4;
82   return rv;
83 }
84 
85 static void
read_target(char * buffer,int address,int count,int asciiz)86 read_target (char *buffer, int address, int count, int asciiz)
87 {
88   char byte;
89   while (count > 0)
90     {
91       byte = mem_get_qi (address++);
92       *buffer++ = byte;
93       if (asciiz && (byte == 0))
94           return;
95       count--;
96     }
97 }
98 
99 static void
write_target(char * buffer,int address,int count,int asciiz)100 write_target (char *buffer, int address, int count, int asciiz)
101 {
102   char byte;
103   while (count > 0)
104     {
105       byte = *buffer++;
106       mem_put_qi (address++, byte);
107       if (asciiz && (byte == 0))
108           return;
109       count--;
110     }
111 }
112 
113 #define PTRSZ (A16 ? 2 : 3)
114 
115 static char *callnames[] = {
116   "SYS_zero",
117   "SYS_exit",
118   "SYS_open",
119   "SYS_close",
120   "SYS_read",
121   "SYS_write",
122   "SYS_lseek",
123   "SYS_unlink",
124   "SYS_getpid",
125   "SYS_kill",
126   "SYS_fstat",
127   "SYS_sbrk",
128   "SYS_argvlen",
129   "SYS_argv",
130   "SYS_chdir",
131   "SYS_stat",
132   "SYS_chmod",
133   "SYS_utime",
134   "SYS_time",
135   "SYS_gettimeofday",
136   "SYS_times",
137   "SYS_link"
138 };
139 
140 int
rx_syscall(int id)141 rx_syscall (int id)
142 {
143   static char buf[256];
144   int rv;
145 
146   argp = 0;
147   stackp = 4;
148   if (trace)
149     printf ("\033[31m/* SYSCALL(%d) = %s */\033[0m\n", id, id <= TARGET_NEWLIB_SYS_link ? callnames[id] : "unknown");
150   switch (id)
151     {
152     case TARGET_NEWLIB_SYS_exit:
153       {
154           int ec = arg ();
155           if (verbose)
156             printf ("[exit %d]\n", ec);
157           return RX_MAKE_EXITED (ec);
158       }
159       break;
160 
161     case TARGET_NEWLIB_SYS_open:
162       {
163           int oflags, cflags;
164           int path = arg ();
165           /* The open function is defined as taking a variable number of arguments
166              because the third parameter to it is optional:
167                open (const char * filename, int flags, ...);
168              Hence the oflags and cflags arguments will be on the stack and we need
169              to skip the (empty) argument registers r3 and r4.  */
170           argp = 4;
171           oflags = arg ();
172           cflags = arg ();
173 
174           read_target (buf, path, 256, 1);
175           if (trace)
176             printf ("open(\"%s\",0x%x,%#o) = ", buf, oflags, cflags);
177 
178           if (callbacks)
179             /* The callback vector ignores CFLAGS.  */
180             rv = callbacks->open (callbacks, buf, oflags);
181           else
182             {
183               int h_oflags = 0;
184 
185               if (oflags & 0x0001)
186                 h_oflags |= O_WRONLY;
187               if (oflags & 0x0002)
188                 h_oflags |= O_RDWR;
189               if (oflags & 0x0200)
190                 h_oflags |= O_CREAT;
191               if (oflags & 0x0008)
192                 h_oflags |= O_APPEND;
193               if (oflags & 0x0400)
194                 h_oflags |= O_TRUNC;
195               rv = open (buf, h_oflags, cflags);
196             }
197           if (trace)
198             printf ("%d\n", rv);
199           put_reg (1, rv);
200       }
201       break;
202 
203     case TARGET_NEWLIB_SYS_close:
204       {
205           int fd = arg ();
206 
207           if (callbacks)
208             rv = callbacks->close (callbacks, fd);
209           else if (fd > 2)
210             rv = close (fd);
211           else
212             rv = 0;
213           if (trace)
214             printf ("close(%d) = %d\n", fd, rv);
215           put_reg (1, rv);
216       }
217       break;
218 
219     case TARGET_NEWLIB_SYS_read:
220       {
221           int fd = arg ();
222           int addr = arg ();
223           int count = arg ();
224 
225           if (count > sizeof (buf))
226             count = sizeof (buf);
227           if (callbacks)
228             rv = callbacks->read (callbacks, fd, buf, count);
229           else
230             rv = read (fd, buf, count);
231           if (trace)
232             printf ("read(%d,%d) = %d\n", fd, count, rv);
233           if (rv > 0)
234             write_target (buf, addr, rv, 0);
235           put_reg (1, rv);
236       }
237       break;
238 
239     case TARGET_NEWLIB_SYS_write:
240       {
241           int fd = arg ();
242           int addr = arg ();
243           int count = arg ();
244 
245           if (count > sizeof (buf))
246             count = sizeof (buf);
247           if (trace)
248             printf ("write(%d,0x%x,%d)\n", fd, addr, count);
249           read_target (buf, addr, count, 0);
250           if (trace)
251             fflush (stdout);
252           if (callbacks)
253             rv = callbacks->write (callbacks, fd, buf, count);
254           else
255             rv = write (fd, buf, count);
256           if (trace)
257             printf ("write(%d,%d) = %d\n", fd, count, rv);
258           put_reg (1, rv);
259       }
260       break;
261 
262     case TARGET_NEWLIB_SYS_getpid:
263       put_reg (1, 42);
264       break;
265 
266     case TARGET_NEWLIB_SYS_gettimeofday:
267       {
268           int tvaddr = arg ();
269           struct timeval tv;
270 
271           rv = gettimeofday (&tv, 0);
272           if (trace)
273             printf ("gettimeofday: %" PRId64 " sec %" PRId64 " usec to 0x%x\n",
274                       (int64_t)tv.tv_sec, (int64_t)tv.tv_usec, tvaddr);
275           mem_put_si (tvaddr, tv.tv_sec);
276           mem_put_si (tvaddr + 4, tv.tv_usec);
277           put_reg (1, rv);
278       }
279       break;
280 
281     case TARGET_NEWLIB_SYS_kill:
282       {
283           int pid = arg ();
284           int sig = arg ();
285           if (pid == 42)
286             {
287               if (verbose)
288                 printf ("[signal %d]\n", sig);
289               return RX_MAKE_STOPPED (sig);
290             }
291       }
292       break;
293 
294     case 11:
295       {
296           int heaptop_arg = arg ();
297           if (trace)
298             printf ("sbrk: heap top set to %x\n", heaptop_arg);
299           heaptop = heaptop_arg;
300           if (heapbottom == 0)
301             heapbottom = heaptop_arg;
302       }
303       break;
304 
305     case 255:
306       {
307           int addr = arg ();
308           mem_put_si (addr, rx_cycles + mem_usage_cycles());
309       }
310       break;
311 
312     }
313   return RX_MAKE_STEPPED ();
314 }
315