On Thu, Mar 22, 2012 at 09:50:44AM +0100, Stefan Bader wrote: > >From 30870b1a5d29c07b75843c0b667fa29a63d818a4 Mon Sep 17 00:00:00 2001 > From: =?UTF-8?q?Stephan=20B=C3=A4rwolf?= <stephan.baerwolf@xxxxxxxxxxxxx> > Date: Thu, 12 Jan 2012 16:43:04 +0100 > Subject: [PATCH 8/8] 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@xxxxxxxxxxxxx> > Signed-off-by: Marcelo Tosatti <mtosatti@xxxxxxxxxx> > > (backported from commit c2226fc9e87ba3da060e47333657cd6616652b84 upstream) > Signed-off-by: Stefan Bader <stefan.bader@xxxxxxxxxxxxx> > --- > arch/x86/include/asm/kvm_emulate.h | 13 +++++++++ > arch/x86/kvm/emulate.c | 51 ++++++++++++++++++++++++++++++++++++ > 2 files changed, 64 insertions(+), 0 deletions(-) > > diff --git a/arch/x86/include/asm/kvm_emulate.h b/arch/x86/include/asm/kvm_emulate.h > index 18e54f1..0ab6a4d 100644 > --- a/arch/x86/include/asm/kvm_emulate.h > +++ b/arch/x86/include/asm/kvm_emulate.h > @@ -301,6 +301,19 @@ struct x86_emulate_ctxt { > #define X86EMUL_MODE_PROT (X86EMUL_MODE_PROT16|X86EMUL_MODE_PROT32| \ > X86EMUL_MODE_PROT64) > > +/* CPUID vendors */ > +#define X86EMUL_CPUID_VENDOR_AuthenticAMD_ebx 0x68747541 > +#define X86EMUL_CPUID_VENDOR_AuthenticAMD_ecx 0x444d4163 > +#define X86EMUL_CPUID_VENDOR_AuthenticAMD_edx 0x69746e65 > + > +#define X86EMUL_CPUID_VENDOR_AMDisbetterI_ebx 0x69444d41 > +#define X86EMUL_CPUID_VENDOR_AMDisbetterI_ecx 0x21726574 > +#define X86EMUL_CPUID_VENDOR_AMDisbetterI_edx 0x74656273 > + > +#define X86EMUL_CPUID_VENDOR_GenuineIntel_ebx 0x756e6547 > +#define X86EMUL_CPUID_VENDOR_GenuineIntel_ecx 0x6c65746e > +#define X86EMUL_CPUID_VENDOR_GenuineIntel_edx 0x49656e69 > + > enum x86_intercept_stage { > X86_ICTP_NONE = 0, /* Allow zero-init to not match anything */ > X86_ICPT_PRE_EXCEPT, > diff --git a/arch/x86/kvm/emulate.c b/arch/x86/kvm/emulate.c > index adc9867..3e7d913 100644 > --- a/arch/x86/kvm/emulate.c > +++ b/arch/x86/kvm/emulate.c > @@ -1901,6 +1901,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 > emulate_syscall(struct x86_emulate_ctxt *ctxt, struct x86_emulate_ops *ops) > { > @@ -1915,9 +1960,15 @@ emulate_syscall(struct x86_emulate_ctxt *ctxt, struct x86_emulate_ops *ops) > 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, ops, &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); ACK -- To unsubscribe from this list: send the line "unsubscribe kvm" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html