xref: /freebsd/sys/i386/i386/exec_machdep.c (revision 29363fb4)
14c5bf591SKonstantin Belousov /*-
24c5bf591SKonstantin Belousov  * SPDX-License-Identifier: BSD-4-Clause
34c5bf591SKonstantin Belousov  *
44c5bf591SKonstantin Belousov  * Copyright (c) 2018 The FreeBSD Foundation
54c5bf591SKonstantin Belousov  * Copyright (c) 1992 Terrence R. Lambert.
64c5bf591SKonstantin Belousov  * Copyright (c) 1982, 1987, 1990 The Regents of the University of California.
74c5bf591SKonstantin Belousov  * All rights reserved.
84c5bf591SKonstantin Belousov  *
94c5bf591SKonstantin Belousov  * This code is derived from software contributed to Berkeley by
104c5bf591SKonstantin Belousov  * William Jolitz.
114c5bf591SKonstantin Belousov  *
124c5bf591SKonstantin Belousov  * Portions of this software were developed by A. Joseph Koshy under
134c5bf591SKonstantin Belousov  * sponsorship from the FreeBSD Foundation and Google, Inc.
144c5bf591SKonstantin Belousov  *
154c5bf591SKonstantin Belousov  * Redistribution and use in source and binary forms, with or without
164c5bf591SKonstantin Belousov  * modification, are permitted provided that the following conditions
174c5bf591SKonstantin Belousov  * are met:
184c5bf591SKonstantin Belousov  * 1. Redistributions of source code must retain the above copyright
194c5bf591SKonstantin Belousov  *    notice, this list of conditions and the following disclaimer.
204c5bf591SKonstantin Belousov  * 2. Redistributions in binary form must reproduce the above copyright
214c5bf591SKonstantin Belousov  *    notice, this list of conditions and the following disclaimer in the
224c5bf591SKonstantin Belousov  *    documentation and/or other materials provided with the distribution.
234c5bf591SKonstantin Belousov  * 3. All advertising materials mentioning features or use of this software
244c5bf591SKonstantin Belousov  *    must display the following acknowledgement:
254c5bf591SKonstantin Belousov  *	This product includes software developed by the University of
264c5bf591SKonstantin Belousov  *	California, Berkeley and its contributors.
274c5bf591SKonstantin Belousov  * 4. Neither the name of the University nor the names of its contributors
284c5bf591SKonstantin Belousov  *    may be used to endorse or promote products derived from this software
294c5bf591SKonstantin Belousov  *    without specific prior written permission.
304c5bf591SKonstantin Belousov  *
314c5bf591SKonstantin Belousov  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
324c5bf591SKonstantin Belousov  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
334c5bf591SKonstantin Belousov  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
344c5bf591SKonstantin Belousov  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
354c5bf591SKonstantin Belousov  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
364c5bf591SKonstantin Belousov  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
374c5bf591SKonstantin Belousov  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
384c5bf591SKonstantin Belousov  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
394c5bf591SKonstantin Belousov  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
404c5bf591SKonstantin Belousov  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
414c5bf591SKonstantin Belousov  * SUCH DAMAGE.
424c5bf591SKonstantin Belousov  */
434c5bf591SKonstantin Belousov 
444c5bf591SKonstantin Belousov #include <sys/cdefs.h>
454c5bf591SKonstantin Belousov #include "opt_cpu.h"
464c5bf591SKonstantin Belousov #include "opt_ddb.h"
474c5bf591SKonstantin Belousov #include "opt_kstack_pages.h"
484c5bf591SKonstantin Belousov 
494c5bf591SKonstantin Belousov #include <sys/param.h>
504c5bf591SKonstantin Belousov #include <sys/proc.h>
514c5bf591SKonstantin Belousov #include <sys/systm.h>
524c5bf591SKonstantin Belousov #include <sys/exec.h>
534c5bf591SKonstantin Belousov #include <sys/imgact.h>
544c5bf591SKonstantin Belousov #include <sys/kdb.h>
554c5bf591SKonstantin Belousov #include <sys/kernel.h>
564c5bf591SKonstantin Belousov #include <sys/ktr.h>
574c5bf591SKonstantin Belousov #include <sys/linker.h>
584c5bf591SKonstantin Belousov #include <sys/lock.h>
594c5bf591SKonstantin Belousov #include <sys/malloc.h>
604c5bf591SKonstantin Belousov #include <sys/mutex.h>
614c5bf591SKonstantin Belousov #include <sys/pcpu.h>
624c5bf591SKonstantin Belousov #include <sys/ptrace.h>
634c5bf591SKonstantin Belousov #include <sys/reg.h>
644c5bf591SKonstantin Belousov #include <sys/rwlock.h>
654c5bf591SKonstantin Belousov #include <sys/signalvar.h>
664c5bf591SKonstantin Belousov #include <sys/syscallsubr.h>
674c5bf591SKonstantin Belousov #include <sys/sysctl.h>
684c5bf591SKonstantin Belousov #include <sys/sysent.h>
694c5bf591SKonstantin Belousov #include <sys/sysproto.h>
704c5bf591SKonstantin Belousov #include <sys/ucontext.h>
714c5bf591SKonstantin Belousov #include <sys/vmmeter.h>
724c5bf591SKonstantin Belousov 
734c5bf591SKonstantin Belousov #include <vm/vm.h>
744c5bf591SKonstantin Belousov #include <vm/vm_param.h>
754c5bf591SKonstantin Belousov #include <vm/vm_extern.h>
764c5bf591SKonstantin Belousov #include <vm/vm_kern.h>
774c5bf591SKonstantin Belousov #include <vm/vm_page.h>
784c5bf591SKonstantin Belousov #include <vm/vm_map.h>
794c5bf591SKonstantin Belousov #include <vm/vm_object.h>
804c5bf591SKonstantin Belousov 
814c5bf591SKonstantin Belousov #ifdef DDB
824c5bf591SKonstantin Belousov #ifndef KDB
834c5bf591SKonstantin Belousov #error KDB must be enabled in order for DDB to work!
844c5bf591SKonstantin Belousov #endif
854c5bf591SKonstantin Belousov #include <ddb/ddb.h>
864c5bf591SKonstantin Belousov #include <ddb/db_sym.h>
874c5bf591SKonstantin Belousov #endif
884c5bf591SKonstantin Belousov 
894c5bf591SKonstantin Belousov #include <machine/cpu.h>
904c5bf591SKonstantin Belousov #include <machine/cputypes.h>
914c5bf591SKonstantin Belousov #include <machine/md_var.h>
924c5bf591SKonstantin Belousov #include <machine/pcb.h>
934c5bf591SKonstantin Belousov #include <machine/pcb_ext.h>
944c5bf591SKonstantin Belousov #include <machine/proc.h>
954c5bf591SKonstantin Belousov #include <machine/sigframe.h>
964c5bf591SKonstantin Belousov #include <machine/specialreg.h>
974c5bf591SKonstantin Belousov #include <machine/sysarch.h>
984c5bf591SKonstantin Belousov #include <machine/trap.h>
994c5bf591SKonstantin Belousov 
1004c5bf591SKonstantin Belousov static void fpstate_drop(struct thread *td);
1014c5bf591SKonstantin Belousov static void get_fpcontext(struct thread *td, mcontext_t *mcp,
1024c5bf591SKonstantin Belousov     char *xfpusave, size_t xfpusave_len);
1034c5bf591SKonstantin Belousov static int  set_fpcontext(struct thread *td, mcontext_t *mcp,
1044c5bf591SKonstantin Belousov     char *xfpustate, size_t xfpustate_len);
1054c5bf591SKonstantin Belousov #ifdef COMPAT_43
1064c5bf591SKonstantin Belousov static void osendsig(sig_t catcher, ksiginfo_t *, sigset_t *mask);
1074c5bf591SKonstantin Belousov #endif
1084c5bf591SKonstantin Belousov #ifdef COMPAT_FREEBSD4
1094c5bf591SKonstantin Belousov static void freebsd4_sendsig(sig_t catcher, ksiginfo_t *, sigset_t *mask);
1104c5bf591SKonstantin Belousov #endif
1114c5bf591SKonstantin Belousov 
1124c5bf591SKonstantin Belousov extern struct sysentvec elf32_freebsd_sysvec;
1134c5bf591SKonstantin Belousov 
114d4f495fbSWarner Losh _Static_assert(sizeof(mcontext_t) == 640, "mcontext_t size incorrect");
115d4f495fbSWarner Losh _Static_assert(sizeof(ucontext_t) == 704, "ucontext_t size incorrect");
116d4f495fbSWarner Losh _Static_assert(sizeof(siginfo_t) == 64, "siginfo_t size incorrect");
117d4f495fbSWarner Losh 
1184c5bf591SKonstantin Belousov /*
1194c5bf591SKonstantin Belousov  * Send an interrupt to process.
1204c5bf591SKonstantin Belousov  *
1214c5bf591SKonstantin Belousov  * Stack is set up to allow sigcode stored at top to call routine,
1224c5bf591SKonstantin Belousov  * followed by call to sigreturn routine below.  After sigreturn
1234c5bf591SKonstantin Belousov  * resets the signal mask, the stack, and the frame pointer, it
1244c5bf591SKonstantin Belousov  * returns to the user specified pc, psl.
1254c5bf591SKonstantin Belousov  */
1264c5bf591SKonstantin Belousov #ifdef COMPAT_43
1274c5bf591SKonstantin Belousov static void
osendsig(sig_t catcher,ksiginfo_t * ksi,sigset_t * mask)1284c5bf591SKonstantin Belousov osendsig(sig_t catcher, ksiginfo_t *ksi, sigset_t *mask)
1294c5bf591SKonstantin Belousov {
1304c5bf591SKonstantin Belousov 	struct osigframe sf, *fp;
1314c5bf591SKonstantin Belousov 	struct proc *p;
1324c5bf591SKonstantin Belousov 	struct thread *td;
1334c5bf591SKonstantin Belousov 	struct sigacts *psp;
1344c5bf591SKonstantin Belousov 	struct trapframe *regs;
1354c5bf591SKonstantin Belousov 	int sig;
1364c5bf591SKonstantin Belousov 	int oonstack;
1374c5bf591SKonstantin Belousov 
1384c5bf591SKonstantin Belousov 	td = curthread;
1394c5bf591SKonstantin Belousov 	p = td->td_proc;
1404c5bf591SKonstantin Belousov 	PROC_LOCK_ASSERT(p, MA_OWNED);
1414c5bf591SKonstantin Belousov 	sig = ksi->ksi_signo;
1424c5bf591SKonstantin Belousov 	psp = p->p_sigacts;
1434c5bf591SKonstantin Belousov 	mtx_assert(&psp->ps_mtx, MA_OWNED);
1444c5bf591SKonstantin Belousov 	regs = td->td_frame;
1454c5bf591SKonstantin Belousov 	oonstack = sigonstack(regs->tf_esp);
1464c5bf591SKonstantin Belousov 
1474c5bf591SKonstantin Belousov 	/* Allocate space for the signal handler context. */
1484c5bf591SKonstantin Belousov 	if ((td->td_pflags & TDP_ALTSTACK) && !oonstack &&
1494c5bf591SKonstantin Belousov 	    SIGISMEMBER(psp->ps_sigonstack, sig)) {
1504c5bf591SKonstantin Belousov 		fp = (struct osigframe *)((uintptr_t)td->td_sigstk.ss_sp +
1514c5bf591SKonstantin Belousov 		    td->td_sigstk.ss_size - sizeof(struct osigframe));
1524c5bf591SKonstantin Belousov #if defined(COMPAT_43)
1534c5bf591SKonstantin Belousov 		td->td_sigstk.ss_flags |= SS_ONSTACK;
1544c5bf591SKonstantin Belousov #endif
1554c5bf591SKonstantin Belousov 	} else
1564c5bf591SKonstantin Belousov 		fp = (struct osigframe *)regs->tf_esp - 1;
1574c5bf591SKonstantin Belousov 
1584c5bf591SKonstantin Belousov 	/* Build the argument list for the signal handler. */
1594c5bf591SKonstantin Belousov 	sf.sf_signum = sig;
1604c5bf591SKonstantin Belousov 	sf.sf_scp = (register_t)&fp->sf_siginfo.si_sc;
1614c5bf591SKonstantin Belousov 	bzero(&sf.sf_siginfo, sizeof(sf.sf_siginfo));
1624c5bf591SKonstantin Belousov 	if (SIGISMEMBER(psp->ps_siginfo, sig)) {
1634c5bf591SKonstantin Belousov 		/* Signal handler installed with SA_SIGINFO. */
1644c5bf591SKonstantin Belousov 		sf.sf_arg2 = (register_t)&fp->sf_siginfo;
1654c5bf591SKonstantin Belousov 		sf.sf_siginfo.si_signo = sig;
1664c5bf591SKonstantin Belousov 		sf.sf_siginfo.si_code = ksi->ksi_code;
1674c5bf591SKonstantin Belousov 		sf.sf_ahu.sf_action = (__osiginfohandler_t *)catcher;
1684c5bf591SKonstantin Belousov 		sf.sf_addr = 0;
1694c5bf591SKonstantin Belousov 	} else {
1704c5bf591SKonstantin Belousov 		/* Old FreeBSD-style arguments. */
1714c5bf591SKonstantin Belousov 		sf.sf_arg2 = ksi->ksi_code;
1724c5bf591SKonstantin Belousov 		sf.sf_addr = (register_t)ksi->ksi_addr;
1734c5bf591SKonstantin Belousov 		sf.sf_ahu.sf_handler = catcher;
1744c5bf591SKonstantin Belousov 	}
1754c5bf591SKonstantin Belousov 	mtx_unlock(&psp->ps_mtx);
1764c5bf591SKonstantin Belousov 	PROC_UNLOCK(p);
1774c5bf591SKonstantin Belousov 
1784c5bf591SKonstantin Belousov 	/* Save most if not all of trap frame. */
1794c5bf591SKonstantin Belousov 	sf.sf_siginfo.si_sc.sc_eax = regs->tf_eax;
1804c5bf591SKonstantin Belousov 	sf.sf_siginfo.si_sc.sc_ebx = regs->tf_ebx;
1814c5bf591SKonstantin Belousov 	sf.sf_siginfo.si_sc.sc_ecx = regs->tf_ecx;
1824c5bf591SKonstantin Belousov 	sf.sf_siginfo.si_sc.sc_edx = regs->tf_edx;
1834c5bf591SKonstantin Belousov 	sf.sf_siginfo.si_sc.sc_esi = regs->tf_esi;
1844c5bf591SKonstantin Belousov 	sf.sf_siginfo.si_sc.sc_edi = regs->tf_edi;
1854c5bf591SKonstantin Belousov 	sf.sf_siginfo.si_sc.sc_cs = regs->tf_cs;
1864c5bf591SKonstantin Belousov 	sf.sf_siginfo.si_sc.sc_ds = regs->tf_ds;
1874c5bf591SKonstantin Belousov 	sf.sf_siginfo.si_sc.sc_ss = regs->tf_ss;
1884c5bf591SKonstantin Belousov 	sf.sf_siginfo.si_sc.sc_es = regs->tf_es;
1894c5bf591SKonstantin Belousov 	sf.sf_siginfo.si_sc.sc_fs = regs->tf_fs;
1904c5bf591SKonstantin Belousov 	sf.sf_siginfo.si_sc.sc_gs = rgs();
1914c5bf591SKonstantin Belousov 	sf.sf_siginfo.si_sc.sc_isp = regs->tf_isp;
1924c5bf591SKonstantin Belousov 
1934c5bf591SKonstantin Belousov 	/* Build the signal context to be used by osigreturn(). */
1944c5bf591SKonstantin Belousov 	sf.sf_siginfo.si_sc.sc_onstack = (oonstack) ? 1 : 0;
1954c5bf591SKonstantin Belousov 	SIG2OSIG(*mask, sf.sf_siginfo.si_sc.sc_mask);
1964c5bf591SKonstantin Belousov 	sf.sf_siginfo.si_sc.sc_sp = regs->tf_esp;
1974c5bf591SKonstantin Belousov 	sf.sf_siginfo.si_sc.sc_fp = regs->tf_ebp;
1984c5bf591SKonstantin Belousov 	sf.sf_siginfo.si_sc.sc_pc = regs->tf_eip;
1994c5bf591SKonstantin Belousov 	sf.sf_siginfo.si_sc.sc_ps = regs->tf_eflags;
2004c5bf591SKonstantin Belousov 	sf.sf_siginfo.si_sc.sc_trapno = regs->tf_trapno;
2014c5bf591SKonstantin Belousov 	sf.sf_siginfo.si_sc.sc_err = regs->tf_err;
2024c5bf591SKonstantin Belousov 
2034c5bf591SKonstantin Belousov 	/*
2044c5bf591SKonstantin Belousov 	 * If we're a vm86 process, we want to save the segment registers.
2054c5bf591SKonstantin Belousov 	 * We also change eflags to be our emulated eflags, not the actual
2064c5bf591SKonstantin Belousov 	 * eflags.
2074c5bf591SKonstantin Belousov 	 */
2084c5bf591SKonstantin Belousov 	if (regs->tf_eflags & PSL_VM) {
2094c5bf591SKonstantin Belousov 		/* XXX confusing names: `tf' isn't a trapframe; `regs' is. */
2104c5bf591SKonstantin Belousov 		struct trapframe_vm86 *tf = (struct trapframe_vm86 *)regs;
2114c5bf591SKonstantin Belousov 		struct vm86_kernel *vm86 = &td->td_pcb->pcb_ext->ext_vm86;
2124c5bf591SKonstantin Belousov 
2134c5bf591SKonstantin Belousov 		sf.sf_siginfo.si_sc.sc_gs = tf->tf_vm86_gs;
2144c5bf591SKonstantin Belousov 		sf.sf_siginfo.si_sc.sc_fs = tf->tf_vm86_fs;
2154c5bf591SKonstantin Belousov 		sf.sf_siginfo.si_sc.sc_es = tf->tf_vm86_es;
2164c5bf591SKonstantin Belousov 		sf.sf_siginfo.si_sc.sc_ds = tf->tf_vm86_ds;
2174c5bf591SKonstantin Belousov 
2184c5bf591SKonstantin Belousov 		if (vm86->vm86_has_vme == 0)
2194c5bf591SKonstantin Belousov 			sf.sf_siginfo.si_sc.sc_ps =
2204c5bf591SKonstantin Belousov 			    (tf->tf_eflags & ~(PSL_VIF | PSL_VIP)) |
2214c5bf591SKonstantin Belousov 			    (vm86->vm86_eflags & (PSL_VIF | PSL_VIP));
2224c5bf591SKonstantin Belousov 
2234c5bf591SKonstantin Belousov 		/* See sendsig() for comments. */
2244c5bf591SKonstantin Belousov 		tf->tf_eflags &= ~(PSL_VM | PSL_NT | PSL_VIF | PSL_VIP);
2254c5bf591SKonstantin Belousov 	}
2264c5bf591SKonstantin Belousov 
2274c5bf591SKonstantin Belousov 	/*
2284c5bf591SKonstantin Belousov 	 * Copy the sigframe out to the user's stack.
2294c5bf591SKonstantin Belousov 	 */
2304c5bf591SKonstantin Belousov 	if (copyout(&sf, fp, sizeof(*fp)) != 0) {
2314c5bf591SKonstantin Belousov 		PROC_LOCK(p);
2324c5bf591SKonstantin Belousov 		sigexit(td, SIGILL);
2334c5bf591SKonstantin Belousov 	}
2344c5bf591SKonstantin Belousov 
2354c5bf591SKonstantin Belousov 	regs->tf_esp = (int)fp;
236361971fbSKornel Dulęba 	if (PROC_HAS_SHP(p)) {
237f6ac79fbSKornel Dulęba 		regs->tf_eip = PROC_SIGCODE(p) + szsigcode -
2384c5bf591SKonstantin Belousov 		    szosigcode;
2394c5bf591SKonstantin Belousov 	} else {
2404c5bf591SKonstantin Belousov 		/* a.out sysentvec does not use shared page */
241706f4a81SMark Johnston 		regs->tf_eip = PROC_PS_STRINGS(p) - szosigcode;
2424c5bf591SKonstantin Belousov 	}
2434c5bf591SKonstantin Belousov 	regs->tf_eflags &= ~(PSL_T | PSL_D);
2444c5bf591SKonstantin Belousov 	regs->tf_cs = _ucodesel;
2454c5bf591SKonstantin Belousov 	regs->tf_ds = _udatasel;
2464c5bf591SKonstantin Belousov 	regs->tf_es = _udatasel;
2474c5bf591SKonstantin Belousov 	regs->tf_fs = _udatasel;
2484c5bf591SKonstantin Belousov 	load_gs(_udatasel);
2494c5bf591SKonstantin Belousov 	regs->tf_ss = _udatasel;
2504c5bf591SKonstantin Belousov 	PROC_LOCK(p);
2514c5bf591SKonstantin Belousov 	mtx_lock(&psp->ps_mtx);
2524c5bf591SKonstantin Belousov }
2534c5bf591SKonstantin Belousov #endif /* COMPAT_43 */
2544c5bf591SKonstantin Belousov 
2554c5bf591SKonstantin Belousov #ifdef COMPAT_FREEBSD4
2564c5bf591SKonstantin Belousov static void
freebsd4_sendsig(sig_t catcher,ksiginfo_t * ksi,sigset_t * mask)2574c5bf591SKonstantin Belousov freebsd4_sendsig(sig_t catcher, ksiginfo_t *ksi, sigset_t *mask)
2584c5bf591SKonstantin Belousov {
259efdb03e9SJohn Baldwin 	struct freebsd4_sigframe sf, *sfp;
2604c5bf591SKonstantin Belousov 	struct proc *p;
2614c5bf591SKonstantin Belousov 	struct thread *td;
2624c5bf591SKonstantin Belousov 	struct sigacts *psp;
2634c5bf591SKonstantin Belousov 	struct trapframe *regs;
2644c5bf591SKonstantin Belousov 	int sig;
2654c5bf591SKonstantin Belousov 	int oonstack;
2664c5bf591SKonstantin Belousov 
2674c5bf591SKonstantin Belousov 	td = curthread;
2684c5bf591SKonstantin Belousov 	p = td->td_proc;
2694c5bf591SKonstantin Belousov 	PROC_LOCK_ASSERT(p, MA_OWNED);
2704c5bf591SKonstantin Belousov 	sig = ksi->ksi_signo;
2714c5bf591SKonstantin Belousov 	psp = p->p_sigacts;
2724c5bf591SKonstantin Belousov 	mtx_assert(&psp->ps_mtx, MA_OWNED);
2734c5bf591SKonstantin Belousov 	regs = td->td_frame;
2744c5bf591SKonstantin Belousov 	oonstack = sigonstack(regs->tf_esp);
2754c5bf591SKonstantin Belousov 
2764c5bf591SKonstantin Belousov 	/* Save user context. */
2774c5bf591SKonstantin Belousov 	bzero(&sf, sizeof(sf));
2784c5bf591SKonstantin Belousov 	sf.sf_uc.uc_sigmask = *mask;
2794c5bf591SKonstantin Belousov 	sf.sf_uc.uc_stack = td->td_sigstk;
2804c5bf591SKonstantin Belousov 	sf.sf_uc.uc_stack.ss_flags = (td->td_pflags & TDP_ALTSTACK)
2814c5bf591SKonstantin Belousov 	    ? ((oonstack) ? SS_ONSTACK : 0) : SS_DISABLE;
2824c5bf591SKonstantin Belousov 	sf.sf_uc.uc_mcontext.mc_onstack = (oonstack) ? 1 : 0;
2834c5bf591SKonstantin Belousov 	sf.sf_uc.uc_mcontext.mc_gs = rgs();
2844c5bf591SKonstantin Belousov 	bcopy(regs, &sf.sf_uc.uc_mcontext.mc_fs, sizeof(*regs));
2854c5bf591SKonstantin Belousov 	bzero(sf.sf_uc.uc_mcontext.mc_fpregs,
2864c5bf591SKonstantin Belousov 	    sizeof(sf.sf_uc.uc_mcontext.mc_fpregs));
2874c5bf591SKonstantin Belousov 	bzero(sf.sf_uc.uc_mcontext.__spare__,
2884c5bf591SKonstantin Belousov 	    sizeof(sf.sf_uc.uc_mcontext.__spare__));
2894c5bf591SKonstantin Belousov 	bzero(sf.sf_uc.__spare__, sizeof(sf.sf_uc.__spare__));
2904c5bf591SKonstantin Belousov 
2914c5bf591SKonstantin Belousov 	/* Allocate space for the signal handler context. */
2924c5bf591SKonstantin Belousov 	if ((td->td_pflags & TDP_ALTSTACK) != 0 && !oonstack &&
2934c5bf591SKonstantin Belousov 	    SIGISMEMBER(psp->ps_sigonstack, sig)) {
294efdb03e9SJohn Baldwin 		sfp = (struct freebsd4_sigframe *)((uintptr_t)td->td_sigstk.ss_sp +
295efdb03e9SJohn Baldwin 		    td->td_sigstk.ss_size - sizeof(struct freebsd4_sigframe));
2964c5bf591SKonstantin Belousov #if defined(COMPAT_43)
2974c5bf591SKonstantin Belousov 		td->td_sigstk.ss_flags |= SS_ONSTACK;
2984c5bf591SKonstantin Belousov #endif
2994c5bf591SKonstantin Belousov 	} else
300efdb03e9SJohn Baldwin 		sfp = (struct freebsd4_sigframe *)regs->tf_esp - 1;
3014c5bf591SKonstantin Belousov 
3024c5bf591SKonstantin Belousov 	/* Build the argument list for the signal handler. */
3034c5bf591SKonstantin Belousov 	sf.sf_signum = sig;
3044c5bf591SKonstantin Belousov 	sf.sf_ucontext = (register_t)&sfp->sf_uc;
3054c5bf591SKonstantin Belousov 	bzero(&sf.sf_si, sizeof(sf.sf_si));
3064c5bf591SKonstantin Belousov 	if (SIGISMEMBER(psp->ps_siginfo, sig)) {
3074c5bf591SKonstantin Belousov 		/* Signal handler installed with SA_SIGINFO. */
3084c5bf591SKonstantin Belousov 		sf.sf_siginfo = (register_t)&sfp->sf_si;
3094c5bf591SKonstantin Belousov 		sf.sf_ahu.sf_action = (__siginfohandler_t *)catcher;
3104c5bf591SKonstantin Belousov 
3114c5bf591SKonstantin Belousov 		/* Fill in POSIX parts */
3124c5bf591SKonstantin Belousov 		sf.sf_si.si_signo = sig;
3134c5bf591SKonstantin Belousov 		sf.sf_si.si_code = ksi->ksi_code;
3144c5bf591SKonstantin Belousov 		sf.sf_si.si_addr = ksi->ksi_addr;
3154c5bf591SKonstantin Belousov 	} else {
3164c5bf591SKonstantin Belousov 		/* Old FreeBSD-style arguments. */
3174c5bf591SKonstantin Belousov 		sf.sf_siginfo = ksi->ksi_code;
3184c5bf591SKonstantin Belousov 		sf.sf_addr = (register_t)ksi->ksi_addr;
3194c5bf591SKonstantin Belousov 		sf.sf_ahu.sf_handler = catcher;
3204c5bf591SKonstantin Belousov 	}
3214c5bf591SKonstantin Belousov 	mtx_unlock(&psp->ps_mtx);
3224c5bf591SKonstantin Belousov 	PROC_UNLOCK(p);
3234c5bf591SKonstantin Belousov 
3244c5bf591SKonstantin Belousov 	/*
3254c5bf591SKonstantin Belousov 	 * If we're a vm86 process, we want to save the segment registers.
3264c5bf591SKonstantin Belousov 	 * We also change eflags to be our emulated eflags, not the actual
3274c5bf591SKonstantin Belousov 	 * eflags.
3284c5bf591SKonstantin Belousov 	 */
3294c5bf591SKonstantin Belousov 	if (regs->tf_eflags & PSL_VM) {
3304c5bf591SKonstantin Belousov 		struct trapframe_vm86 *tf = (struct trapframe_vm86 *)regs;
3314c5bf591SKonstantin Belousov 		struct vm86_kernel *vm86 = &td->td_pcb->pcb_ext->ext_vm86;
3324c5bf591SKonstantin Belousov 
3334c5bf591SKonstantin Belousov 		sf.sf_uc.uc_mcontext.mc_gs = tf->tf_vm86_gs;
3344c5bf591SKonstantin Belousov 		sf.sf_uc.uc_mcontext.mc_fs = tf->tf_vm86_fs;
3354c5bf591SKonstantin Belousov 		sf.sf_uc.uc_mcontext.mc_es = tf->tf_vm86_es;
3364c5bf591SKonstantin Belousov 		sf.sf_uc.uc_mcontext.mc_ds = tf->tf_vm86_ds;
3374c5bf591SKonstantin Belousov 
3384c5bf591SKonstantin Belousov 		if (vm86->vm86_has_vme == 0)
3394c5bf591SKonstantin Belousov 			sf.sf_uc.uc_mcontext.mc_eflags =
3404c5bf591SKonstantin Belousov 			    (tf->tf_eflags & ~(PSL_VIF | PSL_VIP)) |
3414c5bf591SKonstantin Belousov 			    (vm86->vm86_eflags & (PSL_VIF | PSL_VIP));
3424c5bf591SKonstantin Belousov 
3434c5bf591SKonstantin Belousov 		/*
3444c5bf591SKonstantin Belousov 		 * Clear PSL_NT to inhibit T_TSSFLT faults on return from
3454c5bf591SKonstantin Belousov 		 * syscalls made by the signal handler.  This just avoids
3464c5bf591SKonstantin Belousov 		 * wasting time for our lazy fixup of such faults.  PSL_NT
3474c5bf591SKonstantin Belousov 		 * does nothing in vm86 mode, but vm86 programs can set it
3484c5bf591SKonstantin Belousov 		 * almost legitimately in probes for old cpu types.
3494c5bf591SKonstantin Belousov 		 */
3504c5bf591SKonstantin Belousov 		tf->tf_eflags &= ~(PSL_VM | PSL_NT | PSL_VIF | PSL_VIP);
3514c5bf591SKonstantin Belousov 	}
3524c5bf591SKonstantin Belousov 
3534c5bf591SKonstantin Belousov 	/*
3544c5bf591SKonstantin Belousov 	 * Copy the sigframe out to the user's stack.
3554c5bf591SKonstantin Belousov 	 */
3564c5bf591SKonstantin Belousov 	if (copyout(&sf, sfp, sizeof(*sfp)) != 0) {
3574c5bf591SKonstantin Belousov 		PROC_LOCK(p);
3584c5bf591SKonstantin Belousov 		sigexit(td, SIGILL);
3594c5bf591SKonstantin Belousov 	}
3604c5bf591SKonstantin Belousov 
3614c5bf591SKonstantin Belousov 	regs->tf_esp = (int)sfp;
362f6ac79fbSKornel Dulęba 	regs->tf_eip = PROC_SIGCODE(p) + szsigcode -
3634c5bf591SKonstantin Belousov 	    szfreebsd4_sigcode;
3644c5bf591SKonstantin Belousov 	regs->tf_eflags &= ~(PSL_T | PSL_D);
3654c5bf591SKonstantin Belousov 	regs->tf_cs = _ucodesel;
3664c5bf591SKonstantin Belousov 	regs->tf_ds = _udatasel;
3674c5bf591SKonstantin Belousov 	regs->tf_es = _udatasel;
3684c5bf591SKonstantin Belousov 	regs->tf_fs = _udatasel;
3694c5bf591SKonstantin Belousov 	regs->tf_ss = _udatasel;
3704c5bf591SKonstantin Belousov 	PROC_LOCK(p);
3714c5bf591SKonstantin Belousov 	mtx_lock(&psp->ps_mtx);
3724c5bf591SKonstantin Belousov }
3734c5bf591SKonstantin Belousov #endif	/* COMPAT_FREEBSD4 */
3744c5bf591SKonstantin Belousov 
3754c5bf591SKonstantin Belousov void
sendsig(sig_t catcher,ksiginfo_t * ksi,sigset_t * mask)3764c5bf591SKonstantin Belousov sendsig(sig_t catcher, ksiginfo_t *ksi, sigset_t *mask)
3774c5bf591SKonstantin Belousov {
3784c5bf591SKonstantin Belousov 	struct sigframe sf, *sfp;
3794c5bf591SKonstantin Belousov 	struct proc *p;
3804c5bf591SKonstantin Belousov 	struct thread *td;
3814c5bf591SKonstantin Belousov 	struct sigacts *psp;
3824c5bf591SKonstantin Belousov 	char *sp;
3834c5bf591SKonstantin Belousov 	struct trapframe *regs;
3844c5bf591SKonstantin Belousov 	struct segment_descriptor *sdp;
3854c5bf591SKonstantin Belousov 	char *xfpusave;
3864c5bf591SKonstantin Belousov 	size_t xfpusave_len;
3874c5bf591SKonstantin Belousov 	int sig;
3884c5bf591SKonstantin Belousov 	int oonstack;
3894c5bf591SKonstantin Belousov 
3904c5bf591SKonstantin Belousov 	td = curthread;
3914c5bf591SKonstantin Belousov 	p = td->td_proc;
3924c5bf591SKonstantin Belousov 	PROC_LOCK_ASSERT(p, MA_OWNED);
3934c5bf591SKonstantin Belousov 	sig = ksi->ksi_signo;
3944c5bf591SKonstantin Belousov 	psp = p->p_sigacts;
3954c5bf591SKonstantin Belousov 	mtx_assert(&psp->ps_mtx, MA_OWNED);
3964c5bf591SKonstantin Belousov #ifdef COMPAT_FREEBSD4
3974c5bf591SKonstantin Belousov 	if (SIGISMEMBER(psp->ps_freebsd4, sig)) {
3984c5bf591SKonstantin Belousov 		freebsd4_sendsig(catcher, ksi, mask);
3994c5bf591SKonstantin Belousov 		return;
4004c5bf591SKonstantin Belousov 	}
4014c5bf591SKonstantin Belousov #endif
4024c5bf591SKonstantin Belousov #ifdef COMPAT_43
4034c5bf591SKonstantin Belousov 	if (SIGISMEMBER(psp->ps_osigset, sig)) {
4044c5bf591SKonstantin Belousov 		osendsig(catcher, ksi, mask);
4054c5bf591SKonstantin Belousov 		return;
4064c5bf591SKonstantin Belousov 	}
4074c5bf591SKonstantin Belousov #endif
4084c5bf591SKonstantin Belousov 	regs = td->td_frame;
4094c5bf591SKonstantin Belousov 	oonstack = sigonstack(regs->tf_esp);
4104c5bf591SKonstantin Belousov 
4114c5bf591SKonstantin Belousov 	if (cpu_max_ext_state_size > sizeof(union savefpu) && use_xsave) {
4124c5bf591SKonstantin Belousov 		xfpusave_len = cpu_max_ext_state_size - sizeof(union savefpu);
4134c5bf591SKonstantin Belousov 		xfpusave = __builtin_alloca(xfpusave_len);
4144c5bf591SKonstantin Belousov 	} else {
4154c5bf591SKonstantin Belousov 		xfpusave_len = 0;
4164c5bf591SKonstantin Belousov 		xfpusave = NULL;
4174c5bf591SKonstantin Belousov 	}
4184c5bf591SKonstantin Belousov 
4194c5bf591SKonstantin Belousov 	/* Save user context. */
4204c5bf591SKonstantin Belousov 	bzero(&sf, sizeof(sf));
4214c5bf591SKonstantin Belousov 	sf.sf_uc.uc_sigmask = *mask;
4224c5bf591SKonstantin Belousov 	sf.sf_uc.uc_stack = td->td_sigstk;
4234c5bf591SKonstantin Belousov 	sf.sf_uc.uc_stack.ss_flags = (td->td_pflags & TDP_ALTSTACK)
4244c5bf591SKonstantin Belousov 	    ? ((oonstack) ? SS_ONSTACK : 0) : SS_DISABLE;
4254c5bf591SKonstantin Belousov 	sf.sf_uc.uc_mcontext.mc_onstack = (oonstack) ? 1 : 0;
4264c5bf591SKonstantin Belousov 	sf.sf_uc.uc_mcontext.mc_gs = rgs();
4274c5bf591SKonstantin Belousov 	bcopy(regs, &sf.sf_uc.uc_mcontext.mc_fs, sizeof(*regs));
4284c5bf591SKonstantin Belousov 	sf.sf_uc.uc_mcontext.mc_len = sizeof(sf.sf_uc.uc_mcontext); /* magic */
4294c5bf591SKonstantin Belousov 	get_fpcontext(td, &sf.sf_uc.uc_mcontext, xfpusave, xfpusave_len);
4304c5bf591SKonstantin Belousov 	fpstate_drop(td);
4314c5bf591SKonstantin Belousov 	/*
4324c5bf591SKonstantin Belousov 	 * Unconditionally fill the fsbase and gsbase into the mcontext.
4334c5bf591SKonstantin Belousov 	 */
4344c5bf591SKonstantin Belousov 	sdp = &td->td_pcb->pcb_fsd;
4354c5bf591SKonstantin Belousov 	sf.sf_uc.uc_mcontext.mc_fsbase = sdp->sd_hibase << 24 |
4364c5bf591SKonstantin Belousov 	    sdp->sd_lobase;
4374c5bf591SKonstantin Belousov 	sdp = &td->td_pcb->pcb_gsd;
4384c5bf591SKonstantin Belousov 	sf.sf_uc.uc_mcontext.mc_gsbase = sdp->sd_hibase << 24 |
4394c5bf591SKonstantin Belousov 	    sdp->sd_lobase;
4404c5bf591SKonstantin Belousov 	bzero(sf.sf_uc.uc_mcontext.mc_spare2,
4414c5bf591SKonstantin Belousov 	    sizeof(sf.sf_uc.uc_mcontext.mc_spare2));
4424c5bf591SKonstantin Belousov 
4434c5bf591SKonstantin Belousov 	/* Allocate space for the signal handler context. */
4444c5bf591SKonstantin Belousov 	if ((td->td_pflags & TDP_ALTSTACK) != 0 && !oonstack &&
4454c5bf591SKonstantin Belousov 	    SIGISMEMBER(psp->ps_sigonstack, sig)) {
4464c5bf591SKonstantin Belousov 		sp = (char *)td->td_sigstk.ss_sp + td->td_sigstk.ss_size;
4474c5bf591SKonstantin Belousov #if defined(COMPAT_43)
4484c5bf591SKonstantin Belousov 		td->td_sigstk.ss_flags |= SS_ONSTACK;
4494c5bf591SKonstantin Belousov #endif
4504c5bf591SKonstantin Belousov 	} else
4514c5bf591SKonstantin Belousov 		sp = (char *)regs->tf_esp - 128;
4524c5bf591SKonstantin Belousov 	if (xfpusave != NULL) {
4534c5bf591SKonstantin Belousov 		sp -= xfpusave_len;
4544c5bf591SKonstantin Belousov 		sp = (char *)((unsigned int)sp & ~0x3F);
4554c5bf591SKonstantin Belousov 		sf.sf_uc.uc_mcontext.mc_xfpustate = (register_t)sp;
4564c5bf591SKonstantin Belousov 	}
4574c5bf591SKonstantin Belousov 	sp -= sizeof(struct sigframe);
4584c5bf591SKonstantin Belousov 
4594c5bf591SKonstantin Belousov 	/* Align to 16 bytes. */
4604c5bf591SKonstantin Belousov 	sfp = (struct sigframe *)((unsigned int)sp & ~0xF);
4614c5bf591SKonstantin Belousov 
4624c5bf591SKonstantin Belousov 	/* Build the argument list for the signal handler. */
4634c5bf591SKonstantin Belousov 	sf.sf_signum = sig;
4644c5bf591SKonstantin Belousov 	sf.sf_ucontext = (register_t)&sfp->sf_uc;
4654c5bf591SKonstantin Belousov 	bzero(&sf.sf_si, sizeof(sf.sf_si));
4664c5bf591SKonstantin Belousov 	if (SIGISMEMBER(psp->ps_siginfo, sig)) {
4674c5bf591SKonstantin Belousov 		/* Signal handler installed with SA_SIGINFO. */
4684c5bf591SKonstantin Belousov 		sf.sf_siginfo = (register_t)&sfp->sf_si;
4694c5bf591SKonstantin Belousov 		sf.sf_ahu.sf_action = (__siginfohandler_t *)catcher;
4704c5bf591SKonstantin Belousov 
4714c5bf591SKonstantin Belousov 		/* Fill in POSIX parts */
4724c5bf591SKonstantin Belousov 		sf.sf_si = ksi->ksi_info;
4734c5bf591SKonstantin Belousov 		sf.sf_si.si_signo = sig; /* maybe a translated signal */
4744c5bf591SKonstantin Belousov 	} else {
4754c5bf591SKonstantin Belousov 		/* Old FreeBSD-style arguments. */
4764c5bf591SKonstantin Belousov 		sf.sf_siginfo = ksi->ksi_code;
4774c5bf591SKonstantin Belousov 		sf.sf_addr = (register_t)ksi->ksi_addr;
4784c5bf591SKonstantin Belousov 		sf.sf_ahu.sf_handler = catcher;
4794c5bf591SKonstantin Belousov 	}
4804c5bf591SKonstantin Belousov 	mtx_unlock(&psp->ps_mtx);
4814c5bf591SKonstantin Belousov 	PROC_UNLOCK(p);
4824c5bf591SKonstantin Belousov 
4834c5bf591SKonstantin Belousov 	/*
4844c5bf591SKonstantin Belousov 	 * If we're a vm86 process, we want to save the segment registers.
4854c5bf591SKonstantin Belousov 	 * We also change eflags to be our emulated eflags, not the actual
4864c5bf591SKonstantin Belousov 	 * eflags.
4874c5bf591SKonstantin Belousov 	 */
4884c5bf591SKonstantin Belousov 	if (regs->tf_eflags & PSL_VM) {
4894c5bf591SKonstantin Belousov 		struct trapframe_vm86 *tf = (struct trapframe_vm86 *)regs;
4904c5bf591SKonstantin Belousov 		struct vm86_kernel *vm86 = &td->td_pcb->pcb_ext->ext_vm86;
4914c5bf591SKonstantin Belousov 
4924c5bf591SKonstantin Belousov 		sf.sf_uc.uc_mcontext.mc_gs = tf->tf_vm86_gs;
4934c5bf591SKonstantin Belousov 		sf.sf_uc.uc_mcontext.mc_fs = tf->tf_vm86_fs;
4944c5bf591SKonstantin Belousov 		sf.sf_uc.uc_mcontext.mc_es = tf->tf_vm86_es;
4954c5bf591SKonstantin Belousov 		sf.sf_uc.uc_mcontext.mc_ds = tf->tf_vm86_ds;
4964c5bf591SKonstantin Belousov 
4974c5bf591SKonstantin Belousov 		if (vm86->vm86_has_vme == 0)
4984c5bf591SKonstantin Belousov 			sf.sf_uc.uc_mcontext.mc_eflags =
4994c5bf591SKonstantin Belousov 			    (tf->tf_eflags & ~(PSL_VIF | PSL_VIP)) |
5004c5bf591SKonstantin Belousov 			    (vm86->vm86_eflags & (PSL_VIF | PSL_VIP));
5014c5bf591SKonstantin Belousov 
5024c5bf591SKonstantin Belousov 		/*
5034c5bf591SKonstantin Belousov 		 * Clear PSL_NT to inhibit T_TSSFLT faults on return from
5044c5bf591SKonstantin Belousov 		 * syscalls made by the signal handler.  This just avoids
5054c5bf591SKonstantin Belousov 		 * wasting time for our lazy fixup of such faults.  PSL_NT
5064c5bf591SKonstantin Belousov 		 * does nothing in vm86 mode, but vm86 programs can set it
5074c5bf591SKonstantin Belousov 		 * almost legitimately in probes for old cpu types.
5084c5bf591SKonstantin Belousov 		 */
5094c5bf591SKonstantin Belousov 		tf->tf_eflags &= ~(PSL_VM | PSL_NT | PSL_VIF | PSL_VIP);
5104c5bf591SKonstantin Belousov 	}
5114c5bf591SKonstantin Belousov 
5124c5bf591SKonstantin Belousov 	/*
5134c5bf591SKonstantin Belousov 	 * Copy the sigframe out to the user's stack.
5144c5bf591SKonstantin Belousov 	 */
5154c5bf591SKonstantin Belousov 	if (copyout(&sf, sfp, sizeof(*sfp)) != 0 ||
5164c5bf591SKonstantin Belousov 	    (xfpusave != NULL && copyout(xfpusave,
5174c5bf591SKonstantin Belousov 	    (void *)sf.sf_uc.uc_mcontext.mc_xfpustate, xfpusave_len)
5184c5bf591SKonstantin Belousov 	    != 0)) {
5194c5bf591SKonstantin Belousov 		PROC_LOCK(p);
5204c5bf591SKonstantin Belousov 		sigexit(td, SIGILL);
5214c5bf591SKonstantin Belousov 	}
5224c5bf591SKonstantin Belousov 
5234c5bf591SKonstantin Belousov 	regs->tf_esp = (int)sfp;
524f6ac79fbSKornel Dulęba 	regs->tf_eip = PROC_SIGCODE(p);
5254c5bf591SKonstantin Belousov 	if (regs->tf_eip == 0)
526706f4a81SMark Johnston 		regs->tf_eip = PROC_PS_STRINGS(p) - szsigcode;
5274c5bf591SKonstantin Belousov 	regs->tf_eflags &= ~(PSL_T | PSL_D);
5284c5bf591SKonstantin Belousov 	regs->tf_cs = _ucodesel;
5294c5bf591SKonstantin Belousov 	regs->tf_ds = _udatasel;
5304c5bf591SKonstantin Belousov 	regs->tf_es = _udatasel;
5314c5bf591SKonstantin Belousov 	regs->tf_fs = _udatasel;
5324c5bf591SKonstantin Belousov 	regs->tf_ss = _udatasel;
5334c5bf591SKonstantin Belousov 	PROC_LOCK(p);
5344c5bf591SKonstantin Belousov 	mtx_lock(&psp->ps_mtx);
5354c5bf591SKonstantin Belousov }
5364c5bf591SKonstantin Belousov 
5374c5bf591SKonstantin Belousov /*
5384c5bf591SKonstantin Belousov  * System call to cleanup state after a signal has been taken.  Reset
5394c5bf591SKonstantin Belousov  * signal mask and stack state from context left by sendsig (above).
5404c5bf591SKonstantin Belousov  * Return to previous pc and psl as specified by context left by
5414c5bf591SKonstantin Belousov  * sendsig. Check carefully to make sure that the user has not
5424c5bf591SKonstantin Belousov  * modified the state to gain improper privileges.
5434c5bf591SKonstantin Belousov  */
5444c5bf591SKonstantin Belousov #ifdef COMPAT_43
5454c5bf591SKonstantin Belousov int
osigreturn(struct thread * td,struct osigreturn_args * uap)5464c5bf591SKonstantin Belousov osigreturn(struct thread *td, struct osigreturn_args *uap)
5474c5bf591SKonstantin Belousov {
5484c5bf591SKonstantin Belousov 	struct osigcontext sc;
5494c5bf591SKonstantin Belousov 	struct trapframe *regs;
5504c5bf591SKonstantin Belousov 	struct osigcontext *scp;
5514c5bf591SKonstantin Belousov 	int eflags, error;
5524c5bf591SKonstantin Belousov 	ksiginfo_t ksi;
5534c5bf591SKonstantin Belousov 
5544c5bf591SKonstantin Belousov 	regs = td->td_frame;
5554c5bf591SKonstantin Belousov 	error = copyin(uap->sigcntxp, &sc, sizeof(sc));
5564c5bf591SKonstantin Belousov 	if (error != 0)
5574c5bf591SKonstantin Belousov 		return (error);
5584c5bf591SKonstantin Belousov 	scp = &sc;
5594c5bf591SKonstantin Belousov 	eflags = scp->sc_ps;
5604c5bf591SKonstantin Belousov 	if (eflags & PSL_VM) {
5614c5bf591SKonstantin Belousov 		struct trapframe_vm86 *tf = (struct trapframe_vm86 *)regs;
5624c5bf591SKonstantin Belousov 		struct vm86_kernel *vm86;
5634c5bf591SKonstantin Belousov 
5644c5bf591SKonstantin Belousov 		/*
5654c5bf591SKonstantin Belousov 		 * if pcb_ext == 0 or vm86_inited == 0, the user hasn't
5664c5bf591SKonstantin Belousov 		 * set up the vm86 area, and we can't enter vm86 mode.
5674c5bf591SKonstantin Belousov 		 */
5684c5bf591SKonstantin Belousov 		if (td->td_pcb->pcb_ext == 0)
5694c5bf591SKonstantin Belousov 			return (EINVAL);
5704c5bf591SKonstantin Belousov 		vm86 = &td->td_pcb->pcb_ext->ext_vm86;
5714c5bf591SKonstantin Belousov 		if (vm86->vm86_inited == 0)
5724c5bf591SKonstantin Belousov 			return (EINVAL);
5734c5bf591SKonstantin Belousov 
5744c5bf591SKonstantin Belousov 		/* Go back to user mode if both flags are set. */
5754c5bf591SKonstantin Belousov 		if ((eflags & PSL_VIP) && (eflags & PSL_VIF)) {
5764c5bf591SKonstantin Belousov 			ksiginfo_init_trap(&ksi);
5774c5bf591SKonstantin Belousov 			ksi.ksi_signo = SIGBUS;
5784c5bf591SKonstantin Belousov 			ksi.ksi_code = BUS_OBJERR;
5794c5bf591SKonstantin Belousov 			ksi.ksi_addr = (void *)regs->tf_eip;
5804c5bf591SKonstantin Belousov 			trapsignal(td, &ksi);
5814c5bf591SKonstantin Belousov 		}
5824c5bf591SKonstantin Belousov 
5834c5bf591SKonstantin Belousov 		if (vm86->vm86_has_vme) {
5844c5bf591SKonstantin Belousov 			eflags = (tf->tf_eflags & ~VME_USERCHANGE) |
5854c5bf591SKonstantin Belousov 			    (eflags & VME_USERCHANGE) | PSL_VM;
5864c5bf591SKonstantin Belousov 		} else {
5874c5bf591SKonstantin Belousov 			vm86->vm86_eflags = eflags;	/* save VIF, VIP */
5884c5bf591SKonstantin Belousov 			eflags = (tf->tf_eflags & ~VM_USERCHANGE) |
5894c5bf591SKonstantin Belousov 			    (eflags & VM_USERCHANGE) | PSL_VM;
5904c5bf591SKonstantin Belousov 		}
5914c5bf591SKonstantin Belousov 		tf->tf_vm86_ds = scp->sc_ds;
5924c5bf591SKonstantin Belousov 		tf->tf_vm86_es = scp->sc_es;
5934c5bf591SKonstantin Belousov 		tf->tf_vm86_fs = scp->sc_fs;
5944c5bf591SKonstantin Belousov 		tf->tf_vm86_gs = scp->sc_gs;
5954c5bf591SKonstantin Belousov 		tf->tf_ds = _udatasel;
5964c5bf591SKonstantin Belousov 		tf->tf_es = _udatasel;
5974c5bf591SKonstantin Belousov 		tf->tf_fs = _udatasel;
5984c5bf591SKonstantin Belousov 	} else {
5994c5bf591SKonstantin Belousov 		/*
6004c5bf591SKonstantin Belousov 		 * Don't allow users to change privileged or reserved flags.
6014c5bf591SKonstantin Belousov 		 */
6024c5bf591SKonstantin Belousov 		if (!EFL_SECURE(eflags, regs->tf_eflags)) {
6034c5bf591SKonstantin Belousov 			return (EINVAL);
6044c5bf591SKonstantin Belousov 		}
6054c5bf591SKonstantin Belousov 
6064c5bf591SKonstantin Belousov 		/*
6074c5bf591SKonstantin Belousov 		 * Don't allow users to load a valid privileged %cs.  Let the
6084c5bf591SKonstantin Belousov 		 * hardware check for invalid selectors, excess privilege in
6094c5bf591SKonstantin Belousov 		 * other selectors, invalid %eip's and invalid %esp's.
6104c5bf591SKonstantin Belousov 		 */
6114c5bf591SKonstantin Belousov 		if (!CS_SECURE(scp->sc_cs)) {
6124c5bf591SKonstantin Belousov 			ksiginfo_init_trap(&ksi);
6134c5bf591SKonstantin Belousov 			ksi.ksi_signo = SIGBUS;
6144c5bf591SKonstantin Belousov 			ksi.ksi_code = BUS_OBJERR;
6154c5bf591SKonstantin Belousov 			ksi.ksi_trapno = T_PROTFLT;
6164c5bf591SKonstantin Belousov 			ksi.ksi_addr = (void *)regs->tf_eip;
6174c5bf591SKonstantin Belousov 			trapsignal(td, &ksi);
6184c5bf591SKonstantin Belousov 			return (EINVAL);
6194c5bf591SKonstantin Belousov 		}
6204c5bf591SKonstantin Belousov 		regs->tf_ds = scp->sc_ds;
6214c5bf591SKonstantin Belousov 		regs->tf_es = scp->sc_es;
6224c5bf591SKonstantin Belousov 		regs->tf_fs = scp->sc_fs;
6234c5bf591SKonstantin Belousov 	}
6244c5bf591SKonstantin Belousov 
6254c5bf591SKonstantin Belousov 	/* Restore remaining registers. */
6264c5bf591SKonstantin Belousov 	regs->tf_eax = scp->sc_eax;
6274c5bf591SKonstantin Belousov 	regs->tf_ebx = scp->sc_ebx;
6284c5bf591SKonstantin Belousov 	regs->tf_ecx = scp->sc_ecx;
6294c5bf591SKonstantin Belousov 	regs->tf_edx = scp->sc_edx;
6304c5bf591SKonstantin Belousov 	regs->tf_esi = scp->sc_esi;
6314c5bf591SKonstantin Belousov 	regs->tf_edi = scp->sc_edi;
6324c5bf591SKonstantin Belousov 	regs->tf_cs = scp->sc_cs;
6334c5bf591SKonstantin Belousov 	regs->tf_ss = scp->sc_ss;
6344c5bf591SKonstantin Belousov 	regs->tf_isp = scp->sc_isp;
6354c5bf591SKonstantin Belousov 	regs->tf_ebp = scp->sc_fp;
6364c5bf591SKonstantin Belousov 	regs->tf_esp = scp->sc_sp;
6374c5bf591SKonstantin Belousov 	regs->tf_eip = scp->sc_pc;
6384c5bf591SKonstantin Belousov 	regs->tf_eflags = eflags;
639dc4a2d1dSKonstantin Belousov 	regs->tf_trapno = T_RESERVED;
6404c5bf591SKonstantin Belousov 
6414c5bf591SKonstantin Belousov #if defined(COMPAT_43)
6424c5bf591SKonstantin Belousov 	if (scp->sc_onstack & 1)
6434c5bf591SKonstantin Belousov 		td->td_sigstk.ss_flags |= SS_ONSTACK;
6444c5bf591SKonstantin Belousov 	else
6454c5bf591SKonstantin Belousov 		td->td_sigstk.ss_flags &= ~SS_ONSTACK;
6464c5bf591SKonstantin Belousov #endif
6474c5bf591SKonstantin Belousov 	kern_sigprocmask(td, SIG_SETMASK, (sigset_t *)&scp->sc_mask, NULL,
6484c5bf591SKonstantin Belousov 	    SIGPROCMASK_OLD);
6494c5bf591SKonstantin Belousov 	return (EJUSTRETURN);
6504c5bf591SKonstantin Belousov }
6514c5bf591SKonstantin Belousov #endif /* COMPAT_43 */
6524c5bf591SKonstantin Belousov 
6534c5bf591SKonstantin Belousov #ifdef COMPAT_FREEBSD4
6544c5bf591SKonstantin Belousov int
freebsd4_sigreturn(struct thread * td,struct freebsd4_sigreturn_args * uap)6554c5bf591SKonstantin Belousov freebsd4_sigreturn(struct thread *td, struct freebsd4_sigreturn_args *uap)
6564c5bf591SKonstantin Belousov {
657717e7fb2SBrooks Davis 	struct freebsd4_ucontext uc;
6584c5bf591SKonstantin Belousov 	struct trapframe *regs;
659717e7fb2SBrooks Davis 	struct freebsd4_ucontext *ucp;
6604c5bf591SKonstantin Belousov 	int cs, eflags, error;
6614c5bf591SKonstantin Belousov 	ksiginfo_t ksi;
6624c5bf591SKonstantin Belousov 
6634c5bf591SKonstantin Belousov 	error = copyin(uap->sigcntxp, &uc, sizeof(uc));
6644c5bf591SKonstantin Belousov 	if (error != 0)
6654c5bf591SKonstantin Belousov 		return (error);
6664c5bf591SKonstantin Belousov 	ucp = &uc;
6674c5bf591SKonstantin Belousov 	regs = td->td_frame;
6684c5bf591SKonstantin Belousov 	eflags = ucp->uc_mcontext.mc_eflags;
6694c5bf591SKonstantin Belousov 	if (eflags & PSL_VM) {
6704c5bf591SKonstantin Belousov 		struct trapframe_vm86 *tf = (struct trapframe_vm86 *)regs;
6714c5bf591SKonstantin Belousov 		struct vm86_kernel *vm86;
6724c5bf591SKonstantin Belousov 
6734c5bf591SKonstantin Belousov 		/*
6744c5bf591SKonstantin Belousov 		 * if pcb_ext == 0 or vm86_inited == 0, the user hasn't
6754c5bf591SKonstantin Belousov 		 * set up the vm86 area, and we can't enter vm86 mode.
6764c5bf591SKonstantin Belousov 		 */
6774c5bf591SKonstantin Belousov 		if (td->td_pcb->pcb_ext == 0)
6784c5bf591SKonstantin Belousov 			return (EINVAL);
6794c5bf591SKonstantin Belousov 		vm86 = &td->td_pcb->pcb_ext->ext_vm86;
6804c5bf591SKonstantin Belousov 		if (vm86->vm86_inited == 0)
6814c5bf591SKonstantin Belousov 			return (EINVAL);
6824c5bf591SKonstantin Belousov 
6834c5bf591SKonstantin Belousov 		/* Go back to user mode if both flags are set. */
6844c5bf591SKonstantin Belousov 		if ((eflags & PSL_VIP) && (eflags & PSL_VIF)) {
6854c5bf591SKonstantin Belousov 			ksiginfo_init_trap(&ksi);
6864c5bf591SKonstantin Belousov 			ksi.ksi_signo = SIGBUS;
6874c5bf591SKonstantin Belousov 			ksi.ksi_code = BUS_OBJERR;
6884c5bf591SKonstantin Belousov 			ksi.ksi_addr = (void *)regs->tf_eip;
6894c5bf591SKonstantin Belousov 			trapsignal(td, &ksi);
6904c5bf591SKonstantin Belousov 		}
6914c5bf591SKonstantin Belousov 		if (vm86->vm86_has_vme) {
6924c5bf591SKonstantin Belousov 			eflags = (tf->tf_eflags & ~VME_USERCHANGE) |
6934c5bf591SKonstantin Belousov 			    (eflags & VME_USERCHANGE) | PSL_VM;
6944c5bf591SKonstantin Belousov 		} else {
6954c5bf591SKonstantin Belousov 			vm86->vm86_eflags = eflags;	/* save VIF, VIP */
6964c5bf591SKonstantin Belousov 			eflags = (tf->tf_eflags & ~VM_USERCHANGE) |
6974c5bf591SKonstantin Belousov 			    (eflags & VM_USERCHANGE) | PSL_VM;
6984c5bf591SKonstantin Belousov 		}
6994c5bf591SKonstantin Belousov 		bcopy(&ucp->uc_mcontext.mc_fs, tf, sizeof(struct trapframe));
7004c5bf591SKonstantin Belousov 		tf->tf_eflags = eflags;
7014c5bf591SKonstantin Belousov 		tf->tf_vm86_ds = tf->tf_ds;
7024c5bf591SKonstantin Belousov 		tf->tf_vm86_es = tf->tf_es;
7034c5bf591SKonstantin Belousov 		tf->tf_vm86_fs = tf->tf_fs;
7044c5bf591SKonstantin Belousov 		tf->tf_vm86_gs = ucp->uc_mcontext.mc_gs;
7054c5bf591SKonstantin Belousov 		tf->tf_ds = _udatasel;
7064c5bf591SKonstantin Belousov 		tf->tf_es = _udatasel;
7074c5bf591SKonstantin Belousov 		tf->tf_fs = _udatasel;
7084c5bf591SKonstantin Belousov 	} else {
7094c5bf591SKonstantin Belousov 		/*
7104c5bf591SKonstantin Belousov 		 * Don't allow users to change privileged or reserved flags.
7114c5bf591SKonstantin Belousov 		 */
7124c5bf591SKonstantin Belousov 		if (!EFL_SECURE(eflags, regs->tf_eflags)) {
7134c5bf591SKonstantin Belousov 			uprintf(
7144c5bf591SKonstantin Belousov 			    "pid %d (%s): freebsd4_sigreturn eflags = 0x%x\n",
7154c5bf591SKonstantin Belousov 			    td->td_proc->p_pid, td->td_name, eflags);
7164c5bf591SKonstantin Belousov 			return (EINVAL);
7174c5bf591SKonstantin Belousov 		}
7184c5bf591SKonstantin Belousov 
7194c5bf591SKonstantin Belousov 		/*
7204c5bf591SKonstantin Belousov 		 * Don't allow users to load a valid privileged %cs.  Let the
7214c5bf591SKonstantin Belousov 		 * hardware check for invalid selectors, excess privilege in
7224c5bf591SKonstantin Belousov 		 * other selectors, invalid %eip's and invalid %esp's.
7234c5bf591SKonstantin Belousov 		 */
7244c5bf591SKonstantin Belousov 		cs = ucp->uc_mcontext.mc_cs;
7254c5bf591SKonstantin Belousov 		if (!CS_SECURE(cs)) {
7264c5bf591SKonstantin Belousov 			uprintf("pid %d (%s): freebsd4_sigreturn cs = 0x%x\n",
7274c5bf591SKonstantin Belousov 			    td->td_proc->p_pid, td->td_name, cs);
7284c5bf591SKonstantin Belousov 			ksiginfo_init_trap(&ksi);
7294c5bf591SKonstantin Belousov 			ksi.ksi_signo = SIGBUS;
7304c5bf591SKonstantin Belousov 			ksi.ksi_code = BUS_OBJERR;
7314c5bf591SKonstantin Belousov 			ksi.ksi_trapno = T_PROTFLT;
7324c5bf591SKonstantin Belousov 			ksi.ksi_addr = (void *)regs->tf_eip;
7334c5bf591SKonstantin Belousov 			trapsignal(td, &ksi);
7344c5bf591SKonstantin Belousov 			return (EINVAL);
7354c5bf591SKonstantin Belousov 		}
7364c5bf591SKonstantin Belousov 
7374c5bf591SKonstantin Belousov 		bcopy(&ucp->uc_mcontext.mc_fs, regs, sizeof(*regs));
7384c5bf591SKonstantin Belousov 	}
739dc4a2d1dSKonstantin Belousov 	regs->tf_trapno = T_RESERVED;
7404c5bf591SKonstantin Belousov 
7414c5bf591SKonstantin Belousov #if defined(COMPAT_43)
7424c5bf591SKonstantin Belousov 	if (ucp->uc_mcontext.mc_onstack & 1)
7434c5bf591SKonstantin Belousov 		td->td_sigstk.ss_flags |= SS_ONSTACK;
7444c5bf591SKonstantin Belousov 	else
7454c5bf591SKonstantin Belousov 		td->td_sigstk.ss_flags &= ~SS_ONSTACK;
7464c5bf591SKonstantin Belousov #endif
7474c5bf591SKonstantin Belousov 	kern_sigprocmask(td, SIG_SETMASK, &ucp->uc_sigmask, NULL, 0);
7484c5bf591SKonstantin Belousov 	return (EJUSTRETURN);
7494c5bf591SKonstantin Belousov }
7504c5bf591SKonstantin Belousov #endif	/* COMPAT_FREEBSD4 */
7514c5bf591SKonstantin Belousov 
7524c5bf591SKonstantin Belousov int
sys_sigreturn(struct thread * td,struct sigreturn_args * uap)7534c5bf591SKonstantin Belousov sys_sigreturn(struct thread *td, struct sigreturn_args *uap)
7544c5bf591SKonstantin Belousov {
7554c5bf591SKonstantin Belousov 	ucontext_t uc;
7564c5bf591SKonstantin Belousov 	struct proc *p;
7574c5bf591SKonstantin Belousov 	struct trapframe *regs;
7584c5bf591SKonstantin Belousov 	ucontext_t *ucp;
7594c5bf591SKonstantin Belousov 	char *xfpustate;
7604c5bf591SKonstantin Belousov 	size_t xfpustate_len;
7614c5bf591SKonstantin Belousov 	int cs, eflags, error, ret;
7624c5bf591SKonstantin Belousov 	ksiginfo_t ksi;
7634c5bf591SKonstantin Belousov 
7644c5bf591SKonstantin Belousov 	p = td->td_proc;
7654c5bf591SKonstantin Belousov 
7664c5bf591SKonstantin Belousov 	error = copyin(uap->sigcntxp, &uc, sizeof(uc));
7674c5bf591SKonstantin Belousov 	if (error != 0)
7684c5bf591SKonstantin Belousov 		return (error);
7694c5bf591SKonstantin Belousov 	ucp = &uc;
7704c5bf591SKonstantin Belousov 	if ((ucp->uc_mcontext.mc_flags & ~_MC_FLAG_MASK) != 0) {
7714c5bf591SKonstantin Belousov 		uprintf("pid %d (%s): sigreturn mc_flags %x\n", p->p_pid,
7724c5bf591SKonstantin Belousov 		    td->td_name, ucp->uc_mcontext.mc_flags);
7734c5bf591SKonstantin Belousov 		return (EINVAL);
7744c5bf591SKonstantin Belousov 	}
7754c5bf591SKonstantin Belousov 	regs = td->td_frame;
7764c5bf591SKonstantin Belousov 	eflags = ucp->uc_mcontext.mc_eflags;
7774c5bf591SKonstantin Belousov 	if (eflags & PSL_VM) {
7784c5bf591SKonstantin Belousov 		struct trapframe_vm86 *tf = (struct trapframe_vm86 *)regs;
7794c5bf591SKonstantin Belousov 		struct vm86_kernel *vm86;
7804c5bf591SKonstantin Belousov 
7814c5bf591SKonstantin Belousov 		/*
7824c5bf591SKonstantin Belousov 		 * if pcb_ext == 0 or vm86_inited == 0, the user hasn't
7834c5bf591SKonstantin Belousov 		 * set up the vm86 area, and we can't enter vm86 mode.
7844c5bf591SKonstantin Belousov 		 */
7854c5bf591SKonstantin Belousov 		if (td->td_pcb->pcb_ext == 0)
7864c5bf591SKonstantin Belousov 			return (EINVAL);
7874c5bf591SKonstantin Belousov 		vm86 = &td->td_pcb->pcb_ext->ext_vm86;
7884c5bf591SKonstantin Belousov 		if (vm86->vm86_inited == 0)
7894c5bf591SKonstantin Belousov 			return (EINVAL);
7904c5bf591SKonstantin Belousov 
7914c5bf591SKonstantin Belousov 		/* Go back to user mode if both flags are set. */
7924c5bf591SKonstantin Belousov 		if ((eflags & PSL_VIP) && (eflags & PSL_VIF)) {
7934c5bf591SKonstantin Belousov 			ksiginfo_init_trap(&ksi);
7944c5bf591SKonstantin Belousov 			ksi.ksi_signo = SIGBUS;
7954c5bf591SKonstantin Belousov 			ksi.ksi_code = BUS_OBJERR;
7964c5bf591SKonstantin Belousov 			ksi.ksi_addr = (void *)regs->tf_eip;
7974c5bf591SKonstantin Belousov 			trapsignal(td, &ksi);
7984c5bf591SKonstantin Belousov 		}
7994c5bf591SKonstantin Belousov 
8004c5bf591SKonstantin Belousov 		if (vm86->vm86_has_vme) {
8014c5bf591SKonstantin Belousov 			eflags = (tf->tf_eflags & ~VME_USERCHANGE) |
8024c5bf591SKonstantin Belousov 			    (eflags & VME_USERCHANGE) | PSL_VM;
8034c5bf591SKonstantin Belousov 		} else {
8044c5bf591SKonstantin Belousov 			vm86->vm86_eflags = eflags;	/* save VIF, VIP */
8054c5bf591SKonstantin Belousov 			eflags = (tf->tf_eflags & ~VM_USERCHANGE) |
8064c5bf591SKonstantin Belousov 			    (eflags & VM_USERCHANGE) | PSL_VM;
8074c5bf591SKonstantin Belousov 		}
8084c5bf591SKonstantin Belousov 		bcopy(&ucp->uc_mcontext.mc_fs, tf, sizeof(struct trapframe));
8094c5bf591SKonstantin Belousov 		tf->tf_eflags = eflags;
8104c5bf591SKonstantin Belousov 		tf->tf_vm86_ds = tf->tf_ds;
8114c5bf591SKonstantin Belousov 		tf->tf_vm86_es = tf->tf_es;
8124c5bf591SKonstantin Belousov 		tf->tf_vm86_fs = tf->tf_fs;
8134c5bf591SKonstantin Belousov 		tf->tf_vm86_gs = ucp->uc_mcontext.mc_gs;
8144c5bf591SKonstantin Belousov 		tf->tf_ds = _udatasel;
8154c5bf591SKonstantin Belousov 		tf->tf_es = _udatasel;
8164c5bf591SKonstantin Belousov 		tf->tf_fs = _udatasel;
8174c5bf591SKonstantin Belousov 	} else {
8184c5bf591SKonstantin Belousov 		/*
8194c5bf591SKonstantin Belousov 		 * Don't allow users to change privileged or reserved flags.
8204c5bf591SKonstantin Belousov 		 */
8214c5bf591SKonstantin Belousov 		if (!EFL_SECURE(eflags, regs->tf_eflags)) {
8224c5bf591SKonstantin Belousov 			uprintf("pid %d (%s): sigreturn eflags = 0x%x\n",
8234c5bf591SKonstantin Belousov 			    td->td_proc->p_pid, td->td_name, eflags);
8244c5bf591SKonstantin Belousov 			return (EINVAL);
8254c5bf591SKonstantin Belousov 		}
8264c5bf591SKonstantin Belousov 
8274c5bf591SKonstantin Belousov 		/*
8284c5bf591SKonstantin Belousov 		 * Don't allow users to load a valid privileged %cs.  Let the
8294c5bf591SKonstantin Belousov 		 * hardware check for invalid selectors, excess privilege in
8304c5bf591SKonstantin Belousov 		 * other selectors, invalid %eip's and invalid %esp's.
8314c5bf591SKonstantin Belousov 		 */
8324c5bf591SKonstantin Belousov 		cs = ucp->uc_mcontext.mc_cs;
8334c5bf591SKonstantin Belousov 		if (!CS_SECURE(cs)) {
8344c5bf591SKonstantin Belousov 			uprintf("pid %d (%s): sigreturn cs = 0x%x\n",
8354c5bf591SKonstantin Belousov 			    td->td_proc->p_pid, td->td_name, cs);
8364c5bf591SKonstantin Belousov 			ksiginfo_init_trap(&ksi);
8374c5bf591SKonstantin Belousov 			ksi.ksi_signo = SIGBUS;
8384c5bf591SKonstantin Belousov 			ksi.ksi_code = BUS_OBJERR;
8394c5bf591SKonstantin Belousov 			ksi.ksi_trapno = T_PROTFLT;
8404c5bf591SKonstantin Belousov 			ksi.ksi_addr = (void *)regs->tf_eip;
8414c5bf591SKonstantin Belousov 			trapsignal(td, &ksi);
8424c5bf591SKonstantin Belousov 			return (EINVAL);
8434c5bf591SKonstantin Belousov 		}
8444c5bf591SKonstantin Belousov 
8454c5bf591SKonstantin Belousov 		if ((uc.uc_mcontext.mc_flags & _MC_HASFPXSTATE) != 0) {
8464c5bf591SKonstantin Belousov 			xfpustate_len = uc.uc_mcontext.mc_xfpustate_len;
8474c5bf591SKonstantin Belousov 			if (xfpustate_len > cpu_max_ext_state_size -
8484c5bf591SKonstantin Belousov 			    sizeof(union savefpu)) {
8494c5bf591SKonstantin Belousov 				uprintf(
8504c5bf591SKonstantin Belousov 			    "pid %d (%s): sigreturn xfpusave_len = 0x%zx\n",
8514c5bf591SKonstantin Belousov 				    p->p_pid, td->td_name, xfpustate_len);
8524c5bf591SKonstantin Belousov 				return (EINVAL);
8534c5bf591SKonstantin Belousov 			}
8544c5bf591SKonstantin Belousov 			xfpustate = __builtin_alloca(xfpustate_len);
8554c5bf591SKonstantin Belousov 			error = copyin(
8564c5bf591SKonstantin Belousov 			    (const void *)uc.uc_mcontext.mc_xfpustate,
8574c5bf591SKonstantin Belousov 			    xfpustate, xfpustate_len);
8584c5bf591SKonstantin Belousov 			if (error != 0) {
8594c5bf591SKonstantin Belousov 				uprintf(
8604c5bf591SKonstantin Belousov 	"pid %d (%s): sigreturn copying xfpustate failed\n",
8614c5bf591SKonstantin Belousov 				    p->p_pid, td->td_name);
8624c5bf591SKonstantin Belousov 				return (error);
8634c5bf591SKonstantin Belousov 			}
8644c5bf591SKonstantin Belousov 		} else {
8654c5bf591SKonstantin Belousov 			xfpustate = NULL;
8664c5bf591SKonstantin Belousov 			xfpustate_len = 0;
8674c5bf591SKonstantin Belousov 		}
8684c5bf591SKonstantin Belousov 		ret = set_fpcontext(td, &ucp->uc_mcontext, xfpustate,
8694c5bf591SKonstantin Belousov 		    xfpustate_len);
8704c5bf591SKonstantin Belousov 		if (ret != 0)
8714c5bf591SKonstantin Belousov 			return (ret);
8724c5bf591SKonstantin Belousov 		bcopy(&ucp->uc_mcontext.mc_fs, regs, sizeof(*regs));
8734c5bf591SKonstantin Belousov 	}
874dc4a2d1dSKonstantin Belousov 	regs->tf_trapno = T_RESERVED;
8754c5bf591SKonstantin Belousov 
8764c5bf591SKonstantin Belousov #if defined(COMPAT_43)
8774c5bf591SKonstantin Belousov 	if (ucp->uc_mcontext.mc_onstack & 1)
8784c5bf591SKonstantin Belousov 		td->td_sigstk.ss_flags |= SS_ONSTACK;
8794c5bf591SKonstantin Belousov 	else
8804c5bf591SKonstantin Belousov 		td->td_sigstk.ss_flags &= ~SS_ONSTACK;
8814c5bf591SKonstantin Belousov #endif
8824c5bf591SKonstantin Belousov 
8834c5bf591SKonstantin Belousov 	kern_sigprocmask(td, SIG_SETMASK, &ucp->uc_sigmask, NULL, 0);
8844c5bf591SKonstantin Belousov 	return (EJUSTRETURN);
8854c5bf591SKonstantin Belousov }
8864c5bf591SKonstantin Belousov 
8874c5bf591SKonstantin Belousov /*
8884c5bf591SKonstantin Belousov  * Reset the hardware debug registers if they were in use.
8894c5bf591SKonstantin Belousov  * They won't have any meaning for the newly exec'd process.
8904c5bf591SKonstantin Belousov  */
8914c5bf591SKonstantin Belousov void
x86_clear_dbregs(struct pcb * pcb)8924c5bf591SKonstantin Belousov x86_clear_dbregs(struct pcb *pcb)
8934c5bf591SKonstantin Belousov {
8944c5bf591SKonstantin Belousov 	if ((pcb->pcb_flags & PCB_DBREGS) == 0)
8954c5bf591SKonstantin Belousov 		return;
8964c5bf591SKonstantin Belousov 
8974c5bf591SKonstantin Belousov 	pcb->pcb_dr0 = 0;
8984c5bf591SKonstantin Belousov 	pcb->pcb_dr1 = 0;
8994c5bf591SKonstantin Belousov 	pcb->pcb_dr2 = 0;
9004c5bf591SKonstantin Belousov 	pcb->pcb_dr3 = 0;
9014c5bf591SKonstantin Belousov 	pcb->pcb_dr6 = 0;
9024c5bf591SKonstantin Belousov 	pcb->pcb_dr7 = 0;
9034c5bf591SKonstantin Belousov 
9044c5bf591SKonstantin Belousov 	if (pcb == curpcb) {
9054c5bf591SKonstantin Belousov 		/*
9064c5bf591SKonstantin Belousov 		 * Clear the debug registers on the running CPU,
9074c5bf591SKonstantin Belousov 		 * otherwise they will end up affecting the next
9084c5bf591SKonstantin Belousov 		 * process we switch to.
9094c5bf591SKonstantin Belousov 		 */
9104c5bf591SKonstantin Belousov 		reset_dbregs();
9114c5bf591SKonstantin Belousov 	}
9124c5bf591SKonstantin Belousov 	pcb->pcb_flags &= ~PCB_DBREGS;
9134c5bf591SKonstantin Belousov }
9144c5bf591SKonstantin Belousov 
9154c5bf591SKonstantin Belousov #ifdef COMPAT_43
9164c5bf591SKonstantin Belousov static void
setup_priv_lcall_gate(struct proc * p)9174c5bf591SKonstantin Belousov setup_priv_lcall_gate(struct proc *p)
9184c5bf591SKonstantin Belousov {
9194c5bf591SKonstantin Belousov 	struct i386_ldt_args uap;
9204c5bf591SKonstantin Belousov 	union descriptor desc;
9214c5bf591SKonstantin Belousov 	u_int lcall_addr;
9224c5bf591SKonstantin Belousov 
9234c5bf591SKonstantin Belousov 	bzero(&uap, sizeof(uap));
9244c5bf591SKonstantin Belousov 	uap.start = 0;
9254c5bf591SKonstantin Belousov 	uap.num = 1;
9264c5bf591SKonstantin Belousov 	lcall_addr = p->p_sysent->sv_psstrings - sz_lcall_tramp;
9274c5bf591SKonstantin Belousov 	bzero(&desc, sizeof(desc));
9284c5bf591SKonstantin Belousov 	desc.sd.sd_type = SDT_MEMERA;
9294c5bf591SKonstantin Belousov 	desc.sd.sd_dpl = SEL_UPL;
9304c5bf591SKonstantin Belousov 	desc.sd.sd_p = 1;
9314c5bf591SKonstantin Belousov 	desc.sd.sd_def32 = 1;
9324c5bf591SKonstantin Belousov 	desc.sd.sd_gran = 1;
9334c5bf591SKonstantin Belousov 	desc.sd.sd_lolimit = 0xffff;
9344c5bf591SKonstantin Belousov 	desc.sd.sd_hilimit = 0xf;
9354c5bf591SKonstantin Belousov 	desc.sd.sd_lobase = lcall_addr;
9364c5bf591SKonstantin Belousov 	desc.sd.sd_hibase = lcall_addr >> 24;
9374c5bf591SKonstantin Belousov 	i386_set_ldt(curthread, &uap, &desc);
9384c5bf591SKonstantin Belousov }
9394c5bf591SKonstantin Belousov #endif
9404c5bf591SKonstantin Belousov 
9414c5bf591SKonstantin Belousov /*
9424c5bf591SKonstantin Belousov  * Reset registers to default values on exec.
9434c5bf591SKonstantin Belousov  */
9444c5bf591SKonstantin Belousov void
exec_setregs(struct thread * td,struct image_params * imgp,uintptr_t stack)9454c5bf591SKonstantin Belousov exec_setregs(struct thread *td, struct image_params *imgp, uintptr_t stack)
9464c5bf591SKonstantin Belousov {
9474c5bf591SKonstantin Belousov 	struct trapframe *regs;
9484c5bf591SKonstantin Belousov 	struct pcb *pcb;
9494c5bf591SKonstantin Belousov 	register_t saved_eflags;
9504c5bf591SKonstantin Belousov 
9514c5bf591SKonstantin Belousov 	regs = td->td_frame;
9524c5bf591SKonstantin Belousov 	pcb = td->td_pcb;
9534c5bf591SKonstantin Belousov 
9544c5bf591SKonstantin Belousov 	/* Reset pc->pcb_gs and %gs before possibly invalidating it. */
9554c5bf591SKonstantin Belousov 	pcb->pcb_gs = _udatasel;
9564c5bf591SKonstantin Belousov 	load_gs(_udatasel);
9574c5bf591SKonstantin Belousov 
9584c5bf591SKonstantin Belousov 	mtx_lock_spin(&dt_lock);
9594c5bf591SKonstantin Belousov 	if (td->td_proc->p_md.md_ldt != NULL)
9604c5bf591SKonstantin Belousov 		user_ldt_free(td);
9614c5bf591SKonstantin Belousov 	else
9624c5bf591SKonstantin Belousov 		mtx_unlock_spin(&dt_lock);
9634c5bf591SKonstantin Belousov 
9644c5bf591SKonstantin Belousov #ifdef COMPAT_43
9654c5bf591SKonstantin Belousov 	if (td->td_proc->p_sysent->sv_psstrings !=
9664c5bf591SKonstantin Belousov 	    elf32_freebsd_sysvec.sv_psstrings)
9674c5bf591SKonstantin Belousov 		setup_priv_lcall_gate(td->td_proc);
9684c5bf591SKonstantin Belousov #endif
9694c5bf591SKonstantin Belousov 
9704c5bf591SKonstantin Belousov 	/*
9714c5bf591SKonstantin Belousov 	 * Reset the fs and gs bases.  The values from the old address
9724c5bf591SKonstantin Belousov 	 * space do not make sense for the new program.  In particular,
9734c5bf591SKonstantin Belousov 	 * gsbase might be the TLS base for the old program but the new
9744c5bf591SKonstantin Belousov 	 * program has no TLS now.
9754c5bf591SKonstantin Belousov 	 */
9764c5bf591SKonstantin Belousov 	set_fsbase(td, 0);
9774c5bf591SKonstantin Belousov 	set_gsbase(td, 0);
9784c5bf591SKonstantin Belousov 
9794c5bf591SKonstantin Belousov 	/* Make sure edx is 0x0 on entry. Linux binaries depend on it. */
9804c5bf591SKonstantin Belousov 	saved_eflags = regs->tf_eflags & PSL_T;
9814c5bf591SKonstantin Belousov 	bzero((char *)regs, sizeof(struct trapframe));
9824c5bf591SKonstantin Belousov 	regs->tf_eip = imgp->entry_addr;
9834c5bf591SKonstantin Belousov 	regs->tf_esp = stack;
9844c5bf591SKonstantin Belousov 	regs->tf_eflags = PSL_USER | saved_eflags;
9854c5bf591SKonstantin Belousov 	regs->tf_ss = _udatasel;
9864c5bf591SKonstantin Belousov 	regs->tf_ds = _udatasel;
9874c5bf591SKonstantin Belousov 	regs->tf_es = _udatasel;
9884c5bf591SKonstantin Belousov 	regs->tf_fs = _udatasel;
9894c5bf591SKonstantin Belousov 	regs->tf_cs = _ucodesel;
9904c5bf591SKonstantin Belousov 
9914c5bf591SKonstantin Belousov 	/* PS_STRINGS value for BSD/OS binaries.  It is 0 for non-BSD/OS. */
9924c5bf591SKonstantin Belousov 	regs->tf_ebx = (register_t)imgp->ps_strings;
9934c5bf591SKonstantin Belousov 
9944c5bf591SKonstantin Belousov 	x86_clear_dbregs(pcb);
9954c5bf591SKonstantin Belousov 
9964c5bf591SKonstantin Belousov 	pcb->pcb_initial_npxcw = __INITIAL_NPXCW__;
9974c5bf591SKonstantin Belousov 
9984c5bf591SKonstantin Belousov 	/*
9994c5bf591SKonstantin Belousov 	 * Drop the FP state if we hold it, so that the process gets a
10004c5bf591SKonstantin Belousov 	 * clean FP state if it uses the FPU again.
10014c5bf591SKonstantin Belousov 	 */
10024c5bf591SKonstantin Belousov 	fpstate_drop(td);
10034c5bf591SKonstantin Belousov }
10044c5bf591SKonstantin Belousov 
10054c5bf591SKonstantin Belousov int
fill_regs(struct thread * td,struct reg * regs)10064c5bf591SKonstantin Belousov fill_regs(struct thread *td, struct reg *regs)
10074c5bf591SKonstantin Belousov {
10084c5bf591SKonstantin Belousov 	struct pcb *pcb;
10094c5bf591SKonstantin Belousov 	struct trapframe *tp;
10104c5bf591SKonstantin Belousov 
10114c5bf591SKonstantin Belousov 	tp = td->td_frame;
10124c5bf591SKonstantin Belousov 	pcb = td->td_pcb;
10134c5bf591SKonstantin Belousov 	regs->r_gs = pcb->pcb_gs;
10144c5bf591SKonstantin Belousov 	return (fill_frame_regs(tp, regs));
10154c5bf591SKonstantin Belousov }
10164c5bf591SKonstantin Belousov 
10174c5bf591SKonstantin Belousov int
fill_frame_regs(struct trapframe * tp,struct reg * regs)10184c5bf591SKonstantin Belousov fill_frame_regs(struct trapframe *tp, struct reg *regs)
10194c5bf591SKonstantin Belousov {
10204c5bf591SKonstantin Belousov 
10214c5bf591SKonstantin Belousov 	regs->r_fs = tp->tf_fs;
10224c5bf591SKonstantin Belousov 	regs->r_es = tp->tf_es;
10234c5bf591SKonstantin Belousov 	regs->r_ds = tp->tf_ds;
10244c5bf591SKonstantin Belousov 	regs->r_edi = tp->tf_edi;
10254c5bf591SKonstantin Belousov 	regs->r_esi = tp->tf_esi;
10264c5bf591SKonstantin Belousov 	regs->r_ebp = tp->tf_ebp;
10274c5bf591SKonstantin Belousov 	regs->r_ebx = tp->tf_ebx;
10284c5bf591SKonstantin Belousov 	regs->r_edx = tp->tf_edx;
10294c5bf591SKonstantin Belousov 	regs->r_ecx = tp->tf_ecx;
10304c5bf591SKonstantin Belousov 	regs->r_eax = tp->tf_eax;
10314c5bf591SKonstantin Belousov 	regs->r_eip = tp->tf_eip;
10324c5bf591SKonstantin Belousov 	regs->r_cs = tp->tf_cs;
10334c5bf591SKonstantin Belousov 	regs->r_eflags = tp->tf_eflags;
10344c5bf591SKonstantin Belousov 	regs->r_esp = tp->tf_esp;
10354c5bf591SKonstantin Belousov 	regs->r_ss = tp->tf_ss;
10364c5bf591SKonstantin Belousov 	regs->r_err = 0;
10374c5bf591SKonstantin Belousov 	regs->r_trapno = 0;
10384c5bf591SKonstantin Belousov 	return (0);
10394c5bf591SKonstantin Belousov }
10404c5bf591SKonstantin Belousov 
10414c5bf591SKonstantin Belousov int
set_regs(struct thread * td,struct reg * regs)10424c5bf591SKonstantin Belousov set_regs(struct thread *td, struct reg *regs)
10434c5bf591SKonstantin Belousov {
10444c5bf591SKonstantin Belousov 	struct pcb *pcb;
10454c5bf591SKonstantin Belousov 	struct trapframe *tp;
10464c5bf591SKonstantin Belousov 
10474c5bf591SKonstantin Belousov 	tp = td->td_frame;
10484c5bf591SKonstantin Belousov 	if (!EFL_SECURE(regs->r_eflags, tp->tf_eflags) ||
10494c5bf591SKonstantin Belousov 	    !CS_SECURE(regs->r_cs))
10504c5bf591SKonstantin Belousov 		return (EINVAL);
10514c5bf591SKonstantin Belousov 	pcb = td->td_pcb;
10524c5bf591SKonstantin Belousov 	tp->tf_fs = regs->r_fs;
10534c5bf591SKonstantin Belousov 	tp->tf_es = regs->r_es;
10544c5bf591SKonstantin Belousov 	tp->tf_ds = regs->r_ds;
10554c5bf591SKonstantin Belousov 	tp->tf_edi = regs->r_edi;
10564c5bf591SKonstantin Belousov 	tp->tf_esi = regs->r_esi;
10574c5bf591SKonstantin Belousov 	tp->tf_ebp = regs->r_ebp;
10584c5bf591SKonstantin Belousov 	tp->tf_ebx = regs->r_ebx;
10594c5bf591SKonstantin Belousov 	tp->tf_edx = regs->r_edx;
10604c5bf591SKonstantin Belousov 	tp->tf_ecx = regs->r_ecx;
10614c5bf591SKonstantin Belousov 	tp->tf_eax = regs->r_eax;
10624c5bf591SKonstantin Belousov 	tp->tf_eip = regs->r_eip;
10634c5bf591SKonstantin Belousov 	tp->tf_cs = regs->r_cs;
10644c5bf591SKonstantin Belousov 	tp->tf_eflags = regs->r_eflags;
10654c5bf591SKonstantin Belousov 	tp->tf_esp = regs->r_esp;
10664c5bf591SKonstantin Belousov 	tp->tf_ss = regs->r_ss;
10674c5bf591SKonstantin Belousov 	pcb->pcb_gs = regs->r_gs;
10684c5bf591SKonstantin Belousov 	return (0);
10694c5bf591SKonstantin Belousov }
10704c5bf591SKonstantin Belousov 
10714c5bf591SKonstantin Belousov int
fill_fpregs(struct thread * td,struct fpreg * fpregs)10724c5bf591SKonstantin Belousov fill_fpregs(struct thread *td, struct fpreg *fpregs)
10734c5bf591SKonstantin Belousov {
10744c5bf591SKonstantin Belousov 
10754c5bf591SKonstantin Belousov 	KASSERT(td == curthread || TD_IS_SUSPENDED(td) ||
10764c5bf591SKonstantin Belousov 	    P_SHOULDSTOP(td->td_proc),
10774c5bf591SKonstantin Belousov 	    ("not suspended thread %p", td));
10784c5bf591SKonstantin Belousov 	npxgetregs(td);
10794c5bf591SKonstantin Belousov 	if (cpu_fxsr)
10804c5bf591SKonstantin Belousov 		npx_fill_fpregs_xmm(&get_pcb_user_save_td(td)->sv_xmm,
10814c5bf591SKonstantin Belousov 		    (struct save87 *)fpregs);
10824c5bf591SKonstantin Belousov 	else
10834c5bf591SKonstantin Belousov 		bcopy(&get_pcb_user_save_td(td)->sv_87, fpregs,
10844c5bf591SKonstantin Belousov 		    sizeof(*fpregs));
10854c5bf591SKonstantin Belousov 	return (0);
10864c5bf591SKonstantin Belousov }
10874c5bf591SKonstantin Belousov 
10884c5bf591SKonstantin Belousov int
set_fpregs(struct thread * td,struct fpreg * fpregs)10894c5bf591SKonstantin Belousov set_fpregs(struct thread *td, struct fpreg *fpregs)
10904c5bf591SKonstantin Belousov {
10914c5bf591SKonstantin Belousov 
10924c5bf591SKonstantin Belousov 	critical_enter();
10934c5bf591SKonstantin Belousov 	if (cpu_fxsr)
10944c5bf591SKonstantin Belousov 		npx_set_fpregs_xmm((struct save87 *)fpregs,
10954c5bf591SKonstantin Belousov 		    &get_pcb_user_save_td(td)->sv_xmm);
10964c5bf591SKonstantin Belousov 	else
10974c5bf591SKonstantin Belousov 		bcopy(fpregs, &get_pcb_user_save_td(td)->sv_87,
10984c5bf591SKonstantin Belousov 		    sizeof(*fpregs));
10994c5bf591SKonstantin Belousov 	npxuserinited(td);
11004c5bf591SKonstantin Belousov 	critical_exit();
11014c5bf591SKonstantin Belousov 	return (0);
11024c5bf591SKonstantin Belousov }
11034c5bf591SKonstantin Belousov 
11044c5bf591SKonstantin Belousov /*
11054c5bf591SKonstantin Belousov  * Get machine context.
11064c5bf591SKonstantin Belousov  */
11074c5bf591SKonstantin Belousov int
get_mcontext(struct thread * td,mcontext_t * mcp,int flags)11084c5bf591SKonstantin Belousov get_mcontext(struct thread *td, mcontext_t *mcp, int flags)
11094c5bf591SKonstantin Belousov {
11104c5bf591SKonstantin Belousov 	struct trapframe *tp;
11114c5bf591SKonstantin Belousov 	struct segment_descriptor *sdp;
11124c5bf591SKonstantin Belousov 
11134c5bf591SKonstantin Belousov 	tp = td->td_frame;
11144c5bf591SKonstantin Belousov 
11154c5bf591SKonstantin Belousov 	PROC_LOCK(curthread->td_proc);
11164c5bf591SKonstantin Belousov 	mcp->mc_onstack = sigonstack(tp->tf_esp);
11174c5bf591SKonstantin Belousov 	PROC_UNLOCK(curthread->td_proc);
11184c5bf591SKonstantin Belousov 	mcp->mc_gs = td->td_pcb->pcb_gs;
11194c5bf591SKonstantin Belousov 	mcp->mc_fs = tp->tf_fs;
11204c5bf591SKonstantin Belousov 	mcp->mc_es = tp->tf_es;
11214c5bf591SKonstantin Belousov 	mcp->mc_ds = tp->tf_ds;
11224c5bf591SKonstantin Belousov 	mcp->mc_edi = tp->tf_edi;
11234c5bf591SKonstantin Belousov 	mcp->mc_esi = tp->tf_esi;
11244c5bf591SKonstantin Belousov 	mcp->mc_ebp = tp->tf_ebp;
11254c5bf591SKonstantin Belousov 	mcp->mc_isp = tp->tf_isp;
11264c5bf591SKonstantin Belousov 	mcp->mc_eflags = tp->tf_eflags;
11274c5bf591SKonstantin Belousov 	if (flags & GET_MC_CLEAR_RET) {
11284c5bf591SKonstantin Belousov 		mcp->mc_eax = 0;
11294c5bf591SKonstantin Belousov 		mcp->mc_edx = 0;
11304c5bf591SKonstantin Belousov 		mcp->mc_eflags &= ~PSL_C;
11314c5bf591SKonstantin Belousov 	} else {
11324c5bf591SKonstantin Belousov 		mcp->mc_eax = tp->tf_eax;
11334c5bf591SKonstantin Belousov 		mcp->mc_edx = tp->tf_edx;
11344c5bf591SKonstantin Belousov 	}
11354c5bf591SKonstantin Belousov 	mcp->mc_ebx = tp->tf_ebx;
11364c5bf591SKonstantin Belousov 	mcp->mc_ecx = tp->tf_ecx;
11374c5bf591SKonstantin Belousov 	mcp->mc_eip = tp->tf_eip;
11384c5bf591SKonstantin Belousov 	mcp->mc_cs = tp->tf_cs;
11394c5bf591SKonstantin Belousov 	mcp->mc_esp = tp->tf_esp;
11404c5bf591SKonstantin Belousov 	mcp->mc_ss = tp->tf_ss;
11414c5bf591SKonstantin Belousov 	mcp->mc_len = sizeof(*mcp);
11424c5bf591SKonstantin Belousov 	get_fpcontext(td, mcp, NULL, 0);
11434c5bf591SKonstantin Belousov 	sdp = &td->td_pcb->pcb_fsd;
11444c5bf591SKonstantin Belousov 	mcp->mc_fsbase = sdp->sd_hibase << 24 | sdp->sd_lobase;
11454c5bf591SKonstantin Belousov 	sdp = &td->td_pcb->pcb_gsd;
11464c5bf591SKonstantin Belousov 	mcp->mc_gsbase = sdp->sd_hibase << 24 | sdp->sd_lobase;
11474c5bf591SKonstantin Belousov 	mcp->mc_flags = 0;
11484c5bf591SKonstantin Belousov 	mcp->mc_xfpustate = 0;
11494c5bf591SKonstantin Belousov 	mcp->mc_xfpustate_len = 0;
11504c5bf591SKonstantin Belousov 	bzero(mcp->mc_spare2, sizeof(mcp->mc_spare2));
11514c5bf591SKonstantin Belousov 	return (0);
11524c5bf591SKonstantin Belousov }
11534c5bf591SKonstantin Belousov 
11544c5bf591SKonstantin Belousov /*
11554c5bf591SKonstantin Belousov  * Set machine context.
11564c5bf591SKonstantin Belousov  *
11574c5bf591SKonstantin Belousov  * However, we don't set any but the user modifiable flags, and we won't
11584c5bf591SKonstantin Belousov  * touch the cs selector.
11594c5bf591SKonstantin Belousov  */
11604c5bf591SKonstantin Belousov int
set_mcontext(struct thread * td,mcontext_t * mcp)11614c5bf591SKonstantin Belousov set_mcontext(struct thread *td, mcontext_t *mcp)
11624c5bf591SKonstantin Belousov {
11634c5bf591SKonstantin Belousov 	struct trapframe *tp;
11644c5bf591SKonstantin Belousov 	char *xfpustate;
11654c5bf591SKonstantin Belousov 	int eflags, ret;
11664c5bf591SKonstantin Belousov 
11674c5bf591SKonstantin Belousov 	tp = td->td_frame;
11684c5bf591SKonstantin Belousov 	if (mcp->mc_len != sizeof(*mcp) ||
11694c5bf591SKonstantin Belousov 	    (mcp->mc_flags & ~_MC_FLAG_MASK) != 0)
11704c5bf591SKonstantin Belousov 		return (EINVAL);
11714c5bf591SKonstantin Belousov 	eflags = (mcp->mc_eflags & PSL_USERCHANGE) |
11724c5bf591SKonstantin Belousov 	    (tp->tf_eflags & ~PSL_USERCHANGE);
11734c5bf591SKonstantin Belousov 	if (mcp->mc_flags & _MC_HASFPXSTATE) {
11744c5bf591SKonstantin Belousov 		if (mcp->mc_xfpustate_len > cpu_max_ext_state_size -
11754c5bf591SKonstantin Belousov 		    sizeof(union savefpu))
11764c5bf591SKonstantin Belousov 			return (EINVAL);
11774c5bf591SKonstantin Belousov 		xfpustate = __builtin_alloca(mcp->mc_xfpustate_len);
11784c5bf591SKonstantin Belousov 		ret = copyin((void *)mcp->mc_xfpustate, xfpustate,
11794c5bf591SKonstantin Belousov 		    mcp->mc_xfpustate_len);
11804c5bf591SKonstantin Belousov 		if (ret != 0)
11814c5bf591SKonstantin Belousov 			return (ret);
11824c5bf591SKonstantin Belousov 	} else
11834c5bf591SKonstantin Belousov 		xfpustate = NULL;
11844c5bf591SKonstantin Belousov 	ret = set_fpcontext(td, mcp, xfpustate, mcp->mc_xfpustate_len);
11854c5bf591SKonstantin Belousov 	if (ret != 0)
11864c5bf591SKonstantin Belousov 		return (ret);
11874c5bf591SKonstantin Belousov 	tp->tf_fs = mcp->mc_fs;
11884c5bf591SKonstantin Belousov 	tp->tf_es = mcp->mc_es;
11894c5bf591SKonstantin Belousov 	tp->tf_ds = mcp->mc_ds;
11904c5bf591SKonstantin Belousov 	tp->tf_edi = mcp->mc_edi;
11914c5bf591SKonstantin Belousov 	tp->tf_esi = mcp->mc_esi;
11924c5bf591SKonstantin Belousov 	tp->tf_ebp = mcp->mc_ebp;
11934c5bf591SKonstantin Belousov 	tp->tf_ebx = mcp->mc_ebx;
11944c5bf591SKonstantin Belousov 	tp->tf_edx = mcp->mc_edx;
11954c5bf591SKonstantin Belousov 	tp->tf_ecx = mcp->mc_ecx;
11964c5bf591SKonstantin Belousov 	tp->tf_eax = mcp->mc_eax;
11974c5bf591SKonstantin Belousov 	tp->tf_eip = mcp->mc_eip;
11984c5bf591SKonstantin Belousov 	tp->tf_eflags = eflags;
11994c5bf591SKonstantin Belousov 	tp->tf_esp = mcp->mc_esp;
12004c5bf591SKonstantin Belousov 	tp->tf_ss = mcp->mc_ss;
12014c5bf591SKonstantin Belousov 	td->td_pcb->pcb_gs = mcp->mc_gs;
12024c5bf591SKonstantin Belousov 	return (0);
12034c5bf591SKonstantin Belousov }
12044c5bf591SKonstantin Belousov 
12054c5bf591SKonstantin Belousov static void
get_fpcontext(struct thread * td,mcontext_t * mcp,char * xfpusave,size_t xfpusave_len)12064c5bf591SKonstantin Belousov get_fpcontext(struct thread *td, mcontext_t *mcp, char *xfpusave,
12074c5bf591SKonstantin Belousov     size_t xfpusave_len)
12084c5bf591SKonstantin Belousov {
12094c5bf591SKonstantin Belousov 	size_t max_len, len;
12104c5bf591SKonstantin Belousov 
12114c5bf591SKonstantin Belousov 	mcp->mc_ownedfp = npxgetregs(td);
12124c5bf591SKonstantin Belousov 	bcopy(get_pcb_user_save_td(td), &mcp->mc_fpstate[0],
12134c5bf591SKonstantin Belousov 	    sizeof(mcp->mc_fpstate));
12144c5bf591SKonstantin Belousov 	mcp->mc_fpformat = npxformat();
12154c5bf591SKonstantin Belousov 	if (!use_xsave || xfpusave_len == 0)
12164c5bf591SKonstantin Belousov 		return;
12174c5bf591SKonstantin Belousov 	max_len = cpu_max_ext_state_size - sizeof(union savefpu);
12184c5bf591SKonstantin Belousov 	len = xfpusave_len;
12194c5bf591SKonstantin Belousov 	if (len > max_len) {
12204c5bf591SKonstantin Belousov 		len = max_len;
12214c5bf591SKonstantin Belousov 		bzero(xfpusave + max_len, len - max_len);
12224c5bf591SKonstantin Belousov 	}
12234c5bf591SKonstantin Belousov 	mcp->mc_flags |= _MC_HASFPXSTATE;
12244c5bf591SKonstantin Belousov 	mcp->mc_xfpustate_len = len;
12254c5bf591SKonstantin Belousov 	bcopy(get_pcb_user_save_td(td) + 1, xfpusave, len);
12264c5bf591SKonstantin Belousov }
12274c5bf591SKonstantin Belousov 
12284c5bf591SKonstantin Belousov static int
set_fpcontext(struct thread * td,mcontext_t * mcp,char * xfpustate,size_t xfpustate_len)12294c5bf591SKonstantin Belousov set_fpcontext(struct thread *td, mcontext_t *mcp, char *xfpustate,
12304c5bf591SKonstantin Belousov     size_t xfpustate_len)
12314c5bf591SKonstantin Belousov {
12324c5bf591SKonstantin Belousov 	int error;
12334c5bf591SKonstantin Belousov 
12344c5bf591SKonstantin Belousov 	if (mcp->mc_fpformat == _MC_FPFMT_NODEV)
12354c5bf591SKonstantin Belousov 		return (0);
12364c5bf591SKonstantin Belousov 	else if (mcp->mc_fpformat != _MC_FPFMT_387 &&
12374c5bf591SKonstantin Belousov 	    mcp->mc_fpformat != _MC_FPFMT_XMM)
12384c5bf591SKonstantin Belousov 		return (EINVAL);
12394c5bf591SKonstantin Belousov 	else if (mcp->mc_ownedfp == _MC_FPOWNED_NONE) {
12404c5bf591SKonstantin Belousov 		/* We don't care what state is left in the FPU or PCB. */
12414c5bf591SKonstantin Belousov 		fpstate_drop(td);
12424c5bf591SKonstantin Belousov 		error = 0;
12434c5bf591SKonstantin Belousov 	} else if (mcp->mc_ownedfp == _MC_FPOWNED_FPU ||
12444c5bf591SKonstantin Belousov 	    mcp->mc_ownedfp == _MC_FPOWNED_PCB) {
12454c5bf591SKonstantin Belousov 		error = npxsetregs(td, (union savefpu *)&mcp->mc_fpstate,
12464c5bf591SKonstantin Belousov 		    xfpustate, xfpustate_len);
12474c5bf591SKonstantin Belousov 	} else
12484c5bf591SKonstantin Belousov 		return (EINVAL);
12494c5bf591SKonstantin Belousov 	return (error);
12504c5bf591SKonstantin Belousov }
12514c5bf591SKonstantin Belousov 
12524c5bf591SKonstantin Belousov static void
fpstate_drop(struct thread * td)12534c5bf591SKonstantin Belousov fpstate_drop(struct thread *td)
12544c5bf591SKonstantin Belousov {
12554c5bf591SKonstantin Belousov 
12564c5bf591SKonstantin Belousov 	KASSERT(PCB_USER_FPU(td->td_pcb), ("fpstate_drop: kernel-owned fpu"));
12574c5bf591SKonstantin Belousov 	critical_enter();
12584c5bf591SKonstantin Belousov 	if (PCPU_GET(fpcurthread) == td)
12594c5bf591SKonstantin Belousov 		npxdrop();
12604c5bf591SKonstantin Belousov 	/*
12614c5bf591SKonstantin Belousov 	 * XXX force a full drop of the npx.  The above only drops it if we
12624c5bf591SKonstantin Belousov 	 * owned it.  npxgetregs() has the same bug in the !cpu_fxsr case.
12634c5bf591SKonstantin Belousov 	 *
12644c5bf591SKonstantin Belousov 	 * XXX I don't much like npxgetregs()'s semantics of doing a full
12654c5bf591SKonstantin Belousov 	 * drop.  Dropping only to the pcb matches fnsave's behaviour.
12664c5bf591SKonstantin Belousov 	 * We only need to drop to !PCB_INITDONE in sendsig().  But
12674c5bf591SKonstantin Belousov 	 * sendsig() is the only caller of npxgetregs()... perhaps we just
12684c5bf591SKonstantin Belousov 	 * have too many layers.
12694c5bf591SKonstantin Belousov 	 */
12704c5bf591SKonstantin Belousov 	curthread->td_pcb->pcb_flags &= ~(PCB_NPXINITDONE |
12714c5bf591SKonstantin Belousov 	    PCB_NPXUSERINITDONE);
12724c5bf591SKonstantin Belousov 	critical_exit();
12734c5bf591SKonstantin Belousov }
12744c5bf591SKonstantin Belousov 
12754c5bf591SKonstantin Belousov int
fill_dbregs(struct thread * td,struct dbreg * dbregs)12764c5bf591SKonstantin Belousov fill_dbregs(struct thread *td, struct dbreg *dbregs)
12774c5bf591SKonstantin Belousov {
12784c5bf591SKonstantin Belousov 	struct pcb *pcb;
12794c5bf591SKonstantin Belousov 
12804c5bf591SKonstantin Belousov 	if (td == NULL) {
12814c5bf591SKonstantin Belousov 		dbregs->dr[0] = rdr0();
12824c5bf591SKonstantin Belousov 		dbregs->dr[1] = rdr1();
12834c5bf591SKonstantin Belousov 		dbregs->dr[2] = rdr2();
12844c5bf591SKonstantin Belousov 		dbregs->dr[3] = rdr3();
12854c5bf591SKonstantin Belousov 		dbregs->dr[6] = rdr6();
12864c5bf591SKonstantin Belousov 		dbregs->dr[7] = rdr7();
12874c5bf591SKonstantin Belousov 	} else {
12884c5bf591SKonstantin Belousov 		pcb = td->td_pcb;
12894c5bf591SKonstantin Belousov 		dbregs->dr[0] = pcb->pcb_dr0;
12904c5bf591SKonstantin Belousov 		dbregs->dr[1] = pcb->pcb_dr1;
12914c5bf591SKonstantin Belousov 		dbregs->dr[2] = pcb->pcb_dr2;
12924c5bf591SKonstantin Belousov 		dbregs->dr[3] = pcb->pcb_dr3;
12934c5bf591SKonstantin Belousov 		dbregs->dr[6] = pcb->pcb_dr6;
12944c5bf591SKonstantin Belousov 		dbregs->dr[7] = pcb->pcb_dr7;
12954c5bf591SKonstantin Belousov 	}
12964c5bf591SKonstantin Belousov 	dbregs->dr[4] = 0;
12974c5bf591SKonstantin Belousov 	dbregs->dr[5] = 0;
12984c5bf591SKonstantin Belousov 	return (0);
12994c5bf591SKonstantin Belousov }
13004c5bf591SKonstantin Belousov 
13014c5bf591SKonstantin Belousov int
set_dbregs(struct thread * td,struct dbreg * dbregs)13024c5bf591SKonstantin Belousov set_dbregs(struct thread *td, struct dbreg *dbregs)
13034c5bf591SKonstantin Belousov {
13044c5bf591SKonstantin Belousov 	struct pcb *pcb;
13054c5bf591SKonstantin Belousov 	int i;
13064c5bf591SKonstantin Belousov 
13074c5bf591SKonstantin Belousov 	if (td == NULL) {
13084c5bf591SKonstantin Belousov 		load_dr0(dbregs->dr[0]);
13094c5bf591SKonstantin Belousov 		load_dr1(dbregs->dr[1]);
13104c5bf591SKonstantin Belousov 		load_dr2(dbregs->dr[2]);
13114c5bf591SKonstantin Belousov 		load_dr3(dbregs->dr[3]);
13124c5bf591SKonstantin Belousov 		load_dr6(dbregs->dr[6]);
13134c5bf591SKonstantin Belousov 		load_dr7(dbregs->dr[7]);
13144c5bf591SKonstantin Belousov 	} else {
13154c5bf591SKonstantin Belousov 		/*
13164c5bf591SKonstantin Belousov 		 * Don't let an illegal value for dr7 get set.	Specifically,
13174c5bf591SKonstantin Belousov 		 * check for undefined settings.  Setting these bit patterns
13184c5bf591SKonstantin Belousov 		 * result in undefined behaviour and can lead to an unexpected
13194c5bf591SKonstantin Belousov 		 * TRCTRAP.
13204c5bf591SKonstantin Belousov 		 */
13214c5bf591SKonstantin Belousov 		for (i = 0; i < 4; i++) {
13224c5bf591SKonstantin Belousov 			if (DBREG_DR7_ACCESS(dbregs->dr[7], i) == 0x02)
13234c5bf591SKonstantin Belousov 				return (EINVAL);
13244c5bf591SKonstantin Belousov 			if (DBREG_DR7_LEN(dbregs->dr[7], i) == 0x02)
13254c5bf591SKonstantin Belousov 				return (EINVAL);
13264c5bf591SKonstantin Belousov 		}
13274c5bf591SKonstantin Belousov 
13284c5bf591SKonstantin Belousov 		pcb = td->td_pcb;
13294c5bf591SKonstantin Belousov 
13304c5bf591SKonstantin Belousov 		/*
13314c5bf591SKonstantin Belousov 		 * Don't let a process set a breakpoint that is not within the
13324c5bf591SKonstantin Belousov 		 * process's address space.  If a process could do this, it
13334c5bf591SKonstantin Belousov 		 * could halt the system by setting a breakpoint in the kernel
13344c5bf591SKonstantin Belousov 		 * (if ddb was enabled).  Thus, we need to check to make sure
13354c5bf591SKonstantin Belousov 		 * that no breakpoints are being enabled for addresses outside
13364c5bf591SKonstantin Belousov 		 * process's address space.
13374c5bf591SKonstantin Belousov 		 *
13384c5bf591SKonstantin Belousov 		 * XXX - what about when the watched area of the user's
13394c5bf591SKonstantin Belousov 		 * address space is written into from within the kernel
13404c5bf591SKonstantin Belousov 		 * ... wouldn't that still cause a breakpoint to be generated
13414c5bf591SKonstantin Belousov 		 * from within kernel mode?
13424c5bf591SKonstantin Belousov 		 */
13434c5bf591SKonstantin Belousov 
13444c5bf591SKonstantin Belousov 		if (DBREG_DR7_ENABLED(dbregs->dr[7], 0)) {
13454c5bf591SKonstantin Belousov 			/* dr0 is enabled */
13464c5bf591SKonstantin Belousov 			if (dbregs->dr[0] >= VM_MAXUSER_ADDRESS)
13474c5bf591SKonstantin Belousov 				return (EINVAL);
13484c5bf591SKonstantin Belousov 		}
13494c5bf591SKonstantin Belousov 
13504c5bf591SKonstantin Belousov 		if (DBREG_DR7_ENABLED(dbregs->dr[7], 1)) {
13514c5bf591SKonstantin Belousov 			/* dr1 is enabled */
13524c5bf591SKonstantin Belousov 			if (dbregs->dr[1] >= VM_MAXUSER_ADDRESS)
13534c5bf591SKonstantin Belousov 				return (EINVAL);
13544c5bf591SKonstantin Belousov 		}
13554c5bf591SKonstantin Belousov 
13564c5bf591SKonstantin Belousov 		if (DBREG_DR7_ENABLED(dbregs->dr[7], 2)) {
13574c5bf591SKonstantin Belousov 			/* dr2 is enabled */
13584c5bf591SKonstantin Belousov 			if (dbregs->dr[2] >= VM_MAXUSER_ADDRESS)
13594c5bf591SKonstantin Belousov 				return (EINVAL);
13604c5bf591SKonstantin Belousov 		}
13614c5bf591SKonstantin Belousov 
13624c5bf591SKonstantin Belousov 		if (DBREG_DR7_ENABLED(dbregs->dr[7], 3)) {
13634c5bf591SKonstantin Belousov 			/* dr3 is enabled */
13644c5bf591SKonstantin Belousov 			if (dbregs->dr[3] >= VM_MAXUSER_ADDRESS)
13654c5bf591SKonstantin Belousov 				return (EINVAL);
13664c5bf591SKonstantin Belousov 		}
13674c5bf591SKonstantin Belousov 
13684c5bf591SKonstantin Belousov 		pcb->pcb_dr0 = dbregs->dr[0];
13694c5bf591SKonstantin Belousov 		pcb->pcb_dr1 = dbregs->dr[1];
13704c5bf591SKonstantin Belousov 		pcb->pcb_dr2 = dbregs->dr[2];
13714c5bf591SKonstantin Belousov 		pcb->pcb_dr3 = dbregs->dr[3];
13724c5bf591SKonstantin Belousov 		pcb->pcb_dr6 = dbregs->dr[6];
13734c5bf591SKonstantin Belousov 		pcb->pcb_dr7 = dbregs->dr[7];
13744c5bf591SKonstantin Belousov 
13754c5bf591SKonstantin Belousov 		pcb->pcb_flags |= PCB_DBREGS;
13764c5bf591SKonstantin Belousov 	}
13774c5bf591SKonstantin Belousov 
13784c5bf591SKonstantin Belousov 	return (0);
13794c5bf591SKonstantin Belousov }
13804c5bf591SKonstantin Belousov 
13814c5bf591SKonstantin Belousov /*
13824c5bf591SKonstantin Belousov  * Return > 0 if a hardware breakpoint has been hit, and the
13834c5bf591SKonstantin Belousov  * breakpoint was in user space.  Return 0, otherwise.
13844c5bf591SKonstantin Belousov  */
13854c5bf591SKonstantin Belousov int
user_dbreg_trap(register_t dr6)13864c5bf591SKonstantin Belousov user_dbreg_trap(register_t dr6)
13874c5bf591SKonstantin Belousov {
13884c5bf591SKonstantin Belousov 	u_int32_t dr7;
13894c5bf591SKonstantin Belousov 	u_int32_t bp;       /* breakpoint bits extracted from dr6 */
13904c5bf591SKonstantin Belousov 	int nbp;            /* number of breakpoints that triggered */
13914c5bf591SKonstantin Belousov 	caddr_t addr[4];    /* breakpoint addresses */
13924c5bf591SKonstantin Belousov 	int i;
13934c5bf591SKonstantin Belousov 
13944c5bf591SKonstantin Belousov 	bp = dr6 & DBREG_DR6_BMASK;
13954c5bf591SKonstantin Belousov 	if (bp == 0) {
13964c5bf591SKonstantin Belousov 		/*
13974c5bf591SKonstantin Belousov 		 * None of the breakpoint bits are set meaning this
13984c5bf591SKonstantin Belousov 		 * trap was not caused by any of the debug registers
13994c5bf591SKonstantin Belousov 		 */
14004c5bf591SKonstantin Belousov 		return (0);
14014c5bf591SKonstantin Belousov 	}
14024c5bf591SKonstantin Belousov 
14034c5bf591SKonstantin Belousov 	dr7 = rdr7();
14044c5bf591SKonstantin Belousov 	if ((dr7 & 0x000000ff) == 0) {
14054c5bf591SKonstantin Belousov 		/*
14064c5bf591SKonstantin Belousov 		 * all GE and LE bits in the dr7 register are zero,
14074c5bf591SKonstantin Belousov 		 * thus the trap couldn't have been caused by the
14084c5bf591SKonstantin Belousov 		 * hardware debug registers
14094c5bf591SKonstantin Belousov 		 */
14104c5bf591SKonstantin Belousov 		return (0);
14114c5bf591SKonstantin Belousov 	}
14124c5bf591SKonstantin Belousov 
14134c5bf591SKonstantin Belousov 	nbp = 0;
14144c5bf591SKonstantin Belousov 
14154c5bf591SKonstantin Belousov 	/*
14164c5bf591SKonstantin Belousov 	 * at least one of the breakpoints were hit, check to see
14174c5bf591SKonstantin Belousov 	 * which ones and if any of them are user space addresses
14184c5bf591SKonstantin Belousov 	 */
14194c5bf591SKonstantin Belousov 
14204c5bf591SKonstantin Belousov 	if (bp & 0x01) {
14214c5bf591SKonstantin Belousov 		addr[nbp++] = (caddr_t)rdr0();
14224c5bf591SKonstantin Belousov 	}
14234c5bf591SKonstantin Belousov 	if (bp & 0x02) {
14244c5bf591SKonstantin Belousov 		addr[nbp++] = (caddr_t)rdr1();
14254c5bf591SKonstantin Belousov 	}
14264c5bf591SKonstantin Belousov 	if (bp & 0x04) {
14274c5bf591SKonstantin Belousov 		addr[nbp++] = (caddr_t)rdr2();
14284c5bf591SKonstantin Belousov 	}
14294c5bf591SKonstantin Belousov 	if (bp & 0x08) {
14304c5bf591SKonstantin Belousov 		addr[nbp++] = (caddr_t)rdr3();
14314c5bf591SKonstantin Belousov 	}
14324c5bf591SKonstantin Belousov 
14334c5bf591SKonstantin Belousov 	for (i = 0; i < nbp; i++) {
14344c5bf591SKonstantin Belousov 		if (addr[i] < (caddr_t)VM_MAXUSER_ADDRESS) {
14354c5bf591SKonstantin Belousov 			/*
14364c5bf591SKonstantin Belousov 			 * addr[i] is in user space
14374c5bf591SKonstantin Belousov 			 */
14384c5bf591SKonstantin Belousov 			return (nbp);
14394c5bf591SKonstantin Belousov 		}
14404c5bf591SKonstantin Belousov 	}
14414c5bf591SKonstantin Belousov 
14424c5bf591SKonstantin Belousov 	/*
14434c5bf591SKonstantin Belousov 	 * None of the breakpoints are in user space.
14444c5bf591SKonstantin Belousov 	 */
14454c5bf591SKonstantin Belousov 	return (0);
14464c5bf591SKonstantin Belousov }
1447