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> 74*bdc37934SDmitry Chagin #include <compat/linux/linux_vdso.h> 75e1743d02SSøren Schmidt 761d91482dSPeter Wemm MODULE_VERSION(linux, 1); 771d91482dSPeter Wemm 7843bef515SMarcel Moolenaar MALLOC_DEFINE(M_LINUX, "linux", "Linux mode structures"); 7943bef515SMarcel Moolenaar 80d323ddf3SMatthew Dillon #if BYTE_ORDER == LITTLE_ENDIAN 81d323ddf3SMatthew Dillon #define SHELLMAGIC 0x2123 /* #! */ 82d323ddf3SMatthew Dillon #else 83d323ddf3SMatthew Dillon #define SHELLMAGIC 0x2321 84d323ddf3SMatthew Dillon #endif 85d323ddf3SMatthew Dillon 86e061a6caSMarcel Moolenaar /* 87e061a6caSMarcel Moolenaar * Allow the sendsig functions to use the ldebug() facility 88e061a6caSMarcel Moolenaar * even though they are not syscalls themselves. Map them 89e061a6caSMarcel Moolenaar * to syscall 0. This is slightly less bogus than using 90e061a6caSMarcel Moolenaar * ldebug(sigreturn). 91e061a6caSMarcel Moolenaar */ 92e061a6caSMarcel Moolenaar #define LINUX_SYS_linux_rt_sendsig 0 93e061a6caSMarcel Moolenaar #define LINUX_SYS_linux_sendsig 0 94e061a6caSMarcel Moolenaar 958f1e49a6SDmitry Chagin #define LINUX_PS_STRINGS (LINUX_USRSTACK - sizeof(struct ps_strings)) 968f1e49a6SDmitry Chagin 97*bdc37934SDmitry Chagin static int linux_szsigcode; 98*bdc37934SDmitry Chagin static vm_object_t linux_shared_page_obj; 99*bdc37934SDmitry Chagin static char *linux_shared_page_mapping; 100*bdc37934SDmitry Chagin extern char _binary_linux_locore_o_start; 101*bdc37934SDmitry Chagin extern char _binary_linux_locore_o_end; 10243bef515SMarcel Moolenaar 10343bef515SMarcel Moolenaar extern struct sysent linux_sysent[LINUX_SYS_MAXSYSCALL]; 10443bef515SMarcel Moolenaar 105f41325dbSPeter Wemm SET_DECLARE(linux_ioctl_handler_set, struct linux_ioctl_handler); 106060e4882SDoug Ambrisko SET_DECLARE(linux_device_handler_set, struct linux_device_handler); 10743bef515SMarcel Moolenaar 10889c9a483SAlfred Perlstein static int linux_fixup(register_t **stack_base, 10989c9a483SAlfred Perlstein struct image_params *iparams); 11089c9a483SAlfred Perlstein static int elf_linux_fixup(register_t **stack_base, 11189c9a483SAlfred Perlstein struct image_params *iparams); 1129104847fSDavid Xu static void linux_sendsig(sig_t catcher, ksiginfo_t *ksi, sigset_t *mask); 113a107d8aaSNathan Whitehorn static void exec_linux_setregs(struct thread *td, 114a107d8aaSNathan Whitehorn struct image_params *imgp, u_long stack); 1154d7c2e8aSDmitry Chagin static register_t *linux_copyout_strings(struct image_params *imgp); 11689ffc202SBjoern A. Zeeb static boolean_t linux_trans_osrel(const Elf_Note *note, int32_t *osrel); 117*bdc37934SDmitry Chagin static void linux_vdso_install(void *param); 118*bdc37934SDmitry Chagin static void linux_vdso_deinstall(void *param); 1194d7c2e8aSDmitry Chagin 1204d7c2e8aSDmitry Chagin static int linux_szplatform; 1214d7c2e8aSDmitry Chagin const char *linux_platform; 122d66a5066SPeter Wemm 1239b44bfc5SAlexander Leidinger static eventhandler_tag linux_exit_tag; 1249b44bfc5SAlexander Leidinger static eventhandler_tag linux_exec_tag; 12581338031SDmitry Chagin static eventhandler_tag linux_thread_dtor_tag; 1269b44bfc5SAlexander Leidinger 127d66a5066SPeter Wemm /* 128d66a5066SPeter Wemm * Linux syscalls return negative errno's, we do positive and map them 12950e422f0SAlexander Leidinger * Reference: 13050e422f0SAlexander Leidinger * FreeBSD: src/sys/sys/errno.h 13150e422f0SAlexander Leidinger * Linux: linux-2.6.17.8/include/asm-generic/errno-base.h 13250e422f0SAlexander Leidinger * linux-2.6.17.8/include/asm-generic/errno.h 133d66a5066SPeter Wemm */ 13485f118c8SDmitrij Tejblum static int bsd_to_linux_errno[ELAST + 1] = { 135d66a5066SPeter Wemm -0, -1, -2, -3, -4, -5, -6, -7, -8, -9, 136d66a5066SPeter Wemm -10, -35, -12, -13, -14, -15, -16, -17, -18, -19, 137d66a5066SPeter Wemm -20, -21, -22, -23, -24, -25, -26, -27, -28, -29, 138d66a5066SPeter Wemm -30, -31, -32, -33, -34, -11,-115,-114, -88, -89, 139d66a5066SPeter Wemm -90, -91, -92, -93, -94, -95, -96, -97, -98, -99, 140d66a5066SPeter Wemm -100,-101,-102,-103,-104,-105,-106,-107,-108,-109, 141d66a5066SPeter Wemm -110,-111, -40, -36,-112,-113, -39, -11, -87,-122, 142d66a5066SPeter Wemm -116, -66, -6, -6, -6, -6, -6, -37, -38, -9, 14350e422f0SAlexander Leidinger -6, -6, -43, -42, -75,-125, -84, -95, -16, -74, 14450e422f0SAlexander Leidinger -72, -67, -71 145d66a5066SPeter Wemm }; 146d66a5066SPeter Wemm 147956d3333SMarcel Moolenaar int bsd_to_linux_signal[LINUX_SIGTBLSZ] = { 148956d3333SMarcel Moolenaar LINUX_SIGHUP, LINUX_SIGINT, LINUX_SIGQUIT, LINUX_SIGILL, 149956d3333SMarcel Moolenaar LINUX_SIGTRAP, LINUX_SIGABRT, 0, LINUX_SIGFPE, 150ba873f4cSAlexander Kabaev LINUX_SIGKILL, LINUX_SIGBUS, LINUX_SIGSEGV, LINUX_SIGSYS, 151956d3333SMarcel Moolenaar LINUX_SIGPIPE, LINUX_SIGALRM, LINUX_SIGTERM, LINUX_SIGURG, 152956d3333SMarcel Moolenaar LINUX_SIGSTOP, LINUX_SIGTSTP, LINUX_SIGCONT, LINUX_SIGCHLD, 153956d3333SMarcel Moolenaar LINUX_SIGTTIN, LINUX_SIGTTOU, LINUX_SIGIO, LINUX_SIGXCPU, 154956d3333SMarcel Moolenaar LINUX_SIGXFSZ, LINUX_SIGVTALRM, LINUX_SIGPROF, LINUX_SIGWINCH, 155956d3333SMarcel Moolenaar 0, LINUX_SIGUSR1, LINUX_SIGUSR2 156d66a5066SPeter Wemm }; 157d66a5066SPeter Wemm 158956d3333SMarcel Moolenaar int linux_to_bsd_signal[LINUX_SIGTBLSZ] = { 159956d3333SMarcel Moolenaar SIGHUP, SIGINT, SIGQUIT, SIGILL, 160956d3333SMarcel Moolenaar SIGTRAP, SIGABRT, SIGBUS, SIGFPE, 161956d3333SMarcel Moolenaar SIGKILL, SIGUSR1, SIGSEGV, SIGUSR2, 162956d3333SMarcel Moolenaar SIGPIPE, SIGALRM, SIGTERM, SIGBUS, 163956d3333SMarcel Moolenaar SIGCHLD, SIGCONT, SIGSTOP, SIGTSTP, 164956d3333SMarcel Moolenaar SIGTTIN, SIGTTOU, SIGURG, SIGXCPU, 165956d3333SMarcel Moolenaar SIGXFSZ, SIGVTALRM, SIGPROF, SIGWINCH, 166ba873f4cSAlexander Kabaev SIGIO, SIGURG, SIGSYS 167d66a5066SPeter Wemm }; 168d66a5066SPeter Wemm 16927a828fcSPierre Beyssac #define LINUX_T_UNKNOWN 255 17027a828fcSPierre Beyssac static int _bsd_to_linux_trapcode[] = { 17127a828fcSPierre Beyssac LINUX_T_UNKNOWN, /* 0 */ 17227a828fcSPierre Beyssac 6, /* 1 T_PRIVINFLT */ 17327a828fcSPierre Beyssac LINUX_T_UNKNOWN, /* 2 */ 17427a828fcSPierre Beyssac 3, /* 3 T_BPTFLT */ 17527a828fcSPierre Beyssac LINUX_T_UNKNOWN, /* 4 */ 17627a828fcSPierre Beyssac LINUX_T_UNKNOWN, /* 5 */ 17727a828fcSPierre Beyssac 16, /* 6 T_ARITHTRAP */ 17827a828fcSPierre Beyssac 254, /* 7 T_ASTFLT */ 17927a828fcSPierre Beyssac LINUX_T_UNKNOWN, /* 8 */ 18027a828fcSPierre Beyssac 13, /* 9 T_PROTFLT */ 18127a828fcSPierre Beyssac 1, /* 10 T_TRCTRAP */ 18227a828fcSPierre Beyssac LINUX_T_UNKNOWN, /* 11 */ 18327a828fcSPierre Beyssac 14, /* 12 T_PAGEFLT */ 18427a828fcSPierre Beyssac LINUX_T_UNKNOWN, /* 13 */ 18527a828fcSPierre Beyssac 17, /* 14 T_ALIGNFLT */ 18627a828fcSPierre Beyssac LINUX_T_UNKNOWN, /* 15 */ 18727a828fcSPierre Beyssac LINUX_T_UNKNOWN, /* 16 */ 18827a828fcSPierre Beyssac LINUX_T_UNKNOWN, /* 17 */ 18927a828fcSPierre Beyssac 0, /* 18 T_DIVIDE */ 19027a828fcSPierre Beyssac 2, /* 19 T_NMI */ 19127a828fcSPierre Beyssac 4, /* 20 T_OFLOW */ 19227a828fcSPierre Beyssac 5, /* 21 T_BOUND */ 19327a828fcSPierre Beyssac 7, /* 22 T_DNA */ 19427a828fcSPierre Beyssac 8, /* 23 T_DOUBLEFLT */ 19527a828fcSPierre Beyssac 9, /* 24 T_FPOPFLT */ 19627a828fcSPierre Beyssac 10, /* 25 T_TSSFLT */ 19727a828fcSPierre Beyssac 11, /* 26 T_SEGNPFLT */ 19827a828fcSPierre Beyssac 12, /* 27 T_STKFLT */ 19927a828fcSPierre Beyssac 18, /* 28 T_MCHK */ 20027a828fcSPierre Beyssac 19, /* 29 T_XMMFLT */ 20127a828fcSPierre Beyssac 15 /* 30 T_RESERVED */ 20227a828fcSPierre Beyssac }; 20327a828fcSPierre Beyssac #define bsd_to_linux_trapcode(code) \ 20427a828fcSPierre Beyssac ((code)<sizeof(_bsd_to_linux_trapcode)/sizeof(*_bsd_to_linux_trapcode)? \ 20527a828fcSPierre Beyssac _bsd_to_linux_trapcode[(code)]: \ 20627a828fcSPierre Beyssac LINUX_T_UNKNOWN) 20727a828fcSPierre Beyssac 208*bdc37934SDmitry Chagin LINUX_VDSO_SYM_INTPTR(linux_sigcode); 209*bdc37934SDmitry Chagin LINUX_VDSO_SYM_INTPTR(linux_rt_sigcode); 210*bdc37934SDmitry Chagin LINUX_VDSO_SYM_INTPTR(linux_vsyscall); 211*bdc37934SDmitry Chagin 212288078beSEivind Eklund /* 213288078beSEivind Eklund * If FreeBSD & Linux have a difference of opinion about what a trap 214288078beSEivind Eklund * means, deal with it here. 215356861dbSMatthew Dillon * 216356861dbSMatthew Dillon * MPSAFE 217288078beSEivind Eklund */ 218288078beSEivind Eklund static int 219288078beSEivind Eklund translate_traps(int signal, int trap_code) 220288078beSEivind Eklund { 221d563a53aSEivind Eklund if (signal != SIGBUS) 222af682d48SDmitry Chagin return (signal); 223288078beSEivind Eklund switch (trap_code) { 224288078beSEivind Eklund case T_PROTFLT: 225288078beSEivind Eklund case T_TSSFLT: 226288078beSEivind Eklund case T_DOUBLEFLT: 227288078beSEivind Eklund case T_PAGEFLT: 228af682d48SDmitry Chagin return (SIGSEGV); 229288078beSEivind Eklund default: 230af682d48SDmitry Chagin return (signal); 231288078beSEivind Eklund } 232288078beSEivind Eklund } 233288078beSEivind Eklund 234303b270bSEivind Eklund static int 235654f6be1SBruce Evans linux_fixup(register_t **stack_base, struct image_params *imgp) 236d66a5066SPeter Wemm { 237654f6be1SBruce Evans register_t *argv, *envp; 238d66a5066SPeter Wemm 239d66a5066SPeter Wemm argv = *stack_base; 240610ecfe0SMaxim Sobolev envp = *stack_base + (imgp->args->argc + 1); 241d66a5066SPeter Wemm (*stack_base)--; 242aa103453SKonstantin Belousov suword(*stack_base, (intptr_t)(void *)envp); 243d66a5066SPeter Wemm (*stack_base)--; 244aa103453SKonstantin Belousov suword(*stack_base, (intptr_t)(void *)argv); 245d66a5066SPeter Wemm (*stack_base)--; 246aa103453SKonstantin Belousov suword(*stack_base, imgp->args->argc); 2474d7c2e8aSDmitry Chagin return (0); 248d66a5066SPeter Wemm } 249d66a5066SPeter Wemm 250303b270bSEivind Eklund static int 251654f6be1SBruce Evans elf_linux_fixup(register_t **stack_base, struct image_params *imgp) 252e1743d02SSøren Schmidt { 2534d7c2e8aSDmitry Chagin struct proc *p; 25443cf129cSJohn Baldwin Elf32_Auxargs *args; 2554d7c2e8aSDmitry Chagin Elf32_Addr *uplatform; 2564d7c2e8aSDmitry Chagin struct ps_strings *arginfo; 257654f6be1SBruce Evans register_t *pos; 258d66a5066SPeter Wemm 2596617724cSJeff Roberson KASSERT(curthread->td_proc == imgp->proc, 26043cf129cSJohn Baldwin ("unsafe elf_linux_fixup(), should be curproc")); 2614d7c2e8aSDmitry Chagin 2624d7c2e8aSDmitry Chagin p = imgp->proc; 2634d7c2e8aSDmitry Chagin arginfo = (struct ps_strings *)p->p_sysent->sv_psstrings; 264acface68SDmitry Chagin uplatform = (Elf32_Addr *)((caddr_t)arginfo - linux_szplatform); 26543cf129cSJohn Baldwin args = (Elf32_Auxargs *)imgp->auxargs; 266610ecfe0SMaxim Sobolev pos = *stack_base + (imgp->args->argc + imgp->args->envc + 2); 267e1743d02SSøren Schmidt 268*bdc37934SDmitry Chagin AUXARGS_ENTRY(pos, LINUX_AT_SYSINFO_EHDR, 269*bdc37934SDmitry Chagin imgp->proc->p_sysent->sv_shared_page_base); 270*bdc37934SDmitry Chagin AUXARGS_ENTRY(pos, LINUX_AT_SYSINFO, linux_vsyscall); 2714d7c2e8aSDmitry Chagin AUXARGS_ENTRY(pos, LINUX_AT_HWCAP, cpu_feature); 2728d30f381SDmitry Chagin 2738d30f381SDmitry Chagin /* 2748d30f381SDmitry Chagin * Do not export AT_CLKTCK when emulating Linux kernel prior to 2.4.0, 2758d30f381SDmitry Chagin * as it has appeared in the 2.4.0-rc7 first time. 2768d30f381SDmitry Chagin * Being exported, AT_CLKTCK is returned by sysconf(_SC_CLK_TCK), 2778d30f381SDmitry Chagin * glibc falls back to the hard-coded CLK_TCK value when aux entry 2788d30f381SDmitry Chagin * is not present. 2798d30f381SDmitry Chagin * Also see linux_times() implementation. 2808d30f381SDmitry Chagin */ 2818d30f381SDmitry Chagin if (linux_kernver(curthread) >= LINUX_KERNVER_2004000) 2821ca16454SDmitry Chagin AUXARGS_ENTRY(pos, LINUX_AT_CLKTCK, stclohz); 283e1743d02SSøren Schmidt AUXARGS_ENTRY(pos, AT_PHDR, args->phdr); 284e1743d02SSøren Schmidt AUXARGS_ENTRY(pos, AT_PHENT, args->phent); 285e1743d02SSøren Schmidt AUXARGS_ENTRY(pos, AT_PHNUM, args->phnum); 286e1743d02SSøren Schmidt AUXARGS_ENTRY(pos, AT_PAGESZ, args->pagesz); 287e1743d02SSøren Schmidt AUXARGS_ENTRY(pos, AT_FLAGS, args->flags); 288e1743d02SSøren Schmidt AUXARGS_ENTRY(pos, AT_ENTRY, args->entry); 289e1743d02SSøren Schmidt AUXARGS_ENTRY(pos, AT_BASE, args->base); 2904d7c2e8aSDmitry Chagin AUXARGS_ENTRY(pos, LINUX_AT_SECURE, 0); 291b1fc0ec1SRobert Watson AUXARGS_ENTRY(pos, AT_UID, imgp->proc->p_ucred->cr_ruid); 292b1fc0ec1SRobert Watson AUXARGS_ENTRY(pos, AT_EUID, imgp->proc->p_ucred->cr_svuid); 293b1fc0ec1SRobert Watson AUXARGS_ENTRY(pos, AT_GID, imgp->proc->p_ucred->cr_rgid); 294b1fc0ec1SRobert Watson AUXARGS_ENTRY(pos, AT_EGID, imgp->proc->p_ucred->cr_svgid); 2954d7c2e8aSDmitry Chagin AUXARGS_ENTRY(pos, LINUX_AT_PLATFORM, PTROUT(uplatform)); 2964d7c2e8aSDmitry Chagin if (args->execfd != -1) 2974d7c2e8aSDmitry Chagin AUXARGS_ENTRY(pos, AT_EXECFD, args->execfd); 298e1743d02SSøren Schmidt AUXARGS_ENTRY(pos, AT_NULL, 0); 299e1743d02SSøren Schmidt 300e1743d02SSøren Schmidt free(imgp->auxargs, M_TEMP); 301e1743d02SSøren Schmidt imgp->auxargs = NULL; 302e1743d02SSøren Schmidt 303e1743d02SSøren Schmidt (*stack_base)--; 304aa103453SKonstantin Belousov suword(*stack_base, (register_t)imgp->args->argc); 3054d7c2e8aSDmitry Chagin return (0); 306e1743d02SSøren Schmidt } 307d66a5066SPeter Wemm 3084d7c2e8aSDmitry Chagin /* 3094d7c2e8aSDmitry Chagin * Copied from kern/kern_exec.c 3104d7c2e8aSDmitry Chagin */ 3114d7c2e8aSDmitry Chagin static register_t * 3124d7c2e8aSDmitry Chagin linux_copyout_strings(struct image_params *imgp) 3134d7c2e8aSDmitry Chagin { 3144d7c2e8aSDmitry Chagin int argc, envc; 3154d7c2e8aSDmitry Chagin char **vectp; 3164d7c2e8aSDmitry Chagin char *stringp, *destp; 3174d7c2e8aSDmitry Chagin register_t *stack_base; 3184d7c2e8aSDmitry Chagin struct ps_strings *arginfo; 3194d7c2e8aSDmitry Chagin struct proc *p; 3204d7c2e8aSDmitry Chagin 3214d7c2e8aSDmitry Chagin /* 3224d7c2e8aSDmitry Chagin * Calculate string base and vector table pointers. 3234d7c2e8aSDmitry Chagin * Also deal with signal trampoline code for this exec type. 3244d7c2e8aSDmitry Chagin */ 3254d7c2e8aSDmitry Chagin p = imgp->proc; 3264d7c2e8aSDmitry Chagin arginfo = (struct ps_strings *)p->p_sysent->sv_psstrings; 3278f1e49a6SDmitry Chagin destp = (caddr_t)arginfo - SPARE_USRSPACE - linux_szplatform - 3288f1e49a6SDmitry Chagin roundup((ARG_MAX - imgp->args->stringspace), sizeof(char *)); 3294d7c2e8aSDmitry Chagin 3304d7c2e8aSDmitry Chagin /* 3314d7c2e8aSDmitry Chagin * install LINUX_PLATFORM 3324d7c2e8aSDmitry Chagin */ 3338f1e49a6SDmitry Chagin copyout(linux_platform, ((caddr_t)arginfo - linux_szplatform), 3348f1e49a6SDmitry Chagin linux_szplatform); 3354d7c2e8aSDmitry Chagin 3364d7c2e8aSDmitry Chagin /* 3374d7c2e8aSDmitry Chagin * If we have a valid auxargs ptr, prepare some room 3384d7c2e8aSDmitry Chagin * on the stack. 3394d7c2e8aSDmitry Chagin */ 3404d7c2e8aSDmitry Chagin if (imgp->auxargs) { 3414d7c2e8aSDmitry Chagin /* 3424d7c2e8aSDmitry Chagin * 'AT_COUNT*2' is size for the ELF Auxargs data. This is for 3434d7c2e8aSDmitry Chagin * lower compatibility. 3444d7c2e8aSDmitry Chagin */ 3454d7c2e8aSDmitry Chagin imgp->auxarg_size = (imgp->auxarg_size) ? imgp->auxarg_size : 3464d7c2e8aSDmitry Chagin (LINUX_AT_COUNT * 2); 3474d7c2e8aSDmitry Chagin /* 3484d7c2e8aSDmitry Chagin * The '+ 2' is for the null pointers at the end of each of 3494d7c2e8aSDmitry Chagin * the arg and env vector sets,and imgp->auxarg_size is room 3504d7c2e8aSDmitry Chagin * for argument of Runtime loader. 3514d7c2e8aSDmitry Chagin */ 3524d7c2e8aSDmitry Chagin vectp = (char **)(destp - (imgp->args->argc + 3534d7c2e8aSDmitry Chagin imgp->args->envc + 2 + imgp->auxarg_size) * sizeof(char *)); 3544d7c2e8aSDmitry Chagin } else { 3554d7c2e8aSDmitry Chagin /* 3564d7c2e8aSDmitry Chagin * The '+ 2' is for the null pointers at the end of each of 3574d7c2e8aSDmitry Chagin * the arg and env vector sets 3584d7c2e8aSDmitry Chagin */ 3594d7c2e8aSDmitry Chagin vectp = (char **)(destp - (imgp->args->argc + imgp->args->envc + 2) * 3604d7c2e8aSDmitry Chagin sizeof(char *)); 3614d7c2e8aSDmitry Chagin } 3624d7c2e8aSDmitry Chagin 3634d7c2e8aSDmitry Chagin /* 3644d7c2e8aSDmitry Chagin * vectp also becomes our initial stack base 3654d7c2e8aSDmitry Chagin */ 3664d7c2e8aSDmitry Chagin stack_base = (register_t *)vectp; 3674d7c2e8aSDmitry Chagin 3684d7c2e8aSDmitry Chagin stringp = imgp->args->begin_argv; 3694d7c2e8aSDmitry Chagin argc = imgp->args->argc; 3704d7c2e8aSDmitry Chagin envc = imgp->args->envc; 3714d7c2e8aSDmitry Chagin 3724d7c2e8aSDmitry Chagin /* 3734d7c2e8aSDmitry Chagin * Copy out strings - arguments and environment. 3744d7c2e8aSDmitry Chagin */ 3754d7c2e8aSDmitry Chagin copyout(stringp, destp, ARG_MAX - imgp->args->stringspace); 3764d7c2e8aSDmitry Chagin 3774d7c2e8aSDmitry Chagin /* 3784d7c2e8aSDmitry Chagin * Fill in "ps_strings" struct for ps, w, etc. 3794d7c2e8aSDmitry Chagin */ 3804d7c2e8aSDmitry Chagin suword(&arginfo->ps_argvstr, (long)(intptr_t)vectp); 3814d7c2e8aSDmitry Chagin suword(&arginfo->ps_nargvstr, argc); 3824d7c2e8aSDmitry Chagin 3834d7c2e8aSDmitry Chagin /* 3844d7c2e8aSDmitry Chagin * Fill in argument portion of vector table. 3854d7c2e8aSDmitry Chagin */ 3864d7c2e8aSDmitry Chagin for (; argc > 0; --argc) { 3874d7c2e8aSDmitry Chagin suword(vectp++, (long)(intptr_t)destp); 3884d7c2e8aSDmitry Chagin while (*stringp++ != 0) 3894d7c2e8aSDmitry Chagin destp++; 3904d7c2e8aSDmitry Chagin destp++; 3914d7c2e8aSDmitry Chagin } 3924d7c2e8aSDmitry Chagin 3934d7c2e8aSDmitry Chagin /* a null vector table pointer separates the argp's from the envp's */ 3944d7c2e8aSDmitry Chagin suword(vectp++, 0); 3954d7c2e8aSDmitry Chagin 3964d7c2e8aSDmitry Chagin suword(&arginfo->ps_envstr, (long)(intptr_t)vectp); 3974d7c2e8aSDmitry Chagin suword(&arginfo->ps_nenvstr, envc); 3984d7c2e8aSDmitry Chagin 3994d7c2e8aSDmitry Chagin /* 4004d7c2e8aSDmitry Chagin * Fill in environment portion of vector table. 4014d7c2e8aSDmitry Chagin */ 4024d7c2e8aSDmitry Chagin for (; envc > 0; --envc) { 4034d7c2e8aSDmitry Chagin suword(vectp++, (long)(intptr_t)destp); 4044d7c2e8aSDmitry Chagin while (*stringp++ != 0) 4054d7c2e8aSDmitry Chagin destp++; 4064d7c2e8aSDmitry Chagin destp++; 4074d7c2e8aSDmitry Chagin } 4084d7c2e8aSDmitry Chagin 4094d7c2e8aSDmitry Chagin /* end of vector table is a null pointer */ 4104d7c2e8aSDmitry Chagin suword(vectp, 0); 4114d7c2e8aSDmitry Chagin 4124d7c2e8aSDmitry Chagin return (stack_base); 4134d7c2e8aSDmitry Chagin } 4144d7c2e8aSDmitry Chagin 41579363394SAndrew Gallatin static void 4169104847fSDavid Xu linux_rt_sendsig(sig_t catcher, ksiginfo_t *ksi, sigset_t *mask) 41779363394SAndrew Gallatin { 4181d062e2bSDag-Erling Smørgrav struct thread *td = curthread; 4191d062e2bSDag-Erling Smørgrav struct proc *p = td->td_proc; 42090af4afaSJohn Baldwin struct sigacts *psp; 4211d062e2bSDag-Erling Smørgrav struct trapframe *regs; 4225002a60fSMarcel Moolenaar struct l_rt_sigframe *fp, frame; 4239104847fSDavid Xu int sig, code; 42479363394SAndrew Gallatin int oonstack; 42579363394SAndrew Gallatin 4269104847fSDavid Xu sig = ksi->ksi_signo; 4279104847fSDavid Xu code = ksi->ksi_code; 428df53e91cSJohn Baldwin PROC_LOCK_ASSERT(p, MA_OWNED); 42990af4afaSJohn Baldwin psp = p->p_sigacts; 43090af4afaSJohn Baldwin mtx_assert(&psp->ps_mtx, MA_OWNED); 431b40ce416SJulian Elischer regs = td->td_frame; 432d034d459SMarcel Moolenaar oonstack = sigonstack(regs->tf_esp); 43379363394SAndrew Gallatin 43479363394SAndrew Gallatin #ifdef DEBUG 4355002a60fSMarcel Moolenaar if (ldebug(rt_sendsig)) 436728ef954SJohn Baldwin printf(ARGS(rt_sendsig, "%p, %d, %p, %u"), 43724593369SJonathan Lemon catcher, sig, (void*)mask, code); 43879363394SAndrew Gallatin #endif 43979363394SAndrew Gallatin /* 44079363394SAndrew Gallatin * Allocate space for the signal handler context. 44179363394SAndrew Gallatin */ 442a30ec4b9SDavid Xu if ((td->td_pflags & TDP_ALTSTACK) && !oonstack && 44390af4afaSJohn Baldwin SIGISMEMBER(psp->ps_sigonstack, sig)) { 444a30ec4b9SDavid Xu fp = (struct l_rt_sigframe *)(td->td_sigstk.ss_sp + 445a30ec4b9SDavid Xu td->td_sigstk.ss_size - sizeof(struct l_rt_sigframe)); 446d034d459SMarcel Moolenaar } else 4475002a60fSMarcel Moolenaar fp = (struct l_rt_sigframe *)regs->tf_esp - 1; 44890af4afaSJohn Baldwin mtx_unlock(&psp->ps_mtx); 44979363394SAndrew Gallatin 45079363394SAndrew Gallatin /* 45179363394SAndrew Gallatin * Build the argument list for the signal handler. 45279363394SAndrew Gallatin */ 45379363394SAndrew Gallatin if (p->p_sysent->sv_sigtbl) 45479363394SAndrew Gallatin if (sig <= p->p_sysent->sv_sigsize) 45579363394SAndrew Gallatin sig = p->p_sysent->sv_sigtbl[_SIG_IDX(sig)]; 45679363394SAndrew Gallatin 45799d45c5fSMarcel Moolenaar bzero(&frame, sizeof(frame)); 45899d45c5fSMarcel Moolenaar 45979363394SAndrew Gallatin frame.sf_handler = catcher; 46079363394SAndrew Gallatin frame.sf_sig = sig; 46179363394SAndrew Gallatin frame.sf_siginfo = &fp->sf_si; 46279363394SAndrew Gallatin frame.sf_ucontext = &fp->sf_sc; 463cc6ca9b3SMarcel Moolenaar 4649d05b77dSJuli Mallett /* Fill in POSIX parts */ 465aa8b2011SKonstantin Belousov ksiginfo_to_lsiginfo(ksi, &frame.sf_si, sig); 466cc6ca9b3SMarcel Moolenaar 46779363394SAndrew Gallatin /* 46879363394SAndrew Gallatin * Build the signal context to be used by sigreturn. 46979363394SAndrew Gallatin */ 470cc6ca9b3SMarcel Moolenaar frame.sf_sc.uc_flags = 0; /* XXX ??? */ 471cc6ca9b3SMarcel Moolenaar frame.sf_sc.uc_link = NULL; /* XXX ??? */ 472cc6ca9b3SMarcel Moolenaar 473a30ec4b9SDavid Xu frame.sf_sc.uc_stack.ss_sp = td->td_sigstk.ss_sp; 474a30ec4b9SDavid Xu frame.sf_sc.uc_stack.ss_size = td->td_sigstk.ss_size; 475a30ec4b9SDavid Xu frame.sf_sc.uc_stack.ss_flags = (td->td_pflags & TDP_ALTSTACK) 476d034d459SMarcel Moolenaar ? ((oonstack) ? LINUX_SS_ONSTACK : 0) : LINUX_SS_DISABLE; 477611d9407SJohn Baldwin PROC_UNLOCK(p); 478cc6ca9b3SMarcel Moolenaar 479cc6ca9b3SMarcel Moolenaar bsd_to_linux_sigset(mask, &frame.sf_sc.uc_sigmask); 480cc6ca9b3SMarcel Moolenaar 481cc6ca9b3SMarcel Moolenaar frame.sf_sc.uc_mcontext.sc_mask = frame.sf_sc.uc_sigmask.__bits[0]; 48279363394SAndrew Gallatin frame.sf_sc.uc_mcontext.sc_gs = rgs(); 48379363394SAndrew Gallatin frame.sf_sc.uc_mcontext.sc_fs = regs->tf_fs; 48479363394SAndrew Gallatin frame.sf_sc.uc_mcontext.sc_es = regs->tf_es; 48579363394SAndrew Gallatin frame.sf_sc.uc_mcontext.sc_ds = regs->tf_ds; 48679363394SAndrew Gallatin frame.sf_sc.uc_mcontext.sc_edi = regs->tf_edi; 48779363394SAndrew Gallatin frame.sf_sc.uc_mcontext.sc_esi = regs->tf_esi; 48879363394SAndrew Gallatin frame.sf_sc.uc_mcontext.sc_ebp = regs->tf_ebp; 48979363394SAndrew Gallatin frame.sf_sc.uc_mcontext.sc_ebx = regs->tf_ebx; 490*bdc37934SDmitry Chagin frame.sf_sc.uc_mcontext.sc_esp = regs->tf_esp; 49179363394SAndrew Gallatin frame.sf_sc.uc_mcontext.sc_edx = regs->tf_edx; 49279363394SAndrew Gallatin frame.sf_sc.uc_mcontext.sc_ecx = regs->tf_ecx; 49379363394SAndrew Gallatin frame.sf_sc.uc_mcontext.sc_eax = regs->tf_eax; 49479363394SAndrew Gallatin frame.sf_sc.uc_mcontext.sc_eip = regs->tf_eip; 49579363394SAndrew Gallatin frame.sf_sc.uc_mcontext.sc_cs = regs->tf_cs; 49679363394SAndrew Gallatin frame.sf_sc.uc_mcontext.sc_eflags = regs->tf_eflags; 49779363394SAndrew Gallatin frame.sf_sc.uc_mcontext.sc_esp_at_signal = regs->tf_esp; 49879363394SAndrew Gallatin frame.sf_sc.uc_mcontext.sc_ss = regs->tf_ss; 49979363394SAndrew Gallatin frame.sf_sc.uc_mcontext.sc_err = regs->tf_err; 50096a2b635SKonstantin Belousov frame.sf_sc.uc_mcontext.sc_cr2 = (register_t)ksi->ksi_addr; 50127a828fcSPierre Beyssac frame.sf_sc.uc_mcontext.sc_trapno = bsd_to_linux_trapcode(code); 50279363394SAndrew Gallatin 50379363394SAndrew Gallatin #ifdef DEBUG 5045002a60fSMarcel Moolenaar if (ldebug(rt_sendsig)) 50524593369SJonathan Lemon printf(LMSG("rt_sendsig flags: 0x%x, sp: %p, ss: 0x%x, mask: 0x%x"), 5069b778a16SDavid Xu frame.sf_sc.uc_stack.ss_flags, td->td_sigstk.ss_sp, 5079b778a16SDavid Xu td->td_sigstk.ss_size, frame.sf_sc.uc_mcontext.sc_mask); 50879363394SAndrew Gallatin #endif 50979363394SAndrew Gallatin 51079363394SAndrew Gallatin if (copyout(&frame, fp, sizeof(frame)) != 0) { 51179363394SAndrew Gallatin /* 51279363394SAndrew Gallatin * Process has trashed its stack; give it an illegal 51379363394SAndrew Gallatin * instruction to halt it in its tracks. 51479363394SAndrew Gallatin */ 51589734883SAlan Cox #ifdef DEBUG 51689734883SAlan Cox if (ldebug(rt_sendsig)) 51789734883SAlan Cox printf(LMSG("rt_sendsig: bad stack %p, oonstack=%x"), 51889734883SAlan Cox fp, oonstack); 51989734883SAlan Cox #endif 52019eb87d2SJohn Baldwin PROC_LOCK(p); 521b40ce416SJulian Elischer sigexit(td, SIGILL); 52279363394SAndrew Gallatin } 52379363394SAndrew Gallatin 52479363394SAndrew Gallatin /* 52579363394SAndrew Gallatin * Build context to run handler in. 52679363394SAndrew Gallatin */ 52779363394SAndrew Gallatin regs->tf_esp = (int)fp; 528*bdc37934SDmitry Chagin regs->tf_eip = linux_rt_sigcode; 52922eca0bfSKonstantin Belousov regs->tf_eflags &= ~(PSL_T | PSL_VM | PSL_D); 53079363394SAndrew Gallatin regs->tf_cs = _ucodesel; 53179363394SAndrew Gallatin regs->tf_ds = _udatasel; 53279363394SAndrew Gallatin regs->tf_es = _udatasel; 53379363394SAndrew Gallatin regs->tf_fs = _udatasel; 53479363394SAndrew Gallatin regs->tf_ss = _udatasel; 535df53e91cSJohn Baldwin PROC_LOCK(p); 53690af4afaSJohn Baldwin mtx_lock(&psp->ps_mtx); 53779363394SAndrew Gallatin } 53879363394SAndrew Gallatin 539d66a5066SPeter Wemm 540d66a5066SPeter Wemm /* 541d66a5066SPeter Wemm * Send an interrupt to process. 542d66a5066SPeter Wemm * 543d66a5066SPeter Wemm * Stack is set up to allow sigcode stored 544d66a5066SPeter Wemm * in u. to call routine, followed by kcall 545d66a5066SPeter Wemm * to sigreturn routine below. After sigreturn 546d66a5066SPeter Wemm * resets the signal mask, the stack, and the 547d66a5066SPeter Wemm * frame pointer, it returns to the user 548d66a5066SPeter Wemm * specified pc, psl. 549d66a5066SPeter Wemm */ 550303b270bSEivind Eklund static void 5519104847fSDavid Xu linux_sendsig(sig_t catcher, ksiginfo_t *ksi, sigset_t *mask) 552d66a5066SPeter Wemm { 5531d062e2bSDag-Erling Smørgrav struct thread *td = curthread; 5541d062e2bSDag-Erling Smørgrav struct proc *p = td->td_proc; 55590af4afaSJohn Baldwin struct sigacts *psp; 5561d062e2bSDag-Erling Smørgrav struct trapframe *regs; 5575002a60fSMarcel Moolenaar struct l_sigframe *fp, frame; 5585002a60fSMarcel Moolenaar l_sigset_t lmask; 5599104847fSDavid Xu int sig, code; 5602c4ab9ddSAndrew Gallatin int oonstack, i; 561d66a5066SPeter Wemm 5622509e6c2SJohn Baldwin PROC_LOCK_ASSERT(p, MA_OWNED); 56390af4afaSJohn Baldwin psp = p->p_sigacts; 5649104847fSDavid Xu sig = ksi->ksi_signo; 5659104847fSDavid Xu code = ksi->ksi_code; 56690af4afaSJohn Baldwin mtx_assert(&psp->ps_mtx, MA_OWNED); 56790af4afaSJohn Baldwin if (SIGISMEMBER(psp->ps_siginfo, sig)) { 568cc6ca9b3SMarcel Moolenaar /* Signal handler installed with SA_SIGINFO. */ 5699104847fSDavid Xu linux_rt_sendsig(catcher, ksi, mask); 570cc6ca9b3SMarcel Moolenaar return; 571cc6ca9b3SMarcel Moolenaar } 572b40ce416SJulian Elischer regs = td->td_frame; 573d034d459SMarcel Moolenaar oonstack = sigonstack(regs->tf_esp); 574d66a5066SPeter Wemm 575d66a5066SPeter Wemm #ifdef DEBUG 5765002a60fSMarcel Moolenaar if (ldebug(sendsig)) 577728ef954SJohn Baldwin printf(ARGS(sendsig, "%p, %d, %p, %u"), 57824593369SJonathan Lemon catcher, sig, (void*)mask, code); 579d66a5066SPeter Wemm #endif 58079363394SAndrew Gallatin 581d66a5066SPeter Wemm /* 582d66a5066SPeter Wemm * Allocate space for the signal handler context. 583d66a5066SPeter Wemm */ 584a30ec4b9SDavid Xu if ((td->td_pflags & TDP_ALTSTACK) && !oonstack && 58590af4afaSJohn Baldwin SIGISMEMBER(psp->ps_sigonstack, sig)) { 586a30ec4b9SDavid Xu fp = (struct l_sigframe *)(td->td_sigstk.ss_sp + 587a30ec4b9SDavid Xu td->td_sigstk.ss_size - sizeof(struct l_sigframe)); 588d034d459SMarcel Moolenaar } else 5895002a60fSMarcel Moolenaar fp = (struct l_sigframe *)regs->tf_esp - 1; 59090af4afaSJohn Baldwin mtx_unlock(&psp->ps_mtx); 591611d9407SJohn Baldwin PROC_UNLOCK(p); 592d66a5066SPeter Wemm 593d66a5066SPeter Wemm /* 594d66a5066SPeter Wemm * Build the argument list for the signal handler. 595d66a5066SPeter Wemm */ 596956d3333SMarcel Moolenaar if (p->p_sysent->sv_sigtbl) 597956d3333SMarcel Moolenaar if (sig <= p->p_sysent->sv_sigsize) 598956d3333SMarcel Moolenaar sig = p->p_sysent->sv_sigtbl[_SIG_IDX(sig)]; 599d66a5066SPeter Wemm 60099d45c5fSMarcel Moolenaar bzero(&frame, sizeof(frame)); 60199d45c5fSMarcel Moolenaar 602d66a5066SPeter Wemm frame.sf_handler = catcher; 603d66a5066SPeter Wemm frame.sf_sig = sig; 604d66a5066SPeter Wemm 605cc6ca9b3SMarcel Moolenaar bsd_to_linux_sigset(mask, &lmask); 606cc6ca9b3SMarcel Moolenaar 607d66a5066SPeter Wemm /* 608d66a5066SPeter Wemm * Build the signal context to be used by sigreturn. 609d66a5066SPeter Wemm */ 610cc6ca9b3SMarcel Moolenaar frame.sf_sc.sc_mask = lmask.__bits[0]; 6115206bca1SLuoqi Chen frame.sf_sc.sc_gs = rgs(); 6125206bca1SLuoqi Chen frame.sf_sc.sc_fs = regs->tf_fs; 613213fdd80SPeter Wemm frame.sf_sc.sc_es = regs->tf_es; 614213fdd80SPeter Wemm frame.sf_sc.sc_ds = regs->tf_ds; 615213fdd80SPeter Wemm frame.sf_sc.sc_edi = regs->tf_edi; 616213fdd80SPeter Wemm frame.sf_sc.sc_esi = regs->tf_esi; 617213fdd80SPeter Wemm frame.sf_sc.sc_ebp = regs->tf_ebp; 618213fdd80SPeter Wemm frame.sf_sc.sc_ebx = regs->tf_ebx; 619*bdc37934SDmitry Chagin frame.sf_sc.sc_esp = regs->tf_esp; 620213fdd80SPeter Wemm frame.sf_sc.sc_edx = regs->tf_edx; 621213fdd80SPeter Wemm frame.sf_sc.sc_ecx = regs->tf_ecx; 622213fdd80SPeter Wemm frame.sf_sc.sc_eax = regs->tf_eax; 623213fdd80SPeter Wemm frame.sf_sc.sc_eip = regs->tf_eip; 624213fdd80SPeter Wemm frame.sf_sc.sc_cs = regs->tf_cs; 625213fdd80SPeter Wemm frame.sf_sc.sc_eflags = regs->tf_eflags; 626213fdd80SPeter Wemm frame.sf_sc.sc_esp_at_signal = regs->tf_esp; 627213fdd80SPeter Wemm frame.sf_sc.sc_ss = regs->tf_ss; 628213fdd80SPeter Wemm frame.sf_sc.sc_err = regs->tf_err; 62996a2b635SKonstantin Belousov frame.sf_sc.sc_cr2 = (register_t)ksi->ksi_addr; 6309104847fSDavid Xu frame.sf_sc.sc_trapno = bsd_to_linux_trapcode(ksi->ksi_trapno); 631cc6ca9b3SMarcel Moolenaar 6322c4ab9ddSAndrew Gallatin for (i = 0; i < (LINUX_NSIG_WORDS-1); i++) 633cc6ca9b3SMarcel Moolenaar frame.sf_extramask[i] = lmask.__bits[i+1]; 634d66a5066SPeter Wemm 635d66a5066SPeter Wemm if (copyout(&frame, fp, sizeof(frame)) != 0) { 636d66a5066SPeter Wemm /* 637d66a5066SPeter Wemm * Process has trashed its stack; give it an illegal 638d66a5066SPeter Wemm * instruction to halt it in its tracks. 639d66a5066SPeter Wemm */ 64019eb87d2SJohn Baldwin PROC_LOCK(p); 641b40ce416SJulian Elischer sigexit(td, SIGILL); 642d66a5066SPeter Wemm } 643d66a5066SPeter Wemm 644d66a5066SPeter Wemm /* 645d66a5066SPeter Wemm * Build context to run handler in. 646d66a5066SPeter Wemm */ 647213fdd80SPeter Wemm regs->tf_esp = (int)fp; 648*bdc37934SDmitry Chagin regs->tf_eip = linux_sigcode; 64922eca0bfSKonstantin Belousov regs->tf_eflags &= ~(PSL_T | PSL_VM | PSL_D); 650213fdd80SPeter Wemm regs->tf_cs = _ucodesel; 651213fdd80SPeter Wemm regs->tf_ds = _udatasel; 652213fdd80SPeter Wemm regs->tf_es = _udatasel; 6535206bca1SLuoqi Chen regs->tf_fs = _udatasel; 654213fdd80SPeter Wemm regs->tf_ss = _udatasel; 6555002a60fSMarcel Moolenaar PROC_LOCK(p); 65690af4afaSJohn Baldwin mtx_lock(&psp->ps_mtx); 657d66a5066SPeter Wemm } 658d66a5066SPeter Wemm 659d66a5066SPeter Wemm /* 660d66a5066SPeter Wemm * System call to cleanup state after a signal 661d66a5066SPeter Wemm * has been taken. Reset signal mask and 662d66a5066SPeter Wemm * stack state from context left by sendsig (above). 663d66a5066SPeter Wemm * Return to previous pc and psl as specified by 664d66a5066SPeter Wemm * context left by sendsig. Check carefully to 665d66a5066SPeter Wemm * make sure that the user has not modified the 666d66a5066SPeter Wemm * psl to gain improper privileges or to cause 667d66a5066SPeter Wemm * a machine fault. 668d66a5066SPeter Wemm */ 669d66a5066SPeter Wemm int 670b07cd97eSMark Murray linux_sigreturn(struct thread *td, struct linux_sigreturn_args *args) 671d66a5066SPeter Wemm { 6725002a60fSMarcel Moolenaar struct l_sigframe frame; 6731d062e2bSDag-Erling Smørgrav struct trapframe *regs; 6745002a60fSMarcel Moolenaar l_sigset_t lmask; 675d6e029adSKonstantin Belousov sigset_t bmask; 6762c4ab9ddSAndrew Gallatin int eflags, i; 6779104847fSDavid Xu ksiginfo_t ksi; 678d66a5066SPeter Wemm 679b40ce416SJulian Elischer regs = td->td_frame; 680d66a5066SPeter Wemm 681d66a5066SPeter Wemm #ifdef DEBUG 68224593369SJonathan Lemon if (ldebug(sigreturn)) 68324593369SJonathan Lemon printf(ARGS(sigreturn, "%p"), (void *)args->sfp); 684d66a5066SPeter Wemm #endif 685d66a5066SPeter Wemm /* 686cc6ca9b3SMarcel Moolenaar * The trampoline code hands us the sigframe. 687d66a5066SPeter Wemm * It is unsafe to keep track of it ourselves, in the event that a 688d66a5066SPeter Wemm * program jumps out of a signal handler. 689d66a5066SPeter Wemm */ 6904b7ef73dSDag-Erling Smørgrav if (copyin(args->sfp, &frame, sizeof(frame)) != 0) 691d66a5066SPeter Wemm return (EFAULT); 692d66a5066SPeter Wemm 693d66a5066SPeter Wemm /* 694d66a5066SPeter Wemm * Check for security violations. 695d66a5066SPeter Wemm */ 696d66a5066SPeter Wemm #define EFLAGS_SECURE(ef, oef) ((((ef) ^ (oef)) & ~PSL_USERCHANGE) == 0) 697cc6ca9b3SMarcel Moolenaar eflags = frame.sf_sc.sc_eflags; 6983d271aaaSEd Maste if (!EFLAGS_SECURE(eflags, regs->tf_eflags)) 699d66a5066SPeter Wemm return (EINVAL); 700d66a5066SPeter Wemm 701d66a5066SPeter Wemm /* 702d66a5066SPeter Wemm * Don't allow users to load a valid privileged %cs. Let the 703d66a5066SPeter Wemm * hardware check for invalid selectors, excess privilege in 704d66a5066SPeter Wemm * other selectors, invalid %eip's and invalid %esp's. 705d66a5066SPeter Wemm */ 70640d50994SPhilippe Charnier #define CS_SECURE(cs) (ISPL(cs) == SEL_UPL) 707cc6ca9b3SMarcel Moolenaar if (!CS_SECURE(frame.sf_sc.sc_cs)) { 7089104847fSDavid Xu ksiginfo_init_trap(&ksi); 7099104847fSDavid Xu ksi.ksi_signo = SIGBUS; 7109104847fSDavid Xu ksi.ksi_code = BUS_OBJERR; 7119104847fSDavid Xu ksi.ksi_trapno = T_PROTFLT; 7129104847fSDavid Xu ksi.ksi_addr = (void *)regs->tf_eip; 7139104847fSDavid Xu trapsignal(td, &ksi); 714d66a5066SPeter Wemm return (EINVAL); 715d66a5066SPeter Wemm } 716d66a5066SPeter Wemm 717cc6ca9b3SMarcel Moolenaar lmask.__bits[0] = frame.sf_sc.sc_mask; 7182c4ab9ddSAndrew Gallatin for (i = 0; i < (LINUX_NSIG_WORDS-1); i++) 719cc6ca9b3SMarcel Moolenaar lmask.__bits[i+1] = frame.sf_extramask[i]; 720d6e029adSKonstantin Belousov linux_to_bsd_sigset(&lmask, &bmask); 721d6e029adSKonstantin Belousov kern_sigprocmask(td, SIG_SETMASK, &bmask, NULL, 0); 722956d3333SMarcel Moolenaar 723d66a5066SPeter Wemm /* 724d66a5066SPeter Wemm * Restore signal context. 725d66a5066SPeter Wemm */ 7265206bca1SLuoqi Chen /* %gs was restored by the trampoline. */ 727cc6ca9b3SMarcel Moolenaar regs->tf_fs = frame.sf_sc.sc_fs; 728cc6ca9b3SMarcel Moolenaar regs->tf_es = frame.sf_sc.sc_es; 729cc6ca9b3SMarcel Moolenaar regs->tf_ds = frame.sf_sc.sc_ds; 730cc6ca9b3SMarcel Moolenaar regs->tf_edi = frame.sf_sc.sc_edi; 731cc6ca9b3SMarcel Moolenaar regs->tf_esi = frame.sf_sc.sc_esi; 732cc6ca9b3SMarcel Moolenaar regs->tf_ebp = frame.sf_sc.sc_ebp; 733cc6ca9b3SMarcel Moolenaar regs->tf_ebx = frame.sf_sc.sc_ebx; 734cc6ca9b3SMarcel Moolenaar regs->tf_edx = frame.sf_sc.sc_edx; 735cc6ca9b3SMarcel Moolenaar regs->tf_ecx = frame.sf_sc.sc_ecx; 736cc6ca9b3SMarcel Moolenaar regs->tf_eax = frame.sf_sc.sc_eax; 737cc6ca9b3SMarcel Moolenaar regs->tf_eip = frame.sf_sc.sc_eip; 738cc6ca9b3SMarcel Moolenaar regs->tf_cs = frame.sf_sc.sc_cs; 739213fdd80SPeter Wemm regs->tf_eflags = eflags; 740cc6ca9b3SMarcel Moolenaar regs->tf_esp = frame.sf_sc.sc_esp_at_signal; 741cc6ca9b3SMarcel Moolenaar regs->tf_ss = frame.sf_sc.sc_ss; 742d66a5066SPeter Wemm 743d66a5066SPeter Wemm return (EJUSTRETURN); 744d66a5066SPeter Wemm } 745d66a5066SPeter Wemm 74679363394SAndrew Gallatin /* 74779363394SAndrew Gallatin * System call to cleanup state after a signal 74879363394SAndrew Gallatin * has been taken. Reset signal mask and 74979363394SAndrew Gallatin * stack state from context left by rt_sendsig (above). 75079363394SAndrew Gallatin * Return to previous pc and psl as specified by 75179363394SAndrew Gallatin * context left by sendsig. Check carefully to 75279363394SAndrew Gallatin * make sure that the user has not modified the 75379363394SAndrew Gallatin * psl to gain improper privileges or to cause 75479363394SAndrew Gallatin * a machine fault. 75579363394SAndrew Gallatin */ 75679363394SAndrew Gallatin int 757b07cd97eSMark Murray linux_rt_sigreturn(struct thread *td, struct linux_rt_sigreturn_args *args) 75879363394SAndrew Gallatin { 7595002a60fSMarcel Moolenaar struct l_ucontext uc; 7605002a60fSMarcel Moolenaar struct l_sigcontext *context; 761d6e029adSKonstantin Belousov sigset_t bmask; 7625002a60fSMarcel Moolenaar l_stack_t *lss; 763206a5d3aSIan Dowse stack_t ss; 7641d062e2bSDag-Erling Smørgrav struct trapframe *regs; 76579363394SAndrew Gallatin int eflags; 7669104847fSDavid Xu ksiginfo_t ksi; 76779363394SAndrew Gallatin 768b40ce416SJulian Elischer regs = td->td_frame; 76979363394SAndrew Gallatin 77079363394SAndrew Gallatin #ifdef DEBUG 77124593369SJonathan Lemon if (ldebug(rt_sigreturn)) 77224593369SJonathan Lemon printf(ARGS(rt_sigreturn, "%p"), (void *)args->ucp); 77379363394SAndrew Gallatin #endif 77479363394SAndrew Gallatin /* 775cc6ca9b3SMarcel Moolenaar * The trampoline code hands us the ucontext. 77679363394SAndrew Gallatin * It is unsafe to keep track of it ourselves, in the event that a 77779363394SAndrew Gallatin * program jumps out of a signal handler. 77879363394SAndrew Gallatin */ 7794b7ef73dSDag-Erling Smørgrav if (copyin(args->ucp, &uc, sizeof(uc)) != 0) 78079363394SAndrew Gallatin return (EFAULT); 78179363394SAndrew Gallatin 78279363394SAndrew Gallatin context = &uc.uc_mcontext; 78379363394SAndrew Gallatin 78479363394SAndrew Gallatin /* 78579363394SAndrew Gallatin * Check for security violations. 78679363394SAndrew Gallatin */ 78779363394SAndrew Gallatin #define EFLAGS_SECURE(ef, oef) ((((ef) ^ (oef)) & ~PSL_USERCHANGE) == 0) 78879363394SAndrew Gallatin eflags = context->sc_eflags; 7893d271aaaSEd Maste if (!EFLAGS_SECURE(eflags, regs->tf_eflags)) 79079363394SAndrew Gallatin return (EINVAL); 79179363394SAndrew Gallatin 79279363394SAndrew Gallatin /* 79379363394SAndrew Gallatin * Don't allow users to load a valid privileged %cs. Let the 79479363394SAndrew Gallatin * hardware check for invalid selectors, excess privilege in 79579363394SAndrew Gallatin * other selectors, invalid %eip's and invalid %esp's. 79679363394SAndrew Gallatin */ 79779363394SAndrew Gallatin #define CS_SECURE(cs) (ISPL(cs) == SEL_UPL) 79879363394SAndrew Gallatin if (!CS_SECURE(context->sc_cs)) { 7999104847fSDavid Xu ksiginfo_init_trap(&ksi); 8009104847fSDavid Xu ksi.ksi_signo = SIGBUS; 8019104847fSDavid Xu ksi.ksi_code = BUS_OBJERR; 8029104847fSDavid Xu ksi.ksi_trapno = T_PROTFLT; 8039104847fSDavid Xu ksi.ksi_addr = (void *)regs->tf_eip; 8049104847fSDavid Xu trapsignal(td, &ksi); 80579363394SAndrew Gallatin return (EINVAL); 80679363394SAndrew Gallatin } 80779363394SAndrew Gallatin 808d6e029adSKonstantin Belousov linux_to_bsd_sigset(&uc.uc_sigmask, &bmask); 809d6e029adSKonstantin Belousov kern_sigprocmask(td, SIG_SETMASK, &bmask, NULL, 0); 81079363394SAndrew Gallatin 81179363394SAndrew Gallatin /* 812cc6ca9b3SMarcel Moolenaar * Restore signal context 81379363394SAndrew Gallatin */ 81479363394SAndrew Gallatin /* %gs was restored by the trampoline. */ 81579363394SAndrew Gallatin regs->tf_fs = context->sc_fs; 81679363394SAndrew Gallatin regs->tf_es = context->sc_es; 81779363394SAndrew Gallatin regs->tf_ds = context->sc_ds; 81879363394SAndrew Gallatin regs->tf_edi = context->sc_edi; 81979363394SAndrew Gallatin regs->tf_esi = context->sc_esi; 82079363394SAndrew Gallatin regs->tf_ebp = context->sc_ebp; 82179363394SAndrew Gallatin regs->tf_ebx = context->sc_ebx; 82279363394SAndrew Gallatin regs->tf_edx = context->sc_edx; 82379363394SAndrew Gallatin regs->tf_ecx = context->sc_ecx; 82479363394SAndrew Gallatin regs->tf_eax = context->sc_eax; 82579363394SAndrew Gallatin regs->tf_eip = context->sc_eip; 82679363394SAndrew Gallatin regs->tf_cs = context->sc_cs; 82779363394SAndrew Gallatin regs->tf_eflags = eflags; 82879363394SAndrew Gallatin regs->tf_esp = context->sc_esp_at_signal; 82979363394SAndrew Gallatin regs->tf_ss = context->sc_ss; 83079363394SAndrew Gallatin 83179363394SAndrew Gallatin /* 83279363394SAndrew Gallatin * call sigaltstack & ignore results.. 83379363394SAndrew Gallatin */ 83479363394SAndrew Gallatin lss = &uc.uc_stack; 835206a5d3aSIan Dowse ss.ss_sp = lss->ss_sp; 836206a5d3aSIan Dowse ss.ss_size = lss->ss_size; 837206a5d3aSIan Dowse ss.ss_flags = linux_to_bsd_sigaltstack(lss->ss_flags); 83879363394SAndrew Gallatin 83979363394SAndrew Gallatin #ifdef DEBUG 84024593369SJonathan Lemon if (ldebug(rt_sigreturn)) 84124593369SJonathan Lemon printf(LMSG("rt_sigret flags: 0x%x, sp: %p, ss: 0x%x, mask: 0x%x"), 842206a5d3aSIan Dowse ss.ss_flags, ss.ss_sp, ss.ss_size, context->sc_mask); 84379363394SAndrew Gallatin #endif 844206a5d3aSIan Dowse (void)kern_sigaltstack(td, &ss, NULL); 84579363394SAndrew Gallatin 84679363394SAndrew Gallatin return (EJUSTRETURN); 84779363394SAndrew Gallatin } 84879363394SAndrew Gallatin 849afe1a688SKonstantin Belousov static int 850afe1a688SKonstantin Belousov linux_fetch_syscall_args(struct thread *td, struct syscall_args *sa) 851d66a5066SPeter Wemm { 852afe1a688SKonstantin Belousov struct proc *p; 853afe1a688SKonstantin Belousov struct trapframe *frame; 854afe1a688SKonstantin Belousov 855afe1a688SKonstantin Belousov p = td->td_proc; 856afe1a688SKonstantin Belousov frame = td->td_frame; 857afe1a688SKonstantin Belousov 858afe1a688SKonstantin Belousov sa->code = frame->tf_eax; 859afe1a688SKonstantin Belousov sa->args[0] = frame->tf_ebx; 860afe1a688SKonstantin Belousov sa->args[1] = frame->tf_ecx; 861afe1a688SKonstantin Belousov sa->args[2] = frame->tf_edx; 862afe1a688SKonstantin Belousov sa->args[3] = frame->tf_esi; 863afe1a688SKonstantin Belousov sa->args[4] = frame->tf_edi; 864afe1a688SKonstantin Belousov sa->args[5] = frame->tf_ebp; /* Unconfirmed */ 865afe1a688SKonstantin Belousov 866afe1a688SKonstantin Belousov if (sa->code >= p->p_sysent->sv_size) 867afe1a688SKonstantin Belousov sa->callp = &p->p_sysent->sv_table[0]; 868afe1a688SKonstantin Belousov else 869afe1a688SKonstantin Belousov sa->callp = &p->p_sysent->sv_table[sa->code]; 870afe1a688SKonstantin Belousov sa->narg = sa->callp->sy_narg; 871afe1a688SKonstantin Belousov 872afe1a688SKonstantin Belousov td->td_retval[0] = 0; 873afe1a688SKonstantin Belousov td->td_retval[1] = frame->tf_edx; 874afe1a688SKonstantin Belousov 875afe1a688SKonstantin Belousov return (0); 876d66a5066SPeter Wemm } 877d66a5066SPeter Wemm 878d323ddf3SMatthew Dillon /* 879d323ddf3SMatthew Dillon * If a linux binary is exec'ing something, try this image activator 880d323ddf3SMatthew Dillon * first. We override standard shell script execution in order to 881d323ddf3SMatthew Dillon * be able to modify the interpreter path. We only do this if a linux 882d323ddf3SMatthew Dillon * binary is doing the exec, so we do not create an EXEC module for it. 883d323ddf3SMatthew Dillon */ 88489c9a483SAlfred Perlstein static int exec_linux_imgact_try(struct image_params *iparams); 885d323ddf3SMatthew Dillon 886d323ddf3SMatthew Dillon static int 887b07cd97eSMark Murray exec_linux_imgact_try(struct image_params *imgp) 888d323ddf3SMatthew Dillon { 889d323ddf3SMatthew Dillon const char *head = (const char *)imgp->image_header; 8900311233eSJohn Baldwin char *rpath; 891a14a9498SAlan Cox int error = -1; 892d323ddf3SMatthew Dillon 893d323ddf3SMatthew Dillon /* 894d323ddf3SMatthew Dillon * The interpreter for shell scripts run from a linux binary needs 895d323ddf3SMatthew Dillon * to be located in /compat/linux if possible in order to recursively 896d323ddf3SMatthew Dillon * maintain linux path emulation. 897d323ddf3SMatthew Dillon */ 898d323ddf3SMatthew Dillon if (((const short *)head)[0] == SHELLMAGIC) { 899d323ddf3SMatthew Dillon /* 900d323ddf3SMatthew Dillon * Run our normal shell image activator. If it succeeds attempt 901d323ddf3SMatthew Dillon * to use the alternate path for the interpreter. If an alternate 902d323ddf3SMatthew Dillon * path is found, use our stringspace to store it. 903d323ddf3SMatthew Dillon */ 904d323ddf3SMatthew Dillon if ((error = exec_shell_imgact(imgp)) == 0) { 9050311233eSJohn Baldwin linux_emul_convpath(FIRST_THREAD_IN_PROC(imgp->proc), 90648b05c3fSKonstantin Belousov imgp->interpreter_name, UIO_SYSSPACE, &rpath, 0, AT_FDCWD); 907a14a9498SAlan Cox if (rpath != NULL) 908a14a9498SAlan Cox imgp->args->fname_buf = 909a14a9498SAlan Cox imgp->interpreter_name = rpath; 910d323ddf3SMatthew Dillon } 911d323ddf3SMatthew Dillon } 912d323ddf3SMatthew Dillon return (error); 913d323ddf3SMatthew Dillon } 914d323ddf3SMatthew Dillon 915598d45beSMatthew N. Dodd /* 916598d45beSMatthew N. Dodd * exec_setregs may initialize some registers differently than Linux 917598d45beSMatthew N. Dodd * does, thus potentially confusing Linux binaries. If necessary, we 918598d45beSMatthew N. Dodd * override the exec_setregs default(s) here. 919598d45beSMatthew N. Dodd */ 920598d45beSMatthew N. Dodd static void 921a107d8aaSNathan Whitehorn exec_linux_setregs(struct thread *td, struct image_params *imgp, u_long stack) 922598d45beSMatthew N. Dodd { 923598d45beSMatthew N. Dodd struct pcb *pcb = td->td_pcb; 924598d45beSMatthew N. Dodd 925a107d8aaSNathan Whitehorn exec_setregs(td, imgp, stack); 926598d45beSMatthew N. Dodd 927598d45beSMatthew N. Dodd /* Linux sets %gs to 0, we default to _udatasel */ 9282ee8325fSJohn Baldwin pcb->pcb_gs = 0; 9292ee8325fSJohn Baldwin load_gs(0); 9302a51b9b0SDavid Schultz 9312ee8325fSJohn Baldwin pcb->pcb_initial_npxcw = __LINUX_NPXCW__; 932598d45beSMatthew N. Dodd } 933598d45beSMatthew N. Dodd 9344d7c2e8aSDmitry Chagin static void 9354d7c2e8aSDmitry Chagin linux_get_machine(const char **dst) 9364d7c2e8aSDmitry Chagin { 9374d7c2e8aSDmitry Chagin 9384d7c2e8aSDmitry Chagin switch (cpu_class) { 9394d7c2e8aSDmitry Chagin case CPUCLASS_686: 9404d7c2e8aSDmitry Chagin *dst = "i686"; 9414d7c2e8aSDmitry Chagin break; 9424d7c2e8aSDmitry Chagin case CPUCLASS_586: 9434d7c2e8aSDmitry Chagin *dst = "i586"; 9444d7c2e8aSDmitry Chagin break; 9454d7c2e8aSDmitry Chagin case CPUCLASS_486: 9464d7c2e8aSDmitry Chagin *dst = "i486"; 9474d7c2e8aSDmitry Chagin break; 9484d7c2e8aSDmitry Chagin default: 9494d7c2e8aSDmitry Chagin *dst = "i386"; 9504d7c2e8aSDmitry Chagin } 9514d7c2e8aSDmitry Chagin } 9524d7c2e8aSDmitry Chagin 953d66a5066SPeter Wemm struct sysentvec linux_sysvec = { 954a8d403e1SKonstantin Belousov .sv_size = LINUX_SYS_MAXSYSCALL, 955a8d403e1SKonstantin Belousov .sv_table = linux_sysent, 956a8d403e1SKonstantin Belousov .sv_mask = 0, 957a8d403e1SKonstantin Belousov .sv_sigsize = LINUX_SIGTBLSZ, 958a8d403e1SKonstantin Belousov .sv_sigtbl = bsd_to_linux_signal, 959a8d403e1SKonstantin Belousov .sv_errsize = ELAST + 1, 960a8d403e1SKonstantin Belousov .sv_errtbl = bsd_to_linux_errno, 961a8d403e1SKonstantin Belousov .sv_transtrap = translate_traps, 962a8d403e1SKonstantin Belousov .sv_fixup = linux_fixup, 963a8d403e1SKonstantin Belousov .sv_sendsig = linux_sendsig, 964*bdc37934SDmitry Chagin .sv_sigcode = &_binary_linux_locore_o_start, 965a8d403e1SKonstantin Belousov .sv_szsigcode = &linux_szsigcode, 966afe1a688SKonstantin Belousov .sv_prepsyscall = NULL, 967a8d403e1SKonstantin Belousov .sv_name = "Linux a.out", 968a8d403e1SKonstantin Belousov .sv_coredump = NULL, 969a8d403e1SKonstantin Belousov .sv_imgact_try = exec_linux_imgact_try, 970a8d403e1SKonstantin Belousov .sv_minsigstksz = LINUX_MINSIGSTKSZ, 971a8d403e1SKonstantin Belousov .sv_pagesize = PAGE_SIZE, 972a8d403e1SKonstantin Belousov .sv_minuser = VM_MIN_ADDRESS, 973a8d403e1SKonstantin Belousov .sv_maxuser = VM_MAXUSER_ADDRESS, 9748f1e49a6SDmitry Chagin .sv_usrstack = LINUX_USRSTACK, 975a8d403e1SKonstantin Belousov .sv_psstrings = PS_STRINGS, 976a8d403e1SKonstantin Belousov .sv_stackprot = VM_PROT_ALL, 977a8d403e1SKonstantin Belousov .sv_copyout_strings = exec_copyout_strings, 978a8d403e1SKonstantin Belousov .sv_setregs = exec_linux_setregs, 979a8d403e1SKonstantin Belousov .sv_fixlimit = NULL, 980b4cf0e62SKonstantin Belousov .sv_maxssiz = NULL, 981afe1a688SKonstantin Belousov .sv_flags = SV_ABI_LINUX | SV_AOUT | SV_IA32 | SV_ILP32, 982afe1a688SKonstantin Belousov .sv_set_syscall_retval = cpu_set_syscall_retval, 983afe1a688SKonstantin Belousov .sv_fetch_syscall_args = linux_fetch_syscall_args, 984afe1a688SKonstantin Belousov .sv_syscallnames = NULL, 9858f1e49a6SDmitry Chagin .sv_shared_page_base = LINUX_SHAREDPAGE, 9868f1e49a6SDmitry Chagin .sv_shared_page_len = PAGE_SIZE, 987e5d81ef1SDmitry Chagin .sv_schedtail = linux_schedtail, 98881338031SDmitry Chagin .sv_thread_detach = linux_thread_detach, 989d66a5066SPeter Wemm }; 9908f1e49a6SDmitry Chagin INIT_SYSENTVEC(aout_sysvec, &linux_sysvec); 991e1743d02SSøren Schmidt 992e1743d02SSøren Schmidt struct sysentvec elf_linux_sysvec = { 993a8d403e1SKonstantin Belousov .sv_size = LINUX_SYS_MAXSYSCALL, 994a8d403e1SKonstantin Belousov .sv_table = linux_sysent, 995a8d403e1SKonstantin Belousov .sv_mask = 0, 996a8d403e1SKonstantin Belousov .sv_sigsize = LINUX_SIGTBLSZ, 997a8d403e1SKonstantin Belousov .sv_sigtbl = bsd_to_linux_signal, 998a8d403e1SKonstantin Belousov .sv_errsize = ELAST + 1, 999a8d403e1SKonstantin Belousov .sv_errtbl = bsd_to_linux_errno, 1000a8d403e1SKonstantin Belousov .sv_transtrap = translate_traps, 1001a8d403e1SKonstantin Belousov .sv_fixup = elf_linux_fixup, 1002a8d403e1SKonstantin Belousov .sv_sendsig = linux_sendsig, 1003*bdc37934SDmitry Chagin .sv_sigcode = &_binary_linux_locore_o_start, 1004a8d403e1SKonstantin Belousov .sv_szsigcode = &linux_szsigcode, 1005afe1a688SKonstantin Belousov .sv_prepsyscall = NULL, 1006a8d403e1SKonstantin Belousov .sv_name = "Linux ELF", 1007a8d403e1SKonstantin Belousov .sv_coredump = elf32_coredump, 1008a8d403e1SKonstantin Belousov .sv_imgact_try = exec_linux_imgact_try, 1009a8d403e1SKonstantin Belousov .sv_minsigstksz = LINUX_MINSIGSTKSZ, 1010a8d403e1SKonstantin Belousov .sv_pagesize = PAGE_SIZE, 1011a8d403e1SKonstantin Belousov .sv_minuser = VM_MIN_ADDRESS, 1012a8d403e1SKonstantin Belousov .sv_maxuser = VM_MAXUSER_ADDRESS, 10138f1e49a6SDmitry Chagin .sv_usrstack = LINUX_USRSTACK, 10148f1e49a6SDmitry Chagin .sv_psstrings = LINUX_PS_STRINGS, 1015a8d403e1SKonstantin Belousov .sv_stackprot = VM_PROT_ALL, 10164d7c2e8aSDmitry Chagin .sv_copyout_strings = linux_copyout_strings, 1017a8d403e1SKonstantin Belousov .sv_setregs = exec_linux_setregs, 1018a8d403e1SKonstantin Belousov .sv_fixlimit = NULL, 1019b4cf0e62SKonstantin Belousov .sv_maxssiz = NULL, 10208f1e49a6SDmitry Chagin .sv_flags = SV_ABI_LINUX | SV_IA32 | SV_ILP32 | SV_SHP, 1021afe1a688SKonstantin Belousov .sv_set_syscall_retval = cpu_set_syscall_retval, 1022afe1a688SKonstantin Belousov .sv_fetch_syscall_args = linux_fetch_syscall_args, 1023afe1a688SKonstantin Belousov .sv_syscallnames = NULL, 10248f1e49a6SDmitry Chagin .sv_shared_page_base = LINUX_SHAREDPAGE, 10258f1e49a6SDmitry Chagin .sv_shared_page_len = PAGE_SIZE, 1026e5d81ef1SDmitry Chagin .sv_schedtail = linux_schedtail, 102781338031SDmitry Chagin .sv_thread_detach = linux_thread_detach, 1028e1743d02SSøren Schmidt }; 1029*bdc37934SDmitry Chagin 1030*bdc37934SDmitry Chagin static void 1031*bdc37934SDmitry Chagin linux_vdso_install(void *param) 1032*bdc37934SDmitry Chagin { 1033*bdc37934SDmitry Chagin 1034*bdc37934SDmitry Chagin linux_szsigcode = (&_binary_linux_locore_o_end - 1035*bdc37934SDmitry Chagin &_binary_linux_locore_o_start); 1036*bdc37934SDmitry Chagin 1037*bdc37934SDmitry Chagin if (linux_szsigcode > elf_linux_sysvec.sv_shared_page_len) 1038*bdc37934SDmitry Chagin panic("Linux invalid vdso size\n"); 1039*bdc37934SDmitry Chagin 1040*bdc37934SDmitry Chagin __elfN(linux_vdso_fixup)(&elf_linux_sysvec); 1041*bdc37934SDmitry Chagin 1042*bdc37934SDmitry Chagin linux_shared_page_obj = __elfN(linux_shared_page_init) 1043*bdc37934SDmitry Chagin (&linux_shared_page_mapping); 1044*bdc37934SDmitry Chagin 1045*bdc37934SDmitry Chagin __elfN(linux_vdso_reloc)(&elf_linux_sysvec, LINUX_SHAREDPAGE); 1046*bdc37934SDmitry Chagin 1047*bdc37934SDmitry Chagin bcopy(elf_linux_sysvec.sv_sigcode, linux_shared_page_mapping, 1048*bdc37934SDmitry Chagin linux_szsigcode); 1049*bdc37934SDmitry Chagin elf_linux_sysvec.sv_shared_page_obj = linux_shared_page_obj; 1050*bdc37934SDmitry Chagin } 1051*bdc37934SDmitry Chagin SYSINIT(elf_linux_vdso_init, SI_SUB_EXEC, SI_ORDER_ANY, 1052*bdc37934SDmitry Chagin (sysinit_cfunc_t)linux_vdso_install, NULL); 1053*bdc37934SDmitry Chagin 1054*bdc37934SDmitry Chagin static void 1055*bdc37934SDmitry Chagin linux_vdso_deinstall(void *param) 1056*bdc37934SDmitry Chagin { 1057*bdc37934SDmitry Chagin 1058*bdc37934SDmitry Chagin __elfN(linux_shared_page_fini)(linux_shared_page_obj); 1059*bdc37934SDmitry Chagin }; 1060*bdc37934SDmitry Chagin SYSUNINIT(elf_linux_vdso_uninit, SI_SUB_EXEC, SI_ORDER_FIRST, 1061*bdc37934SDmitry Chagin (sysinit_cfunc_t)linux_vdso_deinstall, NULL); 1062e1743d02SSøren Schmidt 106389ffc202SBjoern A. Zeeb static char GNU_ABI_VENDOR[] = "GNU"; 106489ffc202SBjoern A. Zeeb static int GNULINUX_ABI_DESC = 0; 106589ffc202SBjoern A. Zeeb 106689ffc202SBjoern A. Zeeb static boolean_t 106789ffc202SBjoern A. Zeeb linux_trans_osrel(const Elf_Note *note, int32_t *osrel) 106889ffc202SBjoern A. Zeeb { 106989ffc202SBjoern A. Zeeb const Elf32_Word *desc; 107089ffc202SBjoern A. Zeeb uintptr_t p; 107189ffc202SBjoern A. Zeeb 107289ffc202SBjoern A. Zeeb p = (uintptr_t)(note + 1); 107389ffc202SBjoern A. Zeeb p += roundup2(note->n_namesz, sizeof(Elf32_Addr)); 107489ffc202SBjoern A. Zeeb 107589ffc202SBjoern A. Zeeb desc = (const Elf32_Word *)p; 107689ffc202SBjoern A. Zeeb if (desc[0] != GNULINUX_ABI_DESC) 107789ffc202SBjoern A. Zeeb return (FALSE); 107889ffc202SBjoern A. Zeeb 107989ffc202SBjoern A. Zeeb /* 108089ffc202SBjoern A. Zeeb * For linux we encode osrel as follows (see linux_mib.c): 108189ffc202SBjoern A. Zeeb * VVVMMMIII (version, major, minor), see linux_mib.c. 108289ffc202SBjoern A. Zeeb */ 108389ffc202SBjoern A. Zeeb *osrel = desc[1] * 1000000 + desc[2] * 1000 + desc[3]; 108489ffc202SBjoern A. Zeeb 108589ffc202SBjoern A. Zeeb return (TRUE); 108689ffc202SBjoern A. Zeeb } 108732c01de2SDmitry Chagin 108832c01de2SDmitry Chagin static Elf_Brandnote linux_brandnote = { 108989ffc202SBjoern A. Zeeb .hdr.n_namesz = sizeof(GNU_ABI_VENDOR), 109089ffc202SBjoern A. Zeeb .hdr.n_descsz = 16, /* XXX at least 16 */ 109132c01de2SDmitry Chagin .hdr.n_type = 1, 109289ffc202SBjoern A. Zeeb .vendor = GNU_ABI_VENDOR, 109389ffc202SBjoern A. Zeeb .flags = BN_TRANSLATE_OSREL, 109489ffc202SBjoern A. Zeeb .trans_osrel = linux_trans_osrel 109532c01de2SDmitry Chagin }; 109632c01de2SDmitry Chagin 1097514058dcSAlexander Langer static Elf32_Brandinfo linux_brand = { 1098a8d403e1SKonstantin Belousov .brand = ELFOSABI_LINUX, 1099a8d403e1SKonstantin Belousov .machine = EM_386, 1100a8d403e1SKonstantin Belousov .compat_3_brand = "Linux", 1101a8d403e1SKonstantin Belousov .emul_path = "/compat/linux", 1102a8d403e1SKonstantin Belousov .interp_path = "/lib/ld-linux.so.1", 1103a8d403e1SKonstantin Belousov .sysvec = &elf_linux_sysvec, 1104a8d403e1SKonstantin Belousov .interp_newpath = NULL, 110532c01de2SDmitry Chagin .brand_note = &linux_brandnote, 11062dedc128SDmitry Chagin .flags = BI_CAN_EXEC_DYN | BI_BRAND_NOTE 11075cf588ebSPeter Wemm }; 11085cf588ebSPeter Wemm 1109514058dcSAlexander Langer static Elf32_Brandinfo linux_glibc2brand = { 1110a8d403e1SKonstantin Belousov .brand = ELFOSABI_LINUX, 1111a8d403e1SKonstantin Belousov .machine = EM_386, 1112a8d403e1SKonstantin Belousov .compat_3_brand = "Linux", 1113a8d403e1SKonstantin Belousov .emul_path = "/compat/linux", 1114a8d403e1SKonstantin Belousov .interp_path = "/lib/ld-linux.so.2", 1115a8d403e1SKonstantin Belousov .sysvec = &elf_linux_sysvec, 1116a8d403e1SKonstantin Belousov .interp_newpath = NULL, 111732c01de2SDmitry Chagin .brand_note = &linux_brandnote, 11182dedc128SDmitry Chagin .flags = BI_CAN_EXEC_DYN | BI_BRAND_NOTE 11194e138a28SMike Smith }; 11204e138a28SMike Smith 1121514058dcSAlexander Langer Elf32_Brandinfo *linux_brandlist[] = { 1122514058dcSAlexander Langer &linux_brand, 1123514058dcSAlexander Langer &linux_glibc2brand, 1124514058dcSAlexander Langer NULL 1125514058dcSAlexander Langer }; 1126514058dcSAlexander Langer 1127aa855a59SPeter Wemm static int 1128c25ded31SBruce Evans linux_elf_modevent(module_t mod, int type, void *data) 1129d30ea4f5SPeter Wemm { 1130514058dcSAlexander Langer Elf32_Brandinfo **brandinfo; 1131514058dcSAlexander Langer int error; 1132f41325dbSPeter Wemm struct linux_ioctl_handler **lihp; 1133060e4882SDoug Ambrisko struct linux_device_handler **ldhp; 1134514058dcSAlexander Langer 1135514058dcSAlexander Langer error = 0; 1136514058dcSAlexander Langer 1137aa855a59SPeter Wemm switch(type) { 1138aa855a59SPeter Wemm case MOD_LOAD: 1139aa855a59SPeter Wemm for (brandinfo = &linux_brandlist[0]; *brandinfo != NULL; 1140aa855a59SPeter Wemm ++brandinfo) 11413ebc1248SPeter Wemm if (elf32_insert_brand_entry(*brandinfo) < 0) 1142aa855a59SPeter Wemm error = EINVAL; 1143466b14d7SMarcel Moolenaar if (error == 0) { 1144f41325dbSPeter Wemm SET_FOREACH(lihp, linux_ioctl_handler_set) 1145f41325dbSPeter Wemm linux_ioctl_register_handler(*lihp); 1146060e4882SDoug Ambrisko SET_FOREACH(ldhp, linux_device_handler_set) 1147060e4882SDoug Ambrisko linux_device_register_handler(*ldhp); 11489b44bfc5SAlexander Leidinger LIST_INIT(&futex_list); 114979262bf1SDmitry Chagin mtx_init(&futex_mtx, "ftllk", NULL, MTX_DEF); 11509b44bfc5SAlexander Leidinger linux_exit_tag = EVENTHANDLER_REGISTER(process_exit, linux_proc_exit, 11519b44bfc5SAlexander Leidinger NULL, 1000); 11529b44bfc5SAlexander Leidinger linux_exec_tag = EVENTHANDLER_REGISTER(process_exec, linux_proc_exec, 11539b44bfc5SAlexander Leidinger NULL, 1000); 115481338031SDmitry Chagin linux_thread_dtor_tag = EVENTHANDLER_REGISTER(thread_dtor, 115581338031SDmitry Chagin linux_thread_dtor, NULL, EVENTHANDLER_PRI_ANY); 11564d7c2e8aSDmitry Chagin linux_get_machine(&linux_platform); 11574d7c2e8aSDmitry Chagin linux_szplatform = roundup(strlen(linux_platform) + 1, 11584d7c2e8aSDmitry Chagin sizeof(char *)); 11597ae27ff4SJamie Gritton linux_osd_jail_register(); 11601ca16454SDmitry Chagin stclohz = (stathz ? stathz : hz); 116143bef515SMarcel Moolenaar if (bootverbose) 1162466b14d7SMarcel Moolenaar printf("Linux ELF exec handler installed\n"); 1163466b14d7SMarcel Moolenaar } else 1164466b14d7SMarcel Moolenaar printf("cannot insert Linux ELF brand handler\n"); 1165aa855a59SPeter Wemm break; 1166aa855a59SPeter Wemm case MOD_UNLOAD: 1167aa855a59SPeter Wemm for (brandinfo = &linux_brandlist[0]; *brandinfo != NULL; 1168aa855a59SPeter Wemm ++brandinfo) 11693ebc1248SPeter Wemm if (elf32_brand_inuse(*brandinfo)) 1170d2758342SMark Newton error = EBUSY; 1171d2758342SMark Newton if (error == 0) { 1172d2758342SMark Newton for (brandinfo = &linux_brandlist[0]; 1173d2758342SMark Newton *brandinfo != NULL; ++brandinfo) 11743ebc1248SPeter Wemm if (elf32_remove_brand_entry(*brandinfo) < 0) 1175aa855a59SPeter Wemm error = EINVAL; 1176d2758342SMark Newton } 1177466b14d7SMarcel Moolenaar if (error == 0) { 1178f41325dbSPeter Wemm SET_FOREACH(lihp, linux_ioctl_handler_set) 1179f41325dbSPeter Wemm linux_ioctl_unregister_handler(*lihp); 1180060e4882SDoug Ambrisko SET_FOREACH(ldhp, linux_device_handler_set) 1181060e4882SDoug Ambrisko linux_device_unregister_handler(*ldhp); 118279262bf1SDmitry Chagin mtx_destroy(&futex_mtx); 11839b44bfc5SAlexander Leidinger EVENTHANDLER_DEREGISTER(process_exit, linux_exit_tag); 11849b44bfc5SAlexander Leidinger EVENTHANDLER_DEREGISTER(process_exec, linux_exec_tag); 118581338031SDmitry Chagin EVENTHANDLER_DEREGISTER(thread_dtor, linux_thread_dtor_tag); 11867ae27ff4SJamie Gritton linux_osd_jail_deregister(); 1187466b14d7SMarcel Moolenaar if (bootverbose) 1188466b14d7SMarcel Moolenaar printf("Linux ELF exec handler removed\n"); 1189466b14d7SMarcel Moolenaar } else 1190aa855a59SPeter Wemm printf("Could not deinstall ELF interpreter entry\n"); 1191aa855a59SPeter Wemm break; 1192aa855a59SPeter Wemm default: 1193af682d48SDmitry Chagin return (EOPNOTSUPP); 1194d30ea4f5SPeter Wemm } 1195af682d48SDmitry Chagin return (error); 1196aa855a59SPeter Wemm } 1197466b14d7SMarcel Moolenaar 1198aa855a59SPeter Wemm static moduledata_t linux_elf_mod = { 1199aa855a59SPeter Wemm "linuxelf", 1200aa855a59SPeter Wemm linux_elf_modevent, 12019823d527SKevin Lo 0 1202aa855a59SPeter Wemm }; 1203466b14d7SMarcel Moolenaar 120478ae4338SKonstantin Belousov DECLARE_MODULE_TIED(linuxelf, linux_elf_mod, SI_SUB_EXEC, SI_ORDER_ANY); 1205