From 2c66cccab7ceceb3eed086da3b2dedfc77ce72de Mon Sep 17 00:00:00 2001 From: Konstantin Belousov Date: Wed, 1 Apr 2009 13:09:26 +0000 Subject: 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 --- sys/amd64/linux32/linux32_locore.s | 4 --- sys/amd64/linux32/linux32_machdep.c | 9 ++--- sys/amd64/linux32/linux32_sysvec.c | 70 ++++++++++++++++++++----------------- 3 files changed, 41 insertions(+), 42 deletions(-) (limited to 'sys/amd64/linux32') diff --git a/sys/amd64/linux32/linux32_locore.s b/sys/amd64/linux32/linux32_locore.s index 6045925c9b5b..36e1abf87b83 100644 --- a/sys/amd64/linux32/linux32_locore.s +++ b/sys/amd64/linux32/linux32_locore.s @@ -11,8 +11,6 @@ NON_GPROF_ENTRY(linux_sigcode) call *LINUX_SIGF_HANDLER(%esp) leal LINUX_SIGF_SC(%esp),%ebx /* linux scp */ - mov LINUX_SC_ES(%ebx),%es - mov LINUX_SC_DS(%ebx),%ds movl %esp, %ebx /* pass sigframe */ push %eax /* fake ret addr */ movl $LINUX_SYS_linux_sigreturn,%eax /* linux_sigreturn() */ @@ -24,8 +22,6 @@ linux_rt_sigcode: call *LINUX_RT_SIGF_HANDLER(%esp) leal LINUX_RT_SIGF_UC(%esp),%ebx /* linux ucp */ leal LINUX_RT_SIGF_SC(%ebx),%ecx /* linux sigcontext */ - mov LINUX_SC_ES(%ecx),%es - mov LINUX_SC_DS(%ecx),%ds push %eax /* fake ret addr */ movl $LINUX_SYS_linux_rt_sigreturn,%eax /* linux_rt_sigreturn() */ int $0x80 /* enter kernel with args */ diff --git a/sys/amd64/linux32/linux32_machdep.c b/sys/amd64/linux32/linux32_machdep.c index eb91623cfd84..42ea0700f8b6 100644 --- a/sys/amd64/linux32/linux32_machdep.c +++ b/sys/amd64/linux32/linux32_machdep.c @@ -716,8 +716,8 @@ linux_clone(struct thread *td, struct linux_clone_args *args) sd.sd_long, sd.sd_def32, sd.sd_gran); #endif td2->td_pcb->pcb_gsbase = (register_t)info.base_addr; - td2->td_pcb->pcb_gs32sd = sd; - td2->td_pcb->pcb_gs = GSEL(GUGS32_SEL, SEL_UPL); +/* XXXKIB td2->td_pcb->pcb_gs32sd = sd; */ + td2->td_frame->tf_gs = GSEL(GUGS32_SEL, SEL_UPL); td2->td_pcb->pcb_flags |= PCB_GS32BIT | PCB_32BIT; } } @@ -1359,12 +1359,9 @@ linux_set_thread_area(struct thread *td, sd.sd_gran); #endif - critical_enter(); td->td_pcb->pcb_gsbase = (register_t)info.base_addr; - td->td_pcb->pcb_gs32sd = *PCPU_GET(gs32p) = sd; td->td_pcb->pcb_flags |= PCB_32BIT | PCB_GS32BIT; - wrmsr(MSR_KGSBASE, td->td_pcb->pcb_gsbase); - critical_exit(); + update_gdt_gsbase(td, info.base_addr); return (0); } diff --git a/sys/amd64/linux32/linux32_sysvec.c b/sys/amd64/linux32/linux32_sysvec.c index 3ed65eb4cfb8..925d2e100a2f 100644 --- a/sys/amd64/linux32/linux32_sysvec.c +++ b/sys/amd64/linux32/linux32_sysvec.c @@ -290,7 +290,6 @@ elf_linux_fixup(register_t **stack_base, struct image_params *imgp) return 0; } -extern int _ucodesel, _ucode32sel, _udatasel; extern unsigned long linux_sznonrtsigcode; static void @@ -360,13 +359,7 @@ linux_rt_sendsig(sig_t catcher, ksiginfo_t *ksi, sigset_t *mask) bsd_to_linux_sigset(mask, &frame.sf_sc.uc_sigmask); - frame.sf_sc.uc_mcontext.sc_mask = frame.sf_sc.uc_sigmask.__bits[0]; - frame.sf_sc.uc_mcontext.sc_gs = rgs(); - frame.sf_sc.uc_mcontext.sc_fs = rfs(); - __asm __volatile("mov %%es,%0" : - "=rm" (frame.sf_sc.uc_mcontext.sc_es)); - __asm __volatile("mov %%ds,%0" : - "=rm" (frame.sf_sc.uc_mcontext.sc_ds)); + frame.sf_sc.uc_mcontext.sc_mask = frame.sf_sc.uc_sigmask.__bits[0]; frame.sf_sc.uc_mcontext.sc_edi = regs->tf_rdi; frame.sf_sc.uc_mcontext.sc_esi = regs->tf_rsi; frame.sf_sc.uc_mcontext.sc_ebp = regs->tf_rbp; @@ -376,6 +369,10 @@ linux_rt_sendsig(sig_t catcher, ksiginfo_t *ksi, sigset_t *mask) frame.sf_sc.uc_mcontext.sc_eax = regs->tf_rax; frame.sf_sc.uc_mcontext.sc_eip = regs->tf_rip; frame.sf_sc.uc_mcontext.sc_cs = regs->tf_cs; + frame.sf_sc.uc_mcontext.sc_gs = regs->tf_gs; + frame.sf_sc.uc_mcontext.sc_fs = regs->tf_fs; + frame.sf_sc.uc_mcontext.sc_es = regs->tf_es; + frame.sf_sc.uc_mcontext.sc_ds = regs->tf_ds; frame.sf_sc.uc_mcontext.sc_eflags = regs->tf_rflags; frame.sf_sc.uc_mcontext.sc_esp_at_signal = regs->tf_rsp; frame.sf_sc.uc_mcontext.sc_ss = regs->tf_ss; @@ -413,11 +410,11 @@ linux_rt_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; + regs->tf_fs = _ufssel; + regs->tf_gs = _ugssel; + regs->tf_flags = TF_HASSEGS; PROC_LOCK(p); mtx_lock(&psp->ps_mtx); } @@ -495,10 +492,10 @@ linux_sendsig(sig_t catcher, ksiginfo_t *ksi, sigset_t *mask) * Build the signal context to be used by sigreturn. */ frame.sf_sc.sc_mask = lmask.__bits[0]; - frame.sf_sc.sc_gs = rgs(); - frame.sf_sc.sc_fs = rfs(); - __asm __volatile("mov %%es,%0" : "=rm" (frame.sf_sc.sc_es)); - __asm __volatile("mov %%ds,%0" : "=rm" (frame.sf_sc.sc_ds)); + frame.sf_sc.sc_gs = regs->tf_gs; + frame.sf_sc.sc_fs = regs->tf_fs; + frame.sf_sc.sc_es = regs->tf_es; + frame.sf_sc.sc_ds = regs->tf_ds; frame.sf_sc.sc_edi = regs->tf_rdi; frame.sf_sc.sc_esi = regs->tf_rsi; frame.sf_sc.sc_ebp = regs->tf_rbp; @@ -535,11 +532,11 @@ linux_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; + regs->tf_fs = _ufssel; + regs->tf_gs = _ugssel; + regs->tf_flags = TF_HASSEGS; PROC_LOCK(p); mtx_lock(&psp->ps_mtx); } @@ -624,7 +621,6 @@ linux_sigreturn(struct thread *td, struct linux_sigreturn_args *args) /* * Restore signal context. */ - /* Selectors were restored by the trampoline. */ regs->tf_rdi = frame.sf_sc.sc_edi; regs->tf_rsi = frame.sf_sc.sc_esi; regs->tf_rbp = frame.sf_sc.sc_ebp; @@ -634,6 +630,10 @@ linux_sigreturn(struct thread *td, struct linux_sigreturn_args *args) regs->tf_rax = frame.sf_sc.sc_eax; regs->tf_rip = frame.sf_sc.sc_eip; regs->tf_cs = frame.sf_sc.sc_cs; + regs->tf_ds = frame.sf_sc.sc_ds; + regs->tf_es = frame.sf_sc.sc_es; + regs->tf_fs = frame.sf_sc.sc_fs; + regs->tf_gs = frame.sf_sc.sc_gs; regs->tf_rflags = eflags; regs->tf_rsp = frame.sf_sc.sc_esp_at_signal; regs->tf_ss = frame.sf_sc.sc_ss; @@ -722,7 +722,10 @@ linux_rt_sigreturn(struct thread *td, struct linux_rt_sigreturn_args *args) /* * Restore signal context */ - /* Selectors were restored by the trampoline. */ + regs->tf_gs = context->sc_gs; + regs->tf_fs = context->sc_fs; + regs->tf_es = context->sc_es; + regs->tf_ds = context->sc_ds; regs->tf_rdi = context->sc_edi; regs->tf_rsi = context->sc_esi; regs->tf_rbp = context->sc_ebp; @@ -827,27 +830,30 @@ exec_linux_setregs(td, entry, stack, ps_strings) struct trapframe *regs = td->td_frame; struct pcb *pcb = td->td_pcb; + mtx_lock(&dt_lock); + if (td->td_proc->p_md.md_ldt != NULL) + user_ldt_free(td); + else + mtx_unlock(&dt_lock); + critical_enter(); wrmsr(MSR_FSBASE, 0); wrmsr(MSR_KGSBASE, 0); /* User value while we're in the kernel */ 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 = __LINUX_NPXCW__; bzero((char *)regs, sizeof(struct trapframe)); regs->tf_rip = entry; regs->tf_rsp = stack; regs->tf_rflags = PSL_USER | (regs->tf_rflags & PSL_T); + regs->tf_gs = _ugssel; + regs->tf_fs = _ufssel; + regs->tf_es = _udatasel; + regs->tf_ds = _udatasel; regs->tf_ss = _udatasel; + regs->tf_flags = TF_HASSEGS; regs->tf_cs = _ucode32sel; regs->tf_rbx = ps_strings; load_cr0(rcr0() | CR0_MP | CR0_TS); -- cgit v1.3