Discussion:
[PATCH 0/2] KVM guest-kernel panics double fault
Stephan Bärwolf
2012-01-10 14:26:42 UTC
Permalink
=46rom 2168285ffb30716f30e129c3ce98ce42d19c4d4e Mon Sep 17 00:00:00 200=
1
=46rom: Stephan Baerwolf <***@tu-ilmenau.de>
Date: Tue, 10 Jan 2012 14:13:22 +0100
Subject: [PATCH 0/2] KVM guest-kernel panics double fault

regarding: https://lkml.org/lkml/2011/12/28/170

On tested computers (Intel Core i5-2520M, Intel Xeon X5560
and AMD Opteron 6174 [plus some misc.]), 32bit kvm guests
(tested with winxp and linux-3.1) crash during execute of
"syscall" (opcode 0f05). (double fault due to zeroed call
of empty STAR-registers?)

64bit Intel guests behave in 32bit protected compat like
AMD and not like Intel. (which would have to #UD ...)

While the crash is bad (esp. for admins using VMs to isolate),
because every unpriv. user can execute 0f05 - the misbehaviour
with GenuineIntel-cpuid is just a blemish.

Best regards,
Stephan B=C3=A4rwolf

Stephan Baerwolf (2):
KVM: extend "struct x86_emulate_ops" with "get_cpuid"
KVM: fix missing "illegal instruction"-trap in protected modes

arch/x86/include/asm/kvm_emulate.h | 19 +++++++
arch/x86/kvm/emulate.c | 92
++++++++++++++++++++++++++++++++++-
arch/x86/kvm/x86.c | 21 ++++++++
3 files changed, 129 insertions(+), 3 deletions(-)

--=20
1.7.3.4


--
To unsubscribe from this list: send the line "unsubscribe kvm" in
the body of a message to ***@vger.kernel.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
Stephan Bärwolf
2012-01-10 14:26:46 UTC
Permalink
From c603d51a02539c89dec05fd54de336b282b1cc12 Mon Sep 17 00:00:00 2001
From: Stephan Baerwolf <***@tu-ilmenau.de>
Date: Sun, 8 Jan 2012 23:25:59 +0000
Subject: [PATCH 1/2] KVM: extend "struct x86_emulate_ops" with "get_cpuid"

In order to be able to proceed checks on CPU-specific properties
within the emulator, function "get_cpuid" is introduced.
With "get_cpuid" it is possible to virtually call the guests
"cpuid"-opcode without changing the VM's context.

Signed-off-by: Stephan Baerwolf <***@tu-ilmenau.de>
---
arch/x86/include/asm/kvm_emulate.h | 4 ++++
arch/x86/kvm/x86.c | 21 +++++++++++++++++++++
2 files changed, 25 insertions(+), 0 deletions(-)

diff --git a/arch/x86/include/asm/kvm_emulate.h
b/arch/x86/include/asm/kvm_emulate.h
index a026507..b172bf4 100644
--- a/arch/x86/include/asm/kvm_emulate.h
+++ b/arch/x86/include/asm/kvm_emulate.h
@@ -189,6 +189,10 @@ struct x86_emulate_ops {
int (*intercept)(struct x86_emulate_ctxt *ctxt,
struct x86_instruction_info *info,
enum x86_intercept_stage stage);
+
+ /* retrieve ctxt's vcpu's cpuid */
+ bool (*get_cpuid)(struct x86_emulate_ctxt *ctxt,
+ u32 *eax, u32 *ebx, u32 *ecx, u32 *edx);
};

typedef u32 __attribute__((vector_size(16))) sse128_t;
diff --git a/arch/x86/kvm/x86.c b/arch/x86/kvm/x86.c
index 4c938da..6181783 100644
--- a/arch/x86/kvm/x86.c
+++ b/arch/x86/kvm/x86.c
@@ -4655,6 +4655,26 @@ static int emulator_intercept(struct
x86_emulate_ctxt *ctxt,
return kvm_x86_ops->check_intercept(emul_to_vcpu(ctxt), info, stage);
}

+static bool emulator_get_cpuid(struct x86_emulate_ctxt *ctxt,
+ u32 *eax, u32 *ebx, u32 *ecx, u32 *edx)
+{
+ struct kvm_cpuid_entry2 *cpuid = NULL;
+
+ if ((ctxt) && (eax) && (ecx)) {
+ cpuid = kvm_find_cpuid_entry(emul_to_vcpu(ctxt), (*eax), (*ecx));
+ }
+
+ if (cpuid) {
+ (*eax)=cpuid->eax;
+ (*ecx)=cpuid->ecx;
+ if (ebx) (*ebx)=cpuid->ebx;
+ if (edx) (*edx)=cpuid->edx;
+ return true;
+ }
+
+ return false;
+}
+
static struct x86_emulate_ops emulate_ops = {
.read_std = kvm_read_guest_virt_system,
.write_std = kvm_write_guest_virt_system,
@@ -4685,6 +4705,7 @@ static struct x86_emulate_ops emulate_ops = {
.get_fpu = emulator_get_fpu,
.put_fpu = emulator_put_fpu,
.intercept = emulator_intercept,
+ .get_cpuid = emulator_get_cpuid,
};

static void cache_all_regs(struct kvm_vcpu *vcpu)
--
1.7.3.4


--
To unsubscribe from this list: send the line "unsubscribe kvm" in
the body of a message to ***@vger.kernel.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
Stephan Bärwolf
2012-01-10 14:26:49 UTC
Permalink
From 2168285ffb30716f30e129c3ce98ce42d19c4d4e Mon Sep 17 00:00:00 2001
From: Stephan Baerwolf <***@tu-ilmenau.de>
Date: Sun, 8 Jan 2012 02:03:47 +0000
Subject: [PATCH 2/2] KVM: fix missing "illegal instruction"-trap in
protected modes

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.

(Therefore using Intel's "Intel 64 and IA-32 Architecture Software
Developers Manual" http://www.intel.com/content/dam/doc/manual/
64-ia-32-architectures-software-developer-manual-325462.pdf
and AMD's "AMD64 Architecture Programmer's Manual Volume 3:
General-Purpose and System Instructions"
http://support.amd.com/us/Processor_TechDocs/APM_V3_24594.pdf )

Screenshots of an i686 testing VM (CORE i5 host) before
and after applying this patch are available under:

Loading Image...
Loading Image...

Signed-off-by: Stephan Baerwolf <***@tu-ilmenau.de>
---
arch/x86/include/asm/kvm_emulate.h | 15 ++++++
arch/x86/kvm/emulate.c | 92
++++++++++++++++++++++++++++++++++-
2 files changed, 104 insertions(+), 3 deletions(-)

diff --git a/arch/x86/include/asm/kvm_emulate.h
b/arch/x86/include/asm/kvm_emulate.h
index b172bf4..5b68c23 100644
--- a/arch/x86/include/asm/kvm_emulate.h
+++ b/arch/x86/include/asm/kvm_emulate.h
@@ -301,6 +301,21 @@ 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_AMDisbetter_ebx 0x69444d41
+#define X86EMUL_CPUID_VENDOR_AMDisbetter_ecx 0x21726574
+#define X86EMUL_CPUID_VENDOR_AMDisbetter_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 f1e3be1..3357411 100644
--- a/arch/x86/kvm/emulate.c
+++ b/arch/x86/kvm/emulate.c
@@ -1877,6 +1877,94 @@ setup_syscalls_segments(struct x86_emulate_ctxt
*ctxt,
ss->p = 1;
}

+static bool em_syscall_isenabled(struct x86_emulate_ctxt *ctxt)
+{
+ struct x86_emulate_ops *ops = ctxt->ops;
+ u64 efer = 0;
+
+ /* syscall is not available in real mode */
+ if ((ctxt->mode == X86EMUL_MODE_REAL) ||
+ (ctxt->mode == X86EMUL_MODE_VM86))
+ return false;
+
+ ops->get_msr(ctxt, MSR_EFER, &efer);
+ /* check - if guestOS is aware of syscall (0x0f05) */
+ if ((efer & EFER_SCE) == 0) {
+ return false;
+ } else {
+ /* ok, at this point it becomes vendor-specific */
+ /* so first get us an cpuid */
+ bool vendor;
+ u32 eax, ebx, ecx, edx;
+
+ /* getting the cpu-vendor */
+ eax = 0x00000000;
+ ecx = 0x00000000;
+ if (likely(ops->get_cpuid))
+ vendor = ops->get_cpuid(ctxt, &eax, &ebx, &ecx, &edx);
+ else vendor = false;
+
+ if (likely(vendor)) {
+
+ /* AMD AuthenticAMD / AMDisbetter! */
+ if (((ebx==X86EMUL_CPUID_VENDOR_AuthenticAMD_ebx) &&
+ (ecx==X86EMUL_CPUID_VENDOR_AuthenticAMD_ecx) &&
+ (edx==X86EMUL_CPUID_VENDOR_AuthenticAMD_edx)) ||
+ ((ebx==X86EMUL_CPUID_VENDOR_AMDisbetter_ebx) &&
+ (ecx==X86EMUL_CPUID_VENDOR_AMDisbetter_ecx) &&
+ (edx==X86EMUL_CPUID_VENDOR_AMDisbetter_edx))) {
+
+ /* if cpu is not in longmode... */
+ /* ...check edx bit11 of cpuid 0x80000001 */
+ if (ctxt->mode != X86EMUL_MODE_PROT64) {
+ eax = 0x80000001;
+ ecx = 0x00000000;
+ vendor = ops->get_cpuid(ctxt, &eax, &ebx, &ecx, &edx);
+ if (likely(vendor)) {
+ if (unlikely(((edx >> 11) & 0x1) == 0))
+ return false;
+ } else {
+ return false; /* assuming there is no bit 11 */
+ }
+ }
+ goto __em_syscall_enabled_noprotest;
+ } /* end "AMD" */
+
+
+ /* Intel (GenuineIntel) */
+ /* remarks: Intel CPUs only support "syscall" in 64bit longmode */
+ /* Also an 64bit guest within a 32bit compat-app running*/
+ /* will #UD !! */
+ /* While this behaviour can be fixed (by emulating) into*/
+ /* an AMD response - CPUs of AMD can't behave like Intel*/
+ /* because without an hardware-raised #UD there is no */
+ /* call in em.-mode (see x86_emulate_instruction(...))! */
+ /* TODO: make AMD-behaviour configurable */
+ if ((ebx==X86EMUL_CPUID_VENDOR_GenuineIntel_ebx) &&
+ (ecx==X86EMUL_CPUID_VENDOR_GenuineIntel_ecx) &&
+ (edx==X86EMUL_CPUID_VENDOR_GenuineIntel_edx)) {
+ if (ctxt->mode != X86EMUL_MODE_PROT64)
+ return false;
+ goto __em_syscall_enabled_noprotest;
+ } /* end "Intel" */
+
+ } /* end vendor is true */
+
+ } /* end MSR_EFER check */
+
+ /* default: */
+ /* this code wasn't able to process vendor */
+ /* so apply Intels stricter rules... */
+ pr_err_ratelimited("kvm: %i: unknown vcpu vendor - assuming
intel\n",
+ current->tgid);
+
+ if (ctxt->mode == X86EMUL_MODE_PROT64) goto
__em_syscall_enabled_noprotest;
+ return false;
+
+__em_syscall_enabled_noprotest:
+ return true;
+}
+
static int em_syscall(struct x86_emulate_ctxt *ctxt)
{
struct x86_emulate_ops *ops = ctxt->ops;
@@ -1885,9 +1973,7 @@ static int em_syscall(struct x86_emulate_ctxt *ctxt)
u16 cs_sel, ss_sel;
u64 efer = 0;

- /* syscall is not available in real mode */
- if (ctxt->mode == X86EMUL_MODE_REAL ||
- ctxt->mode == X86EMUL_MODE_VM86)
+ if (!(em_syscall_isenabled(ctxt)))
return emulate_ud(ctxt);

ops->get_msr(ctxt, MSR_EFER, &efer);
--
1.7.3.4


--
To unsubscribe from this list: send the line "unsubscribe kvm" in
the body of a message to ***@vger.kernel.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
Marcelo Tosatti
2012-01-11 19:09:28 UTC
Permalink
Post by Stephan Bärwolf
From 2168285ffb30716f30e129c3ce98ce42d19c4d4e Mon Sep 17 00:00:00 20=
01
Post by Stephan Bärwolf
Date: Sun, 8 Jan 2012 02:03:47 +0000
Subject: [PATCH 2/2] KVM: fix missing "illegal instruction"-trap in
protected modes
=20
On hosts without this patch, 32bit guests will crash
(and 64bit guests may behave in a wrong way) for
=20
[bits 32]
global _start
SECTION .text
_start: syscall
=20
(I tested it with winxp and linux - both always crashed)
=20
=20
0: 0f 05 syscall
=20
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)
=20
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.
=20
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.
=20
(Therefore using Intel's "Intel 64 and IA-32 Architecture Software
Developers Manual" http://www.intel.com/content/dam/doc/manual/
64-ia-32-architectures-software-developer-manual-325462.pdf
General-Purpose and System Instructions"
http://support.amd.com/us/Processor_TechDocs/APM_V3_24594.pdf )
=20
Screenshots of an i686 testing VM (CORE i5 host) before
=20
http://matrixstorm.com/software/linux/kvm/20111229/before.jpg
http://matrixstorm.com/software/linux/kvm/20111229/after.jpg
=20
---
arch/x86/include/asm/kvm_emulate.h | 15 ++++++
arch/x86/kvm/emulate.c | 92
++++++++++++++++++++++++++++++++++-
2 files changed, 104 insertions(+), 3 deletions(-)
=20
diff --git a/arch/x86/include/asm/kvm_emulate.h
b/arch/x86/include/asm/kvm_emulate.h
index b172bf4..5b68c23 100644
--- a/arch/x86/include/asm/kvm_emulate.h
+++ b/arch/x86/include/asm/kvm_emulate.h
@@ -301,6 +301,21 @@ struct x86_emulate_ctxt {
#define X86EMUL_MODE_PROT (X86EMUL_MODE_PROT16|X86EMUL_MODE_PROT=
32| \
Post by Stephan Bärwolf
X86EMUL_MODE_PROT64)
=20
+/* 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_AMDisbetter_ebx 0x69444d41
+#define X86EMUL_CPUID_VENDOR_AMDisbetter_ecx 0x21726574
+#define X86EMUL_CPUID_VENDOR_AMDisbetter_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 =3D 0, /* Allow zero-init to not match anything =
*/
Post by Stephan Bärwolf
X86_ICPT_PRE_EXCEPT,
diff --git a/arch/x86/kvm/emulate.c b/arch/x86/kvm/emulate.c
index f1e3be1..3357411 100644
--- a/arch/x86/kvm/emulate.c
+++ b/arch/x86/kvm/emulate.c
@@ -1877,6 +1877,94 @@ setup_syscalls_segments(struct x86_emulate_ctx=
t
Post by Stephan Bärwolf
*ctxt,
ss->p =3D 1;
}
=20
+static bool em_syscall_isenabled(struct x86_emulate_ctxt *ctxt)
+{
+ struct x86_emulate_ops *ops =3D ctxt->ops;
+ u64 efer =3D 0;
+
+ /* syscall is not available in real mode =
*/
Post by Stephan Bärwolf
+ if ((ctxt->mode =3D=3D X86EMUL_MODE_REAL) ||
+ (ctxt->mode =3D=3D X86EMUL_MODE_VM86))
+ return false;
+
+ ops->get_msr(ctxt, MSR_EFER, &efer);
+ /* check - if guestOS is aware of syscall (0x0f05) =
*/
Post by Stephan Bärwolf
+ if ((efer & EFER_SCE) =3D=3D 0) {
+ return false;
+ } else {
+ /* ok, at this point it becomes vendor-specific =
*/
Post by Stephan Bärwolf
+ /* so first get us an cpuid =
*/
Post by Stephan Bärwolf
+ bool vendor;
+ u32 eax, ebx, ecx, edx;
+
+ /* getting the cpu-vendor =
*/
Post by Stephan Bärwolf
+ eax =3D 0x00000000;
+ ecx =3D 0x00000000;
+ if (likely(ops->get_cpuid))
+ vendor =3D ops->get_cpuid(ctxt, &eax, &ebx, &ecx, &edx);
+ else vendor =3D false;
+
+ if (likely(vendor)) {
+
+ /* AMD AuthenticAMD / AMDisbetter! =
*/
Post by Stephan Bärwolf
+ if (((ebx=3D=3DX86EMUL_CPUID_VENDOR_AuthenticAMD_ebx) &&
+ (ecx=3D=3DX86EMUL_CPUID_VENDOR_AuthenticAMD_ecx) &&
+ (edx=3D=3DX86EMUL_CPUID_VENDOR_AuthenticAMD_edx)) ||
+ ((ebx=3D=3DX86EMUL_CPUID_VENDOR_AMDisbetter_ebx) &&
+ (ecx=3D=3DX86EMUL_CPUID_VENDOR_AMDisbetter_ecx) &&
+ (edx=3D=3DX86EMUL_CPUID_VENDOR_AMDisbetter_edx))) {
+
+ /* if cpu is not in longmode... =
*/
Post by Stephan Bärwolf
+ /* ...check edx bit11 of cpuid 0x80000001 =
*/
Post by Stephan Bärwolf
+ if (ctxt->mode !=3D X86EMUL_MODE_PROT64) {
+ eax =3D 0x80000001;
+ ecx =3D 0x00000000;
+ vendor =3D ops->get_cpuid(ctxt, &eax, &ebx, &ecx, &e=
dx);
Post by Stephan Bärwolf
+ if (likely(vendor)) {
+ if (unlikely(((edx >> 11) & 0x1) =3D=3D 0))
+ return false;
+ } else {
+ return false; /* assuming there is no bit 11 =
*/
Post by Stephan Bärwolf
+ }
+ }
+ goto __em_syscall_enabled_noprotest;
+ } /* end "AMD" */
+
+
+ /* Intel (GenuineIntel) =
*/
Post by Stephan Bärwolf
+ /* remarks: Intel CPUs only support "syscall" in 64bit longm=
ode */
Post by Stephan Bärwolf
+ /* Also an 64bit guest within a 32bit compat-app ru=
nning*/
Post by Stephan Bärwolf
+ /* will #UD !! =
*/
Post by Stephan Bärwolf
+ /* While this behaviour can be fixed (by emulating)=
into*/
Post by Stephan Bärwolf
+ /* an AMD response - CPUs of AMD can't behave like =
Intel*/
Post by Stephan Bärwolf
+ /* because without an hardware-raised #UD there is =
no */
Post by Stephan Bärwolf
+ /* call in em.-mode (see x86_emulate_instruction(..=
=2E))! */
Post by Stephan Bärwolf
+ /* TODO: make AMD-behaviour configurable =
*/
Post by Stephan Bärwolf
+ if ((ebx=3D=3DX86EMUL_CPUID_VENDOR_GenuineIntel_ebx) &&
+ (ecx=3D=3DX86EMUL_CPUID_VENDOR_GenuineIntel_ecx) &&
+ (edx=3D=3DX86EMUL_CPUID_VENDOR_GenuineIntel_edx)) {
+ if (ctxt->mode !=3D X86EMUL_MODE_PROT64)
+ return false;
+ goto __em_syscall_enabled_noprotest;
+ } /* end "Intel" */
+
+ } /* end vendor is true */
+
+ } /* end MSR_EFER check */
+
+ /* default: */
+ /* this code wasn't able to process vendor */
+ /* so apply Intels stricter rules... */
+ pr_err_ratelimited("kvm: %i: unknown vcpu vendor - assuming
intel\n",
+ current->tgid);
+
+ if (ctxt->mode =3D=3D X86EMUL_MODE_PROT64) goto
__em_syscall_enabled_noprotest;
+ return false;
+
+ return true;
+}
+
static int em_syscall(struct x86_emulate_ctxt *ctxt)
{
struct x86_emulate_ops *ops =3D ctxt->ops;
@@ -1885,9 +1973,7 @@ static int em_syscall(struct x86_emulate_ctxt *=
ctxt)
Post by Stephan Bärwolf
u16 cs_sel, ss_sel;
u64 efer =3D 0;
=20
- /* syscall is not available in real mode */
- if (ctxt->mode =3D=3D X86EMUL_MODE_REAL ||
- ctxt->mode =3D=3D X86EMUL_MODE_VM86)
+ if (!(em_syscall_isenabled(ctxt)))
return emulate_ud(ctxt);
=20
ops->get_msr(ctxt, MSR_EFER, &efer);
Stephan,=20

I think only the 2-line check to inject UD if EFER_SCE is not set is
missing in em_syscall. The guest is responsible for setting a proper
MSR_STAR for EIP only if it enables SCE_EFER.

Can you please test & resend that patch? Thanks.


--
To unsubscribe from this list: send the line "unsubscribe kvm" in
the body of a message to ***@vger.kernel.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
Stephan Bärwolf
2012-01-11 20:01:10 UTC
Permalink
Post by Marcelo Tosatti
Post by Stephan Bärwolf
From 2168285ffb30716f30e129c3ce98ce42d19c4d4e Mon Sep 17 00:00:00 2=
001
Post by Marcelo Tosatti
Post by Stephan Bärwolf
Date: Sun, 8 Jan 2012 02:03:47 +0000
Subject: [PATCH 2/2] KVM: fix missing "illegal instruction"-trap in
protected modes
On hosts without this patch, 32bit guests will crash
(and 64bit guests may behave in a wrong way) for
[bits 32]
global _start
SECTION .text
_start: syscall
(I tested it with winxp and linux - both always crashed)
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.
(Therefore using Intel's "Intel 64 and IA-32 Architecture Software
Developers Manual" http://www.intel.com/content/dam/doc/manual/
64-ia-32-architectures-software-developer-manual-325462.pdf
General-Purpose and System Instructions"
http://support.amd.com/us/Processor_TechDocs/APM_V3_24594.pdf )
Screenshots of an i686 testing VM (CORE i5 host) before
http://matrixstorm.com/software/linux/kvm/20111229/before.jpg
http://matrixstorm.com/software/linux/kvm/20111229/after.jpg
---
arch/x86/include/asm/kvm_emulate.h | 15 ++++++
arch/x86/kvm/emulate.c | 92
++++++++++++++++++++++++++++++++++-
2 files changed, 104 insertions(+), 3 deletions(-)
diff --git a/arch/x86/include/asm/kvm_emulate.h
b/arch/x86/include/asm/kvm_emulate.h
index b172bf4..5b68c23 100644
--- a/arch/x86/include/asm/kvm_emulate.h
+++ b/arch/x86/include/asm/kvm_emulate.h
@@ -301,6 +301,21 @@ struct x86_emulate_ctxt {
#define X86EMUL_MODE_PROT (X86EMUL_MODE_PROT16|X86EMUL_MODE_PRO=
T32| \
Post by Marcelo Tosatti
Post by Stephan Bärwolf
X86EMUL_MODE_PROT64)
=20
+/* 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_AMDisbetter_ebx 0x69444d41
+#define X86EMUL_CPUID_VENDOR_AMDisbetter_ecx 0x21726574
+#define X86EMUL_CPUID_VENDOR_AMDisbetter_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 =3D 0, /* Allow zero-init to not match anything=
*/
Post by Marcelo Tosatti
Post by Stephan Bärwolf
X86_ICPT_PRE_EXCEPT,
diff --git a/arch/x86/kvm/emulate.c b/arch/x86/kvm/emulate.c
index f1e3be1..3357411 100644
--- a/arch/x86/kvm/emulate.c
+++ b/arch/x86/kvm/emulate.c
@@ -1877,6 +1877,94 @@ setup_syscalls_segments(struct x86_emulate_ct=
xt
Post by Marcelo Tosatti
Post by Stephan Bärwolf
*ctxt,
ss->p =3D 1;
}
=20
+static bool em_syscall_isenabled(struct x86_emulate_ctxt *ctxt)
+{
+ struct x86_emulate_ops *ops =3D ctxt->ops;
+ u64 efer =3D 0;
+
+ /* syscall is not available in real mode =
*/
Post by Marcelo Tosatti
Post by Stephan Bärwolf
+ if ((ctxt->mode =3D=3D X86EMUL_MODE_REAL) ||
+ (ctxt->mode =3D=3D X86EMUL_MODE_VM86))
+ return false;
+
+ ops->get_msr(ctxt, MSR_EFER, &efer);
+ /* check - if guestOS is aware of syscall (0x0f05) =
*/
Post by Marcelo Tosatti
Post by Stephan Bärwolf
+ if ((efer & EFER_SCE) =3D=3D 0) {
+ return false;
+ } else {
+ /* ok, at this point it becomes vendor-specific =
*/
Post by Marcelo Tosatti
Post by Stephan Bärwolf
+ /* so first get us an cpuid =
*/
Post by Marcelo Tosatti
Post by Stephan Bärwolf
+ bool vendor;
+ u32 eax, ebx, ecx, edx;
+
+ /* getting the cpu-vendor =
*/
Post by Marcelo Tosatti
Post by Stephan Bärwolf
+ eax =3D 0x00000000;
+ ecx =3D 0x00000000;
+ if (likely(ops->get_cpuid))
+ vendor =3D ops->get_cpuid(ctxt, &eax, &ebx, &ecx, &edx);
+ else vendor =3D false;
+
+ if (likely(vendor)) {
+
+ /* AMD AuthenticAMD / AMDisbetter! =
*/
Post by Marcelo Tosatti
Post by Stephan Bärwolf
+ if (((ebx=3D=3DX86EMUL_CPUID_VENDOR_AuthenticAMD_ebx) &&
+ (ecx=3D=3DX86EMUL_CPUID_VENDOR_AuthenticAMD_ecx) &&
+ (edx=3D=3DX86EMUL_CPUID_VENDOR_AuthenticAMD_edx)) ||
+ ((ebx=3D=3DX86EMUL_CPUID_VENDOR_AMDisbetter_ebx) &&
+ (ecx=3D=3DX86EMUL_CPUID_VENDOR_AMDisbetter_ecx) &&
+ (edx=3D=3DX86EMUL_CPUID_VENDOR_AMDisbetter_edx))) {
+
+ /* if cpu is not in longmode... =
*/
Post by Marcelo Tosatti
Post by Stephan Bärwolf
+ /* ...check edx bit11 of cpuid 0x80000001 =
*/
Post by Marcelo Tosatti
Post by Stephan Bärwolf
+ if (ctxt->mode !=3D X86EMUL_MODE_PROT64) {
+ eax =3D 0x80000001;
+ ecx =3D 0x00000000;
+ vendor =3D ops->get_cpuid(ctxt, &eax, &ebx, &ecx, &=
edx);
Post by Marcelo Tosatti
Post by Stephan Bärwolf
+ if (likely(vendor)) {
+ if (unlikely(((edx >> 11) & 0x1) =3D=3D 0))
+ return false;
+ } else {
+ return false; /* assuming there is no bit 11 =
*/
Post by Marcelo Tosatti
Post by Stephan Bärwolf
+ }
+ }
+ goto __em_syscall_enabled_noprotest;
+ } /* end "AMD" */
+
+
+ /* Intel (GenuineIntel) =
*/
Post by Marcelo Tosatti
Post by Stephan Bärwolf
+ /* remarks: Intel CPUs only support "syscall" in 64bit long=
mode */
Post by Marcelo Tosatti
Post by Stephan Bärwolf
+ /* Also an 64bit guest within a 32bit compat-app r=
unning*/
Post by Marcelo Tosatti
Post by Stephan Bärwolf
+ /* will #UD !! =
*/
Post by Marcelo Tosatti
Post by Stephan Bärwolf
+ /* While this behaviour can be fixed (by emulating=
) into*/
Post by Marcelo Tosatti
Post by Stephan Bärwolf
+ /* an AMD response - CPUs of AMD can't behave like=
Intel*/
Post by Marcelo Tosatti
Post by Stephan Bärwolf
+ /* because without an hardware-raised #UD there is=
no */
Post by Marcelo Tosatti
Post by Stephan Bärwolf
+ /* call in em.-mode (see x86_emulate_instruction(.=
=2E.))! */
Post by Marcelo Tosatti
Post by Stephan Bärwolf
+ /* TODO: make AMD-behaviour configurable =
*/
Post by Marcelo Tosatti
Post by Stephan Bärwolf
+ if ((ebx=3D=3DX86EMUL_CPUID_VENDOR_GenuineIntel_ebx) &&
+ (ecx=3D=3DX86EMUL_CPUID_VENDOR_GenuineIntel_ecx) &&
+ (edx=3D=3DX86EMUL_CPUID_VENDOR_GenuineIntel_edx)) {
+ if (ctxt->mode !=3D X86EMUL_MODE_PROT64)
+ return false;
+ goto __em_syscall_enabled_noprotest;
+ } /* end "Intel" */
+
+ } /* end vendor is true */
+
+ } /* end MSR_EFER check */
+
+ /* default: */
+ /* this code wasn't able to process vendor */
+ /* so apply Intels stricter rules... */
+ pr_err_ratelimited("kvm: %i: unknown vcpu vendor - assuming
intel\n",
+ current->tgid);
+
+ if (ctxt->mode =3D=3D X86EMUL_MODE_PROT64) goto
__em_syscall_enabled_noprotest;
+ return false;
+
+ return true;
+}
+
static int em_syscall(struct x86_emulate_ctxt *ctxt)
{
struct x86_emulate_ops *ops =3D ctxt->ops;
@@ -1885,9 +1973,7 @@ static int em_syscall(struct x86_emulate_ctxt =
*ctxt)
Post by Marcelo Tosatti
Post by Stephan Bärwolf
u16 cs_sel, ss_sel;
u64 efer =3D 0;
=20
- /* syscall is not available in real mode */
- if (ctxt->mode =3D=3D X86EMUL_MODE_REAL ||
- ctxt->mode =3D=3D X86EMUL_MODE_VM86)
+ if (!(em_syscall_isenabled(ctxt)))
return emulate_ud(ctxt);
=20
ops->get_msr(ctxt, MSR_EFER, &efer);
Stephan,=20
I think only the 2-line check to inject UD if EFER_SCE is not set is
missing in em_syscall. The guest is responsible for setting a proper
MSR_STAR for EIP only if it enables SCE_EFER.
Can you please test & resend that patch? Thanks.
This wouln't work correctly on 64bit longmode guest
running an app in 32bit compat.
(Even on AMD in some special conditions.)
The reason is, in 64Bit compat the MSR_EFER_SCE is still
enabled but syscall is not always available by cpu in such modes.
(I also compared always with a physical computer's behaviour.)
See Intel or even AMD-doku
(http://support.amd.com/us/Processor_TechDocs/APM_V3_24594.pdf) page 37=
6.

Of course in 64bit it should NOT crash (and indeed I haven't
observed it, yet) but if I have cpuid GenuineIntel it should behave
like Intel cpu and not like some special AMD.
(Otherwise I could overwrite the vendor and then the patch will
emulate AMD...)

??What could be a good speedup: Reordering the EFER check and the
real-mode checks
(I would have to check doku, but EFER is 0 in realmode, isn't it?), the=
n
checking if (not)longmode and then:

I think, the patch ->only<- (and only!?) becomes a little bit slower
exactly
in this situation (32bit compat under 64bit long) because in every othe=
r
case?
the first ifs (testing the MSR_EFER and the mode) should decide to #UD.=
=2E.
(At all it should be faster at the end, then it is now ?)

=2E..I'll prepare a patch for what I mean...

I am looking forward to your response,

regards Stephan
--
To unsubscribe from this list: send the line "unsubscribe kvm" in
the body of a message to ***@vger.kernel.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
Marcelo Tosatti
2012-01-11 21:21:50 UTC
Permalink
Post by Stephan Bärwolf
Post by Marcelo Tosatti
Post by Stephan Bärwolf
From 2168285ffb30716f30e129c3ce98ce42d19c4d4e Mon Sep 17 00:00:00=
2001
Post by Stephan Bärwolf
Post by Marcelo Tosatti
Post by Stephan Bärwolf
Date: Sun, 8 Jan 2012 02:03:47 +0000
Subject: [PATCH 2/2] KVM: fix missing "illegal instruction"-trap i=
n
Post by Stephan Bärwolf
Post by Marcelo Tosatti
Post by Stephan Bärwolf
protected modes
On hosts without this patch, 32bit guests will crash
(and 64bit guests may behave in a wrong way) for
[bits 32]
global _start
SECTION .text
_start: syscall
(I tested it with winxp and linux - both always crashed)
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.
(Therefore using Intel's "Intel 64 and IA-32 Architecture Software
Developers Manual" http://www.intel.com/content/dam/doc/manual/
64-ia-32-architectures-software-developer-manual-325462.pdf
General-Purpose and System Instructions"
http://support.amd.com/us/Processor_TechDocs/APM_V3_24594.pdf )
Screenshots of an i686 testing VM (CORE i5 host) before
http://matrixstorm.com/software/linux/kvm/20111229/before.jpg
http://matrixstorm.com/software/linux/kvm/20111229/after.jpg
---
arch/x86/include/asm/kvm_emulate.h | 15 ++++++
arch/x86/kvm/emulate.c | 92
++++++++++++++++++++++++++++++++++-
2 files changed, 104 insertions(+), 3 deletions(-)
diff --git a/arch/x86/include/asm/kvm_emulate.h
b/arch/x86/include/asm/kvm_emulate.h
index b172bf4..5b68c23 100644
--- a/arch/x86/include/asm/kvm_emulate.h
+++ b/arch/x86/include/asm/kvm_emulate.h
@@ -301,6 +301,21 @@ struct x86_emulate_ctxt {
#define X86EMUL_MODE_PROT (X86EMUL_MODE_PROT16|X86EMUL_MODE_P=
ROT32| \
Post by Stephan Bärwolf
Post by Marcelo Tosatti
Post by Stephan Bärwolf
X86EMUL_MODE_PROT64)
=20
+/* 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_AMDisbetter_ebx 0x69444d41
+#define X86EMUL_CPUID_VENDOR_AMDisbetter_ecx 0x21726574
+#define X86EMUL_CPUID_VENDOR_AMDisbetter_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 =3D 0, /* Allow zero-init to not match anythi=
ng */
Post by Stephan Bärwolf
Post by Marcelo Tosatti
Post by Stephan Bärwolf
X86_ICPT_PRE_EXCEPT,
diff --git a/arch/x86/kvm/emulate.c b/arch/x86/kvm/emulate.c
index f1e3be1..3357411 100644
--- a/arch/x86/kvm/emulate.c
+++ b/arch/x86/kvm/emulate.c
@@ -1877,6 +1877,94 @@ setup_syscalls_segments(struct x86_emulate_=
ctxt
Post by Stephan Bärwolf
Post by Marcelo Tosatti
Post by Stephan Bärwolf
*ctxt,
ss->p =3D 1;
}
=20
+static bool em_syscall_isenabled(struct x86_emulate_ctxt *ctxt)
+{
+ struct x86_emulate_ops *ops =3D ctxt->ops;
+ u64 efer =3D 0;
+
+ /* syscall is not available in real mode =
*/
Post by Stephan Bärwolf
Post by Marcelo Tosatti
Post by Stephan Bärwolf
+ if ((ctxt->mode =3D=3D X86EMUL_MODE_REAL) ||
+ (ctxt->mode =3D=3D X86EMUL_MODE_VM86))
+ return false;
+
+ ops->get_msr(ctxt, MSR_EFER, &efer);
+ /* check - if guestOS is aware of syscall (0x0f05) =
*/
Post by Stephan Bärwolf
Post by Marcelo Tosatti
Post by Stephan Bärwolf
+ if ((efer & EFER_SCE) =3D=3D 0) {
+ return false;
+ } else {
+ /* ok, at this point it becomes vendor-specific =
*/
Post by Stephan Bärwolf
Post by Marcelo Tosatti
Post by Stephan Bärwolf
+ /* so first get us an cpuid =
*/
Post by Stephan Bärwolf
Post by Marcelo Tosatti
Post by Stephan Bärwolf
+ bool vendor;
+ u32 eax, ebx, ecx, edx;
+
+ /* getting the cpu-vendor =
*/
Post by Stephan Bärwolf
Post by Marcelo Tosatti
Post by Stephan Bärwolf
+ eax =3D 0x00000000;
+ ecx =3D 0x00000000;
+ if (likely(ops->get_cpuid))
+ vendor =3D ops->get_cpuid(ctxt, &eax, &ebx, &ecx, &edx)=
;
Post by Stephan Bärwolf
Post by Marcelo Tosatti
Post by Stephan Bärwolf
+ else vendor =3D false;
+
+ if (likely(vendor)) {
+
+ /* AMD AuthenticAMD / AMDisbetter! =
*/
Post by Stephan Bärwolf
Post by Marcelo Tosatti
Post by Stephan Bärwolf
+ if (((ebx=3D=3DX86EMUL_CPUID_VENDOR_AuthenticAMD_ebx) &&
+ (ecx=3D=3DX86EMUL_CPUID_VENDOR_AuthenticAMD_ecx) &&
+ (edx=3D=3DX86EMUL_CPUID_VENDOR_AuthenticAMD_edx)) ||
+ ((ebx=3D=3DX86EMUL_CPUID_VENDOR_AMDisbetter_ebx) &&
+ (ecx=3D=3DX86EMUL_CPUID_VENDOR_AMDisbetter_ecx) &&
+ (edx=3D=3DX86EMUL_CPUID_VENDOR_AMDisbetter_edx))) {
+
+ /* if cpu is not in longmode... =
*/
Post by Stephan Bärwolf
Post by Marcelo Tosatti
Post by Stephan Bärwolf
+ /* ...check edx bit11 of cpuid 0x80000001 =
*/
Post by Stephan Bärwolf
Post by Marcelo Tosatti
Post by Stephan Bärwolf
+ if (ctxt->mode !=3D X86EMUL_MODE_PROT64) {
+ eax =3D 0x80000001;
+ ecx =3D 0x00000000;
+ vendor =3D ops->get_cpuid(ctxt, &eax, &ebx, &ecx,=
&edx);
Post by Stephan Bärwolf
Post by Marcelo Tosatti
Post by Stephan Bärwolf
+ if (likely(vendor)) {
+ if (unlikely(((edx >> 11) & 0x1) =3D=3D 0))
+ return false;
+ } else {
+ return false; /* assuming there is no bit 11 =
*/
Post by Stephan Bärwolf
Post by Marcelo Tosatti
Post by Stephan Bärwolf
+ }
+ }
+ goto __em_syscall_enabled_noprotest;
+ } /* end "AMD" */
+
+
+ /* Intel (GenuineIntel) =
*/
Post by Stephan Bärwolf
Post by Marcelo Tosatti
Post by Stephan Bärwolf
+ /* remarks: Intel CPUs only support "syscall" in 64bit lo=
ngmode */
Post by Stephan Bärwolf
Post by Marcelo Tosatti
Post by Stephan Bärwolf
+ /* Also an 64bit guest within a 32bit compat-app=
running*/
Post by Stephan Bärwolf
Post by Marcelo Tosatti
Post by Stephan Bärwolf
+ /* will #UD !! =
*/
Post by Stephan Bärwolf
Post by Marcelo Tosatti
Post by Stephan Bärwolf
+ /* While this behaviour can be fixed (by emulati=
ng) into*/
Post by Stephan Bärwolf
Post by Marcelo Tosatti
Post by Stephan Bärwolf
+ /* an AMD response - CPUs of AMD can't behave li=
ke Intel*/
Post by Stephan Bärwolf
Post by Marcelo Tosatti
Post by Stephan Bärwolf
+ /* because without an hardware-raised #UD there =
is no */
Post by Stephan Bärwolf
Post by Marcelo Tosatti
Post by Stephan Bärwolf
+ /* call in em.-mode (see x86_emulate_instruction=
(...))! */
Post by Stephan Bärwolf
Post by Marcelo Tosatti
Post by Stephan Bärwolf
+ /* TODO: make AMD-behaviour configurable =
*/
Post by Stephan Bärwolf
Post by Marcelo Tosatti
Post by Stephan Bärwolf
+ if ((ebx=3D=3DX86EMUL_CPUID_VENDOR_GenuineIntel_ebx) &&
+ (ecx=3D=3DX86EMUL_CPUID_VENDOR_GenuineIntel_ecx) &&
+ (edx=3D=3DX86EMUL_CPUID_VENDOR_GenuineIntel_edx)) {
+ if (ctxt->mode !=3D X86EMUL_MODE_PROT64)
+ return false;
+ goto __em_syscall_enabled_noprotest;
+ } /* end "Intel" */
+
+ } /* end vendor is true */
+
+ } /* end MSR_EFER check */
+
+ /* default: */
+ /* this code wasn't able to process vendor */
+ /* so apply Intels stricter rules... */
+ pr_err_ratelimited("kvm: %i: unknown vcpu vendor - assumi=
ng
Post by Stephan Bärwolf
Post by Marcelo Tosatti
Post by Stephan Bärwolf
intel\n",
+ current->tgid);
+
+ if (ctxt->mode =3D=3D X86EMUL_MODE_PROT64) goto
__em_syscall_enabled_noprotest;
+ return false;
+
+ return true;
+}
+
static int em_syscall(struct x86_emulate_ctxt *ctxt)
{
struct x86_emulate_ops *ops =3D ctxt->ops;
@@ -1885,9 +1973,7 @@ static int em_syscall(struct x86_emulate_ctx=
t *ctxt)
Post by Stephan Bärwolf
Post by Marcelo Tosatti
Post by Stephan Bärwolf
u16 cs_sel, ss_sel;
u64 efer =3D 0;
=20
- /* syscall is not available in real mode */
- if (ctxt->mode =3D=3D X86EMUL_MODE_REAL ||
- ctxt->mode =3D=3D X86EMUL_MODE_VM86)
+ if (!(em_syscall_isenabled(ctxt)))
return emulate_ud(ctxt);
=20
ops->get_msr(ctxt, MSR_EFER, &efer);
Stephan,=20
I think only the 2-line check to inject UD if EFER_SCE is not set i=
s
Post by Stephan Bärwolf
Post by Marcelo Tosatti
missing in em_syscall. The guest is responsible for setting a prope=
r
Post by Stephan Bärwolf
Post by Marcelo Tosatti
MSR_STAR for EIP only if it enables SCE_EFER.
Can you please test & resend that patch? Thanks.
This wouln't work correctly on 64bit longmode guest
running an app in 32bit compat.
The AMD pseudo-code, in volume 3 "General-Purpose and System
Instructions", says:

SYSCALL_START:

IF (MSR_EFER.SCE =3D 0) // Check if syscall/sysret are enabled.
EXCEPTION [#UD]

IF (LONG_MODE)
SYSCALL_LONG_MODE
ELSE // (LEGACY_MODE)
SYSCALL_LEGACY_MODE
Post by Stephan Bärwolf
(Even on AMD in some special conditions.)
The reason is, in 64Bit compat the MSR_EFER_SCE is still
enabled but syscall is not always available by cpu in such modes.
(I also compared always with a physical computer's behaviour.)
See Intel or even AMD-doku
(http://support.amd.com/us/Processor_TechDocs/APM_V3_24594.pdf) page =
376.
Post by Stephan Bärwolf
=20
Of course in 64bit it should NOT crash (and indeed I haven't
observed it, yet) but if I have cpuid GenuineIntel it should behave
like Intel cpu and not like some special AMD.
(Otherwise I could overwrite the vendor and then the patch will
emulate AMD...)
=20
??What could be a good speedup: Reordering the EFER check and the
real-mode checks
(I would have to check doku, but EFER is 0 in realmode, isn't it?), t=
hen
Post by Stephan Bärwolf
=20
I think, the patch ->only<- (and only!?) becomes a little bit slower
exactly
in this situation (32bit compat under 64bit long) because in every ot=
her
Post by Stephan Bärwolf
case?
the first ifs (testing the MSR_EFER and the mode) should decide to #U=
D...
Post by Stephan Bärwolf
(At all it should be faster at the end, then it is now ?)
=20
...I'll prepare a patch for what I mean...
=20
I am looking forward to your response,
=20
regards Stephan
How about this:

diff --git a/arch/x86/kvm/emulate.c b/arch/x86/kvm/emulate.c
index 05a562b..4e8e534 100644
--- a/arch/x86/kvm/emulate.c
+++ b/arch/x86/kvm/emulate.c
@@ -1907,6 +1907,9 @@ static int em_syscall(struct x86_emulate_ctxt *ct=
xt)
ops->get_msr(ctxt, MSR_EFER, &efer);
setup_syscalls_segments(ctxt, &cs, &ss);
=20
+ if (!(efer & EFER_SCE))
+ return emulate_ud(ctxt);
+
ops->get_msr(ctxt, MSR_STAR, &msr_data);
msr_data >>=3D 32;
cs_sel =3D (u16)(msr_data & 0xfffc);
--
To unsubscribe from this list: send the line "unsubscribe kvm" in
the body of a message to ***@vger.kernel.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
Stephan Bärwolf
2012-01-11 22:19:50 UTC
Permalink
Post by Marcelo Tosatti
Post by Stephan Bärwolf
Post by Marcelo Tosatti
Post by Stephan Bärwolf
From 2168285ffb30716f30e129c3ce98ce42d19c4d4e Mon Sep 17 00:00:00=
2001
Post by Marcelo Tosatti
Post by Stephan Bärwolf
Post by Marcelo Tosatti
Post by Stephan Bärwolf
Date: Sun, 8 Jan 2012 02:03:47 +0000
Subject: [PATCH 2/2] KVM: fix missing "illegal instruction"-trap i=
n
Post by Marcelo Tosatti
Post by Stephan Bärwolf
Post by Marcelo Tosatti
Post by Stephan Bärwolf
protected modes
On hosts without this patch, 32bit guests will crash
(and 64bit guests may behave in a wrong way) for
[bits 32]
global _start
SECTION .text
_start: syscall
(I tested it with winxp and linux - both always crashed)
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.
(Therefore using Intel's "Intel 64 and IA-32 Architecture Software
Developers Manual" http://www.intel.com/content/dam/doc/manual/
64-ia-32-architectures-software-developer-manual-325462.pdf
General-Purpose and System Instructions"
http://support.amd.com/us/Processor_TechDocs/APM_V3_24594.pdf )
Screenshots of an i686 testing VM (CORE i5 host) before
http://matrixstorm.com/software/linux/kvm/20111229/before.jpg
http://matrixstorm.com/software/linux/kvm/20111229/after.jpg
---
arch/x86/include/asm/kvm_emulate.h | 15 ++++++
arch/x86/kvm/emulate.c | 92
++++++++++++++++++++++++++++++++++-
2 files changed, 104 insertions(+), 3 deletions(-)
diff --git a/arch/x86/include/asm/kvm_emulate.h
b/arch/x86/include/asm/kvm_emulate.h
index b172bf4..5b68c23 100644
--- a/arch/x86/include/asm/kvm_emulate.h
+++ b/arch/x86/include/asm/kvm_emulate.h
@@ -301,6 +301,21 @@ struct x86_emulate_ctxt {
#define X86EMUL_MODE_PROT (X86EMUL_MODE_PROT16|X86EMUL_MODE_P=
ROT32| \
Post by Marcelo Tosatti
Post by Stephan Bärwolf
Post by Marcelo Tosatti
Post by Stephan Bärwolf
X86EMUL_MODE_PROT64)
=20
+/* 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_AMDisbetter_ebx 0x69444d41
+#define X86EMUL_CPUID_VENDOR_AMDisbetter_ecx 0x21726574
+#define X86EMUL_CPUID_VENDOR_AMDisbetter_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 =3D 0, /* Allow zero-init to not match anythi=
ng */
Post by Marcelo Tosatti
Post by Stephan Bärwolf
Post by Marcelo Tosatti
Post by Stephan Bärwolf
X86_ICPT_PRE_EXCEPT,
diff --git a/arch/x86/kvm/emulate.c b/arch/x86/kvm/emulate.c
index f1e3be1..3357411 100644
--- a/arch/x86/kvm/emulate.c
+++ b/arch/x86/kvm/emulate.c
@@ -1877,6 +1877,94 @@ setup_syscalls_segments(struct x86_emulate_=
ctxt
Post by Marcelo Tosatti
Post by Stephan Bärwolf
Post by Marcelo Tosatti
Post by Stephan Bärwolf
*ctxt,
ss->p =3D 1;
}
=20
+static bool em_syscall_isenabled(struct x86_emulate_ctxt *ctxt)
+{
+ struct x86_emulate_ops *ops =3D ctxt->ops;
+ u64 efer =3D 0;
+
+ /* syscall is not available in real mode =
*/
Post by Marcelo Tosatti
Post by Stephan Bärwolf
Post by Marcelo Tosatti
Post by Stephan Bärwolf
+ if ((ctxt->mode =3D=3D X86EMUL_MODE_REAL) ||
+ (ctxt->mode =3D=3D X86EMUL_MODE_VM86))
+ return false;
+
+ ops->get_msr(ctxt, MSR_EFER, &efer);
+ /* check - if guestOS is aware of syscall (0x0f05) =
*/
Post by Marcelo Tosatti
Post by Stephan Bärwolf
Post by Marcelo Tosatti
Post by Stephan Bärwolf
+ if ((efer & EFER_SCE) =3D=3D 0) {
+ return false;
+ } else {
+ /* ok, at this point it becomes vendor-specific =
*/
Post by Marcelo Tosatti
Post by Stephan Bärwolf
Post by Marcelo Tosatti
Post by Stephan Bärwolf
+ /* so first get us an cpuid =
*/
Post by Marcelo Tosatti
Post by Stephan Bärwolf
Post by Marcelo Tosatti
Post by Stephan Bärwolf
+ bool vendor;
+ u32 eax, ebx, ecx, edx;
+
+ /* getting the cpu-vendor =
*/
Post by Marcelo Tosatti
Post by Stephan Bärwolf
Post by Marcelo Tosatti
Post by Stephan Bärwolf
+ eax =3D 0x00000000;
+ ecx =3D 0x00000000;
+ if (likely(ops->get_cpuid))
+ vendor =3D ops->get_cpuid(ctxt, &eax, &ebx, &ecx, &edx)=
;
Post by Marcelo Tosatti
Post by Stephan Bärwolf
Post by Marcelo Tosatti
Post by Stephan Bärwolf
+ else vendor =3D false;
+
+ if (likely(vendor)) {
+
+ /* AMD AuthenticAMD / AMDisbetter! =
*/
Post by Marcelo Tosatti
Post by Stephan Bärwolf
Post by Marcelo Tosatti
Post by Stephan Bärwolf
+ if (((ebx=3D=3DX86EMUL_CPUID_VENDOR_AuthenticAMD_ebx) &&
+ (ecx=3D=3DX86EMUL_CPUID_VENDOR_AuthenticAMD_ecx) &&
+ (edx=3D=3DX86EMUL_CPUID_VENDOR_AuthenticAMD_edx)) ||
+ ((ebx=3D=3DX86EMUL_CPUID_VENDOR_AMDisbetter_ebx) &&
+ (ecx=3D=3DX86EMUL_CPUID_VENDOR_AMDisbetter_ecx) &&
+ (edx=3D=3DX86EMUL_CPUID_VENDOR_AMDisbetter_edx))) {
+
+ /* if cpu is not in longmode... =
*/
Post by Marcelo Tosatti
Post by Stephan Bärwolf
Post by Marcelo Tosatti
Post by Stephan Bärwolf
+ /* ...check edx bit11 of cpuid 0x80000001 =
*/
Post by Marcelo Tosatti
Post by Stephan Bärwolf
Post by Marcelo Tosatti
Post by Stephan Bärwolf
+ if (ctxt->mode !=3D X86EMUL_MODE_PROT64) {
+ eax =3D 0x80000001;
+ ecx =3D 0x00000000;
+ vendor =3D ops->get_cpuid(ctxt, &eax, &ebx, &ecx,=
&edx);
Post by Marcelo Tosatti
Post by Stephan Bärwolf
Post by Marcelo Tosatti
Post by Stephan Bärwolf
+ if (likely(vendor)) {
+ if (unlikely(((edx >> 11) & 0x1) =3D=3D 0))
+ return false;
+ } else {
+ return false; /* assuming there is no bit 11 =
*/
Post by Marcelo Tosatti
Post by Stephan Bärwolf
Post by Marcelo Tosatti
Post by Stephan Bärwolf
+ }
+ }
+ goto __em_syscall_enabled_noprotest;
+ } /* end "AMD" */
+
+
+ /* Intel (GenuineIntel) =
*/
Post by Marcelo Tosatti
Post by Stephan Bärwolf
Post by Marcelo Tosatti
Post by Stephan Bärwolf
+ /* remarks: Intel CPUs only support "syscall" in 64bit lo=
ngmode */
Post by Marcelo Tosatti
Post by Stephan Bärwolf
Post by Marcelo Tosatti
Post by Stephan Bärwolf
+ /* Also an 64bit guest within a 32bit compat-app=
running*/
Post by Marcelo Tosatti
Post by Stephan Bärwolf
Post by Marcelo Tosatti
Post by Stephan Bärwolf
+ /* will #UD !! =
*/
Post by Marcelo Tosatti
Post by Stephan Bärwolf
Post by Marcelo Tosatti
Post by Stephan Bärwolf
+ /* While this behaviour can be fixed (by emulati=
ng) into*/
Post by Marcelo Tosatti
Post by Stephan Bärwolf
Post by Marcelo Tosatti
Post by Stephan Bärwolf
+ /* an AMD response - CPUs of AMD can't behave li=
ke Intel*/
Post by Marcelo Tosatti
Post by Stephan Bärwolf
Post by Marcelo Tosatti
Post by Stephan Bärwolf
+ /* because without an hardware-raised #UD there =
is no */
Post by Marcelo Tosatti
Post by Stephan Bärwolf
Post by Marcelo Tosatti
Post by Stephan Bärwolf
+ /* call in em.-mode (see x86_emulate_instruction=
(...))! */
Post by Marcelo Tosatti
Post by Stephan Bärwolf
Post by Marcelo Tosatti
Post by Stephan Bärwolf
+ /* TODO: make AMD-behaviour configurable =
*/
Post by Marcelo Tosatti
Post by Stephan Bärwolf
Post by Marcelo Tosatti
Post by Stephan Bärwolf
+ if ((ebx=3D=3DX86EMUL_CPUID_VENDOR_GenuineIntel_ebx) &&
+ (ecx=3D=3DX86EMUL_CPUID_VENDOR_GenuineIntel_ecx) &&
+ (edx=3D=3DX86EMUL_CPUID_VENDOR_GenuineIntel_edx)) {
+ if (ctxt->mode !=3D X86EMUL_MODE_PROT64)
+ return false;
+ goto __em_syscall_enabled_noprotest;
+ } /* end "Intel" */
+
+ } /* end vendor is true */
+
+ } /* end MSR_EFER check */
+
+ /* default: */
+ /* this code wasn't able to process vendor */
+ /* so apply Intels stricter rules... */
+ pr_err_ratelimited("kvm: %i: unknown vcpu vendor - assumi=
ng
Post by Marcelo Tosatti
Post by Stephan Bärwolf
Post by Marcelo Tosatti
Post by Stephan Bärwolf
intel\n",
+ current->tgid);
+
+ if (ctxt->mode =3D=3D X86EMUL_MODE_PROT64) goto
__em_syscall_enabled_noprotest;
+ return false;
+
+ return true;
+}
+
static int em_syscall(struct x86_emulate_ctxt *ctxt)
{
struct x86_emulate_ops *ops =3D ctxt->ops;
@@ -1885,9 +1973,7 @@ static int em_syscall(struct x86_emulate_ctx=
t *ctxt)
Post by Marcelo Tosatti
Post by Stephan Bärwolf
Post by Marcelo Tosatti
Post by Stephan Bärwolf
u16 cs_sel, ss_sel;
u64 efer =3D 0;
=20
- /* syscall is not available in real mode */
- if (ctxt->mode =3D=3D X86EMUL_MODE_REAL ||
- ctxt->mode =3D=3D X86EMUL_MODE_VM86)
+ if (!(em_syscall_isenabled(ctxt)))
return emulate_ud(ctxt);
=20
ops->get_msr(ctxt, MSR_EFER, &efer);
Stephan,=20
I think only the 2-line check to inject UD if EFER_SCE is not set i=
s
Post by Marcelo Tosatti
Post by Stephan Bärwolf
Post by Marcelo Tosatti
missing in em_syscall. The guest is responsible for setting a prope=
r
Post by Marcelo Tosatti
Post by Stephan Bärwolf
Post by Marcelo Tosatti
MSR_STAR for EIP only if it enables SCE_EFER.
Can you please test & resend that patch? Thanks.
This wouln't work correctly on 64bit longmode guest
running an app in 32bit compat.
The AMD pseudo-code, in volume 3 "General-Purpose and System
IF (MSR_EFER.SCE =3D 0) // Check if syscall/sysret are enabled.
EXCEPTION [#UD]
IF (LONG_MODE)
SYSCALL_LONG_MODE
ELSE // (LEGACY_MODE)
SYSCALL_LEGACY_MODE
Post by Stephan Bärwolf
(Even on AMD in some special conditions.)
The reason is, in 64Bit compat the MSR_EFER_SCE is still
enabled but syscall is not always available by cpu in such modes.
(I also compared always with a physical computer's behaviour.)
See Intel or even AMD-doku
(http://support.amd.com/us/Processor_TechDocs/APM_V3_24594.pdf) page=
376.
Post by Marcelo Tosatti
Post by Stephan Bärwolf
Of course in 64bit it should NOT crash (and indeed I haven't
observed it, yet) but if I have cpuid GenuineIntel it should behave
like Intel cpu and not like some special AMD.
(Otherwise I could overwrite the vendor and then the patch will
emulate AMD...)
??What could be a good speedup: Reordering the EFER check and the
real-mode checks
(I would have to check doku, but EFER is 0 in realmode, isn't it?), =
then
Post by Marcelo Tosatti
Post by Stephan Bärwolf
I think, the patch ->only<- (and only!?) becomes a little bit slower
exactly
in this situation (32bit compat under 64bit long) because in every o=
ther
Post by Marcelo Tosatti
Post by Stephan Bärwolf
case?
the first ifs (testing the MSR_EFER and the mode) should decide to #=
UD...
Post by Marcelo Tosatti
Post by Stephan Bärwolf
(At all it should be faster at the end, then it is now ?)
...I'll prepare a patch for what I mean...
I am looking forward to your response,
regards Stephan
diff --git a/arch/x86/kvm/emulate.c b/arch/x86/kvm/emulate.c
index 05a562b..4e8e534 100644
--- a/arch/x86/kvm/emulate.c
+++ b/arch/x86/kvm/emulate.c
@@ -1907,6 +1907,9 @@ static int em_syscall(struct x86_emulate_ctxt *=
ctxt)
Post by Marcelo Tosatti
ops->get_msr(ctxt, MSR_EFER, &efer);
setup_syscalls_segments(ctxt, &cs, &ss);
=20
+ if (!(efer & EFER_SCE))
+ return emulate_ud(ctxt);
+
ops->get_msr(ctxt, MSR_STAR, &msr_data);
msr_data >>=3D 32;
cs_sel =3D (u16)(msr_data & 0xfffc);
Hi Marcelo,
thank you for your fast response.

Yes, this would be more elegant, ->but<- not exact at least on Intel.
(http://www.intel.com/content/dam/doc/manual/64-ia-32-architectures-sof=
tware-developer-manual-325462.pdf)
4-586 Vol. 2B or PDF-page 1804
"[...] (* Not in 64-Bit Mode or SYSCALL/SYSRET not enabled in IA32_EFER
*) [...]"

We have to check somehow cpu-vendor to get info what cpu should be
emulated...
=2E..I'll prepare a patch by tomorrow reordering things and compacting
checks on AMD's branch.
(obviously cpuid 0x80000001 edx bit 11 needs not to be checked, as far
as the pseudocode tells... )

regards Stephan
--
To unsubscribe from this list: send the line "unsubscribe kvm" in
the body of a message to ***@vger.kernel.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
Marcelo Tosatti
2012-01-12 10:47:56 UTC
Permalink
Post by Stephan Bärwolf
Post by Marcelo Tosatti
Post by Stephan Bärwolf
On Tue, Jan 10, 2012 at 03:26:49PM +0100, Stephan B=E4rwolf wrote=
Post by Stephan Bärwolf
From 2168285ffb30716f30e129c3ce98ce42d19c4d4e Mon Sep 17 00:00:=
00 2001
Post by Stephan Bärwolf
Post by Marcelo Tosatti
Post by Stephan Bärwolf
Post by Stephan Bärwolf
Date: Sun, 8 Jan 2012 02:03:47 +0000
Subject: [PATCH 2/2] KVM: fix missing "illegal instruction"-trap=
in
Post by Stephan Bärwolf
Post by Marcelo Tosatti
Post by Stephan Bärwolf
Post by Stephan Bärwolf
protected modes
On hosts without this patch, 32bit guests will crash
(and 64bit guests may behave in a wrong way) for
[bits 32]
global _start
SECTION .text
_start: syscall
(I tested it with winxp and linux - both always crashed)
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-mod=
e.
Post by Stephan Bärwolf
Post by Marcelo Tosatti
Post by Stephan Bärwolf
Post by Stephan Bärwolf
(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.
(Therefore using Intel's "Intel 64 and IA-32 Architecture Softwa=
re
Post by Stephan Bärwolf
Post by Marcelo Tosatti
Post by Stephan Bärwolf
Post by Stephan Bärwolf
Developers Manual" http://www.intel.com/content/dam/doc/manual/
64-ia-32-architectures-software-developer-manual-325462.pdf
General-Purpose and System Instructions"
http://support.amd.com/us/Processor_TechDocs/APM_V3_24594.pdf )
Screenshots of an i686 testing VM (CORE i5 host) before
http://matrixstorm.com/software/linux/kvm/20111229/before.jpg
http://matrixstorm.com/software/linux/kvm/20111229/after.jpg
---
arch/x86/include/asm/kvm_emulate.h | 15 ++++++
arch/x86/kvm/emulate.c | 92
++++++++++++++++++++++++++++++++++-
2 files changed, 104 insertions(+), 3 deletions(-)
diff --git a/arch/x86/include/asm/kvm_emulate.h
b/arch/x86/include/asm/kvm_emulate.h
index b172bf4..5b68c23 100644
--- a/arch/x86/include/asm/kvm_emulate.h
+++ b/arch/x86/include/asm/kvm_emulate.h
@@ -301,6 +301,21 @@ struct x86_emulate_ctxt {
#define X86EMUL_MODE_PROT (X86EMUL_MODE_PROT16|X86EMUL_MODE=
_PROT32| \
Post by Stephan Bärwolf
Post by Marcelo Tosatti
Post by Stephan Bärwolf
Post by Stephan Bärwolf
X86EMUL_MODE_PROT64)
=20
+/* 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_AMDisbetter_ebx 0x69444d41
+#define X86EMUL_CPUID_VENDOR_AMDisbetter_ecx 0x21726574
+#define X86EMUL_CPUID_VENDOR_AMDisbetter_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 =3D 0, /* Allow zero-init to not match anyt=
hing */
Post by Stephan Bärwolf
Post by Marcelo Tosatti
Post by Stephan Bärwolf
Post by Stephan Bärwolf
X86_ICPT_PRE_EXCEPT,
diff --git a/arch/x86/kvm/emulate.c b/arch/x86/kvm/emulate.c
index f1e3be1..3357411 100644
--- a/arch/x86/kvm/emulate.c
+++ b/arch/x86/kvm/emulate.c
@@ -1877,6 +1877,94 @@ setup_syscalls_segments(struct x86_emulat=
e_ctxt
Post by Stephan Bärwolf
Post by Marcelo Tosatti
Post by Stephan Bärwolf
Post by Stephan Bärwolf
*ctxt,
ss->p =3D 1;
}
=20
+static bool em_syscall_isenabled(struct x86_emulate_ctxt *ctxt)
+{
+ struct x86_emulate_ops *ops =3D ctxt->ops;
+ u64 efer =3D 0;
+
+ /* syscall is not available in real mode =
*/
Post by Stephan Bärwolf
Post by Marcelo Tosatti
Post by Stephan Bärwolf
Post by Stephan Bärwolf
+ if ((ctxt->mode =3D=3D X86EMUL_MODE_REAL) ||
+ (ctxt->mode =3D=3D X86EMUL_MODE_VM86))
+ return false;
+
+ ops->get_msr(ctxt, MSR_EFER, &efer);
+ /* check - if guestOS is aware of syscall (0x0f05) =
*/
Post by Stephan Bärwolf
Post by Marcelo Tosatti
Post by Stephan Bärwolf
Post by Stephan Bärwolf
+ if ((efer & EFER_SCE) =3D=3D 0) {
+ return false;
+ } else {
+ /* ok, at this point it becomes vendor-specific =
*/
Post by Stephan Bärwolf
Post by Marcelo Tosatti
Post by Stephan Bärwolf
Post by Stephan Bärwolf
+ /* so first get us an cpuid =
*/
Post by Stephan Bärwolf
Post by Marcelo Tosatti
Post by Stephan Bärwolf
Post by Stephan Bärwolf
+ bool vendor;
+ u32 eax, ebx, ecx, edx;
+
+ /* getting the cpu-vendor =
*/
Post by Stephan Bärwolf
Post by Marcelo Tosatti
Post by Stephan Bärwolf
Post by Stephan Bärwolf
+ eax =3D 0x00000000;
+ ecx =3D 0x00000000;
+ if (likely(ops->get_cpuid))
+ vendor =3D ops->get_cpuid(ctxt, &eax, &ebx, &ecx, &ed=
x);
Post by Stephan Bärwolf
Post by Marcelo Tosatti
Post by Stephan Bärwolf
Post by Stephan Bärwolf
+ else vendor =3D false;
+
+ if (likely(vendor)) {
+
+ /* AMD AuthenticAMD / AMDisbetter! =
*/
Post by Stephan Bärwolf
Post by Marcelo Tosatti
Post by Stephan Bärwolf
Post by Stephan Bärwolf
+ if (((ebx=3D=3DX86EMUL_CPUID_VENDOR_AuthenticAMD_ebx) &=
&
Post by Stephan Bärwolf
Post by Marcelo Tosatti
Post by Stephan Bärwolf
Post by Stephan Bärwolf
+ (ecx=3D=3DX86EMUL_CPUID_VENDOR_AuthenticAMD_ecx) &=
&
Post by Stephan Bärwolf
Post by Marcelo Tosatti
Post by Stephan Bärwolf
Post by Stephan Bärwolf
+ (edx=3D=3DX86EMUL_CPUID_VENDOR_AuthenticAMD_edx)) =
||
Post by Stephan Bärwolf
Post by Marcelo Tosatti
Post by Stephan Bärwolf
Post by Stephan Bärwolf
+ ((ebx=3D=3DX86EMUL_CPUID_VENDOR_AMDisbetter_ebx) &&
+ (ecx=3D=3DX86EMUL_CPUID_VENDOR_AMDisbetter_ecx) &&
+ (edx=3D=3DX86EMUL_CPUID_VENDOR_AMDisbetter_edx))) =
{
Post by Stephan Bärwolf
Post by Marcelo Tosatti
Post by Stephan Bärwolf
Post by Stephan Bärwolf
+
+ /* if cpu is not in longmode... =
*/
Post by Stephan Bärwolf
Post by Marcelo Tosatti
Post by Stephan Bärwolf
Post by Stephan Bärwolf
+ /* ...check edx bit11 of cpuid 0x80000001 =
*/
Post by Stephan Bärwolf
Post by Marcelo Tosatti
Post by Stephan Bärwolf
Post by Stephan Bärwolf
+ if (ctxt->mode !=3D X86EMUL_MODE_PROT64) {
+ eax =3D 0x80000001;
+ ecx =3D 0x00000000;
+ vendor =3D ops->get_cpuid(ctxt, &eax, &ebx, &ec=
x, &edx);
Post by Stephan Bärwolf
Post by Marcelo Tosatti
Post by Stephan Bärwolf
Post by Stephan Bärwolf
+ if (likely(vendor)) {
+ if (unlikely(((edx >> 11) & 0x1) =3D=3D 0))
+ return false;
+ } else {
+ return false; /* assuming there is no bit 1=
1 */
Post by Stephan Bärwolf
Post by Marcelo Tosatti
Post by Stephan Bärwolf
Post by Stephan Bärwolf
+ }
+ }
+ goto __em_syscall_enabled_noprotest;
+ } /* end "AMD" */
+
+
+ /* Intel (GenuineIntel) =
*/
Post by Stephan Bärwolf
Post by Marcelo Tosatti
Post by Stephan Bärwolf
Post by Stephan Bärwolf
+ /* remarks: Intel CPUs only support "syscall" in 64bit =
longmode */
Post by Stephan Bärwolf
Post by Marcelo Tosatti
Post by Stephan Bärwolf
Post by Stephan Bärwolf
+ /* Also an 64bit guest within a 32bit compat-a=
pp running*/
Post by Stephan Bärwolf
Post by Marcelo Tosatti
Post by Stephan Bärwolf
Post by Stephan Bärwolf
+ /* will #UD !! =
*/
Post by Stephan Bärwolf
Post by Marcelo Tosatti
Post by Stephan Bärwolf
Post by Stephan Bärwolf
+ /* While this behaviour can be fixed (by emula=
ting) into*/
Post by Stephan Bärwolf
Post by Marcelo Tosatti
Post by Stephan Bärwolf
Post by Stephan Bärwolf
+ /* an AMD response - CPUs of AMD can't behave =
like Intel*/
Post by Stephan Bärwolf
Post by Marcelo Tosatti
Post by Stephan Bärwolf
Post by Stephan Bärwolf
+ /* because without an hardware-raised #UD ther=
e is no */
Post by Stephan Bärwolf
Post by Marcelo Tosatti
Post by Stephan Bärwolf
Post by Stephan Bärwolf
+ /* call in em.-mode (see x86_emulate_instructi=
on(...))! */
Post by Stephan Bärwolf
Post by Marcelo Tosatti
Post by Stephan Bärwolf
Post by Stephan Bärwolf
+ /* TODO: make AMD-behaviour configurable =
*/
Post by Stephan Bärwolf
Post by Marcelo Tosatti
Post by Stephan Bärwolf
Post by Stephan Bärwolf
+ if ((ebx=3D=3DX86EMUL_CPUID_VENDOR_GenuineIntel_ebx) &&
+ (ecx=3D=3DX86EMUL_CPUID_VENDOR_GenuineIntel_ecx) &&
+ (edx=3D=3DX86EMUL_CPUID_VENDOR_GenuineIntel_edx)) {
+ if (ctxt->mode !=3D X86EMUL_MODE_PROT64)
+ return false;
+ goto __em_syscall_enabled_noprotest;
+ } /* end "Intel" */
+
+ } /* end vendor is true */
+
+ } /* end MSR_EFER check */
+
+ /* default: */
+ /* this code wasn't able to process vendor */
+ /* so apply Intels stricter rules... */
+ pr_err_ratelimited("kvm: %i: unknown vcpu vendor - assu=
ming
Post by Stephan Bärwolf
Post by Marcelo Tosatti
Post by Stephan Bärwolf
Post by Stephan Bärwolf
intel\n",
+ current->tgid);
+
+ if (ctxt->mode =3D=3D X86EMUL_MODE_PROT64) goto
__em_syscall_enabled_noprotest;
+ return false;
+
+ return true;
+}
+
static int em_syscall(struct x86_emulate_ctxt *ctxt)
{
struct x86_emulate_ops *ops =3D ctxt->ops;
@@ -1885,9 +1973,7 @@ static int em_syscall(struct x86_emulate_c=
txt *ctxt)
Post by Stephan Bärwolf
Post by Marcelo Tosatti
Post by Stephan Bärwolf
Post by Stephan Bärwolf
u16 cs_sel, ss_sel;
u64 efer =3D 0;
=20
- /* syscall is not available in real mode */
- if (ctxt->mode =3D=3D X86EMUL_MODE_REAL ||
- ctxt->mode =3D=3D X86EMUL_MODE_VM86)
+ if (!(em_syscall_isenabled(ctxt)))
return emulate_ud(ctxt);
=20
ops->get_msr(ctxt, MSR_EFER, &efer);
Stephan,=20
I think only the 2-line check to inject UD if EFER_SCE is not set=
is
Post by Stephan Bärwolf
Post by Marcelo Tosatti
Post by Stephan Bärwolf
missing in em_syscall. The guest is responsible for setting a pro=
per
Post by Stephan Bärwolf
Post by Marcelo Tosatti
Post by Stephan Bärwolf
MSR_STAR for EIP only if it enables SCE_EFER.
Can you please test & resend that patch? Thanks.
This wouln't work correctly on 64bit longmode guest
running an app in 32bit compat.
The AMD pseudo-code, in volume 3 "General-Purpose and System
IF (MSR_EFER.SCE =3D 0) // Check if syscall/sysret are enabled.
EXCEPTION [#UD]
IF (LONG_MODE)
SYSCALL_LONG_MODE
ELSE // (LEGACY_MODE)
SYSCALL_LEGACY_MODE
Post by Stephan Bärwolf
(Even on AMD in some special conditions.)
The reason is, in 64Bit compat the MSR_EFER_SCE is still
enabled but syscall is not always available by cpu in such modes.
(I also compared always with a physical computer's behaviour.)
See Intel or even AMD-doku
(http://support.amd.com/us/Processor_TechDocs/APM_V3_24594.pdf) pa=
ge 376.
Post by Stephan Bärwolf
Post by Marcelo Tosatti
Post by Stephan Bärwolf
Of course in 64bit it should NOT crash (and indeed I haven't
observed it, yet) but if I have cpuid GenuineIntel it should behav=
e
Post by Stephan Bärwolf
Post by Marcelo Tosatti
Post by Stephan Bärwolf
like Intel cpu and not like some special AMD.
(Otherwise I could overwrite the vendor and then the patch will
emulate AMD...)
??What could be a good speedup: Reordering the EFER check and the
real-mode checks
(I would have to check doku, but EFER is 0 in realmode, isn't it?)=
, then
Post by Stephan Bärwolf
Post by Marcelo Tosatti
Post by Stephan Bärwolf
I think, the patch ->only<- (and only!?) becomes a little bit slow=
er
Post by Stephan Bärwolf
Post by Marcelo Tosatti
Post by Stephan Bärwolf
exactly
in this situation (32bit compat under 64bit long) because in every=
other
Post by Stephan Bärwolf
Post by Marcelo Tosatti
Post by Stephan Bärwolf
case?
the first ifs (testing the MSR_EFER and the mode) should decide to=
#UD...
Post by Stephan Bärwolf
Post by Marcelo Tosatti
Post by Stephan Bärwolf
(At all it should be faster at the end, then it is now ?)
...I'll prepare a patch for what I mean...
I am looking forward to your response,
regards Stephan
diff --git a/arch/x86/kvm/emulate.c b/arch/x86/kvm/emulate.c
index 05a562b..4e8e534 100644
--- a/arch/x86/kvm/emulate.c
+++ b/arch/x86/kvm/emulate.c
@@ -1907,6 +1907,9 @@ static int em_syscall(struct x86_emulate_ctxt=
*ctxt)
Post by Stephan Bärwolf
Post by Marcelo Tosatti
ops->get_msr(ctxt, MSR_EFER, &efer);
setup_syscalls_segments(ctxt, &cs, &ss);
=20
+ if (!(efer & EFER_SCE))
+ return emulate_ud(ctxt);
+
ops->get_msr(ctxt, MSR_STAR, &msr_data);
msr_data >>=3D 32;
cs_sel =3D (u16)(msr_data & 0xfffc);
Hi Marcelo,
thank you for your fast response.
=20
Yes, this would be more elegant, ->but<- not exact at least on Intel.
(http://www.intel.com/content/dam/doc/manual/64-ia-32-architectures-s=
oftware-developer-manual-325462.pdf)
Post by Stephan Bärwolf
4-586 Vol. 2B or PDF-page 1804
"[...] (* Not in 64-Bit Mode or SYSCALL/SYSRET not enabled in IA32_EF=
ER
Post by Stephan Bärwolf
*) [...]"
=20
We have to check somehow cpu-vendor to get info what cpu should be
emulated...
...I'll prepare a patch by tomorrow reordering things and compacting
checks on AMD's branch.
(obviously cpuid 0x80000001 edx bit 11 needs not to be checked, as fa=
r
Post by Stephan Bärwolf
as the pseudocode tells... )
Right. Please have the EFER check as i suggested (its cleaner), and
then only this check for Intel should suffice:

+ /* TODO: make AMD-behaviour configurable */
+ if ((ebx=3D=3DX86EMUL_CPUID_VENDOR_GenuineIntel_ebx) &&
+ (ecx=3D=3DX86EMUL_CPUID_VENDOR_GenuineIntel_ecx) &&
+ (edx=3D=3DX86EMUL_CPUID_VENDOR_GenuineIntel_edx)) {
+ if (ctxt->mode !=3D X86EMUL_MODE_PROT64)

Please mind Documentation/CodingStyle. Thanks.


--
To unsubscribe from this list: send the line "unsubscribe kvm" in
the body of a message to ***@vger.kernel.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
Stephan Bärwolf
2012-01-12 15:43:00 UTC
Permalink
From d62ca9897e9970d777aec1d399318b0df44489bd Mon Sep 17 00:00:00 2001
From: Stephan Baerwolf <***@tu-ilmenau.de>
Date: Thu, 12 Jan 2012 16:32:46 +0100
Subject: [PATCH 0/2] KVM guest-kernel panics double fault

regarding: https://lkml.org/lkml/2011/12/28/170

On tested computers (Intel Core i5-2520M, Intel Xeon X5560
and AMD Opteron 6174 [plus some misc.]), 32bit kvm guests
(tested with winxp and linux-3.1) crash during execute of
"syscall" (opcode 0f05). (double fault due to zeroed call
of empty STAR-registers?)

64bit Intel guests behave in 32bit protected compat like
AMD and not like Intel. (which would have to #UD ...)

While the crash is bad (esp. for admins using VMs to isolate),
because every unpriv. user can execute 0f05 - the misbehaviour
with GenuineIntel-cpuid is just a blemish.

Best regards,
Stephan BÀrwolf


Stephan Baerwolf (2):
KVM: extend "struct x86_emulate_ops" with "get_cpuid"
KVM: fix missing "illegal instruction"-trap in protected modes

arch/x86/include/asm/kvm_emulate.h | 19 ++++++++
arch/x86/kvm/emulate.c | 80
++++++++++++++++++++++++++++++++++-
arch/x86/kvm/x86.c | 21 +++++++++
3 files changed, 117 insertions(+), 3 deletions(-)
--
1.7.3.4
Jan Kiszka
2012-01-12 15:56:33 UTC
Permalink
From d62ca9897e9970d777aec1d399318b0df44489bd Mon Sep 17 00:00:00 200=
1
Date: Thu, 12 Jan 2012 16:32:46 +0100
Subject: [PATCH 0/2] KVM guest-kernel panics double fault
=20
regarding: https://lkml.org/lkml/2011/12/28/170
=20
On tested computers (Intel Core i5-2520M, Intel Xeon X5560
and AMD Opteron 6174 [plus some misc.]), 32bit kvm guests
(tested with winxp and linux-3.1) crash during execute of
"syscall" (opcode 0f05). (double fault due to zeroed call
of empty STAR-registers?)
=20
64bit Intel guests behave in 32bit protected compat like
AMD and not like Intel. (which would have to #UD ...)
=20
While the crash is bad (esp. for admins using VMs to isolate),
because every unpriv. user can execute 0f05 - the misbehaviour
with GenuineIntel-cpuid is just a blemish.
=20
Best regards,
Stephan B=C3=A4rwolf
=20
=20
KVM: extend "struct x86_emulate_ops" with "get_cpuid"
KVM: fix missing "illegal instruction"-trap in protected modes
=20
arch/x86/include/asm/kvm_emulate.h | 19 ++++++++
arch/x86/kvm/emulate.c | 80
++++++++++++++++++++++++++++++++++-
arch/x86/kvm/x86.c | 21 +++++++++
3 files changed, 117 insertions(+), 3 deletions(-)
=20
linux/scripts/checkpatch.pl can help identifying remaining style violat=
ions.

Moreover, when sending your patches via Thunderbird, you first need to
make sure that you have its line wrapping under control. "Toggle Word
Wrap" helps me for single patches. But for series, I prefer (scripted)
git format-patch/send-email.

Jan

--=20
Siemens AG, Corporate Technology, CT T DE IT 1
Corporate Competence Center Embedded Linux
--
To unsubscribe from this list: send the line "unsubscribe kvm" in
the body of a message to ***@vger.kernel.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
Marcelo Tosatti
2012-01-13 10:13:25 UTC
Permalink
Post by Stephan Bärwolf
KVM: extend "struct x86_emulate_ops" with "get_cpuid"
KVM: fix missing "illegal instruction"-trap in protected modes
arch/x86/include/asm/kvm_emulate.h | 19 ++++++++
arch/x86/kvm/emulate.c | 80
++++++++++++++++++++++++++++++++++-
arch/x86/kvm/x86.c | 21 +++++++++
3 files changed, 117 insertions(+), 3 deletions(-)
linux/scripts/checkpatch.pl can help identifying remaining style violations.
Moreover, when sending your patches via Thunderbird, you first need to
make sure that you have its line wrapping under control. "Toggle Word
Wrap" helps me for single patches. But for series, I prefer (scripted)
git format-patch/send-email.
Applied a cleanup up version of these patches. Thanks Stephan.

http://git.kernel.org/?p=virt/kvm/kvm.git;a=commit;h=0769c5de24621141c953fbe1f943582d37cb4244

http://git.kernel.org/?p=virt/kvm/kvm.git;a=commit;h=e28ba7bb020f07193bc000453c8775e9d2c0dda7


--
To unsubscribe from this list: send the line "unsubscribe kvm" in
the body of a message to ***@vger.kernel.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
Stephan Bärwolf
2012-01-15 19:44:50 UTC
Permalink
Thank you for applying this, Marcelo.

I fear we (or me after I agreed) did some mistake by erasing the additi=
onal
cpuid 0x80000001 checks.
In contradiction to only AMD it MUST also apply on Intel-CPUs.

Documentation
"http://www.intel.com/content/dam/doc/manual/64-ia-32-architectures-sof=
tware-developer-manual-325462.pdf"
Vol. 2A 3-207 (PDF-page 811) first block of table.
(in addition AMD's doku "http://support.amd.com/us/Processor_TechDocs/A=
PM_V3_24594.pdf"
page 376 (PDF-page 408) table "Exceptions" on the bottom)

Not all CPUs might have a syscall op at all (even in longmode) - they i=
nforming about that
via cpuid (But MSR_EFER may be still set).
(You can force it externally in qemu-kvm-emulation via "-cpu host,-sysc=
all" ...)
So an (guest) operating-system might not install *STAR-registers and cr=
ash again on such vcpus, right?

I'll prepare some patch, asap. So everybody can judge this...

regards, Stephan
Post by Marcelo Tosatti
Post by Stephan Bärwolf
KVM: extend "struct x86_emulate_ops" with "get_cpuid"
KVM: fix missing "illegal instruction"-trap in protected modes
arch/x86/include/asm/kvm_emulate.h | 19 ++++++++
arch/x86/kvm/emulate.c | 80
++++++++++++++++++++++++++++++++++-
arch/x86/kvm/x86.c | 21 +++++++++
3 files changed, 117 insertions(+), 3 deletions(-)
linux/scripts/checkpatch.pl can help identifying remaining style vio=
lations.
Post by Marcelo Tosatti
Moreover, when sending your patches via Thunderbird, you first need =
to
Post by Marcelo Tosatti
make sure that you have its line wrapping under control. "Toggle Wor=
d
Post by Marcelo Tosatti
Wrap" helps me for single patches. But for series, I prefer (scripte=
d)
Post by Marcelo Tosatti
git format-patch/send-email.
Applied a cleanup up version of these patches. Thanks Stephan.
http://git.kernel.org/?p=3Dvirt/kvm/kvm.git;a=3Dcommit;h=3D0769c5de24=
621141c953fbe1f943582d37cb4244
Post by Marcelo Tosatti
http://git.kernel.org/?p=3Dvirt/kvm/kvm.git;a=3Dcommit;h=3De28ba7bb02=
0f07193bc000453c8775e9d2c0dda7
--=20
Dipl.-Inf. Stephan B=C3=A4rwolf
Ilmenau University of Technology, Integrated Communication Systems Grou=
p
Phone: +49 (0)3677 69 4130
Email: ***@tu-ilmenau.de, =20
Web: http://www.tu-ilmenau.de/iks

--
To unsubscribe from this list: send the line "unsubscribe kvm" in
the body of a message to ***@vger.kernel.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
Marcelo Tosatti
2012-01-16 09:58:09 UTC
Permalink
Post by Stephan Bärwolf
Thank you for applying this, Marcelo.
=20
I fear we (or me after I agreed) did some mistake by erasing the addi=
tional
Post by Stephan Bärwolf
cpuid 0x80000001 checks.
In contradiction to only AMD it MUST also apply on Intel-CPUs.
=20
Documentation
"http://www.intel.com/content/dam/doc/manual/64-ia-32-architectures-s=
oftware-developer-manual-325462.pdf"
Post by Stephan Bärwolf
Vol. 2A 3-207 (PDF-page 811) first block of table.
(in addition AMD's doku "http://support.amd.com/us/Processor_TechDocs=
/APM_V3_24594.pdf"
Post by Stephan Bärwolf
page 376 (PDF-page 408) table "Exceptions" on the bottom)
=20
Not all CPUs might have a syscall op at all (even in longmode) - they=
informing about that
Post by Stephan Bärwolf
via cpuid (But MSR_EFER may be still set).
(You can force it externally in qemu-kvm-emulation via "-cpu host,-sy=
scall" ...)
Post by Stephan Bärwolf
So an (guest) operating-system might not install *STAR-registers and =
crash again on such vcpus, right?

No because if the operating system does not install the STAR MSRs, it
will not set SCE bit in MSR_EFER (and your patch handles that=20
situation).

--
To unsubscribe from this list: send the line "unsubscribe kvm" in
the body of a message to ***@vger.kernel.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
Stephan Bärwolf
2012-01-16 11:24:17 UTC
Permalink
Okay, thx to hear a second opinion.

Then everything is ok, have a nice day.

regards Stephan
Post by Marcelo Tosatti
Post by Stephan Bärwolf
Thank you for applying this, Marcelo.
I fear we (or me after I agreed) did some mistake by erasing the add=
itional
Post by Marcelo Tosatti
Post by Stephan Bärwolf
cpuid 0x80000001 checks.
In contradiction to only AMD it MUST also apply on Intel-CPUs.
Documentation
"http://www.intel.com/content/dam/doc/manual/64-ia-32-architectures-=
software-developer-manual-325462.pdf"
Post by Marcelo Tosatti
Post by Stephan Bärwolf
Vol. 2A 3-207 (PDF-page 811) first block of table.
(in addition AMD's doku "http://support.amd.com/us/Processor_TechDoc=
s/APM_V3_24594.pdf"
Post by Marcelo Tosatti
Post by Stephan Bärwolf
page 376 (PDF-page 408) table "Exceptions" on the bottom)
Not all CPUs might have a syscall op at all (even in longmode) - the=
y informing about that
Post by Marcelo Tosatti
Post by Stephan Bärwolf
via cpuid (But MSR_EFER may be still set).
(You can force it externally in qemu-kvm-emulation via "-cpu host,-s=
yscall" ...)
Post by Marcelo Tosatti
Post by Stephan Bärwolf
So an (guest) operating-system might not install *STAR-registers and=
crash again on such vcpus, right?
Post by Marcelo Tosatti
No because if the operating system does not install the STAR MSRs, it
will not set SCE bit in MSR_EFER (and your patch handles that=20
situation).
--=20
Dipl.-Inf. Stephan B=E4rwolf
Ilmenau University of Technology, Integrated Communication Systems Grou=
p
Phone: +49 (0)3677 69 4130
Email: ***@tu-ilmenau.de, =20
Web: http://www.tu-ilmenau.de/iks

--
To unsubscribe from this list: send the line "unsubscribe kvm" in
the body of a message to ***@vger.kernel.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
Stephan Bärwolf
2012-01-12 15:43:03 UTC
Permalink
From a8f796f81979094b81cb74535632786ce1ccf9bb Mon Sep 17 00:00:00 2001
From: Stephan Baerwolf <***@tu-ilmenau.de>
Date: Sun, 8 Jan 2012 23:25:59 +0000
Subject: [PATCH 1/2] KVM: extend "struct x86_emulate_ops" with "get_cpuid"

In order to be able to proceed checks on CPU-specific properties
within the emulator, function "get_cpuid" is introduced.
With "get_cpuid" it is possible to virtually call the guests
"cpuid"-opcode without changing the VM's context.

Cc: <***@vger.kernel.org>
Signed-off-by: Stephan Baerwolf <***@tu-ilmenau.de>
---
arch/x86/include/asm/kvm_emulate.h | 4 ++++
arch/x86/kvm/x86.c | 21 +++++++++++++++++++++
2 files changed, 25 insertions(+), 0 deletions(-)

diff --git a/arch/x86/include/asm/kvm_emulate.h
b/arch/x86/include/asm/kvm_emulate.h
index a026507..b172bf4 100644
--- a/arch/x86/include/asm/kvm_emulate.h
+++ b/arch/x86/include/asm/kvm_emulate.h
@@ -189,6 +189,10 @@ struct x86_emulate_ops {
int (*intercept)(struct x86_emulate_ctxt *ctxt,
struct x86_instruction_info *info,
enum x86_intercept_stage stage);
+
+ /* retrieve ctxt's vcpu's cpuid */
+ bool (*get_cpuid)(struct x86_emulate_ctxt *ctxt,
+ u32 *eax, u32 *ebx, u32 *ecx, u32 *edx);
};

typedef u32 __attribute__((vector_size(16))) sse128_t;
diff --git a/arch/x86/kvm/x86.c b/arch/x86/kvm/x86.c
index 4c938da..6181783 100644
--- a/arch/x86/kvm/x86.c
+++ b/arch/x86/kvm/x86.c
@@ -4655,6 +4655,26 @@ static int emulator_intercept(struct
x86_emulate_ctxt *ctxt,
return kvm_x86_ops->check_intercept(emul_to_vcpu(ctxt), info, stage);
}

+static bool emulator_get_cpuid(struct x86_emulate_ctxt *ctxt,
+ u32 *eax, u32 *ebx, u32 *ecx, u32 *edx)
+{
+ struct kvm_cpuid_entry2 *cpuid = NULL;
+
+ if ((ctxt) && (eax) && (ecx)) {
+ cpuid = kvm_find_cpuid_entry(emul_to_vcpu(ctxt), (*eax), (*ecx));
+ }
+
+ if (cpuid) {
+ (*eax)=cpuid->eax;
+ (*ecx)=cpuid->ecx;
+ if (ebx) (*ebx)=cpuid->ebx;
+ if (edx) (*edx)=cpuid->edx;
+ return true;
+ }
+
+ return false;
+}
+
static struct x86_emulate_ops emulate_ops = {
.read_std = kvm_read_guest_virt_system,
.write_std = kvm_write_guest_virt_system,
@@ -4685,6 +4705,7 @@ static struct x86_emulate_ops emulate_ops = {
.get_fpu = emulator_get_fpu,
.put_fpu = emulator_put_fpu,
.intercept = emulator_intercept,
+ .get_cpuid = emulator_get_cpuid,
};

static void cache_all_regs(struct kvm_vcpu *vcpu)
--
1.7.3.4
Stephan Bärwolf
2012-01-12 15:43:04 UTC
Permalink
From d62ca9897e9970d777aec1d399318b0df44489bd Mon Sep 17 00:00:00 2001
From: Stephan Baerwolf <***@tu-ilmenau.de>
Date: Sun, 8 Jan 2012 02:03:47 +0000
Subject: [PATCH 2/2] KVM: fix missing "illegal instruction"-trap in
protected modes

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.

(Therefore using Intel's "Intel 64 and IA-32 Architecture Software
Developers Manual" http://www.intel.com/content/dam/doc/manual/
64-ia-32-architectures-software-developer-manual-325462.pdf
and AMD's "AMD64 Architecture Programmer's Manual Volume 3:
General-Purpose and System Instructions"
http://support.amd.com/us/Processor_TechDocs/APM_V3_24594.pdf )

Screenshots of an i686 testing VM (CORE i5 host) before
and after applying this patch are available under:

http://matrixstorm.com/software/linux/kvm/20111229/before.jpg
http://matrixstorm.com/software/linux/kvm/20111229/after.jpg

Cc: <***@vger.kernel.org>
Signed-off-by: Stephan Baerwolf <***@tu-ilmenau.de>
---
arch/x86/include/asm/kvm_emulate.h | 15 +++++++
arch/x86/kvm/emulate.c | 80
++++++++++++++++++++++++++++++++++-
2 files changed, 92 insertions(+), 3 deletions(-)

diff --git a/arch/x86/include/asm/kvm_emulate.h
b/arch/x86/include/asm/kvm_emulate.h
index b172bf4..f0da4d9 100644
--- a/arch/x86/include/asm/kvm_emulate.h
+++ b/arch/x86/include/asm/kvm_emulate.h
@@ -301,6 +301,21 @@ 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 f1e3be1..29140ae 100644
--- a/arch/x86/kvm/emulate.c
+++ b/arch/x86/kvm/emulate.c
@@ -1877,6 +1877,82 @@ setup_syscalls_segments(struct x86_emulate_ctxt
*ctxt,
ss->p = 1;
}

+static bool em_syscall_isenabled(struct x86_emulate_ctxt *ctxt)
+{
+ struct x86_emulate_ops *ops = ctxt->ops;
+ u64 efer = 0;
+
+ /* NO check for lock-prefix here - done in x86_emulate_instruction()*/
+
+ ops->get_msr(ctxt, MSR_EFER, &efer);
+
+ /* we assume EFER_SCE is unset in REAL and VM86 so with this we */
+ /* should speedup the #UD case */
+ if ((efer & EFER_SCE) == 0)
+ return false;
+
+ /* syscall should always be enabled in longmode - so only become */
+ /* vendorspecific (cpuid) if other modes are active... */
+ if (ctxt->mode != X86EMUL_MODE_PROT64) {
+ bool vendor;
+ u32 eax, ebx, ecx, edx;
+
+ /* syscall is not available in real mode - #UD without cpuid... */
+ if ((ctxt->mode == X86EMUL_MODE_REAL) ||
+ (ctxt->mode == X86EMUL_MODE_VM86))
+ return false;
+
+ /* getting the cpu-vendor */
+ eax = 0x00000000;
+ ecx = 0x00000000;
+ if (likely(ops->get_cpuid)) {
+ vendor = ops->get_cpuid(ctxt, &eax, &ebx, &ecx, &edx);
+ } else vendor = false;
+
+ if (likely(vendor)) {
+
+ /* 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 an AMD response - CPUs of AMD can't behave like */
+ /* Intel, because without an hardware-raised #UD there */
+ /* is no call in em.-mode (see x86_emulate_instruction) */
+ if ((ebx==X86EMUL_CPUID_VENDOR_GenuineIntel_ebx) &&
+ (ecx==X86EMUL_CPUID_VENDOR_GenuineIntel_ecx) &&
+ (edx==X86EMUL_CPUID_VENDOR_GenuineIntel_edx))
+ return false;
+
+ /* end "Intel" */
+
+
+ /* AMD ("AuthenticAMD" / "AMDisbetter!") */
+ if (((ebx==X86EMUL_CPUID_VENDOR_AuthenticAMD_ebx) &&
+ (ecx==X86EMUL_CPUID_VENDOR_AuthenticAMD_ecx) &&
+ (edx==X86EMUL_CPUID_VENDOR_AuthenticAMD_edx)) ||
+ ((ebx==X86EMUL_CPUID_VENDOR_AMDisbetterI_ebx) &&
+ (ecx==X86EMUL_CPUID_VENDOR_AMDisbetterI_ecx) &&
+ (edx==X86EMUL_CPUID_VENDOR_AMDisbetterI_edx))) {
+
+ goto __em_syscall_enabled_noprotest;
+ } /* end "AMD" */
+
+ } /* end vendor is true */
+
+
+ /* default: (not Intel, not AMD ...) */
+ /* this code wasn't able to process vendor */
+ /* so apply Intels stricter rules... */
+ pr_err_ratelimited("kvm: %i: unknown vcpu vendor - assuming intel\n",
+ current->tgid);
+ return false;
+ } /* end "not longmode" */
+
+__em_syscall_enabled_noprotest:
+ return true;
+}
+
static int em_syscall(struct x86_emulate_ctxt *ctxt)
{
struct x86_emulate_ops *ops = ctxt->ops;
@@ -1885,9 +1961,7 @@ static int em_syscall(struct x86_emulate_ctxt *ctxt)
u16 cs_sel, ss_sel;
u64 efer = 0;

- /* syscall is not available in real mode */
- if (ctxt->mode == X86EMUL_MODE_REAL ||
- ctxt->mode == X86EMUL_MODE_VM86)
+ if (!(em_syscall_isenabled(ctxt)))
return emulate_ud(ctxt);

ops->get_msr(ctxt, MSR_EFER, &efer);
--
1.7.3.4
Loading...