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

Commit 3fd28fce authored by Eddie Dong's avatar Eddie Dong Committed by Marcelo Tosatti
Browse files

KVM: x86: make double/triple fault promotion generic to all exceptions



Move Double-Fault generation logic out of page fault
exception generating function to cover more generic case.

Signed-off-by: default avatarEddie Dong <eddie.dong@intel.com>
Signed-off-by: default avatarGleb Natapov <gleb@redhat.com>
Signed-off-by: default avatarMarcelo Tosatti <mtosatti@redhat.com>
parent 30ff056c
Loading
Loading
Loading
Loading
+61 −28
Original line number Original line Diff line number Diff line
@@ -257,38 +257,75 @@ void kvm_set_apic_base(struct kvm_vcpu *vcpu, u64 data)
}
}
EXPORT_SYMBOL_GPL(kvm_set_apic_base);
EXPORT_SYMBOL_GPL(kvm_set_apic_base);


void kvm_queue_exception(struct kvm_vcpu *vcpu, unsigned nr)
#define EXCPT_BENIGN		0
#define EXCPT_CONTRIBUTORY	1
#define EXCPT_PF		2

static int exception_class(int vector)
{
{
	WARN_ON(vcpu->arch.exception.pending);
	switch (vector) {
	vcpu->arch.exception.pending = true;
	case PF_VECTOR:
	vcpu->arch.exception.has_error_code = false;
		return EXCPT_PF;
	vcpu->arch.exception.nr = nr;
	case DE_VECTOR:
	case TS_VECTOR:
	case NP_VECTOR:
	case SS_VECTOR:
	case GP_VECTOR:
		return EXCPT_CONTRIBUTORY;
	default:
		break;
	}
	return EXCPT_BENIGN;
}
}
EXPORT_SYMBOL_GPL(kvm_queue_exception);


void kvm_inject_page_fault(struct kvm_vcpu *vcpu, unsigned long addr,
static void kvm_multiple_exception(struct kvm_vcpu *vcpu,
			   u32 error_code)
		unsigned nr, bool has_error, u32 error_code)
{
{
	++vcpu->stat.pf_guest;
	u32 prev_nr;
	int class1, class2;


	if (vcpu->arch.exception.pending) {
	if (!vcpu->arch.exception.pending) {
		switch(vcpu->arch.exception.nr) {
	queue:
		case DF_VECTOR:
		vcpu->arch.exception.pending = true;
		vcpu->arch.exception.has_error_code = has_error;
		vcpu->arch.exception.nr = nr;
		vcpu->arch.exception.error_code = error_code;
		return;
	}

	/* to check exception */
	prev_nr = vcpu->arch.exception.nr;
	if (prev_nr == DF_VECTOR) {
		/* triple fault -> shutdown */
		/* triple fault -> shutdown */
		set_bit(KVM_REQ_TRIPLE_FAULT, &vcpu->requests);
		set_bit(KVM_REQ_TRIPLE_FAULT, &vcpu->requests);
		return;
		return;
		case PF_VECTOR:
	}
	class1 = exception_class(prev_nr);
	class2 = exception_class(nr);
	if ((class1 == EXCPT_CONTRIBUTORY && class2 == EXCPT_CONTRIBUTORY)
		|| (class1 == EXCPT_PF && class2 != EXCPT_BENIGN)) {
		/* generate double fault per SDM Table 5-5 */
		vcpu->arch.exception.pending = true;
		vcpu->arch.exception.has_error_code = true;
		vcpu->arch.exception.nr = DF_VECTOR;
		vcpu->arch.exception.nr = DF_VECTOR;
		vcpu->arch.exception.error_code = 0;
		vcpu->arch.exception.error_code = 0;
			return;
	} else
		default:
		/* replace previous exception with a new one in a hope
		/* replace previous exception with a new one in a hope
		   that instruction re-execution will regenerate lost
		   that instruction re-execution will regenerate lost
		   exception */
		   exception */
			vcpu->arch.exception.pending = false;
		goto queue;
			break;
}
}

void kvm_queue_exception(struct kvm_vcpu *vcpu, unsigned nr)
{
	kvm_multiple_exception(vcpu, nr, false, 0);
}
}
EXPORT_SYMBOL_GPL(kvm_queue_exception);

void kvm_inject_page_fault(struct kvm_vcpu *vcpu, unsigned long addr,
			   u32 error_code)
{
	++vcpu->stat.pf_guest;
	vcpu->arch.cr2 = addr;
	vcpu->arch.cr2 = addr;
	kvm_queue_exception_e(vcpu, PF_VECTOR, error_code);
	kvm_queue_exception_e(vcpu, PF_VECTOR, error_code);
}
}
@@ -301,11 +338,7 @@ EXPORT_SYMBOL_GPL(kvm_inject_nmi);


void kvm_queue_exception_e(struct kvm_vcpu *vcpu, unsigned nr, u32 error_code)
void kvm_queue_exception_e(struct kvm_vcpu *vcpu, unsigned nr, u32 error_code)
{
{
	WARN_ON(vcpu->arch.exception.pending);
	kvm_multiple_exception(vcpu, nr, true, error_code);
	vcpu->arch.exception.pending = true;
	vcpu->arch.exception.has_error_code = true;
	vcpu->arch.exception.nr = nr;
	vcpu->arch.exception.error_code = error_code;
}
}
EXPORT_SYMBOL_GPL(kvm_queue_exception_e);
EXPORT_SYMBOL_GPL(kvm_queue_exception_e);