1ea0fabbcSTim J. Robbins /*- 2ea0fabbcSTim J. Robbins * Copyright (c) 2004 Tim J. Robbins 3ea0fabbcSTim J. Robbins * Copyright (c) 2003 Peter Wemm 4ea0fabbcSTim J. Robbins * Copyright (c) 2002 Doug Rabson 5ea0fabbcSTim J. Robbins * Copyright (c) 1998-1999 Andrew Gallatin 6ea0fabbcSTim J. Robbins * Copyright (c) 1994-1996 S�ren Schmidt 7ea0fabbcSTim J. Robbins * All rights reserved. 8ea0fabbcSTim J. Robbins * 9ea0fabbcSTim J. Robbins * Redistribution and use in source and binary forms, with or without 10ea0fabbcSTim J. Robbins * modification, are permitted provided that the following conditions 11ea0fabbcSTim J. Robbins * are met: 12ea0fabbcSTim J. Robbins * 1. Redistributions of source code must retain the above copyright 13ea0fabbcSTim J. Robbins * notice, this list of conditions and the following disclaimer 14ea0fabbcSTim J. Robbins * in this position and unchanged. 15ea0fabbcSTim J. Robbins * 2. Redistributions in binary form must reproduce the above copyright 16ea0fabbcSTim J. Robbins * notice, this list of conditions and the following disclaimer in the 17ea0fabbcSTim J. Robbins * documentation and/or other materials provided with the distribution. 18ea0fabbcSTim J. Robbins * 3. The name of the author may not be used to endorse or promote products 19ea0fabbcSTim J. Robbins * derived from this software without specific prior written permission 20ea0fabbcSTim J. Robbins * 21ea0fabbcSTim J. Robbins * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 22ea0fabbcSTim J. Robbins * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 23ea0fabbcSTim J. Robbins * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 24ea0fabbcSTim J. Robbins * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 25ea0fabbcSTim J. Robbins * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 26ea0fabbcSTim J. Robbins * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 27ea0fabbcSTim J. Robbins * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 28ea0fabbcSTim J. Robbins * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 29ea0fabbcSTim J. Robbins * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 30ea0fabbcSTim J. Robbins * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 31ea0fabbcSTim J. Robbins */ 32ea0fabbcSTim J. Robbins 33ea0fabbcSTim J. Robbins #include <sys/cdefs.h> 34ea0fabbcSTim J. Robbins __FBSDID("$FreeBSD$"); 35aefce619SRuslan Ermilov #include "opt_compat.h" 36ea0fabbcSTim J. Robbins 37c680f6b1SDavid E. O'Brien #ifndef COMPAT_IA32 38ce55a234SDavid E. O'Brien #error "Unable to compile Linux-emulator due to missing COMPAT_IA32 option!" 39ea0fabbcSTim J. Robbins #endif 40ea0fabbcSTim J. Robbins 41ea0fabbcSTim J. Robbins #define __ELF_WORD_SIZE 32 42ea0fabbcSTim J. Robbins 43ea0fabbcSTim J. Robbins #include <sys/param.h> 44ea0fabbcSTim J. Robbins #include <sys/systm.h> 45ea0fabbcSTim J. Robbins #include <sys/exec.h> 46ea0fabbcSTim J. Robbins #include <sys/imgact.h> 47ea0fabbcSTim J. Robbins #include <sys/imgact_elf.h> 48ea0fabbcSTim J. Robbins #include <sys/kernel.h> 49ea0fabbcSTim J. Robbins #include <sys/lock.h> 50ea0fabbcSTim J. Robbins #include <sys/malloc.h> 51ea0fabbcSTim J. Robbins #include <sys/module.h> 52ea0fabbcSTim J. Robbins #include <sys/mutex.h> 53ea0fabbcSTim J. Robbins #include <sys/proc.h> 546004362eSDavid Schultz #include <sys/resourcevar.h> 55ea0fabbcSTim J. Robbins #include <sys/signalvar.h> 56ea0fabbcSTim J. Robbins #include <sys/sysctl.h> 57ea0fabbcSTim J. Robbins #include <sys/syscallsubr.h> 58ea0fabbcSTim J. Robbins #include <sys/sysent.h> 59ea0fabbcSTim J. Robbins #include <sys/sysproto.h> 60ea0fabbcSTim J. Robbins #include <sys/vnode.h> 617c09e6c0SAlexander Leidinger #include <sys/eventhandler.h> 62ea0fabbcSTim J. Robbins 63ea0fabbcSTim J. Robbins #include <vm/vm.h> 64ea0fabbcSTim J. Robbins #include <vm/pmap.h> 65ea0fabbcSTim J. Robbins #include <vm/vm_extern.h> 66ea0fabbcSTim J. Robbins #include <vm/vm_map.h> 67ea0fabbcSTim J. Robbins #include <vm/vm_object.h> 68ea0fabbcSTim J. Robbins #include <vm/vm_page.h> 69ea0fabbcSTim J. Robbins #include <vm/vm_param.h> 70ea0fabbcSTim J. Robbins 71ea0fabbcSTim J. Robbins #include <machine/cpu.h> 72ea0fabbcSTim J. Robbins #include <machine/md_var.h> 736004362eSDavid Schultz #include <machine/pcb.h> 74ea0fabbcSTim J. Robbins #include <machine/specialreg.h> 75ea0fabbcSTim J. Robbins 76ea0fabbcSTim J. Robbins #include <amd64/linux32/linux.h> 77ea0fabbcSTim J. Robbins #include <amd64/linux32/linux32_proto.h> 787c09e6c0SAlexander Leidinger #include <compat/linux/linux_emul.h> 79ea0fabbcSTim J. Robbins #include <compat/linux/linux_mib.h> 80ea0fabbcSTim J. Robbins #include <compat/linux/linux_signal.h> 81ea0fabbcSTim J. Robbins #include <compat/linux/linux_util.h> 82ea0fabbcSTim J. Robbins 83ea0fabbcSTim J. Robbins MODULE_VERSION(linux, 1); 84ea0fabbcSTim J. Robbins 85ea0fabbcSTim J. Robbins MALLOC_DEFINE(M_LINUX, "linux", "Linux mode structures"); 86ea0fabbcSTim J. Robbins 87ea0fabbcSTim J. Robbins #define AUXARGS_ENTRY_32(pos, id, val) \ 88ea0fabbcSTim J. Robbins do { \ 89ea0fabbcSTim J. Robbins suword32(pos++, id); \ 90ea0fabbcSTim J. Robbins suword32(pos++, val); \ 91ea0fabbcSTim J. Robbins } while (0) 92ea0fabbcSTim J. Robbins 93ea0fabbcSTim J. Robbins #if BYTE_ORDER == LITTLE_ENDIAN 94ea0fabbcSTim J. Robbins #define SHELLMAGIC 0x2123 /* #! */ 95ea0fabbcSTim J. Robbins #else 96ea0fabbcSTim J. Robbins #define SHELLMAGIC 0x2321 97ea0fabbcSTim J. Robbins #endif 98ea0fabbcSTim J. Robbins 99ea0fabbcSTim J. Robbins /* 100ea0fabbcSTim J. Robbins * Allow the sendsig functions to use the ldebug() facility 101ea0fabbcSTim J. Robbins * even though they are not syscalls themselves. Map them 102ea0fabbcSTim J. Robbins * to syscall 0. This is slightly less bogus than using 103ea0fabbcSTim J. Robbins * ldebug(sigreturn). 104ea0fabbcSTim J. Robbins */ 105ea0fabbcSTim J. Robbins #define LINUX_SYS_linux_rt_sendsig 0 106ea0fabbcSTim J. Robbins #define LINUX_SYS_linux_sendsig 0 107ea0fabbcSTim J. Robbins 108ea0fabbcSTim J. Robbins extern char linux_sigcode[]; 109ea0fabbcSTim J. Robbins extern int linux_szsigcode; 110ea0fabbcSTim J. Robbins 111ea0fabbcSTim J. Robbins extern struct sysent linux_sysent[LINUX_SYS_MAXSYSCALL]; 112ea0fabbcSTim J. Robbins 113ea0fabbcSTim J. Robbins SET_DECLARE(linux_ioctl_handler_set, struct linux_ioctl_handler); 114387196bfSDoug Ambrisko SET_DECLARE(linux_device_handler_set, struct linux_device_handler); 115ea0fabbcSTim J. Robbins 116ea0fabbcSTim J. Robbins static int elf_linux_fixup(register_t **stack_base, 117ea0fabbcSTim J. Robbins struct image_params *iparams); 118ea0fabbcSTim J. Robbins static register_t *linux_copyout_strings(struct image_params *imgp); 119ea0fabbcSTim J. Robbins static void linux_prepsyscall(struct trapframe *tf, int *args, u_int *code, 120ea0fabbcSTim J. Robbins caddr_t *params); 1219104847fSDavid Xu static void linux_sendsig(sig_t catcher, ksiginfo_t *ksi, sigset_t *mask); 122ea0fabbcSTim J. Robbins static void exec_linux_setregs(struct thread *td, u_long entry, 123ea0fabbcSTim J. Robbins u_long stack, u_long ps_strings); 12419059a13SJohn Baldwin static void linux32_fixlimit(struct rlimit *rl, int which); 125ea0fabbcSTim J. Robbins 1267c09e6c0SAlexander Leidinger extern LIST_HEAD(futex_list, futex) futex_list; 127bb59e63fSAlexander Leidinger extern struct sx futex_sx; 1287c09e6c0SAlexander Leidinger 1297c09e6c0SAlexander Leidinger static eventhandler_tag linux_exit_tag; 1307c09e6c0SAlexander Leidinger static eventhandler_tag linux_schedtail_tag; 1317c09e6c0SAlexander Leidinger static eventhandler_tag linux_exec_tag; 1327c09e6c0SAlexander Leidinger 133ea0fabbcSTim J. Robbins /* 134ea0fabbcSTim J. Robbins * Linux syscalls return negative errno's, we do positive and map them 13550e422f0SAlexander Leidinger * Reference: 13650e422f0SAlexander Leidinger * FreeBSD: src/sys/sys/errno.h 13750e422f0SAlexander Leidinger * Linux: linux-2.6.17.8/include/asm-generic/errno-base.h 13850e422f0SAlexander Leidinger * linux-2.6.17.8/include/asm-generic/errno.h 139ea0fabbcSTim J. Robbins */ 140ea0fabbcSTim J. Robbins static int bsd_to_linux_errno[ELAST + 1] = { 141ea0fabbcSTim J. Robbins -0, -1, -2, -3, -4, -5, -6, -7, -8, -9, 142ea0fabbcSTim J. Robbins -10, -35, -12, -13, -14, -15, -16, -17, -18, -19, 143ea0fabbcSTim J. Robbins -20, -21, -22, -23, -24, -25, -26, -27, -28, -29, 144ea0fabbcSTim J. Robbins -30, -31, -32, -33, -34, -11,-115,-114, -88, -89, 145ea0fabbcSTim J. Robbins -90, -91, -92, -93, -94, -95, -96, -97, -98, -99, 146ea0fabbcSTim J. Robbins -100,-101,-102,-103,-104,-105,-106,-107,-108,-109, 147ea0fabbcSTim J. Robbins -110,-111, -40, -36,-112,-113, -39, -11, -87,-122, 148ea0fabbcSTim J. Robbins -116, -66, -6, -6, -6, -6, -6, -37, -38, -9, 14950e422f0SAlexander Leidinger -6, -6, -43, -42, -75,-125, -84, -95, -16, -74, 15050e422f0SAlexander Leidinger -72, -67, -71 151ea0fabbcSTim J. Robbins }; 152ea0fabbcSTim J. Robbins 153ea0fabbcSTim J. Robbins int bsd_to_linux_signal[LINUX_SIGTBLSZ] = { 154ea0fabbcSTim J. Robbins LINUX_SIGHUP, LINUX_SIGINT, LINUX_SIGQUIT, LINUX_SIGILL, 155ea0fabbcSTim J. Robbins LINUX_SIGTRAP, LINUX_SIGABRT, 0, LINUX_SIGFPE, 156ea0fabbcSTim J. Robbins LINUX_SIGKILL, LINUX_SIGBUS, LINUX_SIGSEGV, LINUX_SIGSYS, 157ea0fabbcSTim J. Robbins LINUX_SIGPIPE, LINUX_SIGALRM, LINUX_SIGTERM, LINUX_SIGURG, 158ea0fabbcSTim J. Robbins LINUX_SIGSTOP, LINUX_SIGTSTP, LINUX_SIGCONT, LINUX_SIGCHLD, 159ea0fabbcSTim J. Robbins LINUX_SIGTTIN, LINUX_SIGTTOU, LINUX_SIGIO, LINUX_SIGXCPU, 160ea0fabbcSTim J. Robbins LINUX_SIGXFSZ, LINUX_SIGVTALRM, LINUX_SIGPROF, LINUX_SIGWINCH, 161ea0fabbcSTim J. Robbins 0, LINUX_SIGUSR1, LINUX_SIGUSR2 162ea0fabbcSTim J. Robbins }; 163ea0fabbcSTim J. Robbins 164ea0fabbcSTim J. Robbins int linux_to_bsd_signal[LINUX_SIGTBLSZ] = { 165ea0fabbcSTim J. Robbins SIGHUP, SIGINT, SIGQUIT, SIGILL, 166ea0fabbcSTim J. Robbins SIGTRAP, SIGABRT, SIGBUS, SIGFPE, 167ea0fabbcSTim J. Robbins SIGKILL, SIGUSR1, SIGSEGV, SIGUSR2, 168ea0fabbcSTim J. Robbins SIGPIPE, SIGALRM, SIGTERM, SIGBUS, 169ea0fabbcSTim J. Robbins SIGCHLD, SIGCONT, SIGSTOP, SIGTSTP, 170ea0fabbcSTim J. Robbins SIGTTIN, SIGTTOU, SIGURG, SIGXCPU, 171ea0fabbcSTim J. Robbins SIGXFSZ, SIGVTALRM, SIGPROF, SIGWINCH, 172ea0fabbcSTim J. Robbins SIGIO, SIGURG, SIGSYS 173ea0fabbcSTim J. Robbins }; 174ea0fabbcSTim J. Robbins 175ea0fabbcSTim J. Robbins #define LINUX_T_UNKNOWN 255 176ea0fabbcSTim J. Robbins static int _bsd_to_linux_trapcode[] = { 177ea0fabbcSTim J. Robbins LINUX_T_UNKNOWN, /* 0 */ 178ea0fabbcSTim J. Robbins 6, /* 1 T_PRIVINFLT */ 179ea0fabbcSTim J. Robbins LINUX_T_UNKNOWN, /* 2 */ 180ea0fabbcSTim J. Robbins 3, /* 3 T_BPTFLT */ 181ea0fabbcSTim J. Robbins LINUX_T_UNKNOWN, /* 4 */ 182ea0fabbcSTim J. Robbins LINUX_T_UNKNOWN, /* 5 */ 183ea0fabbcSTim J. Robbins 16, /* 6 T_ARITHTRAP */ 184ea0fabbcSTim J. Robbins 254, /* 7 T_ASTFLT */ 185ea0fabbcSTim J. Robbins LINUX_T_UNKNOWN, /* 8 */ 186ea0fabbcSTim J. Robbins 13, /* 9 T_PROTFLT */ 187ea0fabbcSTim J. Robbins 1, /* 10 T_TRCTRAP */ 188ea0fabbcSTim J. Robbins LINUX_T_UNKNOWN, /* 11 */ 189ea0fabbcSTim J. Robbins 14, /* 12 T_PAGEFLT */ 190ea0fabbcSTim J. Robbins LINUX_T_UNKNOWN, /* 13 */ 191ea0fabbcSTim J. Robbins 17, /* 14 T_ALIGNFLT */ 192ea0fabbcSTim J. Robbins LINUX_T_UNKNOWN, /* 15 */ 193ea0fabbcSTim J. Robbins LINUX_T_UNKNOWN, /* 16 */ 194ea0fabbcSTim J. Robbins LINUX_T_UNKNOWN, /* 17 */ 195ea0fabbcSTim J. Robbins 0, /* 18 T_DIVIDE */ 196ea0fabbcSTim J. Robbins 2, /* 19 T_NMI */ 197ea0fabbcSTim J. Robbins 4, /* 20 T_OFLOW */ 198ea0fabbcSTim J. Robbins 5, /* 21 T_BOUND */ 199ea0fabbcSTim J. Robbins 7, /* 22 T_DNA */ 200ea0fabbcSTim J. Robbins 8, /* 23 T_DOUBLEFLT */ 201ea0fabbcSTim J. Robbins 9, /* 24 T_FPOPFLT */ 202ea0fabbcSTim J. Robbins 10, /* 25 T_TSSFLT */ 203ea0fabbcSTim J. Robbins 11, /* 26 T_SEGNPFLT */ 204ea0fabbcSTim J. Robbins 12, /* 27 T_STKFLT */ 205ea0fabbcSTim J. Robbins 18, /* 28 T_MCHK */ 206ea0fabbcSTim J. Robbins 19, /* 29 T_XMMFLT */ 207ea0fabbcSTim J. Robbins 15 /* 30 T_RESERVED */ 208ea0fabbcSTim J. Robbins }; 209ea0fabbcSTim J. Robbins #define bsd_to_linux_trapcode(code) \ 210ea0fabbcSTim J. Robbins ((code)<sizeof(_bsd_to_linux_trapcode)/sizeof(*_bsd_to_linux_trapcode)? \ 211ea0fabbcSTim J. Robbins _bsd_to_linux_trapcode[(code)]: \ 212ea0fabbcSTim J. Robbins LINUX_T_UNKNOWN) 213ea0fabbcSTim J. Robbins 214ea0fabbcSTim J. Robbins struct linux32_ps_strings { 215ea0fabbcSTim J. Robbins u_int32_t ps_argvstr; /* first of 0 or more argument strings */ 216f2c7668eSDavid Schultz u_int ps_nargvstr; /* the number of argument strings */ 217ea0fabbcSTim J. Robbins u_int32_t ps_envstr; /* first of 0 or more environment strings */ 218f2c7668eSDavid Schultz u_int ps_nenvstr; /* the number of environment strings */ 219ea0fabbcSTim J. Robbins }; 220ea0fabbcSTim J. Robbins 221ea0fabbcSTim J. Robbins /* 222ea0fabbcSTim J. Robbins * If FreeBSD & Linux have a difference of opinion about what a trap 223ea0fabbcSTim J. Robbins * means, deal with it here. 224ea0fabbcSTim J. Robbins * 225ea0fabbcSTim J. Robbins * MPSAFE 226ea0fabbcSTim J. Robbins */ 227ea0fabbcSTim J. Robbins static int 228ea0fabbcSTim J. Robbins translate_traps(int signal, int trap_code) 229ea0fabbcSTim J. Robbins { 230ea0fabbcSTim J. Robbins if (signal != SIGBUS) 231ea0fabbcSTim J. Robbins return signal; 232ea0fabbcSTim J. Robbins switch (trap_code) { 233ea0fabbcSTim J. Robbins case T_PROTFLT: 234ea0fabbcSTim J. Robbins case T_TSSFLT: 235ea0fabbcSTim J. Robbins case T_DOUBLEFLT: 236ea0fabbcSTim J. Robbins case T_PAGEFLT: 237ea0fabbcSTim J. Robbins return SIGSEGV; 238ea0fabbcSTim J. Robbins default: 239ea0fabbcSTim J. Robbins return signal; 240ea0fabbcSTim J. Robbins } 241ea0fabbcSTim J. Robbins } 242ea0fabbcSTim J. Robbins 243ea0fabbcSTim J. Robbins static int 244ea0fabbcSTim J. Robbins elf_linux_fixup(register_t **stack_base, struct image_params *imgp) 245ea0fabbcSTim J. Robbins { 246ea0fabbcSTim J. Robbins Elf32_Auxargs *args; 247ea0fabbcSTim J. Robbins Elf32_Addr *base; 248ea0fabbcSTim J. Robbins Elf32_Addr *pos; 249ea0fabbcSTim J. Robbins 2506617724cSJeff Roberson KASSERT(curthread->td_proc == imgp->proc, 251ea0fabbcSTim J. Robbins ("unsafe elf_linux_fixup(), should be curproc")); 252ea0fabbcSTim J. Robbins base = (Elf32_Addr *)*stack_base; 253ea0fabbcSTim J. Robbins args = (Elf32_Auxargs *)imgp->auxargs; 254610ecfe0SMaxim Sobolev pos = base + (imgp->args->argc + imgp->args->envc + 2); 255ea0fabbcSTim J. Robbins 256ea0fabbcSTim J. Robbins if (args->trace) 257ea0fabbcSTim J. Robbins AUXARGS_ENTRY_32(pos, AT_DEBUG, 1); 258ea0fabbcSTim J. Robbins if (args->execfd != -1) 259ea0fabbcSTim J. Robbins AUXARGS_ENTRY_32(pos, AT_EXECFD, args->execfd); 260ea0fabbcSTim J. Robbins AUXARGS_ENTRY_32(pos, AT_PHDR, args->phdr); 261ea0fabbcSTim J. Robbins AUXARGS_ENTRY_32(pos, AT_PHENT, args->phent); 262ea0fabbcSTim J. Robbins AUXARGS_ENTRY_32(pos, AT_PHNUM, args->phnum); 263ea0fabbcSTim J. Robbins AUXARGS_ENTRY_32(pos, AT_PAGESZ, args->pagesz); 264ea0fabbcSTim J. Robbins AUXARGS_ENTRY_32(pos, AT_FLAGS, args->flags); 265ea0fabbcSTim J. Robbins AUXARGS_ENTRY_32(pos, AT_ENTRY, args->entry); 266ea0fabbcSTim J. Robbins AUXARGS_ENTRY_32(pos, AT_BASE, args->base); 267ea0fabbcSTim J. Robbins AUXARGS_ENTRY_32(pos, AT_UID, imgp->proc->p_ucred->cr_ruid); 268ea0fabbcSTim J. Robbins AUXARGS_ENTRY_32(pos, AT_EUID, imgp->proc->p_ucred->cr_svuid); 269ea0fabbcSTim J. Robbins AUXARGS_ENTRY_32(pos, AT_GID, imgp->proc->p_ucred->cr_rgid); 270ea0fabbcSTim J. Robbins AUXARGS_ENTRY_32(pos, AT_EGID, imgp->proc->p_ucred->cr_svgid); 271ea0fabbcSTim J. Robbins AUXARGS_ENTRY_32(pos, AT_NULL, 0); 272ea0fabbcSTim J. Robbins 273ea0fabbcSTim J. Robbins free(imgp->auxargs, M_TEMP); 274ea0fabbcSTim J. Robbins imgp->auxargs = NULL; 275ea0fabbcSTim J. Robbins 276ea0fabbcSTim J. Robbins base--; 277610ecfe0SMaxim Sobolev suword32(base, (uint32_t)imgp->args->argc); 278ea0fabbcSTim J. Robbins *stack_base = (register_t *)base; 279ea0fabbcSTim J. Robbins return 0; 280ea0fabbcSTim J. Robbins } 281ea0fabbcSTim J. Robbins 282ea0fabbcSTim J. Robbins extern int _ucodesel, _ucode32sel, _udatasel; 283ea0fabbcSTim J. Robbins extern unsigned long linux_sznonrtsigcode; 284ea0fabbcSTim J. Robbins 285ea0fabbcSTim J. Robbins static void 2869104847fSDavid Xu linux_rt_sendsig(sig_t catcher, ksiginfo_t *ksi, sigset_t *mask) 287ea0fabbcSTim J. Robbins { 288ea0fabbcSTim J. Robbins struct thread *td = curthread; 289ea0fabbcSTim J. Robbins struct proc *p = td->td_proc; 290ea0fabbcSTim J. Robbins struct sigacts *psp; 291ea0fabbcSTim J. Robbins struct trapframe *regs; 292ea0fabbcSTim J. Robbins struct l_rt_sigframe *fp, frame; 293ea0fabbcSTim J. Robbins int oonstack; 2949104847fSDavid Xu int sig; 2959104847fSDavid Xu int code; 296ea0fabbcSTim J. Robbins 2979104847fSDavid Xu sig = ksi->ksi_signo; 2989104847fSDavid Xu code = ksi->ksi_code; 299ea0fabbcSTim J. Robbins PROC_LOCK_ASSERT(p, MA_OWNED); 300ea0fabbcSTim J. Robbins psp = p->p_sigacts; 301ea0fabbcSTim J. Robbins mtx_assert(&psp->ps_mtx, MA_OWNED); 302ea0fabbcSTim J. Robbins regs = td->td_frame; 303ea0fabbcSTim J. Robbins oonstack = sigonstack(regs->tf_rsp); 304ea0fabbcSTim J. Robbins 305ea0fabbcSTim J. Robbins #ifdef DEBUG 306ea0fabbcSTim J. Robbins if (ldebug(rt_sendsig)) 307728ef954SJohn Baldwin printf(ARGS(rt_sendsig, "%p, %d, %p, %u"), 308ea0fabbcSTim J. Robbins catcher, sig, (void*)mask, code); 309ea0fabbcSTim J. Robbins #endif 310ea0fabbcSTim J. Robbins /* 311ea0fabbcSTim J. Robbins * Allocate space for the signal handler context. 312ea0fabbcSTim J. Robbins */ 313ea0fabbcSTim J. Robbins if ((td->td_pflags & TDP_ALTSTACK) && !oonstack && 314ea0fabbcSTim J. Robbins SIGISMEMBER(psp->ps_sigonstack, sig)) { 315ea0fabbcSTim J. Robbins fp = (struct l_rt_sigframe *)(td->td_sigstk.ss_sp + 316ea0fabbcSTim J. Robbins td->td_sigstk.ss_size - sizeof(struct l_rt_sigframe)); 317ea0fabbcSTim J. Robbins } else 318ea0fabbcSTim J. Robbins fp = (struct l_rt_sigframe *)regs->tf_rsp - 1; 319ea0fabbcSTim J. Robbins mtx_unlock(&psp->ps_mtx); 320ea0fabbcSTim J. Robbins 321ea0fabbcSTim J. Robbins /* 322ea0fabbcSTim J. Robbins * Build the argument list for the signal handler. 323ea0fabbcSTim J. Robbins */ 324ea0fabbcSTim J. Robbins if (p->p_sysent->sv_sigtbl) 325ea0fabbcSTim J. Robbins if (sig <= p->p_sysent->sv_sigsize) 326ea0fabbcSTim J. Robbins sig = p->p_sysent->sv_sigtbl[_SIG_IDX(sig)]; 327ea0fabbcSTim J. Robbins 328ea0fabbcSTim J. Robbins bzero(&frame, sizeof(frame)); 329ea0fabbcSTim J. Robbins 330ea0fabbcSTim J. Robbins frame.sf_handler = PTROUT(catcher); 331ea0fabbcSTim J. Robbins frame.sf_sig = sig; 332ea0fabbcSTim J. Robbins frame.sf_siginfo = PTROUT(&fp->sf_si); 333ea0fabbcSTim J. Robbins frame.sf_ucontext = PTROUT(&fp->sf_sc); 334ea0fabbcSTim J. Robbins 335ea0fabbcSTim J. Robbins /* Fill in POSIX parts */ 336ea0fabbcSTim J. Robbins frame.sf_si.lsi_signo = sig; 337ea0fabbcSTim J. Robbins frame.sf_si.lsi_code = code; 3389104847fSDavid Xu frame.sf_si.lsi_addr = PTROUT(ksi->ksi_addr); 339ea0fabbcSTim J. Robbins 340ea0fabbcSTim J. Robbins /* 341ea0fabbcSTim J. Robbins * Build the signal context to be used by sigreturn. 342ea0fabbcSTim J. Robbins */ 343ea0fabbcSTim J. Robbins frame.sf_sc.uc_flags = 0; /* XXX ??? */ 344ea0fabbcSTim J. Robbins frame.sf_sc.uc_link = 0; /* XXX ??? */ 345ea0fabbcSTim J. Robbins 346ea0fabbcSTim J. Robbins frame.sf_sc.uc_stack.ss_sp = PTROUT(td->td_sigstk.ss_sp); 347ea0fabbcSTim J. Robbins frame.sf_sc.uc_stack.ss_size = td->td_sigstk.ss_size; 348ea0fabbcSTim J. Robbins frame.sf_sc.uc_stack.ss_flags = (td->td_pflags & TDP_ALTSTACK) 349ea0fabbcSTim J. Robbins ? ((oonstack) ? LINUX_SS_ONSTACK : 0) : LINUX_SS_DISABLE; 350ea0fabbcSTim J. Robbins PROC_UNLOCK(p); 351ea0fabbcSTim J. Robbins 352ea0fabbcSTim J. Robbins bsd_to_linux_sigset(mask, &frame.sf_sc.uc_sigmask); 353ea0fabbcSTim J. Robbins 354ea0fabbcSTim J. Robbins frame.sf_sc.uc_mcontext.sc_mask = frame.sf_sc.uc_sigmask.__bits[0]; 355ea0fabbcSTim J. Robbins frame.sf_sc.uc_mcontext.sc_gs = rgs(); 356ea0fabbcSTim J. Robbins frame.sf_sc.uc_mcontext.sc_fs = rfs(); 357ea0fabbcSTim J. Robbins __asm __volatile("movl %%es,%0" : 358ea0fabbcSTim J. Robbins "=rm" (frame.sf_sc.uc_mcontext.sc_es)); 359ea0fabbcSTim J. Robbins __asm __volatile("movl %%ds,%0" : 360ea0fabbcSTim J. Robbins "=rm" (frame.sf_sc.uc_mcontext.sc_ds)); 361ea0fabbcSTim J. Robbins frame.sf_sc.uc_mcontext.sc_edi = regs->tf_rdi; 362ea0fabbcSTim J. Robbins frame.sf_sc.uc_mcontext.sc_esi = regs->tf_rsi; 363ea0fabbcSTim J. Robbins frame.sf_sc.uc_mcontext.sc_ebp = regs->tf_rbp; 364ea0fabbcSTim J. Robbins frame.sf_sc.uc_mcontext.sc_ebx = regs->tf_rbx; 365ea0fabbcSTim J. Robbins frame.sf_sc.uc_mcontext.sc_edx = regs->tf_rdx; 366ea0fabbcSTim J. Robbins frame.sf_sc.uc_mcontext.sc_ecx = regs->tf_rcx; 367ea0fabbcSTim J. Robbins frame.sf_sc.uc_mcontext.sc_eax = regs->tf_rax; 368ea0fabbcSTim J. Robbins frame.sf_sc.uc_mcontext.sc_eip = regs->tf_rip; 369ea0fabbcSTim J. Robbins frame.sf_sc.uc_mcontext.sc_cs = regs->tf_cs; 370ea0fabbcSTim J. Robbins frame.sf_sc.uc_mcontext.sc_eflags = regs->tf_rflags; 371ea0fabbcSTim J. Robbins frame.sf_sc.uc_mcontext.sc_esp_at_signal = regs->tf_rsp; 372ea0fabbcSTim J. Robbins frame.sf_sc.uc_mcontext.sc_ss = regs->tf_ss; 373ea0fabbcSTim J. Robbins frame.sf_sc.uc_mcontext.sc_err = regs->tf_err; 37496a2b635SKonstantin Belousov frame.sf_sc.uc_mcontext.sc_cr2 = (u_int32_t)(uintptr_t)ksi->ksi_addr; 375ea0fabbcSTim J. Robbins frame.sf_sc.uc_mcontext.sc_trapno = bsd_to_linux_trapcode(code); 376ea0fabbcSTim J. Robbins 377ea0fabbcSTim J. Robbins #ifdef DEBUG 378ea0fabbcSTim J. Robbins if (ldebug(rt_sendsig)) 379c680f6b1SDavid E. O'Brien printf(LMSG("rt_sendsig flags: 0x%x, sp: %p, ss: 0x%lx, mask: 0x%x"), 380ea0fabbcSTim J. Robbins frame.sf_sc.uc_stack.ss_flags, td->td_sigstk.ss_sp, 381ea0fabbcSTim J. Robbins td->td_sigstk.ss_size, frame.sf_sc.uc_mcontext.sc_mask); 382ea0fabbcSTim J. Robbins #endif 383ea0fabbcSTim J. Robbins 384ea0fabbcSTim J. Robbins if (copyout(&frame, fp, sizeof(frame)) != 0) { 385ea0fabbcSTim J. Robbins /* 386ea0fabbcSTim J. Robbins * Process has trashed its stack; give it an illegal 387ea0fabbcSTim J. Robbins * instruction to halt it in its tracks. 388ea0fabbcSTim J. Robbins */ 389ea0fabbcSTim J. Robbins #ifdef DEBUG 390ea0fabbcSTim J. Robbins if (ldebug(rt_sendsig)) 391ea0fabbcSTim J. Robbins printf(LMSG("rt_sendsig: bad stack %p, oonstack=%x"), 392ea0fabbcSTim J. Robbins fp, oonstack); 393ea0fabbcSTim J. Robbins #endif 394ea0fabbcSTim J. Robbins PROC_LOCK(p); 395ea0fabbcSTim J. Robbins sigexit(td, SIGILL); 396ea0fabbcSTim J. Robbins } 397ea0fabbcSTim J. Robbins 398ea0fabbcSTim J. Robbins /* 399ea0fabbcSTim J. Robbins * Build context to run handler in. 400ea0fabbcSTim J. Robbins */ 401ea0fabbcSTim J. Robbins regs->tf_rsp = PTROUT(fp); 402ea0fabbcSTim J. Robbins regs->tf_rip = LINUX32_PS_STRINGS - *(p->p_sysent->sv_szsigcode) + 403ea0fabbcSTim J. Robbins linux_sznonrtsigcode; 40422eca0bfSKonstantin Belousov regs->tf_rflags &= ~(PSL_T | PSL_D); 405ea0fabbcSTim J. Robbins regs->tf_cs = _ucode32sel; 406ea0fabbcSTim J. Robbins regs->tf_ss = _udatasel; 407ea0fabbcSTim J. Robbins load_ds(_udatasel); 408ea0fabbcSTim J. Robbins td->td_pcb->pcb_ds = _udatasel; 409ea0fabbcSTim J. Robbins load_es(_udatasel); 410ea0fabbcSTim J. Robbins td->td_pcb->pcb_es = _udatasel; 4119c5b213eSJung-uk Kim /* leave user %fs and %gs untouched */ 412ea0fabbcSTim J. Robbins PROC_LOCK(p); 413ea0fabbcSTim J. Robbins mtx_lock(&psp->ps_mtx); 414ea0fabbcSTim J. Robbins } 415ea0fabbcSTim J. Robbins 416ea0fabbcSTim J. Robbins 417ea0fabbcSTim J. Robbins /* 418ea0fabbcSTim J. Robbins * Send an interrupt to process. 419ea0fabbcSTim J. Robbins * 420ea0fabbcSTim J. Robbins * Stack is set up to allow sigcode stored 421ea0fabbcSTim J. Robbins * in u. to call routine, followed by kcall 422ea0fabbcSTim J. Robbins * to sigreturn routine below. After sigreturn 423ea0fabbcSTim J. Robbins * resets the signal mask, the stack, and the 424ea0fabbcSTim J. Robbins * frame pointer, it returns to the user 425ea0fabbcSTim J. Robbins * specified pc, psl. 426ea0fabbcSTim J. Robbins */ 427ea0fabbcSTim J. Robbins static void 4289104847fSDavid Xu linux_sendsig(sig_t catcher, ksiginfo_t *ksi, sigset_t *mask) 429ea0fabbcSTim J. Robbins { 430ea0fabbcSTim J. Robbins struct thread *td = curthread; 431ea0fabbcSTim J. Robbins struct proc *p = td->td_proc; 432ea0fabbcSTim J. Robbins struct sigacts *psp; 433ea0fabbcSTim J. Robbins struct trapframe *regs; 434ea0fabbcSTim J. Robbins struct l_sigframe *fp, frame; 435ea0fabbcSTim J. Robbins l_sigset_t lmask; 436ea0fabbcSTim J. Robbins int oonstack, i; 4379104847fSDavid Xu int sig, code; 438ea0fabbcSTim J. Robbins 4399104847fSDavid Xu sig = ksi->ksi_signo; 4409104847fSDavid Xu code = ksi->ksi_code; 441ea0fabbcSTim J. Robbins PROC_LOCK_ASSERT(p, MA_OWNED); 442ea0fabbcSTim J. Robbins psp = p->p_sigacts; 443ea0fabbcSTim J. Robbins mtx_assert(&psp->ps_mtx, MA_OWNED); 444ea0fabbcSTim J. Robbins if (SIGISMEMBER(psp->ps_siginfo, sig)) { 445ea0fabbcSTim J. Robbins /* Signal handler installed with SA_SIGINFO. */ 4469104847fSDavid Xu linux_rt_sendsig(catcher, ksi, mask); 447ea0fabbcSTim J. Robbins return; 448ea0fabbcSTim J. Robbins } 449ea0fabbcSTim J. Robbins 450ea0fabbcSTim J. Robbins regs = td->td_frame; 451ea0fabbcSTim J. Robbins oonstack = sigonstack(regs->tf_rsp); 452ea0fabbcSTim J. Robbins 453ea0fabbcSTim J. Robbins #ifdef DEBUG 454ea0fabbcSTim J. Robbins if (ldebug(sendsig)) 455728ef954SJohn Baldwin printf(ARGS(sendsig, "%p, %d, %p, %u"), 456ea0fabbcSTim J. Robbins catcher, sig, (void*)mask, code); 457ea0fabbcSTim J. Robbins #endif 458ea0fabbcSTim J. Robbins 459ea0fabbcSTim J. Robbins /* 460ea0fabbcSTim J. Robbins * Allocate space for the signal handler context. 461ea0fabbcSTim J. Robbins */ 462ea0fabbcSTim J. Robbins if ((td->td_pflags & TDP_ALTSTACK) && !oonstack && 463ea0fabbcSTim J. Robbins SIGISMEMBER(psp->ps_sigonstack, sig)) { 464ea0fabbcSTim J. Robbins fp = (struct l_sigframe *)(td->td_sigstk.ss_sp + 465ea0fabbcSTim J. Robbins td->td_sigstk.ss_size - sizeof(struct l_sigframe)); 466ea0fabbcSTim J. Robbins } else 467ea0fabbcSTim J. Robbins fp = (struct l_sigframe *)regs->tf_rsp - 1; 468ea0fabbcSTim J. Robbins mtx_unlock(&psp->ps_mtx); 469ea0fabbcSTim J. Robbins PROC_UNLOCK(p); 470ea0fabbcSTim J. Robbins 471ea0fabbcSTim J. Robbins /* 472ea0fabbcSTim J. Robbins * Build the argument list for the signal handler. 473ea0fabbcSTim J. Robbins */ 474ea0fabbcSTim J. Robbins if (p->p_sysent->sv_sigtbl) 475ea0fabbcSTim J. Robbins if (sig <= p->p_sysent->sv_sigsize) 476ea0fabbcSTim J. Robbins sig = p->p_sysent->sv_sigtbl[_SIG_IDX(sig)]; 477ea0fabbcSTim J. Robbins 478ea0fabbcSTim J. Robbins bzero(&frame, sizeof(frame)); 479ea0fabbcSTim J. Robbins 480ea0fabbcSTim J. Robbins frame.sf_handler = PTROUT(catcher); 481ea0fabbcSTim J. Robbins frame.sf_sig = sig; 482ea0fabbcSTim J. Robbins 483ea0fabbcSTim J. Robbins bsd_to_linux_sigset(mask, &lmask); 484ea0fabbcSTim J. Robbins 485ea0fabbcSTim J. Robbins /* 486ea0fabbcSTim J. Robbins * Build the signal context to be used by sigreturn. 487ea0fabbcSTim J. Robbins */ 488ea0fabbcSTim J. Robbins frame.sf_sc.sc_mask = lmask.__bits[0]; 489ea0fabbcSTim J. Robbins frame.sf_sc.sc_gs = rgs(); 490ea0fabbcSTim J. Robbins frame.sf_sc.sc_fs = rfs(); 491ea0fabbcSTim J. Robbins __asm __volatile("movl %%es,%0" : "=rm" (frame.sf_sc.sc_es)); 492ea0fabbcSTim J. Robbins __asm __volatile("movl %%ds,%0" : "=rm" (frame.sf_sc.sc_ds)); 493ea0fabbcSTim J. Robbins frame.sf_sc.sc_edi = regs->tf_rdi; 494ea0fabbcSTim J. Robbins frame.sf_sc.sc_esi = regs->tf_rsi; 495ea0fabbcSTim J. Robbins frame.sf_sc.sc_ebp = regs->tf_rbp; 496ea0fabbcSTim J. Robbins frame.sf_sc.sc_ebx = regs->tf_rbx; 497ea0fabbcSTim J. Robbins frame.sf_sc.sc_edx = regs->tf_rdx; 498ea0fabbcSTim J. Robbins frame.sf_sc.sc_ecx = regs->tf_rcx; 499ea0fabbcSTim J. Robbins frame.sf_sc.sc_eax = regs->tf_rax; 500ea0fabbcSTim J. Robbins frame.sf_sc.sc_eip = regs->tf_rip; 501ea0fabbcSTim J. Robbins frame.sf_sc.sc_cs = regs->tf_cs; 502ea0fabbcSTim J. Robbins frame.sf_sc.sc_eflags = regs->tf_rflags; 503ea0fabbcSTim J. Robbins frame.sf_sc.sc_esp_at_signal = regs->tf_rsp; 504ea0fabbcSTim J. Robbins frame.sf_sc.sc_ss = regs->tf_ss; 505ea0fabbcSTim J. Robbins frame.sf_sc.sc_err = regs->tf_err; 50696a2b635SKonstantin Belousov frame.sf_sc.sc_cr2 = (u_int32_t)(uintptr_t)ksi->ksi_addr; 507ea0fabbcSTim J. Robbins frame.sf_sc.sc_trapno = bsd_to_linux_trapcode(code); 508ea0fabbcSTim J. Robbins 509ea0fabbcSTim J. Robbins for (i = 0; i < (LINUX_NSIG_WORDS-1); i++) 510ea0fabbcSTim J. Robbins frame.sf_extramask[i] = lmask.__bits[i+1]; 511ea0fabbcSTim J. Robbins 512ea0fabbcSTim J. Robbins if (copyout(&frame, fp, sizeof(frame)) != 0) { 513ea0fabbcSTim J. Robbins /* 514ea0fabbcSTim J. Robbins * Process has trashed its stack; give it an illegal 515ea0fabbcSTim J. Robbins * instruction to halt it in its tracks. 516ea0fabbcSTim J. Robbins */ 517ea0fabbcSTim J. Robbins PROC_LOCK(p); 518ea0fabbcSTim J. Robbins sigexit(td, SIGILL); 519ea0fabbcSTim J. Robbins } 520ea0fabbcSTim J. Robbins 521ea0fabbcSTim J. Robbins /* 522ea0fabbcSTim J. Robbins * Build context to run handler in. 523ea0fabbcSTim J. Robbins */ 524ea0fabbcSTim J. Robbins regs->tf_rsp = PTROUT(fp); 525ea0fabbcSTim J. Robbins regs->tf_rip = LINUX32_PS_STRINGS - *(p->p_sysent->sv_szsigcode); 52622eca0bfSKonstantin Belousov regs->tf_rflags &= ~(PSL_T | PSL_D); 527ea0fabbcSTim J. Robbins regs->tf_cs = _ucode32sel; 528ea0fabbcSTim J. Robbins regs->tf_ss = _udatasel; 529ea0fabbcSTim J. Robbins load_ds(_udatasel); 530ea0fabbcSTim J. Robbins td->td_pcb->pcb_ds = _udatasel; 531ea0fabbcSTim J. Robbins load_es(_udatasel); 532ea0fabbcSTim J. Robbins td->td_pcb->pcb_es = _udatasel; 5339c5b213eSJung-uk Kim /* leave user %fs and %gs untouched */ 534ea0fabbcSTim J. Robbins PROC_LOCK(p); 535ea0fabbcSTim J. Robbins mtx_lock(&psp->ps_mtx); 536ea0fabbcSTim J. Robbins } 537ea0fabbcSTim J. Robbins 538ea0fabbcSTim J. Robbins /* 539ea0fabbcSTim J. Robbins * System call to cleanup state after a signal 540ea0fabbcSTim J. Robbins * has been taken. Reset signal mask and 541ea0fabbcSTim J. Robbins * stack state from context left by sendsig (above). 542ea0fabbcSTim J. Robbins * Return to previous pc and psl as specified by 543ea0fabbcSTim J. Robbins * context left by sendsig. Check carefully to 544ea0fabbcSTim J. Robbins * make sure that the user has not modified the 545ea0fabbcSTim J. Robbins * psl to gain improper privileges or to cause 546ea0fabbcSTim J. Robbins * a machine fault. 547ea0fabbcSTim J. Robbins */ 548ea0fabbcSTim J. Robbins int 549ea0fabbcSTim J. Robbins linux_sigreturn(struct thread *td, struct linux_sigreturn_args *args) 550ea0fabbcSTim J. Robbins { 551ea0fabbcSTim J. Robbins struct proc *p = td->td_proc; 552ea0fabbcSTim J. Robbins struct l_sigframe frame; 553ea0fabbcSTim J. Robbins struct trapframe *regs; 554ea0fabbcSTim J. Robbins l_sigset_t lmask; 555ea0fabbcSTim J. Robbins int eflags, i; 5569104847fSDavid Xu ksiginfo_t ksi; 557ea0fabbcSTim J. Robbins 558ea0fabbcSTim J. Robbins regs = td->td_frame; 559ea0fabbcSTim J. Robbins 560ea0fabbcSTim J. Robbins #ifdef DEBUG 561ea0fabbcSTim J. Robbins if (ldebug(sigreturn)) 562ea0fabbcSTim J. Robbins printf(ARGS(sigreturn, "%p"), (void *)args->sfp); 563ea0fabbcSTim J. Robbins #endif 564ea0fabbcSTim J. Robbins /* 565ea0fabbcSTim J. Robbins * The trampoline code hands us the sigframe. 566ea0fabbcSTim J. Robbins * It is unsafe to keep track of it ourselves, in the event that a 567ea0fabbcSTim J. Robbins * program jumps out of a signal handler. 568ea0fabbcSTim J. Robbins */ 569ea0fabbcSTim J. Robbins if (copyin(args->sfp, &frame, sizeof(frame)) != 0) 570ea0fabbcSTim J. Robbins return (EFAULT); 571ea0fabbcSTim J. Robbins 572ea0fabbcSTim J. Robbins /* 573ea0fabbcSTim J. Robbins * Check for security violations. 574ea0fabbcSTim J. Robbins */ 575ea0fabbcSTim J. Robbins #define EFLAGS_SECURE(ef, oef) ((((ef) ^ (oef)) & ~PSL_USERCHANGE) == 0) 576ea0fabbcSTim J. Robbins eflags = frame.sf_sc.sc_eflags; 577ea0fabbcSTim J. Robbins /* 578ea0fabbcSTim J. Robbins * XXX do allow users to change the privileged flag PSL_RF. The 579ea0fabbcSTim J. Robbins * cpu sets PSL_RF in tf_eflags for faults. Debuggers should 580ea0fabbcSTim J. Robbins * sometimes set it there too. tf_eflags is kept in the signal 581ea0fabbcSTim J. Robbins * context during signal handling and there is no other place 582ea0fabbcSTim J. Robbins * to remember it, so the PSL_RF bit may be corrupted by the 583ea0fabbcSTim J. Robbins * signal handler without us knowing. Corruption of the PSL_RF 584ea0fabbcSTim J. Robbins * bit at worst causes one more or one less debugger trap, so 585ea0fabbcSTim J. Robbins * allowing it is fairly harmless. 586ea0fabbcSTim J. Robbins */ 587ea0fabbcSTim J. Robbins if (!EFLAGS_SECURE(eflags & ~PSL_RF, regs->tf_rflags & ~PSL_RF)) 588ea0fabbcSTim J. Robbins return(EINVAL); 589ea0fabbcSTim J. Robbins 590ea0fabbcSTim J. Robbins /* 591ea0fabbcSTim J. Robbins * Don't allow users to load a valid privileged %cs. Let the 592ea0fabbcSTim J. Robbins * hardware check for invalid selectors, excess privilege in 593ea0fabbcSTim J. Robbins * other selectors, invalid %eip's and invalid %esp's. 594ea0fabbcSTim J. Robbins */ 595ea0fabbcSTim J. Robbins #define CS_SECURE(cs) (ISPL(cs) == SEL_UPL) 596ea0fabbcSTim J. Robbins if (!CS_SECURE(frame.sf_sc.sc_cs)) { 5979104847fSDavid Xu ksiginfo_init_trap(&ksi); 5989104847fSDavid Xu ksi.ksi_signo = SIGBUS; 5999104847fSDavid Xu ksi.ksi_code = BUS_OBJERR; 6009104847fSDavid Xu ksi.ksi_trapno = T_PROTFLT; 6019104847fSDavid Xu ksi.ksi_addr = (void *)regs->tf_rip; 6029104847fSDavid Xu trapsignal(td, &ksi); 603ea0fabbcSTim J. Robbins return(EINVAL); 604ea0fabbcSTim J. Robbins } 605ea0fabbcSTim J. Robbins 606ea0fabbcSTim J. Robbins lmask.__bits[0] = frame.sf_sc.sc_mask; 607ea0fabbcSTim J. Robbins for (i = 0; i < (LINUX_NSIG_WORDS-1); i++) 608ea0fabbcSTim J. Robbins lmask.__bits[i+1] = frame.sf_extramask[i]; 609ea0fabbcSTim J. Robbins PROC_LOCK(p); 610ea0fabbcSTim J. Robbins linux_to_bsd_sigset(&lmask, &td->td_sigmask); 611ea0fabbcSTim J. Robbins SIG_CANTMASK(td->td_sigmask); 612ea0fabbcSTim J. Robbins signotify(td); 613ea0fabbcSTim J. Robbins PROC_UNLOCK(p); 614ea0fabbcSTim J. Robbins 615ea0fabbcSTim J. Robbins /* 616ea0fabbcSTim J. Robbins * Restore signal context. 617ea0fabbcSTim J. Robbins */ 618ea0fabbcSTim J. Robbins /* Selectors were restored by the trampoline. */ 619ea0fabbcSTim J. Robbins regs->tf_rdi = frame.sf_sc.sc_edi; 620ea0fabbcSTim J. Robbins regs->tf_rsi = frame.sf_sc.sc_esi; 621ea0fabbcSTim J. Robbins regs->tf_rbp = frame.sf_sc.sc_ebp; 622ea0fabbcSTim J. Robbins regs->tf_rbx = frame.sf_sc.sc_ebx; 623ea0fabbcSTim J. Robbins regs->tf_rdx = frame.sf_sc.sc_edx; 624ea0fabbcSTim J. Robbins regs->tf_rcx = frame.sf_sc.sc_ecx; 625ea0fabbcSTim J. Robbins regs->tf_rax = frame.sf_sc.sc_eax; 626ea0fabbcSTim J. Robbins regs->tf_rip = frame.sf_sc.sc_eip; 627ea0fabbcSTim J. Robbins regs->tf_cs = frame.sf_sc.sc_cs; 628ea0fabbcSTim J. Robbins regs->tf_rflags = eflags; 629ea0fabbcSTim J. Robbins regs->tf_rsp = frame.sf_sc.sc_esp_at_signal; 630ea0fabbcSTim J. Robbins regs->tf_ss = frame.sf_sc.sc_ss; 631ea0fabbcSTim J. Robbins 632ea0fabbcSTim J. Robbins return (EJUSTRETURN); 633ea0fabbcSTim J. Robbins } 634ea0fabbcSTim J. Robbins 635ea0fabbcSTim J. Robbins /* 636ea0fabbcSTim J. Robbins * System call to cleanup state after a signal 637ea0fabbcSTim J. Robbins * has been taken. Reset signal mask and 638ea0fabbcSTim J. Robbins * stack state from context left by rt_sendsig (above). 639ea0fabbcSTim J. Robbins * Return to previous pc and psl as specified by 640ea0fabbcSTim J. Robbins * context left by sendsig. Check carefully to 641ea0fabbcSTim J. Robbins * make sure that the user has not modified the 642ea0fabbcSTim J. Robbins * psl to gain improper privileges or to cause 643ea0fabbcSTim J. Robbins * a machine fault. 644ea0fabbcSTim J. Robbins */ 645ea0fabbcSTim J. Robbins int 646ea0fabbcSTim J. Robbins linux_rt_sigreturn(struct thread *td, struct linux_rt_sigreturn_args *args) 647ea0fabbcSTim J. Robbins { 648ea0fabbcSTim J. Robbins struct proc *p = td->td_proc; 649ea0fabbcSTim J. Robbins struct l_ucontext uc; 650ea0fabbcSTim J. Robbins struct l_sigcontext *context; 651ea0fabbcSTim J. Robbins l_stack_t *lss; 652ea0fabbcSTim J. Robbins stack_t ss; 653ea0fabbcSTim J. Robbins struct trapframe *regs; 654ea0fabbcSTim J. Robbins int eflags; 6559104847fSDavid Xu ksiginfo_t ksi; 656ea0fabbcSTim J. Robbins 657ea0fabbcSTim J. Robbins regs = td->td_frame; 658ea0fabbcSTim J. Robbins 659ea0fabbcSTim J. Robbins #ifdef DEBUG 660ea0fabbcSTim J. Robbins if (ldebug(rt_sigreturn)) 661ea0fabbcSTim J. Robbins printf(ARGS(rt_sigreturn, "%p"), (void *)args->ucp); 662ea0fabbcSTim J. Robbins #endif 663ea0fabbcSTim J. Robbins /* 664ea0fabbcSTim J. Robbins * The trampoline code hands us the ucontext. 665ea0fabbcSTim J. Robbins * It is unsafe to keep track of it ourselves, in the event that a 666ea0fabbcSTim J. Robbins * program jumps out of a signal handler. 667ea0fabbcSTim J. Robbins */ 668ea0fabbcSTim J. Robbins if (copyin(args->ucp, &uc, sizeof(uc)) != 0) 669ea0fabbcSTim J. Robbins return (EFAULT); 670ea0fabbcSTim J. Robbins 671ea0fabbcSTim J. Robbins context = &uc.uc_mcontext; 672ea0fabbcSTim J. Robbins 673ea0fabbcSTim J. Robbins /* 674ea0fabbcSTim J. Robbins * Check for security violations. 675ea0fabbcSTim J. Robbins */ 676ea0fabbcSTim J. Robbins #define EFLAGS_SECURE(ef, oef) ((((ef) ^ (oef)) & ~PSL_USERCHANGE) == 0) 677ea0fabbcSTim J. Robbins eflags = context->sc_eflags; 678ea0fabbcSTim J. Robbins /* 679ea0fabbcSTim J. Robbins * XXX do allow users to change the privileged flag PSL_RF. The 680ea0fabbcSTim J. Robbins * cpu sets PSL_RF in tf_eflags for faults. Debuggers should 681ea0fabbcSTim J. Robbins * sometimes set it there too. tf_eflags is kept in the signal 682ea0fabbcSTim J. Robbins * context during signal handling and there is no other place 683ea0fabbcSTim J. Robbins * to remember it, so the PSL_RF bit may be corrupted by the 684ea0fabbcSTim J. Robbins * signal handler without us knowing. Corruption of the PSL_RF 685ea0fabbcSTim J. Robbins * bit at worst causes one more or one less debugger trap, so 686ea0fabbcSTim J. Robbins * allowing it is fairly harmless. 687ea0fabbcSTim J. Robbins */ 688ea0fabbcSTim J. Robbins if (!EFLAGS_SECURE(eflags & ~PSL_RF, regs->tf_rflags & ~PSL_RF)) 689ea0fabbcSTim J. Robbins return(EINVAL); 690ea0fabbcSTim J. Robbins 691ea0fabbcSTim J. Robbins /* 692ea0fabbcSTim J. Robbins * Don't allow users to load a valid privileged %cs. Let the 693ea0fabbcSTim J. Robbins * hardware check for invalid selectors, excess privilege in 694ea0fabbcSTim J. Robbins * other selectors, invalid %eip's and invalid %esp's. 695ea0fabbcSTim J. Robbins */ 696ea0fabbcSTim J. Robbins #define CS_SECURE(cs) (ISPL(cs) == SEL_UPL) 697ea0fabbcSTim J. Robbins if (!CS_SECURE(context->sc_cs)) { 6989104847fSDavid Xu ksiginfo_init_trap(&ksi); 6999104847fSDavid Xu ksi.ksi_signo = SIGBUS; 7009104847fSDavid Xu ksi.ksi_code = BUS_OBJERR; 7019104847fSDavid Xu ksi.ksi_trapno = T_PROTFLT; 7029104847fSDavid Xu ksi.ksi_addr = (void *)regs->tf_rip; 7039104847fSDavid Xu trapsignal(td, &ksi); 704ea0fabbcSTim J. Robbins return(EINVAL); 705ea0fabbcSTim J. Robbins } 706ea0fabbcSTim J. Robbins 707ea0fabbcSTim J. Robbins PROC_LOCK(p); 708ea0fabbcSTim J. Robbins linux_to_bsd_sigset(&uc.uc_sigmask, &td->td_sigmask); 709ea0fabbcSTim J. Robbins SIG_CANTMASK(td->td_sigmask); 710ea0fabbcSTim J. Robbins signotify(td); 711ea0fabbcSTim J. Robbins PROC_UNLOCK(p); 712ea0fabbcSTim J. Robbins 713ea0fabbcSTim J. Robbins /* 714ea0fabbcSTim J. Robbins * Restore signal context 715ea0fabbcSTim J. Robbins */ 716ea0fabbcSTim J. Robbins /* Selectors were restored by the trampoline. */ 717ea0fabbcSTim J. Robbins regs->tf_rdi = context->sc_edi; 718ea0fabbcSTim J. Robbins regs->tf_rsi = context->sc_esi; 719ea0fabbcSTim J. Robbins regs->tf_rbp = context->sc_ebp; 720ea0fabbcSTim J. Robbins regs->tf_rbx = context->sc_ebx; 721ea0fabbcSTim J. Robbins regs->tf_rdx = context->sc_edx; 722ea0fabbcSTim J. Robbins regs->tf_rcx = context->sc_ecx; 723ea0fabbcSTim J. Robbins regs->tf_rax = context->sc_eax; 724ea0fabbcSTim J. Robbins regs->tf_rip = context->sc_eip; 725ea0fabbcSTim J. Robbins regs->tf_cs = context->sc_cs; 726ea0fabbcSTim J. Robbins regs->tf_rflags = eflags; 727ea0fabbcSTim J. Robbins regs->tf_rsp = context->sc_esp_at_signal; 728ea0fabbcSTim J. Robbins regs->tf_ss = context->sc_ss; 729ea0fabbcSTim J. Robbins 730ea0fabbcSTim J. Robbins /* 731ea0fabbcSTim J. Robbins * call sigaltstack & ignore results.. 732ea0fabbcSTim J. Robbins */ 733ea0fabbcSTim J. Robbins lss = &uc.uc_stack; 734ea0fabbcSTim J. Robbins ss.ss_sp = PTRIN(lss->ss_sp); 735ea0fabbcSTim J. Robbins ss.ss_size = lss->ss_size; 736ea0fabbcSTim J. Robbins ss.ss_flags = linux_to_bsd_sigaltstack(lss->ss_flags); 737ea0fabbcSTim J. Robbins 738ea0fabbcSTim J. Robbins #ifdef DEBUG 739ea0fabbcSTim J. Robbins if (ldebug(rt_sigreturn)) 740c680f6b1SDavid E. O'Brien printf(LMSG("rt_sigret flags: 0x%x, sp: %p, ss: 0x%lx, mask: 0x%x"), 741ea0fabbcSTim J. Robbins ss.ss_flags, ss.ss_sp, ss.ss_size, context->sc_mask); 742ea0fabbcSTim J. Robbins #endif 743ea0fabbcSTim J. Robbins (void)kern_sigaltstack(td, &ss, NULL); 744ea0fabbcSTim J. Robbins 745ea0fabbcSTim J. Robbins return (EJUSTRETURN); 746ea0fabbcSTim J. Robbins } 747ea0fabbcSTim J. Robbins 748ea0fabbcSTim J. Robbins /* 749ea0fabbcSTim J. Robbins * MPSAFE 750ea0fabbcSTim J. Robbins */ 751ea0fabbcSTim J. Robbins static void 752ea0fabbcSTim J. Robbins linux_prepsyscall(struct trapframe *tf, int *args, u_int *code, caddr_t *params) 753ea0fabbcSTim J. Robbins { 754ea0fabbcSTim J. Robbins args[0] = tf->tf_rbx; 755ea0fabbcSTim J. Robbins args[1] = tf->tf_rcx; 756ea0fabbcSTim J. Robbins args[2] = tf->tf_rdx; 757ea0fabbcSTim J. Robbins args[3] = tf->tf_rsi; 758ea0fabbcSTim J. Robbins args[4] = tf->tf_rdi; 759ea0fabbcSTim J. Robbins args[5] = tf->tf_rbp; /* Unconfirmed */ 760ea0fabbcSTim J. Robbins *params = NULL; /* no copyin */ 761ea0fabbcSTim J. Robbins } 762ea0fabbcSTim J. Robbins 763ea0fabbcSTim J. Robbins /* 764ea0fabbcSTim J. Robbins * If a linux binary is exec'ing something, try this image activator 765ea0fabbcSTim J. Robbins * first. We override standard shell script execution in order to 766ea0fabbcSTim J. Robbins * be able to modify the interpreter path. We only do this if a linux 767ea0fabbcSTim J. Robbins * binary is doing the exec, so we do not create an EXEC module for it. 768ea0fabbcSTim J. Robbins */ 769ea0fabbcSTim J. Robbins static int exec_linux_imgact_try(struct image_params *iparams); 770ea0fabbcSTim J. Robbins 771ea0fabbcSTim J. Robbins static int 772ea0fabbcSTim J. Robbins exec_linux_imgact_try(struct image_params *imgp) 773ea0fabbcSTim J. Robbins { 774ea0fabbcSTim J. Robbins const char *head = (const char *)imgp->image_header; 7751d15fdd9SJohn Baldwin char *rpath; 7761d15fdd9SJohn Baldwin int error = -1, len; 777ea0fabbcSTim J. Robbins 778ea0fabbcSTim J. Robbins /* 779ea0fabbcSTim J. Robbins * The interpreter for shell scripts run from a linux binary needs 780ea0fabbcSTim J. Robbins * to be located in /compat/linux if possible in order to recursively 781ea0fabbcSTim J. Robbins * maintain linux path emulation. 782ea0fabbcSTim J. Robbins */ 783ea0fabbcSTim J. Robbins if (((const short *)head)[0] == SHELLMAGIC) { 784ea0fabbcSTim J. Robbins /* 785ea0fabbcSTim J. Robbins * Run our normal shell image activator. If it succeeds attempt 786ea0fabbcSTim J. Robbins * to use the alternate path for the interpreter. If an alternate 787ea0fabbcSTim J. Robbins * path is found, use our stringspace to store it. 788ea0fabbcSTim J. Robbins */ 789ea0fabbcSTim J. Robbins if ((error = exec_shell_imgact(imgp)) == 0) { 7901d15fdd9SJohn Baldwin linux_emul_convpath(FIRST_THREAD_IN_PROC(imgp->proc), 7911d15fdd9SJohn Baldwin imgp->interpreter_name, UIO_SYSSPACE, &rpath, 0); 7921d15fdd9SJohn Baldwin if (rpath != NULL) { 7931d15fdd9SJohn Baldwin len = strlen(rpath) + 1; 794ea0fabbcSTim J. Robbins 795ea0fabbcSTim J. Robbins if (len <= MAXSHELLCMDLEN) { 796ea0fabbcSTim J. Robbins memcpy(imgp->interpreter_name, rpath, len); 797ea0fabbcSTim J. Robbins } 798ea0fabbcSTim J. Robbins free(rpath, M_TEMP); 799ea0fabbcSTim J. Robbins } 800ea0fabbcSTim J. Robbins } 801ea0fabbcSTim J. Robbins } 802ea0fabbcSTim J. Robbins return(error); 803ea0fabbcSTim J. Robbins } 804ea0fabbcSTim J. Robbins 805ea0fabbcSTim J. Robbins /* 806ea0fabbcSTim J. Robbins * Clear registers on exec 807ea0fabbcSTim J. Robbins * XXX copied from ia32_signal.c. 808ea0fabbcSTim J. Robbins */ 809ea0fabbcSTim J. Robbins static void 810ea0fabbcSTim J. Robbins exec_linux_setregs(td, entry, stack, ps_strings) 811ea0fabbcSTim J. Robbins struct thread *td; 812ea0fabbcSTim J. Robbins u_long entry; 813ea0fabbcSTim J. Robbins u_long stack; 814ea0fabbcSTim J. Robbins u_long ps_strings; 815ea0fabbcSTim J. Robbins { 816ea0fabbcSTim J. Robbins struct trapframe *regs = td->td_frame; 817ea0fabbcSTim J. Robbins struct pcb *pcb = td->td_pcb; 818ea0fabbcSTim J. Robbins 8199c5b213eSJung-uk Kim critical_enter(); 820ea0fabbcSTim J. Robbins wrmsr(MSR_FSBASE, 0); 821ea0fabbcSTim J. Robbins wrmsr(MSR_KGSBASE, 0); /* User value while we're in the kernel */ 822ea0fabbcSTim J. Robbins pcb->pcb_fsbase = 0; 823ea0fabbcSTim J. Robbins pcb->pcb_gsbase = 0; 8249c5b213eSJung-uk Kim critical_exit(); 825ea0fabbcSTim J. Robbins load_ds(_udatasel); 826ea0fabbcSTim J. Robbins load_es(_udatasel); 827ea0fabbcSTim J. Robbins load_fs(_udatasel); 8289c5b213eSJung-uk Kim load_gs(_udatasel); 829ea0fabbcSTim J. Robbins pcb->pcb_ds = _udatasel; 830ea0fabbcSTim J. Robbins pcb->pcb_es = _udatasel; 831ea0fabbcSTim J. Robbins pcb->pcb_fs = _udatasel; 8329c5b213eSJung-uk Kim pcb->pcb_gs = _udatasel; 833ea0fabbcSTim J. Robbins 834ea0fabbcSTim J. Robbins bzero((char *)regs, sizeof(struct trapframe)); 835ea0fabbcSTim J. Robbins regs->tf_rip = entry; 836ea0fabbcSTim J. Robbins regs->tf_rsp = stack; 837ea0fabbcSTim J. Robbins regs->tf_rflags = PSL_USER | (regs->tf_rflags & PSL_T); 838ea0fabbcSTim J. Robbins regs->tf_ss = _udatasel; 839ea0fabbcSTim J. Robbins regs->tf_cs = _ucode32sel; 840ea0fabbcSTim J. Robbins regs->tf_rbx = ps_strings; 841ea0fabbcSTim J. Robbins load_cr0(rcr0() | CR0_MP | CR0_TS); 8422a988f7cSStephan Uphoff fpstate_drop(td); 843ea0fabbcSTim J. Robbins 844ea0fabbcSTim J. Robbins /* Return via doreti so that we can change to a different %cs */ 845ea0fabbcSTim J. Robbins pcb->pcb_flags |= PCB_FULLCTX; 846ea0fabbcSTim J. Robbins td->td_retval[1] = 0; 847ea0fabbcSTim J. Robbins } 848ea0fabbcSTim J. Robbins 849ea0fabbcSTim J. Robbins /* 850ea0fabbcSTim J. Robbins * XXX copied from ia32_sysvec.c. 851ea0fabbcSTim J. Robbins */ 852ea0fabbcSTim J. Robbins static register_t * 853ea0fabbcSTim J. Robbins linux_copyout_strings(struct image_params *imgp) 854ea0fabbcSTim J. Robbins { 855ea0fabbcSTim J. Robbins int argc, envc; 856ea0fabbcSTim J. Robbins u_int32_t *vectp; 857ea0fabbcSTim J. Robbins char *stringp, *destp; 858ea0fabbcSTim J. Robbins u_int32_t *stack_base; 859ea0fabbcSTim J. Robbins struct linux32_ps_strings *arginfo; 860ea0fabbcSTim J. Robbins int sigcodesz; 861ea0fabbcSTim J. Robbins 862ea0fabbcSTim J. Robbins /* 863ea0fabbcSTim J. Robbins * Calculate string base and vector table pointers. 864ea0fabbcSTim J. Robbins * Also deal with signal trampoline code for this exec type. 865ea0fabbcSTim J. Robbins */ 866ea0fabbcSTim J. Robbins arginfo = (struct linux32_ps_strings *)LINUX32_PS_STRINGS; 867ea0fabbcSTim J. Robbins sigcodesz = *(imgp->proc->p_sysent->sv_szsigcode); 868ea0fabbcSTim J. Robbins destp = (caddr_t)arginfo - sigcodesz - SPARE_USRSPACE - 869610ecfe0SMaxim Sobolev roundup((ARG_MAX - imgp->args->stringspace), sizeof(char *)); 870ea0fabbcSTim J. Robbins 871ea0fabbcSTim J. Robbins /* 872ea0fabbcSTim J. Robbins * install sigcode 873ea0fabbcSTim J. Robbins */ 874ea0fabbcSTim J. Robbins if (sigcodesz) 875ea0fabbcSTim J. Robbins copyout(imgp->proc->p_sysent->sv_sigcode, 876d4d2a400SKonstantin Belousov ((caddr_t)arginfo - sigcodesz), sigcodesz); 877ea0fabbcSTim J. Robbins 878ea0fabbcSTim J. Robbins /* 879ea0fabbcSTim J. Robbins * If we have a valid auxargs ptr, prepare some room 880ea0fabbcSTim J. Robbins * on the stack. 881ea0fabbcSTim J. Robbins */ 882ea0fabbcSTim J. Robbins if (imgp->auxargs) { 883ea0fabbcSTim J. Robbins /* 884ea0fabbcSTim J. Robbins * 'AT_COUNT*2' is size for the ELF Auxargs data. This is for 885ea0fabbcSTim J. Robbins * lower compatibility. 886ea0fabbcSTim J. Robbins */ 887ea0fabbcSTim J. Robbins imgp->auxarg_size = (imgp->auxarg_size) ? imgp->auxarg_size 888ea0fabbcSTim J. Robbins : (AT_COUNT * 2); 889ea0fabbcSTim J. Robbins /* 890ea0fabbcSTim J. Robbins * The '+ 2' is for the null pointers at the end of each of 891ea0fabbcSTim J. Robbins * the arg and env vector sets,and imgp->auxarg_size is room 892ea0fabbcSTim J. Robbins * for argument of Runtime loader. 893ea0fabbcSTim J. Robbins */ 894610ecfe0SMaxim Sobolev vectp = (u_int32_t *) (destp - (imgp->args->argc + imgp->args->envc + 2 + 895ea0fabbcSTim J. Robbins imgp->auxarg_size) * sizeof(u_int32_t)); 896ea0fabbcSTim J. Robbins 897ea0fabbcSTim J. Robbins } else 898ea0fabbcSTim J. Robbins /* 899ea0fabbcSTim J. Robbins * The '+ 2' is for the null pointers at the end of each of 900ea0fabbcSTim J. Robbins * the arg and env vector sets 901ea0fabbcSTim J. Robbins */ 902ea0fabbcSTim J. Robbins vectp = (u_int32_t *) 903610ecfe0SMaxim Sobolev (destp - (imgp->args->argc + imgp->args->envc + 2) * sizeof(u_int32_t)); 904ea0fabbcSTim J. Robbins 905ea0fabbcSTim J. Robbins /* 906ea0fabbcSTim J. Robbins * vectp also becomes our initial stack base 907ea0fabbcSTim J. Robbins */ 908ea0fabbcSTim J. Robbins stack_base = vectp; 909ea0fabbcSTim J. Robbins 910610ecfe0SMaxim Sobolev stringp = imgp->args->begin_argv; 911610ecfe0SMaxim Sobolev argc = imgp->args->argc; 912610ecfe0SMaxim Sobolev envc = imgp->args->envc; 913ea0fabbcSTim J. Robbins /* 914ea0fabbcSTim J. Robbins * Copy out strings - arguments and environment. 915ea0fabbcSTim J. Robbins */ 916610ecfe0SMaxim Sobolev copyout(stringp, destp, ARG_MAX - imgp->args->stringspace); 917ea0fabbcSTim J. Robbins 918ea0fabbcSTim J. Robbins /* 919ea0fabbcSTim J. Robbins * Fill in "ps_strings" struct for ps, w, etc. 920ea0fabbcSTim J. Robbins */ 921ea0fabbcSTim J. Robbins suword32(&arginfo->ps_argvstr, (u_int32_t)(intptr_t)vectp); 922ea0fabbcSTim J. Robbins suword32(&arginfo->ps_nargvstr, argc); 923ea0fabbcSTim J. Robbins 924ea0fabbcSTim J. Robbins /* 925ea0fabbcSTim J. Robbins * Fill in argument portion of vector table. 926ea0fabbcSTim J. Robbins */ 927ea0fabbcSTim J. Robbins for (; argc > 0; --argc) { 928ea0fabbcSTim J. Robbins suword32(vectp++, (u_int32_t)(intptr_t)destp); 929ea0fabbcSTim J. Robbins while (*stringp++ != 0) 930ea0fabbcSTim J. Robbins destp++; 931ea0fabbcSTim J. Robbins destp++; 932ea0fabbcSTim J. Robbins } 933ea0fabbcSTim J. Robbins 934ea0fabbcSTim J. Robbins /* a null vector table pointer separates the argp's from the envp's */ 935ea0fabbcSTim J. Robbins suword32(vectp++, 0); 936ea0fabbcSTim J. Robbins 937ea0fabbcSTim J. Robbins suword32(&arginfo->ps_envstr, (u_int32_t)(intptr_t)vectp); 938ea0fabbcSTim J. Robbins suword32(&arginfo->ps_nenvstr, envc); 939ea0fabbcSTim J. Robbins 940ea0fabbcSTim J. Robbins /* 941ea0fabbcSTim J. Robbins * Fill in environment portion of vector table. 942ea0fabbcSTim J. Robbins */ 943ea0fabbcSTim J. Robbins for (; envc > 0; --envc) { 944ea0fabbcSTim J. Robbins suword32(vectp++, (u_int32_t)(intptr_t)destp); 945ea0fabbcSTim J. Robbins while (*stringp++ != 0) 946ea0fabbcSTim J. Robbins destp++; 947ea0fabbcSTim J. Robbins destp++; 948ea0fabbcSTim J. Robbins } 949ea0fabbcSTim J. Robbins 950ea0fabbcSTim J. Robbins /* end of vector table is a null pointer */ 951ea0fabbcSTim J. Robbins suword32(vectp, 0); 952ea0fabbcSTim J. Robbins 953ea0fabbcSTim J. Robbins return ((register_t *)stack_base); 954ea0fabbcSTim J. Robbins } 955ea0fabbcSTim J. Robbins 956ea0fabbcSTim J. Robbins SYSCTL_NODE(_compat, OID_AUTO, linux32, CTLFLAG_RW, 0, 957ea0fabbcSTim J. Robbins "32-bit Linux emulation"); 958ea0fabbcSTim J. Robbins 959ea0fabbcSTim J. Robbins static u_long linux32_maxdsiz = LINUX32_MAXDSIZ; 960ea0fabbcSTim J. Robbins SYSCTL_ULONG(_compat_linux32, OID_AUTO, maxdsiz, CTLFLAG_RW, 961ea0fabbcSTim J. Robbins &linux32_maxdsiz, 0, ""); 962ea0fabbcSTim J. Robbins static u_long linux32_maxssiz = LINUX32_MAXSSIZ; 963ea0fabbcSTim J. Robbins SYSCTL_ULONG(_compat_linux32, OID_AUTO, maxssiz, CTLFLAG_RW, 964ea0fabbcSTim J. Robbins &linux32_maxssiz, 0, ""); 965ea0fabbcSTim J. Robbins static u_long linux32_maxvmem = LINUX32_MAXVMEM; 966ea0fabbcSTim J. Robbins SYSCTL_ULONG(_compat_linux32, OID_AUTO, maxvmem, CTLFLAG_RW, 967ea0fabbcSTim J. Robbins &linux32_maxvmem, 0, ""); 968ea0fabbcSTim J. Robbins 969ea0fabbcSTim J. Robbins static void 97019059a13SJohn Baldwin linux32_fixlimit(struct rlimit *rl, int which) 971ea0fabbcSTim J. Robbins { 972ea0fabbcSTim J. Robbins 97319059a13SJohn Baldwin switch (which) { 97419059a13SJohn Baldwin case RLIMIT_DATA: 975ea0fabbcSTim J. Robbins if (linux32_maxdsiz != 0) { 97619059a13SJohn Baldwin if (rl->rlim_cur > linux32_maxdsiz) 97719059a13SJohn Baldwin rl->rlim_cur = linux32_maxdsiz; 97819059a13SJohn Baldwin if (rl->rlim_max > linux32_maxdsiz) 97919059a13SJohn Baldwin rl->rlim_max = linux32_maxdsiz; 980ea0fabbcSTim J. Robbins } 98119059a13SJohn Baldwin break; 98219059a13SJohn Baldwin case RLIMIT_STACK: 983ea0fabbcSTim J. Robbins if (linux32_maxssiz != 0) { 98419059a13SJohn Baldwin if (rl->rlim_cur > linux32_maxssiz) 98519059a13SJohn Baldwin rl->rlim_cur = linux32_maxssiz; 98619059a13SJohn Baldwin if (rl->rlim_max > linux32_maxssiz) 98719059a13SJohn Baldwin rl->rlim_max = linux32_maxssiz; 988ea0fabbcSTim J. Robbins } 98919059a13SJohn Baldwin break; 99019059a13SJohn Baldwin case RLIMIT_VMEM: 991ea0fabbcSTim J. Robbins if (linux32_maxvmem != 0) { 99219059a13SJohn Baldwin if (rl->rlim_cur > linux32_maxvmem) 99319059a13SJohn Baldwin rl->rlim_cur = linux32_maxvmem; 99419059a13SJohn Baldwin if (rl->rlim_max > linux32_maxvmem) 99519059a13SJohn Baldwin rl->rlim_max = linux32_maxvmem; 996ea0fabbcSTim J. Robbins } 99719059a13SJohn Baldwin break; 99819059a13SJohn Baldwin } 999ea0fabbcSTim J. Robbins } 1000ea0fabbcSTim J. Robbins 1001ea0fabbcSTim J. Robbins struct sysentvec elf_linux_sysvec = { 1002ea0fabbcSTim J. Robbins LINUX_SYS_MAXSYSCALL, 1003ea0fabbcSTim J. Robbins linux_sysent, 10049b44bfc5SAlexander Leidinger 0, 1005ea0fabbcSTim J. Robbins LINUX_SIGTBLSZ, 1006ea0fabbcSTim J. Robbins bsd_to_linux_signal, 1007ea0fabbcSTim J. Robbins ELAST + 1, 1008ea0fabbcSTim J. Robbins bsd_to_linux_errno, 1009ea0fabbcSTim J. Robbins translate_traps, 1010ea0fabbcSTim J. Robbins elf_linux_fixup, 1011ea0fabbcSTim J. Robbins linux_sendsig, 1012ea0fabbcSTim J. Robbins linux_sigcode, 1013ea0fabbcSTim J. Robbins &linux_szsigcode, 1014ea0fabbcSTim J. Robbins linux_prepsyscall, 1015ea0fabbcSTim J. Robbins "Linux ELF32", 1016ea0fabbcSTim J. Robbins elf32_coredump, 1017ea0fabbcSTim J. Robbins exec_linux_imgact_try, 1018ea0fabbcSTim J. Robbins LINUX_MINSIGSTKSZ, 1019ea0fabbcSTim J. Robbins PAGE_SIZE, 1020ea0fabbcSTim J. Robbins VM_MIN_ADDRESS, 1021ea0fabbcSTim J. Robbins LINUX32_USRSTACK, 1022ea0fabbcSTim J. Robbins LINUX32_USRSTACK, 1023ea0fabbcSTim J. Robbins LINUX32_PS_STRINGS, 1024ea0fabbcSTim J. Robbins VM_PROT_ALL, 1025ea0fabbcSTim J. Robbins linux_copyout_strings, 1026ea0fabbcSTim J. Robbins exec_linux_setregs, 102759d8f3ffSJohn Baldwin linux32_fixlimit, 102859d8f3ffSJohn Baldwin &linux32_maxssiz, 1029ea0fabbcSTim J. Robbins }; 1030ea0fabbcSTim J. Robbins 1031ea0fabbcSTim J. Robbins static Elf32_Brandinfo linux_brand = { 1032ea0fabbcSTim J. Robbins ELFOSABI_LINUX, 1033ea0fabbcSTim J. Robbins EM_386, 1034ea0fabbcSTim J. Robbins "Linux", 1035ea0fabbcSTim J. Robbins "/compat/linux", 1036ea0fabbcSTim J. Robbins "/lib/ld-linux.so.1", 1037ea0fabbcSTim J. Robbins &elf_linux_sysvec, 1038ea0fabbcSTim J. Robbins NULL, 1039900b28f9SMaxim Sobolev BI_CAN_EXEC_DYN, 1040ea0fabbcSTim J. Robbins }; 1041ea0fabbcSTim J. Robbins 1042ea0fabbcSTim J. Robbins static Elf32_Brandinfo linux_glibc2brand = { 1043ea0fabbcSTim J. Robbins ELFOSABI_LINUX, 1044ea0fabbcSTim J. Robbins EM_386, 1045ea0fabbcSTim J. Robbins "Linux", 1046ea0fabbcSTim J. Robbins "/compat/linux", 1047ea0fabbcSTim J. Robbins "/lib/ld-linux.so.2", 1048ea0fabbcSTim J. Robbins &elf_linux_sysvec, 1049ea0fabbcSTim J. Robbins NULL, 1050900b28f9SMaxim Sobolev BI_CAN_EXEC_DYN, 1051ea0fabbcSTim J. Robbins }; 1052ea0fabbcSTim J. Robbins 1053ea0fabbcSTim J. Robbins Elf32_Brandinfo *linux_brandlist[] = { 1054ea0fabbcSTim J. Robbins &linux_brand, 1055ea0fabbcSTim J. Robbins &linux_glibc2brand, 1056ea0fabbcSTim J. Robbins NULL 1057ea0fabbcSTim J. Robbins }; 1058ea0fabbcSTim J. Robbins 1059ea0fabbcSTim J. Robbins static int 1060ea0fabbcSTim J. Robbins linux_elf_modevent(module_t mod, int type, void *data) 1061ea0fabbcSTim J. Robbins { 1062ea0fabbcSTim J. Robbins Elf32_Brandinfo **brandinfo; 1063ea0fabbcSTim J. Robbins int error; 1064ea0fabbcSTim J. Robbins struct linux_ioctl_handler **lihp; 1065387196bfSDoug Ambrisko struct linux_device_handler **ldhp; 1066ea0fabbcSTim J. Robbins 1067ea0fabbcSTim J. Robbins error = 0; 1068ea0fabbcSTim J. Robbins 1069ea0fabbcSTim J. Robbins switch(type) { 1070ea0fabbcSTim J. Robbins case MOD_LOAD: 1071ea0fabbcSTim J. Robbins for (brandinfo = &linux_brandlist[0]; *brandinfo != NULL; 1072ea0fabbcSTim J. Robbins ++brandinfo) 1073ea0fabbcSTim J. Robbins if (elf32_insert_brand_entry(*brandinfo) < 0) 1074ea0fabbcSTim J. Robbins error = EINVAL; 1075ea0fabbcSTim J. Robbins if (error == 0) { 1076ea0fabbcSTim J. Robbins SET_FOREACH(lihp, linux_ioctl_handler_set) 1077ea0fabbcSTim J. Robbins linux_ioctl_register_handler(*lihp); 1078387196bfSDoug Ambrisko SET_FOREACH(ldhp, linux_device_handler_set) 1079387196bfSDoug Ambrisko linux_device_register_handler(*ldhp); 1080357afa71SJung-uk Kim mtx_init(&emul_lock, "emuldata lock", NULL, MTX_DEF); 10817c09e6c0SAlexander Leidinger sx_init(&emul_shared_lock, "emuldata->shared lock"); 10827c09e6c0SAlexander Leidinger LIST_INIT(&futex_list); 1083bb59e63fSAlexander Leidinger sx_init(&futex_sx, "futex protection lock"); 10847c09e6c0SAlexander Leidinger linux_exit_tag = EVENTHANDLER_REGISTER(process_exit, linux_proc_exit, 10857c09e6c0SAlexander Leidinger NULL, 1000); 10867c09e6c0SAlexander Leidinger linux_schedtail_tag = EVENTHANDLER_REGISTER(schedtail, linux_schedtail, 10877c09e6c0SAlexander Leidinger NULL, 1000); 10887c09e6c0SAlexander Leidinger linux_exec_tag = EVENTHANDLER_REGISTER(process_exec, linux_proc_exec, 10897c09e6c0SAlexander Leidinger NULL, 1000); 1090ea0fabbcSTim J. Robbins if (bootverbose) 1091ea0fabbcSTim J. Robbins printf("Linux ELF exec handler installed\n"); 1092ea0fabbcSTim J. Robbins } else 1093ea0fabbcSTim J. Robbins printf("cannot insert Linux ELF brand handler\n"); 1094ea0fabbcSTim J. Robbins break; 1095ea0fabbcSTim J. Robbins case MOD_UNLOAD: 1096ea0fabbcSTim J. Robbins for (brandinfo = &linux_brandlist[0]; *brandinfo != NULL; 1097ea0fabbcSTim J. Robbins ++brandinfo) 1098ea0fabbcSTim J. Robbins if (elf32_brand_inuse(*brandinfo)) 1099ea0fabbcSTim J. Robbins error = EBUSY; 1100ea0fabbcSTim J. Robbins if (error == 0) { 1101ea0fabbcSTim J. Robbins for (brandinfo = &linux_brandlist[0]; 1102ea0fabbcSTim J. Robbins *brandinfo != NULL; ++brandinfo) 1103ea0fabbcSTim J. Robbins if (elf32_remove_brand_entry(*brandinfo) < 0) 1104ea0fabbcSTim J. Robbins error = EINVAL; 1105ea0fabbcSTim J. Robbins } 1106ea0fabbcSTim J. Robbins if (error == 0) { 1107ea0fabbcSTim J. Robbins SET_FOREACH(lihp, linux_ioctl_handler_set) 1108ea0fabbcSTim J. Robbins linux_ioctl_unregister_handler(*lihp); 1109387196bfSDoug Ambrisko SET_FOREACH(ldhp, linux_device_handler_set) 1110387196bfSDoug Ambrisko linux_device_unregister_handler(*ldhp); 1111357afa71SJung-uk Kim mtx_destroy(&emul_lock); 11127c09e6c0SAlexander Leidinger sx_destroy(&emul_shared_lock); 1113bb59e63fSAlexander Leidinger sx_destroy(&futex_sx); 11147c09e6c0SAlexander Leidinger EVENTHANDLER_DEREGISTER(process_exit, linux_exit_tag); 11157c09e6c0SAlexander Leidinger EVENTHANDLER_DEREGISTER(schedtail, linux_schedtail_tag); 11167c09e6c0SAlexander Leidinger EVENTHANDLER_DEREGISTER(process_exec, linux_exec_tag); 1117ea0fabbcSTim J. Robbins if (bootverbose) 1118ea0fabbcSTim J. Robbins printf("Linux ELF exec handler removed\n"); 1119ea0fabbcSTim J. Robbins } else 1120ea0fabbcSTim J. Robbins printf("Could not deinstall ELF interpreter entry\n"); 1121ea0fabbcSTim J. Robbins break; 1122ea0fabbcSTim J. Robbins default: 1123786e4fc4SAlexander Leidinger return EOPNOTSUPP; 1124ea0fabbcSTim J. Robbins } 1125ea0fabbcSTim J. Robbins return error; 1126ea0fabbcSTim J. Robbins } 1127ea0fabbcSTim J. Robbins 1128ea0fabbcSTim J. Robbins static moduledata_t linux_elf_mod = { 1129ea0fabbcSTim J. Robbins "linuxelf", 1130ea0fabbcSTim J. Robbins linux_elf_modevent, 1131ea0fabbcSTim J. Robbins 0 1132ea0fabbcSTim J. Robbins }; 1133ea0fabbcSTim J. Robbins 1134ea0fabbcSTim J. Robbins DECLARE_MODULE(linuxelf, linux_elf_mod, SI_SUB_EXEC, SI_ORDER_ANY); 1135