From 1e35d3c4a7a9682256c887a1388cf3faefdf53df Mon Sep 17 00:00:00 2001 From: Avi Kivity Date: Fri, 26 Oct 2007 14:16:56 +0200 Subject: [PATCH 1/5] KVM: x86 emulator: fix 'push imm8' emulation 'push imm8' found itself in the wrong switch somehow, so it is never executed. This fixes Windows 2003 installation. Signed-off-by: Avi Kivity --- drivers/kvm/x86_emulate.c | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/drivers/kvm/x86_emulate.c b/drivers/kvm/x86_emulate.c index a6ace302e0cd..da0cdd521da9 100644 --- a/drivers/kvm/x86_emulate.c +++ b/drivers/kvm/x86_emulate.c @@ -980,17 +980,6 @@ done_prefixes: goto cannot_emulate; dst.val = (s32) src.val; break; - case 0x6a: /* push imm8 */ - src.val = 0L; - src.val = insn_fetch(s8, 1, _eip); -push: - dst.type = OP_MEM; - dst.bytes = op_bytes; - dst.val = src.val; - register_address_increment(_regs[VCPU_REGS_RSP], -op_bytes); - dst.ptr = (void *) register_address(ctxt->ss_base, - _regs[VCPU_REGS_RSP]); - break; case 0x80 ... 0x83: /* Grp1 */ switch (modrm_reg) { case 0: @@ -1243,6 +1232,17 @@ special_insn: register_address_increment(_regs[VCPU_REGS_RSP], op_bytes); no_wb = 1; /* Disable writeback. */ break; + case 0x6a: /* push imm8 */ + src.val = 0L; + src.val = insn_fetch(s8, 1, _eip); + push: + dst.type = OP_MEM; + dst.bytes = op_bytes; + dst.val = src.val; + register_address_increment(_regs[VCPU_REGS_RSP], -op_bytes); + dst.ptr = (void *) register_address(ctxt->ss_base, + _regs[VCPU_REGS_RSP]); + break; case 0x6c: /* insb */ case 0x6d: /* insw/insd */ if (kvm_emulate_pio_string(ctxt->vcpu, NULL, From 70433389ccfe2719ef5cd539d04172260294f0f5 Mon Sep 17 00:00:00 2001 From: Avi Kivity Date: Wed, 7 Nov 2007 12:57:23 +0200 Subject: [PATCH 2/5] KVM: SVM: Fix SMP with kernel apic AP processor needs to reset to the SIPI vector, not normal INIT. Signed-off-by: Avi Kivity --- drivers/kvm/svm.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/drivers/kvm/svm.c b/drivers/kvm/svm.c index 729f1cd93606..3910358db79d 100644 --- a/drivers/kvm/svm.c +++ b/drivers/kvm/svm.c @@ -561,6 +561,12 @@ static void svm_vcpu_reset(struct kvm_vcpu *vcpu) struct vcpu_svm *svm = to_svm(vcpu); init_vmcb(svm->vmcb); + + if (vcpu->vcpu_id != 0) { + svm->vmcb->save.rip = 0; + svm->vmcb->save.cs.base = svm->vcpu.sipi_vector << 12; + svm->vmcb->save.cs.selector = svm->vcpu.sipi_vector << 8; + } } static struct kvm_vcpu *svm_create_vcpu(struct kvm *kvm, unsigned int id) From 56ba47ddbd5af7918bf1acdbe3deb979d0dcd64b Mon Sep 17 00:00:00 2001 From: Avi Kivity Date: Wed, 7 Nov 2007 17:14:18 +0200 Subject: [PATCH 3/5] KVM: SVM: Defer nmi processing until switch to host state is complete If we stgi() too soon, nmis can reach the processor even though interrupts are disabled, catching it in a half-switched state. Delay the stgi() until we're done switching. Signed-off-by: Avi Kivity --- drivers/kvm/svm.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/drivers/kvm/svm.c b/drivers/kvm/svm.c index 3910358db79d..7376805c88ab 100644 --- a/drivers/kvm/svm.c +++ b/drivers/kvm/svm.c @@ -1585,10 +1585,6 @@ static void svm_vcpu_run(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run) #endif : "cc", "memory" ); - local_irq_disable(); - - stgi(); - if ((svm->vmcb->save.dr7 & 0xff)) load_db_regs(svm->host_db_regs); @@ -1605,6 +1601,10 @@ static void svm_vcpu_run(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run) reload_tss(vcpu); + local_irq_disable(); + + stgi(); + svm->next_rip = 0; } From 651a3e29b3d19418d7a8a9787906061f9be7cc5f Mon Sep 17 00:00:00 2001 From: Avi Kivity Date: Sun, 28 Oct 2007 16:09:18 +0200 Subject: [PATCH 4/5] KVM: x86 emulator: invd instruction Emulate the 'invd' instruction (opcode 0f 08). Signed-off-by: Avi Kivity --- drivers/kvm/x86_emulate.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/drivers/kvm/x86_emulate.c b/drivers/kvm/x86_emulate.c index da0cdd521da9..33b181451557 100644 --- a/drivers/kvm/x86_emulate.c +++ b/drivers/kvm/x86_emulate.c @@ -167,7 +167,7 @@ static u8 opcode_table[256] = { static u16 twobyte_table[256] = { /* 0x00 - 0x0F */ 0, SrcMem | ModRM | DstReg, 0, 0, 0, 0, ImplicitOps, 0, - 0, ImplicitOps, 0, 0, 0, ImplicitOps | ModRM, 0, 0, + ImplicitOps, ImplicitOps, 0, 0, 0, ImplicitOps | ModRM, 0, 0, /* 0x10 - 0x1F */ 0, 0, 0, 0, 0, 0, 0, 0, ImplicitOps | ModRM, 0, 0, 0, 0, 0, 0, 0, /* 0x20 - 0x2F */ @@ -1532,6 +1532,8 @@ twobyte_special_insn: case 0x06: emulate_clts(ctxt->vcpu); break; + case 0x08: /* invd */ + break; case 0x09: /* wbinvd */ break; case 0x0d: /* GrpP (prefetch) */ From cf5a94d1331b411b84414c13e43f578260942d6b Mon Sep 17 00:00:00 2001 From: Avi Kivity Date: Sun, 28 Oct 2007 16:11:58 +0200 Subject: [PATCH 5/5] KVM: SVM: Intercept the 'invd' and 'wbinvd' instructions 'invd' can destroy host data, and 'wbinvd' allows the guest to induce long (milliseconds) latencies. Noted by Ben Serebrin. Signed-off-by: Avi Kivity --- drivers/kvm/svm.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/drivers/kvm/svm.c b/drivers/kvm/svm.c index 7376805c88ab..7a6eead63a6b 100644 --- a/drivers/kvm/svm.c +++ b/drivers/kvm/svm.c @@ -494,6 +494,7 @@ static void init_vmcb(struct vmcb *vmcb) */ /* (1ULL << INTERCEPT_SELECTIVE_CR0) | */ (1ULL << INTERCEPT_CPUID) | + (1ULL << INTERCEPT_INVD) | (1ULL << INTERCEPT_HLT) | (1ULL << INTERCEPT_INVLPGA) | (1ULL << INTERCEPT_IOIO_PROT) | @@ -507,6 +508,7 @@ static void init_vmcb(struct vmcb *vmcb) (1ULL << INTERCEPT_STGI) | (1ULL << INTERCEPT_CLGI) | (1ULL << INTERCEPT_SKINIT) | + (1ULL << INTERCEPT_WBINVD) | (1ULL << INTERCEPT_MONITOR) | (1ULL << INTERCEPT_MWAIT); @@ -1247,6 +1249,7 @@ static int (*svm_exit_handlers[])(struct vcpu_svm *svm, [SVM_EXIT_VINTR] = interrupt_window_interception, /* [SVM_EXIT_CR0_SEL_WRITE] = emulate_on_interception, */ [SVM_EXIT_CPUID] = cpuid_interception, + [SVM_EXIT_INVD] = emulate_on_interception, [SVM_EXIT_HLT] = halt_interception, [SVM_EXIT_INVLPG] = emulate_on_interception, [SVM_EXIT_INVLPGA] = invalid_op_interception, @@ -1261,6 +1264,7 @@ static int (*svm_exit_handlers[])(struct vcpu_svm *svm, [SVM_EXIT_STGI] = invalid_op_interception, [SVM_EXIT_CLGI] = invalid_op_interception, [SVM_EXIT_SKINIT] = invalid_op_interception, + [SVM_EXIT_WBINVD] = emulate_on_interception, [SVM_EXIT_MONITOR] = invalid_op_interception, [SVM_EXIT_MWAIT] = invalid_op_interception, };