1 /*- 2 * Copyright (c) 1994-1995 S�ren Schmidt 3 * All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions 7 * are met: 8 * 1. Redistributions of source code must retain the above copyright 9 * notice, this list of conditions and the following disclaimer 10 * in this position and unchanged. 11 * 2. Redistributions in binary form must reproduce the above copyright 12 * notice, this list of conditions and the following disclaimer in the 13 * documentation and/or other materials provided with the distribution. 14 * 3. The name of the author may not be used to endorse or promote products 15 * derived from this software without specific prior written permission 16 * 17 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 18 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 19 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 20 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 21 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 22 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 23 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 24 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 25 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 26 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 27 * 28 * $FreeBSD$ 29 */ 30 31 #include <sys/param.h> 32 #include <sys/systm.h> 33 #include <sys/sysproto.h> 34 #include <sys/proc.h> 35 #include <sys/sem.h> 36 #include <sys/shm.h> 37 38 #include <machine/../linux/linux.h> 39 #include <machine/../linux/linux_proto.h> 40 #include <compat/linux/linux_ipc.h> 41 #include <compat/linux/linux_util.h> 42 43 struct l_seminfo { 44 l_int semmap; 45 l_int semmni; 46 l_int semmns; 47 l_int semmnu; 48 l_int semmsl; 49 l_int semopm; 50 l_int semume; 51 l_int semusz; 52 l_int semvmx; 53 l_int semaem; 54 }; 55 56 struct l_shminfo { 57 l_int shmmax; 58 l_int shmmin; 59 l_int shmmni; 60 l_int shmseg; 61 l_int shmall; 62 }; 63 64 struct l_shm_info { 65 l_int used_ids; 66 l_ulong shm_tot; /* total allocated shm */ 67 l_ulong shm_rss; /* total resident shm */ 68 l_ulong shm_swp; /* total swapped shm */ 69 l_ulong swap_attempts; 70 l_ulong swap_successes; 71 }; 72 73 static void 74 bsd_to_linux_shminfo( struct shminfo *bpp, struct l_shminfo *lpp) 75 { 76 lpp->shmmax = bpp->shmmax; 77 lpp->shmmin = bpp->shmmin; 78 lpp->shmmni = bpp->shmmni; 79 lpp->shmseg = bpp->shmseg; 80 lpp->shmall = bpp->shmall; 81 } 82 83 static void 84 bsd_to_linux_shm_info( struct shm_info *bpp, struct l_shm_info *lpp) 85 { 86 lpp->used_ids = bpp->used_ids ; 87 lpp->shm_tot = bpp->shm_tot ; 88 lpp->shm_rss = bpp->shm_rss ; 89 lpp->shm_swp = bpp->shm_swp ; 90 lpp->swap_attempts = bpp->swap_attempts ; 91 lpp->swap_successes = bpp->swap_successes ; 92 } 93 94 struct l_ipc_perm { 95 l_key_t key; 96 l_uid16_t uid; 97 l_gid16_t gid; 98 l_uid16_t cuid; 99 l_gid16_t cgid; 100 l_ushort mode; 101 l_ushort seq; 102 }; 103 104 static void 105 linux_to_bsd_ipc_perm(struct l_ipc_perm *lpp, struct ipc_perm *bpp) 106 { 107 bpp->key = lpp->key; 108 bpp->uid = lpp->uid; 109 bpp->gid = lpp->gid; 110 bpp->cuid = lpp->cuid; 111 bpp->cgid = lpp->cgid; 112 bpp->mode = lpp->mode; 113 bpp->seq = lpp->seq; 114 } 115 116 117 static void 118 bsd_to_linux_ipc_perm(struct ipc_perm *bpp, struct l_ipc_perm *lpp) 119 { 120 lpp->key = bpp->key; 121 lpp->uid = bpp->uid; 122 lpp->gid = bpp->gid; 123 lpp->cuid = bpp->cuid; 124 lpp->cgid = bpp->cgid; 125 lpp->mode = bpp->mode; 126 lpp->seq = bpp->seq; 127 } 128 129 struct l_semid_ds { 130 struct l_ipc_perm sem_perm; 131 l_time_t sem_otime; 132 l_time_t sem_ctime; 133 void *sem_base; 134 void *sem_pending; 135 void *sem_pending_last; 136 void *undo; 137 l_ushort sem_nsems; 138 }; 139 140 struct l_shmid_ds { 141 struct l_ipc_perm shm_perm; 142 l_int shm_segsz; 143 l_time_t shm_atime; 144 l_time_t shm_dtime; 145 l_time_t shm_ctime; 146 l_ushort shm_cpid; 147 l_ushort shm_lpid; 148 l_short shm_nattch; 149 l_ushort private1; 150 void *private2; 151 void *private3; 152 }; 153 154 static void 155 linux_to_bsd_semid_ds(struct l_semid_ds *lsp, struct semid_ds *bsp) 156 { 157 linux_to_bsd_ipc_perm(&lsp->sem_perm, &bsp->sem_perm); 158 bsp->sem_otime = lsp->sem_otime; 159 bsp->sem_ctime = lsp->sem_ctime; 160 bsp->sem_nsems = lsp->sem_nsems; 161 bsp->sem_base = lsp->sem_base; 162 } 163 164 static void 165 bsd_to_linux_semid_ds(struct semid_ds *bsp, struct l_semid_ds *lsp) 166 { 167 bsd_to_linux_ipc_perm(&bsp->sem_perm, &lsp->sem_perm); 168 lsp->sem_otime = bsp->sem_otime; 169 lsp->sem_ctime = bsp->sem_ctime; 170 lsp->sem_nsems = bsp->sem_nsems; 171 lsp->sem_base = bsp->sem_base; 172 } 173 174 static void 175 linux_to_bsd_shmid_ds(struct l_shmid_ds *lsp, struct shmid_ds *bsp) 176 { 177 linux_to_bsd_ipc_perm(&lsp->shm_perm, &bsp->shm_perm); 178 bsp->shm_segsz = lsp->shm_segsz; 179 bsp->shm_lpid = lsp->shm_lpid; 180 bsp->shm_cpid = lsp->shm_cpid; 181 bsp->shm_nattch = lsp->shm_nattch; 182 bsp->shm_atime = lsp->shm_atime; 183 bsp->shm_dtime = lsp->shm_dtime; 184 bsp->shm_ctime = lsp->shm_ctime; 185 bsp->shm_internal = lsp->private3; /* this goes (yet) SOS */ 186 } 187 188 static void 189 bsd_to_linux_shmid_ds(struct shmid_ds *bsp, struct l_shmid_ds *lsp) 190 { 191 bsd_to_linux_ipc_perm(&bsp->shm_perm, &lsp->shm_perm); 192 lsp->shm_segsz = bsp->shm_segsz; 193 lsp->shm_lpid = bsp->shm_lpid; 194 lsp->shm_cpid = bsp->shm_cpid; 195 lsp->shm_nattch = bsp->shm_nattch; 196 lsp->shm_atime = bsp->shm_atime; 197 lsp->shm_dtime = bsp->shm_dtime; 198 lsp->shm_ctime = bsp->shm_ctime; 199 lsp->private3 = bsp->shm_internal; /* this goes (yet) SOS */ 200 } 201 202 int 203 linux_semop(struct thread *td, struct linux_semop_args *args) 204 { 205 struct semop_args /* { 206 int semid; 207 struct sembuf *sops; 208 int nsops; 209 } */ bsd_args; 210 211 bsd_args.semid = args->semid; 212 bsd_args.sops = (struct sembuf *)args->tsops; 213 bsd_args.nsops = args->nsops; 214 return semop(td, &bsd_args); 215 } 216 217 int 218 linux_semget(struct thread *td, struct linux_semget_args *args) 219 { 220 struct semget_args /* { 221 key_t key; 222 int nsems; 223 int semflg; 224 } */ bsd_args; 225 226 bsd_args.key = args->key; 227 bsd_args.nsems = args->nsems; 228 bsd_args.semflg = args->semflg; 229 return semget(td, &bsd_args); 230 } 231 232 int 233 linux_semctl(struct thread *td, struct linux_semctl_args *args) 234 { 235 struct l_semid_ds linux_semid; 236 struct __semctl_args /* { 237 int semid; 238 int semnum; 239 int cmd; 240 union semun *arg; 241 } */ bsd_args; 242 struct l_seminfo linux_seminfo; 243 int error; 244 union semun *unptr; 245 caddr_t sg; 246 247 sg = stackgap_init(); 248 249 /* Make sure the arg parameter can be copied in. */ 250 unptr = stackgap_alloc(&sg, sizeof(union semun)); 251 bcopy(&args->arg, unptr, sizeof(union semun)); 252 253 bsd_args.semid = args->semid; 254 bsd_args.semnum = args->semnum; 255 bsd_args.arg = unptr; 256 257 switch (args->cmd) { 258 case LINUX_IPC_RMID: 259 bsd_args.cmd = IPC_RMID; 260 break; 261 case LINUX_GETNCNT: 262 bsd_args.cmd = GETNCNT; 263 break; 264 case LINUX_GETPID: 265 bsd_args.cmd = GETPID; 266 break; 267 case LINUX_GETVAL: 268 bsd_args.cmd = GETVAL; 269 break; 270 case LINUX_GETZCNT: 271 bsd_args.cmd = GETZCNT; 272 break; 273 case LINUX_SETVAL: 274 bsd_args.cmd = SETVAL; 275 break; 276 case LINUX_IPC_SET: 277 bsd_args.cmd = IPC_SET; 278 error = copyin((caddr_t)args->arg.buf, &linux_semid, 279 sizeof(linux_semid)); 280 if (error) 281 return (error); 282 unptr->buf = stackgap_alloc(&sg, sizeof(struct semid_ds)); 283 linux_to_bsd_semid_ds(&linux_semid, unptr->buf); 284 return __semctl(td, &bsd_args); 285 case LINUX_IPC_STAT: 286 case LINUX_SEM_STAT: 287 if( args->cmd == LINUX_IPC_STAT ) 288 bsd_args.cmd = IPC_STAT; 289 else 290 bsd_args.cmd = SEM_STAT; 291 unptr->buf = stackgap_alloc(&sg, sizeof(struct semid_ds)); 292 error = __semctl(td, &bsd_args); 293 if (error) 294 return error; 295 td->td_retval[0] = IXSEQ_TO_IPCID(bsd_args.semid, 296 unptr->buf->sem_perm); 297 bsd_to_linux_semid_ds(unptr->buf, &linux_semid); 298 return copyout(&linux_semid, (caddr_t)args->arg.buf, 299 sizeof(linux_semid)); 300 case LINUX_IPC_INFO: 301 case LINUX_SEM_INFO: 302 error = copyin((caddr_t)args->arg.buf, &linux_seminfo, 303 sizeof(linux_seminfo) ); 304 if (error) 305 return error; 306 bcopy(&seminfo, &linux_seminfo, sizeof(linux_seminfo) ); 307 /* XXX BSD equivalent? 308 #define used_semids 10 309 #define used_sems 10 310 linux_seminfo.semusz = used_semids; 311 linux_seminfo.semaem = used_sems; 312 */ 313 error = copyout((caddr_t)&linux_seminfo, (caddr_t)args->arg.buf, 314 sizeof(linux_seminfo) ); 315 if (error) 316 return error; 317 td->td_retval[0] = seminfo.semmni; 318 return 0; /* No need for __semctl call */ 319 case LINUX_GETALL: 320 /* FALLTHROUGH */ 321 case LINUX_SETALL: 322 /* FALLTHROUGH */ 323 default: 324 uprintf("linux: 'ipc' typ=%d not implemented\n", args->cmd); 325 return EINVAL; 326 } 327 return __semctl(td, &bsd_args); 328 } 329 330 int 331 linux_msgsnd(struct thread *td, struct linux_msgsnd_args *args) 332 { 333 struct msgsnd_args /* { 334 int msqid; 335 void *msgp; 336 size_t msgsz; 337 int msgflg; 338 } */ bsd_args; 339 340 bsd_args.msqid = args->msqid; 341 bsd_args.msgp = args->msgp; 342 bsd_args.msgsz = args->msgsz; 343 bsd_args.msgflg = args->msgflg; 344 return msgsnd(td, &bsd_args); 345 } 346 347 int 348 linux_msgrcv(struct thread *td, struct linux_msgrcv_args *args) 349 { 350 struct msgrcv_args /* { 351 int msqid; 352 void *msgp; 353 size_t msgsz; 354 long msgtyp; 355 int msgflg; 356 } */ bsd_args; 357 358 bsd_args.msqid = args->msqid; 359 bsd_args.msgp = args->msgp; 360 bsd_args.msgsz = args->msgsz; 361 bsd_args.msgtyp = args->msgtyp; 362 bsd_args.msgflg = args->msgflg; 363 return msgrcv(td, &bsd_args); 364 } 365 366 int 367 linux_msgget(struct thread *td, struct linux_msgget_args *args) 368 { 369 struct msgget_args /* { 370 key_t key; 371 int msgflg; 372 } */ bsd_args; 373 374 bsd_args.key = args->key; 375 bsd_args.msgflg = args->msgflg; 376 return msgget(td, &bsd_args); 377 } 378 379 int 380 linux_msgctl(struct thread *td, struct linux_msgctl_args *args) 381 { 382 struct msgctl_args /* { 383 int msqid; 384 int cmd; 385 struct msqid_ds *buf; 386 } */ bsd_args; 387 int error; 388 389 bsd_args.msqid = args->msqid; 390 bsd_args.cmd = args->cmd; 391 bsd_args.buf = (struct msqid_ds *)args->buf; 392 error = msgctl(td, &bsd_args); 393 return ((args->cmd == LINUX_IPC_RMID && error == EINVAL) ? 0 : error); 394 } 395 396 int 397 linux_shmat(struct thread *td, struct linux_shmat_args *args) 398 { 399 struct shmat_args /* { 400 int shmid; 401 void *shmaddr; 402 int shmflg; 403 } */ bsd_args; 404 int error; 405 406 bsd_args.shmid = args->shmid; 407 bsd_args.shmaddr = args->shmaddr; 408 bsd_args.shmflg = args->shmflg; 409 if ((error = shmat(td, &bsd_args))) 410 return error; 411 #ifdef __i386__ 412 if ((error = copyout(td->td_retval, (caddr_t)args->raddr, sizeof(l_ulong)))) 413 return error; 414 td->td_retval[0] = 0; 415 #endif 416 return 0; 417 } 418 419 int 420 linux_shmdt(struct thread *td, struct linux_shmdt_args *args) 421 { 422 struct shmdt_args /* { 423 void *shmaddr; 424 } */ bsd_args; 425 426 bsd_args.shmaddr = args->shmaddr; 427 return shmdt(td, &bsd_args); 428 } 429 430 int 431 linux_shmget(struct thread *td, struct linux_shmget_args *args) 432 { 433 struct shmget_args /* { 434 key_t key; 435 int size; 436 int shmflg; 437 } */ bsd_args; 438 439 bsd_args.key = args->key; 440 bsd_args.size = args->size; 441 bsd_args.shmflg = args->shmflg; 442 return shmget(td, &bsd_args); 443 } 444 445 int 446 linux_shmctl(struct thread *td, struct linux_shmctl_args *args) 447 { 448 struct l_shmid_ds linux_shmid; 449 struct l_shminfo linux_shminfo; 450 struct l_shm_info linux_shm_info; 451 struct shmctl_args /* { 452 int shmid; 453 int cmd; 454 struct shmid_ds *buf; 455 } */ bsd_args; 456 int error; 457 caddr_t sg = stackgap_init(); 458 459 switch (args->cmd) { 460 461 case LINUX_IPC_INFO: 462 bsd_args.shmid = args->shmid; 463 bsd_args.cmd = IPC_INFO; 464 bsd_args.buf = (struct shmid_ds*)stackgap_alloc(&sg, sizeof(struct shminfo)); 465 if ((error = shmctl(td, &bsd_args))) 466 return error; 467 bsd_to_linux_shminfo( (struct shminfo *)bsd_args.buf, &linux_shminfo ); 468 return copyout(&linux_shminfo, (caddr_t)args->buf, sizeof(shminfo)); 469 470 case LINUX_SHM_INFO: 471 bsd_args.shmid = args->shmid; 472 bsd_args.cmd = SHM_INFO; 473 bsd_args.buf = (struct shmid_ds*)stackgap_alloc(&sg, sizeof(struct shm_info)); 474 if ((error = shmctl(td, &bsd_args))) 475 return error; 476 bsd_to_linux_shm_info( (struct shm_info *)bsd_args.buf, &linux_shm_info ); 477 return copyout(&linux_shm_info, (caddr_t)args->buf, sizeof(struct shm_info)); 478 479 case LINUX_IPC_STAT: 480 bsd_args.shmid = args->shmid; 481 bsd_args.cmd = IPC_STAT; 482 bsd_args.buf = (struct shmid_ds*)stackgap_alloc(&sg, sizeof(struct shmid_ds)); 483 if ((error = shmctl(td, &bsd_args))) 484 return error; 485 bsd_to_linux_shmid_ds(bsd_args.buf, &linux_shmid); 486 return copyout(&linux_shmid, (caddr_t)args->buf, sizeof(linux_shmid)); 487 488 case LINUX_SHM_STAT: 489 bsd_args.shmid = args->shmid; 490 bsd_args.cmd = SHM_STAT; 491 bsd_args.buf = (struct shmid_ds*)stackgap_alloc(&sg, sizeof(struct shmid_ds)); 492 if ((error = shmctl(td, &bsd_args))) { 493 return error; 494 } 495 bsd_to_linux_shmid_ds(bsd_args.buf, &linux_shmid); 496 return copyout(&linux_shmid, (caddr_t)args->buf, sizeof(linux_shmid)); 497 498 case LINUX_IPC_SET: 499 if ((error = copyin((caddr_t)args->buf, &linux_shmid, 500 sizeof(linux_shmid)))) 501 return error; 502 bsd_args.buf = (struct shmid_ds*)stackgap_alloc(&sg, sizeof(struct shmid_ds)); 503 linux_to_bsd_shmid_ds(&linux_shmid, bsd_args.buf); 504 bsd_args.shmid = args->shmid; 505 bsd_args.cmd = IPC_SET; 506 return shmctl(td, &bsd_args); 507 508 case LINUX_IPC_RMID: 509 bsd_args.shmid = args->shmid; 510 bsd_args.cmd = IPC_RMID; 511 if (args->buf == NULL) 512 bsd_args.buf = NULL; 513 else { 514 if ((error = copyin((caddr_t)args->buf, &linux_shmid, 515 sizeof(linux_shmid)))) 516 return error; 517 bsd_args.buf = (struct shmid_ds*)stackgap_alloc(&sg, sizeof(struct shmid_ds)); 518 linux_to_bsd_shmid_ds(&linux_shmid, bsd_args.buf); 519 } 520 return shmctl(td, &bsd_args); 521 522 case LINUX_SHM_LOCK: 523 case LINUX_SHM_UNLOCK: 524 default: 525 uprintf("linux: 'ipc' typ=%d not implemented\n", args->cmd); 526 return EINVAL; 527 } 528 } 529