1 /*- 2 * SPDX-License-Identifier: BSD-3-Clause 3 * 4 * Copyright (c) 2004 Tim J. Robbins 5 * Copyright (c) 2002 Doug Rabson 6 * Copyright (c) 2000 Marcel Moolenaar 7 * All rights reserved. 8 * 9 * Redistribution and use in source and binary forms, with or without 10 * modification, are permitted provided that the following conditions 11 * are met: 12 * 1. Redistributions of source code must retain the above copyright 13 * notice, this list of conditions and the following disclaimer 14 * in this position and unchanged. 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. The name of the author may not be used to endorse or promote products 19 * derived from this software without specific prior written permission. 20 * 21 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 22 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 23 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 24 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 25 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 26 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 27 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 28 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 29 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 30 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 31 */ 32 33 #include <sys/cdefs.h> 34 __FBSDID("$FreeBSD$"); 35 36 #include <sys/param.h> 37 #include <sys/fcntl.h> 38 #include <sys/imgact.h> 39 #include <sys/limits.h> 40 #include <sys/lock.h> 41 #include <sys/malloc.h> 42 #include <sys/mutex.h> 43 #include <sys/priv.h> 44 #include <sys/proc.h> 45 #include <sys/reg.h> 46 #include <sys/syscallsubr.h> 47 48 #include <machine/frame.h> 49 #include <machine/md_var.h> 50 #include <machine/pcb.h> 51 #include <machine/psl.h> 52 #include <machine/segments.h> 53 #include <machine/specialreg.h> 54 #include <x86/ifunc.h> 55 56 #include <vm/pmap.h> 57 #include <vm/vm.h> 58 #include <vm/vm_map.h> 59 60 #include <security/audit/audit.h> 61 62 #include <compat/freebsd32/freebsd32_util.h> 63 #include <amd64/linux32/linux.h> 64 #include <amd64/linux32/linux32_proto.h> 65 #include <compat/linux/linux_emul.h> 66 #include <compat/linux/linux_fork.h> 67 #include <compat/linux/linux_ipc.h> 68 #include <compat/linux/linux_misc.h> 69 #include <compat/linux/linux_mmap.h> 70 #include <compat/linux/linux_signal.h> 71 #include <compat/linux/linux_util.h> 72 73 static void bsd_to_linux_rusage(struct rusage *ru, struct l_rusage *lru); 74 75 struct l_old_select_argv { 76 l_int nfds; 77 l_uintptr_t readfds; 78 l_uintptr_t writefds; 79 l_uintptr_t exceptfds; 80 l_uintptr_t timeout; 81 } __packed; 82 83 static void 84 bsd_to_linux_rusage(struct rusage *ru, struct l_rusage *lru) 85 { 86 87 lru->ru_utime.tv_sec = ru->ru_utime.tv_sec; 88 lru->ru_utime.tv_usec = ru->ru_utime.tv_usec; 89 lru->ru_stime.tv_sec = ru->ru_stime.tv_sec; 90 lru->ru_stime.tv_usec = ru->ru_stime.tv_usec; 91 lru->ru_maxrss = ru->ru_maxrss; 92 lru->ru_ixrss = ru->ru_ixrss; 93 lru->ru_idrss = ru->ru_idrss; 94 lru->ru_isrss = ru->ru_isrss; 95 lru->ru_minflt = ru->ru_minflt; 96 lru->ru_majflt = ru->ru_majflt; 97 lru->ru_nswap = ru->ru_nswap; 98 lru->ru_inblock = ru->ru_inblock; 99 lru->ru_oublock = ru->ru_oublock; 100 lru->ru_msgsnd = ru->ru_msgsnd; 101 lru->ru_msgrcv = ru->ru_msgrcv; 102 lru->ru_nsignals = ru->ru_nsignals; 103 lru->ru_nvcsw = ru->ru_nvcsw; 104 lru->ru_nivcsw = ru->ru_nivcsw; 105 } 106 107 int 108 linux_copyout_rusage(struct rusage *ru, void *uaddr) 109 { 110 struct l_rusage lru; 111 112 bsd_to_linux_rusage(ru, &lru); 113 114 return (copyout(&lru, uaddr, sizeof(struct l_rusage))); 115 } 116 117 int 118 linux_execve(struct thread *td, struct linux_execve_args *args) 119 { 120 struct image_args eargs; 121 char *path; 122 int error; 123 124 if (!LUSECONVPATH(td)) { 125 error = freebsd32_exec_copyin_args(&eargs, args->path, UIO_USERSPACE, 126 args->argp, args->envp); 127 } else { 128 LCONVPATHEXIST(args->path, &path); 129 error = freebsd32_exec_copyin_args(&eargs, path, UIO_SYSSPACE, 130 args->argp, args->envp); 131 LFREEPATH(path); 132 } 133 if (error == 0) 134 error = linux_common_execve(td, &eargs); 135 AUDIT_SYSCALL_EXIT(error == EJUSTRETURN ? 0 : error, td); 136 return (error); 137 } 138 139 CTASSERT(sizeof(struct l_iovec32) == 8); 140 141 int 142 linux32_copyinuio(struct l_iovec32 *iovp, l_ulong iovcnt, struct uio **uiop) 143 { 144 struct l_iovec32 iov32; 145 struct iovec *iov; 146 struct uio *uio; 147 uint32_t iovlen; 148 int error, i; 149 150 *uiop = NULL; 151 if (iovcnt > UIO_MAXIOV) 152 return (EINVAL); 153 iovlen = iovcnt * sizeof(struct iovec); 154 uio = malloc(iovlen + sizeof(*uio), M_IOV, M_WAITOK); 155 iov = (struct iovec *)(uio + 1); 156 for (i = 0; i < iovcnt; i++) { 157 error = copyin(&iovp[i], &iov32, sizeof(struct l_iovec32)); 158 if (error) { 159 free(uio, M_IOV); 160 return (error); 161 } 162 iov[i].iov_base = PTRIN(iov32.iov_base); 163 iov[i].iov_len = iov32.iov_len; 164 } 165 uio->uio_iov = iov; 166 uio->uio_iovcnt = iovcnt; 167 uio->uio_segflg = UIO_USERSPACE; 168 uio->uio_offset = -1; 169 uio->uio_resid = 0; 170 for (i = 0; i < iovcnt; i++) { 171 if (iov->iov_len > INT_MAX - uio->uio_resid) { 172 free(uio, M_IOV); 173 return (EINVAL); 174 } 175 uio->uio_resid += iov->iov_len; 176 iov++; 177 } 178 *uiop = uio; 179 return (0); 180 } 181 182 int 183 linux32_copyiniov(struct l_iovec32 *iovp32, l_ulong iovcnt, struct iovec **iovp, 184 int error) 185 { 186 struct l_iovec32 iov32; 187 struct iovec *iov; 188 uint32_t iovlen; 189 int i; 190 191 *iovp = NULL; 192 if (iovcnt > UIO_MAXIOV) 193 return (error); 194 iovlen = iovcnt * sizeof(struct iovec); 195 iov = malloc(iovlen, M_IOV, M_WAITOK); 196 for (i = 0; i < iovcnt; i++) { 197 error = copyin(&iovp32[i], &iov32, sizeof(struct l_iovec32)); 198 if (error) { 199 free(iov, M_IOV); 200 return (error); 201 } 202 iov[i].iov_base = PTRIN(iov32.iov_base); 203 iov[i].iov_len = iov32.iov_len; 204 } 205 *iovp = iov; 206 return(0); 207 208 } 209 210 int 211 linux_readv(struct thread *td, struct linux_readv_args *uap) 212 { 213 struct uio *auio; 214 int error; 215 216 error = linux32_copyinuio(uap->iovp, uap->iovcnt, &auio); 217 if (error) 218 return (error); 219 error = kern_readv(td, uap->fd, auio); 220 free(auio, M_IOV); 221 return (error); 222 } 223 224 int 225 linux_writev(struct thread *td, struct linux_writev_args *uap) 226 { 227 struct uio *auio; 228 int error; 229 230 error = linux32_copyinuio(uap->iovp, uap->iovcnt, &auio); 231 if (error) 232 return (error); 233 error = kern_writev(td, uap->fd, auio); 234 free(auio, M_IOV); 235 return (error); 236 } 237 238 struct l_ipc_kludge { 239 l_uintptr_t msgp; 240 l_long msgtyp; 241 } __packed; 242 243 int 244 linux_ipc(struct thread *td, struct linux_ipc_args *args) 245 { 246 247 switch (args->what & 0xFFFF) { 248 case LINUX_SEMOP: { 249 250 return (kern_semop(td, args->arg1, PTRIN(args->ptr), 251 args->arg2, NULL)); 252 } 253 case LINUX_SEMGET: { 254 struct linux_semget_args a; 255 256 a.key = args->arg1; 257 a.nsems = args->arg2; 258 a.semflg = args->arg3; 259 return (linux_semget(td, &a)); 260 } 261 case LINUX_SEMCTL: { 262 struct linux_semctl_args a; 263 int error; 264 265 a.semid = args->arg1; 266 a.semnum = args->arg2; 267 a.cmd = args->arg3; 268 error = copyin(PTRIN(args->ptr), &a.arg, sizeof(a.arg)); 269 if (error) 270 return (error); 271 return (linux_semctl(td, &a)); 272 } 273 case LINUX_SEMTIMEDOP: { 274 struct linux_semtimedop_args a; 275 276 a.semid = args->arg1; 277 a.tsops = PTRIN(args->ptr); 278 a.nsops = args->arg2; 279 a.timeout = PTRIN(args->arg5); 280 return (linux_semtimedop(td, &a)); 281 } 282 case LINUX_MSGSND: { 283 struct linux_msgsnd_args a; 284 285 a.msqid = args->arg1; 286 a.msgp = PTRIN(args->ptr); 287 a.msgsz = args->arg2; 288 a.msgflg = args->arg3; 289 return (linux_msgsnd(td, &a)); 290 } 291 case LINUX_MSGRCV: { 292 struct linux_msgrcv_args a; 293 294 a.msqid = args->arg1; 295 a.msgsz = args->arg2; 296 a.msgflg = args->arg3; 297 if ((args->what >> 16) == 0) { 298 struct l_ipc_kludge tmp; 299 int error; 300 301 if (args->ptr == 0) 302 return (EINVAL); 303 error = copyin(PTRIN(args->ptr), &tmp, sizeof(tmp)); 304 if (error) 305 return (error); 306 a.msgp = PTRIN(tmp.msgp); 307 a.msgtyp = tmp.msgtyp; 308 } else { 309 a.msgp = PTRIN(args->ptr); 310 a.msgtyp = args->arg5; 311 } 312 return (linux_msgrcv(td, &a)); 313 } 314 case LINUX_MSGGET: { 315 struct linux_msgget_args a; 316 317 a.key = args->arg1; 318 a.msgflg = args->arg2; 319 return (linux_msgget(td, &a)); 320 } 321 case LINUX_MSGCTL: { 322 struct linux_msgctl_args a; 323 324 a.msqid = args->arg1; 325 a.cmd = args->arg2; 326 a.buf = PTRIN(args->ptr); 327 return (linux_msgctl(td, &a)); 328 } 329 case LINUX_SHMAT: { 330 struct linux_shmat_args a; 331 l_uintptr_t addr; 332 int error; 333 334 a.shmid = args->arg1; 335 a.shmaddr = PTRIN(args->ptr); 336 a.shmflg = args->arg2; 337 error = linux_shmat(td, &a); 338 if (error != 0) 339 return (error); 340 addr = td->td_retval[0]; 341 error = copyout(&addr, PTRIN(args->arg3), sizeof(addr)); 342 td->td_retval[0] = 0; 343 return (error); 344 } 345 case LINUX_SHMDT: { 346 struct linux_shmdt_args a; 347 348 a.shmaddr = PTRIN(args->ptr); 349 return (linux_shmdt(td, &a)); 350 } 351 case LINUX_SHMGET: { 352 struct linux_shmget_args a; 353 354 a.key = args->arg1; 355 a.size = args->arg2; 356 a.shmflg = args->arg3; 357 return (linux_shmget(td, &a)); 358 } 359 case LINUX_SHMCTL: { 360 struct linux_shmctl_args a; 361 362 a.shmid = args->arg1; 363 a.cmd = args->arg2; 364 a.buf = PTRIN(args->ptr); 365 return (linux_shmctl(td, &a)); 366 } 367 default: 368 break; 369 } 370 371 return (EINVAL); 372 } 373 374 int 375 linux_old_select(struct thread *td, struct linux_old_select_args *args) 376 { 377 struct l_old_select_argv linux_args; 378 struct linux_select_args newsel; 379 int error; 380 381 error = copyin(args->ptr, &linux_args, sizeof(linux_args)); 382 if (error) 383 return (error); 384 385 newsel.nfds = linux_args.nfds; 386 newsel.readfds = PTRIN(linux_args.readfds); 387 newsel.writefds = PTRIN(linux_args.writefds); 388 newsel.exceptfds = PTRIN(linux_args.exceptfds); 389 newsel.timeout = PTRIN(linux_args.timeout); 390 return (linux_select(td, &newsel)); 391 } 392 393 int 394 linux_set_cloned_tls(struct thread *td, void *desc) 395 { 396 struct l_user_desc info; 397 struct pcb *pcb; 398 int error; 399 400 error = copyin(desc, &info, sizeof(struct l_user_desc)); 401 if (error) { 402 linux_msg(td, "set_cloned_tls copyin info failed!"); 403 } else { 404 /* We might copy out the entry_number as GUGS32_SEL. */ 405 info.entry_number = GUGS32_SEL; 406 error = copyout(&info, desc, sizeof(struct l_user_desc)); 407 if (error) 408 linux_msg(td, "set_cloned_tls copyout info failed!"); 409 410 pcb = td->td_pcb; 411 update_pcb_bases(pcb); 412 pcb->pcb_gsbase = (register_t)info.base_addr; 413 td->td_frame->tf_gs = GSEL(GUGS32_SEL, SEL_UPL); 414 } 415 416 return (error); 417 } 418 419 int 420 linux_set_upcall(struct thread *td, register_t stack) 421 { 422 423 if (stack) 424 td->td_frame->tf_rsp = stack; 425 426 /* 427 * The newly created Linux thread returns 428 * to the user space by the same path that a parent do. 429 */ 430 td->td_frame->tf_rax = 0; 431 return (0); 432 } 433 434 int 435 linux_mmap2(struct thread *td, struct linux_mmap2_args *args) 436 { 437 438 return (linux_mmap_common(td, PTROUT(args->addr), args->len, args->prot, 439 args->flags, args->fd, (uint64_t)(uint32_t)args->pgoff * 440 PAGE_SIZE)); 441 } 442 443 int 444 linux_mmap(struct thread *td, struct linux_mmap_args *args) 445 { 446 int error; 447 struct l_mmap_argv linux_args; 448 449 error = copyin(args->ptr, &linux_args, sizeof(linux_args)); 450 if (error) 451 return (error); 452 453 return (linux_mmap_common(td, linux_args.addr, linux_args.len, 454 linux_args.prot, linux_args.flags, linux_args.fd, 455 (uint32_t)linux_args.pgoff)); 456 } 457 458 int 459 linux_mprotect(struct thread *td, struct linux_mprotect_args *uap) 460 { 461 462 return (linux_mprotect_common(td, PTROUT(uap->addr), uap->len, uap->prot)); 463 } 464 465 int 466 linux_madvise(struct thread *td, struct linux_madvise_args *uap) 467 { 468 469 return (linux_madvise_common(td, PTROUT(uap->addr), uap->len, uap->behav)); 470 } 471 472 int 473 linux_iopl(struct thread *td, struct linux_iopl_args *args) 474 { 475 int error; 476 477 if (args->level < 0 || args->level > 3) 478 return (EINVAL); 479 if ((error = priv_check(td, PRIV_IO)) != 0) 480 return (error); 481 if ((error = securelevel_gt(td->td_ucred, 0)) != 0) 482 return (error); 483 td->td_frame->tf_rflags = (td->td_frame->tf_rflags & ~PSL_IOPL) | 484 (args->level * (PSL_IOPL / 3)); 485 486 return (0); 487 } 488 489 int 490 linux_sigaction(struct thread *td, struct linux_sigaction_args *args) 491 { 492 l_osigaction_t osa; 493 l_sigaction_t act, oact; 494 int error; 495 496 if (args->nsa != NULL) { 497 error = copyin(args->nsa, &osa, sizeof(l_osigaction_t)); 498 if (error) 499 return (error); 500 act.lsa_handler = osa.lsa_handler; 501 act.lsa_flags = osa.lsa_flags; 502 act.lsa_restorer = osa.lsa_restorer; 503 LINUX_SIGEMPTYSET(act.lsa_mask); 504 act.lsa_mask.__mask = osa.lsa_mask; 505 } 506 507 error = linux_do_sigaction(td, args->sig, args->nsa ? &act : NULL, 508 args->osa ? &oact : NULL); 509 510 if (args->osa != NULL && !error) { 511 osa.lsa_handler = oact.lsa_handler; 512 osa.lsa_flags = oact.lsa_flags; 513 osa.lsa_restorer = oact.lsa_restorer; 514 osa.lsa_mask = oact.lsa_mask.__mask; 515 error = copyout(&osa, args->osa, sizeof(l_osigaction_t)); 516 } 517 518 return (error); 519 } 520 521 /* 522 * Linux has two extra args, restart and oldmask. We don't use these, 523 * but it seems that "restart" is actually a context pointer that 524 * enables the signal to happen with a different register set. 525 */ 526 int 527 linux_sigsuspend(struct thread *td, struct linux_sigsuspend_args *args) 528 { 529 sigset_t sigmask; 530 l_sigset_t mask; 531 532 LINUX_SIGEMPTYSET(mask); 533 mask.__mask = args->mask; 534 linux_to_bsd_sigset(&mask, &sigmask); 535 return (kern_sigsuspend(td, sigmask)); 536 } 537 538 int 539 linux_pause(struct thread *td, struct linux_pause_args *args) 540 { 541 struct proc *p = td->td_proc; 542 sigset_t sigmask; 543 544 PROC_LOCK(p); 545 sigmask = td->td_sigmask; 546 PROC_UNLOCK(p); 547 return (kern_sigsuspend(td, sigmask)); 548 } 549 550 int 551 linux_gettimeofday(struct thread *td, struct linux_gettimeofday_args *uap) 552 { 553 struct timeval atv; 554 l_timeval atv32; 555 struct timezone rtz; 556 int error = 0; 557 558 if (uap->tp) { 559 microtime(&atv); 560 atv32.tv_sec = atv.tv_sec; 561 atv32.tv_usec = atv.tv_usec; 562 error = copyout(&atv32, uap->tp, sizeof(atv32)); 563 } 564 if (error == 0 && uap->tzp != NULL) { 565 rtz.tz_minuteswest = 0; 566 rtz.tz_dsttime = 0; 567 error = copyout(&rtz, uap->tzp, sizeof(rtz)); 568 } 569 return (error); 570 } 571 572 int 573 linux_settimeofday(struct thread *td, struct linux_settimeofday_args *uap) 574 { 575 l_timeval atv32; 576 struct timeval atv, *tvp; 577 struct timezone atz, *tzp; 578 int error; 579 580 if (uap->tp) { 581 error = copyin(uap->tp, &atv32, sizeof(atv32)); 582 if (error) 583 return (error); 584 atv.tv_sec = atv32.tv_sec; 585 atv.tv_usec = atv32.tv_usec; 586 tvp = &atv; 587 } else 588 tvp = NULL; 589 if (uap->tzp) { 590 error = copyin(uap->tzp, &atz, sizeof(atz)); 591 if (error) 592 return (error); 593 tzp = &atz; 594 } else 595 tzp = NULL; 596 return (kern_settimeofday(td, tvp, tzp)); 597 } 598 599 int 600 linux_getrusage(struct thread *td, struct linux_getrusage_args *uap) 601 { 602 struct rusage s; 603 int error; 604 605 error = kern_getrusage(td, uap->who, &s); 606 if (error != 0) 607 return (error); 608 if (uap->rusage != NULL) 609 error = linux_copyout_rusage(&s, uap->rusage); 610 return (error); 611 } 612 613 int 614 linux_set_thread_area(struct thread *td, 615 struct linux_set_thread_area_args *args) 616 { 617 struct l_user_desc info; 618 struct pcb *pcb; 619 int error; 620 621 error = copyin(args->desc, &info, sizeof(struct l_user_desc)); 622 if (error) 623 return (error); 624 625 /* 626 * Semantics of Linux version: every thread in the system has array 627 * of three TLS descriptors. 1st is GLIBC TLS, 2nd is WINE, 3rd unknown. 628 * This syscall loads one of the selected TLS decriptors with a value 629 * and also loads GDT descriptors 6, 7 and 8 with the content of 630 * the per-thread descriptors. 631 * 632 * Semantics of FreeBSD version: I think we can ignore that Linux has 633 * three per-thread descriptors and use just the first one. 634 * The tls_array[] is used only in [gs]et_thread_area() syscalls and 635 * for loading the GDT descriptors. We use just one GDT descriptor 636 * for TLS, so we will load just one. 637 * 638 * XXX: This doesn't work when a user space process tries to use more 639 * than one TLS segment. Comment in the Linux source says wine might 640 * do this. 641 */ 642 643 /* 644 * GLIBC reads current %gs and call set_thread_area() with it. 645 * We should let GUDATA_SEL and GUGS32_SEL proceed as well because 646 * we use these segments. 647 */ 648 switch (info.entry_number) { 649 case GUGS32_SEL: 650 case GUDATA_SEL: 651 case 6: 652 case -1: 653 info.entry_number = GUGS32_SEL; 654 break; 655 default: 656 return (EINVAL); 657 } 658 659 /* 660 * We have to copy out the GDT entry we use. 661 * 662 * XXX: What if a user space program does not check the return value 663 * and tries to use 6, 7 or 8? 664 */ 665 error = copyout(&info, args->desc, sizeof(struct l_user_desc)); 666 if (error) 667 return (error); 668 669 pcb = td->td_pcb; 670 update_pcb_bases(pcb); 671 pcb->pcb_gsbase = (register_t)info.base_addr; 672 update_gdt_gsbase(td, info.base_addr); 673 674 return (0); 675 } 676 677 void 678 bsd_to_linux_regset32(const struct reg32 *b_reg, 679 struct linux_pt_regset32 *l_regset) 680 { 681 682 l_regset->ebx = b_reg->r_ebx; 683 l_regset->ecx = b_reg->r_ecx; 684 l_regset->edx = b_reg->r_edx; 685 l_regset->esi = b_reg->r_esi; 686 l_regset->edi = b_reg->r_edi; 687 l_regset->ebp = b_reg->r_ebp; 688 l_regset->eax = b_reg->r_eax; 689 l_regset->ds = b_reg->r_ds; 690 l_regset->es = b_reg->r_es; 691 l_regset->fs = b_reg->r_fs; 692 l_regset->gs = b_reg->r_gs; 693 l_regset->orig_eax = b_reg->r_eax; 694 l_regset->eip = b_reg->r_eip; 695 l_regset->cs = b_reg->r_cs; 696 l_regset->eflags = b_reg->r_eflags; 697 l_regset->esp = b_reg->r_esp; 698 l_regset->ss = b_reg->r_ss; 699 } 700 701 int futex_xchgl_nosmap(int oparg, uint32_t *uaddr, int *oldval); 702 int futex_xchgl_smap(int oparg, uint32_t *uaddr, int *oldval); 703 DEFINE_IFUNC(, int, futex_xchgl, (int, uint32_t *, int *)) 704 { 705 706 return ((cpu_stdext_feature & CPUID_STDEXT_SMAP) != 0 ? 707 futex_xchgl_smap : futex_xchgl_nosmap); 708 } 709 710 int futex_addl_nosmap(int oparg, uint32_t *uaddr, int *oldval); 711 int futex_addl_smap(int oparg, uint32_t *uaddr, int *oldval); 712 DEFINE_IFUNC(, int, futex_addl, (int, uint32_t *, int *)) 713 { 714 715 return ((cpu_stdext_feature & CPUID_STDEXT_SMAP) != 0 ? 716 futex_addl_smap : futex_addl_nosmap); 717 } 718 719 int futex_orl_nosmap(int oparg, uint32_t *uaddr, int *oldval); 720 int futex_orl_smap(int oparg, uint32_t *uaddr, int *oldval); 721 DEFINE_IFUNC(, int, futex_orl, (int, uint32_t *, int *)) 722 { 723 724 return ((cpu_stdext_feature & CPUID_STDEXT_SMAP) != 0 ? 725 futex_orl_smap : futex_orl_nosmap); 726 } 727 728 int futex_andl_nosmap(int oparg, uint32_t *uaddr, int *oldval); 729 int futex_andl_smap(int oparg, uint32_t *uaddr, int *oldval); 730 DEFINE_IFUNC(, int, futex_andl, (int, uint32_t *, int *)) 731 { 732 733 return ((cpu_stdext_feature & CPUID_STDEXT_SMAP) != 0 ? 734 futex_andl_smap : futex_andl_nosmap); 735 } 736 737 int futex_xorl_nosmap(int oparg, uint32_t *uaddr, int *oldval); 738 int futex_xorl_smap(int oparg, uint32_t *uaddr, int *oldval); 739 DEFINE_IFUNC(, int, futex_xorl, (int, uint32_t *, int *)) 740 { 741 742 return ((cpu_stdext_feature & CPUID_STDEXT_SMAP) != 0 ? 743 futex_xorl_smap : futex_xorl_nosmap); 744 } 745