summaryrefslogtreecommitdiff
path: root/usr/src/uts/i86pc/ml
diff options
context:
space:
mode:
authorjohnlev <none@none>2007-10-15 15:14:42 -0700
committerjohnlev <none@none>2007-10-15 15:14:42 -0700
commit05979f6468537821ca1496fecc054a8ca513aed7 (patch)
treee2ac67e66bff94aef31f2293d754bba4e943156f /usr/src/uts/i86pc/ml
parentd2b85481f18adf6f3720470849b073e3b8dd3ed8 (diff)
downloadillumos-joyent-05979f6468537821ca1496fecc054a8ca513aed7.tar.gz
6616864 amd64 syscall handler needs fixing for xen 3.1.1
Diffstat (limited to 'usr/src/uts/i86pc/ml')
-rw-r--r--usr/src/uts/i86pc/ml/syscall_asm_amd64.s64
1 files changed, 38 insertions, 26 deletions
diff --git a/usr/src/uts/i86pc/ml/syscall_asm_amd64.s b/usr/src/uts/i86pc/ml/syscall_asm_amd64.s
index 5470d32fed..a9c8dddd82 100644
--- a/usr/src/uts/i86pc/ml/syscall_asm_amd64.s
+++ b/usr/src/uts/i86pc/ml/syscall_asm_amd64.s
@@ -339,8 +339,41 @@ __no_rupdate_msg:
*
* Or in other words, we have no registers available at all.
* Only swapgs can save us!
+ *
+ * Under the hypervisor, the swapgs has happened already. However, the
+ * state of the world is very different from that we're familiar with.
+ *
+ * In particular, we have a stack structure like that for interrupt
+ * gates, except that the %cs and %ss registers are modified for reasons
+ * that are not entirely clear. Critically, the %rcx/%r11 values do
+ * *not* reflect the usage of those registers under a 'real' syscall[1];
+ * the stack, therefore, looks like this:
+ *
+ * 0x0(rsp) potentially junk %rcx
+ * 0x8(rsp) potentially junk %r11
+ * 0x10(rsp) user %rip
+ * 0x18(rsp) modified %cs
+ * 0x20(rsp) user %rflags
+ * 0x28(rsp) user %rsp
+ * 0x30(rsp) modified %ss
+ *
+ *
+ * and before continuing on, we must load the %rip into %rcx and the
+ * %rflags into %r11.
+ *
+ * [1] They used to, and we relied on it, but this was broken in 3.1.1.
+ * Sigh.
*/
+#if defined(__xpv)
+#define XPV_SYSCALL_PROD \
+ XPV_TRAP_POP; \
+ movq (%rsp), %rcx; \
+ movq 0x10(%rsp), %r11
+#else
+#define XPV_SYSCALL_PROD /* nothing */
+#endif
+
#if defined(__lint)
/*ARGSUSED*/
@@ -358,47 +391,26 @@ size_t _allsyscalls_size;
ENTRY_NP2(brand_sys_syscall,_allsyscalls)
SWAPGS /* kernel gsbase */
- XPV_TRAP_POP
+ XPV_SYSCALL_PROD
BRAND_CALLBACK(BRAND_CB_SYSCALL)
SWAPGS /* user gsbase */
#if defined(__xpv)
- /*
- * Note that swapgs is handled for us by the hypervisor. Here
- * it is empty.
- */
- jmp nopop_sys_syscall
+ jmp noprod_sys_syscall
#endif
ALTENTRY(sys_syscall)
SWAPGS /* kernel gsbase */
-#if defined(__xpv)
- /*
- * Even though we got here by a syscall instruction from user land
- * the hypervisor constructs our stack the same way as is done
- * for interrupt gates. The only exception is that it pushes kernel
- * cs and ss instead of user cs and ss for some reason. This is all
- * different from running native on the metal.
- *
- * Stack on entry:
- * (0x0)rsp rcx (user rip)
- * (0x8)rsp r11 (user rflags)
- * (0x10)rsp user rip
- * (0x18)rsp kernel cs
- * (0x20)rsp user rflags
- * (0x28)rsp user rsp
- * (0x30)rsp kernel ss
- */
+ XPV_SYSCALL_PROD
- XPV_TRAP_POP
-nopop_sys_syscall:
+noprod_sys_syscall:
ASSERT_UPCALL_MASK_IS_SET
movq %r15, %gs:CPU_RTMP_R15
+#if defined(__xpv)
movq 0x18(%rsp), %r15 /* save user stack */
movq %r15, %gs:CPU_RTMP_RSP
#else
- movq %r15, %gs:CPU_RTMP_R15
movq %rsp, %gs:CPU_RTMP_RSP
#endif /* __xpv */