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