linux32_machdep.c revision 302964
1/*- 2 * Copyright (c) 2004 Tim J. Robbins 3 * Copyright (c) 2002 Doug Rabson 4 * Copyright (c) 2000 Marcel Moolenaar 5 * All rights reserved. 6 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted provided that the following conditions 9 * are met: 10 * 1. Redistributions of source code must retain the above copyright 11 * notice, this list of conditions and the following disclaimer 12 * in this position and unchanged. 13 * 2. Redistributions in binary form must reproduce the above copyright 14 * notice, this list of conditions and the following disclaimer in the 15 * documentation and/or other materials provided with the distribution. 16 * 3. The name of the author may not be used to endorse or promote products 17 * derived from this software without specific prior written permission. 18 * 19 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 20 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 21 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 22 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 23 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 24 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 25 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 26 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 27 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 28 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 29 */ 30 31#include <sys/cdefs.h> 32__FBSDID("$FreeBSD: stable/10/sys/amd64/linux32/linux32_machdep.c 302964 2016-07-17 15:23:32Z dchagin $"); 33 34#include "opt_compat.h" 35 36#include <sys/param.h> 37#include <sys/kernel.h> 38#include <sys/systm.h> 39#include <sys/capsicum.h> 40#include <sys/file.h> 41#include <sys/fcntl.h> 42#include <sys/clock.h> 43#include <sys/imgact.h> 44#include <sys/limits.h> 45#include <sys/lock.h> 46#include <sys/malloc.h> 47#include <sys/mman.h> 48#include <sys/mutex.h> 49#include <sys/priv.h> 50#include <sys/proc.h> 51#include <sys/resource.h> 52#include <sys/resourcevar.h> 53#include <sys/syscallsubr.h> 54#include <sys/sysproto.h> 55#include <sys/unistd.h> 56#include <sys/wait.h> 57 58#include <machine/frame.h> 59#include <machine/pcb.h> 60#include <machine/psl.h> 61#include <machine/segments.h> 62#include <machine/specialreg.h> 63 64#include <vm/vm.h> 65#include <vm/pmap.h> 66#include <vm/vm_map.h> 67 68#include <compat/freebsd32/freebsd32_util.h> 69#include <amd64/linux32/linux.h> 70#include <amd64/linux32/linux32_proto.h> 71#include <compat/linux/linux_ipc.h> 72#include <compat/linux/linux_misc.h> 73#include <compat/linux/linux_mmap.h> 74#include <compat/linux/linux_signal.h> 75#include <compat/linux/linux_util.h> 76#include <compat/linux/linux_emul.h> 77 78static void bsd_to_linux_rusage(struct rusage *ru, struct l_rusage *lru); 79 80struct l_old_select_argv { 81 l_int nfds; 82 l_uintptr_t readfds; 83 l_uintptr_t writefds; 84 l_uintptr_t exceptfds; 85 l_uintptr_t timeout; 86} __packed; 87 88 89static void 90bsd_to_linux_rusage(struct rusage *ru, struct l_rusage *lru) 91{ 92 93 lru->ru_utime.tv_sec = ru->ru_utime.tv_sec; 94 lru->ru_utime.tv_usec = ru->ru_utime.tv_usec; 95 lru->ru_stime.tv_sec = ru->ru_stime.tv_sec; 96 lru->ru_stime.tv_usec = ru->ru_stime.tv_usec; 97 lru->ru_maxrss = ru->ru_maxrss; 98 lru->ru_ixrss = ru->ru_ixrss; 99 lru->ru_idrss = ru->ru_idrss; 100 lru->ru_isrss = ru->ru_isrss; 101 lru->ru_minflt = ru->ru_minflt; 102 lru->ru_majflt = ru->ru_majflt; 103 lru->ru_nswap = ru->ru_nswap; 104 lru->ru_inblock = ru->ru_inblock; 105 lru->ru_oublock = ru->ru_oublock; 106 lru->ru_msgsnd = ru->ru_msgsnd; 107 lru->ru_msgrcv = ru->ru_msgrcv; 108 lru->ru_nsignals = ru->ru_nsignals; 109 lru->ru_nvcsw = ru->ru_nvcsw; 110 lru->ru_nivcsw = ru->ru_nivcsw; 111} 112 113int 114linux_copyout_rusage(struct rusage *ru, void *uaddr) 115{ 116 struct l_rusage lru; 117 118 bsd_to_linux_rusage(ru, &lru); 119 120 return (copyout(&lru, uaddr, sizeof(struct l_rusage))); 121} 122 123int 124linux_execve(struct thread *td, struct linux_execve_args *args) 125{ 126 struct image_args eargs; 127 char *path; 128 int error; 129 130 LCONVPATHEXIST(td, args->path, &path); 131 132#ifdef DEBUG 133 if (ldebug(execve)) 134 printf(ARGS(execve, "%s"), path); 135#endif 136 137 error = freebsd32_exec_copyin_args(&eargs, path, UIO_SYSSPACE, 138 args->argp, args->envp); 139 free(path, M_TEMP); 140 if (error == 0) 141 error = linux_common_execve(td, &eargs); 142 return (error); 143} 144 145CTASSERT(sizeof(struct l_iovec32) == 8); 146 147static int 148linux32_copyinuio(struct l_iovec32 *iovp, l_ulong iovcnt, struct uio **uiop) 149{ 150 struct l_iovec32 iov32; 151 struct iovec *iov; 152 struct uio *uio; 153 uint32_t iovlen; 154 int error, i; 155 156 *uiop = NULL; 157 if (iovcnt > UIO_MAXIOV) 158 return (EINVAL); 159 iovlen = iovcnt * sizeof(struct iovec); 160 uio = malloc(iovlen + sizeof(*uio), M_IOV, M_WAITOK); 161 iov = (struct iovec *)(uio + 1); 162 for (i = 0; i < iovcnt; i++) { 163 error = copyin(&iovp[i], &iov32, sizeof(struct l_iovec32)); 164 if (error) { 165 free(uio, M_IOV); 166 return (error); 167 } 168 iov[i].iov_base = PTRIN(iov32.iov_base); 169 iov[i].iov_len = iov32.iov_len; 170 } 171 uio->uio_iov = iov; 172 uio->uio_iovcnt = iovcnt; 173 uio->uio_segflg = UIO_USERSPACE; 174 uio->uio_offset = -1; 175 uio->uio_resid = 0; 176 for (i = 0; i < iovcnt; i++) { 177 if (iov->iov_len > INT_MAX - uio->uio_resid) { 178 free(uio, M_IOV); 179 return (EINVAL); 180 } 181 uio->uio_resid += iov->iov_len; 182 iov++; 183 } 184 *uiop = uio; 185 return (0); 186} 187 188int 189linux32_copyiniov(struct l_iovec32 *iovp32, l_ulong iovcnt, struct iovec **iovp, 190 int error) 191{ 192 struct l_iovec32 iov32; 193 struct iovec *iov; 194 uint32_t iovlen; 195 int i; 196 197 *iovp = NULL; 198 if (iovcnt > UIO_MAXIOV) 199 return (error); 200 iovlen = iovcnt * sizeof(struct iovec); 201 iov = malloc(iovlen, M_IOV, M_WAITOK); 202 for (i = 0; i < iovcnt; i++) { 203 error = copyin(&iovp32[i], &iov32, sizeof(struct l_iovec32)); 204 if (error) { 205 free(iov, M_IOV); 206 return (error); 207 } 208 iov[i].iov_base = PTRIN(iov32.iov_base); 209 iov[i].iov_len = iov32.iov_len; 210 } 211 *iovp = iov; 212 return(0); 213 214} 215 216int 217linux_readv(struct thread *td, struct linux_readv_args *uap) 218{ 219 struct uio *auio; 220 int error; 221 222 error = linux32_copyinuio(uap->iovp, uap->iovcnt, &auio); 223 if (error) 224 return (error); 225 error = kern_readv(td, uap->fd, auio); 226 free(auio, M_IOV); 227 return (error); 228} 229 230int 231linux_writev(struct thread *td, struct linux_writev_args *uap) 232{ 233 struct uio *auio; 234 int error; 235 236 error = linux32_copyinuio(uap->iovp, uap->iovcnt, &auio); 237 if (error) 238 return (error); 239 error = kern_writev(td, uap->fd, auio); 240 free(auio, M_IOV); 241 return (error); 242} 243 244struct l_ipc_kludge { 245 l_uintptr_t msgp; 246 l_long msgtyp; 247} __packed; 248 249int 250linux_ipc(struct thread *td, struct linux_ipc_args *args) 251{ 252 253 switch (args->what & 0xFFFF) { 254 case LINUX_SEMOP: { 255 struct linux_semop_args a; 256 257 a.semid = args->arg1; 258 a.tsops = args->ptr; 259 a.nsops = args->arg2; 260 return (linux_semop(td, &a)); 261 } 262 case LINUX_SEMGET: { 263 struct linux_semget_args a; 264 265 a.key = args->arg1; 266 a.nsems = args->arg2; 267 a.semflg = args->arg3; 268 return (linux_semget(td, &a)); 269 } 270 case LINUX_SEMCTL: { 271 struct linux_semctl_args a; 272 int error; 273 274 a.semid = args->arg1; 275 a.semnum = args->arg2; 276 a.cmd = args->arg3; 277 error = copyin(args->ptr, &a.arg, sizeof(a.arg)); 278 if (error) 279 return (error); 280 return (linux_semctl(td, &a)); 281 } 282 case LINUX_MSGSND: { 283 struct linux_msgsnd_args a; 284 285 a.msqid = args->arg1; 286 a.msgp = 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(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 = 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 = args->ptr; 327 return (linux_msgctl(td, &a)); 328 } 329 case LINUX_SHMAT: { 330 struct linux_shmat_args a; 331 332 a.shmid = args->arg1; 333 a.shmaddr = args->ptr; 334 a.shmflg = args->arg2; 335 a.raddr = PTRIN((l_uint)args->arg3); 336 return (linux_shmat(td, &a)); 337 } 338 case LINUX_SHMDT: { 339 struct linux_shmdt_args a; 340 341 a.shmaddr = args->ptr; 342 return (linux_shmdt(td, &a)); 343 } 344 case LINUX_SHMGET: { 345 struct linux_shmget_args a; 346 347 a.key = args->arg1; 348 a.size = args->arg2; 349 a.shmflg = args->arg3; 350 return (linux_shmget(td, &a)); 351 } 352 case LINUX_SHMCTL: { 353 struct linux_shmctl_args a; 354 355 a.shmid = args->arg1; 356 a.cmd = args->arg2; 357 a.buf = args->ptr; 358 return (linux_shmctl(td, &a)); 359 } 360 default: 361 break; 362 } 363 364 return (EINVAL); 365} 366 367int 368linux_old_select(struct thread *td, struct linux_old_select_args *args) 369{ 370 struct l_old_select_argv linux_args; 371 struct linux_select_args newsel; 372 int error; 373 374#ifdef DEBUG 375 if (ldebug(old_select)) 376 printf(ARGS(old_select, "%p"), args->ptr); 377#endif 378 379 error = copyin(args->ptr, &linux_args, sizeof(linux_args)); 380 if (error) 381 return (error); 382 383 newsel.nfds = linux_args.nfds; 384 newsel.readfds = PTRIN(linux_args.readfds); 385 newsel.writefds = PTRIN(linux_args.writefds); 386 newsel.exceptfds = PTRIN(linux_args.exceptfds); 387 newsel.timeout = PTRIN(linux_args.timeout); 388 return (linux_select(td, &newsel)); 389} 390 391int 392linux_set_cloned_tls(struct thread *td, void *desc) 393{ 394 struct user_segment_descriptor sd; 395 struct l_user_desc info; 396 struct pcb *pcb; 397 int error; 398 int a[2]; 399 400 error = copyin(desc, &info, sizeof(struct l_user_desc)); 401 if (error) { 402 printf(LMSG("copyin 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 printf(LMSG("copyout failed!")); 409 410 a[0] = LINUX_LDT_entry_a(&info); 411 a[1] = LINUX_LDT_entry_b(&info); 412 413 memcpy(&sd, &a, sizeof(a)); 414#ifdef DEBUG 415 if (ldebug(clone)) 416 printf("Segment created in clone with " 417 "CLONE_SETTLS: lobase: %x, hibase: %x, " 418 "lolimit: %x, hilimit: %x, type: %i, " 419 "dpl: %i, p: %i, xx: %i, long: %i, " 420 "def32: %i, gran: %i\n", sd.sd_lobase, 421 sd.sd_hibase, sd.sd_lolimit, sd.sd_hilimit, 422 sd.sd_type, sd.sd_dpl, sd.sd_p, sd.sd_xx, 423 sd.sd_long, sd.sd_def32, sd.sd_gran); 424#endif 425 pcb = td->td_pcb; 426 pcb->pcb_gsbase = (register_t)info.base_addr; 427 td->td_frame->tf_gs = GSEL(GUGS32_SEL, SEL_UPL); 428 set_pcb_flags(pcb, PCB_32BIT); 429 } 430 431 return (error); 432} 433 434int 435linux_set_upcall_kse(struct thread *td, register_t stack) 436{ 437 438 if (stack) 439 td->td_frame->tf_rsp = stack; 440 441 /* 442 * The newly created Linux thread returns 443 * to the user space by the same path that a parent do. 444 */ 445 td->td_frame->tf_rax = 0; 446 return (0); 447} 448 449int 450linux_mmap2(struct thread *td, struct linux_mmap2_args *args) 451{ 452 453#ifdef DEBUG 454 if (ldebug(mmap2)) 455 printf(ARGS(mmap2, "0x%08x, %d, %d, 0x%08x, %d, %d"), 456 args->addr, args->len, args->prot, 457 args->flags, args->fd, args->pgoff); 458#endif 459 460 return (linux_mmap_common(td, PTROUT(args->addr), args->len, args->prot, 461 args->flags, args->fd, (uint64_t)(uint32_t)args->pgoff * 462 PAGE_SIZE)); 463} 464 465int 466linux_mmap(struct thread *td, struct linux_mmap_args *args) 467{ 468 int error; 469 struct l_mmap_argv linux_args; 470 471 error = copyin(args->ptr, &linux_args, sizeof(linux_args)); 472 if (error) 473 return (error); 474 475#ifdef DEBUG 476 if (ldebug(mmap)) 477 printf(ARGS(mmap, "0x%08x, %d, %d, 0x%08x, %d, %d"), 478 linux_args.addr, linux_args.len, linux_args.prot, 479 linux_args.flags, linux_args.fd, linux_args.pgoff); 480#endif 481 482 return (linux_mmap_common(td, linux_args.addr, linux_args.len, 483 linux_args.prot, linux_args.flags, linux_args.fd, 484 (uint32_t)linux_args.pgoff)); 485} 486 487int 488linux_mprotect(struct thread *td, struct linux_mprotect_args *uap) 489{ 490 491 return (linux_mprotect_common(td, PTROUT(uap->addr), uap->len, uap->prot)); 492} 493 494int 495linux_iopl(struct thread *td, struct linux_iopl_args *args) 496{ 497 int error; 498 499 if (args->level < 0 || args->level > 3) 500 return (EINVAL); 501 if ((error = priv_check(td, PRIV_IO)) != 0) 502 return (error); 503 if ((error = securelevel_gt(td->td_ucred, 0)) != 0) 504 return (error); 505 td->td_frame->tf_rflags = (td->td_frame->tf_rflags & ~PSL_IOPL) | 506 (args->level * (PSL_IOPL / 3)); 507 508 return (0); 509} 510 511int 512linux_sigaction(struct thread *td, struct linux_sigaction_args *args) 513{ 514 l_osigaction_t osa; 515 l_sigaction_t act, oact; 516 int error; 517 518#ifdef DEBUG 519 if (ldebug(sigaction)) 520 printf(ARGS(sigaction, "%d, %p, %p"), 521 args->sig, (void *)args->nsa, (void *)args->osa); 522#endif 523 524 if (args->nsa != NULL) { 525 error = copyin(args->nsa, &osa, sizeof(l_osigaction_t)); 526 if (error) 527 return (error); 528 act.lsa_handler = osa.lsa_handler; 529 act.lsa_flags = osa.lsa_flags; 530 act.lsa_restorer = osa.lsa_restorer; 531 LINUX_SIGEMPTYSET(act.lsa_mask); 532 act.lsa_mask.__mask = osa.lsa_mask; 533 } 534 535 error = linux_do_sigaction(td, args->sig, args->nsa ? &act : NULL, 536 args->osa ? &oact : NULL); 537 538 if (args->osa != NULL && !error) { 539 osa.lsa_handler = oact.lsa_handler; 540 osa.lsa_flags = oact.lsa_flags; 541 osa.lsa_restorer = oact.lsa_restorer; 542 osa.lsa_mask = oact.lsa_mask.__mask; 543 error = copyout(&osa, args->osa, sizeof(l_osigaction_t)); 544 } 545 546 return (error); 547} 548 549/* 550 * Linux has two extra args, restart and oldmask. We don't use these, 551 * but it seems that "restart" is actually a context pointer that 552 * enables the signal to happen with a different register set. 553 */ 554int 555linux_sigsuspend(struct thread *td, struct linux_sigsuspend_args *args) 556{ 557 sigset_t sigmask; 558 l_sigset_t mask; 559 560#ifdef DEBUG 561 if (ldebug(sigsuspend)) 562 printf(ARGS(sigsuspend, "%08lx"), (unsigned long)args->mask); 563#endif 564 565 LINUX_SIGEMPTYSET(mask); 566 mask.__mask = args->mask; 567 linux_to_bsd_sigset(&mask, &sigmask); 568 return (kern_sigsuspend(td, sigmask)); 569} 570 571int 572linux_rt_sigsuspend(struct thread *td, struct linux_rt_sigsuspend_args *uap) 573{ 574 l_sigset_t lmask; 575 sigset_t sigmask; 576 int error; 577 578#ifdef DEBUG 579 if (ldebug(rt_sigsuspend)) 580 printf(ARGS(rt_sigsuspend, "%p, %d"), 581 (void *)uap->newset, uap->sigsetsize); 582#endif 583 584 if (uap->sigsetsize != sizeof(l_sigset_t)) 585 return (EINVAL); 586 587 error = copyin(uap->newset, &lmask, sizeof(l_sigset_t)); 588 if (error) 589 return (error); 590 591 linux_to_bsd_sigset(&lmask, &sigmask); 592 return (kern_sigsuspend(td, sigmask)); 593} 594 595int 596linux_pause(struct thread *td, struct linux_pause_args *args) 597{ 598 struct proc *p = td->td_proc; 599 sigset_t sigmask; 600 601#ifdef DEBUG 602 if (ldebug(pause)) 603 printf(ARGS(pause, "")); 604#endif 605 606 PROC_LOCK(p); 607 sigmask = td->td_sigmask; 608 PROC_UNLOCK(p); 609 return (kern_sigsuspend(td, sigmask)); 610} 611 612int 613linux_sigaltstack(struct thread *td, struct linux_sigaltstack_args *uap) 614{ 615 stack_t ss, oss; 616 l_stack_t lss; 617 int error; 618 619#ifdef DEBUG 620 if (ldebug(sigaltstack)) 621 printf(ARGS(sigaltstack, "%p, %p"), uap->uss, uap->uoss); 622#endif 623 624 if (uap->uss != NULL) { 625 error = copyin(uap->uss, &lss, sizeof(l_stack_t)); 626 if (error) 627 return (error); 628 629 ss.ss_sp = PTRIN(lss.ss_sp); 630 ss.ss_size = lss.ss_size; 631 ss.ss_flags = linux_to_bsd_sigaltstack(lss.ss_flags); 632 } 633 error = kern_sigaltstack(td, (uap->uss != NULL) ? &ss : NULL, 634 (uap->uoss != NULL) ? &oss : NULL); 635 if (!error && uap->uoss != NULL) { 636 lss.ss_sp = PTROUT(oss.ss_sp); 637 lss.ss_size = oss.ss_size; 638 lss.ss_flags = bsd_to_linux_sigaltstack(oss.ss_flags); 639 error = copyout(&lss, uap->uoss, sizeof(l_stack_t)); 640 } 641 642 return (error); 643} 644 645int 646linux_ftruncate64(struct thread *td, struct linux_ftruncate64_args *args) 647{ 648 struct ftruncate_args sa; 649 650#ifdef DEBUG 651 if (ldebug(ftruncate64)) 652 printf(ARGS(ftruncate64, "%u, %jd"), args->fd, 653 (intmax_t)args->length); 654#endif 655 656 sa.fd = args->fd; 657 sa.length = args->length; 658 return sys_ftruncate(td, &sa); 659} 660 661int 662linux_gettimeofday(struct thread *td, struct linux_gettimeofday_args *uap) 663{ 664 struct timeval atv; 665 l_timeval atv32; 666 struct timezone rtz; 667 int error = 0; 668 669 if (uap->tp) { 670 microtime(&atv); 671 atv32.tv_sec = atv.tv_sec; 672 atv32.tv_usec = atv.tv_usec; 673 error = copyout(&atv32, uap->tp, sizeof(atv32)); 674 } 675 if (error == 0 && uap->tzp != NULL) { 676 rtz.tz_minuteswest = tz_minuteswest; 677 rtz.tz_dsttime = tz_dsttime; 678 error = copyout(&rtz, uap->tzp, sizeof(rtz)); 679 } 680 return (error); 681} 682 683int 684linux_settimeofday(struct thread *td, struct linux_settimeofday_args *uap) 685{ 686 l_timeval atv32; 687 struct timeval atv, *tvp; 688 struct timezone atz, *tzp; 689 int error; 690 691 if (uap->tp) { 692 error = copyin(uap->tp, &atv32, sizeof(atv32)); 693 if (error) 694 return (error); 695 atv.tv_sec = atv32.tv_sec; 696 atv.tv_usec = atv32.tv_usec; 697 tvp = &atv; 698 } else 699 tvp = NULL; 700 if (uap->tzp) { 701 error = copyin(uap->tzp, &atz, sizeof(atz)); 702 if (error) 703 return (error); 704 tzp = &atz; 705 } else 706 tzp = NULL; 707 return (kern_settimeofday(td, tvp, tzp)); 708} 709 710int 711linux_getrusage(struct thread *td, struct linux_getrusage_args *uap) 712{ 713 struct rusage s; 714 int error; 715 716 error = kern_getrusage(td, uap->who, &s); 717 if (error != 0) 718 return (error); 719 if (uap->rusage != NULL) 720 error = linux_copyout_rusage(&s, uap->rusage); 721 return (error); 722} 723 724int 725linux_set_thread_area(struct thread *td, 726 struct linux_set_thread_area_args *args) 727{ 728 struct l_user_desc info; 729 struct user_segment_descriptor sd; 730 struct pcb *pcb; 731 int a[2]; 732 int error; 733 734 error = copyin(args->desc, &info, sizeof(struct l_user_desc)); 735 if (error) 736 return (error); 737 738#ifdef DEBUG 739 if (ldebug(set_thread_area)) 740 printf(ARGS(set_thread_area, "%i, %x, %x, %i, %i, %i, " 741 "%i, %i, %i"), info.entry_number, info.base_addr, 742 info.limit, info.seg_32bit, info.contents, 743 info.read_exec_only, info.limit_in_pages, 744 info.seg_not_present, info.useable); 745#endif 746 747 /* 748 * Semantics of Linux version: every thread in the system has array 749 * of three TLS descriptors. 1st is GLIBC TLS, 2nd is WINE, 3rd unknown. 750 * This syscall loads one of the selected TLS decriptors with a value 751 * and also loads GDT descriptors 6, 7 and 8 with the content of 752 * the per-thread descriptors. 753 * 754 * Semantics of FreeBSD version: I think we can ignore that Linux has 755 * three per-thread descriptors and use just the first one. 756 * The tls_array[] is used only in [gs]et_thread_area() syscalls and 757 * for loading the GDT descriptors. We use just one GDT descriptor 758 * for TLS, so we will load just one. 759 * 760 * XXX: This doesn't work when a user space process tries to use more 761 * than one TLS segment. Comment in the Linux source says wine might 762 * do this. 763 */ 764 765 /* 766 * GLIBC reads current %gs and call set_thread_area() with it. 767 * We should let GUDATA_SEL and GUGS32_SEL proceed as well because 768 * we use these segments. 769 */ 770 switch (info.entry_number) { 771 case GUGS32_SEL: 772 case GUDATA_SEL: 773 case 6: 774 case -1: 775 info.entry_number = GUGS32_SEL; 776 break; 777 default: 778 return (EINVAL); 779 } 780 781 /* 782 * We have to copy out the GDT entry we use. 783 * 784 * XXX: What if a user space program does not check the return value 785 * and tries to use 6, 7 or 8? 786 */ 787 error = copyout(&info, args->desc, sizeof(struct l_user_desc)); 788 if (error) 789 return (error); 790 791 if (LINUX_LDT_empty(&info)) { 792 a[0] = 0; 793 a[1] = 0; 794 } else { 795 a[0] = LINUX_LDT_entry_a(&info); 796 a[1] = LINUX_LDT_entry_b(&info); 797 } 798 799 memcpy(&sd, &a, sizeof(a)); 800#ifdef DEBUG 801 if (ldebug(set_thread_area)) 802 printf("Segment created in set_thread_area: " 803 "lobase: %x, hibase: %x, lolimit: %x, hilimit: %x, " 804 "type: %i, dpl: %i, p: %i, xx: %i, long: %i, " 805 "def32: %i, gran: %i\n", 806 sd.sd_lobase, 807 sd.sd_hibase, 808 sd.sd_lolimit, 809 sd.sd_hilimit, 810 sd.sd_type, 811 sd.sd_dpl, 812 sd.sd_p, 813 sd.sd_xx, 814 sd.sd_long, 815 sd.sd_def32, 816 sd.sd_gran); 817#endif 818 819 pcb = td->td_pcb; 820 pcb->pcb_gsbase = (register_t)info.base_addr; 821 set_pcb_flags(pcb, PCB_32BIT); 822 update_gdt_gsbase(td, info.base_addr); 823 824 return (0); 825} 826