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

Lai Jiangshan
2024-02-26T14:36:33Z

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 --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;
--
2.19.1.6.gb485710b