diff --git a/lib/libc/amd64/sys/Makefile.inc b/lib/libc/amd64/sys/Makefile.inc index 5115819..7ba6d3a 100644 --- a/lib/libc/amd64/sys/Makefile.inc +++ b/lib/libc/amd64/sys/Makefile.inc @@ -1,10 +1,12 @@ # from: Makefile.inc,v 1.1 1993/09/03 19:04:23 jtc Exp # $FreeBSD$ -SRCS+= amd64_get_fsbase.c amd64_get_gsbase.c amd64_set_fsbase.c amd64_set_gsbase.c +SRCS+= amd64_get_fsbase.c amd64_get_gsbase.c amd64_set_fsbase.c \ + amd64_set_gsbase.c -MDASM= vfork.S brk.S cerror.S exect.S getcontext.S pipe.S ptrace.S \ - reboot.S sbrk.S setlogin.S sigreturn.S +MDASM= vfork.S brk.S cerror.S exect.S getcontext.S getcontext_freebsd7.S \ + pipe.S ptrace.S reboot.S sbrk.S setlogin.S sigreturn.S \ + sigreturn_freebsd7.S # Don't generate default code for these syscalls: NOASM= break.o exit.o getdomainname.o getlogin.o openbsd_poll.o \ diff --git a/lib/libc/amd64/sys/getcontext_freebsd7.S b/lib/libc/amd64/sys/getcontext_freebsd7.S new file mode 100644 index 0000000..b800eb4 --- /dev/null +++ b/lib/libc/amd64/sys/getcontext_freebsd7.S @@ -0,0 +1,55 @@ +/*- + * Copyright (c) 2003 Peter Wemm + * 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 +__FBSDID("$FreeBSD$"); + +#include +#include "syscalls_vers.S" + +/* + * This has to be magic to handle the multiple returns. + * Otherwise, the setcontext() syscall will return here and we'll + * pop off the return address and go to the *setcontext* call. + */ + .weak _getcontext_freebsd7 + .set _getcontext_freebsd7,__sys_getcontext_freebsd7 + .weak getcontext_freebsd7 + .set getcontext_freebsd7,__sys_getcontext_freebsd7 +ENTRY(__sys_getcontext_freebsd7) + movq (%rsp),%rsi /* save getcontext return address */ + mov $SYS_getcontext_freebsd7,%rax + KERNCALL + jb 1f + addq $8,%rsp /* remove stale (setcontext) return address */ + jmp *%rsi /* restore return address */ +1: +#ifdef PIC + movq PIC_GOT(HIDENAME(cerror)),%rdx + jmp *%rdx +#else + jmp HIDENAME(cerror) +#endif diff --git a/lib/libc/amd64/sys/sigreturn_freebsd7.S b/lib/libc/amd64/sys/sigreturn_freebsd7.S new file mode 100644 index 0000000..43c2b79 --- /dev/null +++ b/lib/libc/amd64/sys/sigreturn_freebsd7.S @@ -0,0 +1,48 @@ +/*- + * Copyright (c) 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. + * 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. + */ + +#if defined(SYSLIBC_SCCS) && !defined(lint) + .asciz "@(#)sigreturn.s 5.2 (Berkeley) 12/17/90" +#endif /* SYSLIBC_SCCS and not lint */ +#include +__FBSDID("$FreeBSD$"); + +#include "SYS.h" +#include "syscalls_vers.S" + +/* + * NOTE: If the profiling ENTRY() code ever changes any registers, they + * must be saved. On FreeBSD, this is not the case. + */ + +RSYSCALL(sigreturn_freebsd7) + diff --git a/lib/libc/i386/sys/Makefile.inc b/lib/libc/i386/sys/Makefile.inc index 8da2ab8..183574b 100644 --- a/lib/libc/i386/sys/Makefile.inc +++ b/lib/libc/i386/sys/Makefile.inc @@ -8,8 +8,9 @@ SRCS+= i386_clr_watch.c i386_get_ioperm.c \ SRCS+= i386_get_fsbase.c i386_get_gsbase.c i386_get_ldt.c \ i386_set_fsbase.c i386_set_gsbase.c i386_set_ldt.c -MDASM= Ovfork.S brk.S cerror.S exect.S getcontext.S pipe.S ptrace.S \ - reboot.S sbrk.S setlogin.S sigreturn.S syscall.S +MDASM= Ovfork.S brk.S cerror.S exect.S getcontext.S getcontext_freebsd7.S \ + pipe.S ptrace.S reboot.S sbrk.S setlogin.S sigreturn.S \ + sigreturn_freebsd7.S syscall.S # Don't generate default code for these syscalls: NOASM= break.o exit.o getdomainname.o getlogin.o openbsd_poll.o \ diff --git a/lib/libc/i386/sys/getcontext_freebsd7.S b/lib/libc/i386/sys/getcontext_freebsd7.S new file mode 100644 index 0000000..ae2a69e --- /dev/null +++ b/lib/libc/i386/sys/getcontext_freebsd7.S @@ -0,0 +1,51 @@ +/*- + * Copyright (c) 2003 Peter Wemm + * 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 +__FBSDID("$FreeBSD$"); + +#include +#include "syscalls_vers.S" + +/* + * This has to be magic to handle the multiple returns. + * Otherwise, the setcontext() syscall will return here and we'll + * pop off the return address and go to the *setcontext* call. + */ + .weak _getcontext_freebsd7 + .set _getcontext_freebsd7,__sys_getcontext_freebsd7 + .weak getcontext_freebsd7 + .set getcontext_freebsd7,__sys_getcontext_freebsd7 +ENTRY(__sys_getcontext_freebsd7) + movl (%esp),%ecx /* save getcontext return address */ + mov $SYS_getcontext_freebsd7,%eax + KERNCALL + jb 1f + addl $4,%esp /* remove stale (setcontext) return address */ + jmp *%ecx /* restore return address */ +1: + PIC_PROLOGUE + jmp PIC_PLT(HIDENAME(cerror)) diff --git a/lib/libc/i386/sys/sigreturn_freebsd7.S b/lib/libc/i386/sys/sigreturn_freebsd7.S new file mode 100644 index 0000000..7f7e1c7 --- /dev/null +++ b/lib/libc/i386/sys/sigreturn_freebsd7.S @@ -0,0 +1,47 @@ +/*- + * Copyright (c) 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. + * 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. + */ + +#if defined(SYSLIBC_SCCS) && !defined(lint) + .asciz "@(#)sigreturn.s 5.2 (Berkeley) 12/17/90" +#endif /* SYSLIBC_SCCS and not lint */ +#include +__FBSDID("$FreeBSD$"); + +#include "SYS.h" +#include "syscalls_vers.S" + +/* + * NOTE: If the profiling ENTRY() code ever changes any registers, they + * must be saved. On FreeBSD, this is not the case. + */ + +RSYSCALL(sigreturn_freebsd7) diff --git a/lib/libc/sys/Makefile.inc b/lib/libc/sys/Makefile.inc index f84ce13..da9c4f6 100644 --- a/lib/libc/sys/Makefile.inc +++ b/lib/libc/sys/Makefile.inc @@ -48,15 +48,17 @@ SPSEUDO= ${PSEUDO:S/.o/.S/} SRCS+= ${SASM} ${SPSEUDO} SYM_MAPS+= ${.CURDIR}/sys/Symbol.map +CFLAGS+= -I${.CURDIR}/sys # Generated files CLEANFILES+= ${SASM} ${SPSEUDO} ${SASM}: - printf '#include "SYS.h"\nRSYSCALL(${.PREFIX})\n' > ${.TARGET} + printf '#include "SYS.h"\n#include "syscalls_vers.S"\nRSYSCALL(${.PREFIX})\n' \ + > ${.TARGET} ${SPSEUDO}: - printf '#include "SYS.h"\nPSEUDO(${.PREFIX:S/_//})\n' \ + printf '#include "SYS.h"\n#include "syscalls_vers.S"\nPSEUDO(${.PREFIX:S/_//})\n' \ > ${.TARGET} MAN+= abort2.2 accept.2 access.2 acct.2 adjtime.2 \ diff --git a/lib/libc/sys/Symbol.map b/lib/libc/sys/Symbol.map index 5217ab0..29fb998 100644 --- a/lib/libc/sys/Symbol.map +++ b/lib/libc/sys/Symbol.map @@ -101,7 +101,6 @@ FBSD_1.0 { getaudit; getaudit_addr; getauid; - getcontext; getdents; getdirentries; getdtablesize; @@ -247,7 +246,6 @@ FBSD_1.0 { setaudit; setaudit_addr; setauid; - setcontext; setegid; seteuid; setgid; @@ -271,12 +269,10 @@ FBSD_1.0 { shmget; shmsys; shutdown; - sigaction; sigaltstack; sigpending; sigprocmask; sigqueue; - sigreturn; sigsuspend; sigtimedwait; sigwait; @@ -288,14 +284,12 @@ FBSD_1.0 { __stack_chk_guard; stat; statfs; - swapcontext; swapoff; swapon; symlink; sync; sysarch; syscall; - thr_create; thr_exit; thr_kill; thr_kill2; @@ -342,6 +336,7 @@ FBSD_1.1 { fexecve; fstatat; futimesat; + getcontext; linkat; mkdirat; mkfifoat; @@ -349,8 +344,13 @@ FBSD_1.1 { openat; readlinkat; renameat; + setcontext; setfib; + sigaction; + sigreturn; + swapcontext; symlinkat; + thr_create; unlinkat; }; diff --git a/lib/libc/sys/syscalls_vers.S b/lib/libc/sys/syscalls_vers.S new file mode 100644 index 0000000..b96204c --- /dev/null +++ b/lib/libc/sys/syscalls_vers.S @@ -0,0 +1,35 @@ +/*- + * Copyright (c) 2008 Konstantin Belousov + * 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. + * + * $FreeBSD$ + */ + +#define SYSCALL_VER(ext, hidden, ver) \ + .symver hidden,ext @ ver + +SYSCALL_VER(getcontext, getcontext_freebsd7, FBSD_1.0); +SYSCALL_VER(sigaction, sigaction_freebsd7, FBSD_1.0); +SYSCALL_VER(setcontext, setcontext_freebsd7, FBSD_1.0); +SYSCALL_VER(sigreturn, sigreturn_freebsd7, FBSD_1.0); +SYSCALL_VER(swapcontext, swapcontext_freebsd7, FBSD_1.0); +SYSCALL_VER(thr_create, thr_create_freebsd7, FBSD_1.0); diff --git a/sys/amd64/amd64/cpu_switch.S b/sys/amd64/amd64/cpu_switch.S index 99d6716..27439d3 100644 --- a/sys/amd64/amd64/cpu_switch.S +++ b/sys/amd64/amd64/cpu_switch.S @@ -75,8 +75,6 @@ ENTRY(cpu_throw) 1: movq TD_PCB(%rdi),%r8 /* Old pcb */ movl PCPU(CPUID), %eax - movq PCB_FSBASE(%r8),%r9 - movq PCB_GSBASE(%r8),%r10 /* release bit from old pm_active */ movq TD_PROC(%rdi), %rdx /* oldtd->td_proc */ movq P_VMSPACE(%rdx), %rdx /* proc->p_vmspace */ @@ -110,28 +108,6 @@ ENTRY(cpu_switch) movq %rbx,PCB_RBX(%r8) movq %rax,PCB_RIP(%r8) - /* - * Reread fs and gs bases. Explicit fs segment register load - * by the usermode code may change actual fs base without - * updating pcb_{fs,gs}base. - * - * %rdx still contains the mtx, save %rdx around rdmsr. - */ - movq %rdx,%r11 - movl $MSR_FSBASE,%ecx - rdmsr - shlq $32,%rdx - leaq (%rax,%rdx),%r9 - movl $MSR_KGSBASE,%ecx - rdmsr - shlq $32,%rdx - leaq (%rax,%rdx),%r10 - movq %r11,%rdx - - testl $PCB_32BIT,PCB_FLAGS(%r8) - jnz store_seg -done_store_seg: - testl $PCB_DBREGS,PCB_FLAGS(%r8) jnz store_dr /* static predict not taken */ done_store_dr: @@ -192,35 +168,66 @@ sw1: testl $TDP_KTHREAD,TD_PFLAGS(%rsi) jnz do_kthread - testl $PCB_32BIT,PCB_FLAGS(%r8) - jnz load_seg -done_load_seg: - - cmpq PCB_FSBASE(%r8),%r9 - jz 1f - /* Restore userland %fs */ - movl $MSR_FSBASE,%ecx + /* + * Load ldt register + */ + movq TD_PROC(%rsi),%rcx + cmpq $0, P_MD+MD_LDT(%rcx) + je 1f + movq PCPU(LDT),%rax + movq P_MD+MD_LDT_SD(%rcx),%rdx + movq %rdx,(%rax) + movq P_MD+MD_LDT_SD+8(%rcx),%rdx + movq %rdx,8(%rax) + movl $LDTSEL,%eax + jmp 2f +1: xorl %eax,%eax +2: lldt %ax + + /* Restore fs base in GDT */ movl PCB_FSBASE(%r8),%eax - movl PCB_FSBASE+4(%r8),%edx - wrmsr -1: - cmpq PCB_GSBASE(%r8),%r10 - jz 2f - /* Restore userland %gs */ - movl $MSR_KGSBASE,%ecx + movq PCPU(FS32P),%rdx + movw %ax,2(%rdx) + shrl $16,%eax + movb %al,4(%rdx) + shrl $8,%eax + movb %al,7(%rdx) + + /* Restore gs base in GDT */ movl PCB_GSBASE(%r8),%eax - movl PCB_GSBASE+4(%r8),%edx - wrmsr -2: + movq PCPU(GS32P),%rdx + movw %ax,2(%rdx) + shrl $16,%eax + movb %al,4(%rdx) + shrl $8,%eax + movb %al,7(%rdx) -do_tss: +do_kthread: +do_tss: movq PCPU(TSSP),%rax + movq PCB_TSSP(%r8),%rdx + testq %rdx,%rdx + jnz 1f + movq PCPU(COMMONTSSP),%rdx +1: cmpq %rax,%rdx + jz 2f + movq %rdx,PCPU(TSSP) + movq %rdx,%rcx + movq PCPU(TSS),%rax + movw %rcx,2(%rax) + shrq $16,%rcx + movb %cl,4(%rax) + shrq $8,%rcx + movb %cl,7(%rax) + shrq $8,%rcx + movl %ecx,8(%rax) + movb $0x89,5(%rax) /* unset busy */ + movl $TSSSEL,%eax + ltr %ax /* Update the TSS_RSP0 pointer for the next interrupt */ - movq PCPU(TSSP), %rax - movq %r8, PCPU(RSP0) +2: movq %r8, PCPU(RSP0) movq %r8, PCPU(CURPCB) - addq $COMMON_TSS_RSP0, %rax movq %rsi, PCPU(CURTHREAD) /* into next thread */ - movq %r8, (%rax) + movq %r8, COMMON_TSS_RSP0(%rdx) /* Test if debug registers should be restored. */ testl $PCB_DBREGS,PCB_FLAGS(%r8) @@ -249,45 +256,6 @@ done_load_dr: * We use jumps rather than call in order to avoid the stack. */ -do_kthread: - /* - * Copy old fs/gsbase to new kthread pcb for future switches - * This maintains curpcb->pcb_[fg]sbase as caches of the MSR - */ - movq %r9,PCB_FSBASE(%r8) - movq %r10,PCB_GSBASE(%r8) - jmp do_tss - -store_seg: - movl %gs,PCB_GS(%r8) - testl $PCB_GS32BIT,PCB_FLAGS(%r8) - jnz 2f -1: movl %ds,PCB_DS(%r8) - movl %es,PCB_ES(%r8) - movl %fs,PCB_FS(%r8) - jmp done_store_seg -2: movq PCPU(GS32P),%rax - movq (%rax),%rax - movq %rax,PCB_GS32SD(%r8) - jmp 1b - -load_seg: - testl $PCB_GS32BIT,PCB_FLAGS(%r8) - jnz 2f -1: movl $MSR_GSBASE,%ecx - rdmsr - movl PCB_GS(%r8),%gs - wrmsr - movl PCB_DS(%r8),%ds - movl PCB_ES(%r8),%es - movl PCB_FS(%r8),%fs - jmp done_load_seg - /* Restore userland %gs while preserving kernel gsbase */ -2: movq PCPU(GS32P),%rax - movq PCB_GS32SD(%r8),%rcx - movq %rcx,(%rax) - jmp 1b - store_dr: movq %dr7,%rax /* yes, do the save */ movq %dr0,%r15 diff --git a/sys/amd64/amd64/db_interface.c b/sys/amd64/amd64/db_interface.c index b297616..287c236 100644 --- a/sys/amd64/amd64/db_interface.c +++ b/sys/amd64/amd64/db_interface.c @@ -139,7 +139,11 @@ void db_show_mdpcpu(struct pcpu *pc) { -#if 0 - db_printf("currentldt = 0x%x\n", pc->pc_currentldt); -#endif + db_printf("curpmap = %p\n", pc->pc_curpmap); + db_printf("tssp = %p\n", pc->pc_tssp); + db_printf("commontssp = %p\n", pc->pc_commontssp); + db_printf("rsp0 = 0x%lx\n", pc->pc_rsp0); + db_printf("gs32p = %p\n", pc->pc_gs32p); + db_printf("ldt = %p\n", pc->pc_ldt); + db_printf("tss = %p\n", pc->pc_tss); } diff --git a/sys/amd64/amd64/db_trace.c b/sys/amd64/amd64/db_trace.c index c4e552d..6789d04 100644 --- a/sys/amd64/amd64/db_trace.c +++ b/sys/amd64/amd64/db_trace.c @@ -67,12 +67,10 @@ static db_varfcn_t db_ss; #define DB_OFFSET(x) (db_expr_t *)offsetof(struct trapframe, x) struct db_variable db_regs[] = { { "cs", DB_OFFSET(tf_cs), db_frame }, -#if 0 { "ds", DB_OFFSET(tf_ds), db_frame }, { "es", DB_OFFSET(tf_es), db_frame }, { "fs", DB_OFFSET(tf_fs), db_frame }, { "gs", DB_OFFSET(tf_gs), db_frame }, -#endif { "ss", NULL, db_ss }, { "rax", DB_OFFSET(tf_rax), db_frame }, { "rcx", DB_OFFSET(tf_rcx), db_frame }, @@ -92,7 +90,7 @@ struct db_variable db_regs[] = { { "r15", DB_OFFSET(tf_r15), db_frame }, { "rip", DB_OFFSET(tf_rip), db_frame }, { "rflags", DB_OFFSET(tf_rflags), db_frame }, -#define DB_N_SHOW_REGS 20 /* Don't show registers after here. */ +#define DB_N_SHOW_REGS 24 /* Don't show registers after here. */ { "dr0", NULL, db_dr0 }, { "dr1", NULL, db_dr1 }, { "dr2", NULL, db_dr2 }, diff --git a/sys/amd64/amd64/exception.S b/sys/amd64/amd64/exception.S index fd0a7ca..9ce2458 100644 --- a/sys/amd64/amd64/exception.S +++ b/sys/amd64/amd64/exception.S @@ -42,6 +42,7 @@ #include #include #include +#include #include "assym.s" @@ -185,6 +186,10 @@ alltraps_pushregs_no_rdi: movq %r13,TF_R13(%rsp) movq %r14,TF_R14(%rsp) movq %r15,TF_R15(%rsp) + movl %fs,TF_FS(%rsp) + movl %gs,TF_GS(%rsp) + movl %es,TF_ES(%rsp) + movl %ds,TF_DS(%rsp) FAKE_MCOUNT(TF_RIP(%rsp)) #ifdef KDTRACE_HOOKS /* @@ -252,6 +257,10 @@ IDTVEC(dblfault) movq %r13,TF_R13(%rsp) movq %r14,TF_R14(%rsp) movq %r15,TF_R15(%rsp) + movl %fs,TF_FS(%rsp) + movl %gs,TF_GS(%rsp) + movl %es,TF_ES(%rsp) + movl %ds,TF_DS(%rsp) testb $SEL_RPL_MASK,TF_CS(%rsp) /* Did we come from kernel? */ jz 1f /* already running with kernel GS.base */ swapgs @@ -288,13 +297,23 @@ IDTVEC(prot) movq %rdi,TF_RDI(%rsp) /* free up a GP register */ leaq doreti_iret(%rip),%rdi cmpq %rdi,TF_RIP(%rsp) - je 2f /* kernel but with user gsbase!! */ + je 1f /* kernel but with user gsbase!! */ + leaq ld_gs(%rip),%rdi + cmpq %rdi,TF_RIP(%rsp) + je 1f + leaq ld_fs(%rip),%rdi + cmpq %rdi,TF_RIP(%rsp) + je 1f + leaq ld_es(%rip),%rdi + cmpq %rdi,TF_RIP(%rsp) + je 1f + leaq ld_ds(%rip),%rdi + cmpq %rdi,TF_RIP(%rsp) + je 1f testb $SEL_RPL_MASK,TF_CS(%rsp) /* Did we come from kernel? */ - jz 1f /* already running with kernel GS.base */ -2: - swapgs -1: - testl $PSL_I,TF_RFLAGS(%rsp) + jz 2f /* already running with kernel GS.base */ +1: swapgs +2: testl $PSL_I,TF_RFLAGS(%rsp) jz alltraps_pushregs_no_rdi sti jmp alltraps_pushregs_no_rdi @@ -333,40 +352,14 @@ IDTVEC(fast_syscall) movq %r13,TF_R13(%rsp) /* C preserved */ movq %r14,TF_R14(%rsp) /* C preserved */ movq %r15,TF_R15(%rsp) /* C preserved */ + movl %fs,TF_FS(%rsp) + movl %gs,TF_GS(%rsp) + movl %es,TF_ES(%rsp) + movl %ds,TF_DS(%rsp) FAKE_MCOUNT(TF_RIP(%rsp)) movq %rsp, %rdi call syscall movq PCPU(CURPCB),%rax - testq $PCB_FULLCTX,PCB_FLAGS(%rax) - jne 3f -1: /* Check for and handle AST's on return to userland */ - cli - movq PCPU(CURTHREAD),%rax - testl $TDF_ASTPENDING | TDF_NEEDRESCHED,TD_FLAGS(%rax) - je 2f - sti - movq %rsp, %rdi - call ast - jmp 1b -2: /* restore preserved registers */ - MEXITCOUNT - movq TF_RDI(%rsp),%rdi /* bonus; preserve arg 1 */ - movq TF_RSI(%rsp),%rsi /* bonus: preserve arg 2 */ - movq TF_RDX(%rsp),%rdx /* return value 2 */ - movq TF_RAX(%rsp),%rax /* return value 1 */ - movq TF_RBX(%rsp),%rbx /* C preserved */ - movq TF_RBP(%rsp),%rbp /* C preserved */ - movq TF_R12(%rsp),%r12 /* C preserved */ - movq TF_R13(%rsp),%r13 /* C preserved */ - movq TF_R14(%rsp),%r14 /* C preserved */ - movq TF_R15(%rsp),%r15 /* C preserved */ - movq TF_RFLAGS(%rsp),%r11 /* original %rflags */ - movq TF_RIP(%rsp),%rcx /* original %rip */ - movq TF_RSP(%rsp),%r9 /* user stack pointer */ - movq %r9,%rsp /* original %rsp */ - swapgs - sysretq -3: /* Requested full context restore, use doreti for that */ andq $~PCB_FULLCTX,PCB_FLAGS(%rax) MEXITCOUNT jmp doreti @@ -421,6 +414,10 @@ IDTVEC(nmi) movq %r13,TF_R13(%rsp) movq %r14,TF_R14(%rsp) movq %r15,TF_R15(%rsp) + movl %fs,TF_FS(%rsp) + movl %gs,TF_GS(%rsp) + movl %es,TF_ES(%rsp) + movl %ds,TF_DS(%rsp) xorl %ebx,%ebx testb $SEL_RPL_MASK,TF_CS(%rsp) jnz nmi_needswapgs /* we came from userland */ @@ -601,6 +598,40 @@ doreti_ast: */ doreti_exit: MEXITCOUNT + movq PCPU(CURTHREAD),%r8 + movq TD_PCB(%r8),%r8 + + /* Restore %fs and fsbase */ + movl TF_FS(%rsp),%eax + .globl ld_fs +ld_fs: movl %eax,%fs + cmpw $KUF32SEL,%ax + jne 1f + movl $MSR_FSBASE,%ecx + movl PCB_FSBASE(%r8),%eax + movl PCB_FSBASE+4(%r8),%edx + wrmsr +1: + /* Restore %gs and gsbase */ + movl TF_GS(%rsp),%esi + pushfq + cli + movl $MSR_GSBASE,%ecx + rdmsr + .globl ld_gs +ld_gs: movl %esi,%gs + wrmsr + popfq + cmpw $KUG32SEL,%si + jne 1f + movl $MSR_KGSBASE,%ecx + movl PCB_GSBASE(%r8),%eax + movl PCB_GSBASE+4(%r8),%edx + wrmsr +1: .globl ld_es +ld_es: movl TF_ES(%rsp),%es + .globl ld_ds +ld_ds: movl TF_DS(%rsp),%ds movq TF_RDI(%rsp),%rdi movq TF_RSI(%rsp),%rsi movq TF_RDX(%rsp),%rdx @@ -639,7 +670,11 @@ doreti_iret_fault: testl $PSL_I,TF_RFLAGS(%rsp) jz 1f sti -1: movq %rdi,TF_RDI(%rsp) +1: movl %fs,TF_FS(%rsp) + movl %gs,TF_GS(%rsp) + movl %es,TF_ES(%rsp) + movl %ds,TF_DS(%rsp) + movq %rdi,TF_RDI(%rsp) movq %rsi,TF_RSI(%rsp) movq %rdx,TF_RDX(%rsp) movq %rcx,TF_RCX(%rsp) @@ -659,6 +694,40 @@ doreti_iret_fault: movq $0,TF_ADDR(%rsp) FAKE_MCOUNT(TF_RIP(%rsp)) jmp calltrap + + ALIGN_TEXT + .globl ds_load_fault +ds_load_fault: + movq $T_PROTFLT,TF_TRAPNO(%rsp) + movl TF_DS(%rsp),%edx + movl %edx,TF_ERR(%rsp) + movl $KUDSEL,TF_FS(%rsp) + jmp calltrap + + ALIGN_TEXT + .globl es_load_fault +es_load_fault: + movl TF_ES(%rsp),%edx + movl %edx,TF_ERR(%rsp) + movl $KUDSEL,TF_FS(%rsp) + jmp calltrap + + ALIGN_TEXT + .globl fs_load_fault +fs_load_fault: + movl TF_FS(%rsp),%edx + movl %edx,TF_ERR(%rsp) + movl $KUF32SEL,TF_FS(%rsp) + jmp calltrap + + ALIGN_TEXT + .globl gs_load_fault +gs_load_fault: + popfq + movl TF_GS(%rsp),%edx + movl %edx,TF_ERR(%rsp) + movl $KUG32SEL,TF_FS(%rsp) + jmp calltrap #ifdef HWPMC_HOOKS ENTRY(end_exceptions) #endif diff --git a/sys/amd64/amd64/genassym.c b/sys/amd64/amd64/genassym.c index f749dd6..1c4415e 100644 --- a/sys/amd64/amd64/genassym.c +++ b/sys/amd64/amd64/genassym.c @@ -75,6 +75,10 @@ ASSYM(P_VMSPACE, offsetof(struct proc, p_vmspace)); ASSYM(VM_PMAP, offsetof(struct vmspace, vm_pmap)); ASSYM(PM_ACTIVE, offsetof(struct pmap, pm_active)); +ASSYM(P_MD, offsetof(struct proc, p_md)); +ASSYM(MD_LDT, offsetof(struct mdproc, md_ldt)); +ASSYM(MD_LDT_SD, offsetof(struct mdproc, md_ldt_sd)); + ASSYM(TD_LOCK, offsetof(struct thread, td_lock)); ASSYM(TD_FLAGS, offsetof(struct thread, td_flags)); ASSYM(TD_PCB, offsetof(struct thread, td_pcb)); @@ -128,16 +132,13 @@ ASSYM(PCB_RBX, offsetof(struct pcb, pcb_rbx)); ASSYM(PCB_RIP, offsetof(struct pcb, pcb_rip)); ASSYM(PCB_FSBASE, offsetof(struct pcb, pcb_fsbase)); ASSYM(PCB_GSBASE, offsetof(struct pcb, pcb_gsbase)); -ASSYM(PCB_DS, offsetof(struct pcb, pcb_ds)); -ASSYM(PCB_ES, offsetof(struct pcb, pcb_es)); -ASSYM(PCB_FS, offsetof(struct pcb, pcb_fs)); -ASSYM(PCB_GS, offsetof(struct pcb, pcb_gs)); ASSYM(PCB_DR0, offsetof(struct pcb, pcb_dr0)); ASSYM(PCB_DR1, offsetof(struct pcb, pcb_dr1)); ASSYM(PCB_DR2, offsetof(struct pcb, pcb_dr2)); ASSYM(PCB_DR3, offsetof(struct pcb, pcb_dr3)); ASSYM(PCB_DR6, offsetof(struct pcb, pcb_dr6)); ASSYM(PCB_DR7, offsetof(struct pcb, pcb_dr7)); +ASSYM(PCB_TSSP, offsetof(struct pcb, pcb_tssp)); ASSYM(PCB_DBREGS, PCB_DBREGS); ASSYM(PCB_32BIT, PCB_32BIT); ASSYM(PCB_GS32BIT, PCB_GS32BIT); @@ -176,6 +177,10 @@ ASSYM(TF_CS, offsetof(struct trapframe, tf_cs)); ASSYM(TF_RFLAGS, offsetof(struct trapframe, tf_rflags)); ASSYM(TF_RSP, offsetof(struct trapframe, tf_rsp)); ASSYM(TF_SS, offsetof(struct trapframe, tf_ss)); +ASSYM(TF_DS, offsetof(struct trapframe, tf_ds)); +ASSYM(TF_ES, offsetof(struct trapframe, tf_es)); +ASSYM(TF_FS, offsetof(struct trapframe, tf_fs)); +ASSYM(TF_GS, offsetof(struct trapframe, tf_gs)); ASSYM(TF_SIZE, sizeof(struct trapframe)); ASSYM(SIGF_HANDLER, offsetof(struct sigframe, sf_ahu.sf_handler)); @@ -198,7 +203,11 @@ ASSYM(PC_SCRATCH_RSP, offsetof(struct pcpu, pc_scratch_rsp)); ASSYM(PC_CURPMAP, offsetof(struct pcpu, pc_curpmap)); ASSYM(PC_TSSP, offsetof(struct pcpu, pc_tssp)); ASSYM(PC_RSP0, offsetof(struct pcpu, pc_rsp0)); +ASSYM(PC_FS32P, offsetof(struct pcpu, pc_fs32p)); ASSYM(PC_GS32P, offsetof(struct pcpu, pc_gs32p)); +ASSYM(PC_LDT, offsetof(struct pcpu, pc_ldt)); +ASSYM(PC_COMMONTSSP, offsetof(struct pcpu, pc_commontssp)); +ASSYM(PC_TSS, offsetof(struct pcpu, pc_tss)); ASSYM(LA_VER, offsetof(struct LAPIC, version)); ASSYM(LA_TPR, offsetof(struct LAPIC, tpr)); @@ -213,6 +222,10 @@ ASSYM(KDSEL, GSEL(GDATA_SEL, SEL_KPL)); ASSYM(KUCSEL, GSEL(GUCODE_SEL, SEL_UPL)); ASSYM(KUDSEL, GSEL(GUDATA_SEL, SEL_UPL)); ASSYM(KUC32SEL, GSEL(GUCODE32_SEL, SEL_UPL)); +ASSYM(KUF32SEL, GSEL(GUFS32_SEL, SEL_UPL)); +ASSYM(KUG32SEL, GSEL(GUGS32_SEL, SEL_UPL)); +ASSYM(TSSSEL, GSEL(GPROC0_SEL, SEL_KPL)); +ASSYM(LDTSEL, GSEL(GUSERLDT_SEL, SEL_KPL)); ASSYM(SEL_RPL_MASK, SEL_RPL_MASK); ASSYM(MSR_GSBASE, MSR_GSBASE); diff --git a/sys/amd64/amd64/machdep.c b/sys/amd64/amd64/machdep.c index 988b039..54ee69e 100644 --- a/sys/amd64/amd64/machdep.c +++ b/sys/amd64/amd64/machdep.c @@ -149,6 +149,8 @@ extern void panicifcpuunsupported(void); static void cpu_startup(void *); static void get_fpcontext(struct thread *td, mcontext_t *mcp); static int set_fpcontext(struct thread *td, const mcontext_t *mcp); +static int set_fpcontext7(struct thread *td, const struct __mcontext7 *mcp); +static void get_fpcontext7(struct thread *td, struct __mcontext7 *mcp); SYSINIT(cpu, SI_SUB_CPU, SI_ORDER_FIRST, cpu_startup, NULL); #ifdef DDB @@ -192,6 +194,8 @@ struct mtx icu_lock; struct mem_range_softc mem_range_softc; +struct mtx dt_lock; /* lock for GDT and LDT */ + static void cpu_startup(dummy) void *dummy; @@ -263,11 +267,150 @@ cpu_startup(dummy) cpu_setregs(); } +static void +sf2sf7(const struct sigframe *sf, struct sigframe7 *sf7) +{ + + bzero(sf7, sizeof(sf7)); + bcopy(&sf->sf_ahu, &sf7->sf_ahu, sizeof(sf->sf_ahu)); + bcopy(&sf->sf_si, &sf7->sf_si, sizeof(sf->sf_si)); + sf7->sf_uc.uc_sigmask = sf->sf_uc.uc_sigmask; + sf7->sf_uc.uc_stack = sf->sf_uc.uc_stack; + sf7->sf_uc.uc_stack.ss_flags = sf->sf_uc.uc_stack.ss_flags; + sf7->sf_uc.uc_mcontext.mc_onstack = sf->sf_uc.uc_mcontext.mc_onstack; + sf7->sf_uc.uc_mcontext.mc_rdi = sf->sf_uc.uc_mcontext.mc_rdi; + sf7->sf_uc.uc_mcontext.mc_rsi = sf->sf_uc.uc_mcontext.mc_rsi; + sf7->sf_uc.uc_mcontext.mc_rdx = sf->sf_uc.uc_mcontext.mc_rdx; + sf7->sf_uc.uc_mcontext.mc_rcx = sf->sf_uc.uc_mcontext.mc_rcx; + sf7->sf_uc.uc_mcontext.mc_r8 = sf->sf_uc.uc_mcontext.mc_r8; + sf7->sf_uc.uc_mcontext.mc_r9 = sf->sf_uc.uc_mcontext.mc_r9; + sf7->sf_uc.uc_mcontext.mc_rax = sf->sf_uc.uc_mcontext.mc_rax; + sf7->sf_uc.uc_mcontext.mc_rbx = sf->sf_uc.uc_mcontext.mc_rbx; + sf7->sf_uc.uc_mcontext.mc_rbp = sf->sf_uc.uc_mcontext.mc_rbp; + sf7->sf_uc.uc_mcontext.mc_r10 = sf->sf_uc.uc_mcontext.mc_r10; + sf7->sf_uc.uc_mcontext.mc_r11 = sf->sf_uc.uc_mcontext.mc_r11; + sf7->sf_uc.uc_mcontext.mc_r12 = sf->sf_uc.uc_mcontext.mc_r12; + sf7->sf_uc.uc_mcontext.mc_r13 = sf->sf_uc.uc_mcontext.mc_r13; + sf7->sf_uc.uc_mcontext.mc_r14 = sf->sf_uc.uc_mcontext.mc_r14; + sf7->sf_uc.uc_mcontext.mc_r15 = sf->sf_uc.uc_mcontext.mc_r15; + sf7->sf_uc.uc_mcontext.mc_trapno = sf->sf_uc.uc_mcontext.mc_trapno; + sf7->sf_uc.uc_mcontext.mc_addr = sf->sf_uc.uc_mcontext.mc_addr; + sf7->sf_uc.uc_mcontext.mc_flags = sf->sf_uc.uc_mcontext.mc_flags; + sf7->sf_uc.uc_mcontext.mc_err = sf->sf_uc.uc_mcontext.mc_err; + sf7->sf_uc.uc_mcontext.mc_rip = sf->sf_uc.uc_mcontext.mc_rip; + sf7->sf_uc.uc_mcontext.mc_cs = sf->sf_uc.uc_mcontext.mc_cs; + sf7->sf_uc.uc_mcontext.mc_rflags = sf->sf_uc.uc_mcontext.mc_rflags; + sf7->sf_uc.uc_mcontext.mc_rsp = sf->sf_uc.uc_mcontext.mc_rsp; + sf7->sf_uc.uc_mcontext.mc_ss = sf->sf_uc.uc_mcontext.mc_ss; + /* magic */ + sf7->sf_uc.uc_mcontext.mc_len = sizeof(sf7->sf_uc.uc_mcontext); + sf7->sf_uc.uc_mcontext.mc_fpformat = sf->sf_uc.uc_mcontext.mc_fpformat; + sf7->sf_uc.uc_mcontext.mc_ownedfp = sf->sf_uc.uc_mcontext.mc_ownedfp; + bcopy(&sf->sf_uc.uc_mcontext.mc_fpstate[0], + &sf7->sf_uc.uc_mcontext.mc_fpstate[0], + sizeof(&sf7->sf_uc.uc_mcontext.mc_fpstate)); +} + +static void +sendsig_freebsd7(sig_t catcher, ksiginfo_t *ksi, sigset_t *mask) +{ + struct sigframe sf; + struct sigframe7 sf7, *sfp7; + struct proc *p; + struct thread *td; + struct sigacts *psp; + char *sp; + struct trapframe *regs; + int sig, oonstack, error; + + td = curthread; + 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); + + /* 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); + fpstate_drop(td); + sf2sf7(&sf, &sf7); + + /* Allocate space for the signal handler context. */ + if ((td->td_pflags & TDP_ALTSTACK) != 0 && !oonstack && + SIGISMEMBER(psp->ps_sigonstack, sig)) { + sp = td->td_sigstk.ss_sp + + td->td_sigstk.ss_size - sizeof(struct sigframe7); +#if defined(COMPAT_43) + td->td_sigstk.ss_flags |= SS_ONSTACK; +#endif + } else + sp = (char *)regs->tf_rsp - sizeof(struct sigframe7) - 128; + /* Align to 16 bytes. */ + sfp7 = (struct sigframe7 *)((unsigned long)sp & ~0xFul); + + /* Translate the signal if appropriate. */ + if (p->p_sysent->sv_sigtbl && sig <= p->p_sysent->sv_sigsize) + sig = p->p_sysent->sv_sigtbl[_SIG_IDX(sig)]; + + /* Build the argument list for the signal handler. */ + regs->tf_rdi = sig; /* arg 1 in %rdi */ + regs->tf_rdx = (register_t)&sfp7->sf_uc; /* arg 3 in %rdx */ + if (SIGISMEMBER(psp->ps_siginfo, sig)) { + /* Signal handler installed with SA_SIGINFO. */ + regs->tf_rsi = (register_t)&sfp7->sf_si;/* arg 2 in %rsi */ + sf7.sf_ahu.sf_action = (__siginfohandler_t *)catcher; + /* Fill in POSIX parts */ + sf7.sf_si = ksi->ksi_info; + sf7.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 */ + sf7.sf_ahu.sf_handler = catcher; + } + mtx_unlock(&psp->ps_mtx); + PROC_UNLOCK(p); + + /* + * Copy the sigframe out to the user's stack. + */ + error = copyout(&sf7, sfp7, sizeof(struct sigframe7)); + if (error != 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)sfp7; + regs->tf_rip = PS_STRINGS - szsigcode7; + regs->tf_rflags &= ~(PSL_T | PSL_D); + regs->tf_cs = _ucodesel; + regs->tf_ds = _udatasel; + regs->tf_es = _udatasel; + regs->tf_fs = GSEL(GUFS32_SEL, SEL_UPL); + regs->tf_gs = GSEL(GUGS32_SEL, SEL_UPL); + PROC_LOCK(p); + mtx_lock(&psp->ps_mtx); +} + /* * Send an interrupt to process. * * Stack is set up to allow sigcode stored - * at top to call routine, followed by kcall + * 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 @@ -282,8 +425,7 @@ sendsig(sig_t catcher, ksiginfo_t *ksi, sigset_t *mask) struct sigacts *psp; char *sp; struct trapframe *regs; - int sig; - int oonstack; + int sig, oonstack, error; td = curthread; p = td->td_proc; @@ -291,6 +433,8 @@ sendsig(sig_t catcher, ksiginfo_t *ksi, sigset_t *mask) sig = ksi->ksi_signo; psp = p->p_sigacts; mtx_assert(&psp->ps_mtx, MA_OWNED); + if (SIGISMEMBER(psp->ps_freebsd7, sig)) + sendsig_freebsd7(catcher, ksi, mask); regs = td->td_frame; oonstack = sigonstack(regs->tf_rsp); @@ -299,18 +443,20 @@ sendsig(sig_t catcher, ksiginfo_t *ksi, sigset_t *mask) 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; + ? ((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); 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 && SIGISMEMBER(psp->ps_sigonstack, sig)) { sp = td->td_sigstk.ss_sp + - td->td_sigstk.ss_size - sizeof(struct sigframe); + td->td_sigstk.ss_size - sizeof(struct sigframe); #if defined(COMPAT_43) td->td_sigstk.ss_flags |= SS_ONSTACK; #endif @@ -325,12 +471,11 @@ sendsig(sig_t catcher, ksiginfo_t *ksi, sigset_t *mask) /* 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 */ + regs->tf_rdx = (register_t)&sfp->sf_uc; 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 */ @@ -347,7 +492,8 @@ sendsig(sig_t catcher, ksiginfo_t *ksi, sigset_t *mask) /* * Copy the sigframe out to the user's stack. */ - if (copyout(&sf, sfp, sizeof(*sfp)) != 0) { + error = copyout(&sf, sfp, sizeof(struct sigframe)); + if (error != 0) { #ifdef DEBUG printf("process %ld has trashed its stack\n", (long)p->p_pid); #endif @@ -359,6 +505,10 @@ sendsig(sig_t catcher, ksiginfo_t *ksi, sigset_t *mask) regs->tf_rip = PS_STRINGS - *(p->p_sysent->sv_szsigcode); regs->tf_rflags &= ~(PSL_T | PSL_D); regs->tf_cs = _ucodesel; + regs->tf_ds = _udatasel; + regs->tf_es = _udatasel; + regs->tf_fs = GSEL(GUFS32_SEL, SEL_UPL); + regs->tf_gs = GSEL(GUGS32_SEL, SEL_UPL); PROC_LOCK(p); mtx_lock(&psp->ps_mtx); } @@ -434,7 +584,9 @@ sigreturn(td, uap) if (ret != 0) return (ret); bcopy(&ucp->uc_mcontext.mc_rdi, regs, sizeof(*regs)); - + td->td_pcb->pcb_fsbase = ucp->uc_mcontext.mc_fsbase; + td->td_pcb->pcb_gsbase = ucp->uc_mcontext.mc_gsbase; + PROC_LOCK(p); #if defined(COMPAT_43) if (ucp->uc_mcontext.mc_onstack & 1) @@ -451,6 +603,110 @@ sigreturn(td, uap) return (EJUSTRETURN); } +int +sigreturn_freebsd7(td, uap) + struct thread *td; + struct sigreturn_freebsd7_args /* { + const struct ucontext7 *sigcntxp; + } */ *uap; +{ + struct ucontext7 uc7; + struct proc *p = td->td_proc; + struct trapframe *regs; + const struct ucontext7 *ucp7; + long rflags; + int cs, error, ret; + ksiginfo_t ksi; + + error = copyin(uap->sigcntxp, &uc7, sizeof(uc7)); + if (error != 0) + return (error); + ucp7 = &uc7; + regs = td->td_frame; + rflags = ucp7->uc_mcontext.mc_rflags; + /* + * Don't allow users to change privileged or reserved flags. + */ + /* + * XXX do allow users to change the privileged flag PSL_RF. + * The cpu sets PSL_RF in tf_rflags for faults. Debuggers + * should sometimes set it there too. tf_rflags is kept in + * the signal context during signal handling and there is no + * other place to remember it, so the PSL_RF bit may be + * corrupted by the signal handler without us knowing. + * Corruption of the PSL_RF bit at worst causes one more or + * one less debugger trap, so allowing it is fairly harmless. + */ + if (!EFL_SECURE(rflags & ~PSL_RF, regs->tf_rflags & ~PSL_RF)) { + printf("sigreturn: rflags = 0x%lx\n", 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 = ucp7->uc_mcontext.mc_cs; + if (!CS_SECURE(cs)) { + printf("sigreturn: cs = 0x%x\n", 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); + } + + ret = set_fpcontext7(td, &ucp7->uc_mcontext); + if (ret != 0) + return (ret); + regs->tf_rdi = ucp7->uc_mcontext.mc_rdi; + regs->tf_rsi = ucp7->uc_mcontext.mc_rsi; + regs->tf_rdx = ucp7->uc_mcontext.mc_rdx; + regs->tf_rcx = ucp7->uc_mcontext.mc_rcx; + regs->tf_r8 = ucp7->uc_mcontext.mc_r8; + regs->tf_r9 = ucp7->uc_mcontext.mc_r9; + regs->tf_rax = ucp7->uc_mcontext.mc_rax; + regs->tf_rbx = ucp7->uc_mcontext.mc_rbx; + regs->tf_rbp = ucp7->uc_mcontext.mc_rbp; + regs->tf_r10 = ucp7->uc_mcontext.mc_r10; + regs->tf_r11 = ucp7->uc_mcontext.mc_r11; + regs->tf_r12 = ucp7->uc_mcontext.mc_r12; + regs->tf_r13 = ucp7->uc_mcontext.mc_r13; + regs->tf_r14 = ucp7->uc_mcontext.mc_r14; + regs->tf_r15 = ucp7->uc_mcontext.mc_r15; + regs->tf_trapno = ucp7->uc_mcontext.mc_trapno; + regs->tf_addr = ucp7->uc_mcontext.mc_addr; + regs->tf_flags = ucp7->uc_mcontext.mc_flags; + regs->tf_err = ucp7->uc_mcontext.mc_err; + regs->tf_rip = ucp7->uc_mcontext.mc_rip; + regs->tf_cs = ucp7->uc_mcontext.mc_cs; + regs->tf_rflags = ucp7->uc_mcontext.mc_rflags; + regs->tf_rsp = ucp7->uc_mcontext.mc_rsp; + regs->tf_ss = ucp7->uc_mcontext.mc_ss; + regs->tf_ds = _udatasel; + regs->tf_es = _udatasel; + regs->tf_fs = GSEL(GUFS32_SEL, SEL_UPL); + regs->tf_gs = GSEL(GUGS32_SEL, SEL_UPL); + + PROC_LOCK(p); +#if defined(COMPAT_43) + if (ucp7->uc_mcontext.mc_onstack & 1) + td->td_sigstk.ss_flags |= SS_ONSTACK; + else + td->td_sigstk.ss_flags &= ~SS_ONSTACK; +#endif + + td->td_sigmask = ucp7->uc_sigmask; + SIG_CANTMASK(td->td_sigmask); + signotify(td); + PROC_UNLOCK(p); + td->td_pcb->pcb_flags |= PCB_FULLCTX; + return (EJUSTRETURN); +} + #ifdef COMPAT_FREEBSD4 int freebsd4_sigreturn(struct thread *td, struct freebsd4_sigreturn_args *uap) @@ -727,22 +983,18 @@ exec_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); + bzero(&td->td_proc->p_md.md_ldt_sd, sizeof(struct + system_segment_descriptor)); + } 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(); pcb->pcb_flags &= ~(PCB_32BIT | PCB_GS32BIT); - 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; bzero((char *)regs, sizeof(struct trapframe)); regs->tf_rip = entry; @@ -751,6 +1003,10 @@ exec_setregs(td, entry, stack, ps_strings) regs->tf_rflags = PSL_USER | (regs->tf_rflags & PSL_T); regs->tf_ss = _udatasel; regs->tf_cs = _ucodesel; + regs->tf_ds = _udatasel; + regs->tf_es = _udatasel; + regs->tf_fs = GSEL(GUFS32_SEL, SEL_UPL); + regs->tf_gs = GSEL(GUGS32_SEL, SEL_UPL); /* * Reset the hardware debug registers if they were in use. @@ -814,87 +1070,114 @@ struct amd64tss common_tss[MAXCPU]; /* software prototypes -- in more palatable form */ struct soft_segment_descriptor gdt_segs[] = { /* GNULL_SEL 0 Null Descriptor */ -{ 0x0, /* segment base address */ - 0x0, /* length */ - 0, /* segment type */ - 0, /* segment descriptor priority level */ - 0, /* segment descriptor present */ - 0, /* long */ - 0, /* default 32 vs 16 bit size */ - 0 /* limit granularity (byte/page units)*/ }, +{ .ssd_base = 0x0, + .ssd_limit = 0x0, + .ssd_type = 0, + .ssd_dpl = 0, + .ssd_p = 0, + .ssd_long = 0, + .ssd_def32 = 0, + .ssd_gran = 0 }, /* GCODE_SEL 1 Code Descriptor for kernel */ -{ 0x0, /* segment base address */ - 0xfffff, /* length - all address space */ - SDT_MEMERA, /* segment type */ - SEL_KPL, /* segment descriptor priority level */ - 1, /* segment descriptor present */ - 1, /* long */ - 0, /* default 32 vs 16 bit size */ - 1 /* limit granularity (byte/page units)*/ }, +{ .ssd_base = 0x0, + .ssd_limit = 0xfffff, + .ssd_type = SDT_MEMERA, + .ssd_dpl = SEL_KPL, + .ssd_p = 1, + .ssd_long = 1, + .ssd_def32 = 0, + .ssd_gran = 1 }, /* GDATA_SEL 2 Data Descriptor for kernel */ -{ 0x0, /* segment base address */ - 0xfffff, /* length - all address space */ - SDT_MEMRWA, /* segment type */ - SEL_KPL, /* segment descriptor priority level */ - 1, /* segment descriptor present */ - 1, /* long */ - 0, /* default 32 vs 16 bit size */ - 1 /* limit granularity (byte/page units)*/ }, +{ .ssd_base = 0x0, + .ssd_limit = 0xfffff, + .ssd_type = SDT_MEMRWA, + .ssd_dpl = SEL_KPL, + .ssd_p = 1, + .ssd_long = 1, + .ssd_def32 = 0, + .ssd_gran = 1 }, /* GUCODE32_SEL 3 32 bit Code Descriptor for user */ -{ 0x0, /* segment base address */ - 0xfffff, /* length - all address space */ - SDT_MEMERA, /* segment type */ - SEL_UPL, /* segment descriptor priority level */ - 1, /* segment descriptor present */ - 0, /* long */ - 1, /* default 32 vs 16 bit size */ - 1 /* limit granularity (byte/page units)*/ }, +{ .ssd_base = 0x0, + .ssd_limit = 0xfffff, + .ssd_type = SDT_MEMERA, + .ssd_dpl = SEL_UPL, + .ssd_p = 1, + .ssd_long = 0, + .ssd_def32 = 1, + .ssd_gran = 1 }, /* GUDATA_SEL 4 32/64 bit Data Descriptor for user */ -{ 0x0, /* segment base address */ - 0xfffff, /* length - all address space */ - SDT_MEMRWA, /* segment type */ - SEL_UPL, /* segment descriptor priority level */ - 1, /* segment descriptor present */ - 0, /* long */ - 1, /* default 32 vs 16 bit size */ - 1 /* limit granularity (byte/page units)*/ }, +{ .ssd_base = 0x0, + .ssd_limit = 0xfffff, + .ssd_type = SDT_MEMRWA, + .ssd_dpl = SEL_UPL, + .ssd_p = 1, + .ssd_long = 0, + .ssd_def32 = 1, + .ssd_gran = 1 }, /* GUCODE_SEL 5 64 bit Code Descriptor for user */ -{ 0x0, /* segment base address */ - 0xfffff, /* length - all address space */ - SDT_MEMERA, /* segment type */ - SEL_UPL, /* segment descriptor priority level */ - 1, /* segment descriptor present */ - 1, /* long */ - 0, /* default 32 vs 16 bit size */ - 1 /* limit granularity (byte/page units)*/ }, +{ .ssd_base = 0x0, + .ssd_limit = 0xfffff, + .ssd_type = SDT_MEMERA, + .ssd_dpl = SEL_UPL, + .ssd_p = 1, + .ssd_long = 1, + .ssd_def32 = 0, + .ssd_gran = 1 }, /* GPROC0_SEL 6 Proc 0 Tss Descriptor */ { - 0x0, /* segment base address */ - sizeof(struct amd64tss)-1,/* length */ - SDT_SYSTSS, /* segment type */ - SEL_KPL, /* segment descriptor priority level */ - 1, /* segment descriptor present */ - 0, /* long */ - 0, /* unused - default 32 vs 16 bit size */ - 0 /* limit granularity (byte/page units)*/ }, + .ssd_base = 0x0, + .ssd_limit = sizeof(struct amd64tss) + IOPAGES * PAGE_SIZE - 1, + .ssd_type = SDT_SYSTSS, + .ssd_dpl = SEL_KPL, + .ssd_p = 1, + .ssd_long = 0, + .ssd_def32 = 0, + .ssd_gran = 0 }, /* Actually, the TSS is a system descriptor which is double size */ -{ 0x0, /* segment base address */ - 0x0, /* length */ - 0, /* segment type */ - 0, /* segment descriptor priority level */ - 0, /* segment descriptor present */ - 0, /* long */ - 0, /* default 32 vs 16 bit size */ - 0 /* limit granularity (byte/page units)*/ }, +{ .ssd_base = 0x0, + .ssd_limit = 0x0, + .ssd_type = 0, + .ssd_dpl = 0, + .ssd_p = 0, + .ssd_long = 0, + .ssd_def32 = 0, + .ssd_gran = 0 }, /* GUGS32_SEL 8 32 bit GS Descriptor for user */ -{ 0x0, /* segment base address */ - 0xfffff, /* length - all address space */ - SDT_MEMRWA, /* segment type */ - SEL_UPL, /* segment descriptor priority level */ - 1, /* segment descriptor present */ - 0, /* long */ - 1, /* default 32 vs 16 bit size */ - 1 /* limit granularity (byte/page units)*/ }, +{ .ssd_base = 0x0, + .ssd_limit = 0xfffff, + .ssd_type = SDT_MEMRWA, + .ssd_dpl = SEL_UPL, + .ssd_p = 1, + .ssd_long = 0, + .ssd_def32 = 1, + .ssd_gran = 1 }, +/* GUFS32_SEL 9 32 bit FS Descriptor for user */ +{ .ssd_base = 0x0, + .ssd_limit = 0xfffff, + .ssd_type = SDT_MEMRWA, + .ssd_dpl = SEL_UPL, + .ssd_p = 1, + .ssd_long = 0, + .ssd_def32 = 1, + .ssd_gran = 1 }, +/* GUSERLDT_SEL 10 LDT Descriptor */ +{ .ssd_base = 0x0, + .ssd_limit = 0x0, + .ssd_type = 0, + .ssd_dpl = 0, + .ssd_p = 0, + .ssd_long = 0, + .ssd_def32 = 0, + .ssd_gran = 0 }, +/* GUSERLDT_SEL 11 LDT Descriptor, double size */ +{ .ssd_base = 0x0, + .ssd_limit = 0x0, + .ssd_type = 0, + .ssd_dpl = 0, + .ssd_p = 0, + .ssd_long = 0, + .ssd_def32 = 0, + .ssd_gran = 0 }, }; void @@ -1324,12 +1607,12 @@ hammer_time(u_int64_t modulep, u_int64_t physfree) /* * make gdt memory segments */ - gdt_segs[GPROC0_SEL].ssd_base = (uintptr_t)&common_tss[0]; - for (x = 0; x < NGDT; x++) { - if (x != GPROC0_SEL && x != (GPROC0_SEL + 1)) + if (x != GPROC0_SEL && x != (GPROC0_SEL + 1) && + x != GUSERLDT_SEL && x != (GUSERLDT_SEL) + 1) ssdtosd(&gdt_segs[x], &gdt[x]); } + gdt_segs[GPROC0_SEL].ssd_base = (uintptr_t)&common_tss[0]; ssdtosyssd(&gdt_segs[GPROC0_SEL], (struct system_segment_descriptor *)&gdt[GPROC0_SEL]); @@ -1347,6 +1630,10 @@ hammer_time(u_int64_t modulep, u_int64_t physfree) PCPU_SET(curthread, &thread0); PCPU_SET(curpcb, thread0.td_pcb); PCPU_SET(tssp, &common_tss[0]); + PCPU_SET(commontssp, &common_tss[0]); + PCPU_SET(tss, (struct system_segment_descriptor *)&gdt[GPROC0_SEL]); + PCPU_SET(ldt, (struct system_segment_descriptor *)&gdt[GUSERLDT_SEL]); + PCPU_SET(fs32p, &gdt[GUFS32_SEL]); PCPU_SET(gs32p, &gdt[GUGS32_SEL]); /* @@ -1359,6 +1646,7 @@ hammer_time(u_int64_t modulep, u_int64_t physfree) */ mutex_init(); mtx_init(&icu_lock, "icu", NULL, MTX_SPIN | MTX_NOWITNESS); + mtx_init(&dt_lock, "descriptor tables", NULL, MTX_DEF); /* exceptions */ for (x = 0; x < NIDT; x++) @@ -1439,7 +1727,8 @@ hammer_time(u_int64_t modulep, u_int64_t physfree) common_tss[0].tss_ist1 = (long)&dblfault_stack[sizeof(dblfault_stack)]; /* Set the IO permission bitmap (empty due to tss seg limit) */ - common_tss[0].tss_iobase = sizeof(struct amd64tss); + common_tss[0].tss_iobase = sizeof(struct amd64tss) + + IOPAGES * PAGE_SIZE; gsel_tss = GSEL(GPROC0_SEL, SEL_KPL); ltr(gsel_tss); @@ -1470,7 +1759,7 @@ hammer_time(u_int64_t modulep, u_int64_t physfree) load_ds(_udatasel); load_es(_udatasel); - load_fs(_udatasel); + load_fs(GSEL(GUFS32_SEL, SEL_UPL)); /* setup proc 0's pcb */ thread0.td_pcb->pcb_flags = 0; @@ -1736,8 +2025,54 @@ get_mcontext(struct thread *td, mcontext_t *mcp, int flags) 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_len = sizeof(*mcp); get_fpcontext(td, mcp); + mcp->mc_fsbase = td->td_pcb->pcb_fsbase; + mcp->mc_gsbase = td->td_pcb->pcb_gsbase; + return (0); +} + +int +get_mcontext7(struct thread *td, struct __mcontext7 *mcp, int flags) +{ + struct trapframe *tp; + + 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_len = sizeof(*mcp); + get_fpcontext7(td, mcp); return (0); } @@ -1781,6 +2116,54 @@ set_mcontext(struct thread *td, const mcontext_t *mcp) tp->tf_rflags = rflags; tp->tf_rsp = mcp->mc_rsp; tp->tf_ss = mcp->mc_ss; + tp->tf_ds = mcp->mc_ds; + tp->tf_es = mcp->mc_es; + tp->tf_fs = mcp->mc_fs; + tp->tf_gs = mcp->mc_gs; + td->td_pcb->pcb_fsbase = mcp->mc_fsbase; + td->td_pcb->pcb_gsbase = mcp->mc_gsbase; + td->td_pcb->pcb_flags |= PCB_FULLCTX; + return (0); +} + +int +set_mcontext7(struct thread *td, const struct __mcontext7 *mcp) +{ + struct trapframe *tp; + long rflags; + int ret; + + tp = td->td_frame; + if (mcp->mc_len != sizeof(*mcp)) + return (EINVAL); + rflags = (mcp->mc_rflags & PSL_USERCHANGE) | + (tp->tf_rflags & ~PSL_USERCHANGE); + ret = set_fpcontext7(td, mcp); + 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_ds = _udatasel; + tp->tf_es = _udatasel; + tp->tf_fs = GSEL(GUFS32_SEL, SEL_UPL); + tp->tf_gs = GSEL(GUGS32_SEL, SEL_UPL); td->td_pcb->pcb_flags |= PCB_FULLCTX; return (0); } @@ -1793,6 +2176,14 @@ get_fpcontext(struct thread *td, mcontext_t *mcp) mcp->mc_fpformat = fpuformat(); } +static void +get_fpcontext7(struct thread *td, struct __mcontext7 *mcp) +{ + + mcp->mc_ownedfp = fpugetregs(td, (struct savefpu *)&mcp->mc_fpstate); + mcp->mc_fpformat = fpuformat(); +} + static int set_fpcontext(struct thread *td, const mcontext_t *mcp) { @@ -1820,6 +2211,33 @@ set_fpcontext(struct thread *td, const mcontext_t *mcp) return (0); } +static int +set_fpcontext7(struct thread *td, const struct __mcontext7 *mcp) +{ + struct savefpu *fpstate; + + 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); + else if (mcp->mc_ownedfp == _MC_FPOWNED_FPU || + mcp->mc_ownedfp == _MC_FPOWNED_PCB) { + /* + * XXX we violate the dubious requirement that fpusetregs() + * be called with interrupts disabled. + * XXX obsolete on trap-16 systems? + */ + fpstate = (struct savefpu *)&mcp->mc_fpstate; + fpstate->sv_env.en_mxcsr &= cpu_mxcsr_mask; + fpusetregs(td, fpstate); + } else + return (EINVAL); + return (0); +} + void fpstate_drop(struct thread *td) { @@ -1843,6 +2261,56 @@ fpstate_drop(struct thread *td) } int +thr_create_freebsd7(struct thread *td, struct thr_create_freebsd7_args *uap) +{ + struct ucontext7 ctx7; + ucontext_t ctx; + int error; + + if ((error = copyin(uap->ctx, &ctx7, sizeof(ctx7)))) + return (error); + + ctx.uc_mcontext.mc_onstack = ctx7.uc_mcontext.mc_onstack; + ctx.uc_mcontext.mc_rdi = ctx7.uc_mcontext.mc_rdi; + ctx.uc_mcontext.mc_rsi = ctx7.uc_mcontext.mc_rsi; + ctx.uc_mcontext.mc_rdx = ctx7.uc_mcontext.mc_rdx; + ctx.uc_mcontext.mc_rcx = ctx7.uc_mcontext.mc_rcx; + ctx.uc_mcontext.mc_r8 = ctx7.uc_mcontext.mc_r8; + ctx.uc_mcontext.mc_r9 = ctx7.uc_mcontext.mc_r9; + ctx.uc_mcontext.mc_rax = ctx7.uc_mcontext.mc_rax; + ctx.uc_mcontext.mc_rbx = ctx7.uc_mcontext.mc_rbx; + ctx.uc_mcontext.mc_rbp = ctx7.uc_mcontext.mc_rbp; + ctx.uc_mcontext.mc_r10 = ctx7.uc_mcontext.mc_r10; + ctx.uc_mcontext.mc_r11 = ctx7.uc_mcontext.mc_r11; + ctx.uc_mcontext.mc_r12 = ctx7.uc_mcontext.mc_r12; + ctx.uc_mcontext.mc_r13 = ctx7.uc_mcontext.mc_r13; + ctx.uc_mcontext.mc_r14 = ctx7.uc_mcontext.mc_r14; + ctx.uc_mcontext.mc_r15 = ctx7.uc_mcontext.mc_r15; + ctx.uc_mcontext.mc_fs = GSEL(GUFS32_SEL, SEL_UPL); + ctx.uc_mcontext.mc_gs = GSEL(GUGS32_SEL, SEL_UPL); + ctx.uc_mcontext.mc_es = _udatasel; + ctx.uc_mcontext.mc_ds = _udatasel; + ctx.uc_mcontext.mc_trapno = ctx7.uc_mcontext.mc_trapno; + ctx.uc_mcontext.mc_addr = ctx7.uc_mcontext.mc_addr; + ctx.uc_mcontext.mc_flags = ctx7.uc_mcontext.mc_flags; + ctx.uc_mcontext.mc_err = ctx7.uc_mcontext.mc_err; + ctx.uc_mcontext.mc_rip = ctx7.uc_mcontext.mc_rip; + ctx.uc_mcontext.mc_cs = ctx7.uc_mcontext.mc_cs; + ctx.uc_mcontext.mc_rflags = ctx7.uc_mcontext.mc_rflags; + ctx.uc_mcontext.mc_rsp = ctx7.uc_mcontext.mc_rsp; + ctx.uc_mcontext.mc_ss = ctx7.uc_mcontext.mc_ss; + ctx.uc_mcontext.mc_len = ctx7.uc_mcontext.mc_len; + ctx.uc_mcontext.mc_fpformat = ctx7.uc_mcontext.mc_fpformat; + ctx.uc_mcontext.mc_ownedfp = ctx7.uc_mcontext.mc_ownedfp; + bcopy(&ctx7.uc_mcontext.mc_fpstate[0], &ctx.uc_mcontext.mc_fpstate[0], + sizeof(ctx.uc_mcontext.mc_fpstate)); + + error = create_thread(td, &ctx.uc_mcontext, NULL, NULL, + NULL, 0, NULL, uap->id, NULL, uap->flags, NULL); + return (error); +} + +int fill_dbregs(struct thread *td, struct dbreg *dbregs) { struct pcb *pcb; diff --git a/sys/amd64/amd64/mp_machdep.c b/sys/amd64/amd64/mp_machdep.c index 7996a90..29e0ae5 100644 --- a/sys/amd64/amd64/mp_machdep.c +++ b/sys/amd64/amd64/mp_machdep.c @@ -445,17 +445,19 @@ init_secondary(void) /* Init tss */ common_tss[cpu] = common_tss[0]; common_tss[cpu].tss_rsp0 = 0; /* not used until after switch */ - common_tss[cpu].tss_iobase = sizeof(struct amd64tss); + common_tss[cpu].tss_iobase = sizeof(struct amd64tss) + + IOPAGES * PAGE_SIZE; common_tss[cpu].tss_ist1 = (long)&doublefault_stack[PAGE_SIZE]; /* Prepare private GDT */ gdt_segs[GPROC0_SEL].ssd_base = (long) &common_tss[cpu]; - ssdtosyssd(&gdt_segs[GPROC0_SEL], - (struct system_segment_descriptor *)&gdt[NGDT * cpu + GPROC0_SEL]); for (x = 0; x < NGDT; x++) { - if (x != GPROC0_SEL && x != (GPROC0_SEL + 1)) + if (x != GPROC0_SEL && x != (GPROC0_SEL + 1) && + x != GUSERLDT_SEL && x != (GUSERLDT_SEL + 1)) ssdtosd(&gdt_segs[x], &gdt[NGDT * cpu + x]); } + ssdtosyssd(&gdt_segs[GPROC0_SEL], + (struct system_segment_descriptor *)&gdt[NGDT * cpu + GPROC0_SEL]); ap_gdt.rd_limit = NGDT * sizeof(gdt[0]) - 1; ap_gdt.rd_base = (long) &gdt[NGDT * cpu]; lgdt(&ap_gdt); /* does magic intra-segment return */ @@ -469,8 +471,14 @@ init_secondary(void) pc->pc_prvspace = pc; pc->pc_curthread = 0; pc->pc_tssp = &common_tss[cpu]; + pc->pc_commontssp = &common_tss[cpu]; pc->pc_rsp0 = 0; + pc->pc_tss = (struct system_segment_descriptor *)&gdt[NGDT * cpu + + GPROC0_SEL]; + pc->pc_fs32p = &gdt[NGDT * cpu + GUFS32_SEL]; pc->pc_gs32p = &gdt[NGDT * cpu + GUGS32_SEL]; + pc->pc_ldt = (struct system_segment_descriptor *)&gdt[NGDT * cpu + + GUSERLDT_SEL]; wrmsr(MSR_FSBASE, 0); /* User value */ wrmsr(MSR_GSBASE, (u_int64_t)pc); @@ -576,7 +584,7 @@ init_secondary(void) load_cr4(rcr4() | CR4_PGE); load_ds(_udatasel); load_es(_udatasel); - load_fs(_udatasel); + load_fs(GSEL(GUFS32_SEL, SEL_UPL)); mtx_unlock_spin(&ap_boot_mtx); /* wait until all the AP's are up */ diff --git a/sys/amd64/amd64/sigtramp.S b/sys/amd64/amd64/sigtramp.S index a05ea85..874ee19 100644 --- a/sys/amd64/amd64/sigtramp.S +++ b/sys/amd64/amd64/sigtramp.S @@ -47,6 +47,15 @@ NON_GPROF_ENTRY(sigcode) 0: hlt /* trap priviliged instruction */ jmp 0b +NON_GPROF_ENTRY(sigcode7) + call *SIGF_HANDLER(%rsp) /* call signal handler */ + lea SIGF_UC(%rsp),%rdi /* get ucontext_t */ + pushq $0 /* junk to fake return addr. */ + movq $SYS_sigreturn_freebsd7,%rax + syscall /* enter kernel with args */ +0: hlt /* trap priviliged instruction */ + jmp 0b + ALIGN_TEXT esigcode: @@ -54,3 +63,6 @@ esigcode: .globl szsigcode szsigcode: .long esigcode-sigcode + .globl szsigcode7 +szsigcode7: + .long esigcode-sigcode7 diff --git a/sys/amd64/amd64/sys_machdep.c b/sys/amd64/amd64/sys_machdep.c index 7f022d0..ee5ad89 100644 --- a/sys/amd64/amd64/sys_machdep.c +++ b/sys/amd64/amd64/sys_machdep.c @@ -36,16 +36,38 @@ __FBSDID("$FreeBSD$"); #include #include #include +#include +#include +#include #include #include -#include -#include -#include +#include #include #include +#include /* for kernel_map */ +#include + +#include +#include +#include +#include +#include #include +#include + +int max_ldt_segment = 1024; +#define LD_PER_PAGE 512 +#define NULL_LDT_BASE ((caddr_t)NULL) + +#ifdef notyet +#ifdef SMP +static void set_user_ldt_rv(struct vmspace *vmsp); +#endif +#endif +static void user_ldt_derefl(struct proc_ldt *pldt); + #ifndef _SYS_SYSPROTO_H_ struct sysarch_args { int op; @@ -54,6 +76,55 @@ struct sysarch_args { #endif int +sysarch_ldt(struct thread *td, struct sysarch_args *uap, int uap_space) +{ + struct i386_ldt_args *largs, la; + struct user_segment_descriptor *lp; + int error = 0; + + /* + * XXXKIB check that the BSM generation code knows to encode + * the op argument. + */ + AUDIT_ARG(cmd, uap->op); + if (uap_space == UIO_USERSPACE) { + error = copyin(uap->parms, &la, sizeof(struct i386_ldt_args)); + if (error != 0) + return (error); + largs = &la; + } else + largs = (struct i386_ldt_args *)uap->parms; + if (largs->num > max_ldt_segment || largs->num <= 0) + return (EINVAL); + + switch(uap->op) { + case I386_GET_LDT: + error = amd64_get_ldt(td, largs); + break; + case I386_SET_LDT: + if (largs->descs != NULL) { + lp = (struct user_segment_descriptor *) + kmem_alloc(kernel_map, largs->num * + sizeof(struct user_segment_descriptor)); + if (lp == NULL) { + error = ENOMEM; + break; + } + error = copyin(largs->descs, lp, largs->num * + sizeof(struct user_segment_descriptor)); + if (error == 0) + error = amd64_set_ldt(td, largs, lp); + kmem_free(kernel_map, (vm_offset_t)lp, largs->num * + sizeof(struct user_segment_descriptor)); + } else { + error = amd64_set_ldt(td, largs, NULL); + } + break; + } + return (error); +} + +int sysarch(td, uap) struct thread *td; register struct sysarch_args *uap; @@ -62,8 +133,36 @@ sysarch(td, uap) struct pcb *pcb = curthread->td_pcb; uint32_t i386base; uint64_t a64base; + struct i386_ioperm_args iargs; - switch(uap->op) { + if (uap->op == I386_GET_LDT || uap->op == I386_SET_LDT) + return (sysarch_ldt(td, uap, UIO_USERSPACE)); + /* + * XXXKIB check that the BSM generation code knows to encode + * the op argument. + */ + AUDIT_ARG(cmd, uap->op); + switch (uap->op) { + case I386_GET_IOPERM: + case I386_SET_IOPERM: + if ((error = copyin(uap->parms, &iargs, + sizeof(struct i386_ioperm_args))) != 0) + return (error); + break; + default: + break; + } + + switch (uap->op) { + case I386_GET_IOPERM: + error = amd64_get_ioperm(td, &iargs); + if (error == 0) + error = copyout(&iargs, uap->parms, + sizeof(struct i386_ioperm_args)); + break; + case I386_SET_IOPERM: + error = amd64_set_ioperm(td, &iargs); + break; case I386_GET_FSBASE: i386base = pcb->pcb_fsbase; error = copyout(&i386base, uap->parms, sizeof(i386base)); @@ -71,10 +170,8 @@ sysarch(td, uap) case I386_SET_FSBASE: error = copyin(uap->parms, &i386base, sizeof(i386base)); if (!error) { - critical_enter(); - wrmsr(MSR_FSBASE, i386base); pcb->pcb_fsbase = i386base; - critical_exit(); + td->td_frame->tf_fs = GSEL(GUFS32_SEL, SEL_UPL); } break; case I386_GET_GSBASE: @@ -84,10 +181,8 @@ sysarch(td, uap) case I386_SET_GSBASE: error = copyin(uap->parms, &i386base, sizeof(i386base)); if (!error) { - critical_enter(); - wrmsr(MSR_KGSBASE, i386base); pcb->pcb_gsbase = i386base; - critical_exit(); + td->td_frame->tf_gs = GSEL(GUGS32_SEL, SEL_UPL); } break; case AMD64_GET_FSBASE: @@ -98,13 +193,10 @@ sysarch(td, uap) error = copyin(uap->parms, &a64base, sizeof(a64base)); if (!error) { if (a64base < VM_MAXUSER_ADDRESS) { - critical_enter(); - wrmsr(MSR_FSBASE, a64base); pcb->pcb_fsbase = a64base; - critical_exit(); - } else { + td->td_frame->tf_fs = GSEL(GUFS32_SEL, SEL_UPL); + } else error = EINVAL; - } } break; @@ -116,13 +208,10 @@ sysarch(td, uap) error = copyin(uap->parms, &a64base, sizeof(a64base)); if (!error) { if (a64base < VM_MAXUSER_ADDRESS) { - critical_enter(); - wrmsr(MSR_KGSBASE, a64base); pcb->pcb_gsbase = a64base; - critical_exit(); - } else { + td->td_frame->tf_gs = GSEL(GUGS32_SEL, SEL_UPL); + } else error = EINVAL; - } } break; @@ -132,3 +221,423 @@ sysarch(td, uap) } return (error); } + +int +amd64_set_ioperm(td, uap) + struct thread *td; + struct i386_ioperm_args *uap; +{ + int i, error; + char *iomap; + struct amd64tss *tssp; + struct system_segment_descriptor *tss_sd; + u_long *addr; + struct pcb *pcb; + + if ((error = priv_check(td, PRIV_IO)) != 0) + return (error); + if ((error = securelevel_gt(td->td_ucred, 0)) != 0) + return (error); + /* + * XXX + * While this is restricted to root, we should probably figure out + * whether any other driver is using this i/o address, as so not to + * cause confusion. This probably requires a global 'usage registry'. + */ + pcb = td->td_pcb; + if ((iomap = pcb->pcb_iomap) == 0) { + pcb->pcb_tss = kmem_alloc(kernel_map, ctob(IOPAGES+1)); + if (pcb->pcb_tss == 0) + return (ENOMEM); + tssp = (struct amd64tss *)pcb->pcb_tss; + iomap = (char *)pcb->pcb_tss + sizeof(tssp); + addr = (u_long *)iomap; + for (i = 0; i < (ctob(IOPAGES) + 1) / sizeof(u_long); i++) + *addr++ = ~0; + critical_enter(); + td->td_pcb->pcb_iomap = iomap; + td->td_pcb->pcb_tssp = tssp; + tss_sd = PCPU_GET(tss); + memcpy(tssp, &common_tss[PCPU_GET(cpuid)], + sizeof(struct amd64tss)); + tssp->tss_iobase = sizeof(tssp); + tss_sd->sd_lobase = (u_long)tssp & 0xffffff; + tss_sd->sd_hibase = ((u_long)tssp >> 24) & 0xfffffffffful; + tss_sd->sd_type = SDT_SYSTSS; + ltr(GSEL(GPROC0_SEL, SEL_KPL)); + critical_exit(); + } + if (uap->start + uap->length > IOPAGES * PAGE_SIZE * NBBY) + return (EINVAL); + + for (i = uap->start; i < uap->start + uap->length; i++) { + if (uap->enable) + iomap[i >> 3] &= ~(1 << (i & 7)); + else + iomap[i >> 3] |= (1 << (i & 7)); + } + return (error); +} + +int +amd64_get_ioperm(td, uap) + struct thread *td; + struct i386_ioperm_args *uap; +{ + int i, state; + char *iomap; + + if (uap->start >= IOPAGES * PAGE_SIZE * NBBY) + return (EINVAL); + + if (td->td_pcb->pcb_iomap == 0) { + uap->length = 0; + goto done; + } + + iomap = (char *)td->td_pcb->pcb_iomap; + + i = uap->start; + state = (iomap[i >> 3] >> (i & 7)) & 1; + uap->enable = !state; + uap->length = 1; + + for (i = uap->start + 1; i < IOPAGES * PAGE_SIZE * NBBY; i++) { + if (state != ((iomap[i >> 3] >> (i & 7)) & 1)) + break; + uap->length++; + } + +done: + return (0); +} + +/* + * Update the GDT entry pointing to the LDT to point to the LDT of the + * current process. + */ +void +set_user_ldt(struct mdproc *mdp) +{ + + *PCPU_GET(ldt) = mdp->md_ldt_sd; + lldt(GSEL(GUSERLDT_SEL, SEL_KPL)); +} + +#ifdef notyet +#ifdef SMP +static void +set_user_ldt_rv(struct vmspace *vmsp) +{ + struct thread *td; + + td = curthread; + if (vmsp != td->td_proc->p_vmspace) + return; + + set_user_ldt(&td->td_proc->p_md); +} +#endif +#endif + +struct proc_ldt * +user_ldt_alloc(struct proc *p, int force) +{ + struct proc_ldt *pldt, *new_ldt; + struct mdproc *mdp; + struct soft_segment_descriptor sldt; + + mtx_assert(&dt_lock, MA_OWNED); + mdp = &p->p_md; + if (!force && mdp->md_ldt != NULL) + return (mdp->md_ldt); + mtx_unlock(&dt_lock); + MALLOC(new_ldt, struct proc_ldt *, sizeof(struct proc_ldt), + M_SUBPROC, M_WAITOK); + + new_ldt->ldt_base = (caddr_t)kmem_alloc(kernel_map, + max_ldt_segment * sizeof(struct user_segment_descriptor)); + if (new_ldt->ldt_base == NULL) { + FREE(new_ldt, M_SUBPROC); + mtx_lock(&dt_lock); + return (NULL); + } + new_ldt->ldt_refcnt = 1; + sldt.ssd_base = (uint64_t)new_ldt->ldt_base; + sldt.ssd_limit = max_ldt_segment * + sizeof(struct user_segment_descriptor) - 1; + sldt.ssd_type = SDT_SYSLDT; + sldt.ssd_dpl = SEL_KPL; + sldt.ssd_p = 1; + sldt.ssd_long = 0; + sldt.ssd_def32 = 0; + sldt.ssd_gran = 0; + mtx_lock(&dt_lock); + pldt = mdp->md_ldt; + if (pldt != NULL && !force) { + kmem_free(kernel_map, (vm_offset_t)pldt->ldt_base, + max_ldt_segment * sizeof(struct user_segment_descriptor)); + FREE(new_ldt, M_SUBPROC); + return (pldt); + } + + mdp->md_ldt = new_ldt; + if (pldt != NULL) { + bcopy(pldt->ldt_base, new_ldt->ldt_base, max_ldt_segment * + sizeof(struct user_segment_descriptor)); + user_ldt_derefl(pldt); + } + ssdtosyssd(&sldt, &p->p_md.md_ldt_sd); + if (p == curproc) + set_user_ldt(mdp); + + return (mdp->md_ldt); +} + +void +user_ldt_free(struct thread *td) +{ + struct proc *p = td->td_proc; + struct mdproc *mdp = &p->p_md; + struct proc_ldt *pldt; + + mtx_assert(&dt_lock, MA_OWNED); + if ((pldt = mdp->md_ldt) == NULL) { + mtx_unlock(&dt_lock); + return; + } + + mdp->md_ldt = NULL; + bzero(&mdp->md_ldt_sd, sizeof(mdp->md_ldt_sd)); + if (td == curthread) + lldt(GSEL(GNULL_SEL, SEL_KPL)); + user_ldt_deref(pldt); +} + +static void +user_ldt_derefl(struct proc_ldt *pldt) +{ + + if (--pldt->ldt_refcnt == 0) { + kmem_free(kernel_map, (vm_offset_t)pldt->ldt_base, + max_ldt_segment * sizeof(struct user_segment_descriptor)); + FREE(pldt, M_SUBPROC); + } +} + +void +user_ldt_deref(struct proc_ldt *pldt) +{ + + mtx_assert(&dt_lock, MA_OWNED); + user_ldt_derefl(pldt); + mtx_unlock(&dt_lock); +} + +/* + * Note for the authors of compat layers (linux, etc): copyout() in + * the function below is not a problem since it presents data in + * arch-specific format (i.e. i386-specific in this case), not in + * the OS-specific one. + */ +int +amd64_get_ldt(td, uap) + struct thread *td; + struct i386_ldt_args *uap; +{ + int error = 0; + struct proc_ldt *pldt; + int num; + struct user_segment_descriptor *lp; + +#ifdef DEBUG + printf("amd64_get_ldt: start=%d num=%d descs=%p\n", + uap->start, uap->num, (void *)uap->descs); +#endif + + if ((pldt = td->td_proc->p_md.md_ldt) != NULL) { + lp = &((struct user_segment_descriptor *)(pldt->ldt_base)) + [uap->start]; + num = min(uap->num, max_ldt_segment); + } else + return (EINVAL); + + if ((uap->start > (unsigned int)max_ldt_segment) || + ((unsigned int)num > (unsigned int)max_ldt_segment) || + ((unsigned int)(uap->start + num) > (unsigned int)max_ldt_segment)) + return(EINVAL); + + error = copyout(lp, uap->descs, num * + sizeof(struct user_segment_descriptor)); + if (!error) + td->td_retval[0] = num; + + return(error); +} + +int +amd64_set_ldt(td, uap, descs) + struct thread *td; + struct i386_ldt_args *uap; + struct user_segment_descriptor *descs; +{ + int error = 0, i; + int largest_ld; + struct mdproc *mdp = &td->td_proc->p_md; + struct proc_ldt *pldt; + struct user_segment_descriptor *dp; + struct proc *p; + +#ifdef DEBUG + printf("amd64_set_ldt: start=%d num=%d descs=%p\n", + uap->start, uap->num, (void *)uap->descs); +#endif + + p = td->td_proc; + if (descs == NULL) { + /* Free descriptors */ + if (uap->start == 0 && uap->num == 0) + uap->num = max_ldt_segment; + if (uap->num <= 0) + return (EINVAL); + if ((pldt = mdp->md_ldt) == NULL || + uap->start >= max_ldt_segment) + return (0); + largest_ld = uap->start + uap->num; + if (largest_ld > max_ldt_segment) + largest_ld = max_ldt_segment; + i = largest_ld - uap->start; + mtx_lock(&dt_lock); + bzero(&((struct user_segment_descriptor *)(pldt->ldt_base)) + [uap->start], sizeof(struct user_segment_descriptor) * i); + mtx_unlock(&dt_lock); + return (0); + } + + if (!(uap->start == LDT_AUTO_ALLOC && uap->num == 1)) { + /* verify range of descriptors to modify */ + largest_ld = uap->start + uap->num; + if (uap->start >= max_ldt_segment || + uap->num < 0 || largest_ld > max_ldt_segment) + return (EINVAL); + } + + /* Check descriptors for access violations */ + for (i = 0; i < uap->num; i++) { + dp = &descs[i]; + + switch (dp->sd_type) { + case SDT_SYSNULL: /* system null */ + dp->sd_p = 0; + break; + case SDT_SYS286TSS: + case SDT_SYSLDT: + case SDT_SYS286BSY: + case SDT_SYS286CGT: + case SDT_SYSTASKGT: + case SDT_SYS286IGT: + case SDT_SYS286TGT: + case SDT_SYSNULL2: + case SDT_SYSTSS: + case SDT_SYSNULL3: + case SDT_SYSBSY: + case SDT_SYSCGT: + case SDT_SYSNULL4: + case SDT_SYSIGT: + case SDT_SYSTGT: + /* I can't think of any reason to allow a user proc + * to create a segment of these types. They are + * for OS use only. + */ + return (EACCES); + /*NOTREACHED*/ + + /* memory segment types */ + case SDT_MEMEC: /* memory execute only conforming */ + case SDT_MEMEAC: /* memory execute only accessed conforming */ + case SDT_MEMERC: /* memory execute read conforming */ + case SDT_MEMERAC: /* memory execute read accessed conforming */ + /* Must be "present" if executable and conforming. */ + if (dp->sd_p == 0) + return (EACCES); + break; + case SDT_MEMRO: /* memory read only */ + case SDT_MEMROA: /* memory read only accessed */ + case SDT_MEMRW: /* memory read write */ + case SDT_MEMRWA: /* memory read write accessed */ + case SDT_MEMROD: /* memory read only expand dwn limit */ + case SDT_MEMRODA: /* memory read only expand dwn lim accessed */ + case SDT_MEMRWD: /* memory read write expand dwn limit */ + case SDT_MEMRWDA: /* memory read write expand dwn lim acessed */ + case SDT_MEME: /* memory execute only */ + case SDT_MEMEA: /* memory execute only accessed */ + case SDT_MEMER: /* memory execute read */ + case SDT_MEMERA: /* memory execute read accessed */ + break; + default: + return(EINVAL); + /*NOTREACHED*/ + } + + /* Only user (ring-3) descriptors may be present. */ + if ((dp->sd_p != 0) && (dp->sd_dpl != SEL_UPL)) + return (EACCES); + } + + if (uap->start == LDT_AUTO_ALLOC && uap->num == 1) { + /* Allocate a free slot */ + mtx_lock(&dt_lock); + pldt = user_ldt_alloc(p, 0); + if (pldt == NULL) { + mtx_unlock(&dt_lock); + return (ENOMEM); + } + + /* + * start scanning a bit up to leave room for NVidia and + * Wine, which still user the "Blat" method of allocation. + */ + i = 16; + dp = &((struct user_segment_descriptor *)(pldt->ldt_base))[i]; + for (; i < max_ldt_segment; ++i, ++dp) { + if (dp->sd_type == SDT_SYSNULL) + break; + } + if (i >= max_ldt_segment) { + mtx_unlock(&dt_lock); + return (ENOSPC); + } + uap->start = i; + error = amd64_set_ldt_data(td, i, 1, descs); + mtx_unlock(&dt_lock); + } else { + largest_ld = uap->start + uap->num; + if (largest_ld > max_ldt_segment) + return (EINVAL); + mtx_lock(&dt_lock); + if (user_ldt_alloc(p, 0) != NULL) { + error = amd64_set_ldt_data(td, uap->start, uap->num, + descs); + } + mtx_unlock(&dt_lock); + } + if (error == 0) + td->td_retval[0] = uap->start; + return (error); +} + +int +amd64_set_ldt_data(struct thread *td, int start, int num, + struct user_segment_descriptor *descs) +{ + struct mdproc *mdp = &td->td_proc->p_md; + struct proc_ldt *pldt = mdp->md_ldt; + + mtx_assert(&dt_lock, MA_OWNED); + + /* Fill in range */ + bcopy(descs, + &((struct user_segment_descriptor *)(pldt->ldt_base))[start], + num * sizeof(struct user_segment_descriptor)); + return (0); +} diff --git a/sys/amd64/amd64/trap.c b/sys/amd64/amd64/trap.c index 8d710cd..8c6d29f 100644 --- a/sys/amd64/amd64/trap.c +++ b/sys/amd64/amd64/trap.c @@ -478,6 +478,22 @@ trap(struct trapframe *frame) frame->tf_rip = (long)doreti_iret_fault; goto out; } + if (frame->tf_rip == (long)ld_ds) { + frame->tf_rip = (long)ds_load_fault; + goto out; + } + if (frame->tf_rip == (long)ld_es) { + frame->tf_rip = (long)es_load_fault; + goto out; + } + if (frame->tf_rip == (long)ld_fs) { + frame->tf_rip = (long)fs_load_fault; + goto out; + } + if (frame->tf_rip == (long)ld_gs) { + frame->tf_rip = (long)gs_load_fault; + goto out; + } if (PCPU_GET(curpcb)->pcb_onfault != NULL) { frame->tf_rip = (long)PCPU_GET(curpcb)->pcb_onfault; @@ -579,6 +595,18 @@ trap(struct trapframe *frame) if ((type == T_PAGEFLT) || (type == T_PROTFLT)) uprintf(", fault VA = 0x%lx", frame->tf_addr); uprintf("\n"); +{ + register_t rg,rgk, rf; + rf = rdmsr(0xc0000100); + rg = rdmsr(0xc0000101); + rgk = rdmsr(0xc0000102); + uprintf("TRAP type %d rip %lx err %lx cs %lx ss %lx ds %lx " + "es %lx fs %lx fsbase %lx %lx gs %lx gsbase %lx %lx %lx\n", + type, frame->tf_rip, frame->tf_err, + frame->tf_cs, frame->tf_ss, frame->tf_ds, frame->tf_es, + frame->tf_fs, td->td_pcb->pcb_fsbase, rf, + frame->tf_gs, td->td_pcb->pcb_gsbase, rg, rgk); + } } #endif diff --git a/sys/amd64/amd64/vm_machdep.c b/sys/amd64/amd64/vm_machdep.c index adddc1c..e7f8f9e 100644 --- a/sys/amd64/amd64/vm_machdep.c +++ b/sys/amd64/amd64/vm_machdep.c @@ -93,6 +93,8 @@ static u_int cpu_reset_proxyid; static volatile u_int cpu_reset_proxy_active; #endif +extern int _udatasel; + /* * Finish a fork operation, with process p2 nearly set up. * Copy and update the pcb, set up the stack so that the child @@ -107,11 +109,23 @@ cpu_fork(td1, p2, td2, flags) { register struct proc *p1; struct pcb *pcb2; - struct mdproc *mdp2; + struct mdproc *mdp1, *mdp2; + struct proc_ldt *pldt; p1 = td1->td_proc; - if ((flags & RFPROC) == 0) + if ((flags & RFPROC) == 0) { + if ((flags & RFMEM) == 0) { + /* unshare user LDT */ + mdp1 = &p1->p_md; + mtx_lock(&dt_lock); + if ((pldt = mdp1->md_ldt) != NULL && + pldt->ldt_refcnt > 1 && + user_ldt_alloc(p1, 1) == NULL) + panic("could not copy LDT"); + mtx_unlock(&dt_lock); + } return; + } /* Ensure that p1's pcb is up to date. */ fpuexit(td1); @@ -173,6 +187,32 @@ cpu_fork(td1, p2, td2, flags) td2->td_md.md_spinlock_count = 1; td2->td_md.md_saved_flags = PSL_KERNEL | PSL_I; + /* As an i386, do not copy io permission bitmap. */ + pcb2->pcb_iomap = NULL; + pcb2->pcb_tssp = NULL; + + /* Copy the LDT, if necessary. */ + mdp1 = &td1->td_proc->p_md; + mdp2 = &p2->p_md; + mtx_lock(&dt_lock); + if (mdp1->md_ldt != NULL) { + if (flags & RFMEM) { + mdp1->md_ldt->ldt_refcnt++; + mdp2->md_ldt = mdp1->md_ldt; + bcopy(&mdp1->md_ldt_sd, &mdp2->md_ldt_sd, sizeof(struct + system_segment_descriptor)); + } else { + mdp2->md_ldt = user_ldt_alloc(p2, 0); + if (mdp2->md_ldt == NULL) + panic("could not copy LDT"); + amd64_set_ldt_data(td2, 0, max_ldt_segment, + (struct user_segment_descriptor *) + mdp1->md_ldt->ldt_base); + } + } else + mdp2->md_ldt = NULL; + mtx_unlock(&dt_lock); + /* * Now, cpu_switch() can schedule the new process. * pcb_rsp is loaded pointing to the cpu_switch() stack frame @@ -207,25 +247,68 @@ cpu_set_fork_handler(td, func, arg) void cpu_exit(struct thread *td) { + + /* + * If this process has a custom LDT, release it. + */ + mtx_lock(&dt_lock); + if (td->td_proc->p_md.md_ldt != 0) { + user_ldt_free(td); + } else + mtx_unlock(&dt_lock); } void cpu_thread_exit(struct thread *td) { + struct system_segment_descriptor *tss_sd; + struct amd64tss *tssp; + struct pcb *pcb; if (td == PCPU_GET(fpcurthread)) fpudrop(); + pcb = td->td_pcb; + /* Disable any hardware breakpoints. */ - if (td->td_pcb->pcb_flags & PCB_DBREGS) { + if (pcb->pcb_flags & PCB_DBREGS) { reset_dbregs(); - td->td_pcb->pcb_flags &= ~PCB_DBREGS; + pcb->pcb_flags &= ~PCB_DBREGS; + } + + /* + * Clean TSS/iomap + */ + if (pcb->pcb_tssp != NULL) { + tssp = PCPU_GET(commontssp); + + /* + * Proc spinlock is owned, and spinlock implies + * critical section. + */ + PCPU_SET(tssp, tssp); + tss_sd = PCPU_GET(tss); + tss_sd->sd_lobase = (u_long)tssp & 0xffffff; + tss_sd->sd_hibase = ((u_long)tssp >> 24) & 0xfffffffffful; + tss_sd->sd_type = SDT_SYSTSS; + ltr(GSEL(GPROC0_SEL, SEL_KPL)); + pcb->pcb_iomap = NULL; + pcb->pcb_tssp = NULL; } } void cpu_thread_clean(struct thread *td) { + struct pcb *pcb; + vm_offset_t tss; + + pcb = td->td_pcb; + if (pcb->pcb_tss != 0) { + tss = pcb->pcb_tss; + pcb->pcb_tss = 0; + kmem_free(kernel_map, tss, ctob(IOPAGES + 1)); + } } void @@ -250,6 +333,8 @@ cpu_thread_alloc(struct thread *td) void cpu_thread_free(struct thread *td) { + + cpu_thread_clean(td); } /* @@ -353,6 +438,10 @@ cpu_set_upcall_kse(struct thread *td, void (*entry)(void *), void *arg, ((register_t)stack->ss_sp + stack->ss_size) & ~0x0f; td->td_frame->tf_rsp -= 8; td->td_frame->tf_rip = (register_t)entry; + td->td_frame->tf_ds = _udatasel; + td->td_frame->tf_es = _udatasel; + td->td_frame->tf_fs = GSEL(GUFS32_SEL, SEL_UPL); + td->td_frame->tf_gs = GSEL(GUGS32_SEL, SEL_UPL); /* * Pass the address of the mailbox for this kse to the uts @@ -370,25 +459,11 @@ cpu_set_user_tls(struct thread *td, void *tls_base) #ifdef COMPAT_IA32 if (td->td_proc->p_sysent == &ia32_freebsd_sysvec) { - if (td == curthread) { - critical_enter(); - td->td_pcb->pcb_gsbase = (register_t)tls_base; - wrmsr(MSR_KGSBASE, td->td_pcb->pcb_gsbase); - critical_exit(); - } else { - td->td_pcb->pcb_gsbase = (register_t)tls_base; - } + td->td_pcb->pcb_gsbase = (register_t)tls_base; return (0); } #endif - if (td == curthread) { - critical_enter(); - td->td_pcb->pcb_fsbase = (register_t)tls_base; - wrmsr(MSR_FSBASE, td->td_pcb->pcb_fsbase); - critical_exit(); - } else { - td->td_pcb->pcb_fsbase = (register_t)tls_base; - } + td->td_pcb->pcb_fsbase = (register_t)tls_base; return (0); } diff --git a/sys/amd64/ia32/ia32_reg.c b/sys/amd64/ia32/ia32_reg.c index 8abc6fc..fef43d1 100644 --- a/sys/amd64/ia32/ia32_reg.c +++ b/sys/amd64/ia32/ia32_reg.c @@ -85,9 +85,10 @@ 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; + regs->r_gs = tp->tf_gs; + regs->r_fs = tp->tf_fs; + regs->r_es = tp->tf_es; + regs->r_ds = tp->tf_ds; regs->r_edi = tp->tf_rdi; regs->r_esi = tp->tf_rsi; regs->r_ebp = tp->tf_rbp; @@ -100,7 +101,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 +114,10 @@ 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_rdi = regs->r_edi; tp->tf_rsi = regs->r_esi; tp->tf_rbp = regs->r_ebp; @@ -134,10 +130,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 +158,7 @@ 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; + 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 162dcf9..4ee58e1 100644 --- a/sys/amd64/ia32/ia32_signal.c +++ b/sys/amd64/ia32/ia32_signal.c @@ -125,7 +125,7 @@ ia32_set_fpcontext(struct thread *td, const struct ia32_mcontext *mcp) * Get machine context. */ static int -ia32_get_mcontext(struct thread *td, struct ia32_mcontext *mcp, int flags) +ia32_get_mcontext7(struct thread *td, struct ia32_mcontext *mcp, int flags) { struct trapframe *tp; @@ -134,10 +134,10 @@ 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; + 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; @@ -161,6 +161,18 @@ ia32_get_mcontext(struct thread *td, struct ia32_mcontext *mcp, int flags) return (0); } +static int +ia32_get_mcontext(struct thread *td, struct ia32_mcontext *mcp, int flags) +{ + int error; + + if ((error = ia32_get_mcontext7(td, mcp, flags)) != 0) + return (error); + mcp->mc_fsbase = td->td_pcb->pcb_fsbase; + mcp->mc_gsbase = td->td_pcb->pcb_gsbase; + return (0); +} + /* * Set machine context. * @@ -168,7 +180,7 @@ ia32_get_mcontext(struct thread *td, struct ia32_mcontext *mcp, int flags) * touch the cs selector. */ static int -ia32_set_mcontext(struct thread *td, const struct ia32_mcontext *mcp) +ia32_set_mcontext7(struct thread *td, const struct ia32_mcontext *mcp) { struct trapframe *tp; long rflags; @@ -182,11 +194,10 @@ 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_rdi = mcp->mc_edi; tp->tf_rsi = mcp->mc_esi; tp->tf_rbp = mcp->mc_ebp; @@ -199,13 +210,22 @@ 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); } +static int +ia32_set_mcontext(struct thread *td, const struct ia32_mcontext *mcp) +{ + int error; + + if ((error = ia32_set_mcontext7(td, mcp)) != 0) + return (error); + td->td_pcb->pcb_fsbase = mcp->mc_fsbase; + td->td_pcb->pcb_gsbase = mcp->mc_gsbase; + return (0); +} + /* * The first two fields of a ucontext_t are the signal mask and * the machine context. The next field is uc_link; we want to @@ -284,6 +304,80 @@ freebsd32_swapcontext(struct thread *td, struct freebsd32_swapcontext_args *uap) return (ret == 0 ? EJUSTRETURN : ret); } +int +freebsd32_getcontext_freebsd7(struct thread *td, + struct freebsd32_getcontext_freebsd7_args *uap) +{ + struct ia32_ucontext uc; + int ret; + + if (uap->ucp == NULL) + ret = EINVAL; + else { + ia32_get_mcontext7(td, &uc.uc_mcontext, GET_MC_CLEAR_RET); + PROC_LOCK(td->td_proc); + uc.uc_sigmask = td->td_sigmask; + PROC_UNLOCK(td->td_proc); + ret = copyout(&uc, uap->ucp, UC_COPY_SIZE); + } + return (ret); +} + +int +freebsd32_setcontext_freebsd7(struct thread *td, + struct freebsd32_setcontext_freebsd7_args *uap) +{ + struct ia32_ucontext uc; + int ret; + + if (uap->ucp == NULL) + ret = EINVAL; + else { + ret = copyin(uap->ucp, &uc, UC_COPY_SIZE); + if (ret == 0) { + ret = ia32_set_mcontext7(td, &uc.uc_mcontext); + if (ret == 0) { + SIG_CANTMASK(uc.uc_sigmask); + PROC_LOCK(td->td_proc); + td->td_sigmask = uc.uc_sigmask; + PROC_UNLOCK(td->td_proc); + } + } + } + return (ret == 0 ? EJUSTRETURN : ret); +} + +int +freebsd32_swapcontext_freebsd7(struct thread *td, + struct freebsd32_swapcontext_freebsd7_args *uap) +{ + struct ia32_ucontext uc; + int ret; + + if (uap->oucp == NULL || uap->ucp == NULL) + ret = EINVAL; + else { + ia32_get_mcontext7(td, &uc.uc_mcontext, GET_MC_CLEAR_RET); + PROC_LOCK(td->td_proc); + uc.uc_sigmask = td->td_sigmask; + PROC_UNLOCK(td->td_proc); + ret = copyout(&uc, uap->oucp, UC_COPY_SIZE); + if (ret == 0) { + ret = copyin(uap->ucp, &uc, UC_COPY_SIZE); + if (ret == 0) { + ret = ia32_set_mcontext7(td, &uc.uc_mcontext); + if (ret == 0) { + SIG_CANTMASK(uc.uc_sigmask); + PROC_LOCK(td->td_proc); + td->td_sigmask = uc.uc_sigmask; + PROC_UNLOCK(td->td_proc); + } + } + } + } + return (ret == 0 ? EJUSTRETURN : ret); +} + /* * Send an interrupt to process. * @@ -345,6 +439,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 +492,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); @@ -460,9 +556,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 && @@ -510,15 +612,18 @@ ia32_sendsig(sig_t catcher, ksiginfo_t *ksi, sigset_t *mask) } regs->tf_rsp = (uintptr_t)sfp; - regs->tf_rip = FREEBSD32_PS_STRINGS - *(p->p_sysent->sv_szsigcode); + regs->tf_rip = FREEBSD32_PS_STRINGS; + if (SIGISMEMBER(psp->ps_freebsd7, sig) && + p->p_sysent->sv_sigcode == ia32_sigcode) + regs->tf_rip -= sz_ia32_sigcode7; + else + regs->tf_rip -= *(p->p_sysent->sv_szsigcode); 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 +696,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 +710,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; @@ -619,12 +727,9 @@ freebsd4_freebsd32_sigreturn(td, uap) /* * MPSAFE */ -int -freebsd32_sigreturn(td, uap) - struct thread *td; - struct freebsd32_sigreturn_args /* { - const struct freebsd32_ucontext *sigcntxp; - } */ *uap; +static int +freebsd32_sigreturn_compat(struct thread *td, + struct freebsd32_sigreturn_args *uap, int compat) { struct ia32_ucontext uc; struct proc *p = td->td_proc; @@ -678,7 +783,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 +797,14 @@ 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; + if (!compat) { + td->td_pcb->pcb_fsbase = ucp->uc_mcontext.mc_fsbase; + td->td_pcb->pcb_gsbase = ucp->uc_mcontext.mc_gsbase; + } PROC_LOCK(p); td->td_sigmask = ucp->uc_sigmask; @@ -702,6 +814,27 @@ freebsd32_sigreturn(td, uap) return (EJUSTRETURN); } +int +freebsd32_sigreturn(td, uap) + struct thread *td; + struct freebsd32_sigreturn_args /* { + const struct freebsd32_ucontext *sigcntxp; + } */ *uap; +{ + + return (freebsd32_sigreturn_compat(td, uap, 0)); +} + +int +freebsd32_sigreturn_freebsd7(td, uap) + struct thread *td; + struct freebsd32_sigreturn_freebsd7_args *uap; +{ + + return (freebsd32_sigreturn(td, + (struct freebsd32_sigreturn_args *)uap), 1); +} + /* * Clear registers on exec */ @@ -715,20 +848,8 @@ 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 */ 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; bzero((char *)regs, sizeof(struct trapframe)); regs->tf_rip = entry; @@ -737,6 +858,10 @@ 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 = GSEL(GUFS32_SEL, SEL_UPL); + regs->tf_gs = GSEL(GUGS32_SEL, SEL_UPL); 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 7b20bc4..4f5b85c 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 - movl IA32_UC_ES(%eax),%es /* restore %es */ - movl IA32_UC_DS(%eax),%ds /* restore %ds */ movl $SYS_sigreturn,%eax pushl %eax /* junk to fake return addr. */ int $0x80 /* enter kernel with args */ @@ -54,14 +52,23 @@ ia32_sigcode: 1: jmp 1b +ia32_sigcode7: + calll *IA32_SIGF_HANDLER(%esp) + leal IA32_SIGF_UC(%esp),%eax /* get ucontext */ + pushl %eax + movl $SYS_sigreturn_freebsd7,%eax + pushl %eax /* junk to fake return addr. */ + int $0x80 /* enter kernel with args */ + /* on stack */ +1: + jmp 1b + #ifdef COMPAT_FREEBSD4 ALIGN_TEXT freebsd4_ia32_sigcode: calll *IA32_SIGF_HANDLER(%esp) leal IA32_SIGF_UC4(%esp),%eax/* get ucontext */ pushl %eax - movl IA32_UC4_ES(%eax),%es /* restore %es */ - movl 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 */ @@ -77,6 +84,9 @@ esigcode: .globl sz_ia32_sigcode sz_ia32_sigcode: .long esigcode-ia32_sigcode + .globl sz_ia32_sigcode7 +sz_ia32_sigcode7: + .long esigcode-ia32_sigcode7 #ifdef COMPAT_FREEBSD4 .globl sz_freebsd4_ia32_sigcode sz_freebsd4_ia32_sigcode: diff --git a/sys/amd64/include/asmacros.h b/sys/amd64/include/asmacros.h index 788f39f..421e871 100644 --- a/sys/amd64/include/asmacros.h +++ b/sys/amd64/include/asmacros.h @@ -161,7 +161,11 @@ movq %r12,TF_R12(%rsp) ; \ movq %r13,TF_R13(%rsp) ; \ movq %r14,TF_R14(%rsp) ; \ - movq %r15,TF_R15(%rsp) + movq %r15,TF_R15(%rsp) ; \ + movl %fs,TF_FS(%rsp) ; \ + movl %gs,TF_GS(%rsp) ; \ + movl %es,TF_ES(%rsp) ; \ + movl %ds,TF_DS(%rsp) #define POP_FRAME \ movq TF_RDI(%rsp),%rdi ; \ diff --git a/sys/amd64/include/frame.h b/sys/amd64/include/frame.h index 26c9dd0..f9026aa 100644 --- a/sys/amd64/include/frame.h +++ b/sys/amd64/include/frame.h @@ -64,6 +64,38 @@ struct trapframe { register_t tf_r13; register_t tf_r14; register_t tf_r15; + register_t tf_fs; + register_t tf_gs; + register_t tf_es; + register_t tf_ds; + register_t tf_trapno; + register_t tf_addr; + register_t tf_flags; + /* below portion defined in hardware */ + register_t tf_err; + register_t tf_rip; + register_t tf_cs; + register_t tf_rflags; + register_t tf_rsp; + register_t tf_ss; +}; + +struct otrapframe { + register_t tf_rdi; + register_t tf_rsi; + register_t tf_rdx; + register_t tf_rcx; + register_t tf_r8; + register_t tf_r9; + register_t tf_rax; + register_t tf_rbx; + register_t tf_rbp; + register_t tf_r10; + register_t tf_r11; + register_t tf_r12; + register_t tf_r13; + register_t tf_r14; + register_t tf_r15; register_t tf_trapno; register_t tf_addr; register_t tf_flags; diff --git a/sys/amd64/include/md_var.h b/sys/amd64/include/md_var.h index 348cb31..fa5b57f 100644 --- a/sys/amd64/include/md_var.h +++ b/sys/amd64/include/md_var.h @@ -54,6 +54,7 @@ extern char cpu_vendor[]; extern char kstack[]; extern char sigcode[]; extern int szsigcode; +extern int szsigcode7; extern uint64_t *vm_page_dump; extern int vm_page_dump_size; @@ -68,6 +69,14 @@ void busdma_swi(void); void cpu_setregs(void); void doreti_iret(void) __asm(__STRING(doreti_iret)); void doreti_iret_fault(void) __asm(__STRING(doreti_iret_fault)); +void ld_ds(void) __asm(__STRING(ld_ds)); +void ld_es(void) __asm(__STRING(ld_es)); +void ld_fs(void) __asm(__STRING(ld_fs)); +void ld_gs(void) __asm(__STRING(ld_gs)); +void ds_load_fault(void) __asm(__STRING(ds_load_fault)); +void es_load_fault(void) __asm(__STRING(es_load_fault)); +void fs_load_fault(void) __asm(__STRING(fs_load_fault)); +void gs_load_fault(void) __asm(__STRING(gs_load_fault)); void dump_add_page(vm_paddr_t); void dump_drop_page(vm_paddr_t); void initializecpu(void); diff --git a/sys/amd64/include/pcb.h b/sys/amd64/include/pcb.h index 43b59e5..c7544ab 100644 --- a/sys/amd64/include/pcb.h +++ b/sys/amd64/include/pcb.h @@ -56,10 +56,6 @@ struct pcb { register_t pcb_fsbase; register_t pcb_gsbase; u_long pcb_flags; - u_int32_t pcb_ds; - u_int32_t pcb_es; - u_int32_t pcb_fs; - u_int32_t pcb_gs; u_int64_t pcb_dr0; u_int64_t pcb_dr1; u_int64_t pcb_dr2; @@ -78,6 +74,10 @@ struct pcb { /* 32-bit segment descriptor */ struct user_segment_descriptor pcb_gs32sd; + caddr_t pcb_iomap; /* i/o permission bitmap */ + /* local tss, with i/o bitmap; NULL for common */ + struct amd64tss *pcb_tssp; + vm_offset_t pcb_tss; }; #ifdef _KERNEL diff --git a/sys/amd64/include/pcpu.h b/sys/amd64/include/pcpu.h index e9faf28..84b4ebb 100644 --- a/sys/amd64/include/pcpu.h +++ b/sys/amd64/include/pcpu.h @@ -45,11 +45,15 @@ struct pcpu *pc_prvspace; /* Self-reference */ \ struct pmap *pc_curpmap; \ struct amd64tss *pc_tssp; \ + struct amd64tss *pc_commontssp; \ register_t pc_rsp0; \ register_t pc_scratch_rsp; /* User %rsp in syscall */ \ u_int pc_apic_id; \ u_int pc_acpi_id; /* ACPI CPU id */ \ - struct user_segment_descriptor *pc_gs32p + struct user_segment_descriptor *pc_fs32p; \ + struct user_segment_descriptor *pc_gs32p; \ + struct system_segment_descriptor *pc_ldt; \ + struct system_segment_descriptor *pc_tss #ifdef _KERNEL diff --git a/sys/amd64/include/proc.h b/sys/amd64/include/proc.h index a3ebd79..273ba5e 100644 --- a/sys/amd64/include/proc.h +++ b/sys/amd64/include/proc.h @@ -33,6 +33,13 @@ #ifndef _MACHINE_PROC_H_ #define _MACHINE_PROC_H_ +#include + +struct proc_ldt { + caddr_t ldt_base; + int ldt_refcnt; +}; + /* * Machine-dependent part of the proc structure for AMD64. */ @@ -42,6 +49,8 @@ struct mdthread { }; struct mdproc { + struct proc_ldt *md_ldt; /* (t) per-process ldt */ + struct system_segment_descriptor md_ldt_sd; }; #ifdef _KERNEL @@ -55,6 +64,18 @@ struct mdproc { (char *)&td; \ } while (0) +void set_user_ldt(struct mdproc *); +struct proc_ldt *user_ldt_alloc(struct proc *, int); +void user_ldt_free(struct thread *); +void user_ldt_deref(struct proc_ldt *); +struct sysarch_args; +int sysarch_ldt(struct thread *td, struct sysarch_args *uap, int uap_space); +int amd64_set_ldt_data(struct thread *td, int start, int num, + struct user_segment_descriptor *descs); + +extern struct mtx dt_lock; +extern int max_ldt_segment; + #endif /* _KERNEL */ #endif /* !_MACHINE_PROC_H_ */ diff --git a/sys/amd64/include/segments.h b/sys/amd64/include/segments.h index 1c83d1c..6c6cb40 100644 --- a/sys/amd64/include/segments.h +++ b/sys/amd64/include/segments.h @@ -108,12 +108,29 @@ struct gate_descriptor { u_int64_t sd_xx1:32; } __packed; +/* + * Generic descriptor + */ +union descriptor { + struct user_segment_descriptor sd; + struct gate_descriptor gd; +}; + /* system segments and gate types */ #define SDT_SYSNULL 0 /* system null */ +#define SDT_SYS286TSS 1 /* system 286 TSS available */ #define SDT_SYSLDT 2 /* system 64 bit local descriptor table */ +#define SDT_SYS286BSY 3 /* system 286 TSS busy */ +#define SDT_SYS286CGT 4 /* system 286 call gate */ +#define SDT_SYSTASKGT 5 /* system task gate */ +#define SDT_SYS286IGT 6 /* system 286 interrupt gate */ +#define SDT_SYS286TGT 7 /* system 286 trap gate */ +#define SDT_SYSNULL2 8 /* system null again */ #define SDT_SYSTSS 9 /* system available 64 bit TSS */ +#define SDT_SYSNULL3 10 /* system null again */ #define SDT_SYSBSY 11 /* system busy 64 bit TSS */ #define SDT_SYSCGT 12 /* system 64 bit call gate */ +#define SDT_SYSNULL4 13 /* system null again */ #define SDT_SYSIGT 14 /* system 64 bit interrupt gate */ #define SDT_SYSTGT 15 /* system 64 bit trap gate */ @@ -203,7 +220,10 @@ struct region_descriptor { #define GPROC0_SEL 6 /* TSS for entering kernel etc */ /* slot 7 is second half of GPROC0_SEL */ #define GUGS32_SEL 8 /* User 32 bit GS Descriptor */ -#define NGDT 9 +#define GUFS32_SEL 9 /* User 32 bit FS Descriptor */ +#define GUSERLDT_SEL 10 /* LDT */ +/* slot 11 is second half of GUSERLDT_SEL */ +#define NGDT 12 #ifdef _KERNEL extern struct user_segment_descriptor gdt[]; diff --git a/sys/amd64/include/sigframe.h b/sys/amd64/include/sigframe.h index d104507..0671104 100644 --- a/sys/amd64/include/sigframe.h +++ b/sys/amd64/include/sigframe.h @@ -43,4 +43,13 @@ struct sigframe { siginfo_t sf_si; /* = *sf_siginfo (SA_SIGINFO case) */ }; +struct sigframe7 { + union { + __siginfohandler_t *sf_action; + __sighandler_t *sf_handler; + } sf_ahu; + struct ucontext7 sf_uc; /* = *sf_ucontext */ + siginfo_t sf_si; /* = *sf_siginfo (SA_SIGINFO case) */ +}; + #endif /* !_MACHINE_SIGFRAME_H_ */ diff --git a/sys/amd64/include/sysarch.h b/sys/amd64/include/sysarch.h index 67c8a4a..6c3e6c9 100644 --- a/sys/amd64/include/sysarch.h +++ b/sys/amd64/include/sysarch.h @@ -35,6 +35,15 @@ #ifndef _MACHINE_SYSARCH_H_ #define _MACHINE_SYSARCH_H_ +#define I386_GET_LDT 0 +#define I386_SET_LDT 1 +#define LDT_AUTO_ALLOC 0xffffffff + /* I386_IOPL */ +#define I386_GET_IOPERM 3 +#define I386_SET_IOPERM 4 + +/* XXX Not implementable #define I386_VM86 6 */ + #define I386_GET_FSBASE 7 #define I386_SET_FSBASE 8 #define I386_GET_GSBASE 9 @@ -46,6 +55,18 @@ #define AMD64_GET_GSBASE 130 #define AMD64_SET_GSBASE 131 +struct i386_ldt_args { + unsigned int start; + struct user_segment_descriptor *descs __packed; + unsigned int num; +}; + +struct i386_ioperm_args { + unsigned int start; + unsigned int length; + int enable; +}; + #ifndef _KERNEL #include @@ -56,6 +77,15 @@ int amd64_set_fsbase(void *); int amd64_set_gsbase(void *); int sysarch(int, void *); __END_DECLS +#else +struct thread; +union descriptor; + +int amd64_get_ldt(struct thread *, struct i386_ldt_args *); +int amd64_set_ldt(struct thread *, struct i386_ldt_args *, + struct user_segment_descriptor *); +int amd64_get_ioperm(struct thread *, struct i386_ioperm_args *); +int amd64_set_ioperm(struct thread *, struct i386_ioperm_args *); #endif #endif /* !_MACHINE_SYSARCH_H_ */ diff --git a/sys/amd64/include/ucontext.h b/sys/amd64/include/ucontext.h index 5c13803..7ca861f 100644 --- a/sys/amd64/include/ucontext.h +++ b/sys/amd64/include/ucontext.h @@ -34,7 +34,7 @@ typedef struct __mcontext { /* - * The first 20 fields must match the definition of + * The first 24 fields must match the definition of * sigcontext. So that we can support sigcontext * and ucontext_t at the same time. */ @@ -54,6 +54,10 @@ typedef struct __mcontext { __register_t mc_r13; __register_t mc_r14; __register_t mc_r15; + __register_t mc_fs; + __register_t mc_gs; + __register_t mc_es; + __register_t mc_ds; __register_t mc_trapno; __register_t mc_addr; __register_t mc_flags; @@ -65,6 +69,10 @@ typedef struct __mcontext { __register_t mc_ss; long mc_len; /* sizeof(mcontext_t) */ + + __register_t mc_fsbase; + __register_t mc_gsbase; + #define _MC_FPFMT_NODEV 0x10000 /* device not present or configured */ #define _MC_FPFMT_XMM 0x10002 long mc_fpformat; @@ -79,4 +87,51 @@ typedef struct __mcontext { long mc_spare[8]; } mcontext_t; +struct __mcontext7 { + /* + * The first 20 fields must match the definition of + * sigcontext. So that we can support sigcontext + * and ucontext_t at the same time. + */ + __register_t mc_onstack; /* XXX - sigcontext compat. */ + __register_t mc_rdi; /* machine state (struct trapframe) */ + __register_t mc_rsi; + __register_t mc_rdx; + __register_t mc_rcx; + __register_t mc_r8; + __register_t mc_r9; + __register_t mc_rax; + __register_t mc_rbx; + __register_t mc_rbp; + __register_t mc_r10; + __register_t mc_r11; + __register_t mc_r12; + __register_t mc_r13; + __register_t mc_r14; + __register_t mc_r15; + __register_t mc_trapno; + __register_t mc_addr; + __register_t mc_flags; + __register_t mc_err; + __register_t mc_rip; + __register_t mc_cs; + __register_t mc_rflags; + __register_t mc_rsp; + __register_t mc_ss; + + long mc_len; /* sizeof(mcontext_t) */ +#define _MC_FPFMT_NODEV 0x10000 /* device not present or configured */ +#define _MC_FPFMT_XMM 0x10002 + long mc_fpformat; +#define _MC_FPOWNED_NONE 0x20000 /* FP state not used */ +#define _MC_FPOWNED_FPU 0x20001 /* FP state came from FPU */ +#define _MC_FPOWNED_PCB 0x20002 /* FP state came from PCB */ + long mc_ownedfp; + /* + * See for the internals of mc_fpstate[]. + */ + long mc_fpstate[64] __aligned(16); + long mc_spare[8]; +}; + #endif /* !_MACHINE_UCONTEXT_H_ */ diff --git a/sys/amd64/linux32/linux32_machdep.c b/sys/amd64/linux32/linux32_machdep.c index aecf869..e54f7b2 100644 --- a/sys/amd64/linux32/linux32_machdep.c +++ b/sys/amd64/linux32/linux32_machdep.c @@ -693,8 +693,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; } } @@ -1351,7 +1351,7 @@ linux_set_thread_area(struct thread *td, critical_enter(); td->td_pcb->pcb_gsbase = (register_t)info.base_addr; - td->td_pcb->pcb_gs32sd = *PCPU_GET(gs32p) = sd; +/* XXXKIB 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(); diff --git a/sys/amd64/linux32/linux32_sysvec.c b/sys/amd64/linux32/linux32_sysvec.c index 5676ddd..865482f 100644 --- a/sys/amd64/linux32/linux32_sysvec.c +++ b/sys/amd64/linux32/linux32_sysvec.c @@ -405,10 +405,10 @@ 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; + regs->tf_ds = _udatasel; + regs->tf_es = _udatasel; + regs->tf_fs = GSEL(GUFS32_SEL, SEL_UPL); + regs->tf_gs = GSEL(GUGS32_SEL, SEL_UPL); /* leave user %fs and %gs untouched */ PROC_LOCK(p); mtx_lock(&psp->ps_mtx); @@ -487,10 +487,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("movl %%es,%0" : "=rm" (frame.sf_sc.sc_es)); - __asm __volatile("movl %%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; @@ -527,10 +527,10 @@ 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; + regs->tf_ds = _udatasel; + regs->tf_es = _udatasel; + regs->tf_fs = GSEL(GUFS32_SEL, SEL_UPL); + regs->tf_gs = GSEL(GUGS32_SEL, SEL_UPL); /* leave user %fs and %gs untouched */ PROC_LOCK(p); mtx_lock(&psp->ps_mtx); @@ -714,7 +714,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; @@ -823,19 +826,15 @@ exec_linux_setregs(td, entry, stack, ps_strings) 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; 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 = _udatasel; + regs->tf_fs = _udatasel; + regs->tf_es = _udatasel; + regs->tf_ds = _udatasel; regs->tf_ss = _udatasel; regs->tf_cs = _ucode32sel; regs->tf_rbx = ps_strings; diff --git a/sys/compat/freebsd32/freebsd32.h b/sys/compat/freebsd32/freebsd32.h index 0c77bab..5957a92 100644 --- a/sys/compat/freebsd32/freebsd32.h +++ b/sys/compat/freebsd32/freebsd32.h @@ -173,4 +173,10 @@ struct thr_param32 { uint32_t spare[3]; }; +struct i386_ldt_args32 { + uint32_t start; + uint32_t descs; + uint32_t num; +}; + #endif /* !_COMPAT_FREEBSD32_FREEBSD32_H_ */ diff --git a/sys/compat/freebsd32/freebsd32_misc.c b/sys/compat/freebsd32/freebsd32_misc.c index 4c89d74..0c89fa7 100644 --- a/sys/compat/freebsd32/freebsd32_misc.c +++ b/sys/compat/freebsd32/freebsd32_misc.c @@ -84,6 +84,7 @@ __FBSDID("$FreeBSD$"); #include #include +#include #include @@ -2017,8 +2018,9 @@ done2: return (error); } -int -freebsd32_sigaction(struct thread *td, struct freebsd32_sigaction_args *uap) +static int +freebsd32_sigaction_compat(struct thread *td, + struct freebsd32_sigaction_args *uap, int compat) { struct sigaction32 s32; struct sigaction sa, osa, *sap; @@ -2034,7 +2036,8 @@ freebsd32_sigaction(struct thread *td, struct freebsd32_sigaction_args *uap) sap = &sa; } else sap = NULL; - error = kern_sigaction(td, uap->sig, sap, &osa, 0); + error = kern_sigaction(td, uap->sig, sap, &osa, compat ? + KSA_FREEBSD7 : 0); if (error == 0 && uap->oact != NULL) { s32.sa_u = PTROUT(osa.sa_handler); CP(osa, s32, sa_flags); @@ -2044,6 +2047,22 @@ freebsd32_sigaction(struct thread *td, struct freebsd32_sigaction_args *uap) return (error); } +int +freebsd32_sigaction(struct thread *td, struct freebsd32_sigaction_args *uap) +{ + + return (freebsd32_sigaction_compat(td, uap, 0)); +} + +int +freebsd32_sigaction_freebsd7(struct thread *td, struct + freebsd32_sigaction_freebsd7_args *uap) +{ + + return (freebsd32_sigaction_compat(td, (struct + freebsd32_sigaction_args *)uap, 1)); +} + #ifdef COMPAT_FREEBSD4 int freebsd4_freebsd32_sigaction(struct thread *td, @@ -2555,6 +2574,31 @@ freebsd32_cpuset_setaffinity(struct thread *td, } 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)); + } +} + +int freebsd32_nmount(struct thread *td, struct freebsd32_nmount_args /* { struct iovec *iovp; diff --git a/sys/compat/freebsd32/syscalls.master b/sys/compat/freebsd32/syscalls.master index 0e70981..d92cb5a 100644 --- a/sys/compat/freebsd32/syscalls.master +++ b/sys/compat/freebsd32/syscalls.master @@ -300,7 +300,7 @@ 163 AUE_SYSCTL NOPROTO { int setdomainname(char *domainname, \ int len); } 164 AUE_NULL NOPROTO { int uname(struct utsname *name); } -165 AUE_SYSARCH NOPROTO { int sysarch(int op, char *parms); } +165 AUE_SYSARCH STD { int freebsd32_sysarch(int op, char *parms); } 166 AUE_RTPRIO NOPROTO { int rtprio(int function, pid_t pid, \ struct rtprio *rtp); } 167 AUE_NULL UNIMPL nosys @@ -699,19 +699,19 @@ 413 AUE_EXTATTR_GET_LINK UNIMPL extattr_get_link 414 AUE_EXTATTR_DELETE_LINK UNIMPL extattr_delete_link 415 AUE_NULL UNIMPL __mac_execve -416 AUE_SIGACTION STD { int freebsd32_sigaction(int sig, \ +416 AUE_SIGACTION STD { int freebsd32_sigaction_freebsd7(int sig, \ struct sigaction32 *act, \ struct sigaction32 *oact); } -417 AUE_SIGRETURN STD { int freebsd32_sigreturn( \ +417 AUE_SIGRETURN STD { int freebsd32_sigreturn_freebsd7( \ const struct freebsd32_ucontext *sigcntxp); } 418 AUE_NULL UNIMPL __xstat 419 AUE_NULL UNIMPL __xfstat 420 AUE_NULL UNIMPL __xlstat -421 AUE_NULL STD { int freebsd32_getcontext( \ +421 AUE_NULL STD { int freebsd32_getcontext_freebsd7( \ struct freebsd32_ucontext *ucp); } -422 AUE_NULL STD { int freebsd32_setcontext( \ +422 AUE_NULL STD { int freebsd32_setcontext_freebsd7( \ const struct freebsd32_ucontext *ucp); } -423 AUE_NULL STD { int freebsd32_swapcontext( \ +423 AUE_NULL STD { int freebsd32_swapcontext_freebsd7( \ struct freebsd32_ucontext *oucp, \ const struct freebsd32_ucontext *ucp); } 424 AUE_SWAPOFF UNIMPL swapoff @@ -854,3 +854,15 @@ 503 AUE_UNLINKAT NOPROTO { int unlinkat(int fd, char *path, \ int flag); } 504 AUE_POSIX_OPENPT NOPROTO { int posix_openpt(int flags); } +505 AUE_SIGACTION STD { int freebsd32_sigaction(int sig, \ + struct sigaction32 *act, \ + struct sigaction32 *oact); } +506 AUE_SIGRETURN STD { int freebsd32_sigreturn( \ + const struct freebsd32_ucontext *sigcntxp); } +507 AUE_NULL STD { int freebsd32_getcontext( \ + struct freebsd32_ucontext *ucp); } +508 AUE_NULL STD { int freebsd32_setcontext( \ + const struct freebsd32_ucontext *ucp); } +509 AUE_NULL STD { int freebsd32_swapcontext( \ + struct freebsd32_ucontext *oucp, \ + const struct freebsd32_ucontext *ucp); } diff --git a/sys/compat/ia32/ia32_signal.h b/sys/compat/ia32/ia32_signal.h index f2be96d..1c1dbca 100644 --- a/sys/compat/ia32/ia32_signal.h +++ b/sys/compat/ia32/ia32_signal.h @@ -59,11 +59,49 @@ struct ia32_mcontext { * See for the internals of mc_fpstate[]. */ u_int32_t mc_fpstate[128] __aligned(16); + u_int32_t mc_fsbase; + u_int32_t mc_gsbase; + u_int32_t mc_spare2[6]; +}; + +struct ia32_mcontext7 { + u_int32_t mc_onstack; /* XXX - sigcontext compat. */ + u_int32_t mc_gs; /* machine state (struct trapframe) */ + u_int32_t mc_fs; + u_int32_t mc_es; + u_int32_t mc_ds; + u_int32_t mc_edi; + u_int32_t mc_esi; + u_int32_t mc_ebp; + u_int32_t mc_isp; + u_int32_t mc_ebx; + u_int32_t mc_edx; + u_int32_t mc_ecx; + u_int32_t mc_eax; + u_int32_t mc_trapno; + u_int32_t mc_err; + u_int32_t mc_eip; + u_int32_t mc_cs; + u_int32_t mc_eflags; + u_int32_t mc_esp; + u_int32_t mc_ss; + u_int32_t mc_len; /* sizeof(struct ia32_mcontext) */ + /* We use the same values for fpformat and ownedfp */ + u_int32_t mc_fpformat; + u_int32_t mc_ownedfp; + u_int32_t mc_spare1[1]; /* align next field to 16 bytes */ + /* + * See for the internals of mc_fpstate[]. + */ + u_int32_t mc_fpstate[128] __aligned(16); u_int32_t mc_spare2[8]; }; struct ia32_ucontext { sigset_t uc_sigmask; + /* + * uc_mcontext may be an ia32_mcontext or ia32_mcontext7. + */ struct ia32_mcontext uc_mcontext; u_int32_t uc_link; struct sigaltstack32 uc_stack; @@ -181,6 +219,7 @@ struct ksiginfo; extern char ia32_sigcode[]; extern char freebsd4_ia32_sigcode[]; extern int sz_ia32_sigcode; +extern int sz_ia32_sigcode7; extern int sz_freebsd4_ia32_sigcode; extern void ia32_sendsig(sig_t, struct ksiginfo *, sigset_t *); extern void ia32_setregs(struct thread *td, u_long entry, u_long stack, diff --git a/sys/i386/i386/locore.s b/sys/i386/i386/locore.s index 7ca2493..6db0e24 100644 --- a/sys/i386/i386/locore.s +++ b/sys/i386/i386/locore.s @@ -347,6 +347,21 @@ NON_GPROF_ENTRY(sigcode) 1: jmp 1b +NON_GPROF_ENTRY(sigcode7) + calll *SIGF_HANDLER(%esp) + leal SIGF_UC(%esp),%eax /* get ucontext */ + pushl %eax + testl $PSL_VM,UC_EFLAGS(%eax) + jne 1f + movl UC_GS(%eax),%gs /* restore %gs */ +1: + movl $SYS_sigreturn_freebsd7,%eax + pushl %eax /* junk to fake return addr. */ + int $0x80 /* enter kernel with args */ + /* on stack */ +1: + jmp 1b + #ifdef COMPAT_FREEBSD4 ALIGN_TEXT freebsd4_sigcode: @@ -388,6 +403,9 @@ esigcode: .globl szsigcode szsigcode: .long esigcode-sigcode + .globl szsigcode7 +szsigcode7: + .long esigcode-sigcode7 #ifdef COMPAT_FREEBSD4 .globl szfreebsd4_sigcode szfreebsd4_sigcode: diff --git a/sys/i386/i386/machdep.c b/sys/i386/i386/machdep.c index d824b26..1d61866 100644 --- a/sys/i386/i386/machdep.c +++ b/sys/i386/i386/machdep.c @@ -178,6 +178,8 @@ extern void initializecpu(void); #define CPU_ENABLE_SSE #endif +static int sigreturn_common(struct thread *td, struct sigreturn_args *uap, + int compat); static void cpu_startup(void *); static void fpstate_drop(struct thread *td); static void get_fpcontext(struct thread *td, mcontext_t *mcp); @@ -578,6 +580,7 @@ sendsig(sig_t catcher, ksiginfo_t *ksi, sigset_t *mask) struct sigacts *psp; char *sp; struct trapframe *regs; + struct segment_descriptor *sdp; int sig; int oonstack; @@ -614,6 +617,15 @@ sendsig(sig_t catcher, ksiginfo_t *ksi, sigset_t *mask) sf.sf_uc.uc_mcontext.mc_len = sizeof(sf.sf_uc.uc_mcontext); /* magic */ get_fpcontext(td, &sf.sf_uc.uc_mcontext); fpstate_drop(td); + /* + * Unconditionally fill the fsbase and gsbase into the mcontext. + */ + sdp = &td->td_pcb->pcb_gsd; + sf.sf_uc.uc_mcontext.mc_fsbase = sdp->sd_hibase << 24 | + sdp->sd_lobase; + sdp = &td->td_pcb->pcb_fsd; + sf.sf_uc.uc_mcontext.mc_gsbase = sdp->sd_hibase << 24 | + sdp->sd_lobase; /* Allocate space for the signal handler context. */ if ((td->td_pflags & TDP_ALTSTACK) != 0 && !oonstack && @@ -693,7 +705,11 @@ sendsig(sig_t catcher, ksiginfo_t *ksi, sigset_t *mask) } regs->tf_esp = (int)sfp; - regs->tf_eip = PS_STRINGS - *(p->p_sysent->sv_szsigcode); + if (SIGISMEMBER(psp->ps_freebsd7, sig) && + p->p_sysent->sv_sigcode == sigcode) + regs->tf_eip = PS_STRINGS - szsigcode7; + else + regs->tf_eip = PS_STRINGS - *(p->p_sysent->sv_szsigcode); regs->tf_eflags &= ~(PSL_T | PSL_D); regs->tf_cs = _ucodesel; regs->tf_ds = _udatasel; @@ -963,16 +979,37 @@ freebsd4_sigreturn(td, uap) * MPSAFE */ int +sigreturn_freebsd7(td, uap) + struct thread *td; + struct sigreturn_freebsd7_args *uap; +{ + + return (sigreturn_common(td, (struct sigreturn_args *)uap, 1)); +} + + +int sigreturn(td, uap) struct thread *td; + struct sigreturn_args *uap; +{ + + return (sigreturn_common(td, uap, 0)); +} + +static int +sigreturn_common(td, uap, compat) + struct thread *td; struct sigreturn_args /* { const struct __ucontext *sigcntxp; } */ *uap; + int compat; { ucontext_t uc; struct proc *p = td->td_proc; struct trapframe *regs; const ucontext_t *ucp; + struct pcb *pcb; int cs, eflags, error, ret; ksiginfo_t ksi; @@ -1062,6 +1099,19 @@ sigreturn(td, uap) if (ret != 0) return (ret); bcopy(&ucp->uc_mcontext.mc_fs, regs, sizeof(*regs)); + if (!compat) { + pcb = td->td_pcb; + critical_enter(); + pcb->pcb_fsd.sd_hibase = (ucp->uc_mcontext.mc_fsbase + >> 24) & 0xff; + pcb->pcb_fsd.sd_lobase = ucp->uc_mcontext.mc_fsbase + & 0xffffff; + pcb->pcb_gsd.sd_hibase = (ucp->uc_mcontext.mc_gsbase + >> 24) & 0xff; + pcb->pcb_gsd.sd_lobase = ucp->uc_mcontext.mc_gsbase + & 0xffffff; + critical_exit(); + } } PROC_LOCK(p); @@ -3063,7 +3113,7 @@ set_fpregs(struct thread *td, struct fpreg *fpregs) * Get machine context. */ int -get_mcontext(struct thread *td, mcontext_t *mcp, int flags) +get_mcontext7(struct thread *td, struct __mcontext7 *mcp, int flags) { struct trapframe *tp; @@ -3096,7 +3146,24 @@ get_mcontext(struct thread *td, mcontext_t *mcp, int flags) mcp->mc_esp = tp->tf_esp; mcp->mc_ss = tp->tf_ss; mcp->mc_len = sizeof(*mcp); - get_fpcontext(td, mcp); + get_fpcontext(td, (mcontext_t *)mcp); + + return (0); +} + +int +get_mcontext(struct thread *td, mcontext_t *mcp, int flags) +{ + struct segment_descriptor *sdp; + int error; + + if ((error = get_mcontext7(td, (struct __mcontext7 *)mcp, flags)) != 0) + return (error); + sdp = &td->td_pcb->pcb_gsd; + mcp->mc_fsbase = sdp->sd_hibase << 24 | sdp->sd_lobase; + sdp = &td->td_pcb->pcb_fsd; + mcp->mc_gsbase = sdp->sd_hibase << 24 | sdp->sd_lobase; + return (0); } @@ -3107,7 +3174,7 @@ get_mcontext(struct thread *td, mcontext_t *mcp, int flags) * touch the cs selector. */ int -set_mcontext(struct thread *td, const mcontext_t *mcp) +set_mcontext7(struct thread *td, const struct __mcontext7 *mcp) { struct trapframe *tp; int eflags, ret; @@ -3117,7 +3184,7 @@ set_mcontext(struct thread *td, const mcontext_t *mcp) return (EINVAL); eflags = (mcp->mc_eflags & PSL_USERCHANGE) | (tp->tf_eflags & ~PSL_USERCHANGE); - if ((ret = set_fpcontext(td, mcp)) == 0) { + if ((ret = set_fpcontext(td, (const mcontext_t *)mcp)) == 0) { tp->tf_fs = mcp->mc_fs; tp->tf_es = mcp->mc_es; tp->tf_ds = mcp->mc_ds; @@ -3133,11 +3200,33 @@ set_mcontext(struct thread *td, const mcontext_t *mcp) tp->tf_esp = mcp->mc_esp; tp->tf_ss = mcp->mc_ss; td->td_pcb->pcb_gs = mcp->mc_gs; + ret = 0; } return (ret); } +int +set_mcontext(struct thread *td, const mcontext_t *mcp) +{ + struct pcb *pcb; + int error; + + if ((error = set_mcontext7(td, (const struct __mcontext7 *)mcp)) != 0) + return (error); + pcb = td->td_pcb; + if (td == curthread) + critical_enter(); + pcb->pcb_fsd.sd_hibase = (mcp->mc_fsbase >> 24) & 0xff; + pcb->pcb_fsd.sd_lobase = mcp->mc_fsbase & 0xffffff; + pcb->pcb_gsd.sd_hibase = (mcp->mc_gsbase >> 24) & 0xff; + pcb->pcb_gsd.sd_lobase = mcp->mc_gsbase & 0xffffff; + if (td == curthread) + critical_exit(); + + return (0); +} + static void get_fpcontext(struct thread *td, mcontext_t *mcp) { @@ -3251,6 +3340,23 @@ fpstate_drop(struct thread *td) } int +thr_create_freebsd7(struct thread *td, struct thr_create_freebsd7_args *uap) +{ + ucontext_t ctx; + int error; + + if ((error = copyin(uap->ctx, &ctx, sizeof(ctx)))) + return (error); + /* + * XXXKIB take mc_fsbase and mc_gsbase from the supplied + * context. + */ + error = create_thread(td, &ctx.uc_mcontext, NULL, NULL, + NULL, 0, NULL, uap->id, NULL, uap->flags, NULL); + return (error); +} + +int fill_dbregs(struct thread *td, struct dbreg *dbregs) { struct pcb *pcb; diff --git a/sys/i386/include/md_var.h b/sys/i386/include/md_var.h index 4f8b96d..7346999 100644 --- a/sys/i386/include/md_var.h +++ b/sys/i386/include/md_var.h @@ -62,6 +62,7 @@ extern u_int cyrix_did; extern char kstack[]; extern char sigcode[]; extern int szsigcode; +extern int szsigcode7; #ifdef COMPAT_FREEBSD4 extern int szfreebsd4_sigcode; #endif diff --git a/sys/i386/include/ucontext.h b/sys/i386/include/ucontext.h index c992495..d4de672 100644 --- a/sys/i386/include/ucontext.h +++ b/sys/i386/include/ucontext.h @@ -72,10 +72,61 @@ typedef struct __mcontext { * See for the internals of mc_fpstate[]. */ int mc_fpstate[128] __aligned(16); - int mc_spare2[8]; + + __register_t mc_fsbase; + __register_t mc_gsbase; + + int mc_spare2[6]; } mcontext_t; -#if defined(_KERNEL) && defined(COMPAT_FREEBSD4) +#if defined(_KERNEL) + +struct __mcontext7 { + /* + * The first 20 fields must match the definition of + * sigcontext. So that we can support sigcontext + * and ucontext_t at the same time. + */ + __register_t mc_onstack; /* XXX - sigcontext compat. */ + __register_t mc_gs; /* machine state (struct trapframe) */ + __register_t mc_fs; + __register_t mc_es; + __register_t mc_ds; + __register_t mc_edi; + __register_t mc_esi; + __register_t mc_ebp; + __register_t mc_isp; + __register_t mc_ebx; + __register_t mc_edx; + __register_t mc_ecx; + __register_t mc_eax; + __register_t mc_trapno; + __register_t mc_err; + __register_t mc_eip; + __register_t mc_cs; + __register_t mc_eflags; + __register_t mc_esp; + __register_t mc_ss; + + int mc_len; /* sizeof(mcontext_t) */ +#define _MC_FPFMT_NODEV 0x10000 /* device not present or configured */ +#define _MC_FPFMT_387 0x10001 +#define _MC_FPFMT_XMM 0x10002 + int mc_fpformat; +#define _MC_FPOWNED_NONE 0x20000 /* FP state not used */ +#define _MC_FPOWNED_FPU 0x20001 /* FP state came from FPU */ +#define _MC_FPOWNED_PCB 0x20002 /* FP state came from PCB */ + int mc_ownedfp; + int mc_spare1[1]; /* align next field to 16 bytes */ + /* + * See for the internals of mc_fpstate[]. + */ + int mc_fpstate[128] __aligned(16); + int mc_spare2[8]; +}; + +#if defined(COMPAT_FREEBSD4) + struct mcontext4 { __register_t mc_onstack; /* XXX - sigcontext compat. */ __register_t mc_gs; /* machine state (struct trapframe) */ @@ -101,5 +152,6 @@ struct mcontext4 { __register_t __spare__[17]; }; #endif +#endif #endif /* !_MACHINE_UCONTEXT_H_ */ diff --git a/sys/kern/kern_context.c b/sys/kern/kern_context.c index f951fca..9376dc1 100644 --- a/sys/kern/kern_context.c +++ b/sys/kern/kern_context.c @@ -27,6 +27,8 @@ #include __FBSDID("$FreeBSD$"); +#include "opt_compat.h" + #include #include #include @@ -44,6 +46,7 @@ __FBSDID("$FreeBSD$"); * when copying out contexts. */ #define UC_COPY_SIZE offsetof(ucontext_t, uc_link) +#define UC7_COPY_SIZE offsetof(struct ucontext7, uc_link) #ifndef _SYS_SYSPROTO_H_ struct getcontext_args { @@ -128,3 +131,111 @@ swapcontext(struct thread *td, struct swapcontext_args *uap) } return (ret == 0 ? EJUSTRETURN : ret); } + +#if defined(__amd64__) || defined(__i386__) +int +getcontext_freebsd7(td, uap) + struct thread *td; + struct getcontext_freebsd7_args *uap; +{ + struct ucontext7 uc; + int ret; + + if (uap->ucp == NULL) + ret = EINVAL; + else { + get_mcontext7(td, &uc.uc_mcontext, GET_MC_CLEAR_RET); + PROC_LOCK(td->td_proc); + uc.uc_sigmask = td->td_sigmask; + PROC_UNLOCK(td->td_proc); + ret = copyout(&uc, uap->ucp, UC7_COPY_SIZE); + } + return (ret); +} + +int +setcontext_freebsd7(td, uap) + struct thread *td; + struct setcontext_freebsd7_args *uap; +{ + struct ucontext7 uc; + int ret; + + if (uap->ucp == NULL) + ret = EINVAL; + else { + ret = copyin(uap->ucp, &uc, UC7_COPY_SIZE); + if (ret == 0) { + ret = set_mcontext7(td, &uc.uc_mcontext); + if (ret == 0) { + SIG_CANTMASK(uc.uc_sigmask); + PROC_LOCK(td->td_proc); + td->td_sigmask = uc.uc_sigmask; + PROC_UNLOCK(td->td_proc); + } + } + } + return (ret == 0 ? EJUSTRETURN : ret); +} + +int +swapcontext_freebsd7(td, uap) + struct thread *td; + struct swapcontext_freebsd7_args *uap; +{ + struct ucontext7 uc; + int ret; + + if (uap->oucp == NULL || uap->ucp == NULL) + ret = EINVAL; + else { + get_mcontext7(td, &uc.uc_mcontext, GET_MC_CLEAR_RET); + PROC_LOCK(td->td_proc); + uc.uc_sigmask = td->td_sigmask; + PROC_UNLOCK(td->td_proc); + ret = copyout(&uc, uap->oucp, UC7_COPY_SIZE); + if (ret == 0) { + ret = copyin(uap->ucp, &uc, UC7_COPY_SIZE); + if (ret == 0) { + ret = set_mcontext7(td, &uc.uc_mcontext); + if (ret == 0) { + SIG_CANTMASK(uc.uc_sigmask); + PROC_LOCK(td->td_proc); + td->td_sigmask = uc.uc_sigmask; + PROC_UNLOCK(td->td_proc); + } + } + } + } + return (ret == 0 ? EJUSTRETURN : ret); +} + +#else + +int +getcontext_freebsd7(td, uap) + struct thread *td; + struct getcontext_freebsd7_args *uap; +{ + + return (getcontext(td, (struct getcontext_args *)uap)); +} + +int +setcontext_freebsd7(td, uap) + struct thread *td; + struct setcontext_freebsd7_args *uap; +{ + + return (setcontext(td, (struct setcontext_args *)uap)); +} + +int +swapcontext_freebsd7(td, uap) + struct thread *td; + struct setcontext_freebsd7_args *uap; +{ + + return (swapcontext(td, (struct swapcontext_args *)uap)); +} +#endif diff --git a/sys/kern/kern_sig.c b/sys/kern/kern_sig.c index d5d1813..f54bfaf 100644 --- a/sys/kern/kern_sig.c +++ b/sys/kern/kern_sig.c @@ -767,6 +767,12 @@ kern_sigaction(td, sig, act, oact, flags) else SIGADDSET(ps->ps_freebsd4, sig); #endif + if (ps->ps_sigact[_SIG_IDX(sig)] == SIG_IGN || + ps->ps_sigact[_SIG_IDX(sig)] == SIG_DFL || + (flags & KSA_FREEBSD7) == 0) + SIGDELSET(ps->ps_freebsd7, sig); + else + SIGADDSET(ps->ps_freebsd7, sig); #ifdef COMPAT_43 if (ps->ps_sigact[_SIG_IDX(sig)] == SIG_IGN || ps->ps_sigact[_SIG_IDX(sig)] == SIG_DFL || @@ -840,7 +846,49 @@ freebsd4_sigaction(td, uap) error = copyout(oactp, uap->oact, sizeof(oact)); return (error); } -#endif /* COMAPT_FREEBSD4 */ +#endif /* COMPAT_FREEBSD4 */ + +#ifndef _SYS_SYSPROTO_H_ +struct freebsd7_sigaction_args { + int sig; + struct sigaction *act; + struct sigaction *oact; +}; +#endif +int +sigaction_freebsd7(td, uap) + struct thread *td; + register struct sigaction_freebsd7_args *uap; +{ + struct sigaction act, oact; + register struct sigaction *actp, *oactp; + int error; + + + actp = (uap->act != NULL) ? &act : NULL; + oactp = (uap->oact != NULL) ? &oact : NULL; + if (actp) { + error = copyin(uap->act, actp, sizeof(act)); + if (error) + return (error); + } + error = kern_sigaction(td, uap->sig, actp, oactp, KSA_FREEBSD7); + if (oactp && !error) + error = copyout(oactp, uap->oact, sizeof(oact)); + return (error); +} + +#if !defined(__amd64__) && !defined(__i386__) +/* Avoid replicating the same stub everywhere */ +int +sigreturn_freebsd7(td, uap) + struct thread *td; + struct sigreturn_freebsd7_args *uap; +{ + + return (sigreturn(td, (struct sigreturn_args *)uap)); +} +#endif #ifdef COMPAT_43 /* XXX - COMPAT_FBSD3 */ #ifndef _SYS_SYSPROTO_H_ diff --git a/sys/kern/kern_thr.c b/sys/kern/kern_thr.c index dc9953b..af42f23 100644 --- a/sys/kern/kern_thr.c +++ b/sys/kern/kern_thr.c @@ -77,13 +77,6 @@ suword_lwpid(void *addr, lwpid_t lwpid) extern int max_threads_per_proc; -static int create_thread(struct thread *td, mcontext_t *ctx, - void (*start_func)(void *), void *arg, - char *stack_base, size_t stack_size, - char *tls_base, - long *child_tid, long *parent_tid, - int flags, struct rtprio *rtp); - /* * System call interface. */ @@ -102,6 +95,15 @@ thr_create(struct thread *td, struct thr_create_args *uap) return (error); } +#if !defined(__amd64__) && !defined(__i386__) +int +thr_create_freebsd7(struct thread *td, struct thr_create_args_freebsd7 *uap) +{ + + return (thr_create(td, (struct thr_create_args *)uap)); +} +#endif + int thr_new(struct thread *td, struct thr_new_args *uap) /* struct thr_param * */ @@ -135,7 +137,7 @@ kern_thr_new(struct thread *td, struct thr_param *param) return (error); } -static int +int create_thread(struct thread *td, mcontext_t *ctx, void (*start_func)(void *), void *arg, char *stack_base, size_t stack_size, diff --git a/sys/kern/makesyscalls.sh b/sys/kern/makesyscalls.sh index 2b778b1..dbb952d 100644 --- a/sys/kern/makesyscalls.sh +++ b/sys/kern/makesyscalls.sh @@ -267,7 +267,7 @@ s/\$//g funcalias = funcname if (argalias == "") { argalias = funcname "_args" - if ($3 == "COMPAT") + if ($3 == "COMPAT" || $3 == "LIBCOMPAT") argalias = "o" argalias if ($3 == "COMPAT4") argalias = "freebsd4_" argalias @@ -447,7 +447,18 @@ s/\$//g $3 == "LIBCOMPAT" { ncompat++ parseline() - printf("%s\to%s();\n", rettype, funcname) > syscompatdcl + if (argc != 0) { + printf("struct %s {\n", argalias) > out + for (i = 1; i <= argc; i++) + printf("\tchar %s_l_[PADL_(%s)]; %s %s; " \ + "char %s_r_[PADR_(%s)];\n", + argname[i], argtype[i], + argtype[i], argname[i], + argname[i], argtype[i]) > out + printf("};\n") > out + } + printf("%s\to%s(struct thread *, struct %s *);\n", rettype, + funcname, argalias) > syscompatdcl printf("\t{ compat(%s,%s), %s, NULL, 0, 0 },", argssize, funcname, auditev) > sysent align_sysent_comment(8 + 9 + \ diff --git a/sys/kern/syscalls.master b/sys/kern/syscalls.master index 38adf73..d823dbf 100644 --- a/sys/kern/syscalls.master +++ b/sys/kern/syscalls.master @@ -737,19 +737,21 @@ const char *attrname); } 415 AUE_NULL STD { int __mac_execve(char *fname, char **argv, \ char **envv, struct mac *mac_p); } -416 AUE_SIGACTION STD { int sigaction(int sig, \ +416 AUE_SIGACTION STD { int sigaction_freebsd7(int sig, \ const struct sigaction *act, \ struct sigaction *oact); } -417 AUE_SIGRETURN STD { int sigreturn( \ +417 AUE_SIGRETURN STD { int sigreturn_freebsd7( \ const struct __ucontext *sigcntxp); } 418 AUE_NULL UNIMPL __xstat 419 AUE_NULL UNIMPL __xfstat 420 AUE_NULL UNIMPL __xlstat -421 AUE_NULL STD { int getcontext(struct __ucontext *ucp); } -422 AUE_NULL STD { int setcontext( \ - const struct __ucontext *ucp); } -423 AUE_NULL STD { int swapcontext(struct __ucontext *oucp, \ - const struct __ucontext *ucp); } +421 AUE_NULL STD { int getcontext_freebsd7(struct __ucontext7 \ + *ucp); } +422 AUE_NULL STD { int setcontext_freebsd7( \ + const struct __ucontext7 *ucp); } +423 AUE_NULL STD { int swapcontext_freebsd7(struct \ + __ucontext7 *oucp, \ + const struct __ucontext7 *ucp); } 424 AUE_SWAPOFF STD { int swapoff(const char *name); } 425 AUE_NULL STD { int __acl_get_link(const char *path, \ acl_type_t type, struct acl *aclp); } @@ -761,8 +763,8 @@ acl_type_t type, struct acl *aclp); } 429 AUE_SIGWAIT STD { int sigwait(const sigset_t *set, \ int *sig); } -430 AUE_NULL STD { int thr_create(ucontext_t *ctx, long *id, \ - int flags); } +430 AUE_NULL STD { int thr_create_freebsd7(struct __ucontext7 \ + *ctx, long *id, int flags); } 431 AUE_NULL STD { void thr_exit(long *state); } 432 AUE_NULL STD { int thr_self(long *id); } 433 AUE_NULL STD { int thr_kill(long id, int sig); } @@ -895,5 +897,17 @@ char *path2); } 503 AUE_UNLINKAT STD { int unlinkat(int fd, char *path, int flag); } 504 AUE_POSIX_OPENPT STD { int posix_openpt(int flags); } +505 AUE_SIGACTION STD { int sigaction(int sig, \ + const struct sigaction *act, \ + struct sigaction *oact); } +506 AUE_SIGRETURN STD { int sigreturn( \ + const struct __ucontext *sigcntxp); } +507 AUE_NULL STD { int getcontext(struct __ucontext *ucp); } +508 AUE_NULL STD { int setcontext( \ + const struct __ucontext *ucp); } +509 AUE_NULL STD { int swapcontext(struct __ucontext *oucp, \ + const struct __ucontext *ucp); } +510 AUE_NULL STD { int thr_create(ucontext_t *ctx, long *id, \ + int flags); } ; Please copy any additions and changes to the following compatability tables: ; sys/compat/freebsd32/syscalls.master diff --git a/sys/sys/proc.h b/sys/sys/proc.h index 66e95ac..6787453 100644 --- a/sys/sys/proc.h +++ b/sys/sys/proc.h @@ -859,6 +859,10 @@ void thread_unthread(struct thread *td); void thread_wait(struct proc *p); struct thread *thread_find(struct proc *p, lwpid_t tid); void thr_exit1(void); +int create_thread(struct thread *td, mcontext_t *ctx, + void (*start_func)(void *), + void *arg, char *stack_base, size_t stack_size, char *tls_base, + long *child_tid, long *parent_tid, int flags, struct rtprio *rtp); #endif /* _KERNEL */ diff --git a/sys/sys/signalvar.h b/sys/sys/signalvar.h index dc09226..98fdf86 100644 --- a/sys/sys/signalvar.h +++ b/sys/sys/signalvar.h @@ -61,6 +61,7 @@ struct sigacts { sigset_t ps_sigignore; /* Signals being ignored. */ sigset_t ps_sigcatch; /* Signals being caught by user. */ sigset_t ps_freebsd4; /* signals using freebsd4 ucontext. */ + sigset_t ps_freebsd7; /* signals using freebsd4 ucontext. */ sigset_t ps_osigset; /* Signals using <= 3.x osigset_t. */ sigset_t ps_usertramp; /* SunOS compat; libc sigtramp. XXX */ int ps_flag; diff --git a/sys/sys/syscallsubr.h b/sys/sys/syscallsubr.h index ec352f8..0873efb 100644 --- a/sys/sys/syscallsubr.h +++ b/sys/sys/syscallsubr.h @@ -214,5 +214,6 @@ int kern_writev(struct thread *td, int fd, struct uio *auio); /* flags for kern_sigaction */ #define KSA_OSIGSET 0x0001 /* uses osigact_t */ #define KSA_FREEBSD4 0x0002 /* uses ucontext4 */ +#define KSA_FREEBSD7 0x0004 /* uses ucontext7 */ #endif /* !_SYS_SYSCALLSUBR_H_ */ diff --git a/sys/sys/ucontext.h b/sys/sys/ucontext.h index baa179e..323e861 100644 --- a/sys/sys/ucontext.h +++ b/sys/sys/ucontext.h @@ -67,6 +67,20 @@ struct ucontext4 { #endif /* __i386__ */ #endif /* _KERNEL */ +#if defined(_KERNEL) && (defined(COMPAT_FREEBSD5) || defined(COMPAT_FREEBSD6) \ + ||defined(COMPAT_FREEBSD7)) +#if !defined(__amd64__) && !defined(__i386__) +#define ucontext7 ucontext +#endif +struct ucontext7 { + sigset_t uc_sigmask; + struct __mcontext7 uc_mcontext; + struct ucontext7 *uc_link; + stack_t uc_stack; + int __spare__[8]; +}; +#endif + #ifndef _KERNEL __BEGIN_DECLS @@ -93,6 +107,8 @@ struct thread; /* Machine-dependent functions: */ int get_mcontext(struct thread *, mcontext_t *, int); int set_mcontext(struct thread *, const mcontext_t *); +int get_mcontext7(struct thread *, struct __mcontext7 *, int); +int set_mcontext7(struct thread *, const struct __mcontext7 *); #endif /* !_KERNEL */