The branch stable/13 has been updated by kib:

URL: 
https://cgit.FreeBSD.org/src/commit/?id=3f602aa873122e8c3771135e6d0ed2610ea229b1

commit 3f602aa873122e8c3771135e6d0ed2610ea229b1
Author:     Konstantin Belousov <[email protected]>
AuthorDate: 2021-10-04 01:29:26 +0000
Commit:     Konstantin Belousov <[email protected]>
CommitDate: 2021-10-16 13:01:47 +0000

    i386: move signal delivery code to exec_machdep.c
    
    (cherry picked from commit 4c5bf591522c5449d017b7ea496488c42f847963)
---
 sys/conf/files.i386            |    1 +
 sys/i386/i386/exec_machdep.c   | 1443 ++++++++++++++++++++++++++++++++++++++++
 sys/i386/i386/machdep.c        | 1391 --------------------------------------
 sys/i386/i386/ptrace_machdep.c |   32 +
 4 files changed, 1476 insertions(+), 1391 deletions(-)

diff --git a/sys/conf/files.i386 b/sys/conf/files.i386
index 5c65ad53cea4..6a0ca49c0432 100644
--- a/sys/conf/files.i386
+++ b/sys/conf/files.i386
@@ -165,6 +165,7 @@ i386/i386/copyout.c         standard
 i386/i386/db_disasm.c          optional ddb
 i386/i386/db_interface.c       optional ddb
 i386/i386/db_trace.c           optional ddb
+i386/i386/exec_machdep.c       standard
 i386/i386/elan-mmcr.c          optional cpu_elan | cpu_soekris
 i386/i386/elf_machdep.c                standard
 i386/i386/exception.s          standard
