summaryrefslogtreecommitdiffstats
path: root/sys/amd64/ia32
diff options
context:
space:
mode:
Diffstat (limited to 'sys/amd64/ia32')
-rw-r--r--sys/amd64/ia32/ia32_sigtramp.S31
-rw-r--r--sys/amd64/ia32/ia32_syscall.c2
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;
OpenPOWER on IntegriCloud