new scsi-generic abstraction, use SG_IO (Christoph Hellwig)
[qemu] / bsd-user / syscall.c
1 /*
2  *  BSD syscalls
3  *
4  *  Copyright (c) 2003 - 2008 Fabrice Bellard
5  *
6  *  This program is free software; you can redistribute it and/or modify
7  *  it under the terms of the GNU General Public License as published by
8  *  the Free Software Foundation; either version 2 of the License, or
9  *  (at your option) any later version.
10  *
11  *  This program is distributed in the hope that it will be useful,
12  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
13  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  *  GNU General Public License for more details.
15  *
16  *  You should have received a copy of the GNU General Public License
17  *  along with this program; if not, write to the Free Software
18  *  Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston,
19  *  MA 02110-1301, USA.
20  */
21 #include <stdlib.h>
22 #include <stdio.h>
23 #include <stdint.h>
24 #include <stdarg.h>
25 #include <string.h>
26 #include <errno.h>
27 #include <unistd.h>
28 #include <fcntl.h>
29 #include <time.h>
30 #include <limits.h>
31 #include <sys/types.h>
32 #include <sys/mman.h>
33 #include <sys/syscall.h>
34 #include <signal.h>
35 #include <utime.h>
36
37 #include "qemu.h"
38 #include "qemu-common.h"
39
40 //#define DEBUG
41
42 static abi_ulong target_brk;
43 static abi_ulong target_original_brk;
44
45 #define get_errno(x) (x)
46 #define target_to_host_bitmask(x, tbl) (x)
47
48 void target_set_brk(abi_ulong new_brk)
49 {
50     target_original_brk = target_brk = HOST_PAGE_ALIGN(new_brk);
51 }
52
53 /* do_syscall() should always have a single exit point at the end so
54    that actions, such as logging of syscall results, can be performed.
55    All errnos that do_syscall() returns must be -TARGET_<errcode>. */
56 abi_long do_freebsd_syscall(void *cpu_env, int num, abi_long arg1,
57                             abi_long arg2, abi_long arg3, abi_long arg4,
58                             abi_long arg5, abi_long arg6)
59 {
60     abi_long ret;
61     void *p;
62
63 #ifdef DEBUG
64     gemu_log("freebsd syscall %d\n", num);
65 #endif
66     if(do_strace)
67         print_freebsd_syscall(num, arg1, arg2, arg3, arg4, arg5, arg6);
68
69     switch(num) {
70     case TARGET_FREEBSD_NR_exit:
71 #ifdef HAVE_GPROF
72         _mcleanup();
73 #endif
74         gdb_exit(cpu_env, arg1);
75         /* XXX: should free thread stack and CPU env */
76         _exit(arg1);
77         ret = 0; /* avoid warning */
78         break;
79     case TARGET_FREEBSD_NR_read:
80         if (!(p = lock_user(VERIFY_WRITE, arg2, arg3, 0)))
81             goto efault;
82         ret = get_errno(read(arg1, p, arg3));
83         unlock_user(p, arg2, ret);
84         break;
85     case TARGET_FREEBSD_NR_write:
86         if (!(p = lock_user(VERIFY_READ, arg2, arg3, 1)))
87             goto efault;
88         ret = get_errno(write(arg1, p, arg3));
89         unlock_user(p, arg2, 0);
90         break;
91     case TARGET_FREEBSD_NR_open:
92         if (!(p = lock_user_string(arg1)))
93             goto efault;
94         ret = get_errno(open(path(p),
95                              target_to_host_bitmask(arg2, fcntl_flags_tbl),
96                              arg3));
97         unlock_user(p, arg1, 0);
98         break;
99     case TARGET_FREEBSD_NR_mmap:
100         ret = get_errno(target_mmap(arg1, arg2, arg3,
101                                     target_to_host_bitmask(arg4, mmap_flags_tbl),
102                                     arg5,
103                                     arg6));
104         break;
105     case TARGET_FREEBSD_NR_mprotect:
106         ret = get_errno(target_mprotect(arg1, arg2, arg3));
107         break;
108     case TARGET_FREEBSD_NR_syscall:
109     case TARGET_FREEBSD_NR___syscall:
110         ret = do_freebsd_syscall(cpu_env,arg1 & 0xffff,arg2,arg3,arg4,arg5,arg6,0);
111         break;
112     default:
113         ret = syscall(num, arg1, arg2, arg3, arg4, arg5, arg6);
114         break;
115     }
116  fail:
117 #ifdef DEBUG
118     gemu_log(" = %ld\n", ret);
119 #endif
120     if (do_strace)
121         print_freebsd_syscall_ret(num, ret);
122     return ret;
123  efault:
124     ret = -TARGET_EFAULT;
125     goto fail;
126 }
127
128 abi_long do_netbsd_syscall(void *cpu_env, int num, abi_long arg1,
129                            abi_long arg2, abi_long arg3, abi_long arg4,
130                            abi_long arg5, abi_long arg6)
131 {
132     abi_long ret;
133     void *p;
134
135 #ifdef DEBUG
136     gemu_log("netbsd syscall %d\n", num);
137 #endif
138     if(do_strace)
139         print_netbsd_syscall(num, arg1, arg2, arg3, arg4, arg5, arg6);
140
141     switch(num) {
142     case TARGET_NETBSD_NR_exit:
143 #ifdef HAVE_GPROF
144         _mcleanup();
145 #endif
146         gdb_exit(cpu_env, arg1);
147         /* XXX: should free thread stack and CPU env */
148         _exit(arg1);
149         ret = 0; /* avoid warning */
150         break;
151     case TARGET_NETBSD_NR_read:
152         if (!(p = lock_user(VERIFY_WRITE, arg2, arg3, 0)))
153             goto efault;
154         ret = get_errno(read(arg1, p, arg3));
155         unlock_user(p, arg2, ret);
156         break;
157     case TARGET_NETBSD_NR_write:
158         if (!(p = lock_user(VERIFY_READ, arg2, arg3, 1)))
159             goto efault;
160         ret = get_errno(write(arg1, p, arg3));
161         unlock_user(p, arg2, 0);
162         break;
163     case TARGET_NETBSD_NR_open:
164         if (!(p = lock_user_string(arg1)))
165             goto efault;
166         ret = get_errno(open(path(p),
167                              target_to_host_bitmask(arg2, fcntl_flags_tbl),
168                              arg3));
169         unlock_user(p, arg1, 0);
170         break;
171     case TARGET_NETBSD_NR_mmap:
172         ret = get_errno(target_mmap(arg1, arg2, arg3,
173                                     target_to_host_bitmask(arg4, mmap_flags_tbl),
174                                     arg5,
175                                     arg6));
176         break;
177     case TARGET_NETBSD_NR_mprotect:
178         ret = get_errno(target_mprotect(arg1, arg2, arg3));
179         break;
180     case TARGET_NETBSD_NR_syscall:
181     case TARGET_NETBSD_NR___syscall:
182         ret = do_netbsd_syscall(cpu_env,arg1 & 0xffff,arg2,arg3,arg4,arg5,arg6,0);
183         break;
184     default:
185         ret = syscall(num, arg1, arg2, arg3, arg4, arg5, arg6);
186         break;
187     }
188  fail:
189 #ifdef DEBUG
190     gemu_log(" = %ld\n", ret);
191 #endif
192     if (do_strace)
193         print_netbsd_syscall_ret(num, ret);
194     return ret;
195  efault:
196     ret = -TARGET_EFAULT;
197     goto fail;
198 }
199
200 abi_long do_openbsd_syscall(void *cpu_env, int num, abi_long arg1,
201                             abi_long arg2, abi_long arg3, abi_long arg4,
202                             abi_long arg5, abi_long arg6)
203 {
204     abi_long ret;
205     void *p;
206
207 #ifdef DEBUG
208     gemu_log("openbsd syscall %d\n", num);
209 #endif
210     if(do_strace)
211         print_openbsd_syscall(num, arg1, arg2, arg3, arg4, arg5, arg6);
212
213     switch(num) {
214     case TARGET_OPENBSD_NR_exit:
215 #ifdef HAVE_GPROF
216         _mcleanup();
217 #endif
218         gdb_exit(cpu_env, arg1);
219         /* XXX: should free thread stack and CPU env */
220         _exit(arg1);
221         ret = 0; /* avoid warning */
222         break;
223     case TARGET_OPENBSD_NR_read:
224         if (!(p = lock_user(VERIFY_WRITE, arg2, arg3, 0)))
225             goto efault;
226         ret = get_errno(read(arg1, p, arg3));
227         unlock_user(p, arg2, ret);
228         break;
229     case TARGET_OPENBSD_NR_write:
230         if (!(p = lock_user(VERIFY_READ, arg2, arg3, 1)))
231             goto efault;
232         ret = get_errno(write(arg1, p, arg3));
233         unlock_user(p, arg2, 0);
234         break;
235     case TARGET_OPENBSD_NR_open:
236         if (!(p = lock_user_string(arg1)))
237             goto efault;
238         ret = get_errno(open(path(p),
239                              target_to_host_bitmask(arg2, fcntl_flags_tbl),
240                              arg3));
241         unlock_user(p, arg1, 0);
242         break;
243     case TARGET_OPENBSD_NR_mmap:
244         ret = get_errno(target_mmap(arg1, arg2, arg3,
245                                     target_to_host_bitmask(arg4, mmap_flags_tbl),
246                                     arg5,
247                                     arg6));
248         break;
249     case TARGET_OPENBSD_NR_mprotect:
250         ret = get_errno(target_mprotect(arg1, arg2, arg3));
251         break;
252     case TARGET_OPENBSD_NR_syscall:
253     case TARGET_OPENBSD_NR___syscall:
254         ret = do_openbsd_syscall(cpu_env,arg1 & 0xffff,arg2,arg3,arg4,arg5,arg6,0);
255         break;
256     default:
257         ret = syscall(num, arg1, arg2, arg3, arg4, arg5, arg6);
258         break;
259     }
260  fail:
261 #ifdef DEBUG
262     gemu_log(" = %ld\n", ret);
263 #endif
264     if (do_strace)
265         print_openbsd_syscall_ret(num, ret);
266     return ret;
267  efault:
268     ret = -TARGET_EFAULT;
269     goto fail;
270 }
271
272 void syscall_init(void)
273 {
274 }