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

Cache object: 400dc2faf0ee3a05865ab56d9fbfb02e


[ 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.