diff options
| -rw-r--r-- | arch/x86/kvm/vmx.c | 134 | 
1 files changed, 75 insertions, 59 deletions
diff --git a/arch/x86/kvm/vmx.c b/arch/x86/kvm/vmx.c index a0a78f09b22d..a406afbb6d21 100644 --- a/arch/x86/kvm/vmx.c +++ b/arch/x86/kvm/vmx.c @@ -8344,12 +8344,14 @@ static bool nested_vmx_exit_reflected(struct kvm_vcpu *vcpu, u32 exit_reason)  	struct vcpu_vmx *vmx = to_vmx(vcpu);  	struct vmcs12 *vmcs12 = get_vmcs12(vcpu); -	trace_kvm_nested_vmexit(kvm_rip_read(vcpu), exit_reason, -				vmcs_readl(EXIT_QUALIFICATION), -				vmx->idt_vectoring_info, -				intr_info, -				vmcs_read32(VM_EXIT_INTR_ERROR_CODE), -				KVM_ISA_VMX); +	if (vmx->nested.nested_run_pending) +		return false; + +	if (unlikely(vmx->fail)) { +		pr_info_ratelimited("%s failed vm entry %x\n", __func__, +				    vmcs_read32(VM_INSTRUCTION_ERROR)); +		return true; +	}  	/*  	 * The host physical addresses of some pages of guest memory @@ -8363,14 +8365,12 @@ static bool nested_vmx_exit_reflected(struct kvm_vcpu *vcpu, u32 exit_reason)  	 */  	nested_mark_vmcs12_pages_dirty(vcpu); -	if (vmx->nested.nested_run_pending) -		return false; - -	if (unlikely(vmx->fail)) { -		pr_info_ratelimited("%s failed vm entry %x\n", __func__, -				    vmcs_read32(VM_INSTRUCTION_ERROR)); -		return true; -	} +	trace_kvm_nested_vmexit(kvm_rip_read(vcpu), exit_reason, +				vmcs_readl(EXIT_QUALIFICATION), +				vmx->idt_vectoring_info, +				intr_info, +				vmcs_read32(VM_EXIT_INTR_ERROR_CODE), +				KVM_ISA_VMX);  	switch (exit_reason) {  	case EXIT_REASON_EXCEPTION_NMI: @@ -11395,46 +11395,30 @@ static void nested_vmx_vmexit(struct kvm_vcpu *vcpu, u32 exit_reason,  {  	struct vcpu_vmx *vmx = to_vmx(vcpu);  	struct vmcs12 *vmcs12 = get_vmcs12(vcpu); -	u32 vm_inst_error = 0;  	/* trying to cancel vmlaunch/vmresume is a bug */  	WARN_ON_ONCE(vmx->nested.nested_run_pending); +	/* +	 * The only expected VM-instruction error is "VM entry with +	 * invalid control field(s)." Anything else indicates a +	 * problem with L0. +	 */ +	WARN_ON_ONCE(vmx->fail && (vmcs_read32(VM_INSTRUCTION_ERROR) != +				   VMXERR_ENTRY_INVALID_CONTROL_FIELD)); +  	leave_guest_mode(vcpu); -	prepare_vmcs12(vcpu, vmcs12, exit_reason, exit_intr_info, -		       exit_qualification); -	if (nested_vmx_store_msr(vcpu, vmcs12->vm_exit_msr_store_addr, -				 vmcs12->vm_exit_msr_store_count)) -		nested_vmx_abort(vcpu, VMX_ABORT_SAVE_GUEST_MSR_FAIL); +	if (likely(!vmx->fail)) { +		prepare_vmcs12(vcpu, vmcs12, exit_reason, exit_intr_info, +			       exit_qualification); -	if (unlikely(vmx->fail)) -		vm_inst_error = vmcs_read32(VM_INSTRUCTION_ERROR); +		if (nested_vmx_store_msr(vcpu, vmcs12->vm_exit_msr_store_addr, +					 vmcs12->vm_exit_msr_store_count)) +			nested_vmx_abort(vcpu, VMX_ABORT_SAVE_GUEST_MSR_FAIL); +	}  	vmx_switch_vmcs(vcpu, &vmx->vmcs01); - -	/* -	 * TODO: SDM says that with acknowledge interrupt on exit, bit 31 of -	 * the VM-exit interrupt information (valid interrupt) is always set to -	 * 1 on EXIT_REASON_EXTERNAL_INTERRUPT, so we shouldn't need -	 * kvm_cpu_has_interrupt().  See the commit message for details. -	 */ -	if (nested_exit_intr_ack_set(vcpu) && -	    exit_reason == EXIT_REASON_EXTERNAL_INTERRUPT && -	    kvm_cpu_has_interrupt(vcpu)) { -		int irq = kvm_cpu_get_interrupt(vcpu); -		WARN_ON(irq < 0); -		vmcs12->vm_exit_intr_info = irq | -			INTR_INFO_VALID_MASK | INTR_TYPE_EXT_INTR; -	} - -	trace_kvm_nested_vmexit_inject(vmcs12->vm_exit_reason, -				       vmcs12->exit_qualification, -				       vmcs12->idt_vectoring_info_field, -				       vmcs12->vm_exit_intr_info, -				       vmcs12->vm_exit_intr_error_code, -				       KVM_ISA_VMX); -  	vm_entry_controls_reset_shadow(vmx);  	vm_exit_controls_reset_shadow(vmx);  	vmx_segment_cache_clear(vmx); @@ -11443,8 +11427,6 @@ static void nested_vmx_vmexit(struct kvm_vcpu *vcpu, u32 exit_reason,  	if (VMCS02_POOL_SIZE == 0)  		nested_free_vmcs02(vmx, vmx->nested.current_vmptr); -	load_vmcs12_host_state(vcpu, vmcs12); -  	/* Update any VMCS fields that might have changed while L2 ran */  	vmcs_write32(VM_EXIT_MSR_LOAD_COUNT, vmx->msr_autoload.nr);  	vmcs_write32(VM_ENTRY_MSR_LOAD_COUNT, vmx->msr_autoload.nr); @@ -11493,23 +11475,57 @@ static void nested_vmx_vmexit(struct kvm_vcpu *vcpu, u32 exit_reason,  	 */  	kvm_make_request(KVM_REQ_APIC_PAGE_RELOAD, vcpu); -	if (unlikely(vmx->fail)) { -		/* -		 * After an early L2 VM-entry failure, we're now back -		 * in L1 which thinks it just finished a VMLAUNCH or -		 * VMRESUME instruction, so we need to set the failure -		 * flag and the VM-instruction error field of the VMCS -		 * accordingly. -		 */ -		vmx->fail = 0; -		nested_vmx_failValid(vcpu, vm_inst_error); -	} -  	if (enable_shadow_vmcs)  		vmx->nested.sync_shadow_vmcs = true;  	/* in case we halted in L2 */  	vcpu->arch.mp_state = KVM_MP_STATE_RUNNABLE; + +	if (likely(!vmx->fail)) { +		/* +		 * TODO: SDM says that with acknowledge interrupt on +		 * exit, bit 31 of the VM-exit interrupt information +		 * (valid interrupt) is always set to 1 on +		 * EXIT_REASON_EXTERNAL_INTERRUPT, so we shouldn't +		 * need kvm_cpu_has_interrupt().  See the commit +		 * message for details. +		 */ +		if (nested_exit_intr_ack_set(vcpu) && +		    exit_reason == EXIT_REASON_EXTERNAL_INTERRUPT && +		    kvm_cpu_has_interrupt(vcpu)) { +			int irq = kvm_cpu_get_interrupt(vcpu); +			WARN_ON(irq < 0); +			vmcs12->vm_exit_intr_info = irq | +				INTR_INFO_VALID_MASK | INTR_TYPE_EXT_INTR; +		} + +		trace_kvm_nested_vmexit_inject(vmcs12->vm_exit_reason, +					       vmcs12->exit_qualification, +					       vmcs12->idt_vectoring_info_field, +					       vmcs12->vm_exit_intr_info, +					       vmcs12->vm_exit_intr_error_code, +					       KVM_ISA_VMX); + +		load_vmcs12_host_state(vcpu, vmcs12); + +		return; +	} +	 +	/* +	 * After an early L2 VM-entry failure, we're now back +	 * in L1 which thinks it just finished a VMLAUNCH or +	 * VMRESUME instruction, so we need to set the failure +	 * flag and the VM-instruction error field of the VMCS +	 * accordingly. +	 */ +	nested_vmx_failValid(vcpu, VMXERR_ENTRY_INVALID_CONTROL_FIELD); +	/* +	 * The emulated instruction was already skipped in +	 * nested_vmx_run, but the updated RIP was never +	 * written back to the vmcs01. +	 */ +	skip_emulated_instruction(vcpu); +	vmx->fail = 0;  }  /*  | 

