diff options
Diffstat (limited to 'sys/amd64')
-rw-r--r-- | sys/amd64/ia32/ia32_sigtramp.S | 31 | ||||
-rw-r--r-- | sys/amd64/ia32/ia32_syscall.c | 2 |
2 files changed, 27 insertions, 6 deletions
diff --git a/sys/amd64/ia32/ia32_sigtramp.S b/sys/amd64/ia32/ia32_sigtramp.S index 710834c..3541988 100644 --- a/sys/amd64/ia32/ia32_sigtramp.S +++ b/sys/amd64/ia32/ia32_sigtramp.S @@ -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 diff --git a/sys/amd64/ia32/ia32_syscall.c b/sys/amd64/ia32/ia32_syscall.c index d79272a..0cdec6f 100644 --- a/sys/amd64/ia32/ia32_syscall.c +++ b/sys/amd64/ia32/ia32_syscall.c @@ -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; |