diff --git a/sys/i386/i386/exec_machdep.c b/sys/i386/i386/exec_machdep.c
new file mode 100644
index 000000000000..13628aba7ab1
--- /dev/null
+++ b/sys/i386/i386/exec_machdep.c
@@ -0,0 +1,1443 @@
+/*-
+ * SPDX-License-Identifier: BSD-4-Clause
+ *
+ * Copyright (c) 2018 The FreeBSD Foundation
+ * Copyright (c) 1992 Terrence R. Lambert.
+ * Copyright (c) 1982, 1987, 1990 The Regents of the University of California.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * William Jolitz.
+ *
+ * Portions of this software were developed by A. Joseph Koshy under
+ * sponsorship from the FreeBSD Foundation and Google, Inc.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:
+ *     This product includes software developed by the University of
+ *     California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ *     from: @(#)machdep.c     7.4 (Berkeley) 6/3/91
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include "opt_cpu.h"
+#include "opt_ddb.h"
+#include "opt_kstack_pages.h"
+
+#include <sys/param.h>
+#include <sys/proc.h>
+#include <sys/systm.h>
+#include <sys/exec.h>
+#include <sys/imgact.h>
+#include <sys/kdb.h>
+#include <sys/kernel.h>
+#include <sys/ktr.h>
+#include <sys/linker.h>
+#include <sys/lock.h>
+#include <sys/malloc.h>
+#include <sys/mutex.h>
+#include <sys/pcpu.h>
+#include <sys/ptrace.h>
+#include <sys/rwlock.h>
+#include <sys/signalvar.h>
+#include <sys/syscallsubr.h>
+#include <sys/sysctl.h>
+#include <sys/sysent.h>
+#include <sys/sysproto.h>
+#include <sys/ucontext.h>
+#include <sys/vmmeter.h>
+
+#include <vm/vm.h>
+#include <vm/vm_param.h>
+#include <vm/vm_extern.h>
+#include <vm/vm_kern.h>
+#include <vm/vm_page.h>
+#include <vm/vm_map.h>
+#include <vm/vm_object.h>
+
+#ifdef DDB
+#ifndef KDB
+#error KDB must be enabled in order for DDB to work!
+#endif
+#include <ddb/ddb.h>
+#include <ddb/db_sym.h>
+#endif
+
+#include <machine/cpu.h>
+#include <machine/cputypes.h>
+#include <machine/md_var.h>
+#include <machine/pcb.h>
+#include <machine/pcb_ext.h>
+#include <machine/proc.h>
+#include <machine/reg.h>
+#include <machine/sigframe.h>
+#include <machine/specialreg.h>
+#include <machine/sysarch.h>
+#include <machine/trap.h>
+
+static void fpstate_drop(struct thread *td);
+static void get_fpcontext(struct thread *td, mcontext_t *mcp,
+    char *xfpusave, size_t xfpusave_len);
+static int  set_fpcontext(struct thread *td, mcontext_t *mcp,
+    char *xfpustate, size_t xfpustate_len);
+#ifdef COMPAT_43
+static void osendsig(sig_t catcher, ksiginfo_t *, sigset_t *mask);
+#endif
+#ifdef COMPAT_FREEBSD4
+static void freebsd4_sendsig(sig_t catcher, ksiginfo_t *, sigset_t *mask);
+#endif
+
+extern struct sysentvec elf32_freebsd_sysvec;
+
+/*
+ * Send an interrupt to process.
+ *
+ * Stack is set up to allow sigcode stored at top to call routine,
+ * followed by call to sigreturn routine below.  After sigreturn
+ * resets the signal mask, the stack, and the frame pointer, it
+ * returns to the user specified pc, psl.
+ */
+#ifdef COMPAT_43
+static void
+osendsig(sig_t catcher, ksiginfo_t *ksi, sigset_t *mask)
+{
+       struct osigframe sf, *fp;
+       struct proc *p;
+       struct thread *td;
+       struct sigacts *psp;
+       struct trapframe *regs;
+       int sig;
+       int oonstack;
+
+       td = curthread;
+       p = td->td_proc;
+       PROC_LOCK_ASSERT(p, MA_OWNED);
+       sig = ksi->ksi_signo;
+       psp = p->p_sigacts;
+       mtx_assert(&psp->ps_mtx, MA_OWNED);
+       regs = td->td_frame;
+       oonstack = sigonstack(regs->tf_esp);
+
+       /* Allocate space for the signal handler context. */
+       if ((td->td_pflags & TDP_ALTSTACK) && !oonstack &&
+           SIGISMEMBER(psp->ps_sigonstack, sig)) {
+               fp = (struct osigframe *)((uintptr_t)td->td_sigstk.ss_sp +
+                   td->td_sigstk.ss_size - sizeof(struct osigframe));
+#if defined(COMPAT_43)
+               td->td_sigstk.ss_flags |= SS_ONSTACK;
+#endif
+       } else
+               fp = (struct osigframe *)regs->tf_esp - 1;
+
+       /* Build the argument list for the signal handler. */
+       sf.sf_signum = sig;
+       sf.sf_scp = (register_t)&fp->sf_siginfo.si_sc;
+       bzero(&sf.sf_siginfo, sizeof(sf.sf_siginfo));
+       if (SIGISMEMBER(psp->ps_siginfo, sig)) {
+               /* Signal handler installed with SA_SIGINFO. */
+               sf.sf_arg2 = (register_t)&fp->sf_siginfo;
+               sf.sf_siginfo.si_signo = sig;
+               sf.sf_siginfo.si_code = ksi->ksi_code;
+               sf.sf_ahu.sf_action = (__osiginfohandler_t *)catcher;
+               sf.sf_addr = 0;
+       } else {
+               /* Old FreeBSD-style arguments. */
+               sf.sf_arg2 = ksi->ksi_code;
+               sf.sf_addr = (register_t)ksi->ksi_addr;
+               sf.sf_ahu.sf_handler = catcher;
+       }
+       mtx_unlock(&psp->ps_mtx);
+       PROC_UNLOCK(p);
+
+       /* Save most if not all of trap frame. */
+       sf.sf_siginfo.si_sc.sc_eax = regs->tf_eax;
+       sf.sf_siginfo.si_sc.sc_ebx = regs->tf_ebx;
+       sf.sf_siginfo.si_sc.sc_ecx = regs->tf_ecx;
+       sf.sf_siginfo.si_sc.sc_edx = regs->tf_edx;
+       sf.sf_siginfo.si_sc.sc_esi = regs->tf_esi;
+       sf.sf_siginfo.si_sc.sc_edi = regs->tf_edi;
+       sf.sf_siginfo.si_sc.sc_cs = regs->tf_cs;
+       sf.sf_siginfo.si_sc.sc_ds = regs->tf_ds;
+       sf.sf_siginfo.si_sc.sc_ss = regs->tf_ss;
+       sf.sf_siginfo.si_sc.sc_es = regs->tf_es;
+       sf.sf_siginfo.si_sc.sc_fs = regs->tf_fs;
+       sf.sf_siginfo.si_sc.sc_gs = rgs();
+       sf.sf_siginfo.si_sc.sc_isp = regs->tf_isp;
+
+       /* Build the signal context to be used by osigreturn(). */
+       sf.sf_siginfo.si_sc.sc_onstack = (oonstack) ? 1 : 0;
+       SIG2OSIG(*mask, sf.sf_siginfo.si_sc.sc_mask);
+       sf.sf_siginfo.si_sc.sc_sp = regs->tf_esp;
+       sf.sf_siginfo.si_sc.sc_fp = regs->tf_ebp;
+       sf.sf_siginfo.si_sc.sc_pc = regs->tf_eip;
+       sf.sf_siginfo.si_sc.sc_ps = regs->tf_eflags;
+       sf.sf_siginfo.si_sc.sc_trapno = regs->tf_trapno;
+       sf.sf_siginfo.si_sc.sc_err = regs->tf_err;
+
+       /*
+        * If we're a vm86 process, we want to save the segment registers.
+        * We also change eflags to be our emulated eflags, not the actual
+        * eflags.
+        */
+       if (regs->tf_eflags & PSL_VM) {
+               /* XXX confusing names: `tf' isn't a trapframe; `regs' is. */
+               struct trapframe_vm86 *tf = (struct trapframe_vm86 *)regs;
+               struct vm86_kernel *vm86 = &td->td_pcb->pcb_ext->ext_vm86;
+
+               sf.sf_siginfo.si_sc.sc_gs = tf->tf_vm86_gs;
+               sf.sf_siginfo.si_sc.sc_fs = tf->tf_vm86_fs;
+               sf.sf_siginfo.si_sc.sc_es = tf->tf_vm86_es;
+               sf.sf_siginfo.si_sc.sc_ds = tf->tf_vm86_ds;
+
+               if (vm86->vm86_has_vme == 0)
+                       sf.sf_siginfo.si_sc.sc_ps =
+                           (tf->tf_eflags & ~(PSL_VIF | PSL_VIP)) |
+                           (vm86->vm86_eflags & (PSL_VIF | PSL_VIP));
+
+               /* See sendsig() for comments. */
+               tf->tf_eflags &= ~(PSL_VM | PSL_NT | PSL_VIF | PSL_VIP);
+       }
+
+       /*
+        * Copy the sigframe out to the user's stack.
+        */
+       if (copyout(&sf, fp, sizeof(*fp)) != 0) {
+               PROC_LOCK(p);
+               sigexit(td, SIGILL);
+       }
+
+       regs->tf_esp = (int)fp;
+       if (p->p_sysent->sv_sigcode_base != 0) {
+               regs->tf_eip = p->p_sysent->sv_sigcode_base + szsigcode -
+                   szosigcode;
+       } else {
+               /* a.out sysentvec does not use shared page */
+               regs->tf_eip = p->p_sysent->sv_psstrings - szosigcode;
+       }
+       regs->tf_eflags &= ~(PSL_T | PSL_D);
+       regs->tf_cs = _ucodesel;
+       regs->tf_ds = _udatasel;
+       regs->tf_es = _udatasel;
+       regs->tf_fs = _udatasel;
+       load_gs(_udatasel);
+       regs->tf_ss = _udatasel;
+       PROC_LOCK(p);
+       mtx_lock(&psp->ps_mtx);
+}
+#endif /* COMPAT_43 */
+
+#ifdef COMPAT_FREEBSD4
+static void
+freebsd4_sendsig(sig_t catcher, ksiginfo_t *ksi, sigset_t *mask)
+{
+       struct sigframe4 sf, *sfp;
+       struct proc *p;
+       struct thread *td;
+       struct sigacts *psp;
+       struct trapframe *regs;
+       int sig;
+       int oonstack;
+
+       td = curthread;
+       p = td->td_proc;
+       PROC_LOCK_ASSERT(p, MA_OWNED);
+       sig = ksi->ksi_signo;
+       psp = p->p_sigacts;
+       mtx_assert(&psp->ps_mtx, MA_OWNED);
+       regs = td->td_frame;
+       oonstack = sigonstack(regs->tf_esp);
+
+       /* Save user context. */
+       bzero(&sf, sizeof(sf));
+       sf.sf_uc.uc_sigmask = *mask;
+       sf.sf_uc.uc_stack = td->td_sigstk;
+       sf.sf_uc.uc_stack.ss_flags = (td->td_pflags & TDP_ALTSTACK)
+           ? ((oonstack) ? SS_ONSTACK : 0) : SS_DISABLE;
+       sf.sf_uc.uc_mcontext.mc_onstack = (oonstack) ? 1 : 0;
+       sf.sf_uc.uc_mcontext.mc_gs = rgs();
+       bcopy(regs, &sf.sf_uc.uc_mcontext.mc_fs, sizeof(*regs));
+       bzero(sf.sf_uc.uc_mcontext.mc_fpregs,
+           sizeof(sf.sf_uc.uc_mcontext.mc_fpregs));
+       bzero(sf.sf_uc.uc_mcontext.__spare__,
+           sizeof(sf.sf_uc.uc_mcontext.__spare__));
+       bzero(sf.sf_uc.__spare__, sizeof(sf.sf_uc.__spare__));
+
+       /* Allocate space for the signal handler context. */
+       if ((td->td_pflags & TDP_ALTSTACK) != 0 && !oonstack &&
+           SIGISMEMBER(psp->ps_sigonstack, sig)) {
+               sfp = (struct sigframe4 *)((uintptr_t)td->td_sigstk.ss_sp +
+                   td->td_sigstk.ss_size - sizeof(struct sigframe4));
+#if defined(COMPAT_43)
+               td->td_sigstk.ss_flags |= SS_ONSTACK;
+#endif
+       } else
+               sfp = (struct sigframe4 *)regs->tf_esp - 1;
+
+       /* Build the argument list for the signal handler. */
+       sf.sf_signum = sig;
+       sf.sf_ucontext = (register_t)&sfp->sf_uc;
+       bzero(&sf.sf_si, sizeof(sf.sf_si));
+       if (SIGISMEMBER(psp->ps_siginfo, sig)) {
+               /* Signal handler installed with SA_SIGINFO. */
+               sf.sf_siginfo = (register_t)&sfp->sf_si;
+               sf.sf_ahu.sf_action = (__siginfohandler_t *)catcher;
+
+               /* Fill in POSIX parts */
+               sf.sf_si.si_signo = sig;
+               sf.sf_si.si_code = ksi->ksi_code;
+               sf.sf_si.si_addr = ksi->ksi_addr;
+       } else {
+               /* Old FreeBSD-style arguments. */
+               sf.sf_siginfo = ksi->ksi_code;
+               sf.sf_addr = (register_t)ksi->ksi_addr;
+               sf.sf_ahu.sf_handler = catcher;
+       }
+       mtx_unlock(&psp->ps_mtx);
+       PROC_UNLOCK(p);
+
+       /*
+        * If we're a vm86 process, we want to save the segment registers.
+        * We also change eflags to be our emulated eflags, not the actual
+        * eflags.
+        */
+       if (regs->tf_eflags & PSL_VM) {
+               struct trapframe_vm86 *tf = (struct trapframe_vm86 *)regs;
+               struct vm86_kernel *vm86 = &td->td_pcb->pcb_ext->ext_vm86;
+
+               sf.sf_uc.uc_mcontext.mc_gs = tf->tf_vm86_gs;
+               sf.sf_uc.uc_mcontext.mc_fs = tf->tf_vm86_fs;
+               sf.sf_uc.uc_mcontext.mc_es = tf->tf_vm86_es;
+               sf.sf_uc.uc_mcontext.mc_ds = tf->tf_vm86_ds;
+
+               if (vm86->vm86_has_vme == 0)
+                       sf.sf_uc.uc_mcontext.mc_eflags =
+                           (tf->tf_eflags & ~(PSL_VIF | PSL_VIP)) |
+                           (vm86->vm86_eflags & (PSL_VIF | PSL_VIP));
+
+               /*
+                * Clear PSL_NT to inhibit T_TSSFLT faults on return from
+                * syscalls made by the signal handler.  This just avoids
+                * wasting time for our lazy fixup of such faults.  PSL_NT
+                * does nothing in vm86 mode, but vm86 programs can set it
+                * almost legitimately in probes for old cpu types.
+                */
+               tf->tf_eflags &= ~(PSL_VM | PSL_NT | PSL_VIF | PSL_VIP);
+       }
+
+       /*
+        * Copy the sigframe out to the user's stack.
+        */
+       if (copyout(&sf, sfp, sizeof(*sfp)) != 0) {
+               PROC_LOCK(p);
+               sigexit(td, SIGILL);
+       }
+
+       regs->tf_esp = (int)sfp;
+       regs->tf_eip = p->p_sysent->sv_sigcode_base + szsigcode -
+           szfreebsd4_sigcode;
+       regs->tf_eflags &= ~(PSL_T | PSL_D);
+       regs->tf_cs = _ucodesel;
+       regs->tf_ds = _udatasel;
+       regs->tf_es = _udatasel;
+       regs->tf_fs = _udatasel;
+       regs->tf_ss = _udatasel;
+       PROC_LOCK(p);
+       mtx_lock(&psp->ps_mtx);
+}
+#endif /* COMPAT_FREEBSD4 */
+
+void
+sendsig(sig_t catcher, ksiginfo_t *ksi, sigset_t *mask)
+{
+       struct sigframe sf, *sfp;
+       struct proc *p;
+       struct thread *td;
+       struct sigacts *psp;
+       char *sp;
+       struct trapframe *regs;
+       struct segment_descriptor *sdp;
+       char *xfpusave;
+       size_t xfpusave_len;
+       int sig;
+       int oonstack;
+
+       td = curthread;
+       p = td->td_proc;
+       PROC_LOCK_ASSERT(p, MA_OWNED);
+       sig = ksi->ksi_signo;
+       psp = p->p_sigacts;
+       mtx_assert(&psp->ps_mtx, MA_OWNED);
+#ifdef COMPAT_FREEBSD4
+       if (SIGISMEMBER(psp->ps_freebsd4, sig)) {
+               freebsd4_sendsig(catcher, ksi, mask);
+               return;
+       }
+#endif
+#ifdef COMPAT_43
+       if (SIGISMEMBER(psp->ps_osigset, sig)) {
+               osendsig(catcher, ksi, mask);
+               return;
+       }
+#endif
+       regs = td->td_frame;
+       oonstack = sigonstack(regs->tf_esp);
+
+       if (cpu_max_ext_state_size > sizeof(union savefpu) && use_xsave) {
+               xfpusave_len = cpu_max_ext_state_size - sizeof(union savefpu);
+               xfpusave = __builtin_alloca(xfpusave_len);
+       } else {
+               xfpusave_len = 0;
+               xfpusave = NULL;
+       }
+
+       /* Save user context. */
+       bzero(&sf, sizeof(sf));
+       sf.sf_uc.uc_sigmask = *mask;
+       sf.sf_uc.uc_stack = td->td_sigstk;
+       sf.sf_uc.uc_stack.ss_flags = (td->td_pflags & TDP_ALTSTACK)
+           ? ((oonstack) ? SS_ONSTACK : 0) : SS_DISABLE;
+       sf.sf_uc.uc_mcontext.mc_onstack = (oonstack) ? 1 : 0;
+       sf.sf_uc.uc_mcontext.mc_gs = rgs();
+       bcopy(regs, &sf.sf_uc.uc_mcontext.mc_fs, sizeof(*regs));
+       sf.sf_uc.uc_mcontext.mc_len = sizeof(sf.sf_uc.uc_mcontext); /* magic */
+       get_fpcontext(td, &sf.sf_uc.uc_mcontext, xfpusave, xfpusave_len);
+       fpstate_drop(td);
+       /*
+        * Unconditionally fill the fsbase and gsbase into the mcontext.
+        */
+       sdp = &td->td_pcb->pcb_fsd;
+       sf.sf_uc.uc_mcontext.mc_fsbase = sdp->sd_hibase << 24 |
+           sdp->sd_lobase;
+       sdp = &td->td_pcb->pcb_gsd;
+       sf.sf_uc.uc_mcontext.mc_gsbase = sdp->sd_hibase << 24 |
+           sdp->sd_lobase;
+       bzero(sf.sf_uc.uc_mcontext.mc_spare2,
+           sizeof(sf.sf_uc.uc_mcontext.mc_spare2));
+
+       /* Allocate space for the signal handler context. */
+       if ((td->td_pflags & TDP_ALTSTACK) != 0 && !oonstack &&
+           SIGISMEMBER(psp->ps_sigonstack, sig)) {
+               sp = (char *)td->td_sigstk.ss_sp + td->td_sigstk.ss_size;
+#if defined(COMPAT_43)
+               td->td_sigstk.ss_flags |= SS_ONSTACK;
+#endif
+       } else
+               sp = (char *)regs->tf_esp - 128;
+       if (xfpusave != NULL) {
+               sp -= xfpusave_len;
+               sp = (char *)((unsigned int)sp & ~0x3F);
+               sf.sf_uc.uc_mcontext.mc_xfpustate = (register_t)sp;
+       }
+       sp -= sizeof(struct sigframe);
+
+       /* Align to 16 bytes. */
+       sfp = (struct sigframe *)((unsigned int)sp & ~0xF);
+
+       /* Build the argument list for the signal handler. */
+       sf.sf_signum = sig;
+       sf.sf_ucontext = (register_t)&sfp->sf_uc;
+       bzero(&sf.sf_si, sizeof(sf.sf_si));
+       if (SIGISMEMBER(psp->ps_siginfo, sig)) {
+               /* Signal handler installed with SA_SIGINFO. */
+               sf.sf_siginfo = (register_t)&sfp->sf_si;
+               sf.sf_ahu.sf_action = (__siginfohandler_t *)catcher;
+
+               /* Fill in POSIX parts */
+               sf.sf_si = ksi->ksi_info;
+               sf.sf_si.si_signo = sig; /* maybe a translated signal */
+       } else {
+               /* Old FreeBSD-style arguments. */
+               sf.sf_siginfo = ksi->ksi_code;
+               sf.sf_addr = (register_t)ksi->ksi_addr;
+               sf.sf_ahu.sf_handler = catcher;
+       }
+       mtx_unlock(&psp->ps_mtx);
+       PROC_UNLOCK(p);
+
+       /*
+        * If we're a vm86 process, we want to save the segment registers.
+        * We also change eflags to be our emulated eflags, not the actual
+        * eflags.
+        */
+       if (regs->tf_eflags & PSL_VM) {
+               struct trapframe_vm86 *tf = (struct trapframe_vm86 *)regs;
+               struct vm86_kernel *vm86 = &td->td_pcb->pcb_ext->ext_vm86;
+
+               sf.sf_uc.uc_mcontext.mc_gs = tf->tf_vm86_gs;
+               sf.sf_uc.uc_mcontext.mc_fs = tf->tf_vm86_fs;
+               sf.sf_uc.uc_mcontext.mc_es = tf->tf_vm86_es;
+               sf.sf_uc.uc_mcontext.mc_ds = tf->tf_vm86_ds;
+
+               if (vm86->vm86_has_vme == 0)
+                       sf.sf_uc.uc_mcontext.mc_eflags =
+                           (tf->tf_eflags & ~(PSL_VIF | PSL_VIP)) |
+                           (vm86->vm86_eflags & (PSL_VIF | PSL_VIP));
+
+               /*
+                * Clear PSL_NT to inhibit T_TSSFLT faults on return from
+                * syscalls made by the signal handler.  This just avoids
+                * wasting time for our lazy fixup of such faults.  PSL_NT
+                * does nothing in vm86 mode, but vm86 programs can set it
+                * almost legitimately in probes for old cpu types.
+                */
+               tf->tf_eflags &= ~(PSL_VM | PSL_NT | PSL_VIF | PSL_VIP);
+       }
+
+       /*
+        * Copy the sigframe out to the user's stack.
+        */
+       if (copyout(&sf, sfp, sizeof(*sfp)) != 0 ||
+           (xfpusave != NULL && copyout(xfpusave,
+           (void *)sf.sf_uc.uc_mcontext.mc_xfpustate, xfpusave_len)
+           != 0)) {
+               PROC_LOCK(p);
+               sigexit(td, SIGILL);
+       }
+
+       regs->tf_esp = (int)sfp;
+       regs->tf_eip = p->p_sysent->sv_sigcode_base;
+       if (regs->tf_eip == 0)
+               regs->tf_eip = p->p_sysent->sv_psstrings - szsigcode;
+       regs->tf_eflags &= ~(PSL_T | PSL_D);
+       regs->tf_cs = _ucodesel;
+       regs->tf_ds = _udatasel;
+       regs->tf_es = _udatasel;
+       regs->tf_fs = _udatasel;
+       regs->tf_ss = _udatasel;
+       PROC_LOCK(p);
+       mtx_lock(&psp->ps_mtx);
+}
+
+/*
+ * System call to cleanup state after a signal has been taken.  Reset
+ * signal mask and stack state from context left by sendsig (above).
+ * Return to previous pc and psl as specified by context left by
+ * sendsig. Check carefully to make sure that the user has not
+ * modified the state to gain improper privileges.
+ */
+#ifdef COMPAT_43
+int
+osigreturn(struct thread *td, struct osigreturn_args *uap)
+{
+       struct osigcontext sc;
+       struct trapframe *regs;
+       struct osigcontext *scp;
+       int eflags, error;
+       ksiginfo_t ksi;
+
+       regs = td->td_frame;
+       error = copyin(uap->sigcntxp, &sc, sizeof(sc));
+       if (error != 0)
+               return (error);
+       scp = &sc;
+       eflags = scp->sc_ps;
+       if (eflags & PSL_VM) {
+               struct trapframe_vm86 *tf = (struct trapframe_vm86 *)regs;
+               struct vm86_kernel *vm86;
+
+               /*
+                * if pcb_ext == 0 or vm86_inited == 0, the user hasn't
+                * set up the vm86 area, and we can't enter vm86 mode.
+                */
+               if (td->td_pcb->pcb_ext == 0)
+                       return (EINVAL);
+               vm86 = &td->td_pcb->pcb_ext->ext_vm86;
+               if (vm86->vm86_inited == 0)
+                       return (EINVAL);
+
+               /* Go back to user mode if both flags are set. */
+               if ((eflags & PSL_VIP) && (eflags & PSL_VIF)) {
+                       ksiginfo_init_trap(&ksi);
+                       ksi.ksi_signo = SIGBUS;
+                       ksi.ksi_code = BUS_OBJERR;
+                       ksi.ksi_addr = (void *)regs->tf_eip;
+                       trapsignal(td, &ksi);
+               }
+
+               if (vm86->vm86_has_vme) {
+                       eflags = (tf->tf_eflags & ~VME_USERCHANGE) |
+                           (eflags & VME_USERCHANGE) | PSL_VM;
+               } else {
+                       vm86->vm86_eflags = eflags;     /* save VIF, VIP */
+                       eflags = (tf->tf_eflags & ~VM_USERCHANGE) |
+                           (eflags & VM_USERCHANGE) | PSL_VM;
+               }
+               tf->tf_vm86_ds = scp->sc_ds;
+               tf->tf_vm86_es = scp->sc_es;
+               tf->tf_vm86_fs = scp->sc_fs;
+               tf->tf_vm86_gs = scp->sc_gs;
+               tf->tf_ds = _udatasel;
+               tf->tf_es = _udatasel;
+               tf->tf_fs = _udatasel;
+       } else {
+               /*
+                * Don't allow users to change privileged or reserved flags.
+                */
+               if (!EFL_SECURE(eflags, regs->tf_eflags)) {
+                       return (EINVAL);
+               }
+
+               /*
+                * Don't allow users to load a valid privileged %cs.  Let the
+                * hardware check for invalid selectors, excess privilege in
+                * other selectors, invalid %eip's and invalid %esp's.
+                */
+               if (!CS_SECURE(scp->sc_cs)) {
+                       ksiginfo_init_trap(&ksi);
+                       ksi.ksi_signo = SIGBUS;
+                       ksi.ksi_code = BUS_OBJERR;
+                       ksi.ksi_trapno = T_PROTFLT;
+                       ksi.ksi_addr = (void *)regs->tf_eip;
+                       trapsignal(td, &ksi);
+                       return (EINVAL);
+               }
+               regs->tf_ds = scp->sc_ds;
+               regs->tf_es = scp->sc_es;
+               regs->tf_fs = scp->sc_fs;
+       }
+
+       /* Restore remaining registers. */
+       regs->tf_eax = scp->sc_eax;
+       regs->tf_ebx = scp->sc_ebx;
+       regs->tf_ecx = scp->sc_ecx;
+       regs->tf_edx = scp->sc_edx;
+       regs->tf_esi = scp->sc_esi;
+       regs->tf_edi = scp->sc_edi;
+       regs->tf_cs = scp->sc_cs;
+       regs->tf_ss = scp->sc_ss;
+       regs->tf_isp = scp->sc_isp;
+       regs->tf_ebp = scp->sc_fp;
+       regs->tf_esp = scp->sc_sp;
+       regs->tf_eip = scp->sc_pc;
+       regs->tf_eflags = eflags;
+
+#if defined(COMPAT_43)
+       if (scp->sc_onstack & 1)
+               td->td_sigstk.ss_flags |= SS_ONSTACK;
+       else
+               td->td_sigstk.ss_flags &= ~SS_ONSTACK;
+#endif
+       kern_sigprocmask(td, SIG_SETMASK, (sigset_t *)&scp->sc_mask, NULL,
+           SIGPROCMASK_OLD);
+       return (EJUSTRETURN);
+}
+#endif /* COMPAT_43 */
+
+#ifdef COMPAT_FREEBSD4
+int
+freebsd4_sigreturn(struct thread *td, struct freebsd4_sigreturn_args *uap)
+{
+       struct ucontext4 uc;
+       struct trapframe *regs;
+       struct ucontext4 *ucp;
+       int cs, eflags, error;
+       ksiginfo_t ksi;
+
+       error = copyin(uap->sigcntxp, &uc, sizeof(uc));
+       if (error != 0)
+               return (error);
+       ucp = &uc;
+       regs = td->td_frame;
+       eflags = ucp->uc_mcontext.mc_eflags;
+       if (eflags & PSL_VM) {
+               struct trapframe_vm86 *tf = (struct trapframe_vm86 *)regs;
+               struct vm86_kernel *vm86;
+
+               /*
+                * if pcb_ext == 0 or vm86_inited == 0, the user hasn't
+                * set up the vm86 area, and we can't enter vm86 mode.
+                */
+               if (td->td_pcb->pcb_ext == 0)
+                       return (EINVAL);
+               vm86 = &td->td_pcb->pcb_ext->ext_vm86;
+               if (vm86->vm86_inited == 0)
+                       return (EINVAL);
+
+               /* Go back to user mode if both flags are set. */
+               if ((eflags & PSL_VIP) && (eflags & PSL_VIF)) {
+                       ksiginfo_init_trap(&ksi);
+                       ksi.ksi_signo = SIGBUS;
+                       ksi.ksi_code = BUS_OBJERR;
+                       ksi.ksi_addr = (void *)regs->tf_eip;
+                       trapsignal(td, &ksi);
+               }
+               if (vm86->vm86_has_vme) {
+                       eflags = (tf->tf_eflags & ~VME_USERCHANGE) |
+                           (eflags & VME_USERCHANGE) | PSL_VM;
+               } else {
+                       vm86->vm86_eflags = eflags;     /* save VIF, VIP */
+                       eflags = (tf->tf_eflags & ~VM_USERCHANGE) |
+                           (eflags & VM_USERCHANGE) | PSL_VM;
+               }
+               bcopy(&ucp->uc_mcontext.mc_fs, tf, sizeof(struct trapframe));
+               tf->tf_eflags = eflags;
+               tf->tf_vm86_ds = tf->tf_ds;
+               tf->tf_vm86_es = tf->tf_es;
+               tf->tf_vm86_fs = tf->tf_fs;
+               tf->tf_vm86_gs = ucp->uc_mcontext.mc_gs;
+               tf->tf_ds = _udatasel;
+               tf->tf_es = _udatasel;
+               tf->tf_fs = _udatasel;
+       } else {
+               /*
+                * Don't allow users to change privileged or reserved flags.
+                */
+               if (!EFL_SECURE(eflags, regs->tf_eflags)) {
+                       uprintf(
+                           "pid %d (%s): freebsd4_sigreturn eflags = 0x%x\n",
+                           td->td_proc->p_pid, td->td_name, eflags);
+                       return (EINVAL);
+               }
+
+               /*
+                * Don't allow users to load a valid privileged %cs.  Let the
+                * hardware check for invalid selectors, excess privilege in
+                * other selectors, invalid %eip's and invalid %esp's.
+                */
+               cs = ucp->uc_mcontext.mc_cs;
+               if (!CS_SECURE(cs)) {
+                       uprintf("pid %d (%s): freebsd4_sigreturn cs = 0x%x\n",
+                           td->td_proc->p_pid, td->td_name, cs);
+                       ksiginfo_init_trap(&ksi);
+                       ksi.ksi_signo = SIGBUS;
+                       ksi.ksi_code = BUS_OBJERR;
+                       ksi.ksi_trapno = T_PROTFLT;
+                       ksi.ksi_addr = (void *)regs->tf_eip;
+                       trapsignal(td, &ksi);
+                       return (EINVAL);
+               }
+
+               bcopy(&ucp->uc_mcontext.mc_fs, regs, sizeof(*regs));
+       }
+
+#if defined(COMPAT_43)
+       if (ucp->uc_mcontext.mc_onstack & 1)
+               td->td_sigstk.ss_flags |= SS_ONSTACK;
+       else
+               td->td_sigstk.ss_flags &= ~SS_ONSTACK;
+#endif
+       kern_sigprocmask(td, SIG_SETMASK, &ucp->uc_sigmask, NULL, 0);
+       return (EJUSTRETURN);
+}
+#endif /* COMPAT_FREEBSD4 */
+
+int
+sys_sigreturn(struct thread *td, struct sigreturn_args *uap)
+{
+       ucontext_t uc;
+       struct proc *p;
+       struct trapframe *regs;
+       ucontext_t *ucp;
+       char *xfpustate;
+       size_t xfpustate_len;
+       int cs, eflags, error, ret;
+       ksiginfo_t ksi;
+
+       p = td->td_proc;
+
+       error = copyin(uap->sigcntxp, &uc, sizeof(uc));
+       if (error != 0)
+               return (error);
+       ucp = &uc;
+       if ((ucp->uc_mcontext.mc_flags & ~_MC_FLAG_MASK) != 0) {
+               uprintf("pid %d (%s): sigreturn mc_flags %x\n", p->p_pid,
+                   td->td_name, ucp->uc_mcontext.mc_flags);
+               return (EINVAL);
+       }
+       regs = td->td_frame;
+       eflags = ucp->uc_mcontext.mc_eflags;
+       if (eflags & PSL_VM) {
+               struct trapframe_vm86 *tf = (struct trapframe_vm86 *)regs;
+               struct vm86_kernel *vm86;
+
+               /*
+                * if pcb_ext == 0 or vm86_inited == 0, the user hasn't
+                * set up the vm86 area, and we can't enter vm86 mode.
+                */
+               if (td->td_pcb->pcb_ext == 0)
+                       return (EINVAL);
+               vm86 = &td->td_pcb->pcb_ext->ext_vm86;
+               if (vm86->vm86_inited == 0)
+                       return (EINVAL);
+
+               /* Go back to user mode if both flags are set. */
+               if ((eflags & PSL_VIP) && (eflags & PSL_VIF)) {
+                       ksiginfo_init_trap(&ksi);
+                       ksi.ksi_signo = SIGBUS;
+                       ksi.ksi_code = BUS_OBJERR;
+                       ksi.ksi_addr = (void *)regs->tf_eip;
+                       trapsignal(td, &ksi);
+               }
+
+               if (vm86->vm86_has_vme) {
+                       eflags = (tf->tf_eflags & ~VME_USERCHANGE) |
+                           (eflags & VME_USERCHANGE) | PSL_VM;
+               } else {
+                       vm86->vm86_eflags = eflags;     /* save VIF, VIP */
+                       eflags = (tf->tf_eflags & ~VM_USERCHANGE) |
+                           (eflags & VM_USERCHANGE) | PSL_VM;
+               }
+               bcopy(&ucp->uc_mcontext.mc_fs, tf, sizeof(struct trapframe));
+               tf->tf_eflags = eflags;
+               tf->tf_vm86_ds = tf->tf_ds;
+               tf->tf_vm86_es = tf->tf_es;
+               tf->tf_vm86_fs = tf->tf_fs;
+               tf->tf_vm86_gs = ucp->uc_mcontext.mc_gs;
+               tf->tf_ds = _udatasel;
+               tf->tf_es = _udatasel;
+               tf->tf_fs = _udatasel;
+       } else {
+               /*
+                * Don't allow users to change privileged or reserved flags.
+                */
+               if (!EFL_SECURE(eflags, regs->tf_eflags)) {
+                       uprintf("pid %d (%s): sigreturn eflags = 0x%x\n",
+                           td->td_proc->p_pid, td->td_name, eflags);
+                       return (EINVAL);
+               }
+
+               /*
+                * Don't allow users to load a valid privileged %cs.  Let the
+                * hardware check for invalid selectors, excess privilege in
+                * other selectors, invalid %eip's and invalid %esp's.
+                */
+               cs = ucp->uc_mcontext.mc_cs;
+               if (!CS_SECURE(cs)) {
+                       uprintf("pid %d (%s): sigreturn cs = 0x%x\n",
+                           td->td_proc->p_pid, td->td_name, cs);
+                       ksiginfo_init_trap(&ksi);
+                       ksi.ksi_signo = SIGBUS;
+                       ksi.ksi_code = BUS_OBJERR;
+                       ksi.ksi_trapno = T_PROTFLT;
+                       ksi.ksi_addr = (void *)regs->tf_eip;
+                       trapsignal(td, &ksi);
+                       return (EINVAL);
+               }
+
+               if ((uc.uc_mcontext.mc_flags & _MC_HASFPXSTATE) != 0) {
+                       xfpustate_len = uc.uc_mcontext.mc_xfpustate_len;
+                       if (xfpustate_len > cpu_max_ext_state_size -
+                           sizeof(union savefpu)) {
+                               uprintf(
+                           "pid %d (%s): sigreturn xfpusave_len = 0x%zx\n",
+                                   p->p_pid, td->td_name, xfpustate_len);
+                               return (EINVAL);
+                       }
+                       xfpustate = __builtin_alloca(xfpustate_len);
+                       error = copyin(
+                           (const void *)uc.uc_mcontext.mc_xfpustate,
+                           xfpustate, xfpustate_len);
+                       if (error != 0) {
+                               uprintf(
+       "pid %d (%s): sigreturn copying xfpustate failed\n",
+                                   p->p_pid, td->td_name);
+                               return (error);
+                       }
+               } else {
+                       xfpustate = NULL;
+                       xfpustate_len = 0;
+               }
+               ret = set_fpcontext(td, &ucp->uc_mcontext, xfpustate,
+                   xfpustate_len);
+               if (ret != 0)
+                       return (ret);
+               bcopy(&ucp->uc_mcontext.mc_fs, regs, sizeof(*regs));
+       }
+
+#if defined(COMPAT_43)
+       if (ucp->uc_mcontext.mc_onstack & 1)
+               td->td_sigstk.ss_flags |= SS_ONSTACK;
+       else
+               td->td_sigstk.ss_flags &= ~SS_ONSTACK;
+#endif
+
+       kern_sigprocmask(td, SIG_SETMASK, &ucp->uc_sigmask, NULL, 0);
+       return (EJUSTRETURN);
+}
+
+/*
+ * Reset the hardware debug registers if they were in use.
+ * They won't have any meaning for the newly exec'd process.
+ */
+void
+x86_clear_dbregs(struct pcb *pcb)
+{
+       if ((pcb->pcb_flags & PCB_DBREGS) == 0)
+               return;
+
+       pcb->pcb_dr0 = 0;
+       pcb->pcb_dr1 = 0;
+       pcb->pcb_dr2 = 0;
+       pcb->pcb_dr3 = 0;
+       pcb->pcb_dr6 = 0;
+       pcb->pcb_dr7 = 0;
+
+       if (pcb == curpcb) {
+               /*
+                * Clear the debug registers on the running CPU,
+                * otherwise they will end up affecting the next
+                * process we switch to.
+                */
+               reset_dbregs();
+       }
+       pcb->pcb_flags &= ~PCB_DBREGS;
+}
+
+#ifdef COMPAT_43
+static void
+setup_priv_lcall_gate(struct proc *p)
+{
+       struct i386_ldt_args uap;
+       union descriptor desc;
+       u_int lcall_addr;
+
+       bzero(&uap, sizeof(uap));
+       uap.start = 0;
+       uap.num = 1;
+       lcall_addr = p->p_sysent->sv_psstrings - sz_lcall_tramp;
+       bzero(&desc, sizeof(desc));
+       desc.sd.sd_type = SDT_MEMERA;
+       desc.sd.sd_dpl = SEL_UPL;
+       desc.sd.sd_p = 1;
+       desc.sd.sd_def32 = 1;
+       desc.sd.sd_gran = 1;
+       desc.sd.sd_lolimit = 0xffff;
+       desc.sd.sd_hilimit = 0xf;
+       desc.sd.sd_lobase = lcall_addr;
+       desc.sd.sd_hibase = lcall_addr >> 24;
+       i386_set_ldt(curthread, &uap, &desc);
+}
+#endif
+
+/*
+ * Reset registers to default values on exec.
+ */
+void
+exec_setregs(struct thread *td, struct image_params *imgp, uintptr_t stack)
+{
+       struct trapframe *regs;
+       struct pcb *pcb;
+       register_t saved_eflags;
+
+       regs = td->td_frame;
+       pcb = td->td_pcb;
*** 1965 LINES SKIPPED ***

Reply via email to