1 /* $NetBSD: linux_sched.c,v 1.30 2006/05/14 21:24:50 elad Exp $ */ 2 3 /*- 4 * Copyright (c) 1999 The NetBSD Foundation, Inc. 5 * All rights reserved. 6 * 7 * This code is derived from software contributed to The NetBSD Foundation 8 * by Jason R. Thorpe of the Numerical Aerospace Simulation Facility, 9 * NASA Ames Research Center; by Matthias Scheler. 10 * 11 * Redistribution and use in source and binary forms, with or without 12 * modification, are permitted provided that the following conditions 13 * are met: 14 * 1. Redistributions of source code must retain the above copyright 15 * notice, this list of conditions and the following disclaimer. 16 * 2. Redistributions in binary form must reproduce the above copyright 17 * notice, this list of conditions and the following disclaimer in the 18 * documentation and/or other materials provided with the distribution. 19 * 3. All advertising materials mentioning features or use of this software 20 * must display the following acknowledgement: 21 * This product includes software developed by the NetBSD 22 * Foundation, Inc. and its contributors. 23 * 4. Neither the name of The NetBSD Foundation nor the names of its 24 * contributors may be used to endorse or promote products derived 25 * from this software without specific prior written permission. 26 * 27 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 28 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 29 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 30 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 31 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 32 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 33 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 34 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 35 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 36 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 37 * POSSIBILITY OF SUCH DAMAGE. 38 */ 39 40 /* 41 * Linux compatibility module. Try to deal with scheduler related syscalls. 42 */ 43 44 #include <sys/cdefs.h> 45 __KERNEL_RCSID(0, "$NetBSD: linux_sched.c,v 1.30 2006/05/14 21:24:50 elad Exp $"); 46 47 #include <sys/param.h> 48 #include <sys/mount.h> 49 #include <sys/proc.h> 50 #include <sys/systm.h> 51 #include <sys/sysctl.h> 52 #include <sys/malloc.h> 53 #include <sys/sa.h> 54 #include <sys/syscallargs.h> 55 #include <sys/wait.h> 56 #include <sys/kauth.h> 57 58 #include <machine/cpu.h> 59 60 #include <compat/linux/common/linux_types.h> 61 #include <compat/linux/common/linux_signal.h> 62 #include <compat/linux/common/linux_machdep.h> /* For LINUX_NPTL */ 63 #include <compat/linux/common/linux_emuldata.h> 64 65 #include <compat/linux/linux_syscallargs.h> 66 67 #include <compat/linux/common/linux_sched.h> 68 69 int 70 linux_sys_clone(l, v, retval) 71 struct lwp *l; 72 void *v; 73 register_t *retval; 74 { 75 struct linux_sys_clone_args /* { 76 syscallarg(int) flags; 77 syscallarg(void *) stack; 78 #ifdef LINUX_NPTL 79 syscallarg(void *) parent_tidptr; 80 syscallarg(void *) child_tidptr; 81 #endif 82 } */ *uap = v; 83 int flags, sig; 84 int error; 85 #ifdef LINUX_NPTL 86 struct linux_emuldata *led; 87 #endif 88 89 /* 90 * We don't support the Linux CLONE_PID or CLONE_PTRACE flags. 91 */ 92 if (SCARG(uap, flags) & (LINUX_CLONE_PID|LINUX_CLONE_PTRACE)) 93 return (EINVAL); 94 95 /* 96 * Thread group implies shared signals. Shared signals 97 * imply shared VM. This matches what Linux kernel does. 98 */ 99 if (SCARG(uap, flags) & LINUX_CLONE_THREAD 100 && (SCARG(uap, flags) & LINUX_CLONE_SIGHAND) == 0) 101 return (EINVAL); 102 if (SCARG(uap, flags) & LINUX_CLONE_SIGHAND 103 && (SCARG(uap, flags) & LINUX_CLONE_VM) == 0) 104 return (EINVAL); 105 106 flags = 0; 107 108 if (SCARG(uap, flags) & LINUX_CLONE_VM) 109 flags |= FORK_SHAREVM; 110 if (SCARG(uap, flags) & LINUX_CLONE_FS) 111 flags |= FORK_SHARECWD; 112 if (SCARG(uap, flags) & LINUX_CLONE_FILES) 113 flags |= FORK_SHAREFILES; 114 if (SCARG(uap, flags) & LINUX_CLONE_SIGHAND) 115 flags |= FORK_SHARESIGS; 116 if (SCARG(uap, flags) & LINUX_CLONE_VFORK) 117 flags |= FORK_PPWAIT; 118 119 /* Thread should not issue a SIGCHLD on termination */ 120 if (SCARG(uap, flags) & LINUX_CLONE_THREAD) { 121 sig = 0; 122 } else { 123 sig = SCARG(uap, flags) & LINUX_CLONE_CSIGNAL; 124 if (sig < 0 || sig >= LINUX__NSIG) 125 return (EINVAL); 126 sig = linux_to_native_signo[sig]; 127 } 128 129 #ifdef LINUX_NPTL 130 led = (struct linux_emuldata *)l->l_proc->p_emuldata; 131 132 if (SCARG(uap, flags) & LINUX_CLONE_PARENT_SETTID) { 133 if (SCARG(uap, parent_tidptr) == NULL) { 134 printf("linux_sys_clone: NULL parent_tidptr\n"); 135 return EINVAL; 136 } 137 138 if ((error = copyout(&l->l_proc->p_pid, 139 SCARG(uap, parent_tidptr), 140 sizeof(l->l_proc->p_pid))) != 0) 141 return error; 142 } 143 144 /* CLONE_CHILD_CLEARTID: TID clear in the child on exit() */ 145 if (SCARG(uap, flags) & LINUX_CLONE_CHILD_CLEARTID) 146 led->child_clear_tid = SCARG(uap, child_tidptr); 147 else 148 led->child_clear_tid = NULL; 149 150 /* CLONE_CHILD_SETTID: TID set in the child on clone() */ 151 if (SCARG(uap, flags) & LINUX_CLONE_CHILD_SETTID) 152 led->child_set_tid = SCARG(uap, child_tidptr); 153 else 154 led->child_set_tid = NULL; 155 156 /* CLONE_SETTLS: new Thread Local Storage in the child */ 157 if (SCARG(uap, flags) & LINUX_CLONE_SETTLS) 158 led->set_tls = linux_get_newtls(l); 159 else 160 led->set_tls = 0; 161 #endif /* LINUX_NPTL */ 162 /* 163 * Note that Linux does not provide a portable way of specifying 164 * the stack area; the caller must know if the stack grows up 165 * or down. So, we pass a stack size of 0, so that the code 166 * that makes this adjustment is a noop. 167 */ 168 if ((error = fork1(l, flags, sig, SCARG(uap, stack), 0, 169 NULL, NULL, retval, NULL)) != 0) 170 return error; 171 172 return 0; 173 } 174 175 int 176 linux_sys_sched_setparam(cl, v, retval) 177 struct lwp *cl; 178 void *v; 179 register_t *retval; 180 { 181 struct linux_sys_sched_setparam_args /* { 182 syscallarg(linux_pid_t) pid; 183 syscallarg(const struct linux_sched_param *) sp; 184 } */ *uap = v; 185 struct proc *cp = cl->l_proc; 186 int error; 187 struct linux_sched_param lp; 188 struct proc *p; 189 190 /* 191 * We only check for valid parameters and return afterwards. 192 */ 193 194 if (SCARG(uap, pid) < 0 || SCARG(uap, sp) == NULL) 195 return EINVAL; 196 197 error = copyin(SCARG(uap, sp), &lp, sizeof(lp)); 198 if (error) 199 return error; 200 201 if (SCARG(uap, pid) != 0) { 202 kauth_cred_t pc = cp->p_cred; 203 204 if ((p = pfind(SCARG(uap, pid))) == NULL) 205 return ESRCH; 206 if (!(cp == p || 207 kauth_cred_geteuid(pc) == 0 || 208 kauth_cred_getuid(pc) == kauth_cred_getuid(p->p_cred) || 209 kauth_cred_geteuid(pc) == kauth_cred_getuid(p->p_cred) || 210 kauth_cred_getuid(pc) == kauth_cred_geteuid(p->p_cred) || 211 kauth_cred_geteuid(pc) == kauth_cred_geteuid(p->p_cred))) 212 return EPERM; 213 } 214 215 return 0; 216 } 217 218 int 219 linux_sys_sched_getparam(cl, v, retval) 220 struct lwp *cl; 221 void *v; 222 register_t *retval; 223 { 224 struct linux_sys_sched_getparam_args /* { 225 syscallarg(linux_pid_t) pid; 226 syscallarg(struct linux_sched_param *) sp; 227 } */ *uap = v; 228 struct proc *cp = cl->l_proc; 229 struct proc *p; 230 struct linux_sched_param lp; 231 232 /* 233 * We only check for valid parameters and return a dummy priority afterwards. 234 */ 235 if (SCARG(uap, pid) < 0 || SCARG(uap, sp) == NULL) 236 return EINVAL; 237 238 if (SCARG(uap, pid) != 0) { 239 kauth_cred_t pc = cp->p_cred; 240 241 if ((p = pfind(SCARG(uap, pid))) == NULL) 242 return ESRCH; 243 if (!(cp == p || 244 kauth_cred_geteuid(pc) == 0 || 245 kauth_cred_getuid(pc) == kauth_cred_getuid(p->p_cred) || 246 kauth_cred_geteuid(pc) == kauth_cred_getuid(p->p_cred) || 247 kauth_cred_getuid(pc) == kauth_cred_geteuid(p->p_cred) || 248 kauth_cred_geteuid(pc) == kauth_cred_geteuid(p->p_cred))) 249 return EPERM; 250 } 251 252 lp.sched_priority = 0; 253 return copyout(&lp, SCARG(uap, sp), sizeof(lp)); 254 } 255 256 int 257 linux_sys_sched_setscheduler(cl, v, retval) 258 struct lwp *cl; 259 void *v; 260 register_t *retval; 261 { 262 struct linux_sys_sched_setscheduler_args /* { 263 syscallarg(linux_pid_t) pid; 264 syscallarg(int) policy; 265 syscallarg(cont struct linux_sched_scheduler *) sp; 266 } */ *uap = v; 267 struct proc *cp = cl->l_proc; 268 int error; 269 struct linux_sched_param lp; 270 struct proc *p; 271 272 /* 273 * We only check for valid parameters and return afterwards. 274 */ 275 276 if (SCARG(uap, pid) < 0 || SCARG(uap, sp) == NULL) 277 return EINVAL; 278 279 error = copyin(SCARG(uap, sp), &lp, sizeof(lp)); 280 if (error) 281 return error; 282 283 if (SCARG(uap, pid) != 0) { 284 kauth_cred_t pc = cp->p_cred; 285 286 if ((p = pfind(SCARG(uap, pid))) == NULL) 287 return ESRCH; 288 if (!(cp == p || 289 kauth_cred_geteuid(pc) == 0 || 290 kauth_cred_getuid(pc) == kauth_cred_getuid(p->p_cred) || 291 kauth_cred_geteuid(pc) == kauth_cred_getuid(p->p_cred) || 292 kauth_cred_getuid(pc) == kauth_cred_geteuid(p->p_cred) || 293 kauth_cred_geteuid(pc) == kauth_cred_geteuid(p->p_cred))) 294 return EPERM; 295 } 296 297 /* 298 * We can't emulate anything put the default scheduling policy. 299 */ 300 if (SCARG(uap, policy) != LINUX_SCHED_OTHER || lp.sched_priority != 0) 301 return EINVAL; 302 303 return 0; 304 } 305 306 int 307 linux_sys_sched_getscheduler(cl, v, retval) 308 struct lwp *cl; 309 void *v; 310 register_t *retval; 311 { 312 struct linux_sys_sched_getscheduler_args /* { 313 syscallarg(linux_pid_t) pid; 314 } */ *uap = v; 315 struct proc *cp = cl->l_proc; 316 struct proc *p; 317 318 *retval = -1; 319 /* 320 * We only check for valid parameters and return afterwards. 321 */ 322 323 if (SCARG(uap, pid) != 0) { 324 kauth_cred_t pc = cp->p_cred; 325 326 if ((p = pfind(SCARG(uap, pid))) == NULL) 327 return ESRCH; 328 if (!(cp == p || 329 kauth_cred_geteuid(pc) == 0 || 330 kauth_cred_getuid(pc) == kauth_cred_getuid(p->p_cred) || 331 kauth_cred_geteuid(pc) == kauth_cred_getuid(p->p_cred) || 332 kauth_cred_getuid(pc) == kauth_cred_geteuid(p->p_cred) || 333 kauth_cred_geteuid(pc) == kauth_cred_geteuid(p->p_cred))) 334 return EPERM; 335 } 336 337 /* 338 * We can't emulate anything put the default scheduling policy. 339 */ 340 *retval = LINUX_SCHED_OTHER; 341 return 0; 342 } 343 344 int 345 linux_sys_sched_yield(cl, v, retval) 346 struct lwp *cl; 347 void *v; 348 register_t *retval; 349 { 350 351 yield(); 352 return 0; 353 } 354 355 int 356 linux_sys_sched_get_priority_max(cl, v, retval) 357 struct lwp *cl; 358 void *v; 359 register_t *retval; 360 { 361 struct linux_sys_sched_get_priority_max_args /* { 362 syscallarg(int) policy; 363 } */ *uap = v; 364 365 /* 366 * We can't emulate anything put the default scheduling policy. 367 */ 368 if (SCARG(uap, policy) != LINUX_SCHED_OTHER) { 369 *retval = -1; 370 return EINVAL; 371 } 372 373 *retval = 0; 374 return 0; 375 } 376 377 int 378 linux_sys_sched_get_priority_min(cl, v, retval) 379 struct lwp *cl; 380 void *v; 381 register_t *retval; 382 { 383 struct linux_sys_sched_get_priority_min_args /* { 384 syscallarg(int) policy; 385 } */ *uap = v; 386 387 /* 388 * We can't emulate anything put the default scheduling policy. 389 */ 390 if (SCARG(uap, policy) != LINUX_SCHED_OTHER) { 391 *retval = -1; 392 return EINVAL; 393 } 394 395 *retval = 0; 396 return 0; 397 } 398 399 #ifndef __m68k__ 400 /* Present on everything but m68k */ 401 int 402 linux_sys_exit_group(l, v, retval) 403 struct lwp *l; 404 void *v; 405 register_t *retval; 406 { 407 struct linux_sys_exit_group_args /* { 408 syscallarg(int) error_code; 409 } */ *uap = v; 410 411 /* 412 * XXX The calling thread is supposed to kill all threads 413 * in the same thread group (i.e. all threads created 414 * via clone(2) with CLONE_THREAD flag set). This appears 415 * to not be used yet, so the thread group handling 416 * is currently not implemented. 417 */ 418 419 exit1(l, W_EXITCODE(SCARG(uap, error_code), 0)); 420 /* NOTREACHED */ 421 return 0; 422 } 423 #endif /* !__m68k__ */ 424 425 #ifdef LINUX_NPTL 426 int 427 linux_sys_set_tid_address(l, v, retval) 428 struct lwp *l; 429 void *v; 430 register_t *retval; 431 { 432 struct linux_sys_set_tid_address_args /* { 433 syscallarg(int *) tidptr; 434 } */ *uap = v; 435 struct linux_emuldata *led; 436 437 led = (struct linux_emuldata *)l->l_proc->p_emuldata; 438 led->clear_tid = SCARG(uap, tid); 439 440 *retval = l->l_proc->p_pid; 441 442 return 0; 443 } 444 445 /* ARGUSED1 */ 446 int 447 linux_sys_gettid(l, v, retval) 448 struct lwp *l; 449 void *v; 450 register_t *retval; 451 { 452 *retval = l->l_proc->p_pid; 453 return 0; 454 } 455 456 int 457 linux_sys_sched_getaffinity(l, v, retval) 458 struct lwp *l; 459 void *v; 460 register_t *retval; 461 { 462 struct linux_sys_sched_getaffinity_args /* { 463 syscallarg(pid_t) pid; 464 syscallarg(unsigned int) len; 465 syscallarg(unsigned long *) mask; 466 } */ *uap = v; 467 int error; 468 int ret; 469 int ncpu; 470 int name[2]; 471 size_t sz; 472 char *data; 473 int *retp; 474 475 if (SCARG(uap, mask) == NULL) 476 return EINVAL; 477 478 if (SCARG(uap, len) < sizeof(int)) 479 return EINVAL; 480 481 if (pfind(SCARG(uap, pid)) == NULL) 482 return ESRCH; 483 484 /* 485 * return the actual number of CPU, tag all of them as available 486 * The result is a mask, the first CPU being in the least significant 487 * bit. 488 */ 489 name[0] = CTL_HW; 490 name[1] = HW_NCPU; 491 sz = sizeof(ncpu); 492 493 if ((error = old_sysctl(&name[0], 2, &ncpu, &sz, NULL, 0, NULL)) != 0) 494 return error; 495 496 ret = (1 << ncpu) - 1; 497 498 data = malloc(SCARG(uap, len), M_TEMP, M_WAITOK|M_ZERO); 499 retp = (int *)&data[SCARG(uap, len) - sizeof(ret)]; 500 *retp = ret; 501 502 if ((error = copyout(data, SCARG(uap, mask), SCARG(uap, len))) != 0) 503 return error; 504 505 free(data, M_TEMP); 506 507 return 0; 508 509 } 510 511 int 512 linux_sys_sched_setaffinity(l, v, retval) 513 struct lwp *l; 514 void *v; 515 register_t *retval; 516 { 517 struct linux_sys_sched_setaffinity_args /* { 518 syscallarg(pid_t) pid; 519 syscallarg(unsigned int) len; 520 syscallarg(unsigned long *) mask; 521 } */ *uap = v; 522 523 if (pfind(SCARG(uap, pid)) == NULL) 524 return ESRCH; 525 526 /* Let's ignore it */ 527 #ifdef DEBUG_LINUX 528 printf("linux_sys_sched_setaffinity\n"); 529 #endif 530 return 0; 531 }; 532 #endif /* LINUX_NPTL */ 533