3aa57a6
From e28ba7bb020f07193bc000453c8775e9d2c0dda7 Mon Sep 17 00:00:00 2001
3aa57a6
From: =?UTF-8?q?Stephan=20B=C3=A4rwolf?= <stephan.baerwolf@tu-ilmenau.de>
3aa57a6
Date: Thu, 12 Jan 2012 16:43:04 +0100
3aa57a6
Subject: [PATCH 2/2] KVM: x86: fix missing checks in syscall emulation
3aa57a6
3aa57a6
On hosts without this patch, 32bit guests will crash (and 64bit guests
3aa57a6
may behave in a wrong way) for example by simply executing following
3aa57a6
nasm-demo-application:
3aa57a6
3aa57a6
    [bits 32]
3aa57a6
    global _start
3aa57a6
    SECTION .text
3aa57a6
    _start: syscall
3aa57a6
3aa57a6
(I tested it with winxp and linux - both always crashed)
3aa57a6
3aa57a6
    Disassembly of section .text:
3aa57a6
3aa57a6
    00000000 <_start>:
3aa57a6
       0:   0f 05                   syscall
3aa57a6
3aa57a6
The reason seems a missing "invalid opcode"-trap (int6) for the
3aa57a6
syscall opcode "0f05", which is not available on Intel CPUs
3aa57a6
within non-longmodes, as also on some AMD CPUs within legacy-mode.
3aa57a6
(depending on CPU vendor, MSR_EFER and cpuid)
3aa57a6
3aa57a6
Because previous mentioned OSs may not engage corresponding
3aa57a6
syscall target-registers (STAR, LSTAR, CSTAR), they remain
3aa57a6
NULL and (non trapping) syscalls are leading to multiple
3aa57a6
faults and finally crashs.
3aa57a6
3aa57a6
Depending on the architecture (AMD or Intel) pretended by
3aa57a6
guests, various checks according to vendor's documentation
3aa57a6
are implemented to overcome the current issue and behave
3aa57a6
like the CPUs physical counterparts.
3aa57a6
3aa57a6
[mtosatti: cleanup/beautify code]
3aa57a6
3aa57a6
Signed-off-by: Stephan Baerwolf <stephan.baerwolf@tu-ilmenau.de>
3aa57a6
Signed-off-by: Marcelo Tosatti <mtosatti@redhat.com>
3aa57a6
---
3aa57a6
 arch/x86/include/asm/kvm_emulate.h |   13 +++++++++
3aa57a6
 arch/x86/kvm/emulate.c             |   51 ++++++++++++++++++++++++++++++++++++
3aa57a6
 2 files changed, 64 insertions(+), 0 deletions(-)
3aa57a6
3aa57a6
diff --git a/arch/x86/include/asm/kvm_emulate.h b/arch/x86/include/asm/kvm_emulate.h
3aa57a6
index c8b2868..7b9cfc4 100644
3aa57a6
--- a/arch/x86/include/asm/kvm_emulate.h
3aa57a6
+++ b/arch/x86/include/asm/kvm_emulate.h
3aa57a6
@@ -301,6 +301,19 @@ struct x86_emulate_ctxt {
3aa57a6
 #define X86EMUL_MODE_PROT     (X86EMUL_MODE_PROT16|X86EMUL_MODE_PROT32| \
3aa57a6
 			       X86EMUL_MODE_PROT64)
3aa57a6
 
