sim: require AC_PROG_CPP explicitly
[binutils-gdb.git] / sim / rx / syscalls.c
1 /* syscalls.c --- implement system calls for the RX simulator.
2
3 Copyright (C) 2005-2021 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
22 #include "config.h"
23 #include <stdio.h>
24 #include <stdlib.h>
25 #include <fcntl.h>
26 #include <unistd.h>
27 #include <sys/time.h>
28
29 #include "gdb/callback.h"
30
31 #include "cpu.h"
32 #include "mem.h"
33 #include "syscalls.h"
34
35 #include "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 <= SYS_link ? callnames[id] : "unknown");
150 switch (id)
151 {
152 case 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 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 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 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 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 SYS_getpid:
263 put_reg (1, 42);
264 break;
265
266 case SYS_gettimeofday:
267 {
268 int tvaddr = arg ();
269 struct timeval tv;
270
271 rv = gettimeofday (&tv, 0);
272 if (trace)
273 printf ("gettimeofday: %ld sec %ld usec to 0x%x\n", tv.tv_sec,
274 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 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 }