summaryrefslogtreecommitdiffstats
path: root/arch/x86/kvm/emulate.c
diff options
context:
space:
mode:
authorOlof Johansson <olof@lixom.net>2012-02-10 12:40:34 -0800
committerOlof Johansson <olof@lixom.net>2012-02-10 12:40:34 -0800
commit082f53c2f573c75a8f1610c587a43b6817e20f90 (patch)
treec3ad3a58967e7f7f61ff12ff59284dba1e76d093 /arch/x86/kvm/emulate.c
parente69128b947da0a2474447868f73c76311e2baedb (diff)
parentb024e33682c8e56cc8e869245dabd1b91ffe00ea (diff)
Merge branch 'for-arm-soc' of git://sources.calxeda.com/kernel/linux into next/soc
* 'for-arm-soc' of git://sources.calxeda.com/kernel/linux: (247 commits) ARM: highbank: remove unused memory.h ARM: highbank: enable sp804 based sched_clock ARM: timer-sp: add sched_clock support Linux 3.3-rc3 pcmcia: fix socket refcount decrementing on each resume mm: fix UP THP spin_is_locked BUGs drivers/leds/leds-lm3530.c: fix setting pltfm->als_vmax mm: compaction: check for overlapping nodes during isolation for migration nilfs2: avoid overflowing segment numbers in nilfs_ioctl_clean_segments() ASoC: wm8994: Disable line output discharge prior to ramping VMID ASoC: wm8994: Fix typo in VMID ramp setting ALSA: oxygen, virtuoso: fix exchanged L/R volumes of aux and CD inputs ALSA: usb-audio: add Edirol UM-3G support checkpatch: Warn on code with 6+ tab indentation ACPI: remove duplicated lines of merging problems with acpi_processor_add ALSA: hda - add support for Uniwill ECS M31EI notebook HID: wiimote: fix invalid power_supply_powers call ALSA: hda - Fix error handling in patch_ca0132.c target: Fix unsupported WRITE_SAME sense payload iscsi: use IP_FREEBIND socket option ...
Diffstat (limited to 'arch/x86/kvm/emulate.c')
-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 05a562b8502..0982507b962 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,
ss->p = 1;
}
+static bool em_syscall_is_enabled(struct x86_emulate_ctxt *ctxt)
+{
+ struct x86_emulate_ops *ops = ctxt->ops;
+ u32 eax, ebx, ecx, edx;
+
+ /*
+ * syscall should always be enabled in longmode - so only become
+ * vendor specific (cpuid) if other modes are active...
+ */
+ if (ctxt->mode == X86EMUL_MODE_PROT64)
+ return true;
+
+ eax = 0x00000000;
+ ecx = 0x00000000;
+ if (ops->get_cpuid(ctxt, &eax, &ebx, &ecx, &edx)) {
+ /*
+ * Intel ("GenuineIntel")
+ * remark: Intel CPUs only support "syscall" in 64bit
+ * longmode. Also an 64bit guest with a
+ * 32bit compat-app running will #UD !! While this
+ * behaviour can be fixed (by emulating) into AMD
+ * response - CPUs of AMD can't behave like Intel.
+ */
+ if (ebx == X86EMUL_CPUID_VENDOR_GenuineIntel_ebx &&
+ ecx == X86EMUL_CPUID_VENDOR_GenuineIntel_ecx &&
+ edx == X86EMUL_CPUID_VENDOR_GenuineIntel_edx)
+ return false;
+
+ /* AMD ("AuthenticAMD") */
+ if (ebx == X86EMUL_CPUID_VENDOR_AuthenticAMD_ebx &&
+ ecx == X86EMUL_CPUID_VENDOR_AuthenticAMD_ecx &&
+ edx == X86EMUL_CPUID_VENDOR_AuthenticAMD_edx)
+ return true;
+
+ /* AMD ("AMDisbetter!") */
+ if (ebx == X86EMUL_CPUID_VENDOR_AMDisbetterI_ebx &&
+ ecx == X86EMUL_CPUID_VENDOR_AMDisbetterI_ecx &&
+ edx == X86EMUL_CPUID_VENDOR_AMDisbetterI_edx)
+ return true;
+ }
+
+ /* default: (not Intel, not AMD), apply Intel's stricter rules... */
+ return false;
+}
+
static int em_syscall(struct x86_emulate_ctxt *ctxt)
{
struct x86_emulate_ops *ops = ctxt->ops;
@@ -1904,9 +1949,15 @@ static int em_syscall(struct x86_emulate_ctxt *ctxt)
ctxt->mode == X86EMUL_MODE_VM86)
return emulate_ud(ctxt);
+ if (!(em_syscall_is_enabled(ctxt)))
+ return emulate_ud(ctxt);
+
ops->get_msr(ctxt, MSR_EFER, &efer);
setup_syscalls_segments(ctxt, &cs, &ss);
+ if (!(efer & EFER_SCE))
+ return emulate_ud(ctxt);
+
ops->get_msr(ctxt, MSR_STAR, &msr_data);
msr_data >>= 32;
cs_sel = (u16)(msr_data & 0xfffc);