aboutsummaryrefslogtreecommitdiffstats
path: root/arch/x86/kvm
diff options
context:
space:
mode:
authorStephan Bärwolf <stephan.baerwolf@tu-ilmenau.de>2012-01-12 10:43:04 -0500
committerAvi Kivity <avi@redhat.com>2012-02-01 04:43:40 -0500
commitc2226fc9e87ba3da060e47333657cd6616652b84 (patch)
tree0589cb84f1548ecc83999e8e61cd05121d9c51fd /arch/x86/kvm
parentbdb42f5afebe208eae90406959383856ae2caf2b (diff)
KVM: x86: fix missing checks in syscall emulation
On hosts without this patch, 32bit guests will crash (and 64bit guests may behave in a wrong way) for example by simply executing following nasm-demo-application: [bits 32] global _start SECTION .text _start: syscall (I tested it with winxp and linux - both always crashed) Disassembly of section .text: 00000000 <_start>: 0: 0f 05 syscall The reason seems a missing "invalid opcode"-trap (int6) for the syscall opcode "0f05", which is not available on Intel CPUs within non-longmodes, as also on some AMD CPUs within legacy-mode. (depending on CPU vendor, MSR_EFER and cpuid) Because previous mentioned OSs may not engage corresponding syscall target-registers (STAR, LSTAR, CSTAR), they remain NULL and (non trapping) syscalls are leading to multiple faults and finally crashs. Depending on the architecture (AMD or Intel) pretended by guests, various checks according to vendor's documentation are implemented to overcome the current issue and behave like the CPUs physical counterparts. [mtosatti: cleanup/beautify code] Signed-off-by: Stephan Baerwolf <stephan.baerwolf@tu-ilmenau.de> Signed-off-by: Marcelo Tosatti <mtosatti@redhat.com>
Diffstat (limited to 'arch/x86/kvm')
-rw-r--r--arch/x86/kvm/emulate.c51
1 files changed, 51 insertions, 0 deletions
diff --git a/arch/x86/kvm/emulate.c b/arch/x86/kvm/emulate.c
index 05a562b85025..0982507b962a 100644
--- a/arch/x86/kvm/emulate.c
+++ b/arch/x86/kvm/emulate.c
@@ -1891,6 +1891,51 @@ setup_syscalls_segments(struct x86_emulate_ctxt *ctxt,
1891 ss->p = 1; 1891 ss->p = 1;
1892} 1892}
1893 1893
1894static bool em_syscall_is_enabled(struct x86_emulate_ctxt *ctxt)
1895{
1896 struct x86_emulate_ops *ops = ctxt->ops;
1897 u32 eax, ebx, ecx, edx;
1898
1899 /*
1900 * syscall should always be enabled in longmode - so only become
1901 * vendor specific (cpuid) if other modes are active...
1902 */
1903 if (ctxt->mode == X86EMUL_MODE_PROT64)
1904 return true;
1905
1906 eax = 0x00000000;
1907 ecx = 0x00000000;
1908 if (ops->get_cpuid(ctxt, &eax, &ebx, &ecx, &edx)) {
1909 /*
1910 * Intel ("GenuineIntel")
1911 * remark: Intel CPUs only support "syscall" in 64bit
1912 * longmode. Also an 64bit guest with a
1913 * 32bit compat-app running will #UD !! While this
1914 * behaviour can be fixed (by emulating) into AMD
1915 * response - CPUs of AMD can't behave like Intel.
1916 */
1917 if (ebx == X86EMUL_CPUID_VENDOR_GenuineIntel_ebx &&
1918 ecx == X86EMUL_CPUID_VENDOR_GenuineIntel_ecx &&
1919 edx == X86EMUL_CPUID_VENDOR_GenuineIntel_edx)
1920 return false;
1921
1922 /* AMD ("AuthenticAMD") */
1923 if (ebx == X86EMUL_CPUID_VENDOR_AuthenticAMD_ebx &&
1924 ecx == X86EMUL_CPUID_VENDOR_AuthenticAMD_ecx &&
1925 edx == X86EMUL_CPUID_VENDOR_AuthenticAMD_edx)
1926 return true;
1927
1928 /* AMD ("AMDisbetter!") */
1929 if (ebx == X86EMUL_CPUID_VENDOR_AMDisbetterI_ebx &&
1930 ecx == X86EMUL_CPUID_VENDOR_AMDisbetterI_ecx &&
1931 edx == X86EMUL_CPUID_VENDOR_AMDisbetterI_edx)
1932 return true;
1933 }
1934
1935 /* default: (not Intel, not AMD), apply Intel's stricter rules... */
1936 return false;
1937}
1938
1894static int em_syscall(struct x86_emulate_ctxt *ctxt) 1939static int em_syscall(struct x86_emulate_ctxt *ctxt)
1895{ 1940{
1896 struct x86_emulate_ops *ops = ctxt->ops; 1941 struct x86_emulate_ops *ops = ctxt->ops;
@@ -1904,9 +1949,15 @@ static int em_syscall(struct x86_emulate_ctxt *ctxt)
1904 ctxt->mode == X86EMUL_MODE_VM86) 1949 ctxt->mode == X86EMUL_MODE_VM86)
1905 return emulate_ud(ctxt); 1950 return emulate_ud(ctxt);
1906 1951
1952 if (!(em_syscall_is_enabled(ctxt)))
1953 return emulate_ud(ctxt);
1954
1907 ops->get_msr(ctxt, MSR_EFER, &efer); 1955 ops->get_msr(ctxt, MSR_EFER, &efer);
1908 setup_syscalls_segments(ctxt, &cs, &ss); 1956 setup_syscalls_segments(ctxt, &cs, &ss);
1909 1957
1958 if (!(efer & EFER_SCE))
1959 return emulate_ud(ctxt);
1960
1910 ops->get_msr(ctxt, MSR_STAR, &msr_data); 1961 ops->get_msr(ctxt, MSR_STAR, &msr_data);
1911 msr_data >>= 32; 1962 msr_data >>= 32;
1912 cs_sel = (u16)(msr_data & 0xfffc); 1963 cs_sel = (u16)(msr_data & 0xfffc);