summaryrefslogtreecommitdiffstats
path: root/sys/amd64/ia32
diff options
context:
space:
mode:
authorkib <kib@FreeBSD.org>2009-04-01 13:09:26 +0000
committerkib <kib@FreeBSD.org>2009-04-01 13:09:26 +0000
commit253f7779bc4142bb2814f0f44999bc0e48e9bbe5 (patch)
treeb58cda2045e48f43c2d8ff644f3d5c3a859f6e99 /sys/amd64/ia32
parentd2c67f9684a76233c58b569abc3a56c24f6a64db (diff)
downloadFreeBSD-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')
-rw-r--r--sys/amd64/ia32/ia32_exception.S5
-rw-r--r--sys/amd64/ia32/ia32_misc.c71
-rw-r--r--sys/amd64/ia32/ia32_reg.c35
-rw-r--r--sys/amd64/ia32/ia32_signal.c87
-rw-r--r--sys/amd64/ia32/ia32_sigtramp.S4
5 files changed, 139 insertions, 63 deletions
diff --git a/sys/amd64/ia32/ia32_exception.S b/sys/amd64/ia32/ia32_exception.S
index 4820f53..76c5d5a 100644
--- a/sys/amd64/ia32/ia32_exception.S
+++ b/sys/amd64/ia32/ia32_exception.S
@@ -60,6 +60,11 @@ IDTVEC(int0x80_syscall)
movq %r13,TF_R13(%rsp)
movq %r14,TF_R14(%rsp)
movq %r15,TF_R15(%rsp)
+ movw %fs,TF_FS(%rsp)
+ movw %gs,TF_GS(%rsp)
+ movw %es,TF_ES(%rsp)
+ movw %ds,TF_DS(%rsp)
+ movl $TF_HASSEGS,TF_FLAGS(%rsp)
FAKE_MCOUNT(TF_RIP(%rsp))
movq %rsp, %rdi
call ia32_syscall
diff --git a/sys/amd64/ia32/ia32_misc.c b/sys/amd64/ia32/ia32_misc.c
new file mode 100644
index 0000000..2fa1972
--- /dev/null
+++ b/sys/amd64/ia32/ia32_misc.c
@@ -0,0 +1,71 @@
+/*-
+ * Copyright (c) 2009 Konstantin Belousov
+ * All rights reserved.
+ *
+ * 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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR 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 AUTHOR 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.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include "opt_compat.h"
+
+#include <sys/param.h>
+#include <sys/mount.h>
+#include <sys/proc.h>
+#include <sys/socket.h>
+#include <sys/sysent.h>
+#include <sys/sysproto.h>
+#include <sys/systm.h>
+#include <sys/uio.h>
+
+#include <machine/cpu.h>
+#include <machine/sysarch.h>
+
+#include <compat/freebsd32/freebsd32_util.h>
+#include <compat/freebsd32/freebsd32.h>
+#include <compat/freebsd32/freebsd32_proto.h>
+
+int
+freebsd32_sysarch(struct thread *td, struct freebsd32_sysarch_args *uap)
+{
+ struct sysarch_args uap1;
+ struct i386_ldt_args uapl;
+ struct i386_ldt_args32 uapl32;
+ int error;
+
+ if (uap->op == I386_SET_LDT || uap->op == I386_GET_LDT) {
+ if ((error = copyin(uap->parms, &uapl32, sizeof(uapl32))) != 0)
+ return (error);
+ uap1.op = uap->op;
+ uap1.parms = (char *)&uapl;
+ uapl.start = uapl32.start;
+ uapl.descs = (struct user_segment_descriptor *)(uintptr_t)
+ uapl32.descs;
+ uapl.num = uapl32.num;
+ return (sysarch_ldt(td, &uap1, UIO_SYSSPACE));
+ } else {
+ uap1.op = uap->op;
+ uap1.parms = uap->parms;
+ return (sysarch(td, &uap1));
+ }
+}
diff --git a/sys/amd64/ia32/ia32_reg.c b/sys/amd64/ia32/ia32_reg.c
index 8abc6fc..49dd4e2 100644
--- a/sys/amd64/ia32/ia32_reg.c
+++ b/sys/amd64/ia32/ia32_reg.c
@@ -85,9 +85,17 @@ fill_regs32(struct thread *td, struct reg32 *regs)
tp = td->td_frame;
pcb = td->td_pcb;
- regs->r_fs = pcb->pcb_fs;
- regs->r_es = pcb->pcb_es;
- regs->r_ds = pcb->pcb_ds;
+ if (tp->tf_flags & TF_HASSEGS) {
+ regs->r_gs = tp->tf_gs;
+ regs->r_fs = tp->tf_fs;
+ regs->r_es = tp->tf_es;
+ regs->r_ds = tp->tf_ds;
+ } else {
+ regs->r_gs = _ugssel;
+ regs->r_fs = _ufssel;
+ regs->r_es = _udatasel;
+ regs->r_ds = _udatasel;
+ }
regs->r_edi = tp->tf_rdi;
regs->r_esi = tp->tf_rsi;
regs->r_ebp = tp->tf_rbp;
@@ -100,7 +108,6 @@ fill_regs32(struct thread *td, struct reg32 *regs)
regs->r_eflags = tp->tf_rflags;
regs->r_esp = tp->tf_rsp;
regs->r_ss = tp->tf_ss;
- regs->r_gs = pcb->pcb_gs;
return (0);
}
@@ -114,14 +121,11 @@ set_regs32(struct thread *td, struct reg32 *regs)
if (!EFL_SECURE(regs->r_eflags, tp->tf_rflags) || !CS_SECURE(regs->r_cs))
return (EINVAL);
pcb = td->td_pcb;
-#if 0
- load_fs(regs->r_fs);
- pcb->pcb_fs = regs->r_fs;
- load_es(regs->r_es);
- pcb->pcb_es = regs->r_es;
- load_ds(regs->r_ds);
- pcb->pcb_ds = regs->r_ds;
-#endif
+ tp->tf_gs = regs->r_gs;
+ tp->tf_fs = regs->r_fs;
+ tp->tf_es = regs->r_es;
+ tp->tf_ds = regs->r_ds;
+ tp->tf_flags = TF_HASSEGS;
tp->tf_rdi = regs->r_edi;
tp->tf_rsi = regs->r_esi;
tp->tf_rbp = regs->r_ebp;
@@ -134,10 +138,6 @@ set_regs32(struct thread *td, struct reg32 *regs)
tp->tf_rflags = regs->r_eflags;
tp->tf_rsp = regs->r_esp;
tp->tf_ss = regs->r_ss;
-#if 0
- load_gs(regs->r_gs);
- pcb->pcb_gs = regs->r_gs;
-#endif
return (0);
}
@@ -166,7 +166,8 @@ fill_fpregs32(struct thread *td, struct fpreg32 *regs)
penv_87->en_fcs = td->td_frame->tf_cs;
penv_87->en_opcode = penv_xmm->en_opcode;
penv_87->en_foo = penv_xmm->en_rdp;
- penv_87->en_fos = td->td_pcb->pcb_ds;
+ /* Entry into the kernel always sets TF_HASSEGS */
+ penv_87->en_fos = td->td_frame->tf_ds;
/* FPU registers */
for (i = 0; i < 8; ++i)
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);
diff --git a/sys/amd64/ia32/ia32_sigtramp.S b/sys/amd64/ia32/ia32_sigtramp.S
index 1cd220a..9455169 100644
--- a/sys/amd64/ia32/ia32_sigtramp.S
+++ b/sys/amd64/ia32/ia32_sigtramp.S
@@ -45,8 +45,6 @@ ia32_sigcode:
calll *IA32_SIGF_HANDLER(%esp)
leal IA32_SIGF_UC(%esp),%eax /* get ucontext */
pushl %eax
- mov IA32_UC_ES(%eax),%es /* restore %es */
- mov IA32_UC_DS(%eax),%ds /* restore %ds */
movl $SYS_sigreturn,%eax
pushl %eax /* junk to fake return addr. */
int $0x80 /* enter kernel with args */
@@ -60,8 +58,6 @@ freebsd4_ia32_sigcode:
calll *IA32_SIGF_HANDLER(%esp)
leal IA32_SIGF_UC4(%esp),%eax/* get ucontext */
pushl %eax
- mov IA32_UC4_ES(%eax),%es /* restore %es */
- mov IA32_UC4_DS(%eax),%ds /* restore %ds */
movl $344,%eax /* 4.x SYS_sigreturn */
pushl %eax /* junk to fake return addr. */
int $0x80 /* enter kernel with args */
OpenPOWER on IntegriCloud