diff options
Diffstat (limited to 'arch/x86/kvm/emulate.c')
-rw-r--r-- | arch/x86/kvm/emulate.c | 51 |
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 | ||
1894 | static 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 | |||
1894 | static int em_syscall(struct x86_emulate_ctxt *ctxt) | 1939 | static 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); |