1 /* $NetBSD: linux_ipccall.c,v 1.2 1995/03/08 17:27:42 fvdl Exp $ */ 2 3 /* 4 * Copyright (c) 1995 Frank van der Linden 5 * All rights reserved. 6 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted provided that the following conditions 9 * are met: 10 * 1. Redistributions of source code must retain the above copyright 11 * notice, this list of conditions and the following disclaimer. 12 * 2. Redistributions in binary form must reproduce the above copyright 13 * notice, this list of conditions and the following disclaimer in the 14 * documentation and/or other materials provided with the distribution. 15 * 3. All advertising materials mentioning features or use of this software 16 * must display the following acknowledgement: 17 * This product includes software developed for the NetBSD Project 18 * by Frank van der Linden 19 * 4. The name of the author may not be used to endorse or promote products 20 * derived from this software without specific prior written permission 21 * 22 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 23 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 24 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 25 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 26 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 27 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 28 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 29 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 30 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 31 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 32 */ 33 34 #include <sys/types.h> 35 #include <sys/param.h> 36 #include <sys/kernel.h> 37 #include <sys/shm.h> 38 #include <sys/msg.h> 39 #include <sys/proc.h> 40 #include <sys/uio.h> 41 #include <sys/time.h> 42 #include <sys/malloc.h> 43 #include <sys/mman.h> 44 #include <sys/systm.h> 45 #include <sys/stat.h> 46 47 #include <sys/mount.h> 48 #include <sys/syscallargs.h> 49 50 #include <compat/linux/linux_types.h> 51 #include <compat/linux/linux_syscallargs.h> 52 #include <compat/linux/linux_util.h> 53 #include <compat/linux/linux_ipc.h> 54 #include <compat/linux/linux_msg.h> 55 #include <compat/linux/linux_shm.h> 56 #include <compat/linux/linux_ipccall.h> 57 58 /* 59 * Stuff to deal with the SysV ipc/shm/semaphore interface in Linux. 60 * The main difference is, that Linux handles it all via one 61 * system call, which has the usual maximum amount of 5 arguments. 62 * This results in a kludge for calls that take 6 of them. 63 * 64 * The SYSVXXXX options have to be enabled to get the appropriate 65 * functions to work. 66 */ 67 68 #ifdef SYSVSEM 69 static int linux_semop __P((struct proc *, struct linux_ipc_args *, 70 register_t *)); 71 static int linux_semget __P((struct proc *, struct linux_ipc_args *, 72 register_t *)); 73 static int linux_semctl __P((struct proc *, struct linux_ipc_args *, 74 register_t *)); 75 #endif 76 77 #ifdef SYSVMSG 78 static int linux_msgsnd __P((struct proc *, struct linux_ipc_args *, 79 register_t *)); 80 static int linux_msgrcv __P((struct proc *, struct linux_ipc_args *, 81 register_t *)); 82 static int linux_msgop __P((struct proc *, struct linux_ipc_args *, 83 register_t *)); 84 static int linux_msgctl __P((struct proc *, struct linux_ipc_args *, 85 register_t *)); 86 #endif 87 88 #ifdef SYSVSHM 89 static int linux_shmat __P((struct proc *, struct linux_ipc_args *, 90 register_t *)); 91 static int linux_shmdt __P((struct proc *, struct linux_ipc_args *, 92 register_t *)); 93 static int linux_shmget __P((struct proc *, struct linux_ipc_args *, 94 register_t *)); 95 static int linux_shmctl __P((struct proc *, struct linux_ipc_args *, 96 register_t *)); 97 #endif 98 99 100 int 101 linux_ipc(p, uap, retval) 102 struct proc *p; 103 struct linux_ipc_args /* { 104 syscallarg(int) what; 105 syscallarg(int) a1; 106 syscallarg(int) a2; 107 syscallarg(int) a3; 108 syscallarg(caddr_t) ptr; 109 } */ *uap; 110 register_t *retval; 111 { 112 int what, error; 113 114 switch (SCARG(uap, what)) { 115 #ifdef SYSVSEM 116 case LINUX_SYS_semop: 117 return linux_semop(p, uap, retval); 118 case LINUX_SYS_semget: 119 return linux_semget(p, uap, retval); 120 case LINUX_SYS_semctl: 121 return linux_semctl(p, uap, retval); 122 #endif 123 #ifdef SYSVMSG 124 case LINUX_SYS_msgsnd: 125 return linux_msgsnd(p, uap, retval); 126 case LINUX_SYS_msgrcv: 127 return linux_msgrcv(p, uap, retval); 128 case LINUX_SYS_msgget: 129 return linux_msgget(p, uap, retval); 130 case LINUX_SYS_msgctl: 131 return linux_msgctl(p, uap, retval); 132 #endif 133 #ifdef SYSVSHM 134 case LINUX_SYS_shmat: 135 return linux_shmat(p, uap, retval); 136 case LINUX_SYS_shmdt: 137 return linux_shmdt(p, uap, retval); 138 case LINUX_SYS_shmget: 139 return linux_shmget(p, uap, retval); 140 case LINUX_SYS_shmctl: 141 return linux_shmctl(p, uap, retval); 142 #endif 143 default: 144 return ENOSYS; 145 } 146 } 147 148 /* 149 * Convert between Linux and NetBSD ipc_perm structures. Only the 150 * order of the fields is different. 151 */ 152 static void 153 linux_to_bsd_ipc_perm(lpp, bpp) 154 struct linux_ipc_perm *lpp; 155 struct ipc_perm *bpp; 156 { 157 bpp->key = lpp->l_key; 158 bpp->uid = lpp->l_uid; 159 bpp->gid = lpp->l_gid; 160 bpp->cuid = lpp->l_cuid; 161 bpp->cgid = lpp->l_cgid; 162 bpp->mode = lpp->l_mode; 163 bpp->seq = lpp->l_seq; 164 } 165 166 167 static void 168 bsd_to_linux_ipc_perm(bpp, lpp) 169 struct ipc_perm *bpp; 170 struct linux_ipc_perm *lpp; 171 { 172 lpp->l_key = bpp->key; 173 lpp->l_uid = bpp->uid; 174 lpp->l_gid = bpp->gid; 175 lpp->l_cuid = bpp->cuid; 176 lpp->l_cgid = bpp->cgid; 177 lpp->l_mode = bpp->mode; 178 lpp->l_seq = bpp->seq; 179 } 180 181 #ifdef SYSVSEM 182 /* 183 * Semaphore operations: not implemented yet. 184 */ 185 int 186 linux_semop(p, uap, retval) 187 struct proc *p; 188 struct linux_ipc_args /* { 189 syscallarg(int) what; 190 syscallarg(int) a1; 191 syscallarg(int) a2; 192 syscallarg(int) a3; 193 syscallarg(caddr_t) ptr; 194 } */ *uap; 195 register_t *retval; 196 { 197 return ENOSYS; 198 } 199 200 int 201 linux_semget(p, uap, retval) 202 struct proc *p; 203 struct linux_ipc_args /* { 204 syscallarg(int) what; 205 syscallarg(int) a1; 206 syscallarg(int) a2; 207 syscallarg(int) a3; 208 syscallarg(caddr_t) ptr; 209 } */ *uap; 210 register_t *retval; 211 { 212 return ENOSYS; 213 } 214 215 int 216 linux_semctl(p, uap, retval) 217 struct proc *p; 218 struct linux_ipc_args /* { 219 syscallarg(int) what; 220 syscallarg(int) a1; 221 syscallarg(int) a2; 222 syscallarg(int) a3; 223 syscallarg(caddr_t) ptr; 224 } */ *uap; 225 register_t *retval; 226 { 227 return ENOSYS; 228 } 229 #endif /* SYSVSEM */ 230 231 #ifdef SYSVMSG 232 /* 233 * Msg functions: not implemented yet. 234 */ 235 int 236 linux_msgsnd(p, uap, retval) 237 struct proc *p; 238 struct linux_ipc_args /* { 239 syscallarg(int) what; 240 syscallarg(int) a1; 241 syscallarg(int) a2; 242 syscallarg(int) a3; 243 syscallarg(caddr_t) ptr; 244 } */ *uap; 245 register_t *retval; 246 { 247 return ENOSYS; 248 } 249 250 int 251 linux_msgrcv(p, uap, retval) 252 struct proc *p; 253 struct linux_ipc_args /* { 254 syscallarg(int) what; 255 syscallarg(int) a1; 256 syscallarg(int) a2; 257 syscallarg(int) a3; 258 syscallarg(caddr_t) ptr; 259 } */ *uap; 260 register_t *retval; 261 { 262 return ENOSYS; 263 } 264 265 int 266 linux_msgget(p, uap, retval) 267 struct proc *p; 268 struct linux_ipc_args /* { 269 syscallarg(int) what; 270 syscallarg(int) a1; 271 syscallarg(int) a2; 272 syscallarg(int) a3; 273 syscallarg(caddr_t) ptr; 274 } */ *uap; 275 register_t *retval; 276 { 277 return ENOSYS; 278 } 279 280 int 281 linux_msgctl(p, uap, retval) 282 struct proc *p; 283 struct linux_ipc_args /* { 284 syscallarg(int) what; 285 syscallarg(int) a1; 286 syscallarg(int) a2; 287 syscallarg(int) a3; 288 syscallarg(caddr_t) ptr; 289 } */ *uap; 290 register_t *retval; 291 { 292 return ENOSYS; 293 } 294 #endif /* SYSVMSG */ 295 296 #ifdef SYSVSHM 297 /* 298 * shmat(2). Very straightforward, except that Linux passes a pointer 299 * in which the return value is to be passed. This is subsequently 300 * handled by libc, apparently. 301 */ 302 int 303 linux_shmat(p, uap, retval) 304 struct proc *p; 305 struct linux_ipc_args /* { 306 syscallarg(int) what; 307 syscallarg(int) a1; 308 syscallarg(int) a2; 309 syscallarg(int) a3; 310 syscallarg(caddr_t) ptr; 311 } */ *uap; 312 register_t *retval; 313 { 314 struct shmat_args bsa; 315 int error; 316 317 SCARG(&bsa, shmid) = SCARG(uap, a1); 318 SCARG(&bsa, shmaddr) = SCARG(uap, ptr); 319 SCARG(&bsa, shmflg) = SCARG(uap, a2); 320 321 if ((error = shmat(p, &bsa, retval))) 322 return error; 323 324 if ((error = copyout(&retval[0], (caddr_t) SCARG(uap, a3), 325 sizeof retval[0]))) 326 return error; 327 328 retval[0] = 0; 329 330 return 0; 331 } 332 333 /* 334 * shmdt(): this could have been mapped directly, if it wasn't for 335 * the extra indirection by the linux_ipc system call. 336 */ 337 int 338 linux_shmdt(p, uap, retval) 339 struct proc *p; 340 struct linux_ipc_args /* { 341 syscallarg(int) what; 342 syscallarg(int) a1; 343 syscallarg(int) a2; 344 syscallarg(int) a3; 345 syscallarg(caddr_t) ptr; 346 } */ *uap; 347 register_t *retval; 348 { 349 struct shmdt_args bsa; 350 351 SCARG(&bsa, shmaddr) = SCARG(uap, ptr); 352 return shmdt(p, &bsa, retval); 353 } 354 355 /* 356 * Same story as shmdt. 357 */ 358 int 359 linux_shmget(p, uap, retval) 360 struct proc *p; 361 struct linux_ipc_args /* { 362 syscallarg(int) what; 363 syscallarg(int) a1; 364 syscallarg(int) a2; 365 syscallarg(int) a3; 366 syscallarg(caddr_t) ptr; 367 } */ *uap; 368 register_t *retval; 369 { 370 struct shmget_args bsa; 371 372 SCARG(&bsa, key) = SCARG(uap, a1); 373 SCARG(&bsa, size) = SCARG(uap, a2); 374 SCARG(&bsa, shmflg) = SCARG(uap, a3); 375 return shmget(p, &bsa, retval); 376 } 377 378 /* 379 * Convert between Linux and NetBSD shmid_ds structures. 380 * The order of the fields is once again the difference, and 381 * we also need a place to store the internal data pointer 382 * in, which is unfortunately stored in this structure. 383 * 384 * We abuse a Linux internal field for that. 385 */ 386 static void 387 linux_to_bsd_shmid_ds(lsp, bsp) 388 struct linux_shmid_ds *lsp; 389 struct shmid_ds *bsp; 390 { 391 linux_to_bsd_ipc_perm(&lsp->l_shm_perm, &bsp->shm_perm); 392 bsp->shm_segsz = lsp->l_shm_segsz; 393 bsp->shm_lpid = lsp->l_shm_lpid; 394 bsp->shm_cpid = lsp->l_shm_cpid; 395 bsp->shm_nattch = lsp->l_shm_nattch; 396 bsp->shm_atime = lsp->l_shm_atime; 397 bsp->shm_dtime = lsp->l_shm_dtime; 398 bsp->shm_ctime = lsp->l_shm_ctime; 399 bsp->shm_internal = lsp->l_private2; /* XXX Oh well. */ 400 } 401 402 static void 403 bsd_to_linux_shmid_ds(bsp, lsp) 404 struct shmid_ds *bsp; 405 struct linux_shmid_ds *lsp; 406 { 407 bsd_to_linux_ipc_perm(&bsp->shm_perm, &lsp->l_shm_perm); 408 lsp->l_shm_segsz = bsp->shm_segsz; 409 lsp->l_shm_lpid = bsp->shm_lpid; 410 lsp->l_shm_cpid = bsp->shm_cpid; 411 lsp->l_shm_nattch = bsp->shm_nattch; 412 lsp->l_shm_atime = bsp->shm_atime; 413 lsp->l_shm_dtime = bsp->shm_dtime; 414 lsp->l_shm_ctime = bsp->shm_ctime; 415 lsp->l_private2 = bsp->shm_internal; /* XXX */ 416 } 417 418 /* 419 * shmctl. Not implemented (for now): IPC_INFO, SHM_INFO, SHM_STAT 420 * SHM_LOCK and SHM_UNLOCK are passed on, but currently not implemented 421 * by NetBSD itself. 422 * 423 * The usual structure conversion and massaging is done. 424 */ 425 int 426 linux_shmctl(p, uap, retval) 427 struct proc *p; 428 struct linux_ipc_args /* { 429 syscallarg(int) what; 430 syscallarg(int) a1; 431 syscallarg(int) a2; 432 syscallarg(int) a3; 433 syscallarg(caddr_t) ptr; 434 } */ *uap; 435 register_t *retval; 436 { 437 int error; 438 caddr_t sg; 439 struct shmctl_args bsa; 440 struct shmid_ds *bsp, bs; 441 struct linux_shmid_ds lseg; 442 443 switch (SCARG(uap, a2)) { 444 case LINUX_IPC_STAT: 445 sg = stackgap_init(); 446 bsp = stackgap_alloc(&sg, sizeof (struct shmid_ds)); 447 SCARG(&bsa, shmid) = SCARG(uap, a1); 448 SCARG(&bsa, cmd) = IPC_STAT; 449 SCARG(&bsa, buf) = bsp; 450 if ((error = shmctl(p, &bsa, retval))) 451 return error; 452 if ((error = copyin((caddr_t) &bs, (caddr_t) bsp, sizeof bs))) 453 return error; 454 bsd_to_linux_shmid_ds(&bs, &lseg); 455 return copyout((caddr_t) &lseg, SCARG(uap, ptr), sizeof lseg); 456 case LINUX_IPC_SET: 457 if ((error = copyin(SCARG(uap, ptr), (caddr_t) &lseg, 458 sizeof lseg))) 459 return error; 460 linux_to_bsd_shmid_ds(&lseg, &bs); 461 sg = stackgap_init(); 462 bsp = stackgap_alloc(&sg, sizeof (struct shmid_ds)); 463 if ((error = copyout((caddr_t) &bs, (caddr_t) bsp, sizeof bs))) 464 return error; 465 SCARG(&bsa, shmid) = SCARG(uap, a1); 466 SCARG(&bsa, cmd) = IPC_SET; 467 SCARG(&bsa, buf) = bsp; 468 return shmctl(p, &bsa, retval); 469 case LINUX_IPC_RMID: 470 case LINUX_SHM_LOCK: 471 case LINUX_SHM_UNLOCK: 472 SCARG(&bsa, shmid) = SCARG(uap, a1); 473 switch (SCARG(uap, a2)) { 474 case LINUX_IPC_RMID: 475 SCARG(&bsa, cmd) = IPC_RMID; 476 break; 477 case LINUX_SHM_LOCK: 478 SCARG(&bsa, cmd) = SHM_LOCK; 479 break; 480 case LINUX_SHM_UNLOCK: 481 SCARG(&bsa, cmd) = SHM_UNLOCK; 482 break; 483 } 484 if ((error = copyin(SCARG(uap, ptr), (caddr_t) &lseg, 485 sizeof lseg))) 486 return error; 487 linux_to_bsd_shmid_ds(&lseg, &bs); 488 sg = stackgap_init(); 489 bsp = stackgap_alloc(&sg, sizeof (struct shmid_ds)); 490 if ((error = copyout((caddr_t) &bs, (caddr_t) bsp, sizeof bs))) 491 return error; 492 SCARG(&bsa, buf) = bsp; 493 return shmctl(p, &bsa, retval); 494 case LINUX_IPC_INFO: 495 case LINUX_SHM_STAT: 496 case LINUX_SHM_INFO: 497 default: 498 return EINVAL; 499 } 500 } 501 #endif /* SYSVSHM */ 502