linux_ipccall.c revision 1.28.14.1 1 /* $NetBSD: linux_ipccall.c,v 1.28.14.1 2007/12/09 19:37:00 jmcneill Exp $ */
2
3 /*-
4 * Copyright (c) 1998 The NetBSD Foundation, Inc.
5 * All rights reserved.
6 *
7 * This code is derived from software contributed to The NetBSD Foundation
8 * by Frank van der Linden and Eric Haszlakiewicz.
9 *
10 * Redistribution and use in source and binary forms, with or without
11 * modification, are permitted provided that the following conditions
12 * are met:
13 * 1. Redistributions of source code must retain the above copyright
14 * notice, this list of conditions and the following disclaimer.
15 * 2. Redistributions in binary form must reproduce the above copyright
16 * notice, this list of conditions and the following disclaimer in the
17 * documentation and/or other materials provided with the distribution.
18 * 3. All advertising materials mentioning features or use of this software
19 * must display the following acknowledgement:
20 * This product includes software developed by the NetBSD
21 * Foundation, Inc. and its contributors.
22 * 4. Neither the name of The NetBSD Foundation nor the names of its
23 * contributors may be used to endorse or promote products derived
24 * from this software without specific prior written permission.
25 *
26 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
27 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
28 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
29 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
30 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
31 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
32 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
33 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
34 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
35 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
36 * POSSIBILITY OF SUCH DAMAGE.
37 */
38
39 #include <sys/cdefs.h>
40 __KERNEL_RCSID(0, "$NetBSD: linux_ipccall.c,v 1.28.14.1 2007/12/09 19:37:00 jmcneill Exp $");
41
42 #if defined(_KERNEL_OPT)
43 #include "opt_sysv.h"
44 #endif
45
46 #include <sys/param.h>
47 #include <sys/shm.h>
48 #include <sys/sem.h>
49 #include <sys/msg.h>
50 #include <sys/proc.h>
51 #include <sys/systm.h>
52
53 /* real syscalls */
54 #include <sys/mount.h>
55 #include <sys/syscallargs.h>
56
57 /* sys_ipc + args prototype */
58 #include <compat/linux/common/linux_types.h>
59 #include <compat/linux/common/linux_signal.h>
60
61 #include <compat/linux/linux_syscallargs.h>
62 #include <compat/linux/linux_syscall.h>
63
64 /* general ipc defines */
65 #include <compat/linux/common/linux_ipc.h>
66
67 /* prototypes for real/normal linux-emul syscalls */
68 #include <compat/linux/common/linux_msg.h>
69 #include <compat/linux/common/linux_shm.h>
70 #include <compat/linux/common/linux_sem.h>
71
72 /* prototypes for sys_ipc stuff */
73 #include <compat/linux/common/linux_ipccall.h>
74
75 /* Used on: arm, i386, m68k, mips, ppc, sparc, sparc64 */
76 /* Not used on: alpha */
77
78 /*
79 * Stuff to deal with the SysV ipc/shm/semaphore interface in Linux.
80 * The main difference is, that Linux handles it all via one
81 * system call, which has the usual maximum amount of 5 arguments.
82 * This results in a kludge for calls that take 6 of them.
83 *
84 * The SYSV??? options have to be enabled to get the appropriate
85 * functions to work.
86 */
87
88 int
89 linux_sys_ipc(struct lwp *l, void *v, register_t *retval)
90 {
91 struct linux_sys_ipc_args /* {
92 syscallarg(int) what;
93 syscallarg(int) a1;
94 syscallarg(int) a2;
95 syscallarg(int) a3;
96 syscallarg(void *) ptr;
97 } */ *uap = v;
98
99 switch (SCARG(uap, what)) {
100 #ifdef SYSVSEM
101 case LINUX_SYS_semop:
102 return linux_semop(l, uap, retval);
103 case LINUX_SYS_semget:
104 return linux_semget(l, uap, retval);
105 case LINUX_SYS_semctl: {
106 struct linux_sys_semctl_args bsa;
107 union linux_semun arg;
108 int error;
109
110 SCARG(&bsa, semid) = SCARG(uap, a1);
111 SCARG(&bsa, semnum) = SCARG(uap, a2);
112 SCARG(&bsa, cmd) = SCARG(uap, a3);
113 /* Convert from (union linux_semun *) to (union linux_semun) */
114 if ((error = copyin(SCARG(uap, ptr), &arg, sizeof arg)))
115 return error;
116 SCARG(&bsa, arg) = arg;
117
118 return linux_sys_semctl(l, &bsa, retval);
119 }
120 #endif
121 #ifdef SYSVMSG
122 case LINUX_SYS_msgsnd:
123 return linux_msgsnd(l, uap, retval);
124 case LINUX_SYS_msgrcv:
125 return linux_msgrcv(l, uap, retval);
126 case LINUX_SYS_msgget:
127 return linux_msgget(l, uap, retval);
128 case LINUX_SYS_msgctl: {
129 struct linux_sys_msgctl_args bsa;
130
131 SCARG(&bsa, msqid) = SCARG(uap, a1);
132 SCARG(&bsa, cmd) = SCARG(uap, a2);
133 SCARG(&bsa, buf) = (struct linux_msqid_ds *)SCARG(uap, ptr);
134
135 return linux_sys_msgctl(l, &bsa, retval);
136 }
137 #endif
138 #ifdef SYSVSHM
139 case LINUX_SYS_shmat: {
140 struct linux_sys_shmat_args bsa;
141
142 SCARG(&bsa, shmid) = SCARG(uap, a1);
143 SCARG(&bsa, shmaddr) = (void *)SCARG(uap, ptr);
144 SCARG(&bsa, shmflg) = SCARG(uap, a2);
145 /* XXX passing pointer inside int here */
146 SCARG(&bsa, raddr) = (u_long *)SCARG(uap, a3);
147
148 return linux_sys_shmat(l, &bsa, retval);
149 }
150 case LINUX_SYS_shmdt:
151 return linux_shmdt(l, uap, retval);
152 case LINUX_SYS_shmget:
153 return linux_shmget(l, uap, retval);
154 case LINUX_SYS_shmctl: {
155 struct linux_sys_shmctl_args bsa;
156
157 SCARG(&bsa, shmid) = SCARG(uap, a1);
158 SCARG(&bsa, cmd) = SCARG(uap, a2);
159 SCARG(&bsa, buf) = (struct linux_shmid_ds *)SCARG(uap, ptr);
160
161 return linux_sys_shmctl(l, &bsa, retval);
162 }
163 #endif
164 default:
165 return ENOSYS;
166 }
167 }
168
169 #ifdef SYSVSEM
170 inline int
171 linux_semop(l, uap, retval)
172 struct lwp *l;
173 struct linux_sys_ipc_args /* {
174 syscallarg(int) what;
175 syscallarg(int) a1;
176 syscallarg(int) a2;
177 syscallarg(int) a3;
178 syscallarg(void *) ptr;
179 } */ *uap;
180 register_t *retval;
181 {
182 struct sys_semop_args bsa;
183
184 SCARG(&bsa, semid) = SCARG(uap, a1);
185 SCARG(&bsa, sops) = (struct sembuf *)SCARG(uap, ptr);
186 SCARG(&bsa, nsops) = SCARG(uap, a2);
187
188 return sys_semop(l, &bsa, retval);
189 }
190
191 inline int
192 linux_semget(l, uap, retval)
193 struct lwp *l;
194 struct linux_sys_ipc_args /* {
195 syscallarg(int) what;
196 syscallarg(int) a1;
197 syscallarg(int) a2;
198 syscallarg(int) a3;
199 syscallarg(void *) ptr;
200 } */ *uap;
201 register_t *retval;
202 {
203 struct sys_semget_args bsa;
204
205 SCARG(&bsa, key) = (key_t)SCARG(uap, a1);
206 SCARG(&bsa, nsems) = SCARG(uap, a2);
207 SCARG(&bsa, semflg) = SCARG(uap, a3);
208
209 return sys_semget(l, &bsa, retval);
210 }
211
212 #endif /* SYSVSEM */
213
214 #ifdef SYSVMSG
215
216 inline int
217 linux_msgsnd(l, uap, retval)
218 struct lwp *l;
219 struct linux_sys_ipc_args /* {
220 syscallarg(int) what;
221 syscallarg(int) a1;
222 syscallarg(int) a2;
223 syscallarg(int) a3;
224 syscallarg(void *) ptr;
225 } */ *uap;
226 register_t *retval;
227 {
228 struct sys_msgsnd_args bma;
229
230 SCARG(&bma, msqid) = SCARG(uap, a1);
231 SCARG(&bma, msgp) = SCARG(uap, ptr);
232 SCARG(&bma, msgsz) = SCARG(uap, a2);
233 SCARG(&bma, msgflg) = SCARG(uap, a3);
234
235 return sys_msgsnd(l, &bma, retval);
236 }
237
238 inline int
239 linux_msgrcv(l, uap, retval)
240 struct lwp *l;
241 struct linux_sys_ipc_args /* {
242 syscallarg(int) what;
243 syscallarg(int) a1;
244 syscallarg(int) a2;
245 syscallarg(int) a3;
246 syscallarg(void *) ptr;
247 } */ *uap;
248 register_t *retval;
249 {
250 struct sys_msgrcv_args bma;
251 struct linux_msgrcv_msgarg kluge;
252 int error;
253
254 if ((error = copyin(SCARG(uap, ptr), &kluge, sizeof kluge)))
255 return error;
256
257 SCARG(&bma, msqid) = SCARG(uap, a1);
258 SCARG(&bma, msgp) = kluge.msg;
259 SCARG(&bma, msgsz) = SCARG(uap, a2);
260 SCARG(&bma, msgtyp) = kluge.type;
261 SCARG(&bma, msgflg) = SCARG(uap, a3);
262
263 return sys_msgrcv(l, &bma, retval);
264 }
265
266 inline int
267 linux_msgget(l, uap, retval)
268 struct lwp *l;
269 struct linux_sys_ipc_args /* {
270 syscallarg(int) what;
271 syscallarg(int) a1;
272 syscallarg(int) a2;
273 syscallarg(int) a3;
274 syscallarg(void *) ptr;
275 } */ *uap;
276 register_t *retval;
277 {
278 struct sys_msgget_args bma;
279
280 SCARG(&bma, key) = (key_t)SCARG(uap, a1);
281 SCARG(&bma, msgflg) = SCARG(uap, a2);
282
283 return sys_msgget(l, &bma, retval);
284 }
285
286 #endif /* SYSVMSG */
287
288 #ifdef SYSVSHM
289 /*
290 * shmdt(): this could have been mapped directly, if it wasn't for
291 * the extra indirection by the linux_ipc system call.
292 */
293 inline int
294 linux_shmdt(l, uap, retval)
295 struct lwp *l;
296 struct linux_sys_ipc_args /* {
297 syscallarg(int) what;
298 syscallarg(int) a1;
299 syscallarg(int) a2;
300 syscallarg(int) a3;
301 syscallarg(void *) ptr;
302 } */ *uap;
303 register_t *retval;
304 {
305 struct sys_shmdt_args bsa;
306
307 SCARG(&bsa, shmaddr) = SCARG(uap, ptr);
308
309 return sys_shmdt(l, &bsa, retval);
310 }
311
312 /*
313 * Same story as shmdt.
314 */
315 inline int
316 linux_shmget(l, uap, retval)
317 struct lwp *l;
318 struct linux_sys_ipc_args /* {
319 syscallarg(int) what;
320 syscallarg(int) a1;
321 syscallarg(int) a2;
322 syscallarg(int) a3;
323 syscallarg(void *) ptr;
324 } */ *uap;
325 register_t *retval;
326 {
327 struct sys_shmget_args bsa;
328
329 SCARG(&bsa, key) = SCARG(uap, a1);
330 SCARG(&bsa, size) = SCARG(uap, a2);
331 SCARG(&bsa, shmflg) = SCARG(uap, a3);
332
333 return linux_sys_shmget(l, &bsa, retval);
334 }
335
336 #endif /* SYSVSHM */
337