1 /* $NetBSD: linux_sched.c,v 1.89 2026/09/20 13:43:51 riastradh Exp $ */ 2 3 /*- 4 * Copyright (c) 1999, 2019 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 * 20 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 21 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 22 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 23 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 24 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 25 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 26 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 27 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 28 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 29 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 30 * POSSIBILITY OF SUCH DAMAGE. 31 */ 32 33 /* 34 * Linux compatibility module. Try to deal with scheduler related syscalls. 35 */ 36 37 #include <sys/cdefs.h> 38 __KERNEL_RCSID(0, "$NetBSD: linux_sched.c,v 1.89 2026/09/20 13:43:51 riastradh Exp $"); 39 40 #include <sys/param.h> 41 #include <sys/mount.h> 42 #include <sys/proc.h> 43 #include <sys/systm.h> 44 #include <sys/sysctl.h> 45 #include <sys/syscallargs.h> 46 #include <sys/wait.h> 47 #include <sys/kauth.h> 48 #include <sys/ptrace.h> 49 #include <sys/atomic.h> 50 51 #include <sys/cpu.h> 52 53 #include <compat/linux/common/linux_types.h> 54 #include <compat/linux/common/linux_signal.h> 55 #include <compat/linux/common/linux_emuldata.h> 56 #include <compat/linux/common/linux_ipc.h> 57 #include <compat/linux/common/linux_sem.h> 58 #include <compat/linux/common/linux_exec.h> 59 #include <compat/linux/common/linux_machdep.h> 60 61 #include <compat/linux/linux_syscallargs.h> 62 63 #include <compat/linux/common/linux_sched.h> 64 65 #include <compat/linux/common/linux_prctl.h> 66 67 static int linux_clone_nptl(struct lwp *, const struct linux_sys_clone_args *, 68 register_t *); 69 70 /* Unlike Linux, dynamically calculate CPU mask size */ 71 #define LINUX_CPU_MASK_SIZE (sizeof(long) * ((ncpu + LONG_BIT - 1) / LONG_BIT)) 72 73 #if DEBUG_LINUX 74 #define DPRINTF(x, ...) uprintf(x, __VA_ARGS__) 75 #else 76 #define DPRINTF(x, ...) 77 #endif 78 79 static void 80 linux_child_return(void *arg) 81 { 82 struct lwp *l = arg; 83 struct proc *p = l->l_proc; 84 struct linux_emuldata *led = l->l_emuldata; 85 void *ctp = led->led_child_tidptr; 86 int error; 87 88 if (ctp) { 89 if ((error = copyout(&p->p_pid, ctp, sizeof(p->p_pid))) != 0) 90 printf("%s: LINUX_CLONE_CHILD_SETTID " 91 "failed (child_tidptr = %p, tid = %d error =%d)\n", 92 __func__, ctp, p->p_pid, error); 93 } 94 child_return(arg); 95 } 96 97 int 98 linux_sys_clone(struct lwp *l, const struct linux_sys_clone_args *uap, 99 register_t *retval) 100 { 101 /* { 102 syscallarg(int) flags; 103 syscallarg(void *) stack; 104 syscallarg(void *) parent_tidptr; 105 syscallarg(void *) tls; 106 syscallarg(void *) child_tidptr; 107 } */ 108 struct linux_emuldata *led; 109 int flags, sig, error; 110 111 /* 112 * We don't support the Linux CLONE_PID or CLONE_PTRACE flags. 113 */ 114 if (SCARG(uap, flags) & (LINUX_CLONE_PID|LINUX_CLONE_PTRACE)) 115 return EINVAL; 116 117 /* 118 * Thread group implies shared signals. Shared signals 119 * imply shared VM. This matches what Linux kernel does. 120 */ 121 if (SCARG(uap, flags) & LINUX_CLONE_THREAD 122 && (SCARG(uap, flags) & LINUX_CLONE_SIGHAND) == 0) 123 return EINVAL; 124 if (SCARG(uap, flags) & LINUX_CLONE_SIGHAND 125 && (SCARG(uap, flags) & LINUX_CLONE_VM) == 0) 126 return EINVAL; 127 128 /* 129 * The thread group flavor is implemented totally differently. 130 */ 131 if (SCARG(uap, flags) & LINUX_CLONE_THREAD) 132 return linux_clone_nptl(l, uap, retval); 133 134 flags = 0; 135 if (SCARG(uap, flags) & LINUX_CLONE_VM) 136 flags |= FORK_SHAREVM; 137 if (SCARG(uap, flags) & LINUX_CLONE_FS) 138 flags |= FORK_SHARECWD; 139 if (SCARG(uap, flags) & LINUX_CLONE_FILES) 140 flags |= FORK_SHAREFILES; 141 if (SCARG(uap, flags) & LINUX_CLONE_SIGHAND) 142 flags |= FORK_SHARESIGS; 143 if (SCARG(uap, flags) & LINUX_CLONE_VFORK) 144 flags |= FORK_PPWAIT; 145 146 sig = SCARG(uap, flags) & LINUX_CLONE_CSIGNAL; 147 if (sig < 0 || sig >= LINUX__NSIG) 148 return EINVAL; 149 sig = linux_to_native_signo[sig]; 150 151 if (SCARG(uap, flags) & LINUX_CLONE_CHILD_SETTID) { 152 led = l->l_emuldata; 153 led->led_child_tidptr = SCARG(uap, child_tidptr); 154 } 155 156 /* 157 * Note that Linux does not provide a portable way of specifying 158 * the stack area; the caller must know if the stack grows up 159 * or down. So, we pass a stack size of 0, so that the code 160 * that makes this adjustment is a noop. 161 */ 162 if ((error = fork1(l, flags, sig, SCARG(uap, stack), 0, 163 linux_child_return, NULL, retval)) != 0) { 164 DPRINTF("%s: fork1: error %d\n", __func__, error); 165 return error; 166 } 167 168 return 0; 169 } 170 171 172 int 173 linux_sys_clone3(struct lwp *l, const struct linux_sys_clone3_args *uap, register_t *retval) 174 { 175 struct linux_user_clone3_args cl_args; 176 struct linux_sys_clone_args clone_args; 177 int error; 178 179 if (SCARG(uap, size) != sizeof(cl_args)) { 180 DPRINTF("%s: Invalid size less or more\n", __func__); 181 return EINVAL; 182 } 183 184 error = copyin(SCARG(uap, cl_args), &cl_args, SCARG(uap, size)); 185 if (error) { 186 DPRINTF("%s: Copyin failed: %d\n", __func__, error); 187 return error; 188 } 189 190 DPRINTF("%s: Flags: %#jx\n", __func__, (intmax_t)cl_args.flags); 191 192 /* Define allowed flags */ 193 if (cl_args.flags & LINUX_CLONE_UNIMPLEMENTED_FLAGS) { 194 DPRINTF("%s: Unsupported flags for clone3: %#" PRIx64 "\n", 195 __func__, cl_args.flags & LINUX_CLONE_UNIMPLEMENTED_FLAGS); 196 return EOPNOTSUPP; 197 } 198 if (cl_args.flags & ~LINUX_CLONE_ALLOWED_FLAGS) { 199 DPRINTF("%s: Disallowed flags for clone3: %#" PRIx64 "\n", 200 __func__, cl_args.flags & ~LINUX_CLONE_ALLOWED_FLAGS); 201 return EINVAL; 202 } 203 204 #if 0 205 // XXX: this is wrong, exit_signal is the signal to deliver to the 206 // process upon exit. 207 if ((cl_args.exit_signal & ~(uint64_t)LINUX_CLONE_CSIGNAL) != 0){ 208 DPRINTF("%s: Disallowed flags for clone3: %#x\n", __func__, 209 cl_args.exit_signal & ~(uint64_t)LINUX_CLONE_CSIGNAL); 210 return EINVAL; 211 } 212 #endif 213 214 if (cl_args.stack == 0 && cl_args.stack_size != 0) { 215 DPRINTF("%s: Stack is NULL but stack size is not 0\n", 216 __func__); 217 return EINVAL; 218 } 219 if (cl_args.stack != 0 && cl_args.stack_size == 0) { 220 DPRINTF("%s: Stack is not NULL but stack size is 0\n", 221 __func__); 222 return EINVAL; 223 } 224 225 int flags = cl_args.flags & LINUX_CLONE_ALLOWED_FLAGS; 226 #if 0 227 int sig = cl_args.exit_signal & LINUX_CLONE_CSIGNAL; 228 #endif 229 // XXX: Pidfd member handling 230 // XXX: we don't have cgroups 231 // XXX: what to do with tid_set and tid_set_size 232 // XXX: clone3 has stacksize, instead implement clone as a clone3 233 // wrapper. 234 memset(&clone_args, 0, sizeof(clone_args)); 235 SCARG(&clone_args, flags) = flags; 236 #ifdef __MACHINE_STACK_GROWS_UP 237 SCARG(&clone_args, stack) = (void *)(uintptr_t)cl_args.stack; 238 #else 239 SCARG(&clone_args, stack) = 240 (void *)(uintptr_t)((uintptr_t)cl_args.stack + cl_args.stack_size); 241 #endif 242 SCARG(&clone_args, parent_tidptr) = 243 (void *)(intptr_t)cl_args.parent_tid; 244 SCARG(&clone_args, tls) = 245 (void *)(intptr_t)cl_args.tls; 246 SCARG(&clone_args, child_tidptr) = 247 (void *)(intptr_t)cl_args.child_tid; 248 249 return linux_sys_clone(l, &clone_args, retval); 250 } 251 252 static int 253 linux_clone_nptl(struct lwp *l, const struct linux_sys_clone_args *uap, register_t *retval) 254 { 255 /* { 256 syscallarg(int) flags; 257 syscallarg(void *) stack; 258 syscallarg(void *) parent_tidptr; 259 syscallarg(void *) tls; 260 syscallarg(void *) child_tidptr; 261 } */ 262 struct proc *p; 263 struct lwp *l2; 264 struct linux_emuldata *led; 265 void *parent_tidptr, *tls, *child_tidptr; 266 vaddr_t uaddr; 267 lwpid_t lid; 268 int flags, error; 269 270 p = l->l_proc; 271 flags = SCARG(uap, flags); 272 parent_tidptr = SCARG(uap, parent_tidptr); 273 tls = SCARG(uap, tls); 274 child_tidptr = SCARG(uap, child_tidptr); 275 276 uaddr = uvm_uarea_alloc(); 277 if (__predict_false(uaddr == 0)) { 278 return ENOMEM; 279 } 280 281 error = lwp_create(l, p, uaddr, LWP_DETACHED, 282 SCARG(uap, stack), 0, child_return, NULL, &l2, l->l_class, 283 &l->l_sigmask, &l->l_sigstk); 284 if (__predict_false(error)) { 285 DPRINTF("%s: lwp_create error=%d\n", __func__, error); 286 uvm_uarea_free(uaddr); 287 return error; 288 } 289 lid = l2->l_lid; 290 291 /* LINUX_CLONE_CHILD_CLEARTID: clear TID in child's memory on exit() */ 292 if (flags & LINUX_CLONE_CHILD_CLEARTID) { 293 led = l2->l_emuldata; 294 led->led_clear_tid = child_tidptr; 295 } 296 297 /* LINUX_CLONE_PARENT_SETTID: store child's TID in parent's memory */ 298 if (flags & LINUX_CLONE_PARENT_SETTID) { 299 if ((error = copyout(&lid, parent_tidptr, sizeof(lid))) != 0) 300 printf("%s: LINUX_CLONE_PARENT_SETTID " 301 "failed (parent_tidptr = %p tid = %d error=%d)\n", 302 __func__, parent_tidptr, lid, error); 303 } 304 305 /* LINUX_CLONE_CHILD_SETTID: store child's TID in child's memory */ 306 if (flags & LINUX_CLONE_CHILD_SETTID) { 307 if ((error = copyout(&lid, child_tidptr, sizeof(lid))) != 0) 308 printf("%s: LINUX_CLONE_CHILD_SETTID " 309 "failed (child_tidptr = %p, tid = %d error=%d)\n", 310 __func__, child_tidptr, lid, error); 311 } 312 313 if (flags & LINUX_CLONE_SETTLS) { 314 error = LINUX_LWP_SETPRIVATE(l2, tls); 315 if (error) { 316 DPRINTF("%s: LINUX_LWP_SETPRIVATE %d\n", __func__, 317 error); 318 lwp_exit(l2); 319 return error; 320 } 321 } 322 323 /* Set the new LWP running. */ 324 lwp_start(l2, 0); 325 326 retval[0] = lid; 327 retval[1] = 0; 328 return 0; 329 } 330 331 /* 332 * linux realtime priority 333 * 334 * - SCHED_RR and SCHED_FIFO tasks have priorities [1,99]. 335 * 336 * - SCHED_OTHER tasks don't have realtime priorities. 337 * in particular, sched_param::sched_priority is always 0. 338 */ 339 340 #define LINUX_SCHED_RTPRIO_MIN 1 341 #define LINUX_SCHED_RTPRIO_MAX 99 342 343 static int 344 sched_linux2native(int linux_policy, struct linux_sched_param *linux_params, 345 int *native_policy, struct sched_param *native_params) 346 { 347 348 switch (linux_policy) { 349 case LINUX_SCHED_OTHER: 350 if (native_policy != NULL) { 351 *native_policy = SCHED_OTHER; 352 } 353 break; 354 355 case LINUX_SCHED_FIFO: 356 if (native_policy != NULL) { 357 *native_policy = SCHED_FIFO; 358 } 359 break; 360 361 case LINUX_SCHED_RR: 362 if (native_policy != NULL) { 363 *native_policy = SCHED_RR; 364 } 365 break; 366 367 default: 368 return EINVAL; 369 } 370 371 if (linux_params != NULL) { 372 int prio = linux_params->sched_priority; 373 374 KASSERT(native_params != NULL); 375 376 if (linux_policy == LINUX_SCHED_OTHER) { 377 if (prio != 0) { 378 return EINVAL; 379 } 380 native_params->sched_priority = PRI_NONE; /* XXX */ 381 } else { 382 if (prio < LINUX_SCHED_RTPRIO_MIN || 383 prio > LINUX_SCHED_RTPRIO_MAX) { 384 return EINVAL; 385 } 386 native_params->sched_priority = 387 (prio - LINUX_SCHED_RTPRIO_MIN) 388 * (SCHED_PRI_MAX - SCHED_PRI_MIN) 389 / (LINUX_SCHED_RTPRIO_MAX - LINUX_SCHED_RTPRIO_MIN) 390 + SCHED_PRI_MIN; 391 } 392 } 393 394 return 0; 395 } 396 397 static int 398 sched_native2linux(int native_policy, struct sched_param *native_params, 399 int *linux_policy, struct linux_sched_param *linux_params) 400 { 401 402 switch (native_policy) { 403 case SCHED_OTHER: 404 if (linux_policy != NULL) { 405 *linux_policy = LINUX_SCHED_OTHER; 406 } 407 break; 408 409 case SCHED_FIFO: 410 if (linux_policy != NULL) { 411 *linux_policy = LINUX_SCHED_FIFO; 412 } 413 break; 414 415 case SCHED_RR: 416 if (linux_policy != NULL) { 417 *linux_policy = LINUX_SCHED_RR; 418 } 419 break; 420 421 default: 422 panic("%s: unknown policy %d\n", __func__, native_policy); 423 } 424 425 if (native_params != NULL) { 426 int prio = native_params->sched_priority; 427 428 KASSERT(prio >= SCHED_PRI_MIN); 429 KASSERT(prio <= SCHED_PRI_MAX); 430 KASSERT(linux_params != NULL); 431 432 memset(linux_params, 0, sizeof(*linux_params)); 433 434 DPRINTF("%s: native: policy %d, priority %d\n", 435 __func__, native_policy, prio); 436 437 if (native_policy == SCHED_OTHER) { 438 linux_params->sched_priority = 0; 439 } else { 440 linux_params->sched_priority = 441 (prio - SCHED_PRI_MIN) 442 * (LINUX_SCHED_RTPRIO_MAX - LINUX_SCHED_RTPRIO_MIN) 443 / (SCHED_PRI_MAX - SCHED_PRI_MIN) 444 + LINUX_SCHED_RTPRIO_MIN; 445 } 446 DPRINTF("%s: linux: policy %d, priority %d\n", 447 __func__, -1, linux_params->sched_priority); 448 } 449 450 return 0; 451 } 452 453 int 454 linux_sys_sched_setparam(struct lwp *l, const struct linux_sys_sched_setparam_args *uap, register_t *retval) 455 { 456 /* { 457 syscallarg(linux_pid_t) pid; 458 syscallarg(const struct linux_sched_param *) sp; 459 } */ 460 int error, policy; 461 struct linux_sched_param lp; 462 struct sched_param sp; 463 464 if (SCARG(uap, pid) < 0 || SCARG(uap, sp) == NULL) { 465 error = EINVAL; 466 goto out; 467 } 468 469 error = copyin(SCARG(uap, sp), &lp, sizeof(lp)); 470 if (error) 471 goto out; 472 473 /* We need the current policy in Linux terms. */ 474 error = do_sched_getparam(SCARG(uap, pid), 0, &policy, NULL); 475 if (error) 476 goto out; 477 error = sched_native2linux(policy, NULL, &policy, NULL); 478 if (error) 479 goto out; 480 481 error = sched_linux2native(policy, &lp, &policy, &sp); 482 if (error) 483 goto out; 484 485 error = do_sched_setparam(SCARG(uap, pid), 0, policy, &sp); 486 if (error) 487 goto out; 488 489 out: 490 return error; 491 } 492 493 int 494 linux_sys_sched_getparam(struct lwp *l, const struct linux_sys_sched_getparam_args *uap, register_t *retval) 495 { 496 /* { 497 syscallarg(linux_pid_t) pid; 498 syscallarg(struct linux_sched_param *) sp; 499 } */ 500 struct linux_sched_param lp; 501 struct sched_param sp; 502 int error, policy; 503 504 if (SCARG(uap, pid) < 0 || SCARG(uap, sp) == NULL) { 505 error = EINVAL; 506 goto out; 507 } 508 509 error = do_sched_getparam(SCARG(uap, pid), 0, &policy, &sp); 510 if (error) 511 goto out; 512 DPRINTF("%s: native: policy %d, priority %d\n", 513 __func__, policy, sp.sched_priority); 514 515 error = sched_native2linux(policy, &sp, NULL, &lp); 516 if (error) 517 goto out; 518 DPRINTF("%s: linux: policy %d, priority %d\n", 519 __func__, policy, lp.sched_priority); 520 521 error = copyout(&lp, SCARG(uap, sp), sizeof(lp)); 522 if (error) 523 goto out; 524 525 out: 526 return error; 527 } 528 529 int 530 linux_sys_sched_setscheduler(struct lwp *l, const struct linux_sys_sched_setscheduler_args *uap, register_t *retval) 531 { 532 /* { 533 syscallarg(linux_pid_t) pid; 534 syscallarg(int) policy; 535 syscallarg(cont struct linux_sched_param *) sp; 536 } */ 537 int error, policy; 538 struct linux_sched_param lp; 539 struct sched_param sp; 540 541 if (SCARG(uap, pid) < 0 || SCARG(uap, sp) == NULL) { 542 error = EINVAL; 543 goto out; 544 } 545 546 error = copyin(SCARG(uap, sp), &lp, sizeof(lp)); 547 if (error) 548 goto out; 549 DPRINTF("%s: linux: policy %d, priority %d\n", 550 __func__, SCARG(uap, policy), lp.sched_priority); 551 552 error = sched_linux2native(SCARG(uap, policy), &lp, &policy, &sp); 553 if (error) 554 goto out; 555 DPRINTF("%s: native: policy %d, priority %d\n", 556 __func__, policy, sp.sched_priority); 557 558 error = do_sched_setparam(SCARG(uap, pid), 0, policy, &sp); 559 if (error) 560 goto out; 561 562 out: 563 return error; 564 } 565 566 int 567 linux_sys_sched_getscheduler(struct lwp *l, const struct linux_sys_sched_getscheduler_args *uap, register_t *retval) 568 { 569 /* { 570 syscallarg(linux_pid_t) pid; 571 } */ 572 int error, policy; 573 574 *retval = -1; 575 576 error = do_sched_getparam(SCARG(uap, pid), 0, &policy, NULL); 577 if (error) 578 goto out; 579 580 error = sched_native2linux(policy, NULL, &policy, NULL); 581 if (error) 582 goto out; 583 584 *retval = policy; 585 586 out: 587 return error; 588 } 589 590 int 591 linux_sys_sched_yield(struct lwp *l, const void *v, register_t *retval) 592 { 593 594 yield(); 595 return 0; 596 } 597 598 int 599 linux_sys_sched_get_priority_max(struct lwp *l, const struct linux_sys_sched_get_priority_max_args *uap, register_t *retval) 600 { 601 /* { 602 syscallarg(int) policy; 603 } */ 604 605 switch (SCARG(uap, policy)) { 606 case LINUX_SCHED_OTHER: 607 *retval = 0; 608 break; 609 case LINUX_SCHED_FIFO: 610 case LINUX_SCHED_RR: 611 *retval = LINUX_SCHED_RTPRIO_MAX; 612 break; 613 default: 614 return EINVAL; 615 } 616 617 return 0; 618 } 619 620 int 621 linux_sys_sched_get_priority_min(struct lwp *l, const struct linux_sys_sched_get_priority_min_args *uap, register_t *retval) 622 { 623 /* { 624 syscallarg(int) policy; 625 } */ 626 627 switch (SCARG(uap, policy)) { 628 case LINUX_SCHED_OTHER: 629 *retval = 0; 630 break; 631 case LINUX_SCHED_FIFO: 632 case LINUX_SCHED_RR: 633 *retval = LINUX_SCHED_RTPRIO_MIN; 634 break; 635 default: 636 return EINVAL; 637 } 638 639 return 0; 640 } 641 642 int 643 linux_sys_exit(struct lwp *l, const struct linux_sys_exit_args *uap, register_t *retval) 644 { 645 646 lwp_exit(l); 647 return 0; 648 } 649 650 #ifndef __m68k__ 651 /* Present on everything but m68k */ 652 int 653 linux_sys_exit_group(struct lwp *l, const struct linux_sys_exit_group_args *uap, register_t *retval) 654 { 655 656 return sys_exit(l, (const void *)uap, retval); 657 } 658 #endif /* !__m68k__ */ 659 660 int 661 linux_sys_set_tid_address(struct lwp *l, const struct linux_sys_set_tid_address_args *uap, register_t *retval) 662 { 663 /* { 664 syscallarg(int *) tidptr; 665 } */ 666 struct linux_emuldata *led; 667 668 led = (struct linux_emuldata *)l->l_emuldata; 669 led->led_clear_tid = SCARG(uap, tid); 670 *retval = l->l_lid; 671 672 return 0; 673 } 674 675 /* ARGUSED1 */ 676 int 677 linux_sys_gettid(struct lwp *l, const void *v, register_t *retval) 678 { 679 680 *retval = l->l_lid; 681 return 0; 682 } 683 684 /* 685 * The affinity syscalls assume that the layout of our cpu kcpuset is 686 * the same as linux's: a linear bitmask. 687 */ 688 int 689 linux_sys_sched_getaffinity(struct lwp *l, const struct linux_sys_sched_getaffinity_args *uap, register_t *retval) 690 { 691 /* { 692 syscallarg(linux_pid_t) pid; 693 syscallarg(unsigned int) len; 694 syscallarg(unsigned long *) mask; 695 } */ 696 struct proc *p; 697 struct lwp *t; 698 kcpuset_t *kcset; 699 size_t size; 700 cpuid_t i; 701 int error; 702 703 size = LINUX_CPU_MASK_SIZE; 704 if (SCARG(uap, len) < size) 705 return EINVAL; 706 707 if (SCARG(uap, pid) == 0) { 708 p = curproc; 709 mutex_enter(p->p_lock); 710 t = curlwp; 711 } else { 712 t = lwp_find2(-1, SCARG(uap, pid)); 713 if (__predict_false(t == NULL)) { 714 return ESRCH; 715 } 716 p = t->l_proc; 717 KASSERT(mutex_owned(p->p_lock)); 718 } 719 720 /* Check the permission */ 721 if (kauth_authorize_process(l->l_cred, 722 KAUTH_PROCESS_SCHEDULER_GETAFFINITY, p, NULL, NULL, NULL)) { 723 mutex_exit(p->p_lock); 724 return EPERM; 725 } 726 727 kcpuset_create(&kcset, true); 728 lwp_lock(t); 729 if (t->l_affinity != NULL) 730 kcpuset_copy(kcset, t->l_affinity); 731 else { 732 /* 733 * All available CPUs should be masked when affinity has not 734 * been set. 735 */ 736 kcpuset_zero(kcset); 737 for (i = 0; i < ncpu; i++) 738 kcpuset_set(kcset, i); 739 } 740 lwp_unlock(t); 741 mutex_exit(p->p_lock); 742 error = kcpuset_copyout(kcset, (cpuset_t *)SCARG(uap, mask), size); 743 kcpuset_unuse(kcset, NULL); 744 *retval = size; 745 return error; 746 } 747 748 int 749 linux_sys_sched_setaffinity(struct lwp *l, const struct linux_sys_sched_setaffinity_args *uap, register_t *retval) 750 { 751 /* { 752 syscallarg(linux_pid_t) pid; 753 syscallarg(unsigned int) len; 754 syscallarg(unsigned long *) mask; 755 } */ 756 struct sys__sched_setaffinity_args ssa; 757 size_t size; 758 pid_t pid; 759 lwpid_t lid; 760 761 size = LINUX_CPU_MASK_SIZE; 762 if (SCARG(uap, len) < size) 763 return EINVAL; 764 765 lid = SCARG(uap, pid); 766 if (lid != 0) { 767 /* Get the canonical PID for the process. */ 768 mutex_enter(&proc_lock); 769 struct proc *p = proc_find_lwpid(SCARG(uap, pid)); 770 if (p == NULL) { 771 mutex_exit(&proc_lock); 772 return ESRCH; 773 } 774 pid = p->p_pid; 775 mutex_exit(&proc_lock); 776 } else { 777 pid = curproc->p_pid; 778 lid = curlwp->l_lid; 779 } 780 781 memset(&ssa, 0, sizeof(ssa)); 782 SCARG(&ssa, pid) = pid; 783 SCARG(&ssa, lid) = lid; 784 SCARG(&ssa, size) = size; 785 SCARG(&ssa, cpuset) = (cpuset_t *)SCARG(uap, mask); 786 787 return sys__sched_setaffinity(l, &ssa, retval); 788 } 789 790 int 791 linux_sys___prctl(struct lwp *l, const struct linux_sys___prctl_args *uap, 792 register_t *retval) 793 { 794 /* { 795 syscallarg(int) code; 796 syscallarg(void *) args[LINUX_SYS_MAXSYSARGS]; 797 } */ 798 799 unsigned int c = SCARG(uap, code); 800 801 /* TODO: add other commonly used prctl codes */ 802 switch(c) { 803 case LINUX_PR_SET_NAME: { 804 struct sys__lwp_setname_args sls; 805 806 memset(&sls, 0, sizeof(sls)); 807 SCARG(&sls, target) = 0; 808 SCARG(&sls, name) = (char *) SCARG(uap, args[0]); 809 return sys__lwp_setname(l, &sls, retval); 810 } 811 case LINUX_PR_GET_NAME: { 812 struct sys__lwp_getname_args slg; 813 814 memset(&slg, 0, sizeof(slg)); 815 SCARG(&slg, target) = 0; 816 SCARG(&slg, name) = (char *) SCARG(uap, args[0]); 817 SCARG(&slg, len) = MAXCOMLEN; 818 return sys__lwp_getname(l, &slg, retval); 819 } 820 default: 821 printf("Unimplemented linux prctl code: (%d)", c); 822 return ENOSYS; 823 } 824 825 } 826