> some software needs fully functional per-thread %gs base address, > hence the diff. limited testing shows no regressions. > INTR_RESTORE_SELECTORS changes include: > - %r11 is used to store curpcb instead of rdx that is used for > wrmsr and gets trashed (it's safe to use %r11 because it's > restored after INTR_RESTORE_SELECTORS gets called); > > - MSR_KERNELGSBASE needs to be updated instead of MSR_GSBASE > so that we don't lose kernel gs.base stored in MSR_GSBASE > and swapped by the swapgs. > > any objections? corrections?
> > Index: sys/arch/amd64/amd64/cpu.c > =================================================================== > RCS file: /home/cvs/src/sys/arch/amd64/amd64/cpu.c,v > retrieving revision 1.47 > diff -u -p -r1.47 cpu.c > --- sys/arch/amd64/amd64/cpu.c 4 Apr 2012 18:44:22 -0000 1.47 > +++ sys/arch/amd64/amd64/cpu.c 13 Apr 2012 15:26:51 -0000 > @@ -682,6 +684,7 @@ cpu_init_msrs(struct cpu_info *ci) > wrmsr(MSR_SFMASK, PSL_NT|PSL_T|PSL_I|PSL_C); > > ci->ci_cur_fsbase = 0; > + ci->ci_cur_gsbase = (u_int64_t)ci; > wrmsr(MSR_FSBASE, 0); > wrmsr(MSR_GSBASE, (u_int64_t)ci); > wrmsr(MSR_KERNELGSBASE, 0); > Index: sys/arch/amd64/amd64/genassym.cf > =================================================================== > RCS file: /home/cvs/src/sys/arch/amd64/amd64/genassym.cf,v > retrieving revision 1.28 > diff -u -p -r1.28 genassym.cf > --- sys/arch/amd64/amd64/genassym.cf 13 Apr 2011 02:49:12 -0000 1.28 > +++ sys/arch/amd64/amd64/genassym.cf 13 Apr 2012 15:25:26 -0000 > @@ -86,6 +86,7 @@ member pcb_rsp > member pcb_rbp > member pcb_kstack > member pcb_fsbase > +member pcb_gsbase > member pcb_onfault > member pcb_fpcpu > member pcb_pmap > @@ -100,6 +101,7 @@ member tss_rsp0 > struct cpu_info > member CPU_INFO_SCRATCH ci_scratch > member CPU_INFO_CUR_FSBASE ci_cur_fsbase > +member CPU_INFO_CUR_GSBASE ci_cur_gsbase > member CPU_INFO_SELF ci_self > member CPU_INFO_CPUID ci_cpuid > member CPU_INFO_APICID ci_apicid > Index: sys/arch/amd64/amd64/machdep.c > =================================================================== > RCS file: /home/cvs/src/sys/arch/amd64/amd64/machdep.c,v > retrieving revision 1.152 > diff -u -p -r1.152 machdep.c > --- sys/arch/amd64/amd64/machdep.c 13 Jan 2012 12:55:52 -0000 1.152 > +++ sys/arch/amd64/amd64/machdep.c 12 Apr 2012 16:41:18 -0000 > @@ -363,7 +363,7 @@ x86_64_proc0_tss_ldt_init(void) > > cpu_info_primary.ci_curpcb = pcb = &proc0.p_addr->u_pcb; > pcb->pcb_cr0 = rcr0(); > - pcb->pcb_fsbase = 0; > + pcb->pcb_fsbase = pcb->pcb_gsbase = 0; > pcb->pcb_kstack = (u_int64_t)proc0.p_addr + USPACE - 16; > proc0.p_md.md_regs = (struct trapframe *)pcb->pcb_kstack - 1; > > @@ -1022,6 +1022,7 @@ setregs(struct proc *p, struct exec_pack > fpusave_proc(p, 0); > p->p_md.md_flags &= ~MDP_USEDFPU; > p->p_addr->u_pcb.pcb_fsbase = 0; > + p->p_addr->u_pcb.pcb_gsbase = 0; > > tf = p->p_md.md_regs; > tf->tf_ds = GSEL(GUDATA_SEL, SEL_UPL); > Index: sys/arch/amd64/amd64/sys_machdep.c > =================================================================== > RCS file: /home/cvs/src/sys/arch/amd64/amd64/sys_machdep.c,v > retrieving revision 1.12 > diff -u -p -r1.12 sys_machdep.c > --- sys/arch/amd64/amd64/sys_machdep.c 13 Apr 2011 02:49:12 -0000 > 1.12 > +++ sys/arch/amd64/amd64/sys_machdep.c 12 Apr 2012 16:37:30 -0000 > @@ -159,6 +159,29 @@ amd64_set_fsbase(struct proc *p, void *a > } > > int > +amd64_get_gsbase(struct proc *p, void *args) > +{ > + return copyout(&p->p_addr->u_pcb.pcb_gsbase, args, > + sizeof(p->p_addr->u_pcb.pcb_gsbase)); > +} > + > +int > +amd64_set_gsbase(struct proc *p, void *args) > +{ > + int error; > + uint64_t base; > + > + if ((error = copyin(args, &base, sizeof(base))) != 0) > + return (error); > + > + if (base >= VM_MAXUSER_ADDRESS) > + return (EINVAL); > + > + p->p_addr->u_pcb.pcb_gsbase = base; > + return 0; > +} > + > +int > sys_sysarch(struct proc *p, void *v, register_t *retval) > { > struct sys_sysarch_args /* { > @@ -196,12 +219,20 @@ sys_sysarch(struct proc *p, void *v, reg > break; > #endif > > - case AMD64_GET_FSBASE: > + case AMD64_GET_FSBASE: > error = amd64_get_fsbase(p, SCARG(uap, parms)); > break; > > - case AMD64_SET_FSBASE: > + case AMD64_SET_FSBASE: > error = amd64_set_fsbase(p, SCARG(uap, parms)); > + break; > + > + case AMD64_GET_GSBASE: > + error = amd64_get_gsbase(p, SCARG(uap, parms)); > + break; > + > + case AMD64_SET_GSBASE: > + error = amd64_set_gsbase(p, SCARG(uap, parms)); > break; > > default: > Index: sys/arch/amd64/include/cpu.h > =================================================================== > RCS file: /home/cvs/src/sys/arch/amd64/include/cpu.h,v > retrieving revision 1.72 > diff -u -p -r1.72 cpu.h > --- sys/arch/amd64/include/cpu.h 4 Apr 2012 18:44:22 -0000 1.72 > +++ sys/arch/amd64/include/cpu.h 13 Apr 2012 15:25:13 -0000 > @@ -73,6 +73,7 @@ struct cpu_info { > > u_int64_t ci_scratch; > u_int64_t ci_cur_fsbase; > + u_int64_t ci_cur_gsbase; > > struct proc *ci_fpcurproc; > struct proc *ci_fpsaveproc; > Index: sys/arch/amd64/include/frameasm.h > =================================================================== > RCS file: /home/cvs/src/sys/arch/amd64/include/frameasm.h,v > retrieving revision 1.6 > diff -u -p -r1.6 frameasm.h > --- sys/arch/amd64/include/frameasm.h 4 Jul 2011 15:54:24 -0000 > 1.6 > +++ sys/arch/amd64/include/frameasm.h 13 Apr 2012 19:15:51 -0000 > @@ -56,16 +56,16 @@ > > /* > * Restore %ds, %es, %fs, and %gs, dealing with the FS.base MSR for > - * %fs and doing the cli/swapgs for %gs. Uses %rax, %rcx, and %rdx > + * %fs and doing the cli/swapgs for %gs. Uses %rax, %rcx, %rdx and %r11 > */ > #define INTR_RESTORE_SELECTORS > \ > - movq CPUVAR(CURPCB),%rdx /* for below */ ; \ > + movq CPUVAR(CURPCB),%r11 /* for below */ ; \ > /* %es and %ds */ \ > movw TF_ES(%rsp),%es ; \ > movw $(GSEL(GUDATA_SEL, SEL_UPL)),%ax ; \ > movw %ax,%ds ; \ > /* Make sure both %fs and FS.base are the desired values */ \ > - movq PCB_FSBASE(%rdx),%rax ; \ > + movq PCB_FSBASE(%r11),%rax ; \ > cmpq $0,%rax ; \ > jne 96f ; \ > movw TF_FS(%rsp),%fs /* zero FS.base by setting %fs */ ; \ > @@ -81,7 +81,20 @@ > movl $MSR_FSBASE,%ecx ; \ > wrmsr ; \ > 98: movq %rax,CPUVAR(CUR_FSBASE) ; \ > -99: cli /* %fs done, so swapgs and do %gs */ ; \ > +99: /* Make sure GS.base is reset */ ; \ > + movq PCB_GSBASE(%r11),%rax ; \ > + cmpq $0,%rax ; \ > + jne 100f ; \ > + movq %rax,CPUVAR(CUR_GSBASE) ; \ > + jmp 101f ; \ > +100: cmpq CPUVAR(CUR_GSBASE),%rax > ; \ > + je 101f ; \ > + movq %rax,CPUVAR(CUR_GSBASE) ; \ > + movq %rax,%rdx ; \ > + shrq $32,%rdx ; \ > + movl $MSR_KERNELGSBASE,%ecx ; \ > + wrmsr ; \ > +101: cli /* %gs done, do swapgs */ > ; \ > swapgs ; \ > movw TF_GS(%rsp),%gs > > Index: sys/arch/amd64/include/pcb.h > =================================================================== > RCS file: /home/cvs/src/sys/arch/amd64/include/pcb.h,v > retrieving revision 1.12 > diff -u -p -r1.12 pcb.h > --- sys/arch/amd64/include/pcb.h 10 Jul 2011 18:12:03 -0000 1.12 > +++ sys/arch/amd64/include/pcb.h 12 Apr 2012 17:28:16 -0000 > @@ -83,18 +83,19 @@ struct pcb { > u_int64_t pcb_rbp; > u_int64_t pcb_kstack; /* kernel stack address */ > u_int64_t pcb_fsbase; /* per-thread offset: %fs */ > + u_int64_t pcb_gsbase; /* per-thread offset: %gs */ > caddr_t pcb_onfault; /* copyin/out fault recovery */ > struct cpu_info *pcb_fpcpu; /* cpu holding our fp state. */ > struct pmap *pcb_pmap; /* back pointer to our pmap */ > int pcb_cr0; /* saved image of CR0 */ > }; > > -/* > - * The pcb is augmented with machine-dependent additional data for > +/* > + * The pcb is augmented with machine-dependent additional data for > * core dumps. For the i386, there is nothing to add. > - */ > + */ > struct md_coredump { > long md_pad[8]; > -}; > +}; > > #endif /* _MACHINE_PCB_H_ */ > Index: sys/arch/amd64/include/sysarch.h > =================================================================== > RCS file: /home/cvs/src/sys/arch/amd64/include/sysarch.h,v > retrieving revision 1.10 > diff -u -p -r1.10 sysarch.h > --- sys/arch/amd64/include/sysarch.h 13 Apr 2011 02:49:12 -0000 1.10 > +++ sys/arch/amd64/include/sysarch.h 12 Apr 2012 20:57:34 -0000 > @@ -16,6 +16,8 @@ > #define AMD64_PMC_READ 10 > #define AMD64_GET_FSBASE 11 > #define AMD64_SET_FSBASE 12 > +#define AMD64_GET_GSBASE 13 > +#define AMD64_SET_GSBASE 14 > > struct amd64_iopl_args { > int iopl; > @@ -67,6 +69,8 @@ struct amd64_pmc_read_args { > int amd64_iopl(struct proc *, void *, register_t *); > int amd64_set_fsbase(struct proc *, void *); > int amd64_get_fsbase(struct proc *, void *); > +int amd64_set_gsbase(struct proc *, void *); > +int amd64_get_gsbase(struct proc *, void *); > #else > int amd64_iopl(int); > int amd64_get_ioperm(u_long *); > @@ -76,6 +80,8 @@ int amd64_pmc_startstop(struct amd64_pmc > int amd64_pmc_read(struct amd64_pmc_read_args *); > int amd64_set_fsbase(void *); > int amd64_get_fsbase(void **); > +int amd64_set_gsbase(void *); > +int amd64_get_gsbase(void **); > int sysarch(int, void *); > #endif > > Index: lib/libarch/amd64/Makefile > =================================================================== > RCS file: /home/cvs/src/lib/libarch/amd64/Makefile,v > retrieving revision 1.10 > diff -u -p -r1.10 Makefile > --- lib/libarch/amd64/Makefile 13 Apr 2011 02:49:12 -0000 1.10 > +++ lib/libarch/amd64/Makefile 13 Apr 2012 19:20:17 -0000 > @@ -3,15 +3,17 @@ > > MANSUBDIR=amd64 > MAN+= amd64_iopl.2 amd64_get_ioperm.2 \ > - amd64_get_fsbase.2 > + amd64_get_fsbase.2 amd64_get_gsbase.2 > MLINKS+=amd64_get_ioperm.2 amd64_set_ioperm.2 \ > - amd64_get_fsbase.2 amd64_set_fsbase.2 > + amd64_get_fsbase.2 amd64_set_fsbase.2 \ > + amd64_get_gsbase.2 amd64_set_gsbase.2 > > .if ${MACHINE_ARCH} == "amd64" > .PATH: ${LIBC}/amd64 > NOPIC= > SRCS+= amd64_iopl.c amd64_get_ioperm.c amd64_set_ioperm.c \ > - amd64_get_fsbase.c amd64_set_fsbase.c > + amd64_get_fsbase.c amd64_set_fsbase.c \ > + amd64_get_gsbase.c amd64_set_gsbase.c > .include <bsd.lib.mk> > .else > NOPROG= > Index: lib/libarch/amd64/amd64_get_gsbase.2 > =================================================================== > RCS file: lib/libarch/amd64/amd64_get_gsbase.2 > diff -N lib/libarch/amd64/amd64_get_gsbase.2 > --- /dev/null 1 Jan 1970 00:00:00 -0000 > +++ lib/libarch/amd64/amd64_get_gsbase.2 13 Apr 2012 19:24:18 -0000 > @@ -0,0 +1,87 @@ > +.\" $OpenBSD$ > +.\" $NetBSD: i386_get_ioperm.2,v 1.3 1996/02/27 22:57:17 jtc Exp $ > +.\" > +.\" Copyright (c) 1996 The NetBSD Foundation, Inc. > +.\" All rights reserved. > +.\" > +.\" This code is derived from software contributed to The NetBSD > Foundation > +.\" by John T. Kohl and Charles M. Hannum. > +.\" > +.\" 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 NETBSD FOUNDATION, INC. 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. > +.\" > +.Dd $Mdocdate$ > +.Dt AMD64_GET_GSBASE 2 amd64 > +.Os > +.Sh NAME > +.Nm amd64_get_gsbase , > +.Nm amd64_set_gsbase > +.Nd manage amd64 per-thread %gs base address > +.Sh SYNOPSIS > +.Fd #include <sys/types.h> > +.Fd #include <machine/sysarch.h> > +.Ft int > +.Fn amd64_get_gsbase "void **base" > +.Ft int > +.Fn amd64_set_gsbase "void *base" > +.Sh DESCRIPTION > +.Fn amd64_get_gsbase > +copies the current base address of the %gs segment into the memory > +referenced by > +.Fa base . > +.Pp > +.Fn amd64_set_gsbase > +sets the base address of the %gs segment to the address > +.Fa base . > +.Pp > +The segment base address is local to each thread. > +The initial thread of a new process inherits its segment base address > +from the parent thread. > +.Xr __tfork 2 > +sets the initial segment base address for threads that it creates. > +.Pp > +.Sy Note: > +Code using the > +.Fn amd64_get_gsbase > +and > +.Fn amd64_set_gsbase > +functions must be compiled using > +.Cm -lamd64 . > +.Sh RETURN VALUES > +Upon successful completion, > +.Fn amd64_get_gsbase > +and > +.Fn amd64_set_gsbase > +return 0. > +Otherwise, a value of \-1 is returned and the global variable > +.Va errno > +is set to indicate the error. > +.Sh ERRORS > +.Fn amd64_get_gsbase > +will fail if: > +.Bl -tag -width [EINVAL] > +.It Bq Er EFAULT > +.Fa base > +points outside the process's allocated address space. > +.El > +.Sh SEE ALSO > +.Xr __tfork 2 , > +.Xr fork 2 > Index: lib/libarch/amd64/amd64_get_gsbase.c > =================================================================== > RCS file: lib/libarch/amd64/amd64_get_gsbase.c > diff -N lib/libarch/amd64/amd64_get_gsbase.c > --- /dev/null 1 Jan 1970 00:00:00 -0000 > +++ lib/libarch/amd64/amd64_get_gsbase.c 13 Apr 2012 19:28:32 -0000 > @@ -0,0 +1,15 @@ > +/* $OpenBSD$ */ > + > +/* Public domain. Written by Mike Belopuhov <mi...@openbsd.org> */ > + > +#include <sys/cdefs.h> > +#include <sys/types.h> > + > +#include <machine/segments.h> > +#include <machine/sysarch.h> > + > +int > +amd64_get_gsbase(void **base) > +{ > + return sysarch(AMD64_GET_GSBASE, base); > +} > Index: lib/libarch/amd64/amd64_set_gsbase.c > =================================================================== > RCS file: lib/libarch/amd64/amd64_set_gsbase.c > diff -N lib/libarch/amd64/amd64_set_gsbase.c > --- /dev/null 1 Jan 1970 00:00:00 -0000 > +++ lib/libarch/amd64/amd64_set_gsbase.c 13 Apr 2012 19:28:19 -0000 > @@ -0,0 +1,15 @@ > +/* $OpenBSD$ */ > + > +/* Public domain. Written by Mike Belopuhov <mi...@openbsd.org> */ > + > +#include <sys/cdefs.h> > +#include <sys/types.h> > + > +#include <machine/segments.h> > +#include <machine/sysarch.h> > + > +int > +amd64_set_gsbase(void *base) > +{ > + return sysarch(AMD64_SET_GSBASE, &base); > +} > Index: lib/libpthread/Makefile > =================================================================== > RCS file: /home/cvs/src/regress/lib/libpthread/Makefile,v > retrieving revision 1.38 > diff -u -p -r1.38 Makefile > --- lib/libpthread/Makefile 13 Apr 2012 19:04:09 -0000 1.38 > +++ lib/libpthread/Makefile 14 Apr 2012 10:27:30 -0000 > @@ -12,6 +12,9 @@ SUBDIR= barrier blocked_close blocked_du > readdir restart select semaphore setjmp setsockopt sigdeliver siginfo \ > siginterrupt signal signals signodefer sigsuspend sigwait sleep \ > socket stack stdarg stdio switch system > +.if ${MACHINE_ARCH} == "amd64" > +SUBDIR+=amd64_set_gsbase > +.endif > > # Not available or disabled: fcntl, getaddrinfo, pause, pw, sigmask, > stdfiles > > Index: lib/libpthread/amd64_set_gsbase/Makefile > =================================================================== > RCS file: lib/libpthread/amd64_set_gsbase/Makefile > diff -N lib/libpthread/amd64_set_gsbase/Makefile > --- /dev/null 1 Jan 1970 00:00:00 -0000 > +++ lib/libpthread/amd64_set_gsbase/Makefile 14 Apr 2012 10:54:33 -0000 > @@ -0,0 +1,10 @@ > +# $OpenBSD$ > + > +PROG= amd64_set_gsbase > + > +LIBARCH= /usr/lib/libamd64.a > + > +LDADD+= ${LIBARCH} > +DPADD+= ${LIBARCH} > + > +.include <bsd.regress.mk> > Index: lib/libpthread/amd64_set_gsbase/amd64_set_gsbase.c > =================================================================== > RCS file: lib/libpthread/amd64_set_gsbase/amd64_set_gsbase.c > diff -N lib/libpthread/amd64_set_gsbase/amd64_set_gsbase.c > --- /dev/null 1 Jan 1970 00:00:00 -0000 > +++ lib/libpthread/amd64_set_gsbase/amd64_set_gsbase.c 14 Apr 2012 > 11:25:53 -0000 > @@ -0,0 +1,52 @@ > +/* $OpenBSD$ */ > + > +/* > + * Public domain. Written by Mike Belopuhov. > + * > + * Test amd64_set_gsbase and amd64_get_gsbase > + */ > + > +#include <sys/types.h> > +#include <machine/sysarch.h> > +#include <pthread.h> > +#include <stdio.h> > +#include <stdlib.h> > +#include <unistd.h> > +#include "test.h" > + > +#define NTHREADS 128 > + > +void * > +new_thread(void *arg) > +{ > + int *val = NULL; > + > + amd64_set_gsbase(arg); > + > + pthread_yield(); > + sleep(arc4random_uniform(10)); > + pthread_yield(); > + > + amd64_get_gsbase((void **)&val); > + > + ASSERT(val == arg); > + > + return (NULL); > +} > + > +int > +main(int argc, char *argv[]) > +{ > + pthread_t threads[NTHREADS]; > + int vals[NTHREADS]; > + int i; > + > + for (i = 0; i < NTHREADS; i++) { > + CHECKr(pthread_create(&threads[i], NULL, new_thread, > + (void *)&vals[i])); > + } > + for (i = 0; i < NTHREADS; i++) { > + CHECKr(pthread_join(threads[i], NULL)); > + } > + SUCCEED; > +}