1ea0fabbcSTim J. Robbins /*- 2ea0fabbcSTim J. Robbins * Copyright (c) 2004 Tim J. Robbins 3ea0fabbcSTim J. Robbins * Copyright (c) 2003 Peter Wemm 4ea0fabbcSTim J. Robbins * Copyright (c) 2002 Doug Rabson 5ea0fabbcSTim J. Robbins * Copyright (c) 1998-1999 Andrew Gallatin 69a14aa01SUlrich Spörlein * Copyright (c) 1994-1996 Søren Schmidt 7ea0fabbcSTim J. Robbins * All rights reserved. 8ea0fabbcSTim J. Robbins * 9ea0fabbcSTim J. Robbins * Redistribution and use in source and binary forms, with or without 10ea0fabbcSTim J. Robbins * modification, are permitted provided that the following conditions 11ea0fabbcSTim J. Robbins * are met: 12ea0fabbcSTim J. Robbins * 1. Redistributions of source code must retain the above copyright 13ea0fabbcSTim J. Robbins * notice, this list of conditions and the following disclaimer 14ea0fabbcSTim J. Robbins * in this position and unchanged. 15ea0fabbcSTim J. Robbins * 2. Redistributions in binary form must reproduce the above copyright 16ea0fabbcSTim J. Robbins * notice, this list of conditions and the following disclaimer in the 17ea0fabbcSTim J. Robbins * documentation and/or other materials provided with the distribution. 18ea0fabbcSTim J. Robbins * 3. The name of the author may not be used to endorse or promote products 19ea0fabbcSTim J. Robbins * derived from this software without specific prior written permission 20ea0fabbcSTim J. Robbins * 21ea0fabbcSTim J. Robbins * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 22ea0fabbcSTim J. Robbins * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 23ea0fabbcSTim J. Robbins * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 24ea0fabbcSTim J. Robbins * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 25ea0fabbcSTim J. Robbins * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 26ea0fabbcSTim J. Robbins * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 27ea0fabbcSTim J. Robbins * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 28ea0fabbcSTim J. Robbins * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 29ea0fabbcSTim J. Robbins * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 30ea0fabbcSTim J. Robbins * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 31ea0fabbcSTim J. Robbins */ 32ea0fabbcSTim J. Robbins 33ea0fabbcSTim J. Robbins #include <sys/cdefs.h> 34ea0fabbcSTim J. Robbins __FBSDID("$FreeBSD$"); 35aefce619SRuslan Ermilov #include "opt_compat.h" 36ea0fabbcSTim J. Robbins 37841c0c7eSNathan Whitehorn #ifndef COMPAT_FREEBSD32 38841c0c7eSNathan Whitehorn #error "Unable to compile Linux-emulator due to missing COMPAT_FREEBSD32 option!" 39ea0fabbcSTim J. Robbins #endif 40ea0fabbcSTim J. Robbins 41ea0fabbcSTim J. Robbins #define __ELF_WORD_SIZE 32 42ea0fabbcSTim J. Robbins 43ea0fabbcSTim J. Robbins #include <sys/param.h> 44ea0fabbcSTim J. Robbins #include <sys/systm.h> 45ea0fabbcSTim J. Robbins #include <sys/exec.h> 4648b05c3fSKonstantin Belousov #include <sys/fcntl.h> 47ea0fabbcSTim J. Robbins #include <sys/imgact.h> 48ea0fabbcSTim J. Robbins #include <sys/imgact_elf.h> 49ea0fabbcSTim J. Robbins #include <sys/kernel.h> 50ea0fabbcSTim J. Robbins #include <sys/lock.h> 51ea0fabbcSTim J. Robbins #include <sys/malloc.h> 52ea0fabbcSTim J. Robbins #include <sys/module.h> 53ea0fabbcSTim J. Robbins #include <sys/mutex.h> 54ea0fabbcSTim J. Robbins #include <sys/proc.h> 556004362eSDavid Schultz #include <sys/resourcevar.h> 56ea0fabbcSTim J. Robbins #include <sys/signalvar.h> 57ea0fabbcSTim J. Robbins #include <sys/sysctl.h> 58ea0fabbcSTim J. Robbins #include <sys/syscallsubr.h> 59ea0fabbcSTim J. Robbins #include <sys/sysent.h> 60ea0fabbcSTim J. Robbins #include <sys/sysproto.h> 61ea0fabbcSTim J. Robbins #include <sys/vnode.h> 627c09e6c0SAlexander Leidinger #include <sys/eventhandler.h> 63ea0fabbcSTim J. Robbins 64ea0fabbcSTim J. Robbins #include <vm/vm.h> 65ea0fabbcSTim J. Robbins #include <vm/pmap.h> 66ea0fabbcSTim J. Robbins #include <vm/vm_extern.h> 67ea0fabbcSTim J. Robbins #include <vm/vm_map.h> 68ea0fabbcSTim J. Robbins #include <vm/vm_object.h> 69ea0fabbcSTim J. Robbins #include <vm/vm_page.h> 70ea0fabbcSTim J. Robbins #include <vm/vm_param.h> 71ea0fabbcSTim J. Robbins 72ea0fabbcSTim J. Robbins #include <machine/cpu.h> 73ea0fabbcSTim J. Robbins #include <machine/md_var.h> 746004362eSDavid Schultz #include <machine/pcb.h> 75ea0fabbcSTim J. Robbins #include <machine/specialreg.h> 76ea0fabbcSTim J. Robbins 77ea0fabbcSTim J. Robbins #include <amd64/linux32/linux.h> 78ea0fabbcSTim J. Robbins #include <amd64/linux32/linux32_proto.h> 797c09e6c0SAlexander Leidinger #include <compat/linux/linux_emul.h> 80fde63162SDmitry Chagin #include <compat/linux/linux_futex.h> 81d825ce0aSJohn Baldwin #include <compat/linux/linux_ioctl.h> 82ea0fabbcSTim J. Robbins #include <compat/linux/linux_mib.h> 834d7c2e8aSDmitry Chagin #include <compat/linux/linux_misc.h> 84ea0fabbcSTim J. Robbins #include <compat/linux/linux_signal.h> 85ea0fabbcSTim J. Robbins #include <compat/linux/linux_util.h> 86*bdc37934SDmitry Chagin #include <compat/linux/linux_vdso.h> 87ea0fabbcSTim J. Robbins 88ea0fabbcSTim J. Robbins MODULE_VERSION(linux, 1); 89ea0fabbcSTim J. Robbins 90ea0fabbcSTim J. Robbins MALLOC_DEFINE(M_LINUX, "linux", "Linux mode structures"); 91ea0fabbcSTim J. Robbins 92ea0fabbcSTim J. Robbins #define AUXARGS_ENTRY_32(pos, id, val) \ 93ea0fabbcSTim J. Robbins do { \ 94ea0fabbcSTim J. Robbins suword32(pos++, id); \ 95ea0fabbcSTim J. Robbins suword32(pos++, val); \ 96ea0fabbcSTim J. Robbins } while (0) 97ea0fabbcSTim J. Robbins 98ea0fabbcSTim J. Robbins #if BYTE_ORDER == LITTLE_ENDIAN 99ea0fabbcSTim J. Robbins #define SHELLMAGIC 0x2123 /* #! */ 100ea0fabbcSTim J. Robbins #else 101ea0fabbcSTim J. Robbins #define SHELLMAGIC 0x2321 102ea0fabbcSTim J. Robbins #endif 103ea0fabbcSTim J. Robbins 104ea0fabbcSTim J. Robbins /* 105ea0fabbcSTim J. Robbins * Allow the sendsig functions to use the ldebug() facility 106ea0fabbcSTim J. Robbins * even though they are not syscalls themselves. Map them 107ea0fabbcSTim J. Robbins * to syscall 0. This is slightly less bogus than using 108ea0fabbcSTim J. Robbins * ldebug(sigreturn). 109ea0fabbcSTim J. Robbins */ 110ea0fabbcSTim J. Robbins #define LINUX_SYS_linux_rt_sendsig 0 111ea0fabbcSTim J. Robbins #define LINUX_SYS_linux_sendsig 0 112ea0fabbcSTim J. Robbins 1134d7c2e8aSDmitry Chagin const char *linux_platform = "i686"; 1144d7c2e8aSDmitry Chagin static int linux_szplatform; 115*bdc37934SDmitry Chagin static int linux_szsigcode; 116*bdc37934SDmitry Chagin static vm_object_t linux_shared_page_obj; 117*bdc37934SDmitry Chagin static char *linux_shared_page_mapping; 118*bdc37934SDmitry Chagin extern char _binary_linux32_locore_o_start; 119*bdc37934SDmitry Chagin extern char _binary_linux32_locore_o_end; 120ea0fabbcSTim J. Robbins 121ea0fabbcSTim J. Robbins extern struct sysent linux_sysent[LINUX_SYS_MAXSYSCALL]; 122ea0fabbcSTim J. Robbins 123ea0fabbcSTim J. Robbins SET_DECLARE(linux_ioctl_handler_set, struct linux_ioctl_handler); 124387196bfSDoug Ambrisko SET_DECLARE(linux_device_handler_set, struct linux_device_handler); 125ea0fabbcSTim J. Robbins 126ea0fabbcSTim J. Robbins static int elf_linux_fixup(register_t **stack_base, 127ea0fabbcSTim J. Robbins struct image_params *iparams); 128ea0fabbcSTim J. Robbins static register_t *linux_copyout_strings(struct image_params *imgp); 1299104847fSDavid Xu static void linux_sendsig(sig_t catcher, ksiginfo_t *ksi, sigset_t *mask); 130a107d8aaSNathan Whitehorn static void exec_linux_setregs(struct thread *td, 131a107d8aaSNathan Whitehorn struct image_params *imgp, u_long stack); 13219059a13SJohn Baldwin static void linux32_fixlimit(struct rlimit *rl, int which); 13389ffc202SBjoern A. Zeeb static boolean_t linux32_trans_osrel(const Elf_Note *note, int32_t *osrel); 134*bdc37934SDmitry Chagin static void linux_vdso_install(void *param); 135*bdc37934SDmitry Chagin static void linux_vdso_deinstall(void *param); 136ea0fabbcSTim J. Robbins 1377c09e6c0SAlexander Leidinger static eventhandler_tag linux_exit_tag; 1387c09e6c0SAlexander Leidinger static eventhandler_tag linux_exec_tag; 13981338031SDmitry Chagin static eventhandler_tag linux_thread_dtor_tag; 1407c09e6c0SAlexander Leidinger 141ea0fabbcSTim J. Robbins /* 142ea0fabbcSTim J. Robbins * Linux syscalls return negative errno's, we do positive and map them 14350e422f0SAlexander Leidinger * Reference: 14450e422f0SAlexander Leidinger * FreeBSD: src/sys/sys/errno.h 14550e422f0SAlexander Leidinger * Linux: linux-2.6.17.8/include/asm-generic/errno-base.h 14650e422f0SAlexander Leidinger * linux-2.6.17.8/include/asm-generic/errno.h 147ea0fabbcSTim J. Robbins */ 148ea0fabbcSTim J. Robbins static int bsd_to_linux_errno[ELAST + 1] = { 149ea0fabbcSTim J. Robbins -0, -1, -2, -3, -4, -5, -6, -7, -8, -9, 150ea0fabbcSTim J. Robbins -10, -35, -12, -13, -14, -15, -16, -17, -18, -19, 151ea0fabbcSTim J. Robbins -20, -21, -22, -23, -24, -25, -26, -27, -28, -29, 152ea0fabbcSTim J. Robbins -30, -31, -32, -33, -34, -11,-115,-114, -88, -89, 153ea0fabbcSTim J. Robbins -90, -91, -92, -93, -94, -95, -96, -97, -98, -99, 154ea0fabbcSTim J. Robbins -100,-101,-102,-103,-104,-105,-106,-107,-108,-109, 155ea0fabbcSTim J. Robbins -110,-111, -40, -36,-112,-113, -39, -11, -87,-122, 156ea0fabbcSTim J. Robbins -116, -66, -6, -6, -6, -6, -6, -37, -38, -9, 15750e422f0SAlexander Leidinger -6, -6, -43, -42, -75,-125, -84, -95, -16, -74, 15850e422f0SAlexander Leidinger -72, -67, -71 159ea0fabbcSTim J. Robbins }; 160ea0fabbcSTim J. Robbins 161ea0fabbcSTim J. Robbins int bsd_to_linux_signal[LINUX_SIGTBLSZ] = { 162ea0fabbcSTim J. Robbins LINUX_SIGHUP, LINUX_SIGINT, LINUX_SIGQUIT, LINUX_SIGILL, 163ea0fabbcSTim J. Robbins LINUX_SIGTRAP, LINUX_SIGABRT, 0, LINUX_SIGFPE, 164ea0fabbcSTim J. Robbins LINUX_SIGKILL, LINUX_SIGBUS, LINUX_SIGSEGV, LINUX_SIGSYS, 165ea0fabbcSTim J. Robbins LINUX_SIGPIPE, LINUX_SIGALRM, LINUX_SIGTERM, LINUX_SIGURG, 166ea0fabbcSTim J. Robbins LINUX_SIGSTOP, LINUX_SIGTSTP, LINUX_SIGCONT, LINUX_SIGCHLD, 167ea0fabbcSTim J. Robbins LINUX_SIGTTIN, LINUX_SIGTTOU, LINUX_SIGIO, LINUX_SIGXCPU, 168ea0fabbcSTim J. Robbins LINUX_SIGXFSZ, LINUX_SIGVTALRM, LINUX_SIGPROF, LINUX_SIGWINCH, 169ea0fabbcSTim J. Robbins 0, LINUX_SIGUSR1, LINUX_SIGUSR2 170ea0fabbcSTim J. Robbins }; 171ea0fabbcSTim J. Robbins 172ea0fabbcSTim J. Robbins int linux_to_bsd_signal[LINUX_SIGTBLSZ] = { 173ea0fabbcSTim J. Robbins SIGHUP, SIGINT, SIGQUIT, SIGILL, 174ea0fabbcSTim J. Robbins SIGTRAP, SIGABRT, SIGBUS, SIGFPE, 175ea0fabbcSTim J. Robbins SIGKILL, SIGUSR1, SIGSEGV, SIGUSR2, 176ea0fabbcSTim J. Robbins SIGPIPE, SIGALRM, SIGTERM, SIGBUS, 177ea0fabbcSTim J. Robbins SIGCHLD, SIGCONT, SIGSTOP, SIGTSTP, 178ea0fabbcSTim J. Robbins SIGTTIN, SIGTTOU, SIGURG, SIGXCPU, 179ea0fabbcSTim J. Robbins SIGXFSZ, SIGVTALRM, SIGPROF, SIGWINCH, 180ea0fabbcSTim J. Robbins SIGIO, SIGURG, SIGSYS 181ea0fabbcSTim J. Robbins }; 182ea0fabbcSTim J. Robbins 183ea0fabbcSTim J. Robbins #define LINUX_T_UNKNOWN 255 184ea0fabbcSTim J. Robbins static int _bsd_to_linux_trapcode[] = { 185ea0fabbcSTim J. Robbins LINUX_T_UNKNOWN, /* 0 */ 186ea0fabbcSTim J. Robbins 6, /* 1 T_PRIVINFLT */ 187ea0fabbcSTim J. Robbins LINUX_T_UNKNOWN, /* 2 */ 188ea0fabbcSTim J. Robbins 3, /* 3 T_BPTFLT */ 189ea0fabbcSTim J. Robbins LINUX_T_UNKNOWN, /* 4 */ 190ea0fabbcSTim J. Robbins LINUX_T_UNKNOWN, /* 5 */ 191ea0fabbcSTim J. Robbins 16, /* 6 T_ARITHTRAP */ 192ea0fabbcSTim J. Robbins 254, /* 7 T_ASTFLT */ 193ea0fabbcSTim J. Robbins LINUX_T_UNKNOWN, /* 8 */ 194ea0fabbcSTim J. Robbins 13, /* 9 T_PROTFLT */ 195ea0fabbcSTim J. Robbins 1, /* 10 T_TRCTRAP */ 196ea0fabbcSTim J. Robbins LINUX_T_UNKNOWN, /* 11 */ 197ea0fabbcSTim J. Robbins 14, /* 12 T_PAGEFLT */ 198ea0fabbcSTim J. Robbins LINUX_T_UNKNOWN, /* 13 */ 199ea0fabbcSTim J. Robbins 17, /* 14 T_ALIGNFLT */ 200ea0fabbcSTim J. Robbins LINUX_T_UNKNOWN, /* 15 */ 201ea0fabbcSTim J. Robbins LINUX_T_UNKNOWN, /* 16 */ 202ea0fabbcSTim J. Robbins LINUX_T_UNKNOWN, /* 17 */ 203ea0fabbcSTim J. Robbins 0, /* 18 T_DIVIDE */ 204ea0fabbcSTim J. Robbins 2, /* 19 T_NMI */ 205ea0fabbcSTim J. Robbins 4, /* 20 T_OFLOW */ 206ea0fabbcSTim J. Robbins 5, /* 21 T_BOUND */ 207ea0fabbcSTim J. Robbins 7, /* 22 T_DNA */ 208ea0fabbcSTim J. Robbins 8, /* 23 T_DOUBLEFLT */ 209ea0fabbcSTim J. Robbins 9, /* 24 T_FPOPFLT */ 210ea0fabbcSTim J. Robbins 10, /* 25 T_TSSFLT */ 211ea0fabbcSTim J. Robbins 11, /* 26 T_SEGNPFLT */ 212ea0fabbcSTim J. Robbins 12, /* 27 T_STKFLT */ 213ea0fabbcSTim J. Robbins 18, /* 28 T_MCHK */ 214ea0fabbcSTim J. Robbins 19, /* 29 T_XMMFLT */ 215ea0fabbcSTim J. Robbins 15 /* 30 T_RESERVED */ 216ea0fabbcSTim J. Robbins }; 217ea0fabbcSTim J. Robbins #define bsd_to_linux_trapcode(code) \ 218ea0fabbcSTim J. Robbins ((code)<sizeof(_bsd_to_linux_trapcode)/sizeof(*_bsd_to_linux_trapcode)? \ 219ea0fabbcSTim J. Robbins _bsd_to_linux_trapcode[(code)]: \ 220ea0fabbcSTim J. Robbins LINUX_T_UNKNOWN) 221ea0fabbcSTim J. Robbins 222ea0fabbcSTim J. Robbins struct linux32_ps_strings { 223ea0fabbcSTim J. Robbins u_int32_t ps_argvstr; /* first of 0 or more argument strings */ 224f2c7668eSDavid Schultz u_int ps_nargvstr; /* the number of argument strings */ 225ea0fabbcSTim J. Robbins u_int32_t ps_envstr; /* first of 0 or more environment strings */ 226f2c7668eSDavid Schultz u_int ps_nenvstr; /* the number of environment strings */ 227ea0fabbcSTim J. Robbins }; 228ea0fabbcSTim J. Robbins 229*bdc37934SDmitry Chagin LINUX_VDSO_SYM_INTPTR(linux32_sigcode); 230*bdc37934SDmitry Chagin LINUX_VDSO_SYM_INTPTR(linux32_rt_sigcode); 231*bdc37934SDmitry Chagin LINUX_VDSO_SYM_INTPTR(linux32_vsyscall); 232*bdc37934SDmitry Chagin 233ea0fabbcSTim J. Robbins /* 234ea0fabbcSTim J. Robbins * If FreeBSD & Linux have a difference of opinion about what a trap 235ea0fabbcSTim J. Robbins * means, deal with it here. 236ea0fabbcSTim J. Robbins * 237ea0fabbcSTim J. Robbins * MPSAFE 238ea0fabbcSTim J. Robbins */ 239ea0fabbcSTim J. Robbins static int 240ea0fabbcSTim J. Robbins translate_traps(int signal, int trap_code) 241ea0fabbcSTim J. Robbins { 242ea0fabbcSTim J. Robbins if (signal != SIGBUS) 243ea0fabbcSTim J. Robbins return signal; 244ea0fabbcSTim J. Robbins switch (trap_code) { 245ea0fabbcSTim J. Robbins case T_PROTFLT: 246ea0fabbcSTim J. Robbins case T_TSSFLT: 247ea0fabbcSTim J. Robbins case T_DOUBLEFLT: 248ea0fabbcSTim J. Robbins case T_PAGEFLT: 249ea0fabbcSTim J. Robbins return SIGSEGV; 250ea0fabbcSTim J. Robbins default: 251ea0fabbcSTim J. Robbins return signal; 252ea0fabbcSTim J. Robbins } 253ea0fabbcSTim J. Robbins } 254ea0fabbcSTim J. Robbins 255ea0fabbcSTim J. Robbins static int 256ea0fabbcSTim J. Robbins elf_linux_fixup(register_t **stack_base, struct image_params *imgp) 257ea0fabbcSTim J. Robbins { 258ea0fabbcSTim J. Robbins Elf32_Auxargs *args; 259ea0fabbcSTim J. Robbins Elf32_Addr *base; 2604d7c2e8aSDmitry Chagin Elf32_Addr *pos, *uplatform; 2614d7c2e8aSDmitry Chagin struct linux32_ps_strings *arginfo; 2624d7c2e8aSDmitry Chagin 2634d7c2e8aSDmitry Chagin arginfo = (struct linux32_ps_strings *)LINUX32_PS_STRINGS; 264acface68SDmitry Chagin uplatform = (Elf32_Addr *)((caddr_t)arginfo - linux_szplatform); 265ea0fabbcSTim J. Robbins 2666617724cSJeff Roberson KASSERT(curthread->td_proc == imgp->proc, 267ea0fabbcSTim J. Robbins ("unsafe elf_linux_fixup(), should be curproc")); 268ea0fabbcSTim J. Robbins base = (Elf32_Addr *)*stack_base; 269ea0fabbcSTim J. Robbins args = (Elf32_Auxargs *)imgp->auxargs; 270610ecfe0SMaxim Sobolev pos = base + (imgp->args->argc + imgp->args->envc + 2); 271ea0fabbcSTim J. Robbins 272*bdc37934SDmitry Chagin AUXARGS_ENTRY_32(pos, LINUX_AT_SYSINFO_EHDR, 273*bdc37934SDmitry Chagin imgp->proc->p_sysent->sv_shared_page_base); 274*bdc37934SDmitry Chagin AUXARGS_ENTRY_32(pos, LINUX_AT_SYSINFO, linux32_vsyscall); 2754d7c2e8aSDmitry Chagin AUXARGS_ENTRY_32(pos, LINUX_AT_HWCAP, cpu_feature); 2768d30f381SDmitry Chagin 2778d30f381SDmitry Chagin /* 2788d30f381SDmitry Chagin * Do not export AT_CLKTCK when emulating Linux kernel prior to 2.4.0, 2798d30f381SDmitry Chagin * as it has appeared in the 2.4.0-rc7 first time. 2808d30f381SDmitry Chagin * Being exported, AT_CLKTCK is returned by sysconf(_SC_CLK_TCK), 2818d30f381SDmitry Chagin * glibc falls back to the hard-coded CLK_TCK value when aux entry 2828d30f381SDmitry Chagin * is not present. 2838d30f381SDmitry Chagin * Also see linux_times() implementation. 2848d30f381SDmitry Chagin */ 2858d30f381SDmitry Chagin if (linux_kernver(curthread) >= LINUX_KERNVER_2004000) 2861ca16454SDmitry Chagin AUXARGS_ENTRY_32(pos, LINUX_AT_CLKTCK, stclohz); 287ea0fabbcSTim J. Robbins AUXARGS_ENTRY_32(pos, AT_PHDR, args->phdr); 288ea0fabbcSTim J. Robbins AUXARGS_ENTRY_32(pos, AT_PHENT, args->phent); 289ea0fabbcSTim J. Robbins AUXARGS_ENTRY_32(pos, AT_PHNUM, args->phnum); 290ea0fabbcSTim J. Robbins AUXARGS_ENTRY_32(pos, AT_PAGESZ, args->pagesz); 291ea0fabbcSTim J. Robbins AUXARGS_ENTRY_32(pos, AT_FLAGS, args->flags); 292ea0fabbcSTim J. Robbins AUXARGS_ENTRY_32(pos, AT_ENTRY, args->entry); 293ea0fabbcSTim J. Robbins AUXARGS_ENTRY_32(pos, AT_BASE, args->base); 2944d7c2e8aSDmitry Chagin AUXARGS_ENTRY_32(pos, LINUX_AT_SECURE, 0); 295ea0fabbcSTim J. Robbins AUXARGS_ENTRY_32(pos, AT_UID, imgp->proc->p_ucred->cr_ruid); 296ea0fabbcSTim J. Robbins AUXARGS_ENTRY_32(pos, AT_EUID, imgp->proc->p_ucred->cr_svuid); 297ea0fabbcSTim J. Robbins AUXARGS_ENTRY_32(pos, AT_GID, imgp->proc->p_ucred->cr_rgid); 298ea0fabbcSTim J. Robbins AUXARGS_ENTRY_32(pos, AT_EGID, imgp->proc->p_ucred->cr_svgid); 2994d7c2e8aSDmitry Chagin AUXARGS_ENTRY_32(pos, LINUX_AT_PLATFORM, PTROUT(uplatform)); 3004d7c2e8aSDmitry Chagin if (args->execfd != -1) 3014d7c2e8aSDmitry Chagin AUXARGS_ENTRY_32(pos, AT_EXECFD, args->execfd); 302ea0fabbcSTim J. Robbins AUXARGS_ENTRY_32(pos, AT_NULL, 0); 303ea0fabbcSTim J. Robbins 304ea0fabbcSTim J. Robbins free(imgp->auxargs, M_TEMP); 305ea0fabbcSTim J. Robbins imgp->auxargs = NULL; 306ea0fabbcSTim J. Robbins 307ea0fabbcSTim J. Robbins base--; 308610ecfe0SMaxim Sobolev suword32(base, (uint32_t)imgp->args->argc); 309ea0fabbcSTim J. Robbins *stack_base = (register_t *)base; 310af682d48SDmitry Chagin return (0); 311ea0fabbcSTim J. Robbins } 312ea0fabbcSTim J. Robbins 313ea0fabbcSTim J. Robbins static void 3149104847fSDavid Xu linux_rt_sendsig(sig_t catcher, ksiginfo_t *ksi, sigset_t *mask) 315ea0fabbcSTim J. Robbins { 316ea0fabbcSTim J. Robbins struct thread *td = curthread; 317ea0fabbcSTim J. Robbins struct proc *p = td->td_proc; 318ea0fabbcSTim J. Robbins struct sigacts *psp; 319ea0fabbcSTim J. Robbins struct trapframe *regs; 320ea0fabbcSTim J. Robbins struct l_rt_sigframe *fp, frame; 321ea0fabbcSTim J. Robbins int oonstack; 3229104847fSDavid Xu int sig; 3239104847fSDavid Xu int code; 324ea0fabbcSTim J. Robbins 3259104847fSDavid Xu sig = ksi->ksi_signo; 3269104847fSDavid Xu code = ksi->ksi_code; 327ea0fabbcSTim J. Robbins PROC_LOCK_ASSERT(p, MA_OWNED); 328ea0fabbcSTim J. Robbins psp = p->p_sigacts; 329ea0fabbcSTim J. Robbins mtx_assert(&psp->ps_mtx, MA_OWNED); 330ea0fabbcSTim J. Robbins regs = td->td_frame; 331ea0fabbcSTim J. Robbins oonstack = sigonstack(regs->tf_rsp); 332ea0fabbcSTim J. Robbins 333ea0fabbcSTim J. Robbins #ifdef DEBUG 334ea0fabbcSTim J. Robbins if (ldebug(rt_sendsig)) 335728ef954SJohn Baldwin printf(ARGS(rt_sendsig, "%p, %d, %p, %u"), 336ea0fabbcSTim J. Robbins catcher, sig, (void*)mask, code); 337ea0fabbcSTim J. Robbins #endif 338ea0fabbcSTim J. Robbins /* 339ea0fabbcSTim J. Robbins * Allocate space for the signal handler context. 340ea0fabbcSTim J. Robbins */ 341ea0fabbcSTim J. Robbins if ((td->td_pflags & TDP_ALTSTACK) && !oonstack && 342ea0fabbcSTim J. Robbins SIGISMEMBER(psp->ps_sigonstack, sig)) { 343ea0fabbcSTim J. Robbins fp = (struct l_rt_sigframe *)(td->td_sigstk.ss_sp + 344ea0fabbcSTim J. Robbins td->td_sigstk.ss_size - sizeof(struct l_rt_sigframe)); 345ea0fabbcSTim J. Robbins } else 346ea0fabbcSTim J. Robbins fp = (struct l_rt_sigframe *)regs->tf_rsp - 1; 347ea0fabbcSTim J. Robbins mtx_unlock(&psp->ps_mtx); 348ea0fabbcSTim J. Robbins 349ea0fabbcSTim J. Robbins /* 350ea0fabbcSTim J. Robbins * Build the argument list for the signal handler. 351ea0fabbcSTim J. Robbins */ 352ea0fabbcSTim J. Robbins if (p->p_sysent->sv_sigtbl) 353ea0fabbcSTim J. Robbins if (sig <= p->p_sysent->sv_sigsize) 354ea0fabbcSTim J. Robbins sig = p->p_sysent->sv_sigtbl[_SIG_IDX(sig)]; 355ea0fabbcSTim J. Robbins 356ea0fabbcSTim J. Robbins bzero(&frame, sizeof(frame)); 357ea0fabbcSTim J. Robbins 358ea0fabbcSTim J. Robbins frame.sf_handler = PTROUT(catcher); 359ea0fabbcSTim J. Robbins frame.sf_sig = sig; 360ea0fabbcSTim J. Robbins frame.sf_siginfo = PTROUT(&fp->sf_si); 361ea0fabbcSTim J. Robbins frame.sf_ucontext = PTROUT(&fp->sf_sc); 362ea0fabbcSTim J. Robbins 363ea0fabbcSTim J. Robbins /* Fill in POSIX parts */ 364aa8b2011SKonstantin Belousov ksiginfo_to_lsiginfo(ksi, &frame.sf_si, sig); 365ea0fabbcSTim J. Robbins 366ea0fabbcSTim J. Robbins /* 367*bdc37934SDmitry Chagin * Build the signal context to be used by sigreturn 368*bdc37934SDmitry Chagin * and libgcc unwind. 369ea0fabbcSTim J. Robbins */ 370ea0fabbcSTim J. Robbins frame.sf_sc.uc_flags = 0; /* XXX ??? */ 371ea0fabbcSTim J. Robbins frame.sf_sc.uc_link = 0; /* XXX ??? */ 372ea0fabbcSTim J. Robbins 373ea0fabbcSTim J. Robbins frame.sf_sc.uc_stack.ss_sp = PTROUT(td->td_sigstk.ss_sp); 374ea0fabbcSTim J. Robbins frame.sf_sc.uc_stack.ss_size = td->td_sigstk.ss_size; 375ea0fabbcSTim J. Robbins frame.sf_sc.uc_stack.ss_flags = (td->td_pflags & TDP_ALTSTACK) 376ea0fabbcSTim J. Robbins ? ((oonstack) ? LINUX_SS_ONSTACK : 0) : LINUX_SS_DISABLE; 377ea0fabbcSTim J. Robbins PROC_UNLOCK(p); 378ea0fabbcSTim J. Robbins 379ea0fabbcSTim J. Robbins bsd_to_linux_sigset(mask, &frame.sf_sc.uc_sigmask); 380ea0fabbcSTim J. Robbins 381ea0fabbcSTim J. Robbins frame.sf_sc.uc_mcontext.sc_mask = frame.sf_sc.uc_sigmask.__bits[0]; 382ea0fabbcSTim J. Robbins frame.sf_sc.uc_mcontext.sc_edi = regs->tf_rdi; 383ea0fabbcSTim J. Robbins frame.sf_sc.uc_mcontext.sc_esi = regs->tf_rsi; 384ea0fabbcSTim J. Robbins frame.sf_sc.uc_mcontext.sc_ebp = regs->tf_rbp; 385ea0fabbcSTim J. Robbins frame.sf_sc.uc_mcontext.sc_ebx = regs->tf_rbx; 386*bdc37934SDmitry Chagin frame.sf_sc.uc_mcontext.sc_esp = regs->tf_rsp; 387ea0fabbcSTim J. Robbins frame.sf_sc.uc_mcontext.sc_edx = regs->tf_rdx; 388ea0fabbcSTim J. Robbins frame.sf_sc.uc_mcontext.sc_ecx = regs->tf_rcx; 389ea0fabbcSTim J. Robbins frame.sf_sc.uc_mcontext.sc_eax = regs->tf_rax; 390ea0fabbcSTim J. Robbins frame.sf_sc.uc_mcontext.sc_eip = regs->tf_rip; 391ea0fabbcSTim J. Robbins frame.sf_sc.uc_mcontext.sc_cs = regs->tf_cs; 3922c66cccaSKonstantin Belousov frame.sf_sc.uc_mcontext.sc_gs = regs->tf_gs; 3932c66cccaSKonstantin Belousov frame.sf_sc.uc_mcontext.sc_fs = regs->tf_fs; 3942c66cccaSKonstantin Belousov frame.sf_sc.uc_mcontext.sc_es = regs->tf_es; 3952c66cccaSKonstantin Belousov frame.sf_sc.uc_mcontext.sc_ds = regs->tf_ds; 396ea0fabbcSTim J. Robbins frame.sf_sc.uc_mcontext.sc_eflags = regs->tf_rflags; 397ea0fabbcSTim J. Robbins frame.sf_sc.uc_mcontext.sc_esp_at_signal = regs->tf_rsp; 398ea0fabbcSTim J. Robbins frame.sf_sc.uc_mcontext.sc_ss = regs->tf_ss; 399ea0fabbcSTim J. Robbins frame.sf_sc.uc_mcontext.sc_err = regs->tf_err; 40096a2b635SKonstantin Belousov frame.sf_sc.uc_mcontext.sc_cr2 = (u_int32_t)(uintptr_t)ksi->ksi_addr; 401ea0fabbcSTim J. Robbins frame.sf_sc.uc_mcontext.sc_trapno = bsd_to_linux_trapcode(code); 402ea0fabbcSTim J. Robbins 403ea0fabbcSTim J. Robbins #ifdef DEBUG 404ea0fabbcSTim J. Robbins if (ldebug(rt_sendsig)) 405c680f6b1SDavid E. O'Brien printf(LMSG("rt_sendsig flags: 0x%x, sp: %p, ss: 0x%lx, mask: 0x%x"), 406ea0fabbcSTim J. Robbins frame.sf_sc.uc_stack.ss_flags, td->td_sigstk.ss_sp, 407ea0fabbcSTim J. Robbins td->td_sigstk.ss_size, frame.sf_sc.uc_mcontext.sc_mask); 408ea0fabbcSTim J. Robbins #endif 409ea0fabbcSTim J. Robbins 410ea0fabbcSTim J. Robbins if (copyout(&frame, fp, sizeof(frame)) != 0) { 411ea0fabbcSTim J. Robbins /* 412ea0fabbcSTim J. Robbins * Process has trashed its stack; give it an illegal 413ea0fabbcSTim J. Robbins * instruction to halt it in its tracks. 414ea0fabbcSTim J. Robbins */ 415ea0fabbcSTim J. Robbins #ifdef DEBUG 416ea0fabbcSTim J. Robbins if (ldebug(rt_sendsig)) 417ea0fabbcSTim J. Robbins printf(LMSG("rt_sendsig: bad stack %p, oonstack=%x"), 418ea0fabbcSTim J. Robbins fp, oonstack); 419ea0fabbcSTim J. Robbins #endif 420ea0fabbcSTim J. Robbins PROC_LOCK(p); 421ea0fabbcSTim J. Robbins sigexit(td, SIGILL); 422ea0fabbcSTim J. Robbins } 423ea0fabbcSTim J. Robbins 424ea0fabbcSTim J. Robbins /* 425ea0fabbcSTim J. Robbins * Build context to run handler in. 426ea0fabbcSTim J. Robbins */ 427ea0fabbcSTim J. Robbins regs->tf_rsp = PTROUT(fp); 428*bdc37934SDmitry Chagin regs->tf_rip = linux32_rt_sigcode; 42922eca0bfSKonstantin Belousov regs->tf_rflags &= ~(PSL_T | PSL_D); 430ea0fabbcSTim J. Robbins regs->tf_cs = _ucode32sel; 431ea0fabbcSTim J. Robbins regs->tf_ss = _udatasel; 4322c66cccaSKonstantin Belousov regs->tf_ds = _udatasel; 4332c66cccaSKonstantin Belousov regs->tf_es = _udatasel; 4342c66cccaSKonstantin Belousov regs->tf_fs = _ufssel; 4352c66cccaSKonstantin Belousov regs->tf_gs = _ugssel; 4362c66cccaSKonstantin Belousov regs->tf_flags = TF_HASSEGS; 437e6c006d9SJung-uk Kim set_pcb_flags(td->td_pcb, PCB_FULL_IRET); 438ea0fabbcSTim J. Robbins PROC_LOCK(p); 439ea0fabbcSTim J. Robbins mtx_lock(&psp->ps_mtx); 440ea0fabbcSTim J. Robbins } 441ea0fabbcSTim J. Robbins 442ea0fabbcSTim J. Robbins 443ea0fabbcSTim J. Robbins /* 444ea0fabbcSTim J. Robbins * Send an interrupt to process. 445ea0fabbcSTim J. Robbins * 446ea0fabbcSTim J. Robbins * Stack is set up to allow sigcode stored 447ea0fabbcSTim J. Robbins * in u. to call routine, followed by kcall 448ea0fabbcSTim J. Robbins * to sigreturn routine below. After sigreturn 449ea0fabbcSTim J. Robbins * resets the signal mask, the stack, and the 450ea0fabbcSTim J. Robbins * frame pointer, it returns to the user 451ea0fabbcSTim J. Robbins * specified pc, psl. 452ea0fabbcSTim J. Robbins */ 453ea0fabbcSTim J. Robbins static void 4549104847fSDavid Xu linux_sendsig(sig_t catcher, ksiginfo_t *ksi, sigset_t *mask) 455ea0fabbcSTim J. Robbins { 456ea0fabbcSTim J. Robbins struct thread *td = curthread; 457ea0fabbcSTim J. Robbins struct proc *p = td->td_proc; 458ea0fabbcSTim J. Robbins struct sigacts *psp; 459ea0fabbcSTim J. Robbins struct trapframe *regs; 460ea0fabbcSTim J. Robbins struct l_sigframe *fp, frame; 461ea0fabbcSTim J. Robbins l_sigset_t lmask; 462ea0fabbcSTim J. Robbins int oonstack, i; 4639104847fSDavid Xu int sig, code; 464ea0fabbcSTim J. Robbins 4659104847fSDavid Xu sig = ksi->ksi_signo; 4669104847fSDavid Xu code = ksi->ksi_code; 467ea0fabbcSTim J. Robbins PROC_LOCK_ASSERT(p, MA_OWNED); 468ea0fabbcSTim J. Robbins psp = p->p_sigacts; 469ea0fabbcSTim J. Robbins mtx_assert(&psp->ps_mtx, MA_OWNED); 470ea0fabbcSTim J. Robbins if (SIGISMEMBER(psp->ps_siginfo, sig)) { 471ea0fabbcSTim J. Robbins /* Signal handler installed with SA_SIGINFO. */ 4729104847fSDavid Xu linux_rt_sendsig(catcher, ksi, mask); 473ea0fabbcSTim J. Robbins return; 474ea0fabbcSTim J. Robbins } 475ea0fabbcSTim J. Robbins 476ea0fabbcSTim J. Robbins regs = td->td_frame; 477ea0fabbcSTim J. Robbins oonstack = sigonstack(regs->tf_rsp); 478ea0fabbcSTim J. Robbins 479ea0fabbcSTim J. Robbins #ifdef DEBUG 480ea0fabbcSTim J. Robbins if (ldebug(sendsig)) 481728ef954SJohn Baldwin printf(ARGS(sendsig, "%p, %d, %p, %u"), 482ea0fabbcSTim J. Robbins catcher, sig, (void*)mask, code); 483ea0fabbcSTim J. Robbins #endif 484ea0fabbcSTim J. Robbins 485ea0fabbcSTim J. Robbins /* 486ea0fabbcSTim J. Robbins * Allocate space for the signal handler context. 487ea0fabbcSTim J. Robbins */ 488ea0fabbcSTim J. Robbins if ((td->td_pflags & TDP_ALTSTACK) && !oonstack && 489ea0fabbcSTim J. Robbins SIGISMEMBER(psp->ps_sigonstack, sig)) { 490ea0fabbcSTim J. Robbins fp = (struct l_sigframe *)(td->td_sigstk.ss_sp + 491ea0fabbcSTim J. Robbins td->td_sigstk.ss_size - sizeof(struct l_sigframe)); 492ea0fabbcSTim J. Robbins } else 493ea0fabbcSTim J. Robbins fp = (struct l_sigframe *)regs->tf_rsp - 1; 494ea0fabbcSTim J. Robbins mtx_unlock(&psp->ps_mtx); 495ea0fabbcSTim J. Robbins PROC_UNLOCK(p); 496ea0fabbcSTim J. Robbins 497ea0fabbcSTim J. Robbins /* 498ea0fabbcSTim J. Robbins * Build the argument list for the signal handler. 499ea0fabbcSTim J. Robbins */ 500ea0fabbcSTim J. Robbins if (p->p_sysent->sv_sigtbl) 501ea0fabbcSTim J. Robbins if (sig <= p->p_sysent->sv_sigsize) 502ea0fabbcSTim J. Robbins sig = p->p_sysent->sv_sigtbl[_SIG_IDX(sig)]; 503ea0fabbcSTim J. Robbins 504ea0fabbcSTim J. Robbins bzero(&frame, sizeof(frame)); 505ea0fabbcSTim J. Robbins 506ea0fabbcSTim J. Robbins frame.sf_handler = PTROUT(catcher); 507ea0fabbcSTim J. Robbins frame.sf_sig = sig; 508ea0fabbcSTim J. Robbins 509ea0fabbcSTim J. Robbins bsd_to_linux_sigset(mask, &lmask); 510ea0fabbcSTim J. Robbins 511ea0fabbcSTim J. Robbins /* 512ea0fabbcSTim J. Robbins * Build the signal context to be used by sigreturn. 513ea0fabbcSTim J. Robbins */ 514ea0fabbcSTim J. Robbins frame.sf_sc.sc_mask = lmask.__bits[0]; 5152c66cccaSKonstantin Belousov frame.sf_sc.sc_gs = regs->tf_gs; 5162c66cccaSKonstantin Belousov frame.sf_sc.sc_fs = regs->tf_fs; 5172c66cccaSKonstantin Belousov frame.sf_sc.sc_es = regs->tf_es; 5182c66cccaSKonstantin Belousov frame.sf_sc.sc_ds = regs->tf_ds; 519ea0fabbcSTim J. Robbins frame.sf_sc.sc_edi = regs->tf_rdi; 520ea0fabbcSTim J. Robbins frame.sf_sc.sc_esi = regs->tf_rsi; 521ea0fabbcSTim J. Robbins frame.sf_sc.sc_ebp = regs->tf_rbp; 522ea0fabbcSTim J. Robbins frame.sf_sc.sc_ebx = regs->tf_rbx; 523*bdc37934SDmitry Chagin frame.sf_sc.sc_esp = regs->tf_rsp; 524ea0fabbcSTim J. Robbins frame.sf_sc.sc_edx = regs->tf_rdx; 525ea0fabbcSTim J. Robbins frame.sf_sc.sc_ecx = regs->tf_rcx; 526ea0fabbcSTim J. Robbins frame.sf_sc.sc_eax = regs->tf_rax; 527ea0fabbcSTim J. Robbins frame.sf_sc.sc_eip = regs->tf_rip; 528ea0fabbcSTim J. Robbins frame.sf_sc.sc_cs = regs->tf_cs; 529ea0fabbcSTim J. Robbins frame.sf_sc.sc_eflags = regs->tf_rflags; 530ea0fabbcSTim J. Robbins frame.sf_sc.sc_esp_at_signal = regs->tf_rsp; 531ea0fabbcSTim J. Robbins frame.sf_sc.sc_ss = regs->tf_ss; 532ea0fabbcSTim J. Robbins frame.sf_sc.sc_err = regs->tf_err; 53396a2b635SKonstantin Belousov frame.sf_sc.sc_cr2 = (u_int32_t)(uintptr_t)ksi->ksi_addr; 534ea0fabbcSTim J. Robbins frame.sf_sc.sc_trapno = bsd_to_linux_trapcode(code); 535ea0fabbcSTim J. Robbins 536ea0fabbcSTim J. Robbins for (i = 0; i < (LINUX_NSIG_WORDS-1); i++) 537ea0fabbcSTim J. Robbins frame.sf_extramask[i] = lmask.__bits[i+1]; 538ea0fabbcSTim J. Robbins 539ea0fabbcSTim J. Robbins if (copyout(&frame, fp, sizeof(frame)) != 0) { 540ea0fabbcSTim J. Robbins /* 541ea0fabbcSTim J. Robbins * Process has trashed its stack; give it an illegal 542ea0fabbcSTim J. Robbins * instruction to halt it in its tracks. 543ea0fabbcSTim J. Robbins */ 544ea0fabbcSTim J. Robbins PROC_LOCK(p); 545ea0fabbcSTim J. Robbins sigexit(td, SIGILL); 546ea0fabbcSTim J. Robbins } 547ea0fabbcSTim J. Robbins 548ea0fabbcSTim J. Robbins /* 549ea0fabbcSTim J. Robbins * Build context to run handler in. 550ea0fabbcSTim J. Robbins */ 551ea0fabbcSTim J. Robbins regs->tf_rsp = PTROUT(fp); 552*bdc37934SDmitry Chagin regs->tf_rip = linux32_sigcode; 55322eca0bfSKonstantin Belousov regs->tf_rflags &= ~(PSL_T | PSL_D); 554ea0fabbcSTim J. Robbins regs->tf_cs = _ucode32sel; 555ea0fabbcSTim J. Robbins regs->tf_ss = _udatasel; 5562c66cccaSKonstantin Belousov regs->tf_ds = _udatasel; 5572c66cccaSKonstantin Belousov regs->tf_es = _udatasel; 5582c66cccaSKonstantin Belousov regs->tf_fs = _ufssel; 5592c66cccaSKonstantin Belousov regs->tf_gs = _ugssel; 5602c66cccaSKonstantin Belousov regs->tf_flags = TF_HASSEGS; 561e6c006d9SJung-uk Kim set_pcb_flags(td->td_pcb, PCB_FULL_IRET); 562ea0fabbcSTim J. Robbins PROC_LOCK(p); 563ea0fabbcSTim J. Robbins mtx_lock(&psp->ps_mtx); 564ea0fabbcSTim J. Robbins } 565ea0fabbcSTim J. Robbins 566ea0fabbcSTim J. Robbins /* 567ea0fabbcSTim J. Robbins * System call to cleanup state after a signal 568ea0fabbcSTim J. Robbins * has been taken. Reset signal mask and 569ea0fabbcSTim J. Robbins * stack state from context left by sendsig (above). 570ea0fabbcSTim J. Robbins * Return to previous pc and psl as specified by 571ea0fabbcSTim J. Robbins * context left by sendsig. Check carefully to 572ea0fabbcSTim J. Robbins * make sure that the user has not modified the 573ea0fabbcSTim J. Robbins * psl to gain improper privileges or to cause 574ea0fabbcSTim J. Robbins * a machine fault. 575ea0fabbcSTim J. Robbins */ 576ea0fabbcSTim J. Robbins int 577ea0fabbcSTim J. Robbins linux_sigreturn(struct thread *td, struct linux_sigreturn_args *args) 578ea0fabbcSTim J. Robbins { 579ea0fabbcSTim J. Robbins struct l_sigframe frame; 580ea0fabbcSTim J. Robbins struct trapframe *regs; 581d6e029adSKonstantin Belousov sigset_t bmask; 582ea0fabbcSTim J. Robbins l_sigset_t lmask; 583ea0fabbcSTim J. Robbins int eflags, i; 5849104847fSDavid Xu ksiginfo_t ksi; 585ea0fabbcSTim J. Robbins 586ea0fabbcSTim J. Robbins regs = td->td_frame; 587ea0fabbcSTim J. Robbins 588ea0fabbcSTim J. Robbins #ifdef DEBUG 589ea0fabbcSTim J. Robbins if (ldebug(sigreturn)) 590ea0fabbcSTim J. Robbins printf(ARGS(sigreturn, "%p"), (void *)args->sfp); 591ea0fabbcSTim J. Robbins #endif 592ea0fabbcSTim J. Robbins /* 593ea0fabbcSTim J. Robbins * The trampoline code hands us the sigframe. 594ea0fabbcSTim J. Robbins * It is unsafe to keep track of it ourselves, in the event that a 595ea0fabbcSTim J. Robbins * program jumps out of a signal handler. 596ea0fabbcSTim J. Robbins */ 597ea0fabbcSTim J. Robbins if (copyin(args->sfp, &frame, sizeof(frame)) != 0) 598ea0fabbcSTim J. Robbins return (EFAULT); 599ea0fabbcSTim J. Robbins 600ea0fabbcSTim J. Robbins /* 601ea0fabbcSTim J. Robbins * Check for security violations. 602ea0fabbcSTim J. Robbins */ 603ea0fabbcSTim J. Robbins #define EFLAGS_SECURE(ef, oef) ((((ef) ^ (oef)) & ~PSL_USERCHANGE) == 0) 604ea0fabbcSTim J. Robbins eflags = frame.sf_sc.sc_eflags; 6053d271aaaSEd Maste if (!EFLAGS_SECURE(eflags, regs->tf_rflags)) 606ea0fabbcSTim J. Robbins return(EINVAL); 607ea0fabbcSTim J. Robbins 608ea0fabbcSTim J. Robbins /* 609ea0fabbcSTim J. Robbins * Don't allow users to load a valid privileged %cs. Let the 610ea0fabbcSTim J. Robbins * hardware check for invalid selectors, excess privilege in 611ea0fabbcSTim J. Robbins * other selectors, invalid %eip's and invalid %esp's. 612ea0fabbcSTim J. Robbins */ 613ea0fabbcSTim J. Robbins #define CS_SECURE(cs) (ISPL(cs) == SEL_UPL) 614ea0fabbcSTim J. Robbins if (!CS_SECURE(frame.sf_sc.sc_cs)) { 6159104847fSDavid Xu ksiginfo_init_trap(&ksi); 6169104847fSDavid Xu ksi.ksi_signo = SIGBUS; 6179104847fSDavid Xu ksi.ksi_code = BUS_OBJERR; 6189104847fSDavid Xu ksi.ksi_trapno = T_PROTFLT; 6199104847fSDavid Xu ksi.ksi_addr = (void *)regs->tf_rip; 6209104847fSDavid Xu trapsignal(td, &ksi); 621ea0fabbcSTim J. Robbins return(EINVAL); 622ea0fabbcSTim J. Robbins } 623ea0fabbcSTim J. Robbins 624ea0fabbcSTim J. Robbins lmask.__bits[0] = frame.sf_sc.sc_mask; 625ea0fabbcSTim J. Robbins for (i = 0; i < (LINUX_NSIG_WORDS-1); i++) 626ea0fabbcSTim J. Robbins lmask.__bits[i+1] = frame.sf_extramask[i]; 627d6e029adSKonstantin Belousov linux_to_bsd_sigset(&lmask, &bmask); 628d6e029adSKonstantin Belousov kern_sigprocmask(td, SIG_SETMASK, &bmask, NULL, 0); 629ea0fabbcSTim J. Robbins 630ea0fabbcSTim J. Robbins /* 631ea0fabbcSTim J. Robbins * Restore signal context. 632ea0fabbcSTim J. Robbins */ 633ea0fabbcSTim J. Robbins regs->tf_rdi = frame.sf_sc.sc_edi; 634ea0fabbcSTim J. Robbins regs->tf_rsi = frame.sf_sc.sc_esi; 635ea0fabbcSTim J. Robbins regs->tf_rbp = frame.sf_sc.sc_ebp; 636ea0fabbcSTim J. Robbins regs->tf_rbx = frame.sf_sc.sc_ebx; 637ea0fabbcSTim J. Robbins regs->tf_rdx = frame.sf_sc.sc_edx; 638ea0fabbcSTim J. Robbins regs->tf_rcx = frame.sf_sc.sc_ecx; 639ea0fabbcSTim J. Robbins regs->tf_rax = frame.sf_sc.sc_eax; 640ea0fabbcSTim J. Robbins regs->tf_rip = frame.sf_sc.sc_eip; 641ea0fabbcSTim J. Robbins regs->tf_cs = frame.sf_sc.sc_cs; 6422c66cccaSKonstantin Belousov regs->tf_ds = frame.sf_sc.sc_ds; 6432c66cccaSKonstantin Belousov regs->tf_es = frame.sf_sc.sc_es; 6442c66cccaSKonstantin Belousov regs->tf_fs = frame.sf_sc.sc_fs; 6452c66cccaSKonstantin Belousov regs->tf_gs = frame.sf_sc.sc_gs; 646ea0fabbcSTim J. Robbins regs->tf_rflags = eflags; 647ea0fabbcSTim J. Robbins regs->tf_rsp = frame.sf_sc.sc_esp_at_signal; 648ea0fabbcSTim J. Robbins regs->tf_ss = frame.sf_sc.sc_ss; 649e6c006d9SJung-uk Kim set_pcb_flags(td->td_pcb, PCB_FULL_IRET); 650ea0fabbcSTim J. Robbins 651ea0fabbcSTim J. Robbins return (EJUSTRETURN); 652ea0fabbcSTim J. Robbins } 653ea0fabbcSTim J. Robbins 654ea0fabbcSTim J. Robbins /* 655ea0fabbcSTim J. Robbins * System call to cleanup state after a signal 656ea0fabbcSTim J. Robbins * has been taken. Reset signal mask and 657ea0fabbcSTim J. Robbins * stack state from context left by rt_sendsig (above). 658ea0fabbcSTim J. Robbins * Return to previous pc and psl as specified by 659ea0fabbcSTim J. Robbins * context left by sendsig. Check carefully to 660ea0fabbcSTim J. Robbins * make sure that the user has not modified the 661ea0fabbcSTim J. Robbins * psl to gain improper privileges or to cause 662ea0fabbcSTim J. Robbins * a machine fault. 663ea0fabbcSTim J. Robbins */ 664ea0fabbcSTim J. Robbins int 665ea0fabbcSTim J. Robbins linux_rt_sigreturn(struct thread *td, struct linux_rt_sigreturn_args *args) 666ea0fabbcSTim J. Robbins { 667ea0fabbcSTim J. Robbins struct l_ucontext uc; 668ea0fabbcSTim J. Robbins struct l_sigcontext *context; 669d6e029adSKonstantin Belousov sigset_t bmask; 670ea0fabbcSTim J. Robbins l_stack_t *lss; 671ea0fabbcSTim J. Robbins stack_t ss; 672ea0fabbcSTim J. Robbins struct trapframe *regs; 673ea0fabbcSTim J. Robbins int eflags; 6749104847fSDavid Xu ksiginfo_t ksi; 675ea0fabbcSTim J. Robbins 676ea0fabbcSTim J. Robbins regs = td->td_frame; 677ea0fabbcSTim J. Robbins 678ea0fabbcSTim J. Robbins #ifdef DEBUG 679ea0fabbcSTim J. Robbins if (ldebug(rt_sigreturn)) 680ea0fabbcSTim J. Robbins printf(ARGS(rt_sigreturn, "%p"), (void *)args->ucp); 681ea0fabbcSTim J. Robbins #endif 682ea0fabbcSTim J. Robbins /* 683ea0fabbcSTim J. Robbins * The trampoline code hands us the ucontext. 684ea0fabbcSTim J. Robbins * It is unsafe to keep track of it ourselves, in the event that a 685ea0fabbcSTim J. Robbins * program jumps out of a signal handler. 686ea0fabbcSTim J. Robbins */ 687ea0fabbcSTim J. Robbins if (copyin(args->ucp, &uc, sizeof(uc)) != 0) 688ea0fabbcSTim J. Robbins return (EFAULT); 689ea0fabbcSTim J. Robbins 690ea0fabbcSTim J. Robbins context = &uc.uc_mcontext; 691ea0fabbcSTim J. Robbins 692ea0fabbcSTim J. Robbins /* 693ea0fabbcSTim J. Robbins * Check for security violations. 694ea0fabbcSTim J. Robbins */ 695ea0fabbcSTim J. Robbins #define EFLAGS_SECURE(ef, oef) ((((ef) ^ (oef)) & ~PSL_USERCHANGE) == 0) 696ea0fabbcSTim J. Robbins eflags = context->sc_eflags; 6973d271aaaSEd Maste if (!EFLAGS_SECURE(eflags, regs->tf_rflags)) 698ea0fabbcSTim J. Robbins return(EINVAL); 699ea0fabbcSTim J. Robbins 700ea0fabbcSTim J. Robbins /* 701ea0fabbcSTim J. Robbins * Don't allow users to load a valid privileged %cs. Let the 702ea0fabbcSTim J. Robbins * hardware check for invalid selectors, excess privilege in 703ea0fabbcSTim J. Robbins * other selectors, invalid %eip's and invalid %esp's. 704ea0fabbcSTim J. Robbins */ 705ea0fabbcSTim J. Robbins #define CS_SECURE(cs) (ISPL(cs) == SEL_UPL) 706ea0fabbcSTim J. Robbins if (!CS_SECURE(context->sc_cs)) { 7079104847fSDavid Xu ksiginfo_init_trap(&ksi); 7089104847fSDavid Xu ksi.ksi_signo = SIGBUS; 7099104847fSDavid Xu ksi.ksi_code = BUS_OBJERR; 7109104847fSDavid Xu ksi.ksi_trapno = T_PROTFLT; 7119104847fSDavid Xu ksi.ksi_addr = (void *)regs->tf_rip; 7129104847fSDavid Xu trapsignal(td, &ksi); 713ea0fabbcSTim J. Robbins return(EINVAL); 714ea0fabbcSTim J. Robbins } 715ea0fabbcSTim J. Robbins 716d6e029adSKonstantin Belousov linux_to_bsd_sigset(&uc.uc_sigmask, &bmask); 717d6e029adSKonstantin Belousov kern_sigprocmask(td, SIG_SETMASK, &bmask, NULL, 0); 718ea0fabbcSTim J. Robbins 719ea0fabbcSTim J. Robbins /* 720ea0fabbcSTim J. Robbins * Restore signal context 721ea0fabbcSTim J. Robbins */ 7222c66cccaSKonstantin Belousov regs->tf_gs = context->sc_gs; 7232c66cccaSKonstantin Belousov regs->tf_fs = context->sc_fs; 7242c66cccaSKonstantin Belousov regs->tf_es = context->sc_es; 7252c66cccaSKonstantin Belousov regs->tf_ds = context->sc_ds; 726ea0fabbcSTim J. Robbins regs->tf_rdi = context->sc_edi; 727ea0fabbcSTim J. Robbins regs->tf_rsi = context->sc_esi; 728ea0fabbcSTim J. Robbins regs->tf_rbp = context->sc_ebp; 729ea0fabbcSTim J. Robbins regs->tf_rbx = context->sc_ebx; 730ea0fabbcSTim J. Robbins regs->tf_rdx = context->sc_edx; 731ea0fabbcSTim J. Robbins regs->tf_rcx = context->sc_ecx; 732ea0fabbcSTim J. Robbins regs->tf_rax = context->sc_eax; 733ea0fabbcSTim J. Robbins regs->tf_rip = context->sc_eip; 734ea0fabbcSTim J. Robbins regs->tf_cs = context->sc_cs; 735ea0fabbcSTim J. Robbins regs->tf_rflags = eflags; 736ea0fabbcSTim J. Robbins regs->tf_rsp = context->sc_esp_at_signal; 737ea0fabbcSTim J. Robbins regs->tf_ss = context->sc_ss; 738e6c006d9SJung-uk Kim set_pcb_flags(td->td_pcb, PCB_FULL_IRET); 739ea0fabbcSTim J. Robbins 740ea0fabbcSTim J. Robbins /* 741ea0fabbcSTim J. Robbins * call sigaltstack & ignore results.. 742ea0fabbcSTim J. Robbins */ 743ea0fabbcSTim J. Robbins lss = &uc.uc_stack; 744ea0fabbcSTim J. Robbins ss.ss_sp = PTRIN(lss->ss_sp); 745ea0fabbcSTim J. Robbins ss.ss_size = lss->ss_size; 746ea0fabbcSTim J. Robbins ss.ss_flags = linux_to_bsd_sigaltstack(lss->ss_flags); 747ea0fabbcSTim J. Robbins 748ea0fabbcSTim J. Robbins #ifdef DEBUG 749ea0fabbcSTim J. Robbins if (ldebug(rt_sigreturn)) 750c680f6b1SDavid E. O'Brien printf(LMSG("rt_sigret flags: 0x%x, sp: %p, ss: 0x%lx, mask: 0x%x"), 751ea0fabbcSTim J. Robbins ss.ss_flags, ss.ss_sp, ss.ss_size, context->sc_mask); 752ea0fabbcSTim J. Robbins #endif 753ea0fabbcSTim J. Robbins (void)kern_sigaltstack(td, &ss, NULL); 754ea0fabbcSTim J. Robbins 755ea0fabbcSTim J. Robbins return (EJUSTRETURN); 756ea0fabbcSTim J. Robbins } 757ea0fabbcSTim J. Robbins 758afe1a688SKonstantin Belousov static int 759afe1a688SKonstantin Belousov linux32_fetch_syscall_args(struct thread *td, struct syscall_args *sa) 760ea0fabbcSTim J. Robbins { 761afe1a688SKonstantin Belousov struct proc *p; 762afe1a688SKonstantin Belousov struct trapframe *frame; 763afe1a688SKonstantin Belousov 764afe1a688SKonstantin Belousov p = td->td_proc; 765afe1a688SKonstantin Belousov frame = td->td_frame; 766afe1a688SKonstantin Belousov 767afe1a688SKonstantin Belousov sa->args[0] = frame->tf_rbx; 768afe1a688SKonstantin Belousov sa->args[1] = frame->tf_rcx; 769afe1a688SKonstantin Belousov sa->args[2] = frame->tf_rdx; 770afe1a688SKonstantin Belousov sa->args[3] = frame->tf_rsi; 771afe1a688SKonstantin Belousov sa->args[4] = frame->tf_rdi; 772afe1a688SKonstantin Belousov sa->args[5] = frame->tf_rbp; /* Unconfirmed */ 773afe1a688SKonstantin Belousov sa->code = frame->tf_rax; 774afe1a688SKonstantin Belousov 775afe1a688SKonstantin Belousov if (sa->code >= p->p_sysent->sv_size) 776afe1a688SKonstantin Belousov sa->callp = &p->p_sysent->sv_table[0]; 777afe1a688SKonstantin Belousov else 778afe1a688SKonstantin Belousov sa->callp = &p->p_sysent->sv_table[sa->code]; 779afe1a688SKonstantin Belousov sa->narg = sa->callp->sy_narg; 780afe1a688SKonstantin Belousov 781afe1a688SKonstantin Belousov td->td_retval[0] = 0; 782afe1a688SKonstantin Belousov td->td_retval[1] = frame->tf_rdx; 783afe1a688SKonstantin Belousov 784afe1a688SKonstantin Belousov return (0); 785ea0fabbcSTim J. Robbins } 786ea0fabbcSTim J. Robbins 787ea0fabbcSTim J. Robbins /* 788ea0fabbcSTim J. Robbins * If a linux binary is exec'ing something, try this image activator 789ea0fabbcSTim J. Robbins * first. We override standard shell script execution in order to 790ea0fabbcSTim J. Robbins * be able to modify the interpreter path. We only do this if a linux 791ea0fabbcSTim J. Robbins * binary is doing the exec, so we do not create an EXEC module for it. 792ea0fabbcSTim J. Robbins */ 793ea0fabbcSTim J. Robbins static int exec_linux_imgact_try(struct image_params *iparams); 794ea0fabbcSTim J. Robbins 795ea0fabbcSTim J. Robbins static int 796ea0fabbcSTim J. Robbins exec_linux_imgact_try(struct image_params *imgp) 797ea0fabbcSTim J. Robbins { 798ea0fabbcSTim J. Robbins const char *head = (const char *)imgp->image_header; 7991d15fdd9SJohn Baldwin char *rpath; 800a14a9498SAlan Cox int error = -1; 801ea0fabbcSTim J. Robbins 802ea0fabbcSTim J. Robbins /* 803ea0fabbcSTim J. Robbins * The interpreter for shell scripts run from a linux binary needs 804ea0fabbcSTim J. Robbins * to be located in /compat/linux if possible in order to recursively 805ea0fabbcSTim J. Robbins * maintain linux path emulation. 806ea0fabbcSTim J. Robbins */ 807ea0fabbcSTim J. Robbins if (((const short *)head)[0] == SHELLMAGIC) { 808ea0fabbcSTim J. Robbins /* 809ea0fabbcSTim J. Robbins * Run our normal shell image activator. If it succeeds attempt 810d065e13dSDavid E. O'Brien * to use the alternate path for the interpreter. If an 811d065e13dSDavid E. O'Brien * alternate * path is found, use our stringspace to store it. 812ea0fabbcSTim J. Robbins */ 813ea0fabbcSTim J. Robbins if ((error = exec_shell_imgact(imgp)) == 0) { 8141d15fdd9SJohn Baldwin linux_emul_convpath(FIRST_THREAD_IN_PROC(imgp->proc), 815d065e13dSDavid E. O'Brien imgp->interpreter_name, UIO_SYSSPACE, &rpath, 0, 816d065e13dSDavid E. O'Brien AT_FDCWD); 817a14a9498SAlan Cox if (rpath != NULL) 818a14a9498SAlan Cox imgp->args->fname_buf = 819a14a9498SAlan Cox imgp->interpreter_name = rpath; 820ea0fabbcSTim J. Robbins } 821ea0fabbcSTim J. Robbins } 822ea0fabbcSTim J. Robbins return (error); 823ea0fabbcSTim J. Robbins } 824ea0fabbcSTim J. Robbins 825ea0fabbcSTim J. Robbins /* 826ea0fabbcSTim J. Robbins * Clear registers on exec 827ea0fabbcSTim J. Robbins * XXX copied from ia32_signal.c. 828ea0fabbcSTim J. Robbins */ 829ea0fabbcSTim J. Robbins static void 830a107d8aaSNathan Whitehorn exec_linux_setregs(struct thread *td, struct image_params *imgp, u_long stack) 831ea0fabbcSTim J. Robbins { 832ea0fabbcSTim J. Robbins struct trapframe *regs = td->td_frame; 833ea0fabbcSTim J. Robbins struct pcb *pcb = td->td_pcb; 834ea0fabbcSTim J. Robbins 8352c66cccaSKonstantin Belousov mtx_lock(&dt_lock); 8362c66cccaSKonstantin Belousov if (td->td_proc->p_md.md_ldt != NULL) 8372c66cccaSKonstantin Belousov user_ldt_free(td); 8382c66cccaSKonstantin Belousov else 8392c66cccaSKonstantin Belousov mtx_unlock(&dt_lock); 8402c66cccaSKonstantin Belousov 8419c5b213eSJung-uk Kim critical_enter(); 842ea0fabbcSTim J. Robbins wrmsr(MSR_FSBASE, 0); 843ea0fabbcSTim J. Robbins wrmsr(MSR_KGSBASE, 0); /* User value while we're in the kernel */ 844ea0fabbcSTim J. Robbins pcb->pcb_fsbase = 0; 845ea0fabbcSTim J. Robbins pcb->pcb_gsbase = 0; 8469c5b213eSJung-uk Kim critical_exit(); 8472ee8325fSJohn Baldwin pcb->pcb_initial_fpucw = __LINUX_NPXCW__; 848ea0fabbcSTim J. Robbins 849ea0fabbcSTim J. Robbins bzero((char *)regs, sizeof(struct trapframe)); 850a107d8aaSNathan Whitehorn regs->tf_rip = imgp->entry_addr; 851ea0fabbcSTim J. Robbins regs->tf_rsp = stack; 852ea0fabbcSTim J. Robbins regs->tf_rflags = PSL_USER | (regs->tf_rflags & PSL_T); 8532c66cccaSKonstantin Belousov regs->tf_gs = _ugssel; 8542c66cccaSKonstantin Belousov regs->tf_fs = _ufssel; 8552c66cccaSKonstantin Belousov regs->tf_es = _udatasel; 8562c66cccaSKonstantin Belousov regs->tf_ds = _udatasel; 857ea0fabbcSTim J. Robbins regs->tf_ss = _udatasel; 8582c66cccaSKonstantin Belousov regs->tf_flags = TF_HASSEGS; 859ea0fabbcSTim J. Robbins regs->tf_cs = _ucode32sel; 860a107d8aaSNathan Whitehorn regs->tf_rbx = imgp->ps_strings; 861bdbf2db5SJung-uk Kim 8622a988f7cSStephan Uphoff fpstate_drop(td); 863ea0fabbcSTim J. Robbins 8641b3c3256SKonstantin Belousov /* Do full restore on return so that we can change to a different %cs */ 865e6c006d9SJung-uk Kim set_pcb_flags(pcb, PCB_32BIT | PCB_FULL_IRET); 866ea0fabbcSTim J. Robbins td->td_retval[1] = 0; 867ea0fabbcSTim J. Robbins } 868ea0fabbcSTim J. Robbins 869ea0fabbcSTim J. Robbins /* 870ea0fabbcSTim J. Robbins * XXX copied from ia32_sysvec.c. 871ea0fabbcSTim J. Robbins */ 872ea0fabbcSTim J. Robbins static register_t * 873ea0fabbcSTim J. Robbins linux_copyout_strings(struct image_params *imgp) 874ea0fabbcSTim J. Robbins { 875ea0fabbcSTim J. Robbins int argc, envc; 876ea0fabbcSTim J. Robbins u_int32_t *vectp; 877ea0fabbcSTim J. Robbins char *stringp, *destp; 878ea0fabbcSTim J. Robbins u_int32_t *stack_base; 879ea0fabbcSTim J. Robbins struct linux32_ps_strings *arginfo; 880ea0fabbcSTim J. Robbins 881ea0fabbcSTim J. Robbins /* 882ea0fabbcSTim J. Robbins * Calculate string base and vector table pointers. 883ea0fabbcSTim J. Robbins * Also deal with signal trampoline code for this exec type. 884ea0fabbcSTim J. Robbins */ 885ea0fabbcSTim J. Robbins arginfo = (struct linux32_ps_strings *)LINUX32_PS_STRINGS; 8868f1e49a6SDmitry Chagin destp = (caddr_t)arginfo - SPARE_USRSPACE - linux_szplatform - 8878f1e49a6SDmitry Chagin roundup((ARG_MAX - imgp->args->stringspace), 8884d7c2e8aSDmitry Chagin sizeof(char *)); 889ea0fabbcSTim J. Robbins 890ea0fabbcSTim J. Robbins /* 8914d7c2e8aSDmitry Chagin * Install LINUX_PLATFORM 8924d7c2e8aSDmitry Chagin */ 8938f1e49a6SDmitry Chagin copyout(linux_platform, ((caddr_t)arginfo - linux_szplatform), 8948f1e49a6SDmitry Chagin linux_szplatform); 895ea0fabbcSTim J. Robbins 896ea0fabbcSTim J. Robbins /* 897ea0fabbcSTim J. Robbins * If we have a valid auxargs ptr, prepare some room 898ea0fabbcSTim J. Robbins * on the stack. 899ea0fabbcSTim J. Robbins */ 900ea0fabbcSTim J. Robbins if (imgp->auxargs) { 901ea0fabbcSTim J. Robbins /* 902ea0fabbcSTim J. Robbins * 'AT_COUNT*2' is size for the ELF Auxargs data. This is for 903ea0fabbcSTim J. Robbins * lower compatibility. 904ea0fabbcSTim J. Robbins */ 905d065e13dSDavid E. O'Brien imgp->auxarg_size = (imgp->auxarg_size) ? imgp->auxarg_size : 9064d7c2e8aSDmitry Chagin (LINUX_AT_COUNT * 2); 907ea0fabbcSTim J. Robbins /* 908ea0fabbcSTim J. Robbins * The '+ 2' is for the null pointers at the end of each of 909ea0fabbcSTim J. Robbins * the arg and env vector sets,and imgp->auxarg_size is room 910ea0fabbcSTim J. Robbins * for argument of Runtime loader. 911ea0fabbcSTim J. Robbins */ 912d065e13dSDavid E. O'Brien vectp = (u_int32_t *) (destp - (imgp->args->argc + 913d065e13dSDavid E. O'Brien imgp->args->envc + 2 + imgp->auxarg_size) * 914d065e13dSDavid E. O'Brien sizeof(u_int32_t)); 915ea0fabbcSTim J. Robbins 916ea0fabbcSTim J. Robbins } else 917ea0fabbcSTim J. Robbins /* 918ea0fabbcSTim J. Robbins * The '+ 2' is for the null pointers at the end of each of 919ea0fabbcSTim J. Robbins * the arg and env vector sets 920ea0fabbcSTim J. Robbins */ 921d065e13dSDavid E. O'Brien vectp = (u_int32_t *)(destp - (imgp->args->argc + 922d065e13dSDavid E. O'Brien imgp->args->envc + 2) * sizeof(u_int32_t)); 923ea0fabbcSTim J. Robbins 924ea0fabbcSTim J. Robbins /* 925ea0fabbcSTim J. Robbins * vectp also becomes our initial stack base 926ea0fabbcSTim J. Robbins */ 927ea0fabbcSTim J. Robbins stack_base = vectp; 928ea0fabbcSTim J. Robbins 929610ecfe0SMaxim Sobolev stringp = imgp->args->begin_argv; 930610ecfe0SMaxim Sobolev argc = imgp->args->argc; 931610ecfe0SMaxim Sobolev envc = imgp->args->envc; 932ea0fabbcSTim J. Robbins /* 933ea0fabbcSTim J. Robbins * Copy out strings - arguments and environment. 934ea0fabbcSTim J. Robbins */ 935610ecfe0SMaxim Sobolev copyout(stringp, destp, ARG_MAX - imgp->args->stringspace); 936ea0fabbcSTim J. Robbins 937ea0fabbcSTim J. Robbins /* 938ea0fabbcSTim J. Robbins * Fill in "ps_strings" struct for ps, w, etc. 939ea0fabbcSTim J. Robbins */ 9404d7c2e8aSDmitry Chagin suword32(&arginfo->ps_argvstr, (uint32_t)(intptr_t)vectp); 941ea0fabbcSTim J. Robbins suword32(&arginfo->ps_nargvstr, argc); 942ea0fabbcSTim J. Robbins 943ea0fabbcSTim J. Robbins /* 944ea0fabbcSTim J. Robbins * Fill in argument portion of vector table. 945ea0fabbcSTim J. Robbins */ 946ea0fabbcSTim J. Robbins for (; argc > 0; --argc) { 9474d7c2e8aSDmitry Chagin suword32(vectp++, (uint32_t)(intptr_t)destp); 948ea0fabbcSTim J. Robbins while (*stringp++ != 0) 949ea0fabbcSTim J. Robbins destp++; 950ea0fabbcSTim J. Robbins destp++; 951ea0fabbcSTim J. Robbins } 952ea0fabbcSTim J. Robbins 953ea0fabbcSTim J. Robbins /* a null vector table pointer separates the argp's from the envp's */ 954ea0fabbcSTim J. Robbins suword32(vectp++, 0); 955ea0fabbcSTim J. Robbins 9564d7c2e8aSDmitry Chagin suword32(&arginfo->ps_envstr, (uint32_t)(intptr_t)vectp); 957ea0fabbcSTim J. Robbins suword32(&arginfo->ps_nenvstr, envc); 958ea0fabbcSTim J. Robbins 959ea0fabbcSTim J. Robbins /* 960ea0fabbcSTim J. Robbins * Fill in environment portion of vector table. 961ea0fabbcSTim J. Robbins */ 962ea0fabbcSTim J. Robbins for (; envc > 0; --envc) { 9634d7c2e8aSDmitry Chagin suword32(vectp++, (uint32_t)(intptr_t)destp); 964ea0fabbcSTim J. Robbins while (*stringp++ != 0) 965ea0fabbcSTim J. Robbins destp++; 966ea0fabbcSTim J. Robbins destp++; 967ea0fabbcSTim J. Robbins } 968ea0fabbcSTim J. Robbins 969ea0fabbcSTim J. Robbins /* end of vector table is a null pointer */ 970ea0fabbcSTim J. Robbins suword32(vectp, 0); 971ea0fabbcSTim J. Robbins 972ea0fabbcSTim J. Robbins return ((register_t *)stack_base); 973ea0fabbcSTim J. Robbins } 974ea0fabbcSTim J. Robbins 9756472ac3dSEd Schouten static SYSCTL_NODE(_compat, OID_AUTO, linux32, CTLFLAG_RW, 0, 976ea0fabbcSTim J. Robbins "32-bit Linux emulation"); 977ea0fabbcSTim J. Robbins 978ea0fabbcSTim J. Robbins static u_long linux32_maxdsiz = LINUX32_MAXDSIZ; 979ea0fabbcSTim J. Robbins SYSCTL_ULONG(_compat_linux32, OID_AUTO, maxdsiz, CTLFLAG_RW, 980ea0fabbcSTim J. Robbins &linux32_maxdsiz, 0, ""); 981ea0fabbcSTim J. Robbins static u_long linux32_maxssiz = LINUX32_MAXSSIZ; 982ea0fabbcSTim J. Robbins SYSCTL_ULONG(_compat_linux32, OID_AUTO, maxssiz, CTLFLAG_RW, 983ea0fabbcSTim J. Robbins &linux32_maxssiz, 0, ""); 984ea0fabbcSTim J. Robbins static u_long linux32_maxvmem = LINUX32_MAXVMEM; 985ea0fabbcSTim J. Robbins SYSCTL_ULONG(_compat_linux32, OID_AUTO, maxvmem, CTLFLAG_RW, 986ea0fabbcSTim J. Robbins &linux32_maxvmem, 0, ""); 987ea0fabbcSTim J. Robbins 988ea0fabbcSTim J. Robbins static void 98919059a13SJohn Baldwin linux32_fixlimit(struct rlimit *rl, int which) 990ea0fabbcSTim J. Robbins { 991ea0fabbcSTim J. Robbins 99219059a13SJohn Baldwin switch (which) { 99319059a13SJohn Baldwin case RLIMIT_DATA: 994ea0fabbcSTim J. Robbins if (linux32_maxdsiz != 0) { 99519059a13SJohn Baldwin if (rl->rlim_cur > linux32_maxdsiz) 99619059a13SJohn Baldwin rl->rlim_cur = linux32_maxdsiz; 99719059a13SJohn Baldwin if (rl->rlim_max > linux32_maxdsiz) 99819059a13SJohn Baldwin rl->rlim_max = linux32_maxdsiz; 999ea0fabbcSTim J. Robbins } 100019059a13SJohn Baldwin break; 100119059a13SJohn Baldwin case RLIMIT_STACK: 1002ea0fabbcSTim J. Robbins if (linux32_maxssiz != 0) { 100319059a13SJohn Baldwin if (rl->rlim_cur > linux32_maxssiz) 100419059a13SJohn Baldwin rl->rlim_cur = linux32_maxssiz; 100519059a13SJohn Baldwin if (rl->rlim_max > linux32_maxssiz) 100619059a13SJohn Baldwin rl->rlim_max = linux32_maxssiz; 1007ea0fabbcSTim J. Robbins } 100819059a13SJohn Baldwin break; 100919059a13SJohn Baldwin case RLIMIT_VMEM: 1010ea0fabbcSTim J. Robbins if (linux32_maxvmem != 0) { 101119059a13SJohn Baldwin if (rl->rlim_cur > linux32_maxvmem) 101219059a13SJohn Baldwin rl->rlim_cur = linux32_maxvmem; 101319059a13SJohn Baldwin if (rl->rlim_max > linux32_maxvmem) 101419059a13SJohn Baldwin rl->rlim_max = linux32_maxvmem; 1015ea0fabbcSTim J. Robbins } 101619059a13SJohn Baldwin break; 101719059a13SJohn Baldwin } 1018ea0fabbcSTim J. Robbins } 1019ea0fabbcSTim J. Robbins 1020ea0fabbcSTim J. Robbins struct sysentvec elf_linux_sysvec = { 1021a8d403e1SKonstantin Belousov .sv_size = LINUX_SYS_MAXSYSCALL, 1022a8d403e1SKonstantin Belousov .sv_table = linux_sysent, 1023a8d403e1SKonstantin Belousov .sv_mask = 0, 1024a8d403e1SKonstantin Belousov .sv_sigsize = LINUX_SIGTBLSZ, 1025a8d403e1SKonstantin Belousov .sv_sigtbl = bsd_to_linux_signal, 1026a8d403e1SKonstantin Belousov .sv_errsize = ELAST + 1, 1027a8d403e1SKonstantin Belousov .sv_errtbl = bsd_to_linux_errno, 1028a8d403e1SKonstantin Belousov .sv_transtrap = translate_traps, 1029a8d403e1SKonstantin Belousov .sv_fixup = elf_linux_fixup, 1030a8d403e1SKonstantin Belousov .sv_sendsig = linux_sendsig, 1031*bdc37934SDmitry Chagin .sv_sigcode = &_binary_linux32_locore_o_start, 1032a8d403e1SKonstantin Belousov .sv_szsigcode = &linux_szsigcode, 1033afe1a688SKonstantin Belousov .sv_prepsyscall = NULL, 1034a8d403e1SKonstantin Belousov .sv_name = "Linux ELF32", 1035a8d403e1SKonstantin Belousov .sv_coredump = elf32_coredump, 1036a8d403e1SKonstantin Belousov .sv_imgact_try = exec_linux_imgact_try, 1037a8d403e1SKonstantin Belousov .sv_minsigstksz = LINUX_MINSIGSTKSZ, 1038a8d403e1SKonstantin Belousov .sv_pagesize = PAGE_SIZE, 1039a8d403e1SKonstantin Belousov .sv_minuser = VM_MIN_ADDRESS, 10408f1e49a6SDmitry Chagin .sv_maxuser = LINUX32_MAXUSER, 1041a8d403e1SKonstantin Belousov .sv_usrstack = LINUX32_USRSTACK, 1042a8d403e1SKonstantin Belousov .sv_psstrings = LINUX32_PS_STRINGS, 1043a8d403e1SKonstantin Belousov .sv_stackprot = VM_PROT_ALL, 1044a8d403e1SKonstantin Belousov .sv_copyout_strings = linux_copyout_strings, 1045a8d403e1SKonstantin Belousov .sv_setregs = exec_linux_setregs, 1046a8d403e1SKonstantin Belousov .sv_fixlimit = linux32_fixlimit, 1047a8d403e1SKonstantin Belousov .sv_maxssiz = &linux32_maxssiz, 10488f1e49a6SDmitry Chagin .sv_flags = SV_ABI_LINUX | SV_ILP32 | SV_IA32 | SV_SHP, 1049afe1a688SKonstantin Belousov .sv_set_syscall_retval = cpu_set_syscall_retval, 1050afe1a688SKonstantin Belousov .sv_fetch_syscall_args = linux32_fetch_syscall_args, 1051afe1a688SKonstantin Belousov .sv_syscallnames = NULL, 10528f1e49a6SDmitry Chagin .sv_shared_page_base = LINUX32_SHAREDPAGE, 10538f1e49a6SDmitry Chagin .sv_shared_page_len = PAGE_SIZE, 1054e5d81ef1SDmitry Chagin .sv_schedtail = linux_schedtail, 105581338031SDmitry Chagin .sv_thread_detach = linux_thread_detach, 1056ea0fabbcSTim J. Robbins }; 1057*bdc37934SDmitry Chagin 1058*bdc37934SDmitry Chagin static void 1059*bdc37934SDmitry Chagin linux_vdso_install(void *param) 1060*bdc37934SDmitry Chagin { 1061*bdc37934SDmitry Chagin 1062*bdc37934SDmitry Chagin linux_szsigcode = (&_binary_linux32_locore_o_end - 1063*bdc37934SDmitry Chagin &_binary_linux32_locore_o_start); 1064*bdc37934SDmitry Chagin 1065*bdc37934SDmitry Chagin if (linux_szsigcode > elf_linux_sysvec.sv_shared_page_len) 1066*bdc37934SDmitry Chagin panic("Linux invalid vdso size\n"); 1067*bdc37934SDmitry Chagin 1068*bdc37934SDmitry Chagin __elfN(linux_vdso_fixup)(&elf_linux_sysvec); 1069*bdc37934SDmitry Chagin 1070*bdc37934SDmitry Chagin linux_shared_page_obj = __elfN(linux_shared_page_init) 1071*bdc37934SDmitry Chagin (&linux_shared_page_mapping); 1072*bdc37934SDmitry Chagin 1073*bdc37934SDmitry Chagin __elfN(linux_vdso_reloc)(&elf_linux_sysvec, LINUX32_SHAREDPAGE); 1074*bdc37934SDmitry Chagin 1075*bdc37934SDmitry Chagin bcopy(elf_linux_sysvec.sv_sigcode, linux_shared_page_mapping, 1076*bdc37934SDmitry Chagin linux_szsigcode); 1077*bdc37934SDmitry Chagin elf_linux_sysvec.sv_shared_page_obj = linux_shared_page_obj; 1078*bdc37934SDmitry Chagin } 1079*bdc37934SDmitry Chagin SYSINIT(elf_linux_vdso_init, SI_SUB_EXEC, SI_ORDER_ANY, 1080*bdc37934SDmitry Chagin (sysinit_cfunc_t)linux_vdso_install, NULL); 1081*bdc37934SDmitry Chagin 1082*bdc37934SDmitry Chagin static void 1083*bdc37934SDmitry Chagin linux_vdso_deinstall(void *param) 1084*bdc37934SDmitry Chagin { 1085*bdc37934SDmitry Chagin 1086*bdc37934SDmitry Chagin __elfN(linux_shared_page_fini)(linux_shared_page_obj); 1087*bdc37934SDmitry Chagin }; 1088*bdc37934SDmitry Chagin SYSUNINIT(elf_linux_vdso_uninit, SI_SUB_EXEC, SI_ORDER_FIRST, 1089*bdc37934SDmitry Chagin (sysinit_cfunc_t)linux_vdso_deinstall, NULL); 1090ea0fabbcSTim J. Robbins 109189ffc202SBjoern A. Zeeb static char GNU_ABI_VENDOR[] = "GNU"; 109289ffc202SBjoern A. Zeeb static int GNULINUX_ABI_DESC = 0; 109389ffc202SBjoern A. Zeeb 109489ffc202SBjoern A. Zeeb static boolean_t 109589ffc202SBjoern A. Zeeb linux32_trans_osrel(const Elf_Note *note, int32_t *osrel) 109689ffc202SBjoern A. Zeeb { 109789ffc202SBjoern A. Zeeb const Elf32_Word *desc; 109889ffc202SBjoern A. Zeeb uintptr_t p; 109989ffc202SBjoern A. Zeeb 110089ffc202SBjoern A. Zeeb p = (uintptr_t)(note + 1); 110189ffc202SBjoern A. Zeeb p += roundup2(note->n_namesz, sizeof(Elf32_Addr)); 110289ffc202SBjoern A. Zeeb 110389ffc202SBjoern A. Zeeb desc = (const Elf32_Word *)p; 110489ffc202SBjoern A. Zeeb if (desc[0] != GNULINUX_ABI_DESC) 110589ffc202SBjoern A. Zeeb return (FALSE); 110689ffc202SBjoern A. Zeeb 110789ffc202SBjoern A. Zeeb /* 110889ffc202SBjoern A. Zeeb * For linux we encode osrel as follows (see linux_mib.c): 110989ffc202SBjoern A. Zeeb * VVVMMMIII (version, major, minor), see linux_mib.c. 111089ffc202SBjoern A. Zeeb */ 111189ffc202SBjoern A. Zeeb *osrel = desc[1] * 1000000 + desc[2] * 1000 + desc[3]; 111289ffc202SBjoern A. Zeeb 111389ffc202SBjoern A. Zeeb return (TRUE); 111489ffc202SBjoern A. Zeeb } 111532c01de2SDmitry Chagin 111632c01de2SDmitry Chagin static Elf_Brandnote linux32_brandnote = { 111789ffc202SBjoern A. Zeeb .hdr.n_namesz = sizeof(GNU_ABI_VENDOR), 111889ffc202SBjoern A. Zeeb .hdr.n_descsz = 16, /* XXX at least 16 */ 111932c01de2SDmitry Chagin .hdr.n_type = 1, 112089ffc202SBjoern A. Zeeb .vendor = GNU_ABI_VENDOR, 112189ffc202SBjoern A. Zeeb .flags = BN_TRANSLATE_OSREL, 112289ffc202SBjoern A. Zeeb .trans_osrel = linux32_trans_osrel 112332c01de2SDmitry Chagin }; 112432c01de2SDmitry Chagin 1125ea0fabbcSTim J. Robbins static Elf32_Brandinfo linux_brand = { 1126a8d403e1SKonstantin Belousov .brand = ELFOSABI_LINUX, 1127a8d403e1SKonstantin Belousov .machine = EM_386, 1128a8d403e1SKonstantin Belousov .compat_3_brand = "Linux", 1129a8d403e1SKonstantin Belousov .emul_path = "/compat/linux", 1130a8d403e1SKonstantin Belousov .interp_path = "/lib/ld-linux.so.1", 1131a8d403e1SKonstantin Belousov .sysvec = &elf_linux_sysvec, 1132a8d403e1SKonstantin Belousov .interp_newpath = NULL, 113332c01de2SDmitry Chagin .brand_note = &linux32_brandnote, 11342dedc128SDmitry Chagin .flags = BI_CAN_EXEC_DYN | BI_BRAND_NOTE 1135ea0fabbcSTim J. Robbins }; 1136ea0fabbcSTim J. Robbins 1137ea0fabbcSTim J. Robbins static Elf32_Brandinfo linux_glibc2brand = { 1138a8d403e1SKonstantin Belousov .brand = ELFOSABI_LINUX, 1139a8d403e1SKonstantin Belousov .machine = EM_386, 1140a8d403e1SKonstantin Belousov .compat_3_brand = "Linux", 1141a8d403e1SKonstantin Belousov .emul_path = "/compat/linux", 1142a8d403e1SKonstantin Belousov .interp_path = "/lib/ld-linux.so.2", 1143a8d403e1SKonstantin Belousov .sysvec = &elf_linux_sysvec, 1144a8d403e1SKonstantin Belousov .interp_newpath = NULL, 114532c01de2SDmitry Chagin .brand_note = &linux32_brandnote, 11462dedc128SDmitry Chagin .flags = BI_CAN_EXEC_DYN | BI_BRAND_NOTE 1147ea0fabbcSTim J. Robbins }; 1148ea0fabbcSTim J. Robbins 1149ea0fabbcSTim J. Robbins Elf32_Brandinfo *linux_brandlist[] = { 1150ea0fabbcSTim J. Robbins &linux_brand, 1151ea0fabbcSTim J. Robbins &linux_glibc2brand, 1152ea0fabbcSTim J. Robbins NULL 1153ea0fabbcSTim J. Robbins }; 1154ea0fabbcSTim J. Robbins 1155ea0fabbcSTim J. Robbins static int 1156ea0fabbcSTim J. Robbins linux_elf_modevent(module_t mod, int type, void *data) 1157ea0fabbcSTim J. Robbins { 1158ea0fabbcSTim J. Robbins Elf32_Brandinfo **brandinfo; 1159ea0fabbcSTim J. Robbins int error; 1160ea0fabbcSTim J. Robbins struct linux_ioctl_handler **lihp; 1161387196bfSDoug Ambrisko struct linux_device_handler **ldhp; 1162ea0fabbcSTim J. Robbins 1163ea0fabbcSTim J. Robbins error = 0; 1164ea0fabbcSTim J. Robbins 1165ea0fabbcSTim J. Robbins switch(type) { 1166ea0fabbcSTim J. Robbins case MOD_LOAD: 1167ea0fabbcSTim J. Robbins for (brandinfo = &linux_brandlist[0]; *brandinfo != NULL; 1168ea0fabbcSTim J. Robbins ++brandinfo) 1169ea0fabbcSTim J. Robbins if (elf32_insert_brand_entry(*brandinfo) < 0) 1170ea0fabbcSTim J. Robbins error = EINVAL; 1171ea0fabbcSTim J. Robbins if (error == 0) { 1172ea0fabbcSTim J. Robbins SET_FOREACH(lihp, linux_ioctl_handler_set) 1173ea0fabbcSTim J. Robbins linux_ioctl_register_handler(*lihp); 1174387196bfSDoug Ambrisko SET_FOREACH(ldhp, linux_device_handler_set) 1175387196bfSDoug Ambrisko linux_device_register_handler(*ldhp); 11767c09e6c0SAlexander Leidinger LIST_INIT(&futex_list); 117779262bf1SDmitry Chagin mtx_init(&futex_mtx, "ftllk", NULL, MTX_DEF); 1178d065e13dSDavid E. O'Brien linux_exit_tag = EVENTHANDLER_REGISTER(process_exit, 1179d065e13dSDavid E. O'Brien linux_proc_exit, NULL, 1000); 1180d065e13dSDavid E. O'Brien linux_exec_tag = EVENTHANDLER_REGISTER(process_exec, 1181d065e13dSDavid E. O'Brien linux_proc_exec, NULL, 1000); 118281338031SDmitry Chagin linux_thread_dtor_tag = EVENTHANDLER_REGISTER(thread_dtor, 118381338031SDmitry Chagin linux_thread_dtor, NULL, EVENTHANDLER_PRI_ANY); 11844d7c2e8aSDmitry Chagin linux_szplatform = roundup(strlen(linux_platform) + 1, 11854d7c2e8aSDmitry Chagin sizeof(char *)); 11867ae27ff4SJamie Gritton linux_osd_jail_register(); 11871ca16454SDmitry Chagin stclohz = (stathz ? stathz : hz); 1188ea0fabbcSTim J. Robbins if (bootverbose) 1189ea0fabbcSTim J. Robbins printf("Linux ELF exec handler installed\n"); 1190ea0fabbcSTim J. Robbins } else 1191ea0fabbcSTim J. Robbins printf("cannot insert Linux ELF brand handler\n"); 1192ea0fabbcSTim J. Robbins break; 1193ea0fabbcSTim J. Robbins case MOD_UNLOAD: 1194ea0fabbcSTim J. Robbins for (brandinfo = &linux_brandlist[0]; *brandinfo != NULL; 1195ea0fabbcSTim J. Robbins ++brandinfo) 1196ea0fabbcSTim J. Robbins if (elf32_brand_inuse(*brandinfo)) 1197ea0fabbcSTim J. Robbins error = EBUSY; 1198ea0fabbcSTim J. Robbins if (error == 0) { 1199ea0fabbcSTim J. Robbins for (brandinfo = &linux_brandlist[0]; 1200ea0fabbcSTim J. Robbins *brandinfo != NULL; ++brandinfo) 1201ea0fabbcSTim J. Robbins if (elf32_remove_brand_entry(*brandinfo) < 0) 1202ea0fabbcSTim J. Robbins error = EINVAL; 1203ea0fabbcSTim J. Robbins } 1204ea0fabbcSTim J. Robbins if (error == 0) { 1205ea0fabbcSTim J. Robbins SET_FOREACH(lihp, linux_ioctl_handler_set) 1206ea0fabbcSTim J. Robbins linux_ioctl_unregister_handler(*lihp); 1207387196bfSDoug Ambrisko SET_FOREACH(ldhp, linux_device_handler_set) 1208387196bfSDoug Ambrisko linux_device_unregister_handler(*ldhp); 120979262bf1SDmitry Chagin mtx_destroy(&futex_mtx); 12107c09e6c0SAlexander Leidinger EVENTHANDLER_DEREGISTER(process_exit, linux_exit_tag); 12117c09e6c0SAlexander Leidinger EVENTHANDLER_DEREGISTER(process_exec, linux_exec_tag); 121281338031SDmitry Chagin EVENTHANDLER_DEREGISTER(thread_dtor, linux_thread_dtor_tag); 12137ae27ff4SJamie Gritton linux_osd_jail_deregister(); 1214ea0fabbcSTim J. Robbins if (bootverbose) 1215ea0fabbcSTim J. Robbins printf("Linux ELF exec handler removed\n"); 1216ea0fabbcSTim J. Robbins } else 1217ea0fabbcSTim J. Robbins printf("Could not deinstall ELF interpreter entry\n"); 1218ea0fabbcSTim J. Robbins break; 1219ea0fabbcSTim J. Robbins default: 1220af682d48SDmitry Chagin return (EOPNOTSUPP); 1221ea0fabbcSTim J. Robbins } 1222af682d48SDmitry Chagin return (error); 1223ea0fabbcSTim J. Robbins } 1224ea0fabbcSTim J. Robbins 1225ea0fabbcSTim J. Robbins static moduledata_t linux_elf_mod = { 1226ea0fabbcSTim J. Robbins "linuxelf", 1227ea0fabbcSTim J. Robbins linux_elf_modevent, 12289823d527SKevin Lo 0 1229ea0fabbcSTim J. Robbins }; 1230ea0fabbcSTim J. Robbins 123178ae4338SKonstantin Belousov DECLARE_MODULE_TIED(linuxelf, linux_elf_mod, SI_SUB_EXEC, SI_ORDER_ANY); 1232