Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit ac9b305c authored by Liran Alon's avatar Liran Alon Committed by Paolo Bonzini
Browse files

KVM: nVMX/nSVM: Don't intercept #UD when running L2



When running L2, #UD should be intercepted by L1 or just forwarded
directly to L2. It should not reach L0 x86 emulator.
Therefore, set intercept for #UD only based on L1 exception-bitmap.

Also add WARN_ON_ONCE() on L0 #UD intercept handlers to make sure
it is never reached while running L2.

This improves commit ae1f5767 ("KVM: nVMX: Do not emulate #UD while
in guest mode") by removing an unnecessary exit from L2 to L0 on #UD
when L1 doesn't intercept it.

In addition, SVM L0 #UD intercept handler doesn't handle correctly the
case it is raised from L2. In this case, it should forward the #UD to
guest instead of x86 emulator. As done in VMX #UD intercept handler.
This commit fixes this issue as-well.

Signed-off-by: default avatarLiran Alon <liran.alon@oracle.com>
Reviewed-by: default avatarNikita Leshenko <nikita.leshchenko@oracle.com>
Reviewed-by: default avatarKonrad Rzeszutek Wilk <konrad.wilk@oracle.com>
Signed-off-by: default avatarKonrad Rzeszutek Wilk <konrad.wilk@oracle.com>
Reviewed-by: default avatarPaolo Bonzini <pbonzini@redhat.com>
Reviewed-by: default avatarWanpeng Li <wanpeng.li@hotmail.com>
Signed-off-by: default avatarRadim Krčmář <rkrcmar@redhat.com>
parent 51c4b8bb
Loading
Loading
Loading
Loading
+8 −1
Original line number Original line Diff line number Diff line
@@ -361,6 +361,7 @@ static void recalc_intercepts(struct vcpu_svm *svm)
{
{
	struct vmcb_control_area *c, *h;
	struct vmcb_control_area *c, *h;
	struct nested_state *g;
	struct nested_state *g;
	u32 h_intercept_exceptions;


	mark_dirty(svm->vmcb, VMCB_INTERCEPTS);
	mark_dirty(svm->vmcb, VMCB_INTERCEPTS);


@@ -371,9 +372,14 @@ static void recalc_intercepts(struct vcpu_svm *svm)
	h = &svm->nested.hsave->control;
	h = &svm->nested.hsave->control;
	g = &svm->nested;
	g = &svm->nested;


	/* No need to intercept #UD if L1 doesn't intercept it */
	h_intercept_exceptions =
		h->intercept_exceptions & ~(1U << UD_VECTOR);

	c->intercept_cr = h->intercept_cr | g->intercept_cr;
	c->intercept_cr = h->intercept_cr | g->intercept_cr;
	c->intercept_dr = h->intercept_dr | g->intercept_dr;
	c->intercept_dr = h->intercept_dr | g->intercept_dr;
	c->intercept_exceptions = h->intercept_exceptions | g->intercept_exceptions;
	c->intercept_exceptions =
		h_intercept_exceptions | g->intercept_exceptions;
	c->intercept = h->intercept | g->intercept;
	c->intercept = h->intercept | g->intercept;
}
}


@@ -2196,6 +2202,7 @@ static int ud_interception(struct vcpu_svm *svm)
{
{
	int er;
	int er;


	WARN_ON_ONCE(is_guest_mode(&svm->vcpu));
	er = emulate_instruction(&svm->vcpu, EMULTYPE_TRAP_UD);
	er = emulate_instruction(&svm->vcpu, EMULTYPE_TRAP_UD);
	if (er != EMULATE_DONE)
	if (er != EMULATE_DONE)
		kvm_queue_exception(&svm->vcpu, UD_VECTOR);
		kvm_queue_exception(&svm->vcpu, UD_VECTOR);
+4 −5
Original line number Original line Diff line number Diff line
@@ -1887,7 +1887,7 @@ static void update_exception_bitmap(struct kvm_vcpu *vcpu)
{
{
	u32 eb;
	u32 eb;


	eb = (1u << PF_VECTOR) | (1u << UD_VECTOR) | (1u << MC_VECTOR) |
	eb = (1u << PF_VECTOR) | (1u << MC_VECTOR) |
	     (1u << DB_VECTOR) | (1u << AC_VECTOR);
	     (1u << DB_VECTOR) | (1u << AC_VECTOR);
	if ((vcpu->guest_debug &
	if ((vcpu->guest_debug &
	     (KVM_GUESTDBG_ENABLE | KVM_GUESTDBG_USE_SW_BP)) ==
	     (KVM_GUESTDBG_ENABLE | KVM_GUESTDBG_USE_SW_BP)) ==
@@ -1905,6 +1905,8 @@ static void update_exception_bitmap(struct kvm_vcpu *vcpu)
	 */
	 */
	if (is_guest_mode(vcpu))
	if (is_guest_mode(vcpu))
		eb |= get_vmcs12(vcpu)->exception_bitmap;
		eb |= get_vmcs12(vcpu)->exception_bitmap;
	else
		eb |= 1u << UD_VECTOR;


	vmcs_write32(EXCEPTION_BITMAP, eb);
	vmcs_write32(EXCEPTION_BITMAP, eb);
}
}
@@ -5915,10 +5917,7 @@ static int handle_exception(struct kvm_vcpu *vcpu)
		return 1;  /* already handled by vmx_vcpu_run() */
		return 1;  /* already handled by vmx_vcpu_run() */


	if (is_invalid_opcode(intr_info)) {
	if (is_invalid_opcode(intr_info)) {
		if (is_guest_mode(vcpu)) {
		WARN_ON_ONCE(is_guest_mode(vcpu));
			kvm_queue_exception(vcpu, UD_VECTOR);
			return 1;
		}
		er = emulate_instruction(vcpu, EMULTYPE_TRAP_UD);
		er = emulate_instruction(vcpu, EMULTYPE_TRAP_UD);
		if (er != EMULATE_DONE)
		if (er != EMULATE_DONE)
			kvm_queue_exception(vcpu, UD_VECTOR);
			kvm_queue_exception(vcpu, UD_VECTOR);