ia32_signal.c revision 230426
1114987Speter/*- 2114987Speter * Copyright (c) 2003 Peter Wemm 3114987Speter * Copyright (c) 1982, 1987, 1990 The Regents of the University of California. 4114987Speter * All rights reserved. 5114987Speter * 6114987Speter * This code is derived from software contributed to Berkeley by 7114987Speter * William Jolitz. 8114987Speter * 9114987Speter * Redistribution and use in source and binary forms, with or without 10114987Speter * modification, are permitted provided that the following conditions 11114987Speter * are met: 12114987Speter * 1. Redistributions of source code must retain the above copyright 13114987Speter * notice, this list of conditions and the following disclaimer. 14114987Speter * 2. Redistributions in binary form must reproduce the above copyright 15114987Speter * notice, this list of conditions and the following disclaimer in the 16114987Speter * documentation and/or other materials provided with the distribution. 17114987Speter * 4. Neither the name of the University nor the names of its contributors 18114987Speter * may be used to endorse or promote products derived from this software 19114987Speter * without specific prior written permission. 20114987Speter * 21114987Speter * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 22114987Speter * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 23114987Speter * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 24114987Speter * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 25114987Speter * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 26114987Speter * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 27114987Speter * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 28114987Speter * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 29114987Speter * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 30114987Speter * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 31114987Speter * SUCH DAMAGE. 32114987Speter */ 33114987Speter 34118031Sobrien#include <sys/cdefs.h> 35118031Sobrien__FBSDID("$FreeBSD: head/sys/amd64/ia32/ia32_signal.c 230426 2012-01-21 17:45:27Z kib $"); 36118031Sobrien 37114987Speter#include "opt_compat.h" 38114987Speter 39114987Speter#include <sys/param.h> 40114987Speter#include <sys/exec.h> 41114987Speter#include <sys/fcntl.h> 42114987Speter#include <sys/imgact.h> 43114987Speter#include <sys/kernel.h> 44114987Speter#include <sys/lock.h> 45114987Speter#include <sys/malloc.h> 46114987Speter#include <sys/mutex.h> 47114987Speter#include <sys/mman.h> 48114987Speter#include <sys/namei.h> 49114987Speter#include <sys/pioctl.h> 50114987Speter#include <sys/proc.h> 51114987Speter#include <sys/procfs.h> 52114987Speter#include <sys/resourcevar.h> 53114987Speter#include <sys/systm.h> 54114987Speter#include <sys/signalvar.h> 55114987Speter#include <sys/stat.h> 56114987Speter#include <sys/sx.h> 57114987Speter#include <sys/syscall.h> 58209613Sjhb#include <sys/syscallsubr.h> 59114987Speter#include <sys/sysctl.h> 60114987Speter#include <sys/sysent.h> 61114987Speter#include <sys/vnode.h> 62114987Speter 63114987Speter#include <vm/vm.h> 64114987Speter#include <vm/vm_kern.h> 65114987Speter#include <vm/vm_param.h> 66114987Speter#include <vm/pmap.h> 67114987Speter#include <vm/vm_map.h> 68114987Speter#include <vm/vm_object.h> 69114987Speter#include <vm/vm_extern.h> 70114987Speter 71163018Sdavidxu#include <compat/freebsd32/freebsd32_signal.h> 72119336Speter#include <compat/freebsd32/freebsd32_util.h> 73119336Speter#include <compat/freebsd32/freebsd32_proto.h> 74230426Skib#include <compat/freebsd32/freebsd32.h> 75119336Speter#include <compat/ia32/ia32_signal.h> 76114987Speter#include <machine/psl.h> 77114987Speter#include <machine/segments.h> 78114987Speter#include <machine/specialreg.h> 79114987Speter#include <machine/frame.h> 80114987Speter#include <machine/md_var.h> 81114987Speter#include <machine/pcb.h> 82114987Speter#include <machine/cpufunc.h> 83114987Speter 84114987Speter#ifdef COMPAT_FREEBSD4 85151316Sdavidxustatic void freebsd4_ia32_sendsig(sig_t, ksiginfo_t *, sigset_t *); 86114987Speter#endif 87114987Speter 88114987Speter#define CS_SECURE(cs) (ISPL(cs) == SEL_UPL) 89114987Speter#define EFL_SECURE(ef, oef) ((((ef) ^ (oef)) & ~PSL_USERCHANGE) == 0) 90114987Speter 91114987Speterstatic void 92230426Skibia32_get_fpcontext(struct thread *td, struct ia32_mcontext *mcp, 93230426Skib char *xfpusave, size_t xfpusave_len) 94114987Speter{ 95230426Skib size_t max_len, len; 96114987Speter 97209208Skib /* 98209208Skib * XXX Format of 64bit and 32bit FXSAVE areas differs. FXSAVE 99209208Skib * in 32bit mode saves %cs and %ds, while on 64bit it saves 100209208Skib * 64bit instruction and data pointers. Ignore the difference 101209208Skib * for now, it should be irrelevant for most applications. 102209208Skib */ 103215865Skib mcp->mc_ownedfp = fpugetregs(td); 104230426Skib bcopy(get_pcb_user_save_td(td), &mcp->mc_fpstate, 105215865Skib sizeof(mcp->mc_fpstate)); 106122292Speter mcp->mc_fpformat = fpuformat(); 107230426Skib if (!use_xsave || xfpusave_len == 0) 108230426Skib return; 109230426Skib max_len = cpu_max_ext_state_size - sizeof(struct savefpu); 110230426Skib len = xfpusave_len; 111230426Skib if (len > max_len) { 112230426Skib len = max_len; 113230426Skib bzero(xfpusave + max_len, len - max_len); 114230426Skib } 115230426Skib mcp->mc_flags |= _MC_HASFPXSTATE; 116230426Skib mcp->mc_xfpustate_len = len; 117230426Skib bcopy(get_pcb_user_save_td(td) + 1, xfpusave, len); 118114987Speter} 119114987Speter 120114987Speterstatic int 121230426Skibia32_set_fpcontext(struct thread *td, const struct ia32_mcontext *mcp, 122230426Skib char *xfpustate, size_t xfpustate_len) 123114987Speter{ 124230426Skib int error; 125114987Speter 126114987Speter if (mcp->mc_fpformat == _MC_FPFMT_NODEV) 127114987Speter return (0); 128114987Speter else if (mcp->mc_fpformat != _MC_FPFMT_XMM) 129114987Speter return (EINVAL); 130230426Skib else if (mcp->mc_ownedfp == _MC_FPOWNED_NONE) { 131114987Speter /* We don't care what state is left in the FPU or PCB. */ 132114987Speter fpstate_drop(td); 133230426Skib error = 0; 134230426Skib } else if (mcp->mc_ownedfp == _MC_FPOWNED_FPU || 135114987Speter mcp->mc_ownedfp == _MC_FPOWNED_PCB) { 136230426Skib error = fpusetregs(td, (struct savefpu *)&mcp->mc_fpstate, 137230426Skib xfpustate, xfpustate_len); 138114987Speter } else 139114987Speter return (EINVAL); 140230426Skib return (error); 141114987Speter} 142114987Speter 143114987Speter/* 144150631Speter * Get machine context. 145150631Speter */ 146150631Speterstatic int 147150631Speteria32_get_mcontext(struct thread *td, struct ia32_mcontext *mcp, int flags) 148150631Speter{ 149216634Sjkim struct pcb *pcb; 150150631Speter struct trapframe *tp; 151150631Speter 152216634Sjkim pcb = td->td_pcb; 153150631Speter tp = td->td_frame; 154150631Speter 155150631Speter PROC_LOCK(curthread->td_proc); 156150631Speter mcp->mc_onstack = sigonstack(tp->tf_rsp); 157150631Speter PROC_UNLOCK(curthread->td_proc); 158190620Skib /* Entry into kernel always sets TF_HASSEGS */ 159190620Skib mcp->mc_gs = tp->tf_gs; 160190620Skib mcp->mc_fs = tp->tf_fs; 161190620Skib mcp->mc_es = tp->tf_es; 162190620Skib mcp->mc_ds = tp->tf_ds; 163150631Speter mcp->mc_edi = tp->tf_rdi; 164150631Speter mcp->mc_esi = tp->tf_rsi; 165150631Speter mcp->mc_ebp = tp->tf_rbp; 166150631Speter mcp->mc_isp = tp->tf_rsp; 167206992Skib mcp->mc_eflags = tp->tf_rflags; 168150631Speter if (flags & GET_MC_CLEAR_RET) { 169150631Speter mcp->mc_eax = 0; 170150631Speter mcp->mc_edx = 0; 171206992Skib mcp->mc_eflags &= ~PSL_C; 172150631Speter } else { 173150631Speter mcp->mc_eax = tp->tf_rax; 174150631Speter mcp->mc_edx = tp->tf_rdx; 175150631Speter } 176150631Speter mcp->mc_ebx = tp->tf_rbx; 177150631Speter mcp->mc_ecx = tp->tf_rcx; 178150631Speter mcp->mc_eip = tp->tf_rip; 179150631Speter mcp->mc_cs = tp->tf_cs; 180150631Speter mcp->mc_esp = tp->tf_rsp; 181150631Speter mcp->mc_ss = tp->tf_ss; 182150631Speter mcp->mc_len = sizeof(*mcp); 183230426Skib mcp->mc_flags = tp->tf_flags; 184230426Skib ia32_get_fpcontext(td, mcp, NULL, 0); 185216634Sjkim mcp->mc_fsbase = pcb->pcb_fsbase; 186216634Sjkim mcp->mc_gsbase = pcb->pcb_gsbase; 187230426Skib mcp->mc_xfpustate = 0; 188230426Skib mcp->mc_xfpustate_len = 0; 189218327Skib bzero(mcp->mc_spare2, sizeof(mcp->mc_spare2)); 190216634Sjkim set_pcb_flags(pcb, PCB_FULL_IRET); 191150631Speter return (0); 192150631Speter} 193150631Speter 194150631Speter/* 195150631Speter * Set machine context. 196150631Speter * 197150631Speter * However, we don't set any but the user modifiable flags, and we won't 198150631Speter * touch the cs selector. 199150631Speter */ 200150631Speterstatic int 201150631Speteria32_set_mcontext(struct thread *td, const struct ia32_mcontext *mcp) 202150631Speter{ 203150631Speter struct trapframe *tp; 204230426Skib char *xfpustate; 205150631Speter long rflags; 206150631Speter int ret; 207150631Speter 208150631Speter tp = td->td_frame; 209150631Speter if (mcp->mc_len != sizeof(*mcp)) 210150631Speter return (EINVAL); 211150631Speter rflags = (mcp->mc_eflags & PSL_USERCHANGE) | 212150631Speter (tp->tf_rflags & ~PSL_USERCHANGE); 213230426Skib if (mcp->mc_flags & _MC_IA32_HASFPXSTATE) { 214230426Skib if (mcp->mc_xfpustate_len > cpu_max_ext_state_size - 215230426Skib sizeof(struct savefpu)) 216230426Skib return (EINVAL); 217230426Skib xfpustate = __builtin_alloca(mcp->mc_xfpustate_len); 218230426Skib ret = copyin(PTRIN(mcp->mc_xfpustate), xfpustate, 219230426Skib mcp->mc_xfpustate_len); 220230426Skib if (ret != 0) 221230426Skib return (ret); 222230426Skib } else 223230426Skib xfpustate = NULL; 224230426Skib ret = ia32_set_fpcontext(td, mcp, xfpustate, mcp->mc_xfpustate_len); 225150631Speter if (ret != 0) 226150631Speter return (ret); 227190620Skib tp->tf_gs = mcp->mc_gs; 228150631Speter tp->tf_fs = mcp->mc_fs; 229150631Speter tp->tf_es = mcp->mc_es; 230150631Speter tp->tf_ds = mcp->mc_ds; 231190620Skib tp->tf_flags = TF_HASSEGS; 232150631Speter tp->tf_rdi = mcp->mc_edi; 233150631Speter tp->tf_rsi = mcp->mc_esi; 234150631Speter tp->tf_rbp = mcp->mc_ebp; 235150631Speter tp->tf_rbx = mcp->mc_ebx; 236150631Speter tp->tf_rdx = mcp->mc_edx; 237150631Speter tp->tf_rcx = mcp->mc_ecx; 238150631Speter tp->tf_rax = mcp->mc_eax; 239150631Speter /* trapno, err */ 240150631Speter tp->tf_rip = mcp->mc_eip; 241150631Speter tp->tf_rflags = rflags; 242150631Speter tp->tf_rsp = mcp->mc_esp; 243150631Speter tp->tf_ss = mcp->mc_ss; 244216634Sjkim set_pcb_flags(td->td_pcb, PCB_FULL_IRET); 245150631Speter return (0); 246150631Speter} 247150631Speter 248150631Speter/* 249150631Speter * The first two fields of a ucontext_t are the signal mask and 250150631Speter * the machine context. The next field is uc_link; we want to 251150631Speter * avoid destroying the link when copying out contexts. 252150631Speter */ 253150631Speter#define UC_COPY_SIZE offsetof(struct ia32_ucontext, uc_link) 254150631Speter 255150631Speterint 256150631Speterfreebsd32_getcontext(struct thread *td, struct freebsd32_getcontext_args *uap) 257150631Speter{ 258150631Speter struct ia32_ucontext uc; 259150631Speter int ret; 260150631Speter 261150631Speter if (uap->ucp == NULL) 262150631Speter ret = EINVAL; 263150631Speter else { 264150631Speter ia32_get_mcontext(td, &uc.uc_mcontext, GET_MC_CLEAR_RET); 265150631Speter PROC_LOCK(td->td_proc); 266150631Speter uc.uc_sigmask = td->td_sigmask; 267150631Speter PROC_UNLOCK(td->td_proc); 268218327Skib bzero(&uc.__spare__, sizeof(uc.__spare__)); 269150631Speter ret = copyout(&uc, uap->ucp, UC_COPY_SIZE); 270150631Speter } 271150631Speter return (ret); 272150631Speter} 273150631Speter 274150631Speterint 275150631Speterfreebsd32_setcontext(struct thread *td, struct freebsd32_setcontext_args *uap) 276150631Speter{ 277150631Speter struct ia32_ucontext uc; 278150631Speter int ret; 279150631Speter 280150631Speter if (uap->ucp == NULL) 281150631Speter ret = EINVAL; 282150631Speter else { 283150631Speter ret = copyin(uap->ucp, &uc, UC_COPY_SIZE); 284150631Speter if (ret == 0) { 285150631Speter ret = ia32_set_mcontext(td, &uc.uc_mcontext); 286150631Speter if (ret == 0) { 287198507Skib kern_sigprocmask(td, SIG_SETMASK, 288198507Skib &uc.uc_sigmask, NULL, 0); 289150631Speter } 290150631Speter } 291150631Speter } 292150631Speter return (ret == 0 ? EJUSTRETURN : ret); 293150631Speter} 294150631Speter 295150631Speterint 296150631Speterfreebsd32_swapcontext(struct thread *td, struct freebsd32_swapcontext_args *uap) 297150631Speter{ 298150631Speter struct ia32_ucontext uc; 299150631Speter int ret; 300150631Speter 301150631Speter if (uap->oucp == NULL || uap->ucp == NULL) 302150631Speter ret = EINVAL; 303150631Speter else { 304150631Speter ia32_get_mcontext(td, &uc.uc_mcontext, GET_MC_CLEAR_RET); 305150631Speter PROC_LOCK(td->td_proc); 306150631Speter uc.uc_sigmask = td->td_sigmask; 307150631Speter PROC_UNLOCK(td->td_proc); 308150631Speter ret = copyout(&uc, uap->oucp, UC_COPY_SIZE); 309150631Speter if (ret == 0) { 310150631Speter ret = copyin(uap->ucp, &uc, UC_COPY_SIZE); 311150631Speter if (ret == 0) { 312150631Speter ret = ia32_set_mcontext(td, &uc.uc_mcontext); 313150631Speter if (ret == 0) { 314198507Skib kern_sigprocmask(td, SIG_SETMASK, 315198507Skib &uc.uc_sigmask, NULL, 0); 316150631Speter } 317150631Speter } 318150631Speter } 319150631Speter } 320150631Speter return (ret == 0 ? EJUSTRETURN : ret); 321150631Speter} 322150631Speter 323150631Speter/* 324114987Speter * Send an interrupt to process. 325114987Speter * 326114987Speter * Stack is set up to allow sigcode stored 327114987Speter * at top to call routine, followed by kcall 328114987Speter * to sigreturn routine below. After sigreturn 329114987Speter * resets the signal mask, the stack, and the 330114987Speter * frame pointer, it returns to the user 331114987Speter * specified pc, psl. 332114987Speter */ 333220238Skib 334220238Skib#ifdef COMPAT_43 335220238Skibstatic void 336220238Skibia32_osendsig(sig_t catcher, ksiginfo_t *ksi, sigset_t *mask) 337220238Skib{ 338220238Skib struct ia32_sigframe3 sf, *fp; 339220238Skib struct proc *p; 340220238Skib struct thread *td; 341220238Skib struct sigacts *psp; 342220238Skib struct trapframe *regs; 343220238Skib int sig; 344220238Skib int oonstack; 345220238Skib 346220238Skib td = curthread; 347220238Skib p = td->td_proc; 348220238Skib PROC_LOCK_ASSERT(p, MA_OWNED); 349220238Skib sig = ksi->ksi_signo; 350220238Skib psp = p->p_sigacts; 351220238Skib mtx_assert(&psp->ps_mtx, MA_OWNED); 352220238Skib regs = td->td_frame; 353220238Skib oonstack = sigonstack(regs->tf_rsp); 354220238Skib 355220238Skib /* Allocate space for the signal handler context. */ 356220238Skib if ((td->td_pflags & TDP_ALTSTACK) && !oonstack && 357220238Skib SIGISMEMBER(psp->ps_sigonstack, sig)) { 358220238Skib fp = (struct ia32_sigframe3 *)(td->td_sigstk.ss_sp + 359220238Skib td->td_sigstk.ss_size - sizeof(sf)); 360220238Skib td->td_sigstk.ss_flags |= SS_ONSTACK; 361220238Skib } else 362220238Skib fp = (struct ia32_sigframe3 *)regs->tf_rsp - 1; 363220238Skib 364220238Skib /* Translate the signal if appropriate. */ 365220238Skib if (p->p_sysent->sv_sigtbl && sig <= p->p_sysent->sv_sigsize) 366220238Skib sig = p->p_sysent->sv_sigtbl[_SIG_IDX(sig)]; 367220238Skib 368220238Skib /* Build the argument list for the signal handler. */ 369220238Skib sf.sf_signum = sig; 370220238Skib sf.sf_scp = (register_t)&fp->sf_siginfo.si_sc; 371220238Skib if (SIGISMEMBER(psp->ps_siginfo, sig)) { 372220238Skib /* Signal handler installed with SA_SIGINFO. */ 373220238Skib sf.sf_arg2 = (register_t)&fp->sf_siginfo; 374220238Skib sf.sf_siginfo.si_signo = sig; 375220238Skib sf.sf_siginfo.si_code = ksi->ksi_code; 376220238Skib sf.sf_ah = (uintptr_t)catcher; 377220238Skib } else { 378220238Skib /* Old FreeBSD-style arguments. */ 379220238Skib sf.sf_arg2 = ksi->ksi_code; 380220238Skib sf.sf_addr = (register_t)ksi->ksi_addr; 381220238Skib sf.sf_ah = (uintptr_t)catcher; 382220238Skib } 383220238Skib mtx_unlock(&psp->ps_mtx); 384220238Skib PROC_UNLOCK(p); 385220238Skib 386220238Skib /* Save most if not all of trap frame. */ 387220238Skib sf.sf_siginfo.si_sc.sc_eax = regs->tf_rax; 388220238Skib sf.sf_siginfo.si_sc.sc_ebx = regs->tf_rbx; 389220238Skib sf.sf_siginfo.si_sc.sc_ecx = regs->tf_rcx; 390220238Skib sf.sf_siginfo.si_sc.sc_edx = regs->tf_rdx; 391220238Skib sf.sf_siginfo.si_sc.sc_esi = regs->tf_rsi; 392220238Skib sf.sf_siginfo.si_sc.sc_edi = regs->tf_rdi; 393220238Skib sf.sf_siginfo.si_sc.sc_cs = regs->tf_cs; 394220238Skib sf.sf_siginfo.si_sc.sc_ds = regs->tf_ds; 395220238Skib sf.sf_siginfo.si_sc.sc_ss = regs->tf_ss; 396220238Skib sf.sf_siginfo.si_sc.sc_es = regs->tf_es; 397220238Skib sf.sf_siginfo.si_sc.sc_fs = regs->tf_fs; 398220238Skib sf.sf_siginfo.si_sc.sc_gs = regs->tf_gs; 399220238Skib sf.sf_siginfo.si_sc.sc_isp = regs->tf_rsp; 400220238Skib 401220238Skib /* Build the signal context to be used by osigreturn(). */ 402220238Skib sf.sf_siginfo.si_sc.sc_onstack = (oonstack) ? 1 : 0; 403220238Skib SIG2OSIG(*mask, sf.sf_siginfo.si_sc.sc_mask); 404220238Skib sf.sf_siginfo.si_sc.sc_esp = regs->tf_rsp; 405220238Skib sf.sf_siginfo.si_sc.sc_ebp = regs->tf_rbp; 406220238Skib sf.sf_siginfo.si_sc.sc_eip = regs->tf_rip; 407220238Skib sf.sf_siginfo.si_sc.sc_eflags = regs->tf_rflags; 408220238Skib sf.sf_siginfo.si_sc.sc_trapno = regs->tf_trapno; 409220238Skib sf.sf_siginfo.si_sc.sc_err = regs->tf_err; 410220238Skib 411220238Skib /* 412220238Skib * Copy the sigframe out to the user's stack. 413220238Skib */ 414220238Skib if (copyout(&sf, fp, sizeof(*fp)) != 0) { 415220238Skib#ifdef DEBUG 416220238Skib printf("process %ld has trashed its stack\n", (long)p->p_pid); 417220238Skib#endif 418220238Skib PROC_LOCK(p); 419220238Skib sigexit(td, SIGILL); 420220238Skib } 421220238Skib 422220238Skib regs->tf_rsp = (uintptr_t)fp; 423220238Skib regs->tf_rip = p->p_sysent->sv_psstrings - sz_ia32_osigcode; 424220238Skib regs->tf_rflags &= ~(PSL_T | PSL_D); 425220238Skib regs->tf_cs = _ucode32sel; 426220238Skib regs->tf_ds = _udatasel; 427220238Skib regs->tf_es = _udatasel; 428220238Skib regs->tf_fs = _udatasel; 429220238Skib regs->tf_ss = _udatasel; 430220238Skib set_pcb_flags(td->td_pcb, PCB_FULL_IRET); 431220238Skib PROC_LOCK(p); 432220238Skib mtx_lock(&psp->ps_mtx); 433220238Skib} 434220238Skib#endif 435220238Skib 436114987Speter#ifdef COMPAT_FREEBSD4 437114987Speterstatic void 438151316Sdavidxufreebsd4_ia32_sendsig(sig_t catcher, ksiginfo_t *ksi, sigset_t *mask) 439114987Speter{ 440114987Speter struct ia32_sigframe4 sf, *sfp; 441163018Sdavidxu struct siginfo32 siginfo; 442114987Speter struct proc *p; 443114987Speter struct thread *td; 444114987Speter struct sigacts *psp; 445114987Speter struct trapframe *regs; 446114987Speter int oonstack; 447151316Sdavidxu int sig; 448114987Speter 449114987Speter td = curthread; 450114987Speter p = td->td_proc; 451163018Sdavidxu siginfo_to_siginfo32(&ksi->ksi_info, &siginfo); 452151316Sdavidxu 453114987Speter PROC_LOCK_ASSERT(p, MA_OWNED); 454151316Sdavidxu sig = siginfo.si_signo; 455114987Speter psp = p->p_sigacts; 456123119Speter mtx_assert(&psp->ps_mtx, MA_OWNED); 457114987Speter regs = td->td_frame; 458114987Speter oonstack = sigonstack(regs->tf_rsp); 459114987Speter 460114987Speter /* Save user context. */ 461114987Speter bzero(&sf, sizeof(sf)); 462114987Speter sf.sf_uc.uc_sigmask = *mask; 463124092Sdavidxu sf.sf_uc.uc_stack.ss_sp = (uintptr_t)td->td_sigstk.ss_sp; 464124092Sdavidxu sf.sf_uc.uc_stack.ss_size = td->td_sigstk.ss_size; 465124092Sdavidxu sf.sf_uc.uc_stack.ss_flags = (td->td_pflags & TDP_ALTSTACK) 466114987Speter ? ((oonstack) ? SS_ONSTACK : 0) : SS_DISABLE; 467114987Speter sf.sf_uc.uc_mcontext.mc_onstack = (oonstack) ? 1 : 0; 468114987Speter sf.sf_uc.uc_mcontext.mc_edi = regs->tf_rdi; 469114987Speter sf.sf_uc.uc_mcontext.mc_esi = regs->tf_rsi; 470114987Speter sf.sf_uc.uc_mcontext.mc_ebp = regs->tf_rbp; 471114987Speter sf.sf_uc.uc_mcontext.mc_isp = regs->tf_rsp; /* XXX */ 472114987Speter sf.sf_uc.uc_mcontext.mc_ebx = regs->tf_rbx; 473114987Speter sf.sf_uc.uc_mcontext.mc_edx = regs->tf_rdx; 474114987Speter sf.sf_uc.uc_mcontext.mc_ecx = regs->tf_rcx; 475114987Speter sf.sf_uc.uc_mcontext.mc_eax = regs->tf_rax; 476114987Speter sf.sf_uc.uc_mcontext.mc_trapno = regs->tf_trapno; 477114987Speter sf.sf_uc.uc_mcontext.mc_err = regs->tf_err; 478114987Speter sf.sf_uc.uc_mcontext.mc_eip = regs->tf_rip; 479114987Speter sf.sf_uc.uc_mcontext.mc_cs = regs->tf_cs; 480114987Speter sf.sf_uc.uc_mcontext.mc_eflags = regs->tf_rflags; 481114987Speter sf.sf_uc.uc_mcontext.mc_esp = regs->tf_rsp; 482114987Speter sf.sf_uc.uc_mcontext.mc_ss = regs->tf_ss; 483190620Skib sf.sf_uc.uc_mcontext.mc_ds = regs->tf_ds; 484190620Skib sf.sf_uc.uc_mcontext.mc_es = regs->tf_es; 485190620Skib sf.sf_uc.uc_mcontext.mc_fs = regs->tf_fs; 486190620Skib sf.sf_uc.uc_mcontext.mc_gs = regs->tf_gs; 487218327Skib bzero(sf.sf_uc.uc_mcontext.mc_fpregs, 488218327Skib sizeof(sf.sf_uc.uc_mcontext.mc_fpregs)); 489218327Skib bzero(sf.sf_uc.uc_mcontext.__spare__, 490218327Skib sizeof(sf.sf_uc.uc_mcontext.__spare__)); 491218327Skib bzero(sf.sf_uc.__spare__, sizeof(sf.sf_uc.__spare__)); 492114987Speter 493114987Speter /* Allocate space for the signal handler context. */ 494124092Sdavidxu if ((td->td_pflags & TDP_ALTSTACK) != 0 && !oonstack && 495114987Speter SIGISMEMBER(psp->ps_sigonstack, sig)) { 496124092Sdavidxu sfp = (struct ia32_sigframe4 *)(td->td_sigstk.ss_sp + 497124092Sdavidxu td->td_sigstk.ss_size - sizeof(sf)); 498114987Speter } else 499114987Speter sfp = (struct ia32_sigframe4 *)regs->tf_rsp - 1; 500114987Speter PROC_UNLOCK(p); 501114987Speter 502114987Speter /* Translate the signal if appropriate. */ 503114987Speter if (p->p_sysent->sv_sigtbl && sig <= p->p_sysent->sv_sigsize) 504114987Speter sig = p->p_sysent->sv_sigtbl[_SIG_IDX(sig)]; 505114987Speter 506114987Speter /* Build the argument list for the signal handler. */ 507114987Speter sf.sf_signum = sig; 508114987Speter sf.sf_ucontext = (register_t)&sfp->sf_uc; 509218327Skib bzero(&sf.sf_si, sizeof(sf.sf_si)); 510126089Speter if (SIGISMEMBER(psp->ps_siginfo, sig)) { 511114987Speter /* Signal handler installed with SA_SIGINFO. */ 512114987Speter sf.sf_siginfo = (u_int32_t)(uintptr_t)&sfp->sf_si; 513114987Speter sf.sf_ah = (u_int32_t)(uintptr_t)catcher; 514114987Speter 515114987Speter /* Fill in POSIX parts */ 516151316Sdavidxu sf.sf_si = siginfo; 517114987Speter sf.sf_si.si_signo = sig; 518114987Speter } else { 519114987Speter /* Old FreeBSD-style arguments. */ 520151316Sdavidxu sf.sf_siginfo = siginfo.si_code; 521151316Sdavidxu sf.sf_addr = (u_int32_t)siginfo.si_addr; 522114987Speter sf.sf_ah = (u_int32_t)(uintptr_t)catcher; 523114987Speter } 524123119Speter mtx_unlock(&psp->ps_mtx); 525114987Speter 526114987Speter /* 527114987Speter * Copy the sigframe out to the user's stack. 528114987Speter */ 529114987Speter if (copyout(&sf, sfp, sizeof(*sfp)) != 0) { 530114987Speter#ifdef DEBUG 531114987Speter printf("process %ld has trashed its stack\n", (long)p->p_pid); 532114987Speter#endif 533114987Speter PROC_LOCK(p); 534114987Speter sigexit(td, SIGILL); 535114987Speter } 536114987Speter 537114987Speter regs->tf_rsp = (uintptr_t)sfp; 538217151Skib regs->tf_rip = p->p_sysent->sv_sigcode_base + sz_ia32_sigcode - 539217151Skib sz_freebsd4_ia32_sigcode; 540177145Skib regs->tf_rflags &= ~(PSL_T | PSL_D); 541114987Speter regs->tf_cs = _ucode32sel; 542114987Speter regs->tf_ss = _udatasel; 543190620Skib regs->tf_ds = _udatasel; 544190620Skib regs->tf_es = _udatasel; 545216634Sjkim set_pcb_flags(td->td_pcb, PCB_FULL_IRET); 546114987Speter /* leave user %fs and %gs untouched */ 547114987Speter PROC_LOCK(p); 548123119Speter mtx_lock(&psp->ps_mtx); 549114987Speter} 550114987Speter#endif /* COMPAT_FREEBSD4 */ 551114987Speter 552114987Spetervoid 553151316Sdavidxuia32_sendsig(sig_t catcher, ksiginfo_t *ksi, sigset_t *mask) 554114987Speter{ 555114987Speter struct ia32_sigframe sf, *sfp; 556163018Sdavidxu struct siginfo32 siginfo; 557114987Speter struct proc *p; 558114987Speter struct thread *td; 559114987Speter struct sigacts *psp; 560114987Speter char *sp; 561114987Speter struct trapframe *regs; 562230426Skib char *xfpusave; 563230426Skib size_t xfpusave_len; 564114987Speter int oonstack; 565151316Sdavidxu int sig; 566114987Speter 567163018Sdavidxu siginfo_to_siginfo32(&ksi->ksi_info, &siginfo); 568114987Speter td = curthread; 569114987Speter p = td->td_proc; 570114987Speter PROC_LOCK_ASSERT(p, MA_OWNED); 571151316Sdavidxu sig = siginfo.si_signo; 572114987Speter psp = p->p_sigacts; 573114987Speter#ifdef COMPAT_FREEBSD4 574114987Speter if (SIGISMEMBER(psp->ps_freebsd4, sig)) { 575151316Sdavidxu freebsd4_ia32_sendsig(catcher, ksi, mask); 576114987Speter return; 577114987Speter } 578114987Speter#endif 579220238Skib#ifdef COMPAT_43 580220238Skib if (SIGISMEMBER(psp->ps_osigset, sig)) { 581220238Skib ia32_osendsig(catcher, ksi, mask); 582220238Skib return; 583220238Skib } 584220238Skib#endif 585123119Speter mtx_assert(&psp->ps_mtx, MA_OWNED); 586114987Speter regs = td->td_frame; 587114987Speter oonstack = sigonstack(regs->tf_rsp); 588114987Speter 589230426Skib if (cpu_max_ext_state_size > sizeof(struct savefpu) && use_xsave) { 590230426Skib xfpusave_len = cpu_max_ext_state_size - sizeof(struct savefpu); 591230426Skib xfpusave = __builtin_alloca(xfpusave_len); 592230426Skib } else { 593230426Skib xfpusave_len = 0; 594230426Skib xfpusave = NULL; 595230426Skib } 596230426Skib 597114987Speter /* Save user context. */ 598114987Speter bzero(&sf, sizeof(sf)); 599114987Speter sf.sf_uc.uc_sigmask = *mask; 600124092Sdavidxu sf.sf_uc.uc_stack.ss_sp = (uintptr_t)td->td_sigstk.ss_sp; 601124092Sdavidxu sf.sf_uc.uc_stack.ss_size = td->td_sigstk.ss_size; 602124092Sdavidxu sf.sf_uc.uc_stack.ss_flags = (td->td_pflags & TDP_ALTSTACK) 603114987Speter ? ((oonstack) ? SS_ONSTACK : 0) : SS_DISABLE; 604114987Speter sf.sf_uc.uc_mcontext.mc_onstack = (oonstack) ? 1 : 0; 605114987Speter sf.sf_uc.uc_mcontext.mc_edi = regs->tf_rdi; 606114987Speter sf.sf_uc.uc_mcontext.mc_esi = regs->tf_rsi; 607114987Speter sf.sf_uc.uc_mcontext.mc_ebp = regs->tf_rbp; 608114987Speter sf.sf_uc.uc_mcontext.mc_isp = regs->tf_rsp; /* XXX */ 609114987Speter sf.sf_uc.uc_mcontext.mc_ebx = regs->tf_rbx; 610114987Speter sf.sf_uc.uc_mcontext.mc_edx = regs->tf_rdx; 611114987Speter sf.sf_uc.uc_mcontext.mc_ecx = regs->tf_rcx; 612114987Speter sf.sf_uc.uc_mcontext.mc_eax = regs->tf_rax; 613114987Speter sf.sf_uc.uc_mcontext.mc_trapno = regs->tf_trapno; 614114987Speter sf.sf_uc.uc_mcontext.mc_err = regs->tf_err; 615114987Speter sf.sf_uc.uc_mcontext.mc_eip = regs->tf_rip; 616114987Speter sf.sf_uc.uc_mcontext.mc_cs = regs->tf_cs; 617114987Speter sf.sf_uc.uc_mcontext.mc_eflags = regs->tf_rflags; 618114987Speter sf.sf_uc.uc_mcontext.mc_esp = regs->tf_rsp; 619114987Speter sf.sf_uc.uc_mcontext.mc_ss = regs->tf_ss; 620190620Skib sf.sf_uc.uc_mcontext.mc_ds = regs->tf_ds; 621190620Skib sf.sf_uc.uc_mcontext.mc_es = regs->tf_es; 622190620Skib sf.sf_uc.uc_mcontext.mc_fs = regs->tf_fs; 623190620Skib sf.sf_uc.uc_mcontext.mc_gs = regs->tf_gs; 624114987Speter sf.sf_uc.uc_mcontext.mc_len = sizeof(sf.sf_uc.uc_mcontext); /* magic */ 625230426Skib ia32_get_fpcontext(td, &sf.sf_uc.uc_mcontext, xfpusave, xfpusave_len); 626114987Speter fpstate_drop(td); 627190620Skib sf.sf_uc.uc_mcontext.mc_fsbase = td->td_pcb->pcb_fsbase; 628190620Skib sf.sf_uc.uc_mcontext.mc_gsbase = td->td_pcb->pcb_gsbase; 629218327Skib bzero(sf.sf_uc.__spare__, sizeof(sf.sf_uc.__spare__)); 630114987Speter 631114987Speter /* Allocate space for the signal handler context. */ 632124092Sdavidxu if ((td->td_pflags & TDP_ALTSTACK) != 0 && !oonstack && 633230426Skib SIGISMEMBER(psp->ps_sigonstack, sig)) 634230426Skib sp = td->td_sigstk.ss_sp + td->td_sigstk.ss_size; 635230426Skib else 636230426Skib sp = (char *)regs->tf_rsp; 637230426Skib if (xfpusave != NULL) { 638230426Skib sp -= xfpusave_len; 639230426Skib sp = (char *)((unsigned long)sp & ~0x3Ful); 640230426Skib sf.sf_uc.uc_mcontext.mc_xfpustate = (register_t)sp; 641230426Skib } 642230426Skib sp -= sizeof(sf); 643114987Speter /* Align to 16 bytes. */ 644114987Speter sfp = (struct ia32_sigframe *)((uintptr_t)sp & ~0xF); 645114987Speter PROC_UNLOCK(p); 646114987Speter 647114987Speter /* Translate the signal if appropriate. */ 648114987Speter if (p->p_sysent->sv_sigtbl && sig <= p->p_sysent->sv_sigsize) 649114987Speter sig = p->p_sysent->sv_sigtbl[_SIG_IDX(sig)]; 650114987Speter 651114987Speter /* Build the argument list for the signal handler. */ 652114987Speter sf.sf_signum = sig; 653114987Speter sf.sf_ucontext = (register_t)&sfp->sf_uc; 654218327Skib bzero(&sf.sf_si, sizeof(sf.sf_si)); 655126089Speter if (SIGISMEMBER(psp->ps_siginfo, sig)) { 656114987Speter /* Signal handler installed with SA_SIGINFO. */ 657114987Speter sf.sf_siginfo = (u_int32_t)(uintptr_t)&sfp->sf_si; 658114987Speter sf.sf_ah = (u_int32_t)(uintptr_t)catcher; 659114987Speter 660114987Speter /* Fill in POSIX parts */ 661151316Sdavidxu sf.sf_si = siginfo; 662114987Speter sf.sf_si.si_signo = sig; 663114987Speter } else { 664114987Speter /* Old FreeBSD-style arguments. */ 665151316Sdavidxu sf.sf_siginfo = siginfo.si_code; 666151316Sdavidxu sf.sf_addr = (u_int32_t)siginfo.si_addr; 667114987Speter sf.sf_ah = (u_int32_t)(uintptr_t)catcher; 668114987Speter } 669123119Speter mtx_unlock(&psp->ps_mtx); 670114987Speter 671114987Speter /* 672114987Speter * Copy the sigframe out to the user's stack. 673114987Speter */ 674230426Skib if (copyout(&sf, sfp, sizeof(*sfp)) != 0 || 675230426Skib (xfpusave != NULL && copyout(xfpusave, 676230426Skib PTRIN(sf.sf_uc.uc_mcontext.mc_xfpustate), xfpusave_len) 677230426Skib != 0)) { 678114987Speter#ifdef DEBUG 679114987Speter printf("process %ld has trashed its stack\n", (long)p->p_pid); 680114987Speter#endif 681114987Speter PROC_LOCK(p); 682114987Speter sigexit(td, SIGILL); 683114987Speter } 684114987Speter 685114987Speter regs->tf_rsp = (uintptr_t)sfp; 686217151Skib regs->tf_rip = p->p_sysent->sv_sigcode_base; 687177145Skib regs->tf_rflags &= ~(PSL_T | PSL_D); 688114987Speter regs->tf_cs = _ucode32sel; 689114987Speter regs->tf_ss = _udatasel; 690190620Skib regs->tf_ds = _udatasel; 691190620Skib regs->tf_es = _udatasel; 692216634Sjkim set_pcb_flags(td->td_pcb, PCB_FULL_IRET); 693190620Skib /* XXXKIB leave user %fs and %gs untouched */ 694114987Speter PROC_LOCK(p); 695123119Speter mtx_lock(&psp->ps_mtx); 696114987Speter} 697114987Speter 698114987Speter/* 699114987Speter * System call to cleanup state after a signal 700114987Speter * has been taken. Reset signal mask and 701114987Speter * stack state from context left by sendsig (above). 702114987Speter * Return to previous pc and psl as specified by 703114987Speter * context left by sendsig. Check carefully to 704114987Speter * make sure that the user has not modified the 705114987Speter * state to gain improper privileges. 706114987Speter */ 707220238Skib 708220238Skib#ifdef COMPAT_43 709220238Skibint 710220238Skibofreebsd32_sigreturn(struct thread *td, struct ofreebsd32_sigreturn_args *uap) 711220238Skib{ 712220238Skib struct ia32_sigcontext3 sc, *scp; 713220238Skib struct trapframe *regs; 714220238Skib int eflags, error; 715220238Skib ksiginfo_t ksi; 716220238Skib 717220238Skib regs = td->td_frame; 718220238Skib error = copyin(uap->sigcntxp, &sc, sizeof(sc)); 719220238Skib if (error != 0) 720220238Skib return (error); 721220238Skib scp = ≻ 722220238Skib eflags = scp->sc_eflags; 723220238Skib if (!EFL_SECURE(eflags & ~PSL_RF, regs->tf_rflags & ~PSL_RF)) { 724220238Skib return (EINVAL); 725220238Skib } 726220238Skib if (!CS_SECURE(scp->sc_cs)) { 727220238Skib ksiginfo_init_trap(&ksi); 728220238Skib ksi.ksi_signo = SIGBUS; 729220238Skib ksi.ksi_code = BUS_OBJERR; 730220238Skib ksi.ksi_trapno = T_PROTFLT; 731220238Skib ksi.ksi_addr = (void *)regs->tf_rip; 732220238Skib trapsignal(td, &ksi); 733220238Skib return (EINVAL); 734220238Skib } 735220238Skib regs->tf_ds = scp->sc_ds; 736220238Skib regs->tf_es = scp->sc_es; 737220238Skib regs->tf_fs = scp->sc_fs; 738220238Skib regs->tf_gs = scp->sc_gs; 739220238Skib 740220238Skib regs->tf_rax = scp->sc_eax; 741220238Skib regs->tf_rbx = scp->sc_ebx; 742220238Skib regs->tf_rcx = scp->sc_ecx; 743220238Skib regs->tf_rdx = scp->sc_edx; 744220238Skib regs->tf_rsi = scp->sc_esi; 745220238Skib regs->tf_rdi = scp->sc_edi; 746220238Skib regs->tf_cs = scp->sc_cs; 747220238Skib regs->tf_ss = scp->sc_ss; 748220238Skib regs->tf_rbp = scp->sc_ebp; 749220238Skib regs->tf_rsp = scp->sc_esp; 750220238Skib regs->tf_rip = scp->sc_eip; 751220238Skib regs->tf_rflags = eflags; 752220238Skib 753220238Skib if (scp->sc_onstack & 1) 754220238Skib td->td_sigstk.ss_flags |= SS_ONSTACK; 755220238Skib else 756220238Skib td->td_sigstk.ss_flags &= ~SS_ONSTACK; 757220238Skib 758220238Skib kern_sigprocmask(td, SIG_SETMASK, (sigset_t *)&scp->sc_mask, NULL, 759220238Skib SIGPROCMASK_OLD); 760220238Skib set_pcb_flags(td->td_pcb, PCB_FULL_IRET); 761220238Skib return (EJUSTRETURN); 762220238Skib} 763220238Skib#endif 764220238Skib 765114987Speter#ifdef COMPAT_FREEBSD4 766114987Speter/* 767114987Speter * MPSAFE 768114987Speter */ 769114987Speterint 770119336Speterfreebsd4_freebsd32_sigreturn(td, uap) 771114987Speter struct thread *td; 772119336Speter struct freebsd4_freebsd32_sigreturn_args /* { 773119336Speter const struct freebsd4_freebsd32_ucontext *sigcntxp; 774114987Speter } */ *uap; 775114987Speter{ 776114987Speter struct ia32_ucontext4 uc; 777114987Speter struct trapframe *regs; 778198507Skib struct ia32_ucontext4 *ucp; 779114987Speter int cs, eflags, error; 780151316Sdavidxu ksiginfo_t ksi; 781114987Speter 782114987Speter error = copyin(uap->sigcntxp, &uc, sizeof(uc)); 783114987Speter if (error != 0) 784114987Speter return (error); 785114987Speter ucp = &uc; 786114987Speter regs = td->td_frame; 787114987Speter eflags = ucp->uc_mcontext.mc_eflags; 788114987Speter /* 789114987Speter * Don't allow users to change privileged or reserved flags. 790114987Speter */ 791114987Speter /* 792114987Speter * XXX do allow users to change the privileged flag PSL_RF. 793114987Speter * The cpu sets PSL_RF in tf_eflags for faults. Debuggers 794114987Speter * should sometimes set it there too. tf_eflags is kept in 795114987Speter * the signal context during signal handling and there is no 796114987Speter * other place to remember it, so the PSL_RF bit may be 797114987Speter * corrupted by the signal handler without us knowing. 798114987Speter * Corruption of the PSL_RF bit at worst causes one more or 799114987Speter * one less debugger trap, so allowing it is fairly harmless. 800114987Speter */ 801114987Speter if (!EFL_SECURE(eflags & ~PSL_RF, regs->tf_rflags & ~PSL_RF)) { 802206553Skib uprintf("pid %d (%s): freebsd4_freebsd32_sigreturn eflags = 0x%x\n", 803206553Skib td->td_proc->p_pid, td->td_name, eflags); 804114987Speter return (EINVAL); 805114987Speter } 806114987Speter 807114987Speter /* 808114987Speter * Don't allow users to load a valid privileged %cs. Let the 809114987Speter * hardware check for invalid selectors, excess privilege in 810114987Speter * other selectors, invalid %eip's and invalid %esp's. 811114987Speter */ 812114987Speter cs = ucp->uc_mcontext.mc_cs; 813114987Speter if (!CS_SECURE(cs)) { 814206553Skib uprintf("pid %d (%s): freebsd4_sigreturn cs = 0x%x\n", 815206553Skib td->td_proc->p_pid, td->td_name, cs); 816151316Sdavidxu ksiginfo_init_trap(&ksi); 817151316Sdavidxu ksi.ksi_signo = SIGBUS; 818151316Sdavidxu ksi.ksi_code = BUS_OBJERR; 819151316Sdavidxu ksi.ksi_trapno = T_PROTFLT; 820151316Sdavidxu ksi.ksi_addr = (void *)regs->tf_rip; 821151316Sdavidxu trapsignal(td, &ksi); 822114987Speter return (EINVAL); 823114987Speter } 824114987Speter 825114987Speter regs->tf_rdi = ucp->uc_mcontext.mc_edi; 826114987Speter regs->tf_rsi = ucp->uc_mcontext.mc_esi; 827114987Speter regs->tf_rbp = ucp->uc_mcontext.mc_ebp; 828114987Speter regs->tf_rbx = ucp->uc_mcontext.mc_ebx; 829114987Speter regs->tf_rdx = ucp->uc_mcontext.mc_edx; 830114987Speter regs->tf_rcx = ucp->uc_mcontext.mc_ecx; 831114987Speter regs->tf_rax = ucp->uc_mcontext.mc_eax; 832114987Speter regs->tf_trapno = ucp->uc_mcontext.mc_trapno; 833114987Speter regs->tf_err = ucp->uc_mcontext.mc_err; 834114987Speter regs->tf_rip = ucp->uc_mcontext.mc_eip; 835114987Speter regs->tf_cs = cs; 836114987Speter regs->tf_rflags = ucp->uc_mcontext.mc_eflags; 837114987Speter regs->tf_rsp = ucp->uc_mcontext.mc_esp; 838114987Speter regs->tf_ss = ucp->uc_mcontext.mc_ss; 839190620Skib regs->tf_ds = ucp->uc_mcontext.mc_ds; 840190620Skib regs->tf_es = ucp->uc_mcontext.mc_es; 841190620Skib regs->tf_fs = ucp->uc_mcontext.mc_fs; 842190620Skib regs->tf_gs = ucp->uc_mcontext.mc_gs; 843114987Speter 844198507Skib kern_sigprocmask(td, SIG_SETMASK, &ucp->uc_sigmask, NULL, 0); 845216634Sjkim set_pcb_flags(td->td_pcb, PCB_FULL_IRET); 846114987Speter return (EJUSTRETURN); 847114987Speter} 848114987Speter#endif /* COMPAT_FREEBSD4 */ 849114987Speter 850114987Speter/* 851114987Speter * MPSAFE 852114987Speter */ 853114987Speterint 854119336Speterfreebsd32_sigreturn(td, uap) 855114987Speter struct thread *td; 856119336Speter struct freebsd32_sigreturn_args /* { 857119336Speter const struct freebsd32_ucontext *sigcntxp; 858114987Speter } */ *uap; 859114987Speter{ 860114987Speter struct ia32_ucontext uc; 861114987Speter struct trapframe *regs; 862198507Skib struct ia32_ucontext *ucp; 863230426Skib char *xfpustate; 864230426Skib size_t xfpustate_len; 865114987Speter int cs, eflags, error, ret; 866151316Sdavidxu ksiginfo_t ksi; 867114987Speter 868114987Speter error = copyin(uap->sigcntxp, &uc, sizeof(uc)); 869114987Speter if (error != 0) 870114987Speter return (error); 871114987Speter ucp = &uc; 872114987Speter regs = td->td_frame; 873114987Speter eflags = ucp->uc_mcontext.mc_eflags; 874114987Speter /* 875114987Speter * Don't allow users to change privileged or reserved flags. 876114987Speter */ 877114987Speter /* 878114987Speter * XXX do allow users to change the privileged flag PSL_RF. 879114987Speter * The cpu sets PSL_RF in tf_eflags for faults. Debuggers 880114987Speter * should sometimes set it there too. tf_eflags is kept in 881114987Speter * the signal context during signal handling and there is no 882114987Speter * other place to remember it, so the PSL_RF bit may be 883114987Speter * corrupted by the signal handler without us knowing. 884114987Speter * Corruption of the PSL_RF bit at worst causes one more or 885114987Speter * one less debugger trap, so allowing it is fairly harmless. 886114987Speter */ 887114987Speter if (!EFL_SECURE(eflags & ~PSL_RF, regs->tf_rflags & ~PSL_RF)) { 888206553Skib uprintf("pid %d (%s): freebsd32_sigreturn eflags = 0x%x\n", 889206553Skib td->td_proc->p_pid, td->td_name, eflags); 890114987Speter return (EINVAL); 891114987Speter } 892114987Speter 893114987Speter /* 894114987Speter * Don't allow users to load a valid privileged %cs. Let the 895114987Speter * hardware check for invalid selectors, excess privilege in 896114987Speter * other selectors, invalid %eip's and invalid %esp's. 897114987Speter */ 898114987Speter cs = ucp->uc_mcontext.mc_cs; 899114987Speter if (!CS_SECURE(cs)) { 900206553Skib uprintf("pid %d (%s): sigreturn cs = 0x%x\n", 901206553Skib td->td_proc->p_pid, td->td_name, cs); 902151316Sdavidxu ksiginfo_init_trap(&ksi); 903151316Sdavidxu ksi.ksi_signo = SIGBUS; 904151316Sdavidxu ksi.ksi_code = BUS_OBJERR; 905151316Sdavidxu ksi.ksi_trapno = T_PROTFLT; 906151316Sdavidxu ksi.ksi_addr = (void *)regs->tf_rip; 907151316Sdavidxu trapsignal(td, &ksi); 908114987Speter return (EINVAL); 909114987Speter } 910114987Speter 911230426Skib if ((ucp->uc_mcontext.mc_flags & _MC_HASFPXSTATE) != 0) { 912230426Skib xfpustate_len = uc.uc_mcontext.mc_xfpustate_len; 913230426Skib if (xfpustate_len > cpu_max_ext_state_size - 914230426Skib sizeof(struct savefpu)) { 915230426Skib uprintf("pid %d (%s): sigreturn xfpusave_len = 0x%zx\n", 916230426Skib td->td_proc->p_pid, td->td_name, xfpustate_len); 917230426Skib return (EINVAL); 918230426Skib } 919230426Skib xfpustate = __builtin_alloca(xfpustate_len); 920230426Skib error = copyin(PTRIN(ucp->uc_mcontext.mc_xfpustate), 921230426Skib xfpustate, xfpustate_len); 922230426Skib if (error != 0) { 923230426Skib uprintf( 924230426Skib "pid %d (%s): sigreturn copying xfpustate failed\n", 925230426Skib td->td_proc->p_pid, td->td_name); 926230426Skib return (error); 927230426Skib } 928230426Skib } else { 929230426Skib xfpustate = NULL; 930230426Skib xfpustate_len = 0; 931230426Skib } 932230426Skib ret = ia32_set_fpcontext(td, &ucp->uc_mcontext, xfpustate, 933230426Skib xfpustate_len); 934230426Skib if (ret != 0) { 935230426Skib uprintf("pid %d (%s): sigreturn set_fpcontext err %d\n", 936230426Skib td->td_proc->p_pid, td->td_name, ret); 937114987Speter return (ret); 938230426Skib } 939114987Speter 940114987Speter regs->tf_rdi = ucp->uc_mcontext.mc_edi; 941114987Speter regs->tf_rsi = ucp->uc_mcontext.mc_esi; 942114987Speter regs->tf_rbp = ucp->uc_mcontext.mc_ebp; 943114987Speter regs->tf_rbx = ucp->uc_mcontext.mc_ebx; 944114987Speter regs->tf_rdx = ucp->uc_mcontext.mc_edx; 945114987Speter regs->tf_rcx = ucp->uc_mcontext.mc_ecx; 946114987Speter regs->tf_rax = ucp->uc_mcontext.mc_eax; 947114987Speter regs->tf_trapno = ucp->uc_mcontext.mc_trapno; 948114987Speter regs->tf_err = ucp->uc_mcontext.mc_err; 949114987Speter regs->tf_rip = ucp->uc_mcontext.mc_eip; 950114987Speter regs->tf_cs = cs; 951114987Speter regs->tf_rflags = ucp->uc_mcontext.mc_eflags; 952114987Speter regs->tf_rsp = ucp->uc_mcontext.mc_esp; 953114987Speter regs->tf_ss = ucp->uc_mcontext.mc_ss; 954190620Skib regs->tf_ds = ucp->uc_mcontext.mc_ds; 955190620Skib regs->tf_es = ucp->uc_mcontext.mc_es; 956190620Skib regs->tf_fs = ucp->uc_mcontext.mc_fs; 957190620Skib regs->tf_gs = ucp->uc_mcontext.mc_gs; 958190620Skib regs->tf_flags = TF_HASSEGS; 959114987Speter 960198507Skib kern_sigprocmask(td, SIG_SETMASK, &ucp->uc_sigmask, NULL, 0); 961216634Sjkim set_pcb_flags(td->td_pcb, PCB_FULL_IRET); 962114987Speter return (EJUSTRETURN); 963114987Speter} 964122303Speter 965122303Speter/* 966122303Speter * Clear registers on exec 967122303Speter */ 968122303Spetervoid 969205642Snwhitehornia32_setregs(struct thread *td, struct image_params *imgp, u_long stack) 970122303Speter{ 971122303Speter struct trapframe *regs = td->td_frame; 972122303Speter struct pcb *pcb = td->td_pcb; 973122303Speter 974190620Skib mtx_lock(&dt_lock); 975190620Skib if (td->td_proc->p_md.md_ldt != NULL) 976190620Skib user_ldt_free(td); 977190620Skib else 978190620Skib mtx_unlock(&dt_lock); 979220238Skib#ifdef COMPAT_43 980220238Skib setup_lcall_gate(); 981220238Skib#endif 982190620Skib 983122303Speter pcb->pcb_fsbase = 0; 984122303Speter pcb->pcb_gsbase = 0; 985189423Sjhb pcb->pcb_initial_fpucw = __INITIAL_FPUCW_I386__; 986122303Speter 987122303Speter bzero((char *)regs, sizeof(struct trapframe)); 988205642Snwhitehorn regs->tf_rip = imgp->entry_addr; 989122303Speter regs->tf_rsp = stack; 990122303Speter regs->tf_rflags = PSL_USER | (regs->tf_rflags & PSL_T); 991122303Speter regs->tf_ss = _udatasel; 992122303Speter regs->tf_cs = _ucode32sel; 993205642Snwhitehorn regs->tf_rbx = imgp->ps_strings; 994190620Skib regs->tf_ds = _udatasel; 995190620Skib regs->tf_es = _udatasel; 996190620Skib regs->tf_fs = _ufssel; 997190620Skib regs->tf_gs = _ugssel; 998190620Skib regs->tf_flags = TF_HASSEGS; 999190620Skib 1000122303Speter fpstate_drop(td); 1001122303Speter 1002122303Speter /* Return via doreti so that we can change to a different %cs */ 1003216634Sjkim set_pcb_flags(pcb, PCB_32BIT | PCB_FULL_IRET); 1004216634Sjkim clear_pcb_flags(pcb, PCB_GS32BIT); 1005122303Speter td->td_retval[1] = 0; 1006122303Speter} 1007