Page Menu
Home
FreeBSD
Search
Configure Global Search
Log In
Files
F135970165
D31954.id95155.diff
No One
Temporary
Actions
View File
Edit File
Delete File
View Transforms
Subscribe
Mute Notifications
Flag For Later
Award Token
Size
58 KB
Referenced Files
None
Subscribers
None
D31954.id95155.diff
View Options
diff --git a/sys/amd64/amd64/fpu.c b/sys/amd64/amd64/fpu.c
--- a/sys/amd64/amd64/fpu.c
+++ b/sys/amd64/amd64/fpu.c
@@ -448,6 +448,8 @@
xsave_area_elm_descr), M_DEVBUF, M_WAITOK | M_ZERO);
}
+ cpu_thread_alloc(&thread0);
+
saveintr = intr_disable();
stop_emulating();
diff --git a/sys/amd64/amd64/machdep.c b/sys/amd64/amd64/machdep.c
--- a/sys/amd64/amd64/machdep.c
+++ b/sys/amd64/amd64/machdep.c
@@ -166,14 +166,7 @@
extern u_int64_t hammer_time(u_int64_t, u_int64_t);
-#define CS_SECURE(cs) (ISPL(cs) == SEL_UPL)
-#define EFL_SECURE(ef, oef) ((((ef) ^ (oef)) & ~PSL_USERCHANGE) == 0)
-
static void cpu_startup(void *);
-static void get_fpcontext(struct thread *td, mcontext_t *mcp,
- char *xfpusave, size_t xfpusave_len);
-static int set_fpcontext(struct thread *td, mcontext_t *mcp,
- char *xfpustate, size_t xfpustate_len);
SYSINIT(cpu, SI_SUB_CPU, SI_ORDER_FIRST, cpu_startup, NULL);
/* Preload data parse function */
@@ -325,331 +318,6 @@
}
SYSINIT(late_ifunc_resolve, SI_SUB_CPU, SI_ORDER_ANY, late_ifunc_resolve, NULL);
-/*
- * Send an interrupt to process.
- *
- * Stack is set up to allow sigcode stored
- * at top to call routine, followed by call
- * to sigreturn routine below. After sigreturn
- * resets the signal mask, the stack, and the
- * frame pointer, it returns to the user
- * specified pc, psl.
- */
-void
-sendsig(sig_t catcher, ksiginfo_t *ksi, sigset_t *mask)
-{
- struct sigframe sf, *sfp;
- struct pcb *pcb;
- struct proc *p;
- struct thread *td;
- struct sigacts *psp;
- char *sp;
- struct trapframe *regs;
- char *xfpusave;
- size_t xfpusave_len;
- int sig;
- int oonstack;
-
- td = curthread;
- pcb = td->td_pcb;
- p = td->td_proc;
- PROC_LOCK_ASSERT(p, MA_OWNED);
- sig = ksi->ksi_signo;
- psp = p->p_sigacts;
- mtx_assert(&psp->ps_mtx, MA_OWNED);
- regs = td->td_frame;
- oonstack = sigonstack(regs->tf_rsp);
-
- if (cpu_max_ext_state_size > sizeof(struct savefpu) && use_xsave) {
- xfpusave_len = cpu_max_ext_state_size - sizeof(struct savefpu);
- xfpusave = __builtin_alloca(xfpusave_len);
- } else {
- xfpusave_len = 0;
- xfpusave = NULL;
- }
-
- /* Save user context. */
- bzero(&sf, sizeof(sf));
- sf.sf_uc.uc_sigmask = *mask;
- sf.sf_uc.uc_stack = td->td_sigstk;
- sf.sf_uc.uc_stack.ss_flags = (td->td_pflags & TDP_ALTSTACK)
- ? ((oonstack) ? SS_ONSTACK : 0) : SS_DISABLE;
- sf.sf_uc.uc_mcontext.mc_onstack = (oonstack) ? 1 : 0;
- bcopy(regs, &sf.sf_uc.uc_mcontext.mc_rdi, sizeof(*regs));
- sf.sf_uc.uc_mcontext.mc_len = sizeof(sf.sf_uc.uc_mcontext); /* magic */
- get_fpcontext(td, &sf.sf_uc.uc_mcontext, xfpusave, xfpusave_len);
- fpstate_drop(td);
- update_pcb_bases(pcb);
- sf.sf_uc.uc_mcontext.mc_fsbase = pcb->pcb_fsbase;
- sf.sf_uc.uc_mcontext.mc_gsbase = pcb->pcb_gsbase;
- bzero(sf.sf_uc.uc_mcontext.mc_spare,
- sizeof(sf.sf_uc.uc_mcontext.mc_spare));
-
- /* Allocate space for the signal handler context. */
- if ((td->td_pflags & TDP_ALTSTACK) != 0 && !oonstack &&
- SIGISMEMBER(psp->ps_sigonstack, sig)) {
- sp = (char *)td->td_sigstk.ss_sp + td->td_sigstk.ss_size;
-#if defined(COMPAT_43)
- td->td_sigstk.ss_flags |= SS_ONSTACK;
-#endif
- } else
- sp = (char *)regs->tf_rsp - 128;
- if (xfpusave != NULL) {
- sp -= xfpusave_len;
- sp = (char *)((unsigned long)sp & ~0x3Ful);
- sf.sf_uc.uc_mcontext.mc_xfpustate = (register_t)sp;
- }
- sp -= sizeof(struct sigframe);
- /* Align to 16 bytes. */
- sfp = (struct sigframe *)((unsigned long)sp & ~0xFul);
-
- /* Build the argument list for the signal handler. */
- regs->tf_rdi = sig; /* arg 1 in %rdi */
- regs->tf_rdx = (register_t)&sfp->sf_uc; /* arg 3 in %rdx */
- bzero(&sf.sf_si, sizeof(sf.sf_si));
- if (SIGISMEMBER(psp->ps_siginfo, sig)) {
- /* Signal handler installed with SA_SIGINFO. */
- regs->tf_rsi = (register_t)&sfp->sf_si; /* arg 2 in %rsi */
- sf.sf_ahu.sf_action = (__siginfohandler_t *)catcher;
-
- /* Fill in POSIX parts */
- sf.sf_si = ksi->ksi_info;
- sf.sf_si.si_signo = sig; /* maybe a translated signal */
- regs->tf_rcx = (register_t)ksi->ksi_addr; /* arg 4 in %rcx */
- } else {
- /* Old FreeBSD-style arguments. */
- regs->tf_rsi = ksi->ksi_code; /* arg 2 in %rsi */
- regs->tf_rcx = (register_t)ksi->ksi_addr; /* arg 4 in %rcx */
- sf.sf_ahu.sf_handler = catcher;
- }
- mtx_unlock(&psp->ps_mtx);
- PROC_UNLOCK(p);
-
- /*
- * Copy the sigframe out to the user's stack.
- */
- if (copyout(&sf, sfp, sizeof(*sfp)) != 0 ||
- (xfpusave != NULL && copyout(xfpusave,
- (void *)sf.sf_uc.uc_mcontext.mc_xfpustate, xfpusave_len)
- != 0)) {
-#ifdef DEBUG
- printf("process %ld has trashed its stack\n", (long)p->p_pid);
-#endif
- PROC_LOCK(p);
- sigexit(td, SIGILL);
- }
-
- regs->tf_rsp = (long)sfp;
- regs->tf_rip = p->p_sysent->sv_sigcode_base;
- regs->tf_rflags &= ~(PSL_T | PSL_D);
- regs->tf_cs = _ucodesel;
- regs->tf_ds = _udatasel;
- regs->tf_ss = _udatasel;
- regs->tf_es = _udatasel;
- regs->tf_fs = _ufssel;
- regs->tf_gs = _ugssel;
- regs->tf_flags = TF_HASSEGS;
- PROC_LOCK(p);
- mtx_lock(&psp->ps_mtx);
-}
-
-/*
- * System call to cleanup state after a signal
- * has been taken. Reset signal mask and
- * stack state from context left by sendsig (above).
- * Return to previous pc and psl as specified by
- * context left by sendsig. Check carefully to
- * make sure that the user has not modified the
- * state to gain improper privileges.
- *
- * MPSAFE
- */
-int
-sys_sigreturn(td, uap)
- struct thread *td;
- struct sigreturn_args /* {
- const struct __ucontext *sigcntxp;
- } */ *uap;
-{
- ucontext_t uc;
- struct pcb *pcb;
- struct proc *p;
- struct trapframe *regs;
- ucontext_t *ucp;
- char *xfpustate;
- size_t xfpustate_len;
- long rflags;
- int cs, error, ret;
- ksiginfo_t ksi;
-
- pcb = td->td_pcb;
- p = td->td_proc;
-
- error = copyin(uap->sigcntxp, &uc, sizeof(uc));
- if (error != 0) {
- uprintf("pid %d (%s): sigreturn copyin failed\n",
- p->p_pid, td->td_name);
- return (error);
- }
- ucp = &uc;
- if ((ucp->uc_mcontext.mc_flags & ~_MC_FLAG_MASK) != 0) {
- uprintf("pid %d (%s): sigreturn mc_flags %x\n", p->p_pid,
- td->td_name, ucp->uc_mcontext.mc_flags);
- return (EINVAL);
- }
- regs = td->td_frame;
- rflags = ucp->uc_mcontext.mc_rflags;
- /*
- * Don't allow users to change privileged or reserved flags.
- */
- if (!EFL_SECURE(rflags, regs->tf_rflags)) {
- uprintf("pid %d (%s): sigreturn rflags = 0x%lx\n", p->p_pid,
- td->td_name, rflags);
- return (EINVAL);
- }
-
- /*
- * Don't allow users to load a valid privileged %cs. Let the
- * hardware check for invalid selectors, excess privilege in
- * other selectors, invalid %eip's and invalid %esp's.
- */
- cs = ucp->uc_mcontext.mc_cs;
- if (!CS_SECURE(cs)) {
- uprintf("pid %d (%s): sigreturn cs = 0x%x\n", p->p_pid,
- td->td_name, cs);
- ksiginfo_init_trap(&ksi);
- ksi.ksi_signo = SIGBUS;
- ksi.ksi_code = BUS_OBJERR;
- ksi.ksi_trapno = T_PROTFLT;
- ksi.ksi_addr = (void *)regs->tf_rip;
- trapsignal(td, &ksi);
- return (EINVAL);
- }
-
- if ((uc.uc_mcontext.mc_flags & _MC_HASFPXSTATE) != 0) {
- xfpustate_len = uc.uc_mcontext.mc_xfpustate_len;
- if (xfpustate_len > cpu_max_ext_state_size -
- sizeof(struct savefpu)) {
- uprintf("pid %d (%s): sigreturn xfpusave_len = 0x%zx\n",
- p->p_pid, td->td_name, xfpustate_len);
- return (EINVAL);
- }
- xfpustate = __builtin_alloca(xfpustate_len);
- error = copyin((const void *)uc.uc_mcontext.mc_xfpustate,
- xfpustate, xfpustate_len);
- if (error != 0) {
- uprintf(
- "pid %d (%s): sigreturn copying xfpustate failed\n",
- p->p_pid, td->td_name);
- return (error);
- }
- } else {
- xfpustate = NULL;
- xfpustate_len = 0;
- }
- ret = set_fpcontext(td, &ucp->uc_mcontext, xfpustate, xfpustate_len);
- if (ret != 0) {
- uprintf("pid %d (%s): sigreturn set_fpcontext err %d\n",
- p->p_pid, td->td_name, ret);
- return (ret);
- }
- bcopy(&ucp->uc_mcontext.mc_rdi, regs, sizeof(*regs));
- update_pcb_bases(pcb);
- pcb->pcb_fsbase = ucp->uc_mcontext.mc_fsbase;
- pcb->pcb_gsbase = ucp->uc_mcontext.mc_gsbase;
-
-#if defined(COMPAT_43)
- if (ucp->uc_mcontext.mc_onstack & 1)
- td->td_sigstk.ss_flags |= SS_ONSTACK;
- else
- td->td_sigstk.ss_flags &= ~SS_ONSTACK;
-#endif
-
- kern_sigprocmask(td, SIG_SETMASK, &ucp->uc_sigmask, NULL, 0);
- return (EJUSTRETURN);
-}
-
-#ifdef COMPAT_FREEBSD4
-int
-freebsd4_sigreturn(struct thread *td, struct freebsd4_sigreturn_args *uap)
-{
-
- return sys_sigreturn(td, (struct sigreturn_args *)uap);
-}
-#endif
-
-/*
- * Reset the hardware debug registers if they were in use.
- * They won't have any meaning for the newly exec'd process.
- */
-void
-x86_clear_dbregs(struct pcb *pcb)
-{
- if ((pcb->pcb_flags & PCB_DBREGS) == 0)
- return;
-
- pcb->pcb_dr0 = 0;
- pcb->pcb_dr1 = 0;
- pcb->pcb_dr2 = 0;
- pcb->pcb_dr3 = 0;
- pcb->pcb_dr6 = 0;
- pcb->pcb_dr7 = 0;
-
- if (pcb == curpcb) {
- /*
- * Clear the debug registers on the running CPU,
- * otherwise they will end up affecting the next
- * process we switch to.
- */
- reset_dbregs();
- }
- clear_pcb_flags(pcb, PCB_DBREGS);
-}
-
-/*
- * Reset registers to default values on exec.
- */
-void
-exec_setregs(struct thread *td, struct image_params *imgp, uintptr_t stack)
-{
- struct trapframe *regs;
- struct pcb *pcb;
- register_t saved_rflags;
-
- regs = td->td_frame;
- pcb = td->td_pcb;
-
- if (td->td_proc->p_md.md_ldt != NULL)
- user_ldt_free(td);
-
- update_pcb_bases(pcb);
- pcb->pcb_fsbase = 0;
- pcb->pcb_gsbase = 0;
- clear_pcb_flags(pcb, PCB_32BIT);
- pcb->pcb_initial_fpucw = __INITIAL_FPUCW__;
-
- saved_rflags = regs->tf_rflags & PSL_T;
- bzero((char *)regs, sizeof(struct trapframe));
- regs->tf_rip = imgp->entry_addr;
- regs->tf_rsp = ((stack - 8) & ~0xFul) + 8;
- regs->tf_rdi = stack; /* argv */
- regs->tf_rflags = PSL_USER | saved_rflags;
- regs->tf_ss = _udatasel;
- regs->tf_cs = _ucodesel;
- regs->tf_ds = _udatasel;
- regs->tf_es = _udatasel;
- regs->tf_fs = _ufssel;
- regs->tf_gs = _ugssel;
- regs->tf_flags = TF_HASSEGS;
-
- x86_clear_dbregs(pcb);
-
- /*
- * Drop the FP state if we hold it, so that the process gets a
- * clean FP state if it uses the FPU again.
- */
- fpstate_drop(td);
-}
void
cpu_setregs(void)
@@ -1590,7 +1258,6 @@
caddr_t kmdp;
int gsel_tss, x;
struct pcpu *pc;
- struct xstate_hdr *xhdr;
uint64_t cr3, rsp0;
pml4_entry_t *pml4e;
pdp_entry_t *pdpe;
@@ -1896,19 +1563,6 @@
msgbufinit(msgbufp, msgbufsize);
fpuinit();
- /*
- * Reinitialize thread0's stack base now that the xsave area size is
- * known. Set up thread0's pcb save area after fpuinit calculated fpu
- * save area size. Zero out the extended state header in fpu save area.
- */
- set_top_of_stack_td(&thread0);
- thread0.td_pcb->pcb_save = get_pcb_user_save_td(&thread0);
- bzero(thread0.td_pcb->pcb_save, cpu_max_ext_state_size);
- if (use_xsave) {
- xhdr = (struct xstate_hdr *)(get_pcb_user_save_td(&thread0) +
- 1);
- xhdr->xstate_bv = xsave_mask;
- }
/* make an initial tss so cpu can get interrupt stack on syscall! */
rsp0 = thread0.td_md.md_stack_base;
/* Ensure the stack is aligned to 16 bytes */
@@ -2071,601 +1725,6 @@
pcb->pcb_rsp = tf->tf_rsp;
}
-int
-ptrace_set_pc(struct thread *td, unsigned long addr)
-{
-
- td->td_frame->tf_rip = addr;
- set_pcb_flags(td->td_pcb, PCB_FULL_IRET);
- return (0);
-}
-
-int
-ptrace_single_step(struct thread *td)
-{
-
- PROC_LOCK_ASSERT(td->td_proc, MA_OWNED);
- if ((td->td_frame->tf_rflags & PSL_T) == 0) {
- td->td_frame->tf_rflags |= PSL_T;
- td->td_dbgflags |= TDB_STEP;
- }
- return (0);
-}
-
-int
-ptrace_clear_single_step(struct thread *td)
-{
-
- PROC_LOCK_ASSERT(td->td_proc, MA_OWNED);
- td->td_frame->tf_rflags &= ~PSL_T;
- td->td_dbgflags &= ~TDB_STEP;
- return (0);
-}
-
-int
-fill_regs(struct thread *td, struct reg *regs)
-{
- struct trapframe *tp;
-
- tp = td->td_frame;
- return (fill_frame_regs(tp, regs));
-}
-
-int
-fill_frame_regs(struct trapframe *tp, struct reg *regs)
-{
-
- regs->r_r15 = tp->tf_r15;
- regs->r_r14 = tp->tf_r14;
- regs->r_r13 = tp->tf_r13;
- regs->r_r12 = tp->tf_r12;
- regs->r_r11 = tp->tf_r11;
- regs->r_r10 = tp->tf_r10;
- regs->r_r9 = tp->tf_r9;
- regs->r_r8 = tp->tf_r8;
- regs->r_rdi = tp->tf_rdi;
- regs->r_rsi = tp->tf_rsi;
- regs->r_rbp = tp->tf_rbp;
- regs->r_rbx = tp->tf_rbx;
- regs->r_rdx = tp->tf_rdx;
- regs->r_rcx = tp->tf_rcx;
- regs->r_rax = tp->tf_rax;
- regs->r_rip = tp->tf_rip;
- regs->r_cs = tp->tf_cs;
- regs->r_rflags = tp->tf_rflags;
- regs->r_rsp = tp->tf_rsp;
- regs->r_ss = tp->tf_ss;
- if (tp->tf_flags & TF_HASSEGS) {
- regs->r_ds = tp->tf_ds;
- regs->r_es = tp->tf_es;
- regs->r_fs = tp->tf_fs;
- regs->r_gs = tp->tf_gs;
- } else {
- regs->r_ds = 0;
- regs->r_es = 0;
- regs->r_fs = 0;
- regs->r_gs = 0;
- }
- regs->r_err = 0;
- regs->r_trapno = 0;
- return (0);
-}
-
-int
-set_regs(struct thread *td, struct reg *regs)
-{
- struct trapframe *tp;
- register_t rflags;
-
- tp = td->td_frame;
- rflags = regs->r_rflags & 0xffffffff;
- if (!EFL_SECURE(rflags, tp->tf_rflags) || !CS_SECURE(regs->r_cs))
- return (EINVAL);
- tp->tf_r15 = regs->r_r15;
- tp->tf_r14 = regs->r_r14;
- tp->tf_r13 = regs->r_r13;
- tp->tf_r12 = regs->r_r12;
- tp->tf_r11 = regs->r_r11;
- tp->tf_r10 = regs->r_r10;
- tp->tf_r9 = regs->r_r9;
- tp->tf_r8 = regs->r_r8;
- tp->tf_rdi = regs->r_rdi;
- tp->tf_rsi = regs->r_rsi;
- tp->tf_rbp = regs->r_rbp;
- tp->tf_rbx = regs->r_rbx;
- tp->tf_rdx = regs->r_rdx;
- tp->tf_rcx = regs->r_rcx;
- tp->tf_rax = regs->r_rax;
- tp->tf_rip = regs->r_rip;
- tp->tf_cs = regs->r_cs;
- tp->tf_rflags = rflags;
- tp->tf_rsp = regs->r_rsp;
- tp->tf_ss = regs->r_ss;
- if (0) { /* XXXKIB */
- tp->tf_ds = regs->r_ds;
- tp->tf_es = regs->r_es;
- tp->tf_fs = regs->r_fs;
- tp->tf_gs = regs->r_gs;
- tp->tf_flags = TF_HASSEGS;
- }
- set_pcb_flags(td->td_pcb, PCB_FULL_IRET);
- return (0);
-}
-
-/* XXX check all this stuff! */
-/* externalize from sv_xmm */
-static void
-fill_fpregs_xmm(struct savefpu *sv_xmm, struct fpreg *fpregs)
-{
- struct envxmm *penv_fpreg = (struct envxmm *)&fpregs->fpr_env;
- struct envxmm *penv_xmm = &sv_xmm->sv_env;
- int i;
-
- /* pcb -> fpregs */
- bzero(fpregs, sizeof(*fpregs));
-
- /* FPU control/status */
- penv_fpreg->en_cw = penv_xmm->en_cw;
- penv_fpreg->en_sw = penv_xmm->en_sw;
- penv_fpreg->en_tw = penv_xmm->en_tw;
- penv_fpreg->en_opcode = penv_xmm->en_opcode;
- penv_fpreg->en_rip = penv_xmm->en_rip;
- penv_fpreg->en_rdp = penv_xmm->en_rdp;
- penv_fpreg->en_mxcsr = penv_xmm->en_mxcsr;
- penv_fpreg->en_mxcsr_mask = penv_xmm->en_mxcsr_mask;
-
- /* FPU registers */
- for (i = 0; i < 8; ++i)
- bcopy(sv_xmm->sv_fp[i].fp_acc.fp_bytes, fpregs->fpr_acc[i], 10);
-
- /* SSE registers */
- for (i = 0; i < 16; ++i)
- bcopy(sv_xmm->sv_xmm[i].xmm_bytes, fpregs->fpr_xacc[i], 16);
-}
-
-/* internalize from fpregs into sv_xmm */
-static void
-set_fpregs_xmm(struct fpreg *fpregs, struct savefpu *sv_xmm)
-{
- struct envxmm *penv_xmm = &sv_xmm->sv_env;
- struct envxmm *penv_fpreg = (struct envxmm *)&fpregs->fpr_env;
- int i;
-
- /* fpregs -> pcb */
- /* FPU control/status */
- penv_xmm->en_cw = penv_fpreg->en_cw;
- penv_xmm->en_sw = penv_fpreg->en_sw;
- penv_xmm->en_tw = penv_fpreg->en_tw;
- penv_xmm->en_opcode = penv_fpreg->en_opcode;
- penv_xmm->en_rip = penv_fpreg->en_rip;
- penv_xmm->en_rdp = penv_fpreg->en_rdp;
- penv_xmm->en_mxcsr = penv_fpreg->en_mxcsr;
- penv_xmm->en_mxcsr_mask = penv_fpreg->en_mxcsr_mask & cpu_mxcsr_mask;
-
- /* FPU registers */
- for (i = 0; i < 8; ++i)
- bcopy(fpregs->fpr_acc[i], sv_xmm->sv_fp[i].fp_acc.fp_bytes, 10);
-
- /* SSE registers */
- for (i = 0; i < 16; ++i)
- bcopy(fpregs->fpr_xacc[i], sv_xmm->sv_xmm[i].xmm_bytes, 16);
-}
-
-/* externalize from td->pcb */
-int
-fill_fpregs(struct thread *td, struct fpreg *fpregs)
-{
-
- KASSERT(td == curthread || TD_IS_SUSPENDED(td) ||
- P_SHOULDSTOP(td->td_proc),
- ("not suspended thread %p", td));
- fpugetregs(td);
- fill_fpregs_xmm(get_pcb_user_save_td(td), fpregs);
- return (0);
-}
-
-/* internalize to td->pcb */
-int
-set_fpregs(struct thread *td, struct fpreg *fpregs)
-{
-
- critical_enter();
- set_fpregs_xmm(fpregs, get_pcb_user_save_td(td));
- fpuuserinited(td);
- critical_exit();
- return (0);
-}
-
-/*
- * Get machine context.
- */
-int
-get_mcontext(struct thread *td, mcontext_t *mcp, int flags)
-{
- struct pcb *pcb;
- struct trapframe *tp;
-
- pcb = td->td_pcb;
- tp = td->td_frame;
- PROC_LOCK(curthread->td_proc);
- mcp->mc_onstack = sigonstack(tp->tf_rsp);
- PROC_UNLOCK(curthread->td_proc);
- mcp->mc_r15 = tp->tf_r15;
- mcp->mc_r14 = tp->tf_r14;
- mcp->mc_r13 = tp->tf_r13;
- mcp->mc_r12 = tp->tf_r12;
- mcp->mc_r11 = tp->tf_r11;
- mcp->mc_r10 = tp->tf_r10;
- mcp->mc_r9 = tp->tf_r9;
- mcp->mc_r8 = tp->tf_r8;
- mcp->mc_rdi = tp->tf_rdi;
- mcp->mc_rsi = tp->tf_rsi;
- mcp->mc_rbp = tp->tf_rbp;
- mcp->mc_rbx = tp->tf_rbx;
- mcp->mc_rcx = tp->tf_rcx;
- mcp->mc_rflags = tp->tf_rflags;
- if (flags & GET_MC_CLEAR_RET) {
- mcp->mc_rax = 0;
- mcp->mc_rdx = 0;
- mcp->mc_rflags &= ~PSL_C;
- } else {
- mcp->mc_rax = tp->tf_rax;
- mcp->mc_rdx = tp->tf_rdx;
- }
- mcp->mc_rip = tp->tf_rip;
- mcp->mc_cs = tp->tf_cs;
- mcp->mc_rsp = tp->tf_rsp;
- mcp->mc_ss = tp->tf_ss;
- mcp->mc_ds = tp->tf_ds;
- mcp->mc_es = tp->tf_es;
- mcp->mc_fs = tp->tf_fs;
- mcp->mc_gs = tp->tf_gs;
- mcp->mc_flags = tp->tf_flags;
- mcp->mc_len = sizeof(*mcp);
- get_fpcontext(td, mcp, NULL, 0);
- update_pcb_bases(pcb);
- mcp->mc_fsbase = pcb->pcb_fsbase;
- mcp->mc_gsbase = pcb->pcb_gsbase;
- mcp->mc_xfpustate = 0;
- mcp->mc_xfpustate_len = 0;
- bzero(mcp->mc_spare, sizeof(mcp->mc_spare));
- return (0);
-}
-
-/*
- * Set machine context.
- *
- * However, we don't set any but the user modifiable flags, and we won't
- * touch the cs selector.
- */
-int
-set_mcontext(struct thread *td, mcontext_t *mcp)
-{
- struct pcb *pcb;
- struct trapframe *tp;
- char *xfpustate;
- long rflags;
- int ret;
-
- pcb = td->td_pcb;
- tp = td->td_frame;
- if (mcp->mc_len != sizeof(*mcp) ||
- (mcp->mc_flags & ~_MC_FLAG_MASK) != 0)
- return (EINVAL);
- rflags = (mcp->mc_rflags & PSL_USERCHANGE) |
- (tp->tf_rflags & ~PSL_USERCHANGE);
- if (mcp->mc_flags & _MC_HASFPXSTATE) {
- if (mcp->mc_xfpustate_len > cpu_max_ext_state_size -
- sizeof(struct savefpu))
- return (EINVAL);
- xfpustate = __builtin_alloca(mcp->mc_xfpustate_len);
- ret = copyin((void *)mcp->mc_xfpustate, xfpustate,
- mcp->mc_xfpustate_len);
- if (ret != 0)
- return (ret);
- } else
- xfpustate = NULL;
- ret = set_fpcontext(td, mcp, xfpustate, mcp->mc_xfpustate_len);
- if (ret != 0)
- return (ret);
- tp->tf_r15 = mcp->mc_r15;
- tp->tf_r14 = mcp->mc_r14;
- tp->tf_r13 = mcp->mc_r13;
- tp->tf_r12 = mcp->mc_r12;
- tp->tf_r11 = mcp->mc_r11;
- tp->tf_r10 = mcp->mc_r10;
- tp->tf_r9 = mcp->mc_r9;
- tp->tf_r8 = mcp->mc_r8;
- tp->tf_rdi = mcp->mc_rdi;
- tp->tf_rsi = mcp->mc_rsi;
- tp->tf_rbp = mcp->mc_rbp;
- tp->tf_rbx = mcp->mc_rbx;
- tp->tf_rdx = mcp->mc_rdx;
- tp->tf_rcx = mcp->mc_rcx;
- tp->tf_rax = mcp->mc_rax;
- tp->tf_rip = mcp->mc_rip;
- tp->tf_rflags = rflags;
- tp->tf_rsp = mcp->mc_rsp;
- tp->tf_ss = mcp->mc_ss;
- tp->tf_flags = mcp->mc_flags;
- if (tp->tf_flags & TF_HASSEGS) {
- tp->tf_ds = mcp->mc_ds;
- tp->tf_es = mcp->mc_es;
- tp->tf_fs = mcp->mc_fs;
- tp->tf_gs = mcp->mc_gs;
- }
- set_pcb_flags(pcb, PCB_FULL_IRET);
- if (mcp->mc_flags & _MC_HASBASES) {
- pcb->pcb_fsbase = mcp->mc_fsbase;
- pcb->pcb_gsbase = mcp->mc_gsbase;
- }
- return (0);
-}
-
-static void
-get_fpcontext(struct thread *td, mcontext_t *mcp, char *xfpusave,
- size_t xfpusave_len)
-{
- size_t max_len, len;
-
- mcp->mc_ownedfp = fpugetregs(td);
- bcopy(get_pcb_user_save_td(td), &mcp->mc_fpstate[0],
- sizeof(mcp->mc_fpstate));
- mcp->mc_fpformat = fpuformat();
- if (!use_xsave || xfpusave_len == 0)
- return;
- max_len = cpu_max_ext_state_size - sizeof(struct savefpu);
- len = xfpusave_len;
- if (len > max_len) {
- len = max_len;
- bzero(xfpusave + max_len, len - max_len);
- }
- mcp->mc_flags |= _MC_HASFPXSTATE;
- mcp->mc_xfpustate_len = len;
- bcopy(get_pcb_user_save_td(td) + 1, xfpusave, len);
-}
-
-static int
-set_fpcontext(struct thread *td, mcontext_t *mcp, char *xfpustate,
- size_t xfpustate_len)
-{
- int error;
-
- if (mcp->mc_fpformat == _MC_FPFMT_NODEV)
- return (0);
- else if (mcp->mc_fpformat != _MC_FPFMT_XMM)
- return (EINVAL);
- else if (mcp->mc_ownedfp == _MC_FPOWNED_NONE) {
- /* We don't care what state is left in the FPU or PCB. */
- fpstate_drop(td);
- error = 0;
- } else if (mcp->mc_ownedfp == _MC_FPOWNED_FPU ||
- mcp->mc_ownedfp == _MC_FPOWNED_PCB) {
- error = fpusetregs(td, (struct savefpu *)&mcp->mc_fpstate,
- xfpustate, xfpustate_len);
- } else
- return (EINVAL);
- return (error);
-}
-
-void
-fpstate_drop(struct thread *td)
-{
-
- KASSERT(PCB_USER_FPU(td->td_pcb), ("fpstate_drop: kernel-owned fpu"));
- critical_enter();
- if (PCPU_GET(fpcurthread) == td)
- fpudrop();
- /*
- * XXX force a full drop of the fpu. The above only drops it if we
- * owned it.
- *
- * XXX I don't much like fpugetuserregs()'s semantics of doing a full
- * drop. Dropping only to the pcb matches fnsave's behaviour.
- * We only need to drop to !PCB_INITDONE in sendsig(). But
- * sendsig() is the only caller of fpugetuserregs()... perhaps we just
- * have too many layers.
- */
- clear_pcb_flags(curthread->td_pcb,
- PCB_FPUINITDONE | PCB_USERFPUINITDONE);
- critical_exit();
-}
-
-int
-fill_dbregs(struct thread *td, struct dbreg *dbregs)
-{
- struct pcb *pcb;
-
- if (td == NULL) {
- dbregs->dr[0] = rdr0();
- dbregs->dr[1] = rdr1();
- dbregs->dr[2] = rdr2();
- dbregs->dr[3] = rdr3();
- dbregs->dr[6] = rdr6();
- dbregs->dr[7] = rdr7();
- } else {
- pcb = td->td_pcb;
- dbregs->dr[0] = pcb->pcb_dr0;
- dbregs->dr[1] = pcb->pcb_dr1;
- dbregs->dr[2] = pcb->pcb_dr2;
- dbregs->dr[3] = pcb->pcb_dr3;
- dbregs->dr[6] = pcb->pcb_dr6;
- dbregs->dr[7] = pcb->pcb_dr7;
- }
- dbregs->dr[4] = 0;
- dbregs->dr[5] = 0;
- dbregs->dr[8] = 0;
- dbregs->dr[9] = 0;
- dbregs->dr[10] = 0;
- dbregs->dr[11] = 0;
- dbregs->dr[12] = 0;
- dbregs->dr[13] = 0;
- dbregs->dr[14] = 0;
- dbregs->dr[15] = 0;
- return (0);
-}
-
-int
-set_dbregs(struct thread *td, struct dbreg *dbregs)
-{
- struct pcb *pcb;
- int i;
-
- if (td == NULL) {
- load_dr0(dbregs->dr[0]);
- load_dr1(dbregs->dr[1]);
- load_dr2(dbregs->dr[2]);
- load_dr3(dbregs->dr[3]);
- load_dr6(dbregs->dr[6]);
- load_dr7(dbregs->dr[7]);
- } else {
- /*
- * Don't let an illegal value for dr7 get set. Specifically,
- * check for undefined settings. Setting these bit patterns
- * result in undefined behaviour and can lead to an unexpected
- * TRCTRAP or a general protection fault right here.
- * Upper bits of dr6 and dr7 must not be set
- */
- for (i = 0; i < 4; i++) {
- if (DBREG_DR7_ACCESS(dbregs->dr[7], i) == 0x02)
- return (EINVAL);
- if (td->td_frame->tf_cs == _ucode32sel &&
- DBREG_DR7_LEN(dbregs->dr[7], i) == DBREG_DR7_LEN_8)
- return (EINVAL);
- }
- if ((dbregs->dr[6] & 0xffffffff00000000ul) != 0 ||
- (dbregs->dr[7] & 0xffffffff00000000ul) != 0)
- return (EINVAL);
-
- pcb = td->td_pcb;
-
- /*
- * Don't let a process set a breakpoint that is not within the
- * process's address space. If a process could do this, it
- * could halt the system by setting a breakpoint in the kernel
- * (if ddb was enabled). Thus, we need to check to make sure
- * that no breakpoints are being enabled for addresses outside
- * process's address space.
- *
- * XXX - what about when the watched area of the user's
- * address space is written into from within the kernel
- * ... wouldn't that still cause a breakpoint to be generated
- * from within kernel mode?
- */
-
- if (DBREG_DR7_ENABLED(dbregs->dr[7], 0)) {
- /* dr0 is enabled */
- if (dbregs->dr[0] >= VM_MAXUSER_ADDRESS)
- return (EINVAL);
- }
- if (DBREG_DR7_ENABLED(dbregs->dr[7], 1)) {
- /* dr1 is enabled */
- if (dbregs->dr[1] >= VM_MAXUSER_ADDRESS)
- return (EINVAL);
- }
- if (DBREG_DR7_ENABLED(dbregs->dr[7], 2)) {
- /* dr2 is enabled */
- if (dbregs->dr[2] >= VM_MAXUSER_ADDRESS)
- return (EINVAL);
- }
- if (DBREG_DR7_ENABLED(dbregs->dr[7], 3)) {
- /* dr3 is enabled */
- if (dbregs->dr[3] >= VM_MAXUSER_ADDRESS)
- return (EINVAL);
- }
-
- pcb->pcb_dr0 = dbregs->dr[0];
- pcb->pcb_dr1 = dbregs->dr[1];
- pcb->pcb_dr2 = dbregs->dr[2];
- pcb->pcb_dr3 = dbregs->dr[3];
- pcb->pcb_dr6 = dbregs->dr[6];
- pcb->pcb_dr7 = dbregs->dr[7];
-
- set_pcb_flags(pcb, PCB_DBREGS);
- }
-
- return (0);
-}
-
-void
-reset_dbregs(void)
-{
-
- load_dr7(0); /* Turn off the control bits first */
- load_dr0(0);
- load_dr1(0);
- load_dr2(0);
- load_dr3(0);
- load_dr6(0);
-}
-
-/*
- * Return > 0 if a hardware breakpoint has been hit, and the
- * breakpoint was in user space. Return 0, otherwise.
- */
-int
-user_dbreg_trap(register_t dr6)
-{
- u_int64_t dr7;
- u_int64_t bp; /* breakpoint bits extracted from dr6 */
- int nbp; /* number of breakpoints that triggered */
- caddr_t addr[4]; /* breakpoint addresses */
- int i;
-
- bp = dr6 & DBREG_DR6_BMASK;
- if (bp == 0) {
- /*
- * None of the breakpoint bits are set meaning this
- * trap was not caused by any of the debug registers
- */
- return 0;
- }
-
- dr7 = rdr7();
- if ((dr7 & 0x000000ff) == 0) {
- /*
- * all GE and LE bits in the dr7 register are zero,
- * thus the trap couldn't have been caused by the
- * hardware debug registers
- */
- return 0;
- }
-
- nbp = 0;
-
- /*
- * at least one of the breakpoints were hit, check to see
- * which ones and if any of them are user space addresses
- */
-
- if (bp & 0x01) {
- addr[nbp++] = (caddr_t)rdr0();
- }
- if (bp & 0x02) {
- addr[nbp++] = (caddr_t)rdr1();
- }
- if (bp & 0x04) {
- addr[nbp++] = (caddr_t)rdr2();
- }
- if (bp & 0x08) {
- addr[nbp++] = (caddr_t)rdr3();
- }
-
- for (i = 0; i < nbp; i++) {
- if (addr[i] < (caddr_t)VM_MAXUSER_ADDRESS) {
- /*
- * addr[i] is in user space
- */
- return nbp;
- }
- }
-
- /*
- * None of the breakpoints are in user space.
- */
- return 0;
-}
-
/*
* The pcb_flags is only modified by current thread, or by other threads
* when current thread is stopped. However, current thread may change it
diff --git a/sys/amd64/amd64/ptrace_machdep.c b/sys/amd64/amd64/ptrace_machdep.c
--- a/sys/amd64/amd64/ptrace_machdep.c
+++ b/sys/amd64/amd64/ptrace_machdep.c
@@ -32,7 +32,9 @@
#include <sys/param.h>
#include <sys/systm.h>
+#include <sys/lock.h>
#include <sys/malloc.h>
+#include <sys/mutex.h>
#include <sys/proc.h>
#include <sys/ptrace.h>
#include <sys/sysent.h>
@@ -278,3 +280,34 @@
return (error);
}
+
+int
+ptrace_set_pc(struct thread *td, unsigned long addr)
+{
+
+ td->td_frame->tf_rip = addr;
+ set_pcb_flags(td->td_pcb, PCB_FULL_IRET);
+ return (0);
+}
+
+int
+ptrace_single_step(struct thread *td)
+{
+
+ PROC_LOCK_ASSERT(td->td_proc, MA_OWNED);
+ if ((td->td_frame->tf_rflags & PSL_T) == 0) {
+ td->td_frame->tf_rflags |= PSL_T;
+ td->td_dbgflags |= TDB_STEP;
+ }
+ return (0);
+}
+
+int
+ptrace_clear_single_step(struct thread *td)
+{
+
+ PROC_LOCK_ASSERT(td->td_proc, MA_OWNED);
+ td->td_frame->tf_rflags &= ~PSL_T;
+ td->td_dbgflags &= ~TDB_STEP;
+ return (0);
+}
diff --git a/sys/amd64/amd64/sig_machdep.c b/sys/amd64/amd64/sig_machdep.c
new file mode 100644
--- /dev/null
+++ b/sys/amd64/amd64/sig_machdep.c
@@ -0,0 +1,988 @@
+/*-
+ * SPDX-License-Identifier: BSD-4-Clause
+ *
+ * Copyright (c) 2003 Peter Wemm.
+ * Copyright (c) 1992 Terrence R. Lambert.
+ * Copyright (c) 1982, 1987, 1990 The Regents of the University of California.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * William Jolitz.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * from: @(#)machdep.c 7.4 (Berkeley) 6/3/91
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include "opt_cpu.h"
+#include "opt_ddb.h"
+#include "opt_kstack_pages.h"
+
+#include <sys/param.h>
+#include <sys/proc.h>
+#include <sys/systm.h>
+#include <sys/exec.h>
+#include <sys/imgact.h>
+#include <sys/kdb.h>
+#include <sys/kernel.h>
+#include <sys/ktr.h>
+#include <sys/linker.h>
+#include <sys/lock.h>
+#include <sys/malloc.h>
+#include <sys/mutex.h>
+#include <sys/pcpu.h>
+#include <sys/reg.h>
+#include <sys/rwlock.h>
+#include <sys/signalvar.h>
+#ifdef SMP
+#include <sys/smp.h>
+#endif
+#include <sys/syscallsubr.h>
+#include <sys/sysctl.h>
+#include <sys/sysent.h>
+#include <sys/sysproto.h>
+#include <sys/ucontext.h>
+#include <sys/vmmeter.h>
+
+#include <vm/vm.h>
+#include <vm/vm_param.h>
+#include <vm/vm_extern.h>
+#include <vm/pmap.h>
+
+#ifdef DDB
+#ifndef KDB
+#error KDB must be enabled in order for DDB to work!
+#endif
+#include <ddb/ddb.h>
+#include <ddb/db_sym.h>
+#endif
+
+#include <machine/vmparam.h>
+#include <machine/frame.h>
+#include <machine/md_var.h>
+#include <machine/pcb.h>
+#include <machine/proc.h>
+#include <machine/sigframe.h>
+#include <machine/specialreg.h>
+#include <machine/trap.h>
+
+#define CS_SECURE(cs) (ISPL(cs) == SEL_UPL)
+#define EFL_SECURE(ef, oef) ((((ef) ^ (oef)) & ~PSL_USERCHANGE) == 0)
+
+static void get_fpcontext(struct thread *td, mcontext_t *mcp,
+ char *xfpusave, size_t xfpusave_len);
+static int set_fpcontext(struct thread *td, mcontext_t *mcp,
+ char *xfpustate, size_t xfpustate_len);
+
+/*
+ * Send an interrupt to process.
+ *
+ * Stack is set up to allow sigcode stored
+ * at top to call routine, followed by call
+ * to sigreturn routine below. After sigreturn
+ * resets the signal mask, the stack, and the
+ * frame pointer, it returns to the user
+ * specified pc, psl.
+ */
+void
+sendsig(sig_t catcher, ksiginfo_t *ksi, sigset_t *mask)
+{
+ struct sigframe sf, *sfp;
+ struct pcb *pcb;
+ struct proc *p;
+ struct thread *td;
+ struct sigacts *psp;
+ char *sp;
+ struct trapframe *regs;
+ char *xfpusave;
+ size_t xfpusave_len;
+ int sig;
+ int oonstack;
+
+ td = curthread;
+ pcb = td->td_pcb;
+ p = td->td_proc;
+ PROC_LOCK_ASSERT(p, MA_OWNED);
+ sig = ksi->ksi_signo;
+ psp = p->p_sigacts;
+ mtx_assert(&psp->ps_mtx, MA_OWNED);
+ regs = td->td_frame;
+ oonstack = sigonstack(regs->tf_rsp);
+
+ if (cpu_max_ext_state_size > sizeof(struct savefpu) && use_xsave) {
+ xfpusave_len = cpu_max_ext_state_size - sizeof(struct savefpu);
+ xfpusave = (char *)td->td_md.md_fpu_scratch;
+ } else {
+ xfpusave_len = 0;
+ xfpusave = NULL;
+ }
+
+ /* Save user context. */
+ bzero(&sf, sizeof(sf));
+ sf.sf_uc.uc_sigmask = *mask;
+ sf.sf_uc.uc_stack = td->td_sigstk;
+ sf.sf_uc.uc_stack.ss_flags = (td->td_pflags & TDP_ALTSTACK)
+ ? ((oonstack) ? SS_ONSTACK : 0) : SS_DISABLE;
+ sf.sf_uc.uc_mcontext.mc_onstack = (oonstack) ? 1 : 0;
+ bcopy(regs, &sf.sf_uc.uc_mcontext.mc_rdi, sizeof(*regs));
+ sf.sf_uc.uc_mcontext.mc_len = sizeof(sf.sf_uc.uc_mcontext); /* magic */
+ get_fpcontext(td, &sf.sf_uc.uc_mcontext, xfpusave, xfpusave_len);
+ fpstate_drop(td);
+ update_pcb_bases(pcb);
+ sf.sf_uc.uc_mcontext.mc_fsbase = pcb->pcb_fsbase;
+ sf.sf_uc.uc_mcontext.mc_gsbase = pcb->pcb_gsbase;
+ bzero(sf.sf_uc.uc_mcontext.mc_spare,
+ sizeof(sf.sf_uc.uc_mcontext.mc_spare));
+
+ /* Allocate space for the signal handler context. */
+ if ((td->td_pflags & TDP_ALTSTACK) != 0 && !oonstack &&
+ SIGISMEMBER(psp->ps_sigonstack, sig)) {
+ sp = (char *)td->td_sigstk.ss_sp + td->td_sigstk.ss_size;
+#if defined(COMPAT_43)
+ td->td_sigstk.ss_flags |= SS_ONSTACK;
+#endif
+ } else
+ sp = (char *)regs->tf_rsp - 128;
+ if (xfpusave != NULL) {
+ sp -= xfpusave_len;
+ sp = (char *)((unsigned long)sp & ~0x3Ful);
+ sf.sf_uc.uc_mcontext.mc_xfpustate = (register_t)sp;
+ }
+ sp -= sizeof(struct sigframe);
+ /* Align to 16 bytes. */
+ sfp = (struct sigframe *)((unsigned long)sp & ~0xFul);
+
+ /* Build the argument list for the signal handler. */
+ regs->tf_rdi = sig; /* arg 1 in %rdi */
+ regs->tf_rdx = (register_t)&sfp->sf_uc; /* arg 3 in %rdx */
+ bzero(&sf.sf_si, sizeof(sf.sf_si));
+ if (SIGISMEMBER(psp->ps_siginfo, sig)) {
+ /* Signal handler installed with SA_SIGINFO. */
+ regs->tf_rsi = (register_t)&sfp->sf_si; /* arg 2 in %rsi */
+ sf.sf_ahu.sf_action = (__siginfohandler_t *)catcher;
+
+ /* Fill in POSIX parts */
+ sf.sf_si = ksi->ksi_info;
+ sf.sf_si.si_signo = sig; /* maybe a translated signal */
+ regs->tf_rcx = (register_t)ksi->ksi_addr; /* arg 4 in %rcx */
+ } else {
+ /* Old FreeBSD-style arguments. */
+ regs->tf_rsi = ksi->ksi_code; /* arg 2 in %rsi */
+ regs->tf_rcx = (register_t)ksi->ksi_addr; /* arg 4 in %rcx */
+ sf.sf_ahu.sf_handler = catcher;
+ }
+ mtx_unlock(&psp->ps_mtx);
+ PROC_UNLOCK(p);
+
+ /*
+ * Copy the sigframe out to the user's stack.
+ */
+ if (copyout(&sf, sfp, sizeof(*sfp)) != 0 ||
+ (xfpusave != NULL && copyout(xfpusave,
+ (void *)sf.sf_uc.uc_mcontext.mc_xfpustate, xfpusave_len)
+ != 0)) {
+#ifdef DEBUG
+ printf("process %ld has trashed its stack\n", (long)p->p_pid);
+#endif
+ PROC_LOCK(p);
+ sigexit(td, SIGILL);
+ }
+
+ regs->tf_rsp = (long)sfp;
+ regs->tf_rip = p->p_sysent->sv_sigcode_base;
+ regs->tf_rflags &= ~(PSL_T | PSL_D);
+ regs->tf_cs = _ucodesel;
+ regs->tf_ds = _udatasel;
+ regs->tf_ss = _udatasel;
+ regs->tf_es = _udatasel;
+ regs->tf_fs = _ufssel;
+ regs->tf_gs = _ugssel;
+ regs->tf_flags = TF_HASSEGS;
+ PROC_LOCK(p);
+ mtx_lock(&psp->ps_mtx);
+}
+
+/*
+ * System call to cleanup state after a signal
+ * has been taken. Reset signal mask and
+ * stack state from context left by sendsig (above).
+ * Return to previous pc and psl as specified by
+ * context left by sendsig. Check carefully to
+ * make sure that the user has not modified the
+ * state to gain improper privileges.
+ */
+int
+sys_sigreturn(struct thread *td, struct sigreturn_args *uap)
+{
+ ucontext_t uc;
+ struct pcb *pcb;
+ struct proc *p;
+ struct trapframe *regs;
+ ucontext_t *ucp;
+ char *xfpustate;
+ size_t xfpustate_len;
+ long rflags;
+ int cs, error, ret;
+ ksiginfo_t ksi;
+
+ pcb = td->td_pcb;
+ p = td->td_proc;
+
+ error = copyin(uap->sigcntxp, &uc, sizeof(uc));
+ if (error != 0) {
+ uprintf("pid %d (%s): sigreturn copyin failed\n",
+ p->p_pid, td->td_name);
+ return (error);
+ }
+ ucp = &uc;
+ if ((ucp->uc_mcontext.mc_flags & ~_MC_FLAG_MASK) != 0) {
+ uprintf("pid %d (%s): sigreturn mc_flags %x\n", p->p_pid,
+ td->td_name, ucp->uc_mcontext.mc_flags);
+ return (EINVAL);
+ }
+ regs = td->td_frame;
+ rflags = ucp->uc_mcontext.mc_rflags;
+ /*
+ * Don't allow users to change privileged or reserved flags.
+ */
+ if (!EFL_SECURE(rflags, regs->tf_rflags)) {
+ uprintf("pid %d (%s): sigreturn rflags = 0x%lx\n", p->p_pid,
+ td->td_name, rflags);
+ return (EINVAL);
+ }
+
+ /*
+ * Don't allow users to load a valid privileged %cs. Let the
+ * hardware check for invalid selectors, excess privilege in
+ * other selectors, invalid %eip's and invalid %esp's.
+ */
+ cs = ucp->uc_mcontext.mc_cs;
+ if (!CS_SECURE(cs)) {
+ uprintf("pid %d (%s): sigreturn cs = 0x%x\n", p->p_pid,
+ td->td_name, cs);
+ ksiginfo_init_trap(&ksi);
+ ksi.ksi_signo = SIGBUS;
+ ksi.ksi_code = BUS_OBJERR;
+ ksi.ksi_trapno = T_PROTFLT;
+ ksi.ksi_addr = (void *)regs->tf_rip;
+ trapsignal(td, &ksi);
+ return (EINVAL);
+ }
+
+ if ((uc.uc_mcontext.mc_flags & _MC_HASFPXSTATE) != 0) {
+ xfpustate_len = uc.uc_mcontext.mc_xfpustate_len;
+ if (xfpustate_len > cpu_max_ext_state_size -
+ sizeof(struct savefpu)) {
+ uprintf("pid %d (%s): sigreturn xfpusave_len = 0x%zx\n",
+ p->p_pid, td->td_name, xfpustate_len);
+ return (EINVAL);
+ }
+ xfpustate = __builtin_alloca(xfpustate_len);
+ error = copyin((const void *)uc.uc_mcontext.mc_xfpustate,
+ xfpustate, xfpustate_len);
+ if (error != 0) {
+ uprintf(
+ "pid %d (%s): sigreturn copying xfpustate failed\n",
+ p->p_pid, td->td_name);
+ return (error);
+ }
+ } else {
+ xfpustate = NULL;
+ xfpustate_len = 0;
+ }
+ ret = set_fpcontext(td, &ucp->uc_mcontext, xfpustate, xfpustate_len);
+ if (ret != 0) {
+ uprintf("pid %d (%s): sigreturn set_fpcontext err %d\n",
+ p->p_pid, td->td_name, ret);
+ return (ret);
+ }
+ bcopy(&ucp->uc_mcontext.mc_rdi, regs, sizeof(*regs));
+ update_pcb_bases(pcb);
+ pcb->pcb_fsbase = ucp->uc_mcontext.mc_fsbase;
+ pcb->pcb_gsbase = ucp->uc_mcontext.mc_gsbase;
+
+#if defined(COMPAT_43)
+ if (ucp->uc_mcontext.mc_onstack & 1)
+ td->td_sigstk.ss_flags |= SS_ONSTACK;
+ else
+ td->td_sigstk.ss_flags &= ~SS_ONSTACK;
+#endif
+
+ kern_sigprocmask(td, SIG_SETMASK, &ucp->uc_sigmask, NULL, 0);
+ return (EJUSTRETURN);
+}
+
+#ifdef COMPAT_FREEBSD4
+int
+freebsd4_sigreturn(struct thread *td, struct freebsd4_sigreturn_args *uap)
+{
+
+ return sys_sigreturn(td, (struct sigreturn_args *)uap);
+}
+#endif
+
+/*
+ * Reset the hardware debug registers if they were in use.
+ * They won't have any meaning for the newly exec'd process.
+ */
+void
+x86_clear_dbregs(struct pcb *pcb)
+{
+ if ((pcb->pcb_flags & PCB_DBREGS) == 0)
+ return;
+
+ pcb->pcb_dr0 = 0;
+ pcb->pcb_dr1 = 0;
+ pcb->pcb_dr2 = 0;
+ pcb->pcb_dr3 = 0;
+ pcb->pcb_dr6 = 0;
+ pcb->pcb_dr7 = 0;
+
+ if (pcb == curpcb) {
+ /*
+ * Clear the debug registers on the running CPU,
+ * otherwise they will end up affecting the next
+ * process we switch to.
+ */
+ reset_dbregs();
+ }
+ clear_pcb_flags(pcb, PCB_DBREGS);
+}
+
+/*
+ * Reset registers to default values on exec.
+ */
+void
+exec_setregs(struct thread *td, struct image_params *imgp, uintptr_t stack)
+{
+ struct trapframe *regs;
+ struct pcb *pcb;
+ register_t saved_rflags;
+
+ regs = td->td_frame;
+ pcb = td->td_pcb;
+
+ if (td->td_proc->p_md.md_ldt != NULL)
+ user_ldt_free(td);
+
+ update_pcb_bases(pcb);
+ pcb->pcb_fsbase = 0;
+ pcb->pcb_gsbase = 0;
+ clear_pcb_flags(pcb, PCB_32BIT);
+ pcb->pcb_initial_fpucw = __INITIAL_FPUCW__;
+
+ saved_rflags = regs->tf_rflags & PSL_T;
+ bzero((char *)regs, sizeof(struct trapframe));
+ regs->tf_rip = imgp->entry_addr;
+ regs->tf_rsp = ((stack - 8) & ~0xFul) + 8;
+ regs->tf_rdi = stack; /* argv */
+ regs->tf_rflags = PSL_USER | saved_rflags;
+ regs->tf_ss = _udatasel;
+ regs->tf_cs = _ucodesel;
+ regs->tf_ds = _udatasel;
+ regs->tf_es = _udatasel;
+ regs->tf_fs = _ufssel;
+ regs->tf_gs = _ugssel;
+ regs->tf_flags = TF_HASSEGS;
+
+ x86_clear_dbregs(pcb);
+
+ /*
+ * Drop the FP state if we hold it, so that the process gets a
+ * clean FP state if it uses the FPU again.
+ */
+ fpstate_drop(td);
+}
+
+int
+fill_regs(struct thread *td, struct reg *regs)
+{
+ struct trapframe *tp;
+
+ tp = td->td_frame;
+ return (fill_frame_regs(tp, regs));
+}
+
+int
+fill_frame_regs(struct trapframe *tp, struct reg *regs)
+{
+
+ regs->r_r15 = tp->tf_r15;
+ regs->r_r14 = tp->tf_r14;
+ regs->r_r13 = tp->tf_r13;
+ regs->r_r12 = tp->tf_r12;
+ regs->r_r11 = tp->tf_r11;
+ regs->r_r10 = tp->tf_r10;
+ regs->r_r9 = tp->tf_r9;
+ regs->r_r8 = tp->tf_r8;
+ regs->r_rdi = tp->tf_rdi;
+ regs->r_rsi = tp->tf_rsi;
+ regs->r_rbp = tp->tf_rbp;
+ regs->r_rbx = tp->tf_rbx;
+ regs->r_rdx = tp->tf_rdx;
+ regs->r_rcx = tp->tf_rcx;
+ regs->r_rax = tp->tf_rax;
+ regs->r_rip = tp->tf_rip;
+ regs->r_cs = tp->tf_cs;
+ regs->r_rflags = tp->tf_rflags;
+ regs->r_rsp = tp->tf_rsp;
+ regs->r_ss = tp->tf_ss;
+ if (tp->tf_flags & TF_HASSEGS) {
+ regs->r_ds = tp->tf_ds;
+ regs->r_es = tp->tf_es;
+ regs->r_fs = tp->tf_fs;
+ regs->r_gs = tp->tf_gs;
+ } else {
+ regs->r_ds = 0;
+ regs->r_es = 0;
+ regs->r_fs = 0;
+ regs->r_gs = 0;
+ }
+ regs->r_err = 0;
+ regs->r_trapno = 0;
+ return (0);
+}
+
+int
+set_regs(struct thread *td, struct reg *regs)
+{
+ struct trapframe *tp;
+ register_t rflags;
+
+ tp = td->td_frame;
+ rflags = regs->r_rflags & 0xffffffff;
+ if (!EFL_SECURE(rflags, tp->tf_rflags) || !CS_SECURE(regs->r_cs))
+ return (EINVAL);
+ tp->tf_r15 = regs->r_r15;
+ tp->tf_r14 = regs->r_r14;
+ tp->tf_r13 = regs->r_r13;
+ tp->tf_r12 = regs->r_r12;
+ tp->tf_r11 = regs->r_r11;
+ tp->tf_r10 = regs->r_r10;
+ tp->tf_r9 = regs->r_r9;
+ tp->tf_r8 = regs->r_r8;
+ tp->tf_rdi = regs->r_rdi;
+ tp->tf_rsi = regs->r_rsi;
+ tp->tf_rbp = regs->r_rbp;
+ tp->tf_rbx = regs->r_rbx;
+ tp->tf_rdx = regs->r_rdx;
+ tp->tf_rcx = regs->r_rcx;
+ tp->tf_rax = regs->r_rax;
+ tp->tf_rip = regs->r_rip;
+ tp->tf_cs = regs->r_cs;
+ tp->tf_rflags = rflags;
+ tp->tf_rsp = regs->r_rsp;
+ tp->tf_ss = regs->r_ss;
+ if (0) { /* XXXKIB */
+ tp->tf_ds = regs->r_ds;
+ tp->tf_es = regs->r_es;
+ tp->tf_fs = regs->r_fs;
+ tp->tf_gs = regs->r_gs;
+ tp->tf_flags = TF_HASSEGS;
+ }
+ set_pcb_flags(td->td_pcb, PCB_FULL_IRET);
+ return (0);
+}
+
+/* XXX check all this stuff! */
+/* externalize from sv_xmm */
+static void
+fill_fpregs_xmm(struct savefpu *sv_xmm, struct fpreg *fpregs)
+{
+ struct envxmm *penv_fpreg = (struct envxmm *)&fpregs->fpr_env;
+ struct envxmm *penv_xmm = &sv_xmm->sv_env;
+ int i;
+
+ /* pcb -> fpregs */
+ bzero(fpregs, sizeof(*fpregs));
+
+ /* FPU control/status */
+ penv_fpreg->en_cw = penv_xmm->en_cw;
+ penv_fpreg->en_sw = penv_xmm->en_sw;
+ penv_fpreg->en_tw = penv_xmm->en_tw;
+ penv_fpreg->en_opcode = penv_xmm->en_opcode;
+ penv_fpreg->en_rip = penv_xmm->en_rip;
+ penv_fpreg->en_rdp = penv_xmm->en_rdp;
+ penv_fpreg->en_mxcsr = penv_xmm->en_mxcsr;
+ penv_fpreg->en_mxcsr_mask = penv_xmm->en_mxcsr_mask;
+
+ /* FPU registers */
+ for (i = 0; i < 8; ++i)
+ bcopy(sv_xmm->sv_fp[i].fp_acc.fp_bytes, fpregs->fpr_acc[i], 10);
+
+ /* SSE registers */
+ for (i = 0; i < 16; ++i)
+ bcopy(sv_xmm->sv_xmm[i].xmm_bytes, fpregs->fpr_xacc[i], 16);
+}
+
+/* internalize from fpregs into sv_xmm */
+static void
+set_fpregs_xmm(struct fpreg *fpregs, struct savefpu *sv_xmm)
+{
+ struct envxmm *penv_xmm = &sv_xmm->sv_env;
+ struct envxmm *penv_fpreg = (struct envxmm *)&fpregs->fpr_env;
+ int i;
+
+ /* fpregs -> pcb */
+ /* FPU control/status */
+ penv_xmm->en_cw = penv_fpreg->en_cw;
+ penv_xmm->en_sw = penv_fpreg->en_sw;
+ penv_xmm->en_tw = penv_fpreg->en_tw;
+ penv_xmm->en_opcode = penv_fpreg->en_opcode;
+ penv_xmm->en_rip = penv_fpreg->en_rip;
+ penv_xmm->en_rdp = penv_fpreg->en_rdp;
+ penv_xmm->en_mxcsr = penv_fpreg->en_mxcsr;
+ penv_xmm->en_mxcsr_mask = penv_fpreg->en_mxcsr_mask & cpu_mxcsr_mask;
+
+ /* FPU registers */
+ for (i = 0; i < 8; ++i)
+ bcopy(fpregs->fpr_acc[i], sv_xmm->sv_fp[i].fp_acc.fp_bytes, 10);
+
+ /* SSE registers */
+ for (i = 0; i < 16; ++i)
+ bcopy(fpregs->fpr_xacc[i], sv_xmm->sv_xmm[i].xmm_bytes, 16);
+}
+
+/* externalize from td->pcb */
+int
+fill_fpregs(struct thread *td, struct fpreg *fpregs)
+{
+
+ KASSERT(td == curthread || TD_IS_SUSPENDED(td) ||
+ P_SHOULDSTOP(td->td_proc),
+ ("not suspended thread %p", td));
+ fpugetregs(td);
+ fill_fpregs_xmm(get_pcb_user_save_td(td), fpregs);
+ return (0);
+}
+
+/* internalize to td->pcb */
+int
+set_fpregs(struct thread *td, struct fpreg *fpregs)
+{
+
+ critical_enter();
+ set_fpregs_xmm(fpregs, get_pcb_user_save_td(td));
+ fpuuserinited(td);
+ critical_exit();
+ return (0);
+}
+
+/*
+ * Get machine context.
+ */
+int
+get_mcontext(struct thread *td, mcontext_t *mcp, int flags)
+{
+ struct pcb *pcb;
+ struct trapframe *tp;
+
+ pcb = td->td_pcb;
+ tp = td->td_frame;
+ PROC_LOCK(curthread->td_proc);
+ mcp->mc_onstack = sigonstack(tp->tf_rsp);
+ PROC_UNLOCK(curthread->td_proc);
+ mcp->mc_r15 = tp->tf_r15;
+ mcp->mc_r14 = tp->tf_r14;
+ mcp->mc_r13 = tp->tf_r13;
+ mcp->mc_r12 = tp->tf_r12;
+ mcp->mc_r11 = tp->tf_r11;
+ mcp->mc_r10 = tp->tf_r10;
+ mcp->mc_r9 = tp->tf_r9;
+ mcp->mc_r8 = tp->tf_r8;
+ mcp->mc_rdi = tp->tf_rdi;
+ mcp->mc_rsi = tp->tf_rsi;
+ mcp->mc_rbp = tp->tf_rbp;
+ mcp->mc_rbx = tp->tf_rbx;
+ mcp->mc_rcx = tp->tf_rcx;
+ mcp->mc_rflags = tp->tf_rflags;
+ if (flags & GET_MC_CLEAR_RET) {
+ mcp->mc_rax = 0;
+ mcp->mc_rdx = 0;
+ mcp->mc_rflags &= ~PSL_C;
+ } else {
+ mcp->mc_rax = tp->tf_rax;
+ mcp->mc_rdx = tp->tf_rdx;
+ }
+ mcp->mc_rip = tp->tf_rip;
+ mcp->mc_cs = tp->tf_cs;
+ mcp->mc_rsp = tp->tf_rsp;
+ mcp->mc_ss = tp->tf_ss;
+ mcp->mc_ds = tp->tf_ds;
+ mcp->mc_es = tp->tf_es;
+ mcp->mc_fs = tp->tf_fs;
+ mcp->mc_gs = tp->tf_gs;
+ mcp->mc_flags = tp->tf_flags;
+ mcp->mc_len = sizeof(*mcp);
+ get_fpcontext(td, mcp, NULL, 0);
+ update_pcb_bases(pcb);
+ mcp->mc_fsbase = pcb->pcb_fsbase;
+ mcp->mc_gsbase = pcb->pcb_gsbase;
+ mcp->mc_xfpustate = 0;
+ mcp->mc_xfpustate_len = 0;
+ bzero(mcp->mc_spare, sizeof(mcp->mc_spare));
+ return (0);
+}
+
+/*
+ * Set machine context.
+ *
+ * However, we don't set any but the user modifiable flags, and we won't
+ * touch the cs selector.
+ */
+int
+set_mcontext(struct thread *td, mcontext_t *mcp)
+{
+ struct pcb *pcb;
+ struct trapframe *tp;
+ char *xfpustate;
+ long rflags;
+ int ret;
+
+ pcb = td->td_pcb;
+ tp = td->td_frame;
+ if (mcp->mc_len != sizeof(*mcp) ||
+ (mcp->mc_flags & ~_MC_FLAG_MASK) != 0)
+ return (EINVAL);
+ rflags = (mcp->mc_rflags & PSL_USERCHANGE) |
+ (tp->tf_rflags & ~PSL_USERCHANGE);
+ if (mcp->mc_flags & _MC_HASFPXSTATE) {
+ if (mcp->mc_xfpustate_len > cpu_max_ext_state_size -
+ sizeof(struct savefpu))
+ return (EINVAL);
+ xfpustate = (char *)td->td_md.md_fpu_scratch;
+ ret = copyin((void *)mcp->mc_xfpustate, xfpustate,
+ mcp->mc_xfpustate_len);
+ if (ret != 0)
+ return (ret);
+ } else
+ xfpustate = NULL;
+ ret = set_fpcontext(td, mcp, xfpustate, mcp->mc_xfpustate_len);
+ if (ret != 0)
+ return (ret);
+ tp->tf_r15 = mcp->mc_r15;
+ tp->tf_r14 = mcp->mc_r14;
+ tp->tf_r13 = mcp->mc_r13;
+ tp->tf_r12 = mcp->mc_r12;
+ tp->tf_r11 = mcp->mc_r11;
+ tp->tf_r10 = mcp->mc_r10;
+ tp->tf_r9 = mcp->mc_r9;
+ tp->tf_r8 = mcp->mc_r8;
+ tp->tf_rdi = mcp->mc_rdi;
+ tp->tf_rsi = mcp->mc_rsi;
+ tp->tf_rbp = mcp->mc_rbp;
+ tp->tf_rbx = mcp->mc_rbx;
+ tp->tf_rdx = mcp->mc_rdx;
+ tp->tf_rcx = mcp->mc_rcx;
+ tp->tf_rax = mcp->mc_rax;
+ tp->tf_rip = mcp->mc_rip;
+ tp->tf_rflags = rflags;
+ tp->tf_rsp = mcp->mc_rsp;
+ tp->tf_ss = mcp->mc_ss;
+ tp->tf_flags = mcp->mc_flags;
+ if (tp->tf_flags & TF_HASSEGS) {
+ tp->tf_ds = mcp->mc_ds;
+ tp->tf_es = mcp->mc_es;
+ tp->tf_fs = mcp->mc_fs;
+ tp->tf_gs = mcp->mc_gs;
+ }
+ set_pcb_flags(pcb, PCB_FULL_IRET);
+ if (mcp->mc_flags & _MC_HASBASES) {
+ pcb->pcb_fsbase = mcp->mc_fsbase;
+ pcb->pcb_gsbase = mcp->mc_gsbase;
+ }
+ return (0);
+}
+
+static void
+get_fpcontext(struct thread *td, mcontext_t *mcp, char *xfpusave,
+ size_t xfpusave_len)
+{
+ size_t max_len, len;
+
+ mcp->mc_ownedfp = fpugetregs(td);
+ bcopy(get_pcb_user_save_td(td), &mcp->mc_fpstate[0],
+ sizeof(mcp->mc_fpstate));
+ mcp->mc_fpformat = fpuformat();
+ if (!use_xsave || xfpusave_len == 0)
+ return;
+ max_len = cpu_max_ext_state_size - sizeof(struct savefpu);
+ len = xfpusave_len;
+ if (len > max_len) {
+ len = max_len;
+ bzero(xfpusave + max_len, len - max_len);
+ }
+ mcp->mc_flags |= _MC_HASFPXSTATE;
+ mcp->mc_xfpustate_len = len;
+ bcopy(get_pcb_user_save_td(td) + 1, xfpusave, len);
+}
+
+static int
+set_fpcontext(struct thread *td, mcontext_t *mcp, char *xfpustate,
+ size_t xfpustate_len)
+{
+ int error;
+
+ if (mcp->mc_fpformat == _MC_FPFMT_NODEV)
+ return (0);
+ else if (mcp->mc_fpformat != _MC_FPFMT_XMM)
+ return (EINVAL);
+ else if (mcp->mc_ownedfp == _MC_FPOWNED_NONE) {
+ /* We don't care what state is left in the FPU or PCB. */
+ fpstate_drop(td);
+ error = 0;
+ } else if (mcp->mc_ownedfp == _MC_FPOWNED_FPU ||
+ mcp->mc_ownedfp == _MC_FPOWNED_PCB) {
+ error = fpusetregs(td, (struct savefpu *)&mcp->mc_fpstate,
+ xfpustate, xfpustate_len);
+ } else
+ return (EINVAL);
+ return (error);
+}
+
+void
+fpstate_drop(struct thread *td)
+{
+
+ KASSERT(PCB_USER_FPU(td->td_pcb), ("fpstate_drop: kernel-owned fpu"));
+ critical_enter();
+ if (PCPU_GET(fpcurthread) == td)
+ fpudrop();
+ /*
+ * XXX force a full drop of the fpu. The above only drops it if we
+ * owned it.
+ *
+ * XXX I don't much like fpugetuserregs()'s semantics of doing a full
+ * drop. Dropping only to the pcb matches fnsave's behaviour.
+ * We only need to drop to !PCB_INITDONE in sendsig(). But
+ * sendsig() is the only caller of fpugetuserregs()... perhaps we just
+ * have too many layers.
+ */
+ clear_pcb_flags(curthread->td_pcb,
+ PCB_FPUINITDONE | PCB_USERFPUINITDONE);
+ critical_exit();
+}
+
+int
+fill_dbregs(struct thread *td, struct dbreg *dbregs)
+{
+ struct pcb *pcb;
+
+ if (td == NULL) {
+ dbregs->dr[0] = rdr0();
+ dbregs->dr[1] = rdr1();
+ dbregs->dr[2] = rdr2();
+ dbregs->dr[3] = rdr3();
+ dbregs->dr[6] = rdr6();
+ dbregs->dr[7] = rdr7();
+ } else {
+ pcb = td->td_pcb;
+ dbregs->dr[0] = pcb->pcb_dr0;
+ dbregs->dr[1] = pcb->pcb_dr1;
+ dbregs->dr[2] = pcb->pcb_dr2;
+ dbregs->dr[3] = pcb->pcb_dr3;
+ dbregs->dr[6] = pcb->pcb_dr6;
+ dbregs->dr[7] = pcb->pcb_dr7;
+ }
+ dbregs->dr[4] = 0;
+ dbregs->dr[5] = 0;
+ dbregs->dr[8] = 0;
+ dbregs->dr[9] = 0;
+ dbregs->dr[10] = 0;
+ dbregs->dr[11] = 0;
+ dbregs->dr[12] = 0;
+ dbregs->dr[13] = 0;
+ dbregs->dr[14] = 0;
+ dbregs->dr[15] = 0;
+ return (0);
+}
+
+int
+set_dbregs(struct thread *td, struct dbreg *dbregs)
+{
+ struct pcb *pcb;
+ int i;
+
+ if (td == NULL) {
+ load_dr0(dbregs->dr[0]);
+ load_dr1(dbregs->dr[1]);
+ load_dr2(dbregs->dr[2]);
+ load_dr3(dbregs->dr[3]);
+ load_dr6(dbregs->dr[6]);
+ load_dr7(dbregs->dr[7]);
+ } else {
+ /*
+ * Don't let an illegal value for dr7 get set. Specifically,
+ * check for undefined settings. Setting these bit patterns
+ * result in undefined behaviour and can lead to an unexpected
+ * TRCTRAP or a general protection fault right here.
+ * Upper bits of dr6 and dr7 must not be set
+ */
+ for (i = 0; i < 4; i++) {
+ if (DBREG_DR7_ACCESS(dbregs->dr[7], i) == 0x02)
+ return (EINVAL);
+ if (td->td_frame->tf_cs == _ucode32sel &&
+ DBREG_DR7_LEN(dbregs->dr[7], i) == DBREG_DR7_LEN_8)
+ return (EINVAL);
+ }
+ if ((dbregs->dr[6] & 0xffffffff00000000ul) != 0 ||
+ (dbregs->dr[7] & 0xffffffff00000000ul) != 0)
+ return (EINVAL);
+
+ pcb = td->td_pcb;
+
+ /*
+ * Don't let a process set a breakpoint that is not within the
+ * process's address space. If a process could do this, it
+ * could halt the system by setting a breakpoint in the kernel
+ * (if ddb was enabled). Thus, we need to check to make sure
+ * that no breakpoints are being enabled for addresses outside
+ * process's address space.
+ *
+ * XXX - what about when the watched area of the user's
+ * address space is written into from within the kernel
+ * ... wouldn't that still cause a breakpoint to be generated
+ * from within kernel mode?
+ */
+
+ if (DBREG_DR7_ENABLED(dbregs->dr[7], 0)) {
+ /* dr0 is enabled */
+ if (dbregs->dr[0] >= VM_MAXUSER_ADDRESS)
+ return (EINVAL);
+ }
+ if (DBREG_DR7_ENABLED(dbregs->dr[7], 1)) {
+ /* dr1 is enabled */
+ if (dbregs->dr[1] >= VM_MAXUSER_ADDRESS)
+ return (EINVAL);
+ }
+ if (DBREG_DR7_ENABLED(dbregs->dr[7], 2)) {
+ /* dr2 is enabled */
+ if (dbregs->dr[2] >= VM_MAXUSER_ADDRESS)
+ return (EINVAL);
+ }
+ if (DBREG_DR7_ENABLED(dbregs->dr[7], 3)) {
+ /* dr3 is enabled */
+ if (dbregs->dr[3] >= VM_MAXUSER_ADDRESS)
+ return (EINVAL);
+ }
+
+ pcb->pcb_dr0 = dbregs->dr[0];
+ pcb->pcb_dr1 = dbregs->dr[1];
+ pcb->pcb_dr2 = dbregs->dr[2];
+ pcb->pcb_dr3 = dbregs->dr[3];
+ pcb->pcb_dr6 = dbregs->dr[6];
+ pcb->pcb_dr7 = dbregs->dr[7];
+
+ set_pcb_flags(pcb, PCB_DBREGS);
+ }
+
+ return (0);
+}
+
+void
+reset_dbregs(void)
+{
+
+ load_dr7(0); /* Turn off the control bits first */
+ load_dr0(0);
+ load_dr1(0);
+ load_dr2(0);
+ load_dr3(0);
+ load_dr6(0);
+}
+
+/*
+ * Return > 0 if a hardware breakpoint has been hit, and the
+ * breakpoint was in user space. Return 0, otherwise.
+ */
+int
+user_dbreg_trap(register_t dr6)
+{
+ u_int64_t dr7;
+ u_int64_t bp; /* breakpoint bits extracted from dr6 */
+ int nbp; /* number of breakpoints that triggered */
+ caddr_t addr[4]; /* breakpoint addresses */
+ int i;
+
+ bp = dr6 & DBREG_DR6_BMASK;
+ if (bp == 0) {
+ /*
+ * None of the breakpoint bits are set meaning this
+ * trap was not caused by any of the debug registers
+ */
+ return (0);
+ }
+
+ dr7 = rdr7();
+ if ((dr7 & 0x000000ff) == 0) {
+ /*
+ * all GE and LE bits in the dr7 register are zero,
+ * thus the trap couldn't have been caused by the
+ * hardware debug registers
+ */
+ return (0);
+ }
+
+ nbp = 0;
+
+ /*
+ * at least one of the breakpoints were hit, check to see
+ * which ones and if any of them are user space addresses
+ */
+
+ if (bp & 0x01) {
+ addr[nbp++] = (caddr_t)rdr0();
+ }
+ if (bp & 0x02) {
+ addr[nbp++] = (caddr_t)rdr1();
+ }
+ if (bp & 0x04) {
+ addr[nbp++] = (caddr_t)rdr2();
+ }
+ if (bp & 0x08) {
+ addr[nbp++] = (caddr_t)rdr3();
+ }
+
+ for (i = 0; i < nbp; i++) {
+ if (addr[i] < (caddr_t)VM_MAXUSER_ADDRESS) {
+ /*
+ * addr[i] is in user space
+ */
+ return (nbp);
+ }
+ }
+
+ /*
+ * None of the breakpoints are in user space.
+ */
+ return (0);
+}
diff --git a/sys/amd64/amd64/vm_machdep.c b/sys/amd64/amd64/vm_machdep.c
--- a/sys/amd64/amd64/vm_machdep.c
+++ b/sys/amd64/amd64/vm_machdep.c
@@ -90,19 +90,17 @@
set_top_of_stack_td(struct thread *td)
{
td->td_md.md_stack_base = td->td_kstack +
- td->td_kstack_pages * PAGE_SIZE -
- roundup2(cpu_max_ext_state_size, XSAVE_AREA_ALIGN);
+ td->td_kstack_pages * PAGE_SIZE;
}
struct savefpu *
get_pcb_user_save_td(struct thread *td)
{
- vm_offset_t p;
-
- p = td->td_md.md_stack_base;
- KASSERT((p % XSAVE_AREA_ALIGN) == 0,
- ("Unaligned pcb_user_save area ptr %#lx td %p", p, td));
- return ((struct savefpu *)p);
+ KASSERT(((vm_offset_t)td->td_md.md_usr_fpu_save %
+ XSAVE_AREA_ALIGN) == 0,
+ ("Unaligned pcb_user_save area ptr %p td %p",
+ td->td_md.md_usr_fpu_save, td));
+ return (td->td_md.md_usr_fpu_save);
}
struct pcb *
@@ -393,6 +391,8 @@
set_top_of_stack_td(td);
td->td_pcb = pcb = get_pcb_td(td);
td->td_frame = (struct trapframe *)td->td_md.md_stack_base - 1;
+ td->td_md.md_usr_fpu_save = fpu_save_area_alloc();
+ td->td_md.md_fpu_scratch = fpu_save_area_alloc();
pcb->pcb_save = get_pcb_user_save_pcb(pcb);
if (use_xsave) {
xhdr = (struct xstate_hdr *)(pcb->pcb_save + 1);
@@ -404,8 +404,12 @@
void
cpu_thread_free(struct thread *td)
{
-
cpu_thread_clean(td);
+
+ fpu_save_area_free(td->td_md.md_usr_fpu_save);
+ td->td_md.md_usr_fpu_save = NULL;
+ fpu_save_area_free(td->td_md.md_fpu_scratch);
+ td->td_md.md_fpu_scratch = NULL;
}
bool
diff --git a/sys/amd64/ia32/ia32_reg.c b/sys/amd64/ia32/ia32_reg.c
--- a/sys/amd64/ia32/ia32_reg.c
+++ b/sys/amd64/ia32/ia32_reg.c
@@ -73,9 +73,6 @@
#include <machine/pcb.h>
#include <machine/cpufunc.h>
-#define CS_SECURE(cs) (ISPL(cs) == SEL_UPL)
-#define EFL_SECURE(ef, oef) ((((ef) ^ (oef)) & ~PSL_USERCHANGE) == 0)
-
int
fill_regs32(struct thread *td, struct reg32 *regs)
{
diff --git a/sys/amd64/ia32/ia32_signal.c b/sys/amd64/ia32/ia32_signal.c
--- a/sys/amd64/ia32/ia32_signal.c
+++ b/sys/amd64/ia32/ia32_signal.c
@@ -85,9 +85,6 @@
static void freebsd4_ia32_sendsig(sig_t, ksiginfo_t *, sigset_t *);
#endif
-#define CS_SECURE(cs) (ISPL(cs) == SEL_UPL)
-#define EFL_SECURE(ef, oef) ((((ef) ^ (oef)) & ~PSL_USERCHANGE) == 0)
-
static void
ia32_get_fpcontext(struct thread *td, struct ia32_mcontext *mcp,
char *xfpusave, size_t xfpusave_len)
diff --git a/sys/amd64/include/frame.h b/sys/amd64/include/frame.h
--- a/sys/amd64/include/frame.h
+++ b/sys/amd64/include/frame.h
@@ -46,4 +46,9 @@
register_t pti_ss;
};
+#ifdef _KERNEL
+#define CS_SECURE(cs) (ISPL(cs) == SEL_UPL)
+#define EFL_SECURE(ef, oef) ((((ef) ^ (oef)) & ~PSL_USERCHANGE) == 0)
+#endif
+
#endif
diff --git a/sys/amd64/include/proc.h b/sys/amd64/include/proc.h
--- a/sys/amd64/include/proc.h
+++ b/sys/amd64/include/proc.h
@@ -75,6 +75,8 @@
int md_efirt_dis_pf; /* (k) */
struct pcb md_pcb;
vm_offset_t md_stack_base;
+ struct savefpu *md_usr_fpu_save;
+ struct savefpu *md_fpu_scratch;
};
struct mdproc {
diff --git a/sys/conf/files.amd64 b/sys/conf/files.amd64
--- a/sys/conf/files.amd64
+++ b/sys/conf/files.amd64
@@ -99,6 +99,7 @@
amd64/amd64/mpboot.S optional smp
amd64/amd64/pmap.c standard
amd64/amd64/ptrace_machdep.c standard
+amd64/amd64/sig_machdep.c standard
amd64/amd64/sigtramp.S standard
amd64/amd64/support.S standard
amd64/amd64/sys_machdep.c standard
diff --git a/sys/kern/kern_thread.c b/sys/kern/kern_thread.c
--- a/sys/kern/kern_thread.c
+++ b/sys/kern/kern_thread.c
@@ -91,7 +91,7 @@
"struct thread KBI td_pflags");
_Static_assert(offsetof(struct thread, td_frame) == 0x4a8,
"struct thread KBI td_frame");
-_Static_assert(offsetof(struct thread, td_emuldata) == 0x6b0,
+_Static_assert(offsetof(struct thread, td_emuldata) == 0x6c0,
"struct thread KBI td_emuldata");
_Static_assert(offsetof(struct proc, p_flag) == 0xb8,
"struct proc KBI p_flag");
diff --git a/sys/modules/linux/Makefile b/sys/modules/linux/Makefile
--- a/sys/modules/linux/Makefile
+++ b/sys/modules/linux/Makefile
@@ -60,7 +60,7 @@
sh ${SYSDIR}/kern/genassym.sh linux${SFX}_genassym.o > ${.TARGET}
.if ${MACHINE_CPUARCH} == "amd64"
-VDSOFLAGS=-DCOMPAT_FREEBSD32 -DCOMPAT_LINUX32 -m32
+VDSOFLAGS=-DCOMPAT_FREEBSD32 -DCOMPAT_LINUX32 -D__M32_BROKEN_MODULE_HACK__ -m32
.else
VDSOFLAGS=-mregparm=0
.endif
diff --git a/sys/x86/include/fpu.h b/sys/x86/include/fpu.h
--- a/sys/x86/include/fpu.h
+++ b/sys/x86/include/fpu.h
@@ -123,10 +123,12 @@
} __aligned(16);
#ifdef __i386__
+#ifndef __M32_BROKEN_MODULE_HACK__
union savefpu {
struct save87 sv_87;
struct savexmm sv_xmm;
};
+#endif /* __M32_BROKEN_MODULE_HACK__ */
#else
/* Floating point context. (amd64 fxsave/fxrstor) */
struct savefpu {
File Metadata
Details
Attached
Mime Type
text/plain
Expires
Sat, Nov 15, 4:39 PM (14 h, 59 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
25332817
Default Alt Text
D31954.id95155.diff (58 KB)
Attached To
Mode
D31954: amd64: stop using top of the thread' kernel stack for FPU user save area
Attached
Detach File
Event Timeline
Log In to Comment