1/* syscalls.c --- implement system calls for the M32C simulator.
2
3Copyright (C) 2005, 2007 Free Software Foundation, Inc.
4Contributed by Red Hat, Inc.
5
6This file is part of the GNU simulators.
7
8This program is free software; you can redistribute it and/or modify
9it under the terms of the GNU General Public License as published by
10the Free Software Foundation; either version 3 of the License, or
11(at your option) any later version.
12
13This program is distributed in the hope that it will be useful,
14but WITHOUT ANY WARRANTY; without even the implied warranty of
15MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16GNU General Public License for more details.
17
18You should have received a copy of the GNU General Public License
19along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
20
21
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.  */
37static struct host_callback_struct *callbacks;
38
39void
40set_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
60int argp, stackp;
61
62static int
63arg (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
120static void
121read_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
134static void
135write_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
150static 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
175void
176m32c_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}
335