diff mbox series

[RFC,35/73] KVM: x86/PVM: Handle PVM_SYNTHETIC_CPUID synthetic instruction

Message ID 20240226143630.33643-36-jiangshanlai@gmail.com (mailing list archive)
State New, archived
Headers show
Series KVM: x86/PVM: Introduce a new hypervisor | expand

Commit Message

Lai Jiangshan Feb. 26, 2024, 2:35 p.m. UTC
From: Lai Jiangshan <jiangshan.ljs@antgroup.com>

The PVM guest utilizes the CPUID instruction for detecting PVM
hypervisor support. However, the CPUID instruction in the PVM guest is
not directly trapped and emulated. Instead, the PVM guest employs the
"invlpg 0xffffffffff4d5650; cpuid;" instructions to cause a #GP trap.
The hypervisor must identify this trap and handle the emulation of the
CPUID instruction within the #GP handling process.

Signed-off-by: Lai Jiangshan <jiangshan.ljs@antgroup.com>
Signed-off-by: Hou Wenlong <houwenlong.hwl@antgroup.com>
---
 arch/x86/kvm/pvm/pvm.c | 33 +++++++++++++++++++++++++++++++++
 1 file changed, 33 insertions(+)
diff mbox series

Patch

diff --git a/arch/x86/kvm/pvm/pvm.c b/arch/x86/kvm/pvm/pvm.c
index 514f0573f70f..a2602d9828a5 100644
--- a/arch/x86/kvm/pvm/pvm.c
+++ b/arch/x86/kvm/pvm/pvm.c
@@ -1294,6 +1294,36 @@  static int handle_exit_breakpoint(struct kvm_vcpu *vcpu)
 	return 1;
 }
 
+static bool handle_synthetic_instruction_pvm_cpuid(struct kvm_vcpu *vcpu)
+{
+	/* invlpg 0xffffffffff4d5650; cpuid; */
+	static const char pvm_synthetic_cpuid_insns[] = { PVM_SYNTHETIC_CPUID };
+	char insns[10];
+	struct x86_exception e;
+
+	if (kvm_read_guest_virt(vcpu, kvm_get_linear_rip(vcpu),
+				insns, sizeof(insns), &e) == 0 &&
+	    memcmp(insns, pvm_synthetic_cpuid_insns, sizeof(insns)) == 0) {
+		u32 eax, ebx, ecx, edx;
+
+		if (unlikely(pvm_guest_allowed_va(vcpu, PVM_SYNTHETIC_CPUID_ADDRESS)))
+			kvm_mmu_invlpg(vcpu, PVM_SYNTHETIC_CPUID_ADDRESS);
+
+		eax = kvm_rax_read(vcpu);
+		ecx = kvm_rcx_read(vcpu);
+		kvm_cpuid(vcpu, &eax, &ebx, &ecx, &edx, false);
+		kvm_rax_write(vcpu, eax);
+		kvm_rbx_write(vcpu, ebx);
+		kvm_rcx_write(vcpu, ecx);
+		kvm_rdx_write(vcpu, edx);
+
+		kvm_rip_write(vcpu, kvm_rip_read(vcpu) + sizeof(insns));
+		return true;
+	}
+
+	return false;
+}
+
 static int handle_exit_exception(struct kvm_vcpu *vcpu)
 {
 	struct vcpu_pvm *pvm = to_pvm(vcpu);
@@ -1321,6 +1351,9 @@  static int handle_exit_exception(struct kvm_vcpu *vcpu)
 		return kvm_handle_page_fault(vcpu, error_code, pvm->exit_cr2,
 					     NULL, 0);
 	case GP_VECTOR:
+		if (is_smod(pvm) && handle_synthetic_instruction_pvm_cpuid(vcpu))
+			return 1;
+
 		err = kvm_emulate_instruction(vcpu, EMULTYPE_PVM_GP);
 		if (!err)
 			return 0;