aboutsummaryrefslogtreecommitdiffstats
path: root/arch/x86
diff options
context:
space:
mode:
authorBorislav Petkov <bp@suse.de>2013-10-29 07:54:56 -0400
committerPaolo Bonzini <pbonzini@redhat.com>2013-10-30 13:54:41 -0400
commit84cffe499b9418d6c3b4de2ad9599cc2ec50c607 (patch)
treee6558ea19648dd028cd877640d9fa8a934c42dee /arch/x86
parent0bc5eedb82a54ccd9cbf79825226dd068427a94a (diff)
kvm: Emulate MOVBE
This basically came from the need to be able to boot 32-bit Atom SMP guests on an AMD host, i.e. a host which doesn't support MOVBE. As a matter of fact, qemu has since recently received MOVBE support but we cannot share that with kvm emulation and thus we have to do this in the host. We're waay faster in kvm anyway. :-) So, we piggyback on the #UD path and emulate the MOVBE functionality. With it, an 8-core SMP guest boots in under 6 seconds. Also, requesting MOVBE emulation needs to happen explicitly to work, i.e. qemu -cpu n270,+movbe... Just FYI, a fairly straight-forward boot of a MOVBE-enabled 3.9-rc6+ kernel in kvm executes MOVBE ~60K times. Signed-off-by: Andre Przywara <andre@andrep.de> Signed-off-by: Borislav Petkov <bp@suse.de> Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
Diffstat (limited to 'arch/x86')
-rw-r--r--arch/x86/kvm/cpuid.c18
-rw-r--r--arch/x86/kvm/emulate.c53
2 files changed, 66 insertions, 5 deletions
diff --git a/arch/x86/kvm/cpuid.c b/arch/x86/kvm/cpuid.c
index 78a4439bfdc5..86d5756dda07 100644
--- a/arch/x86/kvm/cpuid.c
+++ b/arch/x86/kvm/cpuid.c
@@ -222,6 +222,22 @@ static bool supported_xcr0_bit(unsigned bit)
222static int __do_cpuid_ent_emulated(struct kvm_cpuid_entry2 *entry, 222static int __do_cpuid_ent_emulated(struct kvm_cpuid_entry2 *entry,
223 u32 func, u32 index, int *nent, int maxnent) 223 u32 func, u32 index, int *nent, int maxnent)
224{ 224{
225 switch (func) {
226 case 0:
227 entry->eax = 1; /* only one leaf currently */
228 ++*nent;
229 break;
230 case 1:
231 entry->ecx = F(MOVBE);
232 ++*nent;
233 break;
234 default:
235 break;
236 }
237
238 entry->function = func;
239 entry->index = index;
240
225 return 0; 241 return 0;
226} 242}
227 243
@@ -593,7 +609,7 @@ int kvm_dev_ioctl_get_cpuid(struct kvm_cpuid2 *cpuid,
593 return -EINVAL; 609 return -EINVAL;
594 610
595 r = -ENOMEM; 611 r = -ENOMEM;
596 cpuid_entries = vmalloc(sizeof(struct kvm_cpuid_entry2) * cpuid->nent); 612 cpuid_entries = vzalloc(sizeof(struct kvm_cpuid_entry2) * cpuid->nent);
597 if (!cpuid_entries) 613 if (!cpuid_entries)
598 goto out; 614 goto out;
599 615
diff --git a/arch/x86/kvm/emulate.c b/arch/x86/kvm/emulate.c
index 6c5cfe962b28..8e2a07bd8eac 100644
--- a/arch/x86/kvm/emulate.c
+++ b/arch/x86/kvm/emulate.c
@@ -2961,6 +2961,46 @@ static int em_mov(struct x86_emulate_ctxt *ctxt)
2961 return X86EMUL_CONTINUE; 2961 return X86EMUL_CONTINUE;
2962} 2962}
2963 2963
2964#define FFL(x) bit(X86_FEATURE_##x)
2965
2966static int em_movbe(struct x86_emulate_ctxt *ctxt)
2967{
2968 u32 ebx, ecx, edx, eax = 1;
2969 u16 tmp;
2970
2971 /*
2972 * Check MOVBE is set in the guest-visible CPUID leaf.
2973 */
2974 ctxt->ops->get_cpuid(ctxt, &eax, &ebx, &ecx, &edx);
2975 if (!(ecx & FFL(MOVBE)))
2976 return emulate_ud(ctxt);
2977
2978 switch (ctxt->op_bytes) {
2979 case 2:
2980 /*
2981 * From MOVBE definition: "...When the operand size is 16 bits,
2982 * the upper word of the destination register remains unchanged
2983 * ..."
2984 *
2985 * Both casting ->valptr and ->val to u16 breaks strict aliasing
2986 * rules so we have to do the operation almost per hand.
2987 */
2988 tmp = (u16)ctxt->src.val;
2989 ctxt->dst.val &= ~0xffffUL;
2990 ctxt->dst.val |= (unsigned long)swab16(tmp);
2991 break;
2992 case 4:
2993 ctxt->dst.val = swab32((u32)ctxt->src.val);
2994 break;
2995 case 8:
2996 ctxt->dst.val = swab64(ctxt->src.val);
2997 break;
2998 default:
2999 return X86EMUL_PROPAGATE_FAULT;
3000 }
3001 return X86EMUL_CONTINUE;
3002}
3003
2964static int em_cr_write(struct x86_emulate_ctxt *ctxt) 3004static int em_cr_write(struct x86_emulate_ctxt *ctxt)
2965{ 3005{
2966 if (ctxt->ops->set_cr(ctxt, ctxt->modrm_reg, ctxt->src.val)) 3006 if (ctxt->ops->set_cr(ctxt, ctxt->modrm_reg, ctxt->src.val))
@@ -3893,11 +3933,11 @@ static const struct opcode twobyte_table[256] = {
3893}; 3933};
3894 3934
3895static const struct gprefix three_byte_0f_38_f0 = { 3935static const struct gprefix three_byte_0f_38_f0 = {
3896 N, N, N, N 3936 I(DstReg | SrcMem | Mov, em_movbe), N, N, N
3897}; 3937};
3898 3938
3899static const struct gprefix three_byte_0f_38_f1 = { 3939static const struct gprefix three_byte_0f_38_f1 = {
3900 N, N, N, N 3940 I(DstMem | SrcReg | Mov, em_movbe), N, N, N
3901}; 3941};
3902 3942
3903/* 3943/*
@@ -3907,8 +3947,13 @@ static const struct gprefix three_byte_0f_38_f1 = {
3907static const struct opcode opcode_map_0f_38[256] = { 3947static const struct opcode opcode_map_0f_38[256] = {
3908 /* 0x00 - 0x7f */ 3948 /* 0x00 - 0x7f */
3909 X16(N), X16(N), X16(N), X16(N), X16(N), X16(N), X16(N), X16(N), 3949 X16(N), X16(N), X16(N), X16(N), X16(N), X16(N), X16(N), X16(N),
3910 /* 0x80 - 0xff */ 3950 /* 0x80 - 0xef */
3911 X16(N), X16(N), X16(N), X16(N), X16(N), X16(N), X16(N), X16(N) 3951 X16(N), X16(N), X16(N), X16(N), X16(N), X16(N), X16(N),
3952 /* 0xf0 - 0xf1 */
3953 GP(EmulateOnUD | ModRM | Prefix, &three_byte_0f_38_f0),
3954 GP(EmulateOnUD | ModRM | Prefix, &three_byte_0f_38_f1),
3955 /* 0xf2 - 0xff */
3956 N, N, X4(N), X8(N)
3912}; 3957};
3913 3958
3914#undef D 3959#undef D