3aa57a6
+/* CPUID vendors */
3aa57a6
+#define X86EMUL_CPUID_VENDOR_AuthenticAMD_ebx 0x68747541
3aa57a6
+#define X86EMUL_CPUID_VENDOR_AuthenticAMD_ecx 0x444d4163
3aa57a6
+#define X86EMUL_CPUID_VENDOR_AuthenticAMD_edx 0x69746e65
3aa57a6
+
3aa57a6
+#define X86EMUL_CPUID_VENDOR_AMDisbetterI_ebx 0x69444d41
3aa57a6
+#define X86EMUL_CPUID_VENDOR_AMDisbetterI_ecx 0x21726574
3aa57a6
+#define X86EMUL_CPUID_VENDOR_AMDisbetterI_edx 0x74656273
3aa57a6
+
3aa57a6
+#define X86EMUL_CPUID_VENDOR_GenuineIntel_ebx 0x756e6547
3aa57a6
+#define X86EMUL_CPUID_VENDOR_GenuineIntel_ecx 0x6c65746e
3aa57a6
+#define X86EMUL_CPUID_VENDOR_GenuineIntel_edx 0x49656e69
3aa57a6
+
3aa57a6
 enum x86_intercept_stage {
3aa57a6
 	X86_ICTP_NONE = 0,   /* Allow zero-init to not match anything */
3aa57a6
 	X86_ICPT_PRE_EXCEPT,
3aa57a6
diff --git a/arch/x86/kvm/emulate.c b/arch/x86/kvm/emulate.c
3aa57a6
index 05a562b..0982507 100644
3aa57a6
--- a/arch/x86/kvm/emulate.c
3aa57a6
+++ b/arch/x86/kvm/emulate.c
3aa57a6
@@ -1891,6 +1891,51 @@ setup_syscalls_segments(struct x86_emulate_ctxt *ctxt,
3aa57a6
 	ss->p = 1;
3aa57a6
 }
3aa57a6
 
3aa57a6
+static bool em_syscall_is_enabled(struct x86_emulate_ctxt *ctxt)
3aa57a6
+{
3aa57a6
+	struct x86_emulate_ops *ops = ctxt->ops;
3aa57a6
+	u32 eax, ebx, ecx, edx;
3aa57a6
+
3aa57a6
+	/*
3aa57a6
+	 * syscall should always be enabled in longmode - so only become
3aa57a6
+	 * vendor specific (cpuid) if other modes are active...
3aa57a6
+	 */
3aa57a6
+	if (ctxt->mode == X86EMUL_MODE_PROT64)
3aa57a6
+		return true;
3aa57a6
+
3aa57a6
+	eax = 0x00000000;
3aa57a6
+	ecx = 0x00000000;
3aa57a6
+	if (ops->get_cpuid(ctxt, &eax, &ebx, &ecx, &edx)) {
3aa57a6
+		/*
3aa57a6
+		 * Intel ("GenuineIntel")
3aa57a6
+		 * remark: Intel CPUs only support "syscall" in 64bit
3aa57a6
+		 * longmode. Also an 64bit guest with a
3aa57a6
+		 * 32bit compat-app running will #UD !! While this
3aa57a6
+		 * behaviour can be fixed (by emulating) into AMD
3aa57a6
+		 * response - CPUs of AMD can't behave like Intel.
3aa57a6
+		 */
3aa57a6
+		if (ebx == X86EMUL_CPUID_VENDOR_GenuineIntel_ebx &&
3aa57a6
+		    ecx == X86EMUL_CPUID_VENDOR_GenuineIntel_ecx &&
3aa57a6
+		    edx == X86EMUL_CPUID_VENDOR_GenuineIntel_edx)
3aa57a6
+			return false;
3aa57a6
+
3aa57a6
+		/* AMD ("AuthenticAMD") */
3aa57a6
+		if (ebx == X86EMUL_CPUID_VENDOR_AuthenticAMD_ebx &&
3aa57a6
+		    ecx == X86EMUL_CPUID_VENDOR_AuthenticAMD_ecx &&
3aa57a6
+		    edx == X86EMUL_CPUID_VENDOR_AuthenticAMD_edx)
3aa57a6
+			return true;
3aa57a6
+
3aa57a6
+		/* AMD ("AMDisbetter!") */
3aa57a6
+		if (ebx == X86EMUL_CPUID_VENDOR_AMDisbetterI_ebx &&
3aa57a6
+		    ecx == X86EMUL_CPUID_VENDOR_AMDisbetterI_ecx &&
3aa57a6
+		    edx == X86EMUL_CPUID_VENDOR_AMDisbetterI_edx)
3aa57a6
+			return true;
3aa57a6
+	}
3aa57a6
+
3aa57a6
+	/* default: (not Intel, not AMD), apply Intel's stricter rules... */
3aa57a6
+	return false;
3aa57a6
+}
3aa57a6
+
3aa57a6
 static int em_syscall(struct x86_emulate_ctxt *ctxt)
3aa57a6
 {
3aa57a6
 	struct x86_emulate_ops *ops = ctxt->ops;
3aa57a6
@@ -1904,9 +1949,15 @@ static int em_syscall(struct x86_emulate_ctxt *ctxt)
3aa57a6
 	    ctxt->mode == X86EMUL_MODE_VM86)
3aa57a6
 		return emulate_ud(ctxt);
3aa57a6
 
3aa57a6
+	if (!(em_syscall_is_enabled(ctxt)))
3aa57a6
+		return emulate_ud(ctxt);
3aa57a6
+
3aa57a6
 	ops->get_msr(ctxt, MSR_EFER, &efer);
3aa57a6
 	setup_syscalls_segments(ctxt, &cs, &ss);
3aa57a6
 
3aa57a6
+	if (!(efer & EFER_SCE))
3aa57a6
+		return emulate_ud(ctxt);
3aa57a6
+
3aa57a6
 	ops->get_msr(ctxt, MSR_STAR, &msr_data);
3aa57a6
 	msr_data >>= 32;
3aa57a6
 	cs_sel = (u16)(msr_data & 0xfffc);
3aa57a6
-- 
3aa57a6
1.7.7.5
3aa57a6