|
@@ -1891,6 +1891,51 @@ setup_syscalls_segments(struct x86_emulate_ctxt *ctxt,
|
|
ss->p = 1;
|
|
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)
|
|
static int em_syscall(struct x86_emulate_ctxt *ctxt)
|
|
{
|
|
{
|
|
struct x86_emulate_ops *ops = ctxt->ops;
|
|
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)
|
|
ctxt->mode == X86EMUL_MODE_VM86)
|
|
return emulate_ud(ctxt);
|
|
return emulate_ud(ctxt);
|
|
|
|
|
|
|
|
+ if (!(em_syscall_is_enabled(ctxt)))
|
|
|
|
+ return emulate_ud(ctxt);
|
|
|
|
+
|
|
ops->get_msr(ctxt, MSR_EFER, &efer);
|
|
ops->get_msr(ctxt, MSR_EFER, &efer);
|
|
setup_syscalls_segments(ctxt, &cs, &ss);
|
|
setup_syscalls_segments(ctxt, &cs, &ss);
|
|
|
|
|
|
|
|
+ if (!(efer & EFER_SCE))
|
|
|
|
+ return emulate_ud(ctxt);
|
|
|
|
+
|
|
ops->get_msr(ctxt, MSR_STAR, &msr_data);
|
|
ops->get_msr(ctxt, MSR_STAR, &msr_data);
|
|
msr_data >>= 32;
|
|
msr_data >>= 32;
|
|
cs_sel = (u16)(msr_data & 0xfffc);
|
|
cs_sel = (u16)(msr_data & 0xfffc);
|