PR 14072
[external/binutils.git] / sim / m32c / syscalls.c
1 /* syscalls.c --- implement system calls for the M32C 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 #include "config.h"
22 #include <stdio.h>
23 #include <stdlib.h>
24 #include <fcntl.h>
25 #include <unistd.h>
26 #include <sys/time.h>
27
28 #include "gdb/callback.h"
29
30 #include "cpu.h"
31 #include "mem.h"
32 #include "syscalls.h"
33
34 #include "syscall.h"
35
36 /* The current syscall callbacks we're using.  */
37 static struct host_callback_struct *callbacks;
38
39 void
40 set_callbacks (struct host_callback_struct *cb)
41 {
42   callbacks = cb;
43 }
44
45
46 /* A16 ABI: arg1 in r1l (QI) or r1 (HI) or stack
47             arg2 in r2 (HI) or stack
48             arg3..N on stack
49             padding: none
50
51    A24 ABI: arg1 in r0l (QI) or r0 (HI) or stack
52             arg2..N on stack
53             padding: qi->hi
54
55    return value in r0l (QI) r0 (HI) r2r0 (SI)
56      structs: pointer pushed on stack last
57
58 */
59
60 int argp, stackp;
61
62 static int
63 arg (int bytes)
64 {
65   int rv = 0;
66   argp++;
67   if (A16)
68     {
69       switch (argp)
70         {
71         case 1:
72           if (bytes == 1)
73             return get_reg (r1l);
74           if (bytes == 2)
75             return get_reg (r1);
76           break;
77         case 2:
78           if (bytes == 2)
79             return get_reg (r2);
80           break;
81         }
82     }
83   else
84     {
85       switch (argp)
86         {
87         case 1:
88           if (bytes == 1)
89             return get_reg (r0l);
90           if (bytes == 2)
91             return get_reg (r0);
92           break;
93         }
94     }
95   if (bytes == 0)
96     bytes = 2;
97   switch (bytes)
98     {
99     case 1:
100       rv = mem_get_qi (get_reg (sp) + stackp);
101       if (A24)
102         stackp++;
103       break;
104     case 2:
105       rv = mem_get_hi (get_reg (sp) + stackp);
106       break;
107     case 3:
108       rv = mem_get_psi (get_reg (sp) + stackp);
109       if (A24)
110         stackp++;
111       break;
112     case 4:
113       rv = mem_get_si (get_reg (sp) + stackp);
114       break;
115     }
116   stackp += bytes;
117   return rv;
118 }
119
120 static void
121 read_target (char *buffer, int address, int count, int asciiz)
122 {
123   char byte;
124   while (count > 0)
125     {
126       byte = mem_get_qi (address++);
127       *buffer++ = byte;
128       if (asciiz && (byte == 0))
129         return;
130       count--;
131     }
132 }
133
134 static void
135 write_target (char *buffer, int address, int count, int asciiz)
136 {
137   char byte;
138   while (count > 0)
139     {
140       byte = *buffer++;
141       mem_put_qi (address++, byte);
142       if (asciiz && (byte == 0))
143         return;
144       count--;
145     }
146 }
147
148 #define PTRSZ (A16 ? 2 : 3)
149
150 static char *callnames[] = {
151   "SYS_zero",
152   "SYS_exit",
153   "SYS_open",
154   "SYS_close",
155   "SYS_read",
156   "SYS_write",
157   "SYS_lseek",
158   "SYS_unlink",
159   "SYS_getpid",
160   "SYS_kill",
161   "SYS_fstat",
162   "SYS_sbrk",
163   "SYS_argvlen",
164   "SYS_argv",
165   "SYS_chdir",
166   "SYS_stat",
167   "SYS_chmod",
168   "SYS_utime",
169   "SYS_time",
170   "SYS_gettimeofday",
171   "SYS_times",
172   "SYS_link"
173 };
174
175 void
176 m32c_syscall (int id)
177 {
178   static char buf[256];
179   int rv;
180
181   argp = 0;
182   stackp = A16 ? 3 : 4;
183   if (trace)
184     printf ("\033[31m/* SYSCALL(%d) = %s */\033[0m\n", id, callnames[id]);
185   switch (id)
186     {
187     case SYS_exit:
188       {
189         int ec = arg (2);
190         if (verbose)
191           printf ("[exit %d]\n", ec);
192         step_result = M32C_MAKE_EXITED (ec);
193       }
194       break;
195
196     case SYS_open:
197       {
198         int path = arg (PTRSZ);
199         int oflags = arg (2);
200         int cflags = arg (2);
201
202         read_target (buf, path, 256, 1);
203         if (trace)
204           printf ("open(\"%s\",0x%x,%#o) = ", buf, oflags, cflags);
205
206         if (callbacks)
207           /* The callback vector ignores CFLAGS.  */
208           rv = callbacks->open (callbacks, buf, oflags);
209         else
210           {
211             int h_oflags = 0;
212
213             if (oflags & 0x0001)
214               h_oflags |= O_WRONLY;
215             if (oflags & 0x0002)
216               h_oflags |= O_RDWR;
217             if (oflags & 0x0200)
218               h_oflags |= O_CREAT;
219             if (oflags & 0x0008)
220               h_oflags |= O_APPEND;
221             if (oflags & 0x0400)
222               h_oflags |= O_TRUNC;
223             rv = open (buf, h_oflags, cflags);
224           }
225         if (trace)
226           printf ("%d\n", rv);
227         put_reg (r0, rv);
228       }
229       break;
230
231     case SYS_close:
232       {
233         int fd = arg (2);
234
235         if (callbacks)
236           rv = callbacks->close (callbacks, fd);
237         else if (fd > 2)
238           rv = close (fd);
239         else
240           rv = 0;
241         if (trace)
242           printf ("close(%d) = %d\n", fd, rv);
243         put_reg (r0, rv);
244       }
245       break;
246
247     case SYS_read:
248       {
249         int fd = arg (2);
250         int addr = arg (PTRSZ);
251         int count = arg (2);
252
253         if (count > sizeof (buf))
254           count = sizeof (buf);
255         if (callbacks)
256           rv = callbacks->read (callbacks, fd, buf, count);
257         else
258           rv = read (fd, buf, count);
259         if (trace)
260           printf ("read(%d,%d) = %d\n", fd, count, rv);
261         if (rv > 0)
262           write_target (buf, addr, rv, 0);
263         put_reg (r0, rv);
264       }
265       break;
266
267     case SYS_write:
268       {
269         int fd = arg (2);
270         int addr = arg (PTRSZ);
271         int count = arg (2);
272
273         if (count > sizeof (buf))
274           count = sizeof (buf);
275         if (trace)
276           printf ("write(%d,0x%x,%d)\n", fd, addr, count);
277         read_target (buf, addr, count, 0);
278         if (trace)
279           fflush (stdout);
280         if (callbacks)
281           rv = callbacks->write (callbacks, fd, buf, count);
282         else
283           rv = write (fd, buf, count);
284         if (trace)
285           printf ("write(%d,%d) = %d\n", fd, count, rv);
286         put_reg (r0, rv);
287       }
288       break;
289
290     case SYS_getpid:
291       put_reg (r0, 42);
292       break;
293
294     case SYS_gettimeofday:
295       {
296         int tvaddr = arg (PTRSZ);
297         struct timeval tv;
298
299         rv = gettimeofday (&tv, 0);
300         if (trace)
301           printf ("gettimeofday: %ld sec %ld usec to 0x%x\n", tv.tv_sec,
302                   tv.tv_usec, tvaddr);
303         mem_put_si (tvaddr, tv.tv_sec);
304         mem_put_si (tvaddr + 4, tv.tv_usec);
305         put_reg (r0, rv);
306       }
307       break;
308
309     case SYS_kill:
310       {
311         int pid = arg (2);
312         int sig = arg (2);
313         if (pid == 42)
314           {
315             if (verbose)
316               printf ("[signal %d]\n", sig);
317             step_result = M32C_MAKE_STOPPED (sig);
318           }
319       }
320       break;
321
322     case 11:
323       {
324         int heaptop_arg = arg (PTRSZ);
325         if (trace)
326           printf ("sbrk: heap top set to %x\n", heaptop_arg);
327         heaptop = heaptop_arg;
328         if (heapbottom == 0)
329           heapbottom = heaptop_arg;
330       }
331       break;
332
333     }
334 }