xref: /netbsd-src/external/gpl3/gdb/dist/sim/rx/syscalls.c (revision b7b7574d3bf8eeb51a1fa3977b59142ec6434a55)
1 /* syscalls.c --- implement system calls for the RX simulator.
2 
3 Copyright (C) 2005-2014 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 ()
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 }
314