Automatic date update in version.in
[platform/upstream/binutils.git] / sim / rx / syscalls.c
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 }