xref: /netbsd-src/external/gpl3/gdb/dist/sim/rx/syscalls.c (revision 1f4e7eb9e5e045e008f1894823a8e4e6c9f46890)
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
41 set_callbacks (struct host_callback_struct *cb)
42 {
43   callbacks = cb;
44 }
45 
46 struct host_callback_struct *
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
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
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
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
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