The Design and Implementation of the FreeBSD Operating System, Second Edition
Now available: The Design and Implementation of the FreeBSD Operating System (Second Edition)


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]

FreeBSD/Linux Kernel Cross Reference
sys/i386/linux/linux_sysvec.c

Version: -  FREEBSD  -  FREEBSD-13-STABLE  -  FREEBSD-13-0  -  FREEBSD-12-STABLE  -  FREEBSD-12-0  -  FREEBSD-11-STABLE  -  FREEBSD-11-0  -  FREEBSD-10-STABLE  -  FREEBSD-10-0  -  FREEBSD-9-STABLE  -  FREEBSD-9-0  -  FREEBSD-8-STABLE  -  FREEBSD-8-0  -  FREEBSD-7-STABLE  -  FREEBSD-7-0  -  FREEBSD-6-STABLE  -  FREEBSD-6-0  -  FREEBSD-5-STABLE  -  FREEBSD-5-0  -  FREEBSD-4-STABLE  -  FREEBSD-3-STABLE  -  FREEBSD22  -  l41  -  OPENBSD  -  linux-2.6  -  MK84  -  PLAN9  -  xnu-8792 
SearchContext: -  none  -  3  -  10 

    1 /*-
    2  * Copyright (c) 1994-1996 Søren Schmidt
    3  * All rights reserved.
    4  *
    5  * Redistribution and use in source and binary forms, with or without
    6  * modification, are permitted provided that the following conditions
    7  * are met:
    8  * 1. Redistributions of source code must retain the above copyright
    9  *    notice, this list of conditions and the following disclaimer 
   10  *    in this position and unchanged.
   11  * 2. Redistributions in binary form must reproduce the above copyright
   12  *    notice, this list of conditions and the following disclaimer in the
   13  *    documentation and/or other materials provided with the distribution.
   14  * 3. The name of the author may not be used to endorse or promote products
   15  *    derived from this software withough specific prior written permission
   16  *
   17  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
   18  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
   19  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
   20  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
   21  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
   22  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
   23  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
   24  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
   25  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
   26  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
   27  *
   28  * $FreeBSD$
   29  */
   30 
   31 /* XXX we use functions that might not exist. */
   32 #include "opt_compat.h"
   33 
   34 #ifndef COMPAT_43
   35 #error "Unable to compile Linux-emulator due to missing COMPAT_43 option!"
   36 #endif
   37 
   38 #include <sys/param.h>
   39 #include <sys/buf.h>
   40 #include <sys/proc.h>
   41 #include <sys/systm.h>
   42 #include <sys/sysent.h>
   43 #include <sys/imgact.h>
   44 #include <sys/imgact_aout.h>
   45 #include <sys/imgact_elf.h>
   46 #include <sys/signalvar.h>
   47 #include <sys/malloc.h>
   48 #include <vm/vm.h>
   49 #include <vm/vm_param.h>
   50 #include <vm/vm_prot.h>
   51 #include <vm/vm_page.h>
   52 #include <vm/vm_extern.h>
   53 #include <sys/exec.h>
   54 #include <sys/kernel.h>
   55 #include <sys/module.h>
   56 #include <machine/cpu.h>
   57 
   58 #include <i386/linux/linux.h>
   59 #include <i386/linux/linux_proto.h>
   60 
   61 static int      linux_fixup __P((long **stack_base,
   62                                  struct image_params *iparams));
   63 static int      elf_linux_fixup __P((long **stack_base,
   64                                      struct image_params *iparams));
   65 static void     linux_prepsyscall __P((struct trapframe *tf, int *args,
   66                                        u_int *code, caddr_t *params));
   67 static void     linux_sendsig __P((sig_t catcher, int sig, int mask,
   68                                    u_long code));
   69 
   70 /*
   71  * Linux syscalls return negative errno's, we do positive and map them
   72  */
   73 static int bsd_to_linux_errno[ELAST + 1] = {
   74         -0,  -1,  -2,  -3,  -4,  -5,  -6,  -7,  -8,  -9,
   75         -10, -35, -12, -13, -14, -15, -16, -17, -18, -19,
   76         -20, -21, -22, -23, -24, -25, -26, -27, -28, -29,
   77         -30, -31, -32, -33, -34, -11,-115,-114, -88, -89,
   78         -90, -91, -92, -93, -94, -95, -96, -97, -98, -99,
   79         -100,-101,-102,-103,-104,-105,-106,-107,-108,-109,
   80         -110,-111, -40, -36,-112,-113, -39, -11, -87,-122,
   81         -116, -66,  -6,  -6,  -6,  -6,  -6, -37, -38,  -9,
   82         -6, -6, -43, -42, -75, -6, -84
   83 };
   84 
   85 int bsd_to_linux_signal[NSIG] = {
   86         0, LINUX_SIGHUP, LINUX_SIGINT, LINUX_SIGQUIT,
   87         LINUX_SIGILL, LINUX_SIGTRAP, LINUX_SIGABRT, 0,
   88         LINUX_SIGFPE, LINUX_SIGKILL, LINUX_SIGBUS, LINUX_SIGSEGV, 
   89         0, LINUX_SIGPIPE, LINUX_SIGALRM, LINUX_SIGTERM,
   90         LINUX_SIGURG, LINUX_SIGSTOP, LINUX_SIGTSTP, LINUX_SIGCONT,      
   91         LINUX_SIGCHLD, LINUX_SIGTTIN, LINUX_SIGTTOU, LINUX_SIGIO, 
   92         LINUX_SIGXCPU, LINUX_SIGXFSZ, LINUX_SIGVTALRM, LINUX_SIGPROF, 
   93         LINUX_SIGWINCH, 0, LINUX_SIGUSR1, LINUX_SIGUSR2
   94 };
   95 
   96 int linux_to_bsd_signal[LINUX_NSIG] = {
   97         0, SIGHUP, SIGINT, SIGQUIT, SIGILL, SIGTRAP, SIGABRT, SIGBUS,
   98         SIGFPE, SIGKILL, SIGUSR1, SIGSEGV, SIGUSR2, SIGPIPE, SIGALRM, SIGTERM, 
   99         SIGBUS, SIGCHLD, SIGCONT, SIGSTOP, SIGTSTP, SIGTTIN, SIGTTOU, SIGURG,
  100         SIGXCPU, SIGXFSZ, SIGVTALRM, SIGPROF, SIGWINCH, SIGIO, SIGURG, 0
  101 };
  102 
  103 /*
  104  * If FreeBSD & Linux have a difference of opinion about what a trap
  105  * means, deal with it here.
  106  */
  107 static int
  108 translate_traps(int signal, int trap_code)
  109 {
  110         if (signal != SIGBUS)
  111                 return signal;
  112         switch (trap_code) {
  113         case T_PROTFLT:
  114         case T_TSSFLT:
  115         case T_DOUBLEFLT:
  116         case T_PAGEFLT:
  117                 return SIGSEGV;
  118         default:
  119                 return signal;
  120         }
  121 }
  122 
  123 static int
  124 linux_fixup(long **stack_base, struct image_params *imgp)
  125 {
  126         long *argv, *envp;
  127 
  128         argv = *stack_base;
  129         envp = *stack_base + (imgp->argc + 1);
  130         (*stack_base)--;
  131         **stack_base = (intptr_t)(void *)envp;
  132         (*stack_base)--;
  133         **stack_base = (intptr_t)(void *)argv;
  134         (*stack_base)--;
  135         **stack_base = imgp->argc;
  136         return 0;
  137 }
  138 
  139 static int
  140 elf_linux_fixup(long **stack_base, struct image_params *imgp)
  141 {
  142         Elf32_Auxargs *args = (Elf32_Auxargs *)imgp->auxargs;
  143         long *pos;
  144              
  145         pos = *stack_base + (imgp->argc + imgp->envc + 2);  
  146     
  147         if (args->trace) {
  148                 AUXARGS_ENTRY(pos, AT_DEBUG, 1);
  149         }
  150         if (args->execfd != -1) {
  151                 AUXARGS_ENTRY(pos, AT_EXECFD, args->execfd);
  152         }       
  153         AUXARGS_ENTRY(pos, AT_PHDR, args->phdr);
  154         AUXARGS_ENTRY(pos, AT_PHENT, args->phent);
  155         AUXARGS_ENTRY(pos, AT_PHNUM, args->phnum);
  156         AUXARGS_ENTRY(pos, AT_PAGESZ, args->pagesz);
  157         AUXARGS_ENTRY(pos, AT_FLAGS, args->flags);
  158         AUXARGS_ENTRY(pos, AT_ENTRY, args->entry);
  159         AUXARGS_ENTRY(pos, AT_BASE, args->base);
  160         AUXARGS_ENTRY(pos, AT_UID, imgp->proc->p_cred->p_ruid);
  161         AUXARGS_ENTRY(pos, AT_EUID, imgp->proc->p_cred->p_svuid);
  162         AUXARGS_ENTRY(pos, AT_GID, imgp->proc->p_cred->p_rgid);
  163         AUXARGS_ENTRY(pos, AT_EGID, imgp->proc->p_cred->p_svgid);
  164         AUXARGS_ENTRY(pos, AT_NULL, 0);
  165         
  166         free(imgp->auxargs, M_TEMP);      
  167         imgp->auxargs = NULL;
  168 
  169         (*stack_base)--;
  170         **stack_base = (long)imgp->argc;
  171         return 0;
  172 }
  173 
  174 extern int _ucodesel, _udatasel;
  175 
  176 /*
  177  * Send an interrupt to process.
  178  *
  179  * Stack is set up to allow sigcode stored
  180  * in u. to call routine, followed by kcall
  181  * to sigreturn routine below.  After sigreturn
  182  * resets the signal mask, the stack, and the
  183  * frame pointer, it returns to the user
  184  * specified pc, psl.
  185  */
  186 
  187 static void
  188 linux_sendsig(sig_t catcher, int sig, int mask, u_long code)
  189 {
  190         register struct proc *p = curproc;
  191         register struct trapframe *regs;
  192         struct linux_sigframe *fp, frame;
  193         struct sigacts *psp = p->p_sigacts;
  194         int oonstack;
  195 
  196         regs = p->p_md.md_regs;
  197         oonstack = psp->ps_sigstk.ss_flags & SS_ONSTACK;
  198 
  199 #ifdef DEBUG
  200         printf("Linux-emul(%ld): linux_sendsig(%p, %d, %d, %lu)\n",
  201             (long)p->p_pid, catcher, sig, mask, code);
  202 #endif
  203         /*
  204          * Allocate space for the signal handler context.
  205          */
  206         if ((psp->ps_flags & SAS_ALTSTACK) && !oonstack &&
  207             (psp->ps_sigonstack & sigmask(sig))) {
  208                 fp = (struct linux_sigframe *)(psp->ps_sigstk.ss_sp +
  209                     psp->ps_sigstk.ss_size - sizeof(struct linux_sigframe));
  210                 psp->ps_sigstk.ss_flags |= SS_ONSTACK;
  211         } else {
  212                 fp = (struct linux_sigframe *)regs->tf_esp - 1;
  213         }
  214 
  215         /*
  216          * grow() will return FALSE if the fp will not fit inside the stack
  217          *      and the stack can not be grown. useracc will return FALSE
  218          *      if access is denied.
  219          */
  220 #ifdef VM_STACK
  221         if ((grow_stack (p, (int)fp) == FALSE) ||
  222 #else
  223         if ((grow(p, (int)fp) == FALSE) ||
  224 #endif 
  225             (useracc((caddr_t)fp, sizeof (struct linux_sigframe), B_WRITE) == FALSE)) {
  226                 /*
  227                  * Process has trashed its stack; give it an illegal
  228                  * instruction to halt it in its tracks.
  229                  */
  230                 SIGACTION(p, SIGILL) = SIG_DFL;
  231                 sig = sigmask(SIGILL);
  232                 p->p_sigignore &= ~sig;
  233                 p->p_sigcatch &= ~sig;
  234                 p->p_sigmask &= ~sig;
  235                 psignal(p, SIGILL);
  236                 return;
  237         }
  238 
  239         /*
  240          * Build the argument list for the signal handler.
  241          */
  242         if (p->p_sysent->sv_sigtbl) {
  243                 if (sig < p->p_sysent->sv_sigsize)
  244                         sig = p->p_sysent->sv_sigtbl[sig];
  245                 else
  246                         sig = p->p_sysent->sv_sigsize + 1;
  247         }
  248 
  249         frame.sf_handler = catcher;
  250         frame.sf_sig = sig;
  251 
  252         /*
  253          * Build the signal context to be used by sigreturn.
  254          */
  255         frame.sf_sc.sc_mask   = mask;
  256         __asm("movl %%gs,%w0" : "=r" (frame.sf_sc.sc_gs));
  257         __asm("movl %%fs,%w0" : "=r" (frame.sf_sc.sc_fs));
  258         frame.sf_sc.sc_es     = regs->tf_es;
  259         frame.sf_sc.sc_ds     = regs->tf_ds;
  260         frame.sf_sc.sc_edi    = regs->tf_edi;
  261         frame.sf_sc.sc_esi    = regs->tf_esi;
  262         frame.sf_sc.sc_ebp    = regs->tf_ebp;
  263         frame.sf_sc.sc_ebx    = regs->tf_ebx;
  264         frame.sf_sc.sc_edx    = regs->tf_edx;
  265         frame.sf_sc.sc_ecx    = regs->tf_ecx;
  266         frame.sf_sc.sc_eax    = regs->tf_eax;
  267         frame.sf_sc.sc_eip    = regs->tf_eip;
  268         frame.sf_sc.sc_cs     = regs->tf_cs;
  269         frame.sf_sc.sc_eflags = regs->tf_eflags;
  270         frame.sf_sc.sc_esp_at_signal = regs->tf_esp;
  271         frame.sf_sc.sc_ss     = regs->tf_ss;
  272         frame.sf_sc.sc_err    = regs->tf_err;
  273         frame.sf_sc.sc_trapno = code;   /* XXX ???? */
  274 
  275         if (copyout(&frame, fp, sizeof(frame)) != 0) {
  276                 /*
  277                  * Process has trashed its stack; give it an illegal
  278                  * instruction to halt it in its tracks.
  279                  */
  280                 sigexit(p, SIGILL);
  281                 /* NOTREACHED */
  282         }
  283 
  284         /*
  285          * Build context to run handler in.
  286          */
  287         regs->tf_esp = (int)fp;
  288         regs->tf_eip = PS_STRINGS - *(p->p_sysent->sv_szsigcode);
  289         regs->tf_eflags &= ~PSL_VM;
  290         regs->tf_cs = _ucodesel;
  291         regs->tf_ds = _udatasel;
  292         regs->tf_es = _udatasel;
  293         regs->tf_ss = _udatasel;
  294 }
  295 
  296 /*
  297  * System call to cleanup state after a signal
  298  * has been taken.  Reset signal mask and
  299  * stack state from context left by sendsig (above).
  300  * Return to previous pc and psl as specified by
  301  * context left by sendsig. Check carefully to
  302  * make sure that the user has not modified the
  303  * psl to gain improper privileges or to cause
  304  * a machine fault.
  305  */
  306 int
  307 linux_sigreturn(p, args)
  308         struct proc *p;
  309         struct linux_sigreturn_args *args;
  310 {
  311         struct linux_sigcontext *scp, context;
  312         register struct trapframe *regs;
  313         int eflags;
  314 
  315         regs = p->p_md.md_regs;
  316 
  317 #ifdef DEBUG
  318         printf("Linux-emul(%ld): linux_sigreturn(%p)\n",
  319             (long)p->p_pid, (void *)args->scp);
  320 #endif
  321         /*
  322          * The trampoline code hands us the context.
  323          * It is unsafe to keep track of it ourselves, in the event that a
  324          * program jumps out of a signal handler.
  325          */
  326         scp = SCARG(args,scp);
  327         if (copyin((caddr_t)scp, &context, sizeof(*scp)) != 0)
  328                 return (EFAULT);
  329 
  330         /*
  331          * Check for security violations.
  332          */
  333 #define EFLAGS_SECURE(ef, oef)  ((((ef) ^ (oef)) & ~PSL_USERCHANGE) == 0)
  334         eflags = context.sc_eflags;
  335         /*
  336          * XXX do allow users to change the privileged flag PSL_RF.  The
  337          * cpu sets PSL_RF in tf_eflags for faults.  Debuggers should
  338          * sometimes set it there too.  tf_eflags is kept in the signal
  339          * context during signal handling and there is no other place
  340          * to remember it, so the PSL_RF bit may be corrupted by the
  341          * signal handler without us knowing.  Corruption of the PSL_RF
  342          * bit at worst causes one more or one less debugger trap, so
  343          * allowing it is fairly harmless.
  344          */
  345         if (!EFLAGS_SECURE(eflags & ~PSL_RF, regs->tf_eflags & ~PSL_RF)) {
  346                 return(EINVAL);
  347         }
  348 
  349         /*
  350          * Don't allow users to load a valid privileged %cs.  Let the
  351          * hardware check for invalid selectors, excess privilege in
  352          * other selectors, invalid %eip's and invalid %esp's.
  353          */
  354 #define CS_SECURE(cs)   (ISPL(cs) == SEL_UPL)
  355         if (!CS_SECURE(context.sc_cs)) {
  356                 trapsignal(p, SIGBUS, T_PROTFLT);
  357                 return(EINVAL);
  358         }
  359 
  360         p->p_sigacts->ps_sigstk.ss_flags &= ~SS_ONSTACK;
  361         p->p_sigmask = context.sc_mask &~
  362                 (sigmask(SIGKILL)|sigmask(SIGCONT)|sigmask(SIGSTOP));
  363         /*
  364          * Restore signal context.
  365          */
  366         /* %fs and %gs were restored by the trampoline. */
  367         regs->tf_es     = context.sc_es;
  368         regs->tf_ds     = context.sc_ds;
  369         regs->tf_edi    = context.sc_edi;
  370         regs->tf_esi    = context.sc_esi;
  371         regs->tf_ebp    = context.sc_ebp;
  372         regs->tf_ebx    = context.sc_ebx;
  373         regs->tf_edx    = context.sc_edx;
  374         regs->tf_ecx    = context.sc_ecx;
  375         regs->tf_eax    = context.sc_eax;
  376         regs->tf_eip    = context.sc_eip;
  377         regs->tf_cs     = context.sc_cs;
  378         regs->tf_eflags = eflags;
  379         regs->tf_esp    = context.sc_esp_at_signal;
  380         regs->tf_ss     = context.sc_ss;
  381 
  382         return (EJUSTRETURN);
  383 }
  384 
  385 static void
  386 linux_prepsyscall(struct trapframe *tf, int *args, u_int *code, caddr_t *params)
  387 {
  388         args[0] = tf->tf_ebx;
  389         args[1] = tf->tf_ecx;
  390         args[2] = tf->tf_edx;
  391         args[3] = tf->tf_esi;
  392         args[4] = tf->tf_edi;
  393         *params = NULL;         /* no copyin */
  394 }
  395 
  396 struct sysentvec linux_sysvec = {
  397         LINUX_SYS_MAXSYSCALL,
  398         linux_sysent,
  399         0xff,
  400         NSIG,
  401         bsd_to_linux_signal,
  402         ELAST + 1, 
  403         bsd_to_linux_errno,
  404         translate_traps,
  405         linux_fixup,
  406         linux_sendsig,
  407         linux_sigcode,  
  408         &linux_szsigcode,
  409         linux_prepsyscall,
  410         "Linux a.out",
  411         aout_coredump
  412 };
  413 
  414 struct sysentvec elf_linux_sysvec = {
  415         LINUX_SYS_MAXSYSCALL,
  416         linux_sysent,
  417         0xff,
  418         NSIG,
  419         bsd_to_linux_signal,
  420         ELAST + 1,
  421         bsd_to_linux_errno,
  422         translate_traps,
  423         elf_linux_fixup,
  424         linux_sendsig,
  425         linux_sigcode,
  426         &linux_szsigcode,
  427         linux_prepsyscall,
  428         "Linux ELF",
  429         elf_coredump
  430 };
  431 
  432 static Elf32_Brandinfo linux_brand = {
  433                                         "Linux",
  434                                         "/compat/linux",
  435                                         "/lib/ld-linux.so.1",
  436                                         &elf_linux_sysvec
  437                                  };
  438 
  439 static Elf32_Brandinfo linux_glibc2brand = {
  440                                         "Linux",
  441                                         "/compat/linux",
  442                                         "/lib/ld-linux.so.2",
  443                                         &elf_linux_sysvec
  444                                  };
  445 
  446 Elf32_Brandinfo *linux_brandlist[] = {
  447                                         &linux_brand,
  448                                         &linux_glibc2brand,
  449                                         NULL
  450                                 };
  451 
  452 static int
  453 linux_elf_modevent(module_t mod, int type, void *data)
  454 {
  455         Elf32_Brandinfo **brandinfo;
  456         int error;
  457 
  458         error = 0;
  459 
  460         switch(type) {
  461         case MOD_LOAD:
  462                 for (brandinfo = &linux_brandlist[0]; *brandinfo != NULL;
  463                     ++brandinfo)
  464                         if (elf_insert_brand_entry(*brandinfo) < 0)
  465                                 error = EINVAL;
  466                 if (error)
  467                         printf("cannot insert Linux elf brand handler\n");
  468                 else if (bootverbose)
  469                         printf("Linux-ELF exec handler installed\n");
  470                 break;
  471         case MOD_UNLOAD:
  472                 for (brandinfo = &linux_brandlist[0]; *brandinfo != NULL;
  473                     ++brandinfo)
  474                         if (elf_brand_inuse(*brandinfo)) {
  475                                 error = EBUSY;
  476                         }
  477 
  478                 if (error == 0) {
  479                         for (brandinfo = &linux_brandlist[0];
  480                             *brandinfo != NULL; ++brandinfo)
  481                                 if (elf_remove_brand_entry(*brandinfo) < 0)
  482                                         error = EINVAL;
  483                 }
  484                 if (error)
  485                         printf("Could not deinstall ELF interpreter entry\n");
  486                 else if (bootverbose)
  487                         printf("Linux-elf exec handler removed\n");
  488                 break;
  489         default:
  490                 break;
  491         }
  492         return error;
  493 }
  494 static moduledata_t linux_elf_mod = {
  495         "linuxelf",
  496         linux_elf_modevent,
  497         0
  498 };
  499 DECLARE_MODULE(linuxelf, linux_elf_mod, SI_SUB_EXEC, SI_ORDER_ANY);

Cache object: 89431b867932ab2e54123017e59884a9


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]


This page is part of the FreeBSD/Linux Linux Kernel Cross-Reference, and was automatically generated using a modified version of the LXR engine.