1d66a5066SPeter Wemm /*- 29a14aa01SUlrich Spörlein * Copyright (c) 1994-1996 Søren Schmidt 3d66a5066SPeter Wemm * All rights reserved. 4d66a5066SPeter Wemm * 5d66a5066SPeter Wemm * Redistribution and use in source and binary forms, with or without 6d66a5066SPeter Wemm * modification, are permitted provided that the following conditions 7d66a5066SPeter Wemm * are met: 8d66a5066SPeter Wemm * 1. Redistributions of source code must retain the above copyright 9d66a5066SPeter Wemm * notice, this list of conditions and the following disclaimer 10d66a5066SPeter Wemm * in this position and unchanged. 11d66a5066SPeter Wemm * 2. Redistributions in binary form must reproduce the above copyright 12d66a5066SPeter Wemm * notice, this list of conditions and the following disclaimer in the 13d66a5066SPeter Wemm * documentation and/or other materials provided with the distribution. 14d66a5066SPeter Wemm * 3. The name of the author may not be used to endorse or promote products 1521dc7d4fSJens Schweikhardt * derived from this software without specific prior written permission 16d66a5066SPeter Wemm * 17d66a5066SPeter Wemm * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 18d66a5066SPeter Wemm * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 19d66a5066SPeter Wemm * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 20d66a5066SPeter Wemm * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 21d66a5066SPeter Wemm * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 22d66a5066SPeter Wemm * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 23d66a5066SPeter Wemm * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 24d66a5066SPeter Wemm * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 25d66a5066SPeter Wemm * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 26d66a5066SPeter Wemm * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 27d66a5066SPeter Wemm */ 28d66a5066SPeter Wemm 2927e0099cSDavid E. O'Brien #include <sys/cdefs.h> 3027e0099cSDavid E. O'Brien __FBSDID("$FreeBSD$"); 3127e0099cSDavid E. O'Brien 32d66a5066SPeter Wemm #include <sys/param.h> 3375f83872SPeter Wemm #include <sys/systm.h> 34ff22c670SBruce Evans #include <sys/exec.h> 3557b4252eSKonstantin Belousov #include <sys/fcntl.h> 36d66a5066SPeter Wemm #include <sys/imgact.h> 3722d4b0fbSJohn Polstra #include <sys/imgact_aout.h> 38e1743d02SSøren Schmidt #include <sys/imgact_elf.h> 39ff22c670SBruce Evans #include <sys/kernel.h> 407106ca0dSJohn Baldwin #include <sys/lock.h> 41e1743d02SSøren Schmidt #include <sys/malloc.h> 42ff22c670SBruce Evans #include <sys/module.h> 4323955314SAlfred Perlstein #include <sys/mutex.h> 44fb919e4dSMark Murray #include <sys/proc.h> 45fb919e4dSMark Murray #include <sys/signalvar.h> 46206a5d3aSIan Dowse #include <sys/syscallsubr.h> 47fb919e4dSMark Murray #include <sys/sysent.h> 48fb919e4dSMark Murray #include <sys/sysproto.h> 49a9148ab1SPeter Wemm #include <sys/vnode.h> 509b44bfc5SAlexander Leidinger #include <sys/eventhandler.h> 51fb919e4dSMark Murray 52d66a5066SPeter Wemm #include <vm/vm.h> 53a9148ab1SPeter Wemm #include <vm/pmap.h> 54ff22c670SBruce Evans #include <vm/vm_extern.h> 55a9148ab1SPeter Wemm #include <vm/vm_map.h> 56a9148ab1SPeter Wemm #include <vm/vm_object.h> 57ff22c670SBruce Evans #include <vm/vm_page.h> 58ff22c670SBruce Evans #include <vm/vm_param.h> 59ff22c670SBruce Evans 60ff22c670SBruce Evans #include <machine/cpu.h> 614d7c2e8aSDmitry Chagin #include <machine/cputypes.h> 62ff22c670SBruce Evans #include <machine/md_var.h> 63d3adf769SDavid Schultz #include <machine/pcb.h> 64a9148ab1SPeter Wemm 65d66a5066SPeter Wemm #include <i386/linux/linux.h> 66ebea8660SMarcel Moolenaar #include <i386/linux/linux_proto.h> 6794cb2ecfSAlexander Leidinger #include <compat/linux/linux_emul.h> 68fde63162SDmitry Chagin #include <compat/linux/linux_futex.h> 69d825ce0aSJohn Baldwin #include <compat/linux/linux_ioctl.h> 700f9d6538SJohn Baldwin #include <compat/linux/linux_mib.h> 714d7c2e8aSDmitry Chagin #include <compat/linux/linux_misc.h> 72b595ab37SAndrew Gallatin #include <compat/linux/linux_signal.h> 73322bfdc3SMarcel Moolenaar #include <compat/linux/linux_util.h> 74e1743d02SSøren Schmidt 751d91482dSPeter Wemm MODULE_VERSION(linux, 1); 761d91482dSPeter Wemm 7743bef515SMarcel Moolenaar MALLOC_DEFINE(M_LINUX, "linux", "Linux mode structures"); 7843bef515SMarcel Moolenaar 79d323ddf3SMatthew Dillon #if BYTE_ORDER == LITTLE_ENDIAN 80d323ddf3SMatthew Dillon #define SHELLMAGIC 0x2123 /* #! */ 81d323ddf3SMatthew Dillon #else 82d323ddf3SMatthew Dillon #define SHELLMAGIC 0x2321 83d323ddf3SMatthew Dillon #endif 84d323ddf3SMatthew Dillon 85e061a6caSMarcel Moolenaar /* 86e061a6caSMarcel Moolenaar * Allow the sendsig functions to use the ldebug() facility 87e061a6caSMarcel Moolenaar * even though they are not syscalls themselves. Map them 88e061a6caSMarcel Moolenaar * to syscall 0. This is slightly less bogus than using 89e061a6caSMarcel Moolenaar * ldebug(sigreturn). 90e061a6caSMarcel Moolenaar */ 91e061a6caSMarcel Moolenaar #define LINUX_SYS_linux_rt_sendsig 0 92e061a6caSMarcel Moolenaar #define LINUX_SYS_linux_sendsig 0 93e061a6caSMarcel Moolenaar 948f1e49a6SDmitry Chagin #define LINUX_PS_STRINGS (LINUX_USRSTACK - sizeof(struct ps_strings)) 958f1e49a6SDmitry Chagin 9643bef515SMarcel Moolenaar extern char linux_sigcode[]; 9743bef515SMarcel Moolenaar extern int linux_szsigcode; 9843bef515SMarcel Moolenaar 9943bef515SMarcel Moolenaar extern struct sysent linux_sysent[LINUX_SYS_MAXSYSCALL]; 10043bef515SMarcel Moolenaar 101f41325dbSPeter Wemm SET_DECLARE(linux_ioctl_handler_set, struct linux_ioctl_handler); 102060e4882SDoug Ambrisko SET_DECLARE(linux_device_handler_set, struct linux_device_handler); 10343bef515SMarcel Moolenaar 10489c9a483SAlfred Perlstein static int linux_fixup(register_t **stack_base, 10589c9a483SAlfred Perlstein struct image_params *iparams); 10689c9a483SAlfred Perlstein static int elf_linux_fixup(register_t **stack_base, 10789c9a483SAlfred Perlstein struct image_params *iparams); 1089104847fSDavid Xu static void linux_sendsig(sig_t catcher, ksiginfo_t *ksi, sigset_t *mask); 109a107d8aaSNathan Whitehorn static void exec_linux_setregs(struct thread *td, 110a107d8aaSNathan Whitehorn struct image_params *imgp, u_long stack); 1114d7c2e8aSDmitry Chagin static register_t *linux_copyout_strings(struct image_params *imgp); 11289ffc202SBjoern A. Zeeb static boolean_t linux_trans_osrel(const Elf_Note *note, int32_t *osrel); 1134d7c2e8aSDmitry Chagin 1144d7c2e8aSDmitry Chagin static int linux_szplatform; 1154d7c2e8aSDmitry Chagin const char *linux_platform; 116d66a5066SPeter Wemm 1179b44bfc5SAlexander Leidinger static eventhandler_tag linux_exit_tag; 1189b44bfc5SAlexander Leidinger static eventhandler_tag linux_exec_tag; 11981338031SDmitry Chagin static eventhandler_tag linux_thread_dtor_tag; 1209b44bfc5SAlexander Leidinger 121d66a5066SPeter Wemm /* 122d66a5066SPeter Wemm * Linux syscalls return negative errno's, we do positive and map them 12350e422f0SAlexander Leidinger * Reference: 12450e422f0SAlexander Leidinger * FreeBSD: src/sys/sys/errno.h 12550e422f0SAlexander Leidinger * Linux: linux-2.6.17.8/include/asm-generic/errno-base.h 12650e422f0SAlexander Leidinger * linux-2.6.17.8/include/asm-generic/errno.h 127d66a5066SPeter Wemm */ 12885f118c8SDmitrij Tejblum static int bsd_to_linux_errno[ELAST + 1] = { 129d66a5066SPeter Wemm -0, -1, -2, -3, -4, -5, -6, -7, -8, -9, 130d66a5066SPeter Wemm -10, -35, -12, -13, -14, -15, -16, -17, -18, -19, 131d66a5066SPeter Wemm -20, -21, -22, -23, -24, -25, -26, -27, -28, -29, 132d66a5066SPeter Wemm -30, -31, -32, -33, -34, -11,-115,-114, -88, -89, 133d66a5066SPeter Wemm -90, -91, -92, -93, -94, -95, -96, -97, -98, -99, 134d66a5066SPeter Wemm -100,-101,-102,-103,-104,-105,-106,-107,-108,-109, 135d66a5066SPeter Wemm -110,-111, -40, -36,-112,-113, -39, -11, -87,-122, 136d66a5066SPeter Wemm -116, -66, -6, -6, -6, -6, -6, -37, -38, -9, 13750e422f0SAlexander Leidinger -6, -6, -43, -42, -75,-125, -84, -95, -16, -74, 13850e422f0SAlexander Leidinger -72, -67, -71 139d66a5066SPeter Wemm }; 140d66a5066SPeter Wemm 141956d3333SMarcel Moolenaar int bsd_to_linux_signal[LINUX_SIGTBLSZ] = { 142956d3333SMarcel Moolenaar LINUX_SIGHUP, LINUX_SIGINT, LINUX_SIGQUIT, LINUX_SIGILL, 143956d3333SMarcel Moolenaar LINUX_SIGTRAP, LINUX_SIGABRT, 0, LINUX_SIGFPE, 144ba873f4cSAlexander Kabaev LINUX_SIGKILL, LINUX_SIGBUS, LINUX_SIGSEGV, LINUX_SIGSYS, 145956d3333SMarcel Moolenaar LINUX_SIGPIPE, LINUX_SIGALRM, LINUX_SIGTERM, LINUX_SIGURG, 146956d3333SMarcel Moolenaar LINUX_SIGSTOP, LINUX_SIGTSTP, LINUX_SIGCONT, LINUX_SIGCHLD, 147956d3333SMarcel Moolenaar LINUX_SIGTTIN, LINUX_SIGTTOU, LINUX_SIGIO, LINUX_SIGXCPU, 148956d3333SMarcel Moolenaar LINUX_SIGXFSZ, LINUX_SIGVTALRM, LINUX_SIGPROF, LINUX_SIGWINCH, 149956d3333SMarcel Moolenaar 0, LINUX_SIGUSR1, LINUX_SIGUSR2 150d66a5066SPeter Wemm }; 151d66a5066SPeter Wemm 152956d3333SMarcel Moolenaar int linux_to_bsd_signal[LINUX_SIGTBLSZ] = { 153956d3333SMarcel Moolenaar SIGHUP, SIGINT, SIGQUIT, SIGILL, 154956d3333SMarcel Moolenaar SIGTRAP, SIGABRT, SIGBUS, SIGFPE, 155956d3333SMarcel Moolenaar SIGKILL, SIGUSR1, SIGSEGV, SIGUSR2, 156956d3333SMarcel Moolenaar SIGPIPE, SIGALRM, SIGTERM, SIGBUS, 157956d3333SMarcel Moolenaar SIGCHLD, SIGCONT, SIGSTOP, SIGTSTP, 158956d3333SMarcel Moolenaar SIGTTIN, SIGTTOU, SIGURG, SIGXCPU, 159956d3333SMarcel Moolenaar SIGXFSZ, SIGVTALRM, SIGPROF, SIGWINCH, 160ba873f4cSAlexander Kabaev SIGIO, SIGURG, SIGSYS 161d66a5066SPeter Wemm }; 162d66a5066SPeter Wemm 16327a828fcSPierre Beyssac #define LINUX_T_UNKNOWN 255 16427a828fcSPierre Beyssac static int _bsd_to_linux_trapcode[] = { 16527a828fcSPierre Beyssac LINUX_T_UNKNOWN, /* 0 */ 16627a828fcSPierre Beyssac 6, /* 1 T_PRIVINFLT */ 16727a828fcSPierre Beyssac LINUX_T_UNKNOWN, /* 2 */ 16827a828fcSPierre Beyssac 3, /* 3 T_BPTFLT */ 16927a828fcSPierre Beyssac LINUX_T_UNKNOWN, /* 4 */ 17027a828fcSPierre Beyssac LINUX_T_UNKNOWN, /* 5 */ 17127a828fcSPierre Beyssac 16, /* 6 T_ARITHTRAP */ 17227a828fcSPierre Beyssac 254, /* 7 T_ASTFLT */ 17327a828fcSPierre Beyssac LINUX_T_UNKNOWN, /* 8 */ 17427a828fcSPierre Beyssac 13, /* 9 T_PROTFLT */ 17527a828fcSPierre Beyssac 1, /* 10 T_TRCTRAP */ 17627a828fcSPierre Beyssac LINUX_T_UNKNOWN, /* 11 */ 17727a828fcSPierre Beyssac 14, /* 12 T_PAGEFLT */ 17827a828fcSPierre Beyssac LINUX_T_UNKNOWN, /* 13 */ 17927a828fcSPierre Beyssac 17, /* 14 T_ALIGNFLT */ 18027a828fcSPierre Beyssac LINUX_T_UNKNOWN, /* 15 */ 18127a828fcSPierre Beyssac LINUX_T_UNKNOWN, /* 16 */ 18227a828fcSPierre Beyssac LINUX_T_UNKNOWN, /* 17 */ 18327a828fcSPierre Beyssac 0, /* 18 T_DIVIDE */ 18427a828fcSPierre Beyssac 2, /* 19 T_NMI */ 18527a828fcSPierre Beyssac 4, /* 20 T_OFLOW */ 18627a828fcSPierre Beyssac 5, /* 21 T_BOUND */ 18727a828fcSPierre Beyssac 7, /* 22 T_DNA */ 18827a828fcSPierre Beyssac 8, /* 23 T_DOUBLEFLT */ 18927a828fcSPierre Beyssac 9, /* 24 T_FPOPFLT */ 19027a828fcSPierre Beyssac 10, /* 25 T_TSSFLT */ 19127a828fcSPierre Beyssac 11, /* 26 T_SEGNPFLT */ 19227a828fcSPierre Beyssac 12, /* 27 T_STKFLT */ 19327a828fcSPierre Beyssac 18, /* 28 T_MCHK */ 19427a828fcSPierre Beyssac 19, /* 29 T_XMMFLT */ 19527a828fcSPierre Beyssac 15 /* 30 T_RESERVED */ 19627a828fcSPierre Beyssac }; 19727a828fcSPierre Beyssac #define bsd_to_linux_trapcode(code) \ 19827a828fcSPierre Beyssac ((code)<sizeof(_bsd_to_linux_trapcode)/sizeof(*_bsd_to_linux_trapcode)? \ 19927a828fcSPierre Beyssac _bsd_to_linux_trapcode[(code)]: \ 20027a828fcSPierre Beyssac LINUX_T_UNKNOWN) 20127a828fcSPierre Beyssac 202288078beSEivind Eklund /* 203288078beSEivind Eklund * If FreeBSD & Linux have a difference of opinion about what a trap 204288078beSEivind Eklund * means, deal with it here. 205356861dbSMatthew Dillon * 206356861dbSMatthew Dillon * MPSAFE 207288078beSEivind Eklund */ 208288078beSEivind Eklund static int 209288078beSEivind Eklund translate_traps(int signal, int trap_code) 210288078beSEivind Eklund { 211d563a53aSEivind Eklund if (signal != SIGBUS) 212*af682d48SDmitry Chagin return (signal); 213288078beSEivind Eklund switch (trap_code) { 214288078beSEivind Eklund case T_PROTFLT: 215288078beSEivind Eklund case T_TSSFLT: 216288078beSEivind Eklund case T_DOUBLEFLT: 217288078beSEivind Eklund case T_PAGEFLT: 218*af682d48SDmitry Chagin return (SIGSEGV); 219288078beSEivind Eklund default: 220*af682d48SDmitry Chagin return (signal); 221288078beSEivind Eklund } 222288078beSEivind Eklund } 223288078beSEivind Eklund 224303b270bSEivind Eklund static int 225654f6be1SBruce Evans linux_fixup(register_t **stack_base, struct image_params *imgp) 226d66a5066SPeter Wemm { 227654f6be1SBruce Evans register_t *argv, *envp; 228d66a5066SPeter Wemm 229d66a5066SPeter Wemm argv = *stack_base; 230610ecfe0SMaxim Sobolev envp = *stack_base + (imgp->args->argc + 1); 231d66a5066SPeter Wemm (*stack_base)--; 232aa103453SKonstantin Belousov suword(*stack_base, (intptr_t)(void *)envp); 233d66a5066SPeter Wemm (*stack_base)--; 234aa103453SKonstantin Belousov suword(*stack_base, (intptr_t)(void *)argv); 235d66a5066SPeter Wemm (*stack_base)--; 236aa103453SKonstantin Belousov suword(*stack_base, imgp->args->argc); 2374d7c2e8aSDmitry Chagin return (0); 238d66a5066SPeter Wemm } 239d66a5066SPeter Wemm 240303b270bSEivind Eklund static int 241654f6be1SBruce Evans elf_linux_fixup(register_t **stack_base, struct image_params *imgp) 242e1743d02SSøren Schmidt { 2434d7c2e8aSDmitry Chagin struct proc *p; 24443cf129cSJohn Baldwin Elf32_Auxargs *args; 2454d7c2e8aSDmitry Chagin Elf32_Addr *uplatform; 2464d7c2e8aSDmitry Chagin struct ps_strings *arginfo; 247654f6be1SBruce Evans register_t *pos; 248d66a5066SPeter Wemm 2496617724cSJeff Roberson KASSERT(curthread->td_proc == imgp->proc, 25043cf129cSJohn Baldwin ("unsafe elf_linux_fixup(), should be curproc")); 2514d7c2e8aSDmitry Chagin 2524d7c2e8aSDmitry Chagin p = imgp->proc; 2534d7c2e8aSDmitry Chagin arginfo = (struct ps_strings *)p->p_sysent->sv_psstrings; 254acface68SDmitry Chagin uplatform = (Elf32_Addr *)((caddr_t)arginfo - linux_szplatform); 25543cf129cSJohn Baldwin args = (Elf32_Auxargs *)imgp->auxargs; 256610ecfe0SMaxim Sobolev pos = *stack_base + (imgp->args->argc + imgp->args->envc + 2); 257e1743d02SSøren Schmidt 2584d7c2e8aSDmitry Chagin AUXARGS_ENTRY(pos, LINUX_AT_HWCAP, cpu_feature); 2598d30f381SDmitry Chagin 2608d30f381SDmitry Chagin /* 2618d30f381SDmitry Chagin * Do not export AT_CLKTCK when emulating Linux kernel prior to 2.4.0, 2628d30f381SDmitry Chagin * as it has appeared in the 2.4.0-rc7 first time. 2638d30f381SDmitry Chagin * Being exported, AT_CLKTCK is returned by sysconf(_SC_CLK_TCK), 2648d30f381SDmitry Chagin * glibc falls back to the hard-coded CLK_TCK value when aux entry 2658d30f381SDmitry Chagin * is not present. 2668d30f381SDmitry Chagin * Also see linux_times() implementation. 2678d30f381SDmitry Chagin */ 2688d30f381SDmitry Chagin if (linux_kernver(curthread) >= LINUX_KERNVER_2004000) 2691ca16454SDmitry Chagin AUXARGS_ENTRY(pos, LINUX_AT_CLKTCK, stclohz); 270e1743d02SSøren Schmidt AUXARGS_ENTRY(pos, AT_PHDR, args->phdr); 271e1743d02SSøren Schmidt AUXARGS_ENTRY(pos, AT_PHENT, args->phent); 272e1743d02SSøren Schmidt AUXARGS_ENTRY(pos, AT_PHNUM, args->phnum); 273e1743d02SSøren Schmidt AUXARGS_ENTRY(pos, AT_PAGESZ, args->pagesz); 274e1743d02SSøren Schmidt AUXARGS_ENTRY(pos, AT_FLAGS, args->flags); 275e1743d02SSøren Schmidt AUXARGS_ENTRY(pos, AT_ENTRY, args->entry); 276e1743d02SSøren Schmidt AUXARGS_ENTRY(pos, AT_BASE, args->base); 2774d7c2e8aSDmitry Chagin AUXARGS_ENTRY(pos, LINUX_AT_SECURE, 0); 278b1fc0ec1SRobert Watson AUXARGS_ENTRY(pos, AT_UID, imgp->proc->p_ucred->cr_ruid); 279b1fc0ec1SRobert Watson AUXARGS_ENTRY(pos, AT_EUID, imgp->proc->p_ucred->cr_svuid); 280b1fc0ec1SRobert Watson AUXARGS_ENTRY(pos, AT_GID, imgp->proc->p_ucred->cr_rgid); 281b1fc0ec1SRobert Watson AUXARGS_ENTRY(pos, AT_EGID, imgp->proc->p_ucred->cr_svgid); 2824d7c2e8aSDmitry Chagin AUXARGS_ENTRY(pos, LINUX_AT_PLATFORM, PTROUT(uplatform)); 2834d7c2e8aSDmitry Chagin if (args->execfd != -1) 2844d7c2e8aSDmitry Chagin AUXARGS_ENTRY(pos, AT_EXECFD, args->execfd); 285e1743d02SSøren Schmidt AUXARGS_ENTRY(pos, AT_NULL, 0); 286e1743d02SSøren Schmidt 287e1743d02SSøren Schmidt free(imgp->auxargs, M_TEMP); 288e1743d02SSøren Schmidt imgp->auxargs = NULL; 289e1743d02SSøren Schmidt 290e1743d02SSøren Schmidt (*stack_base)--; 291aa103453SKonstantin Belousov suword(*stack_base, (register_t)imgp->args->argc); 2924d7c2e8aSDmitry Chagin return (0); 293e1743d02SSøren Schmidt } 294d66a5066SPeter Wemm 2954d7c2e8aSDmitry Chagin /* 2964d7c2e8aSDmitry Chagin * Copied from kern/kern_exec.c 2974d7c2e8aSDmitry Chagin */ 2984d7c2e8aSDmitry Chagin static register_t * 2994d7c2e8aSDmitry Chagin linux_copyout_strings(struct image_params *imgp) 3004d7c2e8aSDmitry Chagin { 3014d7c2e8aSDmitry Chagin int argc, envc; 3024d7c2e8aSDmitry Chagin char **vectp; 3034d7c2e8aSDmitry Chagin char *stringp, *destp; 3044d7c2e8aSDmitry Chagin register_t *stack_base; 3054d7c2e8aSDmitry Chagin struct ps_strings *arginfo; 3064d7c2e8aSDmitry Chagin struct proc *p; 3074d7c2e8aSDmitry Chagin 3084d7c2e8aSDmitry Chagin /* 3094d7c2e8aSDmitry Chagin * Calculate string base and vector table pointers. 3104d7c2e8aSDmitry Chagin * Also deal with signal trampoline code for this exec type. 3114d7c2e8aSDmitry Chagin */ 3124d7c2e8aSDmitry Chagin p = imgp->proc; 3134d7c2e8aSDmitry Chagin arginfo = (struct ps_strings *)p->p_sysent->sv_psstrings; 3148f1e49a6SDmitry Chagin destp = (caddr_t)arginfo - SPARE_USRSPACE - linux_szplatform - 3158f1e49a6SDmitry Chagin roundup((ARG_MAX - imgp->args->stringspace), sizeof(char *)); 3164d7c2e8aSDmitry Chagin 3174d7c2e8aSDmitry Chagin /* 3184d7c2e8aSDmitry Chagin * install LINUX_PLATFORM 3194d7c2e8aSDmitry Chagin */ 3208f1e49a6SDmitry Chagin copyout(linux_platform, ((caddr_t)arginfo - linux_szplatform), 3218f1e49a6SDmitry Chagin linux_szplatform); 3224d7c2e8aSDmitry Chagin 3234d7c2e8aSDmitry Chagin /* 3244d7c2e8aSDmitry Chagin * If we have a valid auxargs ptr, prepare some room 3254d7c2e8aSDmitry Chagin * on the stack. 3264d7c2e8aSDmitry Chagin */ 3274d7c2e8aSDmitry Chagin if (imgp->auxargs) { 3284d7c2e8aSDmitry Chagin /* 3294d7c2e8aSDmitry Chagin * 'AT_COUNT*2' is size for the ELF Auxargs data. This is for 3304d7c2e8aSDmitry Chagin * lower compatibility. 3314d7c2e8aSDmitry Chagin */ 3324d7c2e8aSDmitry Chagin imgp->auxarg_size = (imgp->auxarg_size) ? imgp->auxarg_size : 3334d7c2e8aSDmitry Chagin (LINUX_AT_COUNT * 2); 3344d7c2e8aSDmitry Chagin /* 3354d7c2e8aSDmitry Chagin * The '+ 2' is for the null pointers at the end of each of 3364d7c2e8aSDmitry Chagin * the arg and env vector sets,and imgp->auxarg_size is room 3374d7c2e8aSDmitry Chagin * for argument of Runtime loader. 3384d7c2e8aSDmitry Chagin */ 3394d7c2e8aSDmitry Chagin vectp = (char **)(destp - (imgp->args->argc + 3404d7c2e8aSDmitry Chagin imgp->args->envc + 2 + imgp->auxarg_size) * sizeof(char *)); 3414d7c2e8aSDmitry Chagin } else { 3424d7c2e8aSDmitry Chagin /* 3434d7c2e8aSDmitry Chagin * The '+ 2' is for the null pointers at the end of each of 3444d7c2e8aSDmitry Chagin * the arg and env vector sets 3454d7c2e8aSDmitry Chagin */ 3464d7c2e8aSDmitry Chagin vectp = (char **)(destp - (imgp->args->argc + imgp->args->envc + 2) * 3474d7c2e8aSDmitry Chagin sizeof(char *)); 3484d7c2e8aSDmitry Chagin } 3494d7c2e8aSDmitry Chagin 3504d7c2e8aSDmitry Chagin /* 3514d7c2e8aSDmitry Chagin * vectp also becomes our initial stack base 3524d7c2e8aSDmitry Chagin */ 3534d7c2e8aSDmitry Chagin stack_base = (register_t *)vectp; 3544d7c2e8aSDmitry Chagin 3554d7c2e8aSDmitry Chagin stringp = imgp->args->begin_argv; 3564d7c2e8aSDmitry Chagin argc = imgp->args->argc; 3574d7c2e8aSDmitry Chagin envc = imgp->args->envc; 3584d7c2e8aSDmitry Chagin 3594d7c2e8aSDmitry Chagin /* 3604d7c2e8aSDmitry Chagin * Copy out strings - arguments and environment. 3614d7c2e8aSDmitry Chagin */ 3624d7c2e8aSDmitry Chagin copyout(stringp, destp, ARG_MAX - imgp->args->stringspace); 3634d7c2e8aSDmitry Chagin 3644d7c2e8aSDmitry Chagin /* 3654d7c2e8aSDmitry Chagin * Fill in "ps_strings" struct for ps, w, etc. 3664d7c2e8aSDmitry Chagin */ 3674d7c2e8aSDmitry Chagin suword(&arginfo->ps_argvstr, (long)(intptr_t)vectp); 3684d7c2e8aSDmitry Chagin suword(&arginfo->ps_nargvstr, argc); 3694d7c2e8aSDmitry Chagin 3704d7c2e8aSDmitry Chagin /* 3714d7c2e8aSDmitry Chagin * Fill in argument portion of vector table. 3724d7c2e8aSDmitry Chagin */ 3734d7c2e8aSDmitry Chagin for (; argc > 0; --argc) { 3744d7c2e8aSDmitry Chagin suword(vectp++, (long)(intptr_t)destp); 3754d7c2e8aSDmitry Chagin while (*stringp++ != 0) 3764d7c2e8aSDmitry Chagin destp++; 3774d7c2e8aSDmitry Chagin destp++; 3784d7c2e8aSDmitry Chagin } 3794d7c2e8aSDmitry Chagin 3804d7c2e8aSDmitry Chagin /* a null vector table pointer separates the argp's from the envp's */ 3814d7c2e8aSDmitry Chagin suword(vectp++, 0); 3824d7c2e8aSDmitry Chagin 3834d7c2e8aSDmitry Chagin suword(&arginfo->ps_envstr, (long)(intptr_t)vectp); 3844d7c2e8aSDmitry Chagin suword(&arginfo->ps_nenvstr, envc); 3854d7c2e8aSDmitry Chagin 3864d7c2e8aSDmitry Chagin /* 3874d7c2e8aSDmitry Chagin * Fill in environment portion of vector table. 3884d7c2e8aSDmitry Chagin */ 3894d7c2e8aSDmitry Chagin for (; envc > 0; --envc) { 3904d7c2e8aSDmitry Chagin suword(vectp++, (long)(intptr_t)destp); 3914d7c2e8aSDmitry Chagin while (*stringp++ != 0) 3924d7c2e8aSDmitry Chagin destp++; 3934d7c2e8aSDmitry Chagin destp++; 3944d7c2e8aSDmitry Chagin } 3954d7c2e8aSDmitry Chagin 3964d7c2e8aSDmitry Chagin /* end of vector table is a null pointer */ 3974d7c2e8aSDmitry Chagin suword(vectp, 0); 3984d7c2e8aSDmitry Chagin 3994d7c2e8aSDmitry Chagin return (stack_base); 4004d7c2e8aSDmitry Chagin } 4014d7c2e8aSDmitry Chagin 4024d7c2e8aSDmitry Chagin 4034d7c2e8aSDmitry Chagin 40402318dacSJake Burkholder extern unsigned long linux_sznonrtsigcode; 40579363394SAndrew Gallatin 40679363394SAndrew Gallatin static void 4079104847fSDavid Xu linux_rt_sendsig(sig_t catcher, ksiginfo_t *ksi, sigset_t *mask) 40879363394SAndrew Gallatin { 4091d062e2bSDag-Erling Smørgrav struct thread *td = curthread; 4101d062e2bSDag-Erling Smørgrav struct proc *p = td->td_proc; 41190af4afaSJohn Baldwin struct sigacts *psp; 4121d062e2bSDag-Erling Smørgrav struct trapframe *regs; 4135002a60fSMarcel Moolenaar struct l_rt_sigframe *fp, frame; 4149104847fSDavid Xu int sig, code; 41579363394SAndrew Gallatin int oonstack; 41679363394SAndrew Gallatin 4179104847fSDavid Xu sig = ksi->ksi_signo; 4189104847fSDavid Xu code = ksi->ksi_code; 419df53e91cSJohn Baldwin PROC_LOCK_ASSERT(p, MA_OWNED); 42090af4afaSJohn Baldwin psp = p->p_sigacts; 42190af4afaSJohn Baldwin mtx_assert(&psp->ps_mtx, MA_OWNED); 422b40ce416SJulian Elischer regs = td->td_frame; 423d034d459SMarcel Moolenaar oonstack = sigonstack(regs->tf_esp); 42479363394SAndrew Gallatin 42579363394SAndrew Gallatin #ifdef DEBUG 4265002a60fSMarcel Moolenaar if (ldebug(rt_sendsig)) 427728ef954SJohn Baldwin printf(ARGS(rt_sendsig, "%p, %d, %p, %u"), 42824593369SJonathan Lemon catcher, sig, (void*)mask, code); 42979363394SAndrew Gallatin #endif 43079363394SAndrew Gallatin /* 43179363394SAndrew Gallatin * Allocate space for the signal handler context. 43279363394SAndrew Gallatin */ 433a30ec4b9SDavid Xu if ((td->td_pflags & TDP_ALTSTACK) && !oonstack && 43490af4afaSJohn Baldwin SIGISMEMBER(psp->ps_sigonstack, sig)) { 435a30ec4b9SDavid Xu fp = (struct l_rt_sigframe *)(td->td_sigstk.ss_sp + 436a30ec4b9SDavid Xu td->td_sigstk.ss_size - sizeof(struct l_rt_sigframe)); 437d034d459SMarcel Moolenaar } else 4385002a60fSMarcel Moolenaar fp = (struct l_rt_sigframe *)regs->tf_esp - 1; 43990af4afaSJohn Baldwin mtx_unlock(&psp->ps_mtx); 44079363394SAndrew Gallatin 44179363394SAndrew Gallatin /* 44279363394SAndrew Gallatin * Build the argument list for the signal handler. 44379363394SAndrew Gallatin */ 44479363394SAndrew Gallatin if (p->p_sysent->sv_sigtbl) 44579363394SAndrew Gallatin if (sig <= p->p_sysent->sv_sigsize) 44679363394SAndrew Gallatin sig = p->p_sysent->sv_sigtbl[_SIG_IDX(sig)]; 44779363394SAndrew Gallatin 44899d45c5fSMarcel Moolenaar bzero(&frame, sizeof(frame)); 44999d45c5fSMarcel Moolenaar 45079363394SAndrew Gallatin frame.sf_handler = catcher; 45179363394SAndrew Gallatin frame.sf_sig = sig; 45279363394SAndrew Gallatin frame.sf_siginfo = &fp->sf_si; 45379363394SAndrew Gallatin frame.sf_ucontext = &fp->sf_sc; 454cc6ca9b3SMarcel Moolenaar 4559d05b77dSJuli Mallett /* Fill in POSIX parts */ 456aa8b2011SKonstantin Belousov ksiginfo_to_lsiginfo(ksi, &frame.sf_si, sig); 457cc6ca9b3SMarcel Moolenaar 45879363394SAndrew Gallatin /* 45979363394SAndrew Gallatin * Build the signal context to be used by sigreturn. 46079363394SAndrew Gallatin */ 461cc6ca9b3SMarcel Moolenaar frame.sf_sc.uc_flags = 0; /* XXX ??? */ 462cc6ca9b3SMarcel Moolenaar frame.sf_sc.uc_link = NULL; /* XXX ??? */ 463cc6ca9b3SMarcel Moolenaar 464a30ec4b9SDavid Xu frame.sf_sc.uc_stack.ss_sp = td->td_sigstk.ss_sp; 465a30ec4b9SDavid Xu frame.sf_sc.uc_stack.ss_size = td->td_sigstk.ss_size; 466a30ec4b9SDavid Xu frame.sf_sc.uc_stack.ss_flags = (td->td_pflags & TDP_ALTSTACK) 467d034d459SMarcel Moolenaar ? ((oonstack) ? LINUX_SS_ONSTACK : 0) : LINUX_SS_DISABLE; 468611d9407SJohn Baldwin PROC_UNLOCK(p); 469cc6ca9b3SMarcel Moolenaar 470cc6ca9b3SMarcel Moolenaar bsd_to_linux_sigset(mask, &frame.sf_sc.uc_sigmask); 471cc6ca9b3SMarcel Moolenaar 472cc6ca9b3SMarcel Moolenaar frame.sf_sc.uc_mcontext.sc_mask = frame.sf_sc.uc_sigmask.__bits[0]; 47379363394SAndrew Gallatin frame.sf_sc.uc_mcontext.sc_gs = rgs(); 47479363394SAndrew Gallatin frame.sf_sc.uc_mcontext.sc_fs = regs->tf_fs; 47579363394SAndrew Gallatin frame.sf_sc.uc_mcontext.sc_es = regs->tf_es; 47679363394SAndrew Gallatin frame.sf_sc.uc_mcontext.sc_ds = regs->tf_ds; 47779363394SAndrew Gallatin frame.sf_sc.uc_mcontext.sc_edi = regs->tf_edi; 47879363394SAndrew Gallatin frame.sf_sc.uc_mcontext.sc_esi = regs->tf_esi; 47979363394SAndrew Gallatin frame.sf_sc.uc_mcontext.sc_ebp = regs->tf_ebp; 48079363394SAndrew Gallatin frame.sf_sc.uc_mcontext.sc_ebx = regs->tf_ebx; 48179363394SAndrew Gallatin frame.sf_sc.uc_mcontext.sc_edx = regs->tf_edx; 48279363394SAndrew Gallatin frame.sf_sc.uc_mcontext.sc_ecx = regs->tf_ecx; 48379363394SAndrew Gallatin frame.sf_sc.uc_mcontext.sc_eax = regs->tf_eax; 48479363394SAndrew Gallatin frame.sf_sc.uc_mcontext.sc_eip = regs->tf_eip; 48579363394SAndrew Gallatin frame.sf_sc.uc_mcontext.sc_cs = regs->tf_cs; 48679363394SAndrew Gallatin frame.sf_sc.uc_mcontext.sc_eflags = regs->tf_eflags; 48779363394SAndrew Gallatin frame.sf_sc.uc_mcontext.sc_esp_at_signal = regs->tf_esp; 48879363394SAndrew Gallatin frame.sf_sc.uc_mcontext.sc_ss = regs->tf_ss; 48979363394SAndrew Gallatin frame.sf_sc.uc_mcontext.sc_err = regs->tf_err; 49096a2b635SKonstantin Belousov frame.sf_sc.uc_mcontext.sc_cr2 = (register_t)ksi->ksi_addr; 49127a828fcSPierre Beyssac frame.sf_sc.uc_mcontext.sc_trapno = bsd_to_linux_trapcode(code); 49279363394SAndrew Gallatin 49379363394SAndrew Gallatin #ifdef DEBUG 4945002a60fSMarcel Moolenaar if (ldebug(rt_sendsig)) 49524593369SJonathan Lemon printf(LMSG("rt_sendsig flags: 0x%x, sp: %p, ss: 0x%x, mask: 0x%x"), 4969b778a16SDavid Xu frame.sf_sc.uc_stack.ss_flags, td->td_sigstk.ss_sp, 4979b778a16SDavid Xu td->td_sigstk.ss_size, frame.sf_sc.uc_mcontext.sc_mask); 49879363394SAndrew Gallatin #endif 49979363394SAndrew Gallatin 50079363394SAndrew Gallatin if (copyout(&frame, fp, sizeof(frame)) != 0) { 50179363394SAndrew Gallatin /* 50279363394SAndrew Gallatin * Process has trashed its stack; give it an illegal 50379363394SAndrew Gallatin * instruction to halt it in its tracks. 50479363394SAndrew Gallatin */ 50589734883SAlan Cox #ifdef DEBUG 50689734883SAlan Cox if (ldebug(rt_sendsig)) 50789734883SAlan Cox printf(LMSG("rt_sendsig: bad stack %p, oonstack=%x"), 50889734883SAlan Cox fp, oonstack); 50989734883SAlan Cox #endif 51019eb87d2SJohn Baldwin PROC_LOCK(p); 511b40ce416SJulian Elischer sigexit(td, SIGILL); 51279363394SAndrew Gallatin } 51379363394SAndrew Gallatin 51479363394SAndrew Gallatin /* 51579363394SAndrew Gallatin * Build context to run handler in. 51679363394SAndrew Gallatin */ 51779363394SAndrew Gallatin regs->tf_esp = (int)fp; 5188f1e49a6SDmitry Chagin regs->tf_eip = p->p_sysent->sv_sigcode_base + linux_sznonrtsigcode; 51922eca0bfSKonstantin Belousov regs->tf_eflags &= ~(PSL_T | PSL_VM | PSL_D); 52079363394SAndrew Gallatin regs->tf_cs = _ucodesel; 52179363394SAndrew Gallatin regs->tf_ds = _udatasel; 52279363394SAndrew Gallatin regs->tf_es = _udatasel; 52379363394SAndrew Gallatin regs->tf_fs = _udatasel; 52479363394SAndrew Gallatin regs->tf_ss = _udatasel; 525df53e91cSJohn Baldwin PROC_LOCK(p); 52690af4afaSJohn Baldwin mtx_lock(&psp->ps_mtx); 52779363394SAndrew Gallatin } 52879363394SAndrew Gallatin 529d66a5066SPeter Wemm 530d66a5066SPeter Wemm /* 531d66a5066SPeter Wemm * Send an interrupt to process. 532d66a5066SPeter Wemm * 533d66a5066SPeter Wemm * Stack is set up to allow sigcode stored 534d66a5066SPeter Wemm * in u. to call routine, followed by kcall 535d66a5066SPeter Wemm * to sigreturn routine below. After sigreturn 536d66a5066SPeter Wemm * resets the signal mask, the stack, and the 537d66a5066SPeter Wemm * frame pointer, it returns to the user 538d66a5066SPeter Wemm * specified pc, psl. 539d66a5066SPeter Wemm */ 540303b270bSEivind Eklund static void 5419104847fSDavid Xu linux_sendsig(sig_t catcher, ksiginfo_t *ksi, sigset_t *mask) 542d66a5066SPeter Wemm { 5431d062e2bSDag-Erling Smørgrav struct thread *td = curthread; 5441d062e2bSDag-Erling Smørgrav struct proc *p = td->td_proc; 54590af4afaSJohn Baldwin struct sigacts *psp; 5461d062e2bSDag-Erling Smørgrav struct trapframe *regs; 5475002a60fSMarcel Moolenaar struct l_sigframe *fp, frame; 5485002a60fSMarcel Moolenaar l_sigset_t lmask; 5499104847fSDavid Xu int sig, code; 5502c4ab9ddSAndrew Gallatin int oonstack, i; 551d66a5066SPeter Wemm 5522509e6c2SJohn Baldwin PROC_LOCK_ASSERT(p, MA_OWNED); 55390af4afaSJohn Baldwin psp = p->p_sigacts; 5549104847fSDavid Xu sig = ksi->ksi_signo; 5559104847fSDavid Xu code = ksi->ksi_code; 55690af4afaSJohn Baldwin mtx_assert(&psp->ps_mtx, MA_OWNED); 55790af4afaSJohn Baldwin if (SIGISMEMBER(psp->ps_siginfo, sig)) { 558cc6ca9b3SMarcel Moolenaar /* Signal handler installed with SA_SIGINFO. */ 5599104847fSDavid Xu linux_rt_sendsig(catcher, ksi, mask); 560cc6ca9b3SMarcel Moolenaar return; 561cc6ca9b3SMarcel Moolenaar } 562b40ce416SJulian Elischer regs = td->td_frame; 563d034d459SMarcel Moolenaar oonstack = sigonstack(regs->tf_esp); 564d66a5066SPeter Wemm 565d66a5066SPeter Wemm #ifdef DEBUG 5665002a60fSMarcel Moolenaar if (ldebug(sendsig)) 567728ef954SJohn Baldwin printf(ARGS(sendsig, "%p, %d, %p, %u"), 56824593369SJonathan Lemon catcher, sig, (void*)mask, code); 569d66a5066SPeter Wemm #endif 57079363394SAndrew Gallatin 571d66a5066SPeter Wemm /* 572d66a5066SPeter Wemm * Allocate space for the signal handler context. 573d66a5066SPeter Wemm */ 574a30ec4b9SDavid Xu if ((td->td_pflags & TDP_ALTSTACK) && !oonstack && 57590af4afaSJohn Baldwin SIGISMEMBER(psp->ps_sigonstack, sig)) { 576a30ec4b9SDavid Xu fp = (struct l_sigframe *)(td->td_sigstk.ss_sp + 577a30ec4b9SDavid Xu td->td_sigstk.ss_size - sizeof(struct l_sigframe)); 578d034d459SMarcel Moolenaar } else 5795002a60fSMarcel Moolenaar fp = (struct l_sigframe *)regs->tf_esp - 1; 58090af4afaSJohn Baldwin mtx_unlock(&psp->ps_mtx); 581611d9407SJohn Baldwin PROC_UNLOCK(p); 582d66a5066SPeter Wemm 583d66a5066SPeter Wemm /* 584d66a5066SPeter Wemm * Build the argument list for the signal handler. 585d66a5066SPeter Wemm */ 586956d3333SMarcel Moolenaar if (p->p_sysent->sv_sigtbl) 587956d3333SMarcel Moolenaar if (sig <= p->p_sysent->sv_sigsize) 588956d3333SMarcel Moolenaar sig = p->p_sysent->sv_sigtbl[_SIG_IDX(sig)]; 589d66a5066SPeter Wemm 59099d45c5fSMarcel Moolenaar bzero(&frame, sizeof(frame)); 59199d45c5fSMarcel Moolenaar 592d66a5066SPeter Wemm frame.sf_handler = catcher; 593d66a5066SPeter Wemm frame.sf_sig = sig; 594d66a5066SPeter Wemm 595cc6ca9b3SMarcel Moolenaar bsd_to_linux_sigset(mask, &lmask); 596cc6ca9b3SMarcel Moolenaar 597d66a5066SPeter Wemm /* 598d66a5066SPeter Wemm * Build the signal context to be used by sigreturn. 599d66a5066SPeter Wemm */ 600cc6ca9b3SMarcel Moolenaar frame.sf_sc.sc_mask = lmask.__bits[0]; 6015206bca1SLuoqi Chen frame.sf_sc.sc_gs = rgs(); 6025206bca1SLuoqi Chen frame.sf_sc.sc_fs = regs->tf_fs; 603213fdd80SPeter Wemm frame.sf_sc.sc_es = regs->tf_es; 604213fdd80SPeter Wemm frame.sf_sc.sc_ds = regs->tf_ds; 605213fdd80SPeter Wemm frame.sf_sc.sc_edi = regs->tf_edi; 606213fdd80SPeter Wemm frame.sf_sc.sc_esi = regs->tf_esi; 607213fdd80SPeter Wemm frame.sf_sc.sc_ebp = regs->tf_ebp; 608213fdd80SPeter Wemm frame.sf_sc.sc_ebx = regs->tf_ebx; 609213fdd80SPeter Wemm frame.sf_sc.sc_edx = regs->tf_edx; 610213fdd80SPeter Wemm frame.sf_sc.sc_ecx = regs->tf_ecx; 611213fdd80SPeter Wemm frame.sf_sc.sc_eax = regs->tf_eax; 612213fdd80SPeter Wemm frame.sf_sc.sc_eip = regs->tf_eip; 613213fdd80SPeter Wemm frame.sf_sc.sc_cs = regs->tf_cs; 614213fdd80SPeter Wemm frame.sf_sc.sc_eflags = regs->tf_eflags; 615213fdd80SPeter Wemm frame.sf_sc.sc_esp_at_signal = regs->tf_esp; 616213fdd80SPeter Wemm frame.sf_sc.sc_ss = regs->tf_ss; 617213fdd80SPeter Wemm frame.sf_sc.sc_err = regs->tf_err; 61896a2b635SKonstantin Belousov frame.sf_sc.sc_cr2 = (register_t)ksi->ksi_addr; 6199104847fSDavid Xu frame.sf_sc.sc_trapno = bsd_to_linux_trapcode(ksi->ksi_trapno); 620cc6ca9b3SMarcel Moolenaar 6212c4ab9ddSAndrew Gallatin for (i = 0; i < (LINUX_NSIG_WORDS-1); i++) 622cc6ca9b3SMarcel Moolenaar frame.sf_extramask[i] = lmask.__bits[i+1]; 623d66a5066SPeter Wemm 624d66a5066SPeter Wemm if (copyout(&frame, fp, sizeof(frame)) != 0) { 625d66a5066SPeter Wemm /* 626d66a5066SPeter Wemm * Process has trashed its stack; give it an illegal 627d66a5066SPeter Wemm * instruction to halt it in its tracks. 628d66a5066SPeter Wemm */ 62919eb87d2SJohn Baldwin PROC_LOCK(p); 630b40ce416SJulian Elischer sigexit(td, SIGILL); 631d66a5066SPeter Wemm } 632d66a5066SPeter Wemm 633d66a5066SPeter Wemm /* 634d66a5066SPeter Wemm * Build context to run handler in. 635d66a5066SPeter Wemm */ 636213fdd80SPeter Wemm regs->tf_esp = (int)fp; 6378f1e49a6SDmitry Chagin regs->tf_eip = p->p_sysent->sv_sigcode_base; 63822eca0bfSKonstantin Belousov regs->tf_eflags &= ~(PSL_T | PSL_VM | PSL_D); 639213fdd80SPeter Wemm regs->tf_cs = _ucodesel; 640213fdd80SPeter Wemm regs->tf_ds = _udatasel; 641213fdd80SPeter Wemm regs->tf_es = _udatasel; 6425206bca1SLuoqi Chen regs->tf_fs = _udatasel; 643213fdd80SPeter Wemm regs->tf_ss = _udatasel; 6445002a60fSMarcel Moolenaar PROC_LOCK(p); 64590af4afaSJohn Baldwin mtx_lock(&psp->ps_mtx); 646d66a5066SPeter Wemm } 647d66a5066SPeter Wemm 648d66a5066SPeter Wemm /* 649d66a5066SPeter Wemm * System call to cleanup state after a signal 650d66a5066SPeter Wemm * has been taken. Reset signal mask and 651d66a5066SPeter Wemm * stack state from context left by sendsig (above). 652d66a5066SPeter Wemm * Return to previous pc and psl as specified by 653d66a5066SPeter Wemm * context left by sendsig. Check carefully to 654d66a5066SPeter Wemm * make sure that the user has not modified the 655d66a5066SPeter Wemm * psl to gain improper privileges or to cause 656d66a5066SPeter Wemm * a machine fault. 657d66a5066SPeter Wemm */ 658d66a5066SPeter Wemm int 659b07cd97eSMark Murray linux_sigreturn(struct thread *td, struct linux_sigreturn_args *args) 660d66a5066SPeter Wemm { 6615002a60fSMarcel Moolenaar struct l_sigframe frame; 6621d062e2bSDag-Erling Smørgrav struct trapframe *regs; 6635002a60fSMarcel Moolenaar l_sigset_t lmask; 664d6e029adSKonstantin Belousov sigset_t bmask; 6652c4ab9ddSAndrew Gallatin int eflags, i; 6669104847fSDavid Xu ksiginfo_t ksi; 667d66a5066SPeter Wemm 668b40ce416SJulian Elischer regs = td->td_frame; 669d66a5066SPeter Wemm 670d66a5066SPeter Wemm #ifdef DEBUG 67124593369SJonathan Lemon if (ldebug(sigreturn)) 67224593369SJonathan Lemon printf(ARGS(sigreturn, "%p"), (void *)args->sfp); 673d66a5066SPeter Wemm #endif 674d66a5066SPeter Wemm /* 675cc6ca9b3SMarcel Moolenaar * The trampoline code hands us the sigframe. 676d66a5066SPeter Wemm * It is unsafe to keep track of it ourselves, in the event that a 677d66a5066SPeter Wemm * program jumps out of a signal handler. 678d66a5066SPeter Wemm */ 6794b7ef73dSDag-Erling Smørgrav if (copyin(args->sfp, &frame, sizeof(frame)) != 0) 680d66a5066SPeter Wemm return (EFAULT); 681d66a5066SPeter Wemm 682d66a5066SPeter Wemm /* 683d66a5066SPeter Wemm * Check for security violations. 684d66a5066SPeter Wemm */ 685d66a5066SPeter Wemm #define EFLAGS_SECURE(ef, oef) ((((ef) ^ (oef)) & ~PSL_USERCHANGE) == 0) 686cc6ca9b3SMarcel Moolenaar eflags = frame.sf_sc.sc_eflags; 6873d271aaaSEd Maste if (!EFLAGS_SECURE(eflags, regs->tf_eflags)) 688d66a5066SPeter Wemm return (EINVAL); 689d66a5066SPeter Wemm 690d66a5066SPeter Wemm /* 691d66a5066SPeter Wemm * Don't allow users to load a valid privileged %cs. Let the 692d66a5066SPeter Wemm * hardware check for invalid selectors, excess privilege in 693d66a5066SPeter Wemm * other selectors, invalid %eip's and invalid %esp's. 694d66a5066SPeter Wemm */ 69540d50994SPhilippe Charnier #define CS_SECURE(cs) (ISPL(cs) == SEL_UPL) 696cc6ca9b3SMarcel Moolenaar if (!CS_SECURE(frame.sf_sc.sc_cs)) { 6979104847fSDavid Xu ksiginfo_init_trap(&ksi); 6989104847fSDavid Xu ksi.ksi_signo = SIGBUS; 6999104847fSDavid Xu ksi.ksi_code = BUS_OBJERR; 7009104847fSDavid Xu ksi.ksi_trapno = T_PROTFLT; 7019104847fSDavid Xu ksi.ksi_addr = (void *)regs->tf_eip; 7029104847fSDavid Xu trapsignal(td, &ksi); 703d66a5066SPeter Wemm return (EINVAL); 704d66a5066SPeter Wemm } 705d66a5066SPeter Wemm 706cc6ca9b3SMarcel Moolenaar lmask.__bits[0] = frame.sf_sc.sc_mask; 7072c4ab9ddSAndrew Gallatin for (i = 0; i < (LINUX_NSIG_WORDS-1); i++) 708cc6ca9b3SMarcel Moolenaar lmask.__bits[i+1] = frame.sf_extramask[i]; 709d6e029adSKonstantin Belousov linux_to_bsd_sigset(&lmask, &bmask); 710d6e029adSKonstantin Belousov kern_sigprocmask(td, SIG_SETMASK, &bmask, NULL, 0); 711956d3333SMarcel Moolenaar 712d66a5066SPeter Wemm /* 713d66a5066SPeter Wemm * Restore signal context. 714d66a5066SPeter Wemm */ 7155206bca1SLuoqi Chen /* %gs was restored by the trampoline. */ 716cc6ca9b3SMarcel Moolenaar regs->tf_fs = frame.sf_sc.sc_fs; 717cc6ca9b3SMarcel Moolenaar regs->tf_es = frame.sf_sc.sc_es; 718cc6ca9b3SMarcel Moolenaar regs->tf_ds = frame.sf_sc.sc_ds; 719cc6ca9b3SMarcel Moolenaar regs->tf_edi = frame.sf_sc.sc_edi; 720cc6ca9b3SMarcel Moolenaar regs->tf_esi = frame.sf_sc.sc_esi; 721cc6ca9b3SMarcel Moolenaar regs->tf_ebp = frame.sf_sc.sc_ebp; 722cc6ca9b3SMarcel Moolenaar regs->tf_ebx = frame.sf_sc.sc_ebx; 723cc6ca9b3SMarcel Moolenaar regs->tf_edx = frame.sf_sc.sc_edx; 724cc6ca9b3SMarcel Moolenaar regs->tf_ecx = frame.sf_sc.sc_ecx; 725cc6ca9b3SMarcel Moolenaar regs->tf_eax = frame.sf_sc.sc_eax; 726cc6ca9b3SMarcel Moolenaar regs->tf_eip = frame.sf_sc.sc_eip; 727cc6ca9b3SMarcel Moolenaar regs->tf_cs = frame.sf_sc.sc_cs; 728213fdd80SPeter Wemm regs->tf_eflags = eflags; 729cc6ca9b3SMarcel Moolenaar regs->tf_esp = frame.sf_sc.sc_esp_at_signal; 730cc6ca9b3SMarcel Moolenaar regs->tf_ss = frame.sf_sc.sc_ss; 731d66a5066SPeter Wemm 732d66a5066SPeter Wemm return (EJUSTRETURN); 733d66a5066SPeter Wemm } 734d66a5066SPeter Wemm 73579363394SAndrew Gallatin /* 73679363394SAndrew Gallatin * System call to cleanup state after a signal 73779363394SAndrew Gallatin * has been taken. Reset signal mask and 73879363394SAndrew Gallatin * stack state from context left by rt_sendsig (above). 73979363394SAndrew Gallatin * Return to previous pc and psl as specified by 74079363394SAndrew Gallatin * context left by sendsig. Check carefully to 74179363394SAndrew Gallatin * make sure that the user has not modified the 74279363394SAndrew Gallatin * psl to gain improper privileges or to cause 74379363394SAndrew Gallatin * a machine fault. 74479363394SAndrew Gallatin */ 74579363394SAndrew Gallatin int 746b07cd97eSMark Murray linux_rt_sigreturn(struct thread *td, struct linux_rt_sigreturn_args *args) 74779363394SAndrew Gallatin { 7485002a60fSMarcel Moolenaar struct l_ucontext uc; 7495002a60fSMarcel Moolenaar struct l_sigcontext *context; 750d6e029adSKonstantin Belousov sigset_t bmask; 7515002a60fSMarcel Moolenaar l_stack_t *lss; 752206a5d3aSIan Dowse stack_t ss; 7531d062e2bSDag-Erling Smørgrav struct trapframe *regs; 75479363394SAndrew Gallatin int eflags; 7559104847fSDavid Xu ksiginfo_t ksi; 75679363394SAndrew Gallatin 757b40ce416SJulian Elischer regs = td->td_frame; 75879363394SAndrew Gallatin 75979363394SAndrew Gallatin #ifdef DEBUG 76024593369SJonathan Lemon if (ldebug(rt_sigreturn)) 76124593369SJonathan Lemon printf(ARGS(rt_sigreturn, "%p"), (void *)args->ucp); 76279363394SAndrew Gallatin #endif 76379363394SAndrew Gallatin /* 764cc6ca9b3SMarcel Moolenaar * The trampoline code hands us the ucontext. 76579363394SAndrew Gallatin * It is unsafe to keep track of it ourselves, in the event that a 76679363394SAndrew Gallatin * program jumps out of a signal handler. 76779363394SAndrew Gallatin */ 7684b7ef73dSDag-Erling Smørgrav if (copyin(args->ucp, &uc, sizeof(uc)) != 0) 76979363394SAndrew Gallatin return (EFAULT); 77079363394SAndrew Gallatin 77179363394SAndrew Gallatin context = &uc.uc_mcontext; 77279363394SAndrew Gallatin 77379363394SAndrew Gallatin /* 77479363394SAndrew Gallatin * Check for security violations. 77579363394SAndrew Gallatin */ 77679363394SAndrew Gallatin #define EFLAGS_SECURE(ef, oef) ((((ef) ^ (oef)) & ~PSL_USERCHANGE) == 0) 77779363394SAndrew Gallatin eflags = context->sc_eflags; 7783d271aaaSEd Maste if (!EFLAGS_SECURE(eflags, regs->tf_eflags)) 77979363394SAndrew Gallatin return (EINVAL); 78079363394SAndrew Gallatin 78179363394SAndrew Gallatin /* 78279363394SAndrew Gallatin * Don't allow users to load a valid privileged %cs. Let the 78379363394SAndrew Gallatin * hardware check for invalid selectors, excess privilege in 78479363394SAndrew Gallatin * other selectors, invalid %eip's and invalid %esp's. 78579363394SAndrew Gallatin */ 78679363394SAndrew Gallatin #define CS_SECURE(cs) (ISPL(cs) == SEL_UPL) 78779363394SAndrew Gallatin if (!CS_SECURE(context->sc_cs)) { 7889104847fSDavid Xu ksiginfo_init_trap(&ksi); 7899104847fSDavid Xu ksi.ksi_signo = SIGBUS; 7909104847fSDavid Xu ksi.ksi_code = BUS_OBJERR; 7919104847fSDavid Xu ksi.ksi_trapno = T_PROTFLT; 7929104847fSDavid Xu ksi.ksi_addr = (void *)regs->tf_eip; 7939104847fSDavid Xu trapsignal(td, &ksi); 79479363394SAndrew Gallatin return (EINVAL); 79579363394SAndrew Gallatin } 79679363394SAndrew Gallatin 797d6e029adSKonstantin Belousov linux_to_bsd_sigset(&uc.uc_sigmask, &bmask); 798d6e029adSKonstantin Belousov kern_sigprocmask(td, SIG_SETMASK, &bmask, NULL, 0); 79979363394SAndrew Gallatin 80079363394SAndrew Gallatin /* 801cc6ca9b3SMarcel Moolenaar * Restore signal context 80279363394SAndrew Gallatin */ 80379363394SAndrew Gallatin /* %gs was restored by the trampoline. */ 80479363394SAndrew Gallatin regs->tf_fs = context->sc_fs; 80579363394SAndrew Gallatin regs->tf_es = context->sc_es; 80679363394SAndrew Gallatin regs->tf_ds = context->sc_ds; 80779363394SAndrew Gallatin regs->tf_edi = context->sc_edi; 80879363394SAndrew Gallatin regs->tf_esi = context->sc_esi; 80979363394SAndrew Gallatin regs->tf_ebp = context->sc_ebp; 81079363394SAndrew Gallatin regs->tf_ebx = context->sc_ebx; 81179363394SAndrew Gallatin regs->tf_edx = context->sc_edx; 81279363394SAndrew Gallatin regs->tf_ecx = context->sc_ecx; 81379363394SAndrew Gallatin regs->tf_eax = context->sc_eax; 81479363394SAndrew Gallatin regs->tf_eip = context->sc_eip; 81579363394SAndrew Gallatin regs->tf_cs = context->sc_cs; 81679363394SAndrew Gallatin regs->tf_eflags = eflags; 81779363394SAndrew Gallatin regs->tf_esp = context->sc_esp_at_signal; 81879363394SAndrew Gallatin regs->tf_ss = context->sc_ss; 81979363394SAndrew Gallatin 82079363394SAndrew Gallatin /* 82179363394SAndrew Gallatin * call sigaltstack & ignore results.. 82279363394SAndrew Gallatin */ 82379363394SAndrew Gallatin lss = &uc.uc_stack; 824206a5d3aSIan Dowse ss.ss_sp = lss->ss_sp; 825206a5d3aSIan Dowse ss.ss_size = lss->ss_size; 826206a5d3aSIan Dowse ss.ss_flags = linux_to_bsd_sigaltstack(lss->ss_flags); 82779363394SAndrew Gallatin 82879363394SAndrew Gallatin #ifdef DEBUG 82924593369SJonathan Lemon if (ldebug(rt_sigreturn)) 83024593369SJonathan Lemon printf(LMSG("rt_sigret flags: 0x%x, sp: %p, ss: 0x%x, mask: 0x%x"), 831206a5d3aSIan Dowse ss.ss_flags, ss.ss_sp, ss.ss_size, context->sc_mask); 83279363394SAndrew Gallatin #endif 833206a5d3aSIan Dowse (void)kern_sigaltstack(td, &ss, NULL); 83479363394SAndrew Gallatin 83579363394SAndrew Gallatin return (EJUSTRETURN); 83679363394SAndrew Gallatin } 83779363394SAndrew Gallatin 838afe1a688SKonstantin Belousov static int 839afe1a688SKonstantin Belousov linux_fetch_syscall_args(struct thread *td, struct syscall_args *sa) 840d66a5066SPeter Wemm { 841afe1a688SKonstantin Belousov struct proc *p; 842afe1a688SKonstantin Belousov struct trapframe *frame; 843afe1a688SKonstantin Belousov 844afe1a688SKonstantin Belousov p = td->td_proc; 845afe1a688SKonstantin Belousov frame = td->td_frame; 846afe1a688SKonstantin Belousov 847afe1a688SKonstantin Belousov sa->code = frame->tf_eax; 848afe1a688SKonstantin Belousov sa->args[0] = frame->tf_ebx; 849afe1a688SKonstantin Belousov sa->args[1] = frame->tf_ecx; 850afe1a688SKonstantin Belousov sa->args[2] = frame->tf_edx; 851afe1a688SKonstantin Belousov sa->args[3] = frame->tf_esi; 852afe1a688SKonstantin Belousov sa->args[4] = frame->tf_edi; 853afe1a688SKonstantin Belousov sa->args[5] = frame->tf_ebp; /* Unconfirmed */ 854afe1a688SKonstantin Belousov 855afe1a688SKonstantin Belousov if (sa->code >= p->p_sysent->sv_size) 856afe1a688SKonstantin Belousov sa->callp = &p->p_sysent->sv_table[0]; 857afe1a688SKonstantin Belousov else 858afe1a688SKonstantin Belousov sa->callp = &p->p_sysent->sv_table[sa->code]; 859afe1a688SKonstantin Belousov sa->narg = sa->callp->sy_narg; 860afe1a688SKonstantin Belousov 861afe1a688SKonstantin Belousov td->td_retval[0] = 0; 862afe1a688SKonstantin Belousov td->td_retval[1] = frame->tf_edx; 863afe1a688SKonstantin Belousov 864afe1a688SKonstantin Belousov return (0); 865d66a5066SPeter Wemm } 866d66a5066SPeter Wemm 867d323ddf3SMatthew Dillon /* 868d323ddf3SMatthew Dillon * If a linux binary is exec'ing something, try this image activator 869d323ddf3SMatthew Dillon * first. We override standard shell script execution in order to 870d323ddf3SMatthew Dillon * be able to modify the interpreter path. We only do this if a linux 871d323ddf3SMatthew Dillon * binary is doing the exec, so we do not create an EXEC module for it. 872d323ddf3SMatthew Dillon */ 87389c9a483SAlfred Perlstein static int exec_linux_imgact_try(struct image_params *iparams); 874d323ddf3SMatthew Dillon 875d323ddf3SMatthew Dillon static int 876b07cd97eSMark Murray exec_linux_imgact_try(struct image_params *imgp) 877d323ddf3SMatthew Dillon { 878d323ddf3SMatthew Dillon const char *head = (const char *)imgp->image_header; 8790311233eSJohn Baldwin char *rpath; 880a14a9498SAlan Cox int error = -1; 881d323ddf3SMatthew Dillon 882d323ddf3SMatthew Dillon /* 883d323ddf3SMatthew Dillon * The interpreter for shell scripts run from a linux binary needs 884d323ddf3SMatthew Dillon * to be located in /compat/linux if possible in order to recursively 885d323ddf3SMatthew Dillon * maintain linux path emulation. 886d323ddf3SMatthew Dillon */ 887d323ddf3SMatthew Dillon if (((const short *)head)[0] == SHELLMAGIC) { 888d323ddf3SMatthew Dillon /* 889d323ddf3SMatthew Dillon * Run our normal shell image activator. If it succeeds attempt 890d323ddf3SMatthew Dillon * to use the alternate path for the interpreter. If an alternate 891d323ddf3SMatthew Dillon * path is found, use our stringspace to store it. 892d323ddf3SMatthew Dillon */ 893d323ddf3SMatthew Dillon if ((error = exec_shell_imgact(imgp)) == 0) { 8940311233eSJohn Baldwin linux_emul_convpath(FIRST_THREAD_IN_PROC(imgp->proc), 89548b05c3fSKonstantin Belousov imgp->interpreter_name, UIO_SYSSPACE, &rpath, 0, AT_FDCWD); 896a14a9498SAlan Cox if (rpath != NULL) 897a14a9498SAlan Cox imgp->args->fname_buf = 898a14a9498SAlan Cox imgp->interpreter_name = rpath; 899d323ddf3SMatthew Dillon } 900d323ddf3SMatthew Dillon } 901d323ddf3SMatthew Dillon return (error); 902d323ddf3SMatthew Dillon } 903d323ddf3SMatthew Dillon 904598d45beSMatthew N. Dodd /* 905598d45beSMatthew N. Dodd * exec_setregs may initialize some registers differently than Linux 906598d45beSMatthew N. Dodd * does, thus potentially confusing Linux binaries. If necessary, we 907598d45beSMatthew N. Dodd * override the exec_setregs default(s) here. 908598d45beSMatthew N. Dodd */ 909598d45beSMatthew N. Dodd static void 910a107d8aaSNathan Whitehorn exec_linux_setregs(struct thread *td, struct image_params *imgp, u_long stack) 911598d45beSMatthew N. Dodd { 912598d45beSMatthew N. Dodd struct pcb *pcb = td->td_pcb; 913598d45beSMatthew N. Dodd 914a107d8aaSNathan Whitehorn exec_setregs(td, imgp, stack); 915598d45beSMatthew N. Dodd 916598d45beSMatthew N. Dodd /* Linux sets %gs to 0, we default to _udatasel */ 9172ee8325fSJohn Baldwin pcb->pcb_gs = 0; 9182ee8325fSJohn Baldwin load_gs(0); 9192a51b9b0SDavid Schultz 9202ee8325fSJohn Baldwin pcb->pcb_initial_npxcw = __LINUX_NPXCW__; 921598d45beSMatthew N. Dodd } 922598d45beSMatthew N. Dodd 9234d7c2e8aSDmitry Chagin static void 9244d7c2e8aSDmitry Chagin linux_get_machine(const char **dst) 9254d7c2e8aSDmitry Chagin { 9264d7c2e8aSDmitry Chagin 9274d7c2e8aSDmitry Chagin switch (cpu_class) { 9284d7c2e8aSDmitry Chagin case CPUCLASS_686: 9294d7c2e8aSDmitry Chagin *dst = "i686"; 9304d7c2e8aSDmitry Chagin break; 9314d7c2e8aSDmitry Chagin case CPUCLASS_586: 9324d7c2e8aSDmitry Chagin *dst = "i586"; 9334d7c2e8aSDmitry Chagin break; 9344d7c2e8aSDmitry Chagin case CPUCLASS_486: 9354d7c2e8aSDmitry Chagin *dst = "i486"; 9364d7c2e8aSDmitry Chagin break; 9374d7c2e8aSDmitry Chagin default: 9384d7c2e8aSDmitry Chagin *dst = "i386"; 9394d7c2e8aSDmitry Chagin } 9404d7c2e8aSDmitry Chagin } 9414d7c2e8aSDmitry Chagin 942d66a5066SPeter Wemm struct sysentvec linux_sysvec = { 943a8d403e1SKonstantin Belousov .sv_size = LINUX_SYS_MAXSYSCALL, 944a8d403e1SKonstantin Belousov .sv_table = linux_sysent, 945a8d403e1SKonstantin Belousov .sv_mask = 0, 946a8d403e1SKonstantin Belousov .sv_sigsize = LINUX_SIGTBLSZ, 947a8d403e1SKonstantin Belousov .sv_sigtbl = bsd_to_linux_signal, 948a8d403e1SKonstantin Belousov .sv_errsize = ELAST + 1, 949a8d403e1SKonstantin Belousov .sv_errtbl = bsd_to_linux_errno, 950a8d403e1SKonstantin Belousov .sv_transtrap = translate_traps, 951a8d403e1SKonstantin Belousov .sv_fixup = linux_fixup, 952a8d403e1SKonstantin Belousov .sv_sendsig = linux_sendsig, 953a8d403e1SKonstantin Belousov .sv_sigcode = linux_sigcode, 954a8d403e1SKonstantin Belousov .sv_szsigcode = &linux_szsigcode, 955afe1a688SKonstantin Belousov .sv_prepsyscall = NULL, 956a8d403e1SKonstantin Belousov .sv_name = "Linux a.out", 957a8d403e1SKonstantin Belousov .sv_coredump = NULL, 958a8d403e1SKonstantin Belousov .sv_imgact_try = exec_linux_imgact_try, 959a8d403e1SKonstantin Belousov .sv_minsigstksz = LINUX_MINSIGSTKSZ, 960a8d403e1SKonstantin Belousov .sv_pagesize = PAGE_SIZE, 961a8d403e1SKonstantin Belousov .sv_minuser = VM_MIN_ADDRESS, 962a8d403e1SKonstantin Belousov .sv_maxuser = VM_MAXUSER_ADDRESS, 9638f1e49a6SDmitry Chagin .sv_usrstack = LINUX_USRSTACK, 964a8d403e1SKonstantin Belousov .sv_psstrings = PS_STRINGS, 965a8d403e1SKonstantin Belousov .sv_stackprot = VM_PROT_ALL, 966a8d403e1SKonstantin Belousov .sv_copyout_strings = exec_copyout_strings, 967a8d403e1SKonstantin Belousov .sv_setregs = exec_linux_setregs, 968a8d403e1SKonstantin Belousov .sv_fixlimit = NULL, 969b4cf0e62SKonstantin Belousov .sv_maxssiz = NULL, 970afe1a688SKonstantin Belousov .sv_flags = SV_ABI_LINUX | SV_AOUT | SV_IA32 | SV_ILP32, 971afe1a688SKonstantin Belousov .sv_set_syscall_retval = cpu_set_syscall_retval, 972afe1a688SKonstantin Belousov .sv_fetch_syscall_args = linux_fetch_syscall_args, 973afe1a688SKonstantin Belousov .sv_syscallnames = NULL, 9748f1e49a6SDmitry Chagin .sv_shared_page_base = LINUX_SHAREDPAGE, 9758f1e49a6SDmitry Chagin .sv_shared_page_len = PAGE_SIZE, 976e5d81ef1SDmitry Chagin .sv_schedtail = linux_schedtail, 97781338031SDmitry Chagin .sv_thread_detach = linux_thread_detach, 978d66a5066SPeter Wemm }; 9798f1e49a6SDmitry Chagin INIT_SYSENTVEC(aout_sysvec, &linux_sysvec); 980e1743d02SSøren Schmidt 981e1743d02SSøren Schmidt struct sysentvec elf_linux_sysvec = { 982a8d403e1SKonstantin Belousov .sv_size = LINUX_SYS_MAXSYSCALL, 983a8d403e1SKonstantin Belousov .sv_table = linux_sysent, 984a8d403e1SKonstantin Belousov .sv_mask = 0, 985a8d403e1SKonstantin Belousov .sv_sigsize = LINUX_SIGTBLSZ, 986a8d403e1SKonstantin Belousov .sv_sigtbl = bsd_to_linux_signal, 987a8d403e1SKonstantin Belousov .sv_errsize = ELAST + 1, 988a8d403e1SKonstantin Belousov .sv_errtbl = bsd_to_linux_errno, 989a8d403e1SKonstantin Belousov .sv_transtrap = translate_traps, 990a8d403e1SKonstantin Belousov .sv_fixup = elf_linux_fixup, 991a8d403e1SKonstantin Belousov .sv_sendsig = linux_sendsig, 992a8d403e1SKonstantin Belousov .sv_sigcode = linux_sigcode, 993a8d403e1SKonstantin Belousov .sv_szsigcode = &linux_szsigcode, 994afe1a688SKonstantin Belousov .sv_prepsyscall = NULL, 995a8d403e1SKonstantin Belousov .sv_name = "Linux ELF", 996a8d403e1SKonstantin Belousov .sv_coredump = elf32_coredump, 997a8d403e1SKonstantin Belousov .sv_imgact_try = exec_linux_imgact_try, 998a8d403e1SKonstantin Belousov .sv_minsigstksz = LINUX_MINSIGSTKSZ, 999a8d403e1SKonstantin Belousov .sv_pagesize = PAGE_SIZE, 1000a8d403e1SKonstantin Belousov .sv_minuser = VM_MIN_ADDRESS, 1001a8d403e1SKonstantin Belousov .sv_maxuser = VM_MAXUSER_ADDRESS, 10028f1e49a6SDmitry Chagin .sv_usrstack = LINUX_USRSTACK, 10038f1e49a6SDmitry Chagin .sv_psstrings = LINUX_PS_STRINGS, 1004a8d403e1SKonstantin Belousov .sv_stackprot = VM_PROT_ALL, 10054d7c2e8aSDmitry Chagin .sv_copyout_strings = linux_copyout_strings, 1006a8d403e1SKonstantin Belousov .sv_setregs = exec_linux_setregs, 1007a8d403e1SKonstantin Belousov .sv_fixlimit = NULL, 1008b4cf0e62SKonstantin Belousov .sv_maxssiz = NULL, 10098f1e49a6SDmitry Chagin .sv_flags = SV_ABI_LINUX | SV_IA32 | SV_ILP32 | SV_SHP, 1010afe1a688SKonstantin Belousov .sv_set_syscall_retval = cpu_set_syscall_retval, 1011afe1a688SKonstantin Belousov .sv_fetch_syscall_args = linux_fetch_syscall_args, 1012afe1a688SKonstantin Belousov .sv_syscallnames = NULL, 10138f1e49a6SDmitry Chagin .sv_shared_page_base = LINUX_SHAREDPAGE, 10148f1e49a6SDmitry Chagin .sv_shared_page_len = PAGE_SIZE, 1015e5d81ef1SDmitry Chagin .sv_schedtail = linux_schedtail, 101681338031SDmitry Chagin .sv_thread_detach = linux_thread_detach, 1017e1743d02SSøren Schmidt }; 10188f1e49a6SDmitry Chagin INIT_SYSENTVEC(elf_sysvec, &elf_linux_sysvec); 1019e1743d02SSøren Schmidt 102089ffc202SBjoern A. Zeeb static char GNU_ABI_VENDOR[] = "GNU"; 102189ffc202SBjoern A. Zeeb static int GNULINUX_ABI_DESC = 0; 102289ffc202SBjoern A. Zeeb 102389ffc202SBjoern A. Zeeb static boolean_t 102489ffc202SBjoern A. Zeeb linux_trans_osrel(const Elf_Note *note, int32_t *osrel) 102589ffc202SBjoern A. Zeeb { 102689ffc202SBjoern A. Zeeb const Elf32_Word *desc; 102789ffc202SBjoern A. Zeeb uintptr_t p; 102889ffc202SBjoern A. Zeeb 102989ffc202SBjoern A. Zeeb p = (uintptr_t)(note + 1); 103089ffc202SBjoern A. Zeeb p += roundup2(note->n_namesz, sizeof(Elf32_Addr)); 103189ffc202SBjoern A. Zeeb 103289ffc202SBjoern A. Zeeb desc = (const Elf32_Word *)p; 103389ffc202SBjoern A. Zeeb if (desc[0] != GNULINUX_ABI_DESC) 103489ffc202SBjoern A. Zeeb return (FALSE); 103589ffc202SBjoern A. Zeeb 103689ffc202SBjoern A. Zeeb /* 103789ffc202SBjoern A. Zeeb * For linux we encode osrel as follows (see linux_mib.c): 103889ffc202SBjoern A. Zeeb * VVVMMMIII (version, major, minor), see linux_mib.c. 103989ffc202SBjoern A. Zeeb */ 104089ffc202SBjoern A. Zeeb *osrel = desc[1] * 1000000 + desc[2] * 1000 + desc[3]; 104189ffc202SBjoern A. Zeeb 104289ffc202SBjoern A. Zeeb return (TRUE); 104389ffc202SBjoern A. Zeeb } 104432c01de2SDmitry Chagin 104532c01de2SDmitry Chagin static Elf_Brandnote linux_brandnote = { 104689ffc202SBjoern A. Zeeb .hdr.n_namesz = sizeof(GNU_ABI_VENDOR), 104789ffc202SBjoern A. Zeeb .hdr.n_descsz = 16, /* XXX at least 16 */ 104832c01de2SDmitry Chagin .hdr.n_type = 1, 104989ffc202SBjoern A. Zeeb .vendor = GNU_ABI_VENDOR, 105089ffc202SBjoern A. Zeeb .flags = BN_TRANSLATE_OSREL, 105189ffc202SBjoern A. Zeeb .trans_osrel = linux_trans_osrel 105232c01de2SDmitry Chagin }; 105332c01de2SDmitry Chagin 1054514058dcSAlexander Langer static Elf32_Brandinfo linux_brand = { 1055a8d403e1SKonstantin Belousov .brand = ELFOSABI_LINUX, 1056a8d403e1SKonstantin Belousov .machine = EM_386, 1057a8d403e1SKonstantin Belousov .compat_3_brand = "Linux", 1058a8d403e1SKonstantin Belousov .emul_path = "/compat/linux", 1059a8d403e1SKonstantin Belousov .interp_path = "/lib/ld-linux.so.1", 1060a8d403e1SKonstantin Belousov .sysvec = &elf_linux_sysvec, 1061a8d403e1SKonstantin Belousov .interp_newpath = NULL, 106232c01de2SDmitry Chagin .brand_note = &linux_brandnote, 10632dedc128SDmitry Chagin .flags = BI_CAN_EXEC_DYN | BI_BRAND_NOTE 10645cf588ebSPeter Wemm }; 10655cf588ebSPeter Wemm 1066514058dcSAlexander Langer static Elf32_Brandinfo linux_glibc2brand = { 1067a8d403e1SKonstantin Belousov .brand = ELFOSABI_LINUX, 1068a8d403e1SKonstantin Belousov .machine = EM_386, 1069a8d403e1SKonstantin Belousov .compat_3_brand = "Linux", 1070a8d403e1SKonstantin Belousov .emul_path = "/compat/linux", 1071a8d403e1SKonstantin Belousov .interp_path = "/lib/ld-linux.so.2", 1072a8d403e1SKonstantin Belousov .sysvec = &elf_linux_sysvec, 1073a8d403e1SKonstantin Belousov .interp_newpath = NULL, 107432c01de2SDmitry Chagin .brand_note = &linux_brandnote, 10752dedc128SDmitry Chagin .flags = BI_CAN_EXEC_DYN | BI_BRAND_NOTE 10764e138a28SMike Smith }; 10774e138a28SMike Smith 1078514058dcSAlexander Langer Elf32_Brandinfo *linux_brandlist[] = { 1079514058dcSAlexander Langer &linux_brand, 1080514058dcSAlexander Langer &linux_glibc2brand, 1081514058dcSAlexander Langer NULL 1082514058dcSAlexander Langer }; 1083514058dcSAlexander Langer 1084aa855a59SPeter Wemm static int 1085c25ded31SBruce Evans linux_elf_modevent(module_t mod, int type, void *data) 1086d30ea4f5SPeter Wemm { 1087514058dcSAlexander Langer Elf32_Brandinfo **brandinfo; 1088514058dcSAlexander Langer int error; 1089f41325dbSPeter Wemm struct linux_ioctl_handler **lihp; 1090060e4882SDoug Ambrisko struct linux_device_handler **ldhp; 1091514058dcSAlexander Langer 1092514058dcSAlexander Langer error = 0; 1093514058dcSAlexander Langer 1094aa855a59SPeter Wemm switch(type) { 1095aa855a59SPeter Wemm case MOD_LOAD: 1096aa855a59SPeter Wemm for (brandinfo = &linux_brandlist[0]; *brandinfo != NULL; 1097aa855a59SPeter Wemm ++brandinfo) 10983ebc1248SPeter Wemm if (elf32_insert_brand_entry(*brandinfo) < 0) 1099aa855a59SPeter Wemm error = EINVAL; 1100466b14d7SMarcel Moolenaar if (error == 0) { 1101f41325dbSPeter Wemm SET_FOREACH(lihp, linux_ioctl_handler_set) 1102f41325dbSPeter Wemm linux_ioctl_register_handler(*lihp); 1103060e4882SDoug Ambrisko SET_FOREACH(ldhp, linux_device_handler_set) 1104060e4882SDoug Ambrisko linux_device_register_handler(*ldhp); 11059b44bfc5SAlexander Leidinger LIST_INIT(&futex_list); 110679262bf1SDmitry Chagin mtx_init(&futex_mtx, "ftllk", NULL, MTX_DEF); 11079b44bfc5SAlexander Leidinger linux_exit_tag = EVENTHANDLER_REGISTER(process_exit, linux_proc_exit, 11089b44bfc5SAlexander Leidinger NULL, 1000); 11099b44bfc5SAlexander Leidinger linux_exec_tag = EVENTHANDLER_REGISTER(process_exec, linux_proc_exec, 11109b44bfc5SAlexander Leidinger NULL, 1000); 111181338031SDmitry Chagin linux_thread_dtor_tag = EVENTHANDLER_REGISTER(thread_dtor, 111281338031SDmitry Chagin linux_thread_dtor, NULL, EVENTHANDLER_PRI_ANY); 11134d7c2e8aSDmitry Chagin linux_get_machine(&linux_platform); 11144d7c2e8aSDmitry Chagin linux_szplatform = roundup(strlen(linux_platform) + 1, 11154d7c2e8aSDmitry Chagin sizeof(char *)); 11167ae27ff4SJamie Gritton linux_osd_jail_register(); 11171ca16454SDmitry Chagin stclohz = (stathz ? stathz : hz); 111843bef515SMarcel Moolenaar if (bootverbose) 1119466b14d7SMarcel Moolenaar printf("Linux ELF exec handler installed\n"); 1120466b14d7SMarcel Moolenaar } else 1121466b14d7SMarcel Moolenaar printf("cannot insert Linux ELF brand handler\n"); 1122aa855a59SPeter Wemm break; 1123aa855a59SPeter Wemm case MOD_UNLOAD: 1124aa855a59SPeter Wemm for (brandinfo = &linux_brandlist[0]; *brandinfo != NULL; 1125aa855a59SPeter Wemm ++brandinfo) 11263ebc1248SPeter Wemm if (elf32_brand_inuse(*brandinfo)) 1127d2758342SMark Newton error = EBUSY; 1128d2758342SMark Newton if (error == 0) { 1129d2758342SMark Newton for (brandinfo = &linux_brandlist[0]; 1130d2758342SMark Newton *brandinfo != NULL; ++brandinfo) 11313ebc1248SPeter Wemm if (elf32_remove_brand_entry(*brandinfo) < 0) 1132aa855a59SPeter Wemm error = EINVAL; 1133d2758342SMark Newton } 1134466b14d7SMarcel Moolenaar if (error == 0) { 1135f41325dbSPeter Wemm SET_FOREACH(lihp, linux_ioctl_handler_set) 1136f41325dbSPeter Wemm linux_ioctl_unregister_handler(*lihp); 1137060e4882SDoug Ambrisko SET_FOREACH(ldhp, linux_device_handler_set) 1138060e4882SDoug Ambrisko linux_device_unregister_handler(*ldhp); 113979262bf1SDmitry Chagin mtx_destroy(&futex_mtx); 11409b44bfc5SAlexander Leidinger EVENTHANDLER_DEREGISTER(process_exit, linux_exit_tag); 11419b44bfc5SAlexander Leidinger EVENTHANDLER_DEREGISTER(process_exec, linux_exec_tag); 114281338031SDmitry Chagin EVENTHANDLER_DEREGISTER(thread_dtor, linux_thread_dtor_tag); 11437ae27ff4SJamie Gritton linux_osd_jail_deregister(); 1144466b14d7SMarcel Moolenaar if (bootverbose) 1145466b14d7SMarcel Moolenaar printf("Linux ELF exec handler removed\n"); 1146466b14d7SMarcel Moolenaar } else 1147aa855a59SPeter Wemm printf("Could not deinstall ELF interpreter entry\n"); 1148aa855a59SPeter Wemm break; 1149aa855a59SPeter Wemm default: 1150*af682d48SDmitry Chagin return (EOPNOTSUPP); 1151d30ea4f5SPeter Wemm } 1152*af682d48SDmitry Chagin return (error); 1153aa855a59SPeter Wemm } 1154466b14d7SMarcel Moolenaar 1155aa855a59SPeter Wemm static moduledata_t linux_elf_mod = { 1156aa855a59SPeter Wemm "linuxelf", 1157aa855a59SPeter Wemm linux_elf_modevent, 11589823d527SKevin Lo 0 1159aa855a59SPeter Wemm }; 1160466b14d7SMarcel Moolenaar 116178ae4338SKonstantin Belousov DECLARE_MODULE_TIED(linuxelf, linux_elf_mod, SI_SUB_EXEC, SI_ORDER_ANY); 1162