diff options
author | kib <kib@FreeBSD.org> | 2009-04-01 13:09:26 +0000 |
---|---|---|
committer | kib <kib@FreeBSD.org> | 2009-04-01 13:09:26 +0000 |
commit | 253f7779bc4142bb2814f0f44999bc0e48e9bbe5 (patch) | |
tree | b58cda2045e48f43c2d8ff644f3d5c3a859f6e99 /sys/amd64/ia32/ia32_signal.c | |
parent | d2c67f9684a76233c58b569abc3a56c24f6a64db (diff) | |
download | FreeBSD-src-253f7779bc4142bb2814f0f44999bc0e48e9bbe5.zip FreeBSD-src-253f7779bc4142bb2814f0f44999bc0e48e9bbe5.tar.gz |
Save and restore segment registers on amd64 when entering and leaving
the kernel on amd64. Fill and read segment registers for mcontext and
signals. Handle traps caused by restoration of the
invalidated selectors.
Implement user-mode creation and manipulation of the process-specific
LDT descriptors for amd64, see sysarch(2).
Implement support for TSS i/o port access permission bitmap for amd64.
Context-switch LDT and TSS. Do not save and restore segment registers on
the context switch, that is handled by kernel enter/leave trampolines
now. Remove segment restore code from the signal trampolines for
freebsd/amd64, freebsd/ia32 and linux/i386 for the same reason.
Implement amd64-specific compat shims for sysarch.
Linuxolator (temporary ?) switched to use gsbase for thread_area pointer.
TODO:
Currently, gdb is not adapted to show segment registers from struct reg.
Also, no machine-depended ptrace command is added to set segment
registers for debugged process.
In collaboration with: pho
Discussed with: peter
Reviewed by: jhb
Linuxolator tested by: dchagin
Diffstat (limited to 'sys/amd64/ia32/ia32_signal.c')
-rw-r--r-- | sys/amd64/ia32/ia32_signal.c | 87 |
1 files changed, 45 insertions, 42 deletions
diff --git a/sys/amd64/ia32/ia32_signal.c b/sys/amd64/ia32/ia32_signal.c index 019faba..37e8013 100644 --- a/sys/amd64/ia32/ia32_signal.c +++ b/sys/amd64/ia32/ia32_signal.c @@ -85,8 +85,6 @@ static void freebsd4_ia32_sendsig(sig_t, ksiginfo_t *, sigset_t *); static void ia32_get_fpcontext(struct thread *td, struct ia32_mcontext *mcp); static int ia32_set_fpcontext(struct thread *td, const struct ia32_mcontext *mcp); -extern int _ucode32sel, _udatasel; - #define CS_SECURE(cs) (ISPL(cs) == SEL_UPL) #define EFL_SECURE(ef, oef) ((((ef) ^ (oef)) & ~PSL_USERCHANGE) == 0) @@ -134,10 +132,11 @@ ia32_get_mcontext(struct thread *td, struct ia32_mcontext *mcp, int flags) PROC_LOCK(curthread->td_proc); mcp->mc_onstack = sigonstack(tp->tf_rsp); PROC_UNLOCK(curthread->td_proc); - mcp->mc_gs = td->td_pcb->pcb_gs; - mcp->mc_fs = td->td_pcb->pcb_fs; - mcp->mc_es = td->td_pcb->pcb_es; - mcp->mc_ds = td->td_pcb->pcb_ds; + /* Entry into kernel always sets TF_HASSEGS */ + mcp->mc_gs = tp->tf_gs; + mcp->mc_fs = tp->tf_fs; + mcp->mc_es = tp->tf_es; + mcp->mc_ds = tp->tf_ds; mcp->mc_edi = tp->tf_rdi; mcp->mc_esi = tp->tf_rsi; mcp->mc_ebp = tp->tf_rbp; @@ -158,6 +157,8 @@ ia32_get_mcontext(struct thread *td, struct ia32_mcontext *mcp, int flags) mcp->mc_ss = tp->tf_ss; mcp->mc_len = sizeof(*mcp); ia32_get_fpcontext(td, mcp); + mcp->mc_fsbase = td->td_pcb->pcb_fsbase; + mcp->mc_gsbase = td->td_pcb->pcb_gsbase; return (0); } @@ -182,11 +183,11 @@ ia32_set_mcontext(struct thread *td, const struct ia32_mcontext *mcp) ret = ia32_set_fpcontext(td, mcp); if (ret != 0) return (ret); -#if 0 /* XXX deal with load_fs() and friends */ + tp->tf_gs = mcp->mc_gs; tp->tf_fs = mcp->mc_fs; tp->tf_es = mcp->mc_es; tp->tf_ds = mcp->mc_ds; -#endif + tp->tf_flags = TF_HASSEGS; tp->tf_rdi = mcp->mc_edi; tp->tf_rsi = mcp->mc_esi; tp->tf_rbp = mcp->mc_ebp; @@ -199,9 +200,6 @@ ia32_set_mcontext(struct thread *td, const struct ia32_mcontext *mcp) tp->tf_rflags = rflags; tp->tf_rsp = mcp->mc_esp; tp->tf_ss = mcp->mc_ss; -#if 0 /* XXX deal with load_gs() and friends */ - td->td_pcb->pcb_gs = mcp->mc_gs; -#endif td->td_pcb->pcb_flags |= PCB_FULLCTX; return (0); } @@ -326,10 +324,6 @@ freebsd4_ia32_sendsig(sig_t catcher, ksiginfo_t *ksi, sigset_t *mask) sf.sf_uc.uc_stack.ss_flags = (td->td_pflags & TDP_ALTSTACK) ? ((oonstack) ? SS_ONSTACK : 0) : SS_DISABLE; sf.sf_uc.uc_mcontext.mc_onstack = (oonstack) ? 1 : 0; - sf.sf_uc.uc_mcontext.mc_gs = rgs(); - sf.sf_uc.uc_mcontext.mc_fs = rfs(); - __asm __volatile("mov %%es,%0" : "=rm" (sf.sf_uc.uc_mcontext.mc_es)); - __asm __volatile("mov %%ds,%0" : "=rm" (sf.sf_uc.uc_mcontext.mc_ds)); sf.sf_uc.uc_mcontext.mc_edi = regs->tf_rdi; sf.sf_uc.uc_mcontext.mc_esi = regs->tf_rsi; sf.sf_uc.uc_mcontext.mc_ebp = regs->tf_rbp; @@ -345,6 +339,10 @@ freebsd4_ia32_sendsig(sig_t catcher, ksiginfo_t *ksi, sigset_t *mask) sf.sf_uc.uc_mcontext.mc_eflags = regs->tf_rflags; sf.sf_uc.uc_mcontext.mc_esp = regs->tf_rsp; sf.sf_uc.uc_mcontext.mc_ss = regs->tf_ss; + sf.sf_uc.uc_mcontext.mc_ds = regs->tf_ds; + sf.sf_uc.uc_mcontext.mc_es = regs->tf_es; + sf.sf_uc.uc_mcontext.mc_fs = regs->tf_fs; + sf.sf_uc.uc_mcontext.mc_gs = regs->tf_gs; /* Allocate space for the signal handler context. */ if ((td->td_pflags & TDP_ALTSTACK) != 0 && !oonstack && @@ -394,10 +392,8 @@ freebsd4_ia32_sendsig(sig_t catcher, ksiginfo_t *ksi, sigset_t *mask) regs->tf_rflags &= ~(PSL_T | PSL_D); regs->tf_cs = _ucode32sel; regs->tf_ss = _udatasel; - load_ds(_udatasel); - td->td_pcb->pcb_ds = _udatasel; - load_es(_udatasel); - td->td_pcb->pcb_es = _udatasel; + regs->tf_ds = _udatasel; + regs->tf_es = _udatasel; /* leave user %fs and %gs untouched */ PROC_LOCK(p); mtx_lock(&psp->ps_mtx); @@ -441,10 +437,6 @@ ia32_sendsig(sig_t catcher, ksiginfo_t *ksi, sigset_t *mask) sf.sf_uc.uc_stack.ss_flags = (td->td_pflags & TDP_ALTSTACK) ? ((oonstack) ? SS_ONSTACK : 0) : SS_DISABLE; sf.sf_uc.uc_mcontext.mc_onstack = (oonstack) ? 1 : 0; - sf.sf_uc.uc_mcontext.mc_gs = rgs(); - sf.sf_uc.uc_mcontext.mc_fs = rfs(); - __asm __volatile("mov %%es,%0" : "=rm" (sf.sf_uc.uc_mcontext.mc_es)); - __asm __volatile("mov %%ds,%0" : "=rm" (sf.sf_uc.uc_mcontext.mc_ds)); sf.sf_uc.uc_mcontext.mc_edi = regs->tf_rdi; sf.sf_uc.uc_mcontext.mc_esi = regs->tf_rsi; sf.sf_uc.uc_mcontext.mc_ebp = regs->tf_rbp; @@ -460,9 +452,15 @@ ia32_sendsig(sig_t catcher, ksiginfo_t *ksi, sigset_t *mask) sf.sf_uc.uc_mcontext.mc_eflags = regs->tf_rflags; sf.sf_uc.uc_mcontext.mc_esp = regs->tf_rsp; sf.sf_uc.uc_mcontext.mc_ss = regs->tf_ss; + sf.sf_uc.uc_mcontext.mc_ds = regs->tf_ds; + sf.sf_uc.uc_mcontext.mc_es = regs->tf_es; + sf.sf_uc.uc_mcontext.mc_fs = regs->tf_fs; + sf.sf_uc.uc_mcontext.mc_gs = regs->tf_gs; sf.sf_uc.uc_mcontext.mc_len = sizeof(sf.sf_uc.uc_mcontext); /* magic */ ia32_get_fpcontext(td, &sf.sf_uc.uc_mcontext); fpstate_drop(td); + sf.sf_uc.uc_mcontext.mc_fsbase = td->td_pcb->pcb_fsbase; + sf.sf_uc.uc_mcontext.mc_gsbase = td->td_pcb->pcb_gsbase; /* Allocate space for the signal handler context. */ if ((td->td_pflags & TDP_ALTSTACK) != 0 && !oonstack && @@ -514,11 +512,9 @@ ia32_sendsig(sig_t catcher, ksiginfo_t *ksi, sigset_t *mask) regs->tf_rflags &= ~(PSL_T | PSL_D); regs->tf_cs = _ucode32sel; regs->tf_ss = _udatasel; - load_ds(_udatasel); - td->td_pcb->pcb_ds = _udatasel; - load_es(_udatasel); - td->td_pcb->pcb_es = _udatasel; - /* leave user %fs and %gs untouched */ + regs->tf_ds = _udatasel; + regs->tf_es = _udatasel; + /* XXXKIB leave user %fs and %gs untouched */ PROC_LOCK(p); mtx_lock(&psp->ps_mtx); } @@ -591,7 +587,6 @@ freebsd4_freebsd32_sigreturn(td, uap) return (EINVAL); } - /* Segment selectors restored by sigtramp.S */ regs->tf_rdi = ucp->uc_mcontext.mc_edi; regs->tf_rsi = ucp->uc_mcontext.mc_esi; regs->tf_rbp = ucp->uc_mcontext.mc_ebp; @@ -606,6 +601,10 @@ freebsd4_freebsd32_sigreturn(td, uap) regs->tf_rflags = ucp->uc_mcontext.mc_eflags; regs->tf_rsp = ucp->uc_mcontext.mc_esp; regs->tf_ss = ucp->uc_mcontext.mc_ss; + regs->tf_ds = ucp->uc_mcontext.mc_ds; + regs->tf_es = ucp->uc_mcontext.mc_es; + regs->tf_fs = ucp->uc_mcontext.mc_fs; + regs->tf_gs = ucp->uc_mcontext.mc_gs; PROC_LOCK(p); td->td_sigmask = ucp->uc_sigmask; @@ -678,7 +677,6 @@ freebsd32_sigreturn(td, uap) if (ret != 0) return (ret); - /* Segment selectors restored by sigtramp.S */ regs->tf_rdi = ucp->uc_mcontext.mc_edi; regs->tf_rsi = ucp->uc_mcontext.mc_esi; regs->tf_rbp = ucp->uc_mcontext.mc_ebp; @@ -693,6 +691,11 @@ freebsd32_sigreturn(td, uap) regs->tf_rflags = ucp->uc_mcontext.mc_eflags; regs->tf_rsp = ucp->uc_mcontext.mc_esp; regs->tf_ss = ucp->uc_mcontext.mc_ss; + regs->tf_ds = ucp->uc_mcontext.mc_ds; + regs->tf_es = ucp->uc_mcontext.mc_es; + regs->tf_fs = ucp->uc_mcontext.mc_fs; + regs->tf_gs = ucp->uc_mcontext.mc_gs; + regs->tf_flags = TF_HASSEGS; PROC_LOCK(p); td->td_sigmask = ucp->uc_sigmask; @@ -715,20 +718,14 @@ ia32_setregs(td, entry, stack, ps_strings) struct trapframe *regs = td->td_frame; struct pcb *pcb = td->td_pcb; - critical_enter(); - wrmsr(MSR_FSBASE, 0); - wrmsr(MSR_KGSBASE, 0); /* User value while we're in the kernel */ + mtx_lock(&dt_lock); + if (td->td_proc->p_md.md_ldt != NULL) + user_ldt_free(td); + else + mtx_unlock(&dt_lock); + pcb->pcb_fsbase = 0; pcb->pcb_gsbase = 0; - critical_exit(); - load_ds(_udatasel); - load_es(_udatasel); - load_fs(_udatasel); - load_gs(_udatasel); - pcb->pcb_ds = _udatasel; - pcb->pcb_es = _udatasel; - pcb->pcb_fs = _udatasel; - pcb->pcb_gs = _udatasel; pcb->pcb_initial_fpucw = __INITIAL_FPUCW_I386__; bzero((char *)regs, sizeof(struct trapframe)); @@ -738,6 +735,12 @@ ia32_setregs(td, entry, stack, ps_strings) regs->tf_ss = _udatasel; regs->tf_cs = _ucode32sel; regs->tf_rbx = ps_strings; + regs->tf_ds = _udatasel; + regs->tf_es = _udatasel; + regs->tf_fs = _ufssel; + regs->tf_gs = _ugssel; + regs->tf_flags = TF_HASSEGS; + load_cr0(rcr0() | CR0_MP | CR0_TS); fpstate_drop(td); |