Date: Tue, 14 Aug 2012 12:13:27 +0000 (UTC) From: Konstantin Belousov <kib@FreeBSD.org> To: src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-head@freebsd.org Subject: svn commit: r239251 - head/sys/amd64/ia32 Message-ID: <201208141213.q7ECDRrZ093233@svn.freebsd.org>
next in thread | raw e-mail | index | archive | help
Author: kib Date: Tue Aug 14 12:13:27 2012 New Revision: 239251 URL: http://svn.freebsd.org/changeset/base/239251 Log: Real hardware, as opposed to QEMU, does not allow to have a call gate in long mode which transfers control to 32bit code segment. Unbreak the lcall $7,$0 implementation on amd64 by putting the 64bit user code segment' selector into call gate, and execute the 64bit trampoline which converts the return frame into 32bit format and switches back to 32bit mode for executing int $0x80 trampoline. Note that all jumps over the hoops are performed in the user mode. MFC after: 1 week Modified: head/sys/amd64/ia32/ia32_sigtramp.S head/sys/amd64/ia32/ia32_syscall.c Modified: head/sys/amd64/ia32/ia32_sigtramp.S ============================================================================== --- head/sys/amd64/ia32/ia32_sigtramp.S Tue Aug 14 12:11:48 2012 (r239250) +++ head/sys/amd64/ia32/ia32_sigtramp.S Tue Aug 14 12:13:27 2012 (r239251) @@ -91,8 +91,29 @@ ia32_osigcode: */ ALIGN_TEXT lcall_tramp: + .code64 + /* + * There, we are in 64bit mode and need to return to 32bit. + * First, convert call frame from 64 to 32 bit format. + */ + pushq %rax + movl 16(%rsp),%eax + movl %eax,20(%rsp) /* ret %cs */ + movl 8(%rsp),%eax + movl %eax,16(%rsp) /* ret %rip -> %eip */ + popq %rax + addq $8,%rsp + /* Now return to 32bit */ + pushq $0x33 /* _ucode32sel UPL */ + callq 1f +1: + addq $2f-1b,(%rsp) + lretq +2: + /* Back in 32bit mode */ + .code32 cmpl $SYS_vfork,%eax - je 2f + je 4f pushl %ebp movl %esp,%ebp pushl 0x24(%ebp) /* arg 6 */ @@ -101,19 +122,19 @@ lcall_tramp: pushl 0x18(%ebp) pushl 0x14(%ebp) pushl 0x10(%ebp) /* arg 1 */ - pushl 0xc(%ebp) /* gap */ + pushl 0xc(%ebp) /* gap */ int $0x80 leavel -1: +3: lretl -2: +4: /* * vfork handling is special and relies on the libc stub saving * the return ip in %ecx. If vfork failed, then there is no * child which can corrupt the frame created by call gate. */ int $0x80 - jb 1b + jb 3b addl $8,%esp jmpl *%ecx #endif Modified: head/sys/amd64/ia32/ia32_syscall.c ============================================================================== --- head/sys/amd64/ia32/ia32_syscall.c Tue Aug 14 12:11:48 2012 (r239250) +++ head/sys/amd64/ia32/ia32_syscall.c Tue Aug 14 12:13:27 2012 (r239251) @@ -244,7 +244,7 @@ setup_lcall_gate(void) bzero(ssd, sizeof(*ssd)); ssd->gd_looffset = lcall_addr; ssd->gd_hioffset = lcall_addr >> 16; - ssd->gd_selector = _ucode32sel; + ssd->gd_selector = _ucodesel; ssd->gd_type = SDT_SYSCGT; ssd->gd_dpl = SEL_UPL; ssd->gd_p = 1;
Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?201208141213.q7ECDRrZ093233>