aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorGleb Natapov <gleb@redhat.com>2012-12-20 09:57:47 -0500
committerMarcelo Tosatti <mtosatti@redhat.com>2013-01-02 16:36:31 -0500
commit0ca1b4f4ba3a9f75bb099ccaf6c4bd8bb6db7a74 (patch)
treeedd7943dc03ffec9ed3055a499b9b98a1e4996bd
parentd54d07b2ca19a2908aa89e0c67715ca2e8e62a4c (diff)
KVM: VMX: handle IO when emulation is due to #GP in real mode.
With emulate_invalid_guest_state=0 if a vcpu is in real mode VMX can enter the vcpu with smaller segment limit than guest configured. If the guest tries to access pass this limit it will get #GP at which point instruction will be emulated with correct segment limit applied. If during the emulation IO is detected it is not handled correctly. Vcpu thread should exit to userspace to serve the IO, but it returns to the guest instead. Since emulation is not completed till userspace completes the IO the faulty instruction is re-executed ad infinitum. The patch fixes that by exiting to userspace if IO happens during instruction emulation. Reported-by: Alex Williamson <alex.williamson@redhat.com> Signed-off-by: Gleb Natapov <gleb@redhat.com> Signed-off-by: Marcelo Tosatti <mtosatti@redhat.com>
-rw-r--r--arch/x86/kvm/vmx.c75
1 files changed, 41 insertions, 34 deletions
diff --git a/arch/x86/kvm/vmx.c b/arch/x86/kvm/vmx.c
index a101dd488f23..55dfc375f1ab 100644
--- a/arch/x86/kvm/vmx.c
+++ b/arch/x86/kvm/vmx.c
@@ -4230,28 +4230,9 @@ static int vmx_set_tss_addr(struct kvm *kvm, unsigned int addr)
4230 return 0; 4230 return 0;
4231} 4231}
4232 4232
4233static int handle_rmode_exception(struct kvm_vcpu *vcpu, 4233static bool rmode_exception(struct kvm_vcpu *vcpu, int vec)
4234 int vec, u32 err_code)
4235{ 4234{
4236 /*
4237 * Instruction with address size override prefix opcode 0x67
4238 * Cause the #SS fault with 0 error code in VM86 mode.
4239 */
4240 if (((vec == GP_VECTOR) || (vec == SS_VECTOR)) && err_code == 0)
4241 if (emulate_instruction(vcpu, 0) == EMULATE_DONE)
4242 return 1;
4243 /*
4244 * Forward all other exceptions that are valid in real mode.
4245 * FIXME: Breaks guest debugging in real mode, needs to be fixed with
4246 * the required debugging infrastructure rework.
4247 */
4248 switch (vec) { 4235 switch (vec) {
4249 case DB_VECTOR:
4250 if (vcpu->guest_debug &
4251 (KVM_GUESTDBG_SINGLESTEP | KVM_GUESTDBG_USE_HW_BP))
4252 return 0;
4253 kvm_queue_exception(vcpu, vec);
4254 return 1;
4255 case BP_VECTOR: 4236 case BP_VECTOR:
4256 /* 4237 /*
4257 * Update instruction length as we may reinject the exception 4238 * Update instruction length as we may reinject the exception
@@ -4260,7 +4241,12 @@ static int handle_rmode_exception(struct kvm_vcpu *vcpu,
4260 to_vmx(vcpu)->vcpu.arch.event_exit_inst_len = 4241 to_vmx(vcpu)->vcpu.arch.event_exit_inst_len =
4261 vmcs_read32(VM_EXIT_INSTRUCTION_LEN); 4242 vmcs_read32(VM_EXIT_INSTRUCTION_LEN);
4262 if (vcpu->guest_debug & KVM_GUESTDBG_USE_SW_BP) 4243 if (vcpu->guest_debug & KVM_GUESTDBG_USE_SW_BP)
4263 return 0; 4244 return false;
4245 /* fall through */
4246 case DB_VECTOR:
4247 if (vcpu->guest_debug &
4248 (KVM_GUESTDBG_SINGLESTEP | KVM_GUESTDBG_USE_HW_BP))
4249 return false;
4264 /* fall through */ 4250 /* fall through */
4265 case DE_VECTOR: 4251 case DE_VECTOR:
4266 case OF_VECTOR: 4252 case OF_VECTOR:
@@ -4270,10 +4256,37 @@ static int handle_rmode_exception(struct kvm_vcpu *vcpu,
4270 case SS_VECTOR: 4256 case SS_VECTOR:
4271 case GP_VECTOR: 4257 case GP_VECTOR:
4272 case MF_VECTOR: 4258 case MF_VECTOR:
4273 kvm_queue_exception(vcpu, vec); 4259 return true;
4274 return 1; 4260 break;
4275 } 4261 }
4276 return 0; 4262 return false;
4263}
4264
4265static int handle_rmode_exception(struct kvm_vcpu *vcpu,
4266 int vec, u32 err_code)
4267{
4268 /*
4269 * Instruction with address size override prefix opcode 0x67
4270 * Cause the #SS fault with 0 error code in VM86 mode.
4271 */
4272 if (((vec == GP_VECTOR) || (vec == SS_VECTOR)) && err_code == 0) {
4273 if (emulate_instruction(vcpu, 0) == EMULATE_DONE) {
4274 if (vcpu->arch.halt_request) {
4275 vcpu->arch.halt_request = 0;
4276 return kvm_emulate_halt(vcpu);
4277 }
4278 return 1;
4279 }
4280 return 0;
4281 }
4282
4283 /*
4284 * Forward all other exceptions that are valid in real mode.
4285 * FIXME: Breaks guest debugging in real mode, needs to be fixed with
4286 * the required debugging infrastructure rework.
4287 */
4288 kvm_queue_exception(vcpu, vec);
4289 return 1;
4277} 4290}
4278 4291
4279/* 4292/*
@@ -4361,17 +4374,11 @@ static int handle_exception(struct kvm_vcpu *vcpu)
4361 return kvm_mmu_page_fault(vcpu, cr2, error_code, NULL, 0); 4374 return kvm_mmu_page_fault(vcpu, cr2, error_code, NULL, 0);
4362 } 4375 }
4363 4376
4364 if (vmx->rmode.vm86_active &&
4365 handle_rmode_exception(vcpu, intr_info & INTR_INFO_VECTOR_MASK,
4366 error_code)) {
4367 if (vcpu->arch.halt_request) {
4368 vcpu->arch.halt_request = 0;
4369 return kvm_emulate_halt(vcpu);
4370 }
4371 return 1;
4372 }
4373
4374 ex_no = intr_info & INTR_INFO_VECTOR_MASK; 4377 ex_no = intr_info & INTR_INFO_VECTOR_MASK;
4378
4379 if (vmx->rmode.vm86_active && rmode_exception(vcpu, ex_no))
4380 return handle_rmode_exception(vcpu, ex_no, error_code);
4381
4375 switch (ex_no) { 4382 switch (ex_no) {
4376 case DB_VECTOR: 4383 case DB_VECTOR:
4377 dr6 = vmcs_readl(EXIT_QUALIFICATION); 4384 dr6 = vmcs_readl(EXIT_QUALIFICATION);