6d2f16317df95260590702edf0de510a3729aabf
[external/binutils.git] / sim / rx / syscalls.c
1 /* syscalls.c --- implement system calls for the RX simulator.
2
3 Copyright (C) 2005, 2007-2012 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
47 /* Arguments 1..4 are in R1..R4, remainder on stack.
48
49    Return value in R1..R4 as needed.
50      structs bigger than 16 bytes: pointer pushed on stack last
51
52    We only support arguments that fit in general registers.
53
54    The system call number is in R5.  We expect ssycalls to look like
55    this in libgloss:
56
57    _exit:
58         mov     #SYS_exit, r5
59         int     #255
60         rts
61 */
62
63 int argp, stackp;
64
65 static int
66 arg ()
67 {
68   int rv = 0;
69   argp++;
70
71   if (argp < 4)
72     return get_reg (argp);
73
74   rv = mem_get_si (get_reg (sp) + stackp);
75   stackp += 4;
76   return rv;
77 }
78
79 static void
80 read_target (char *buffer, int address, int count, int asciiz)
81 {
82   char byte;
83   while (count > 0)
84     {
85       byte = mem_get_qi (address++);
86       *buffer++ = byte;
87       if (asciiz && (byte == 0))
88         return;
89       count--;
90     }
91 }
92
93 static void
94 write_target (char *buffer, int address, int count, int asciiz)
95 {
96   char byte;
97   while (count > 0)
98     {
99       byte = *buffer++;
100       mem_put_qi (address++, byte);
101       if (asciiz && (byte == 0))
102         return;
103       count--;
104     }
105 }
106
107 #define PTRSZ (A16 ? 2 : 3)
108
109 static char *callnames[] = {
110   "SYS_zero",
111   "SYS_exit",
112   "SYS_open",
113   "SYS_close",
114   "SYS_read",
115   "SYS_write",
116   "SYS_lseek",
117   "SYS_unlink",
118   "SYS_getpid",
119   "SYS_kill",
120   "SYS_fstat",
121   "SYS_sbrk",
122   "SYS_argvlen",
123   "SYS_argv",
124   "SYS_chdir",
125   "SYS_stat",
126   "SYS_chmod",
127   "SYS_utime",
128   "SYS_time",
129   "SYS_gettimeofday",
130   "SYS_times",
131   "SYS_link"
132 };
133
134 int
135 rx_syscall (int id)
136 {
137   static char buf[256];
138   int rv;
139
140   argp = 0;
141   stackp = 4;
142   if (trace)
143     printf ("\033[31m/* SYSCALL(%d) = %s */\033[0m\n", id, id <= SYS_link ? callnames[id] : "unknown");
144   switch (id)
145     {
146     case SYS_exit:
147       {
148         int ec = arg ();
149         if (verbose)
150           printf ("[exit %d]\n", ec);
151         return RX_MAKE_EXITED (ec);
152       }
153       break;
154
155     case SYS_open:
156       {
157         int path = arg ();
158         /* The open function is defined as taking a variable number of arguments
159            because the third parameter to it is optional:
160              open (const char * filename, int flags, ...);
161            Hence the oflags and cflags arguments will be on the stack and we need
162            to skip the (empty) argument registers r3 and r4.  */
163         argp = 4;
164         int oflags = arg ();
165         int cflags = arg ();
166
167         read_target (buf, path, 256, 1);
168         if (trace)
169           printf ("open(\"%s\",0x%x,%#o) = ", buf, oflags, cflags);
170
171         if (callbacks)
172           /* The callback vector ignores CFLAGS.  */
173           rv = callbacks->open (callbacks, buf, oflags);
174         else
175           {
176             int h_oflags = 0;
177
178             if (oflags & 0x0001)
179               h_oflags |= O_WRONLY;
180             if (oflags & 0x0002)
181               h_oflags |= O_RDWR;
182             if (oflags & 0x0200)
183               h_oflags |= O_CREAT;
184             if (oflags & 0x0008)
185               h_oflags |= O_APPEND;
186             if (oflags & 0x0400)
187               h_oflags |= O_TRUNC;
188             rv = open (buf, h_oflags, cflags);
189           }
190         if (trace)
191           printf ("%d\n", rv);
192         put_reg (1, rv);
193       }
194       break;
195
196     case SYS_close:
197       {
198         int fd = arg ();
199
200         if (callbacks)
201           rv = callbacks->close (callbacks, fd);
202         else if (fd > 2)
203           rv = close (fd);
204         else
205           rv = 0;
206         if (trace)
207           printf ("close(%d) = %d\n", fd, rv);
208         put_reg (1, rv);
209       }
210       break;
211
212     case SYS_read:
213       {
214         int fd = arg ();
215         int addr = arg ();
216         int count = arg ();
217
218         if (count > sizeof (buf))
219           count = sizeof (buf);
220         if (callbacks)
221           rv = callbacks->read (callbacks, fd, buf, count);
222         else
223           rv = read (fd, buf, count);
224         if (trace)
225           printf ("read(%d,%d) = %d\n", fd, count, rv);
226         if (rv > 0)
227           write_target (buf, addr, rv, 0);
228         put_reg (1, rv);
229       }
230       break;
231
232     case SYS_write:
233       {
234         int fd = arg ();
235         int addr = arg ();
236         int count = arg ();
237
238         if (count > sizeof (buf))
239           count = sizeof (buf);
240         if (trace)
241           printf ("write(%d,0x%x,%d)\n", fd, addr, count);
242         read_target (buf, addr, count, 0);
243         if (trace)
244           fflush (stdout);
245         if (callbacks)
246           rv = callbacks->write (callbacks, fd, buf, count);
247         else
248           rv = write (fd, buf, count);
249         if (trace)
250           printf ("write(%d,%d) = %d\n", fd, count, rv);
251         put_reg (1, rv);
252       }
253       break;
254
255     case SYS_getpid:
256       put_reg (1, 42);
257       break;
258
259     case SYS_gettimeofday:
260       {
261         int tvaddr = arg ();
262         struct timeval tv;
263
264         rv = gettimeofday (&tv, 0);
265         if (trace)
266           printf ("gettimeofday: %ld sec %ld usec to 0x%x\n", tv.tv_sec,
267                   tv.tv_usec, tvaddr);
268         mem_put_si (tvaddr, tv.tv_sec);
269         mem_put_si (tvaddr + 4, tv.tv_usec);
270         put_reg (1, rv);
271       }
272       break;
273
274     case SYS_kill:
275       {
276         int pid = arg ();
277         int sig = arg ();
278         if (pid == 42)
279           {
280             if (verbose)
281               printf ("[signal %d]\n", sig);
282             return RX_MAKE_STOPPED (sig);
283           }
284       }
285       break;
286
287     case 11:
288       {
289         int heaptop_arg = arg ();
290         if (trace)
291           printf ("sbrk: heap top set to %x\n", heaptop_arg);
292         heaptop = heaptop_arg;
293         if (heapbottom == 0)
294           heapbottom = heaptop_arg;
295       }
296       break;
297
298     case 255:
299       {
300         int addr = arg ();
301         mem_put_si (addr, rx_cycles + mem_usage_cycles());
302       }
303       break;
304
305     }
306   return RX_MAKE_STEPPED ();
307 }