]> git.ipfire.org Git - thirdparty/binutils-gdb.git/blob - sim/rx/syscalls.c
2f89da173307a827650534bc025262d615b1cd49
[thirdparty/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 path = arg ();
164 /* The open function is defined as taking a variable number of arguments
165 because the third parameter to it is optional:
166 open (const char * filename, int flags, ...);
167 Hence the oflags and cflags arguments will be on the stack and we need
168 to skip the (empty) argument registers r3 and r4. */
169 argp = 4;
170 int oflags = arg ();
171 int cflags = arg ();
172
173 read_target (buf, path, 256, 1);
174 if (trace)
175 printf ("open(\"%s\",0x%x,%#o) = ", buf, oflags, cflags);
176
177 if (callbacks)
178 /* The callback vector ignores CFLAGS. */
179 rv = callbacks->open (callbacks, buf, oflags);
180 else
181 {
182 int h_oflags = 0;
183
184 if (oflags & 0x0001)
185 h_oflags |= O_WRONLY;
186 if (oflags & 0x0002)
187 h_oflags |= O_RDWR;
188 if (oflags & 0x0200)
189 h_oflags |= O_CREAT;
190 if (oflags & 0x0008)
191 h_oflags |= O_APPEND;
192 if (oflags & 0x0400)
193 h_oflags |= O_TRUNC;
194 rv = open (buf, h_oflags, cflags);
195 }
196 if (trace)
197 printf ("%d\n", rv);
198 put_reg (1, rv);
199 }
200 break;
201
202 case SYS_close:
203 {
204 int fd = arg ();
205
206 if (callbacks)
207 rv = callbacks->close (callbacks, fd);
208 else if (fd > 2)
209 rv = close (fd);
210 else
211 rv = 0;
212 if (trace)
213 printf ("close(%d) = %d\n", fd, rv);
214 put_reg (1, rv);
215 }
216 break;
217
218 case SYS_read:
219 {
220 int fd = arg ();
221 int addr = arg ();
222 int count = arg ();
223
224 if (count > sizeof (buf))
225 count = sizeof (buf);
226 if (callbacks)
227 rv = callbacks->read (callbacks, fd, buf, count);
228 else
229 rv = read (fd, buf, count);
230 if (trace)
231 printf ("read(%d,%d) = %d\n", fd, count, rv);
232 if (rv > 0)
233 write_target (buf, addr, rv, 0);
234 put_reg (1, rv);
235 }
236 break;
237
238 case SYS_write:
239 {
240 int fd = arg ();
241 int addr = arg ();
242 int count = arg ();
243
244 if (count > sizeof (buf))
245 count = sizeof (buf);
246 if (trace)
247 printf ("write(%d,0x%x,%d)\n", fd, addr, count);
248 read_target (buf, addr, count, 0);
249 if (trace)
250 fflush (stdout);
251 if (callbacks)
252 rv = callbacks->write (callbacks, fd, buf, count);
253 else
254 rv = write (fd, buf, count);
255 if (trace)
256 printf ("write(%d,%d) = %d\n", fd, count, rv);
257 put_reg (1, rv);
258 }
259 break;
260
261 case SYS_getpid:
262 put_reg (1, 42);
263 break;
264
265 case SYS_gettimeofday:
266 {
267 int tvaddr = arg ();
268 struct timeval tv;
269
270 rv = gettimeofday (&tv, 0);
271 if (trace)
272 printf ("gettimeofday: %ld sec %ld usec to 0x%x\n", tv.tv_sec,
273 tv.tv_usec, tvaddr);
274 mem_put_si (tvaddr, tv.tv_sec);
275 mem_put_si (tvaddr + 4, tv.tv_usec);
276 put_reg (1, rv);
277 }
278 break;
279
280 case SYS_kill:
281 {
282 int pid = arg ();
283 int sig = arg ();
284 if (pid == 42)
285 {
286 if (verbose)
287 printf ("[signal %d]\n", sig);
288 return RX_MAKE_STOPPED (sig);
289 }
290 }
291 break;
292
293 case 11:
294 {
295 int heaptop_arg = arg ();
296 if (trace)
297 printf ("sbrk: heap top set to %x\n", heaptop_arg);
298 heaptop = heaptop_arg;
299 if (heapbottom == 0)
300 heapbottom = heaptop_arg;
301 }
302 break;
303
304 case 255:
305 {
306 int addr = arg ();
307 mem_put_si (addr, rx_cycles + mem_usage_cycles());
308 }
309 break;
310
311 }
312 return RX_MAKE_STEPPED ();
313 }