KVM: x86: Refactor can_emulate_instruction() return to be more expressive
authorSean Christopherson <seanjc@google.com>
Fri, 25 Aug 2023 01:36:20 +0000 (18:36 -0700)
committerSean Christopherson <seanjc@google.com>
Wed, 4 Oct 2023 22:08:53 +0000 (15:08 -0700)
Refactor and rename can_emulate_instruction() to allow vendor code to
return more than true/false, e.g. to explicitly differentiate between
"retry", "fault", and "unhandleable".  For now, just do the plumbing, a
future patch will expand SVM's implementation to signal outright failure
if KVM attempts EMULTYPE_SKIP on an SEV guest.

No functional change intended (or rather, none that are visible to the
guest or userspace).

Link: https://lore.kernel.org/r/20230825013621.2845700-4-seanjc@google.com
Signed-off-by: Sean Christopherson <seanjc@google.com>
arch/x86/include/asm/kvm-x86-ops.h
arch/x86/include/asm/kvm_host.h
arch/x86/kvm/svm/svm.c
arch/x86/kvm/vmx/vmx.c
arch/x86/kvm/x86.c

index e3054e3e46d52deaa70480901862b287e2200ee2..ee2404a559af1ad78c8b279ea7f402c44d6a99ef 100644 (file)
@@ -126,7 +126,7 @@ KVM_X86_OP_OPTIONAL(vm_copy_enc_context_from)
 KVM_X86_OP_OPTIONAL(vm_move_enc_context_from)
 KVM_X86_OP_OPTIONAL(guest_memory_reclaimed)
 KVM_X86_OP(get_msr_feature)
-KVM_X86_OP(can_emulate_instruction)
+KVM_X86_OP(check_emulate_instruction)
 KVM_X86_OP(apic_init_signal_blocked)
 KVM_X86_OP_OPTIONAL(enable_l2_tlb_flush)
 KVM_X86_OP_OPTIONAL(migrate_timers)
index 17715cb8731d5d2c7d60caeebf6e340158888ef5..89583b410527eb3767e68ef07e1901d11607d6bf 100644 (file)
@@ -1734,8 +1734,8 @@ struct kvm_x86_ops {
 
        int (*get_msr_feature)(struct kvm_msr_entry *entry);
 
-       bool (*can_emulate_instruction)(struct kvm_vcpu *vcpu, int emul_type,
-                                       void *insn, int insn_len);
+       int (*check_emulate_instruction)(struct kvm_vcpu *vcpu, int emul_type,
+                                        void *insn, int insn_len);
 
        bool (*apic_init_signal_blocked)(struct kvm_vcpu *vcpu);
        int (*enable_l2_tlb_flush)(struct kvm_vcpu *vcpu);
index f36a6d819280ad304cd35d2c06aaa2978e9f4a8f..c4e700f945f828c73308c33564ce313aaac068fb 100644 (file)
@@ -364,8 +364,8 @@ static void svm_set_interrupt_shadow(struct kvm_vcpu *vcpu, int mask)
                svm->vmcb->control.int_state |= SVM_INTERRUPT_SHADOW_MASK;
 
 }
-static bool svm_can_emulate_instruction(struct kvm_vcpu *vcpu, int emul_type,
-                                       void *insn, int insn_len);
+static int svm_check_emulate_instruction(struct kvm_vcpu *vcpu, int emul_type,
+                                        void *insn, int insn_len);
 
 static int __svm_skip_emulated_instruction(struct kvm_vcpu *vcpu,
                                           bool commit_side_effects)
@@ -391,7 +391,7 @@ static int __svm_skip_emulated_instruction(struct kvm_vcpu *vcpu,
                 * right thing and treats "can't emulate" as outright failure
                 * for EMULTYPE_SKIP.
                 */
-               if (!svm_can_emulate_instruction(vcpu, EMULTYPE_SKIP, NULL, 0))
+               if (svm_check_emulate_instruction(vcpu, EMULTYPE_SKIP, NULL, 0) != X86EMUL_CONTINUE)
                        return 0;
 
                if (unlikely(!commit_side_effects))
@@ -4727,15 +4727,15 @@ static void svm_enable_smi_window(struct kvm_vcpu *vcpu)
 }
 #endif
 
-static bool svm_can_emulate_instruction(struct kvm_vcpu *vcpu, int emul_type,
-                                       void *insn, int insn_len)
+static int svm_check_emulate_instruction(struct kvm_vcpu *vcpu, int emul_type,
+                                        void *insn, int insn_len)
 {
        bool smep, smap, is_user;
        u64 error_code;
 
        /* Emulation is always possible when KVM has access to all guest state. */
        if (!sev_guest(vcpu->kvm))
-               return true;
+               return X86EMUL_CONTINUE;
 
        /* #UD and #GP should never be intercepted for SEV guests. */
        WARN_ON_ONCE(emul_type & (EMULTYPE_TRAP_UD |
@@ -4747,14 +4747,14 @@ static bool svm_can_emulate_instruction(struct kvm_vcpu *vcpu, int emul_type,
         * to guest register state.
         */
        if (sev_es_guest(vcpu->kvm))
-               return false;
+               return X86EMUL_RETRY_INSTR;
 
        /*
         * Emulation is possible if the instruction is already decoded, e.g.
         * when completing I/O after returning from userspace.
         */
        if (emul_type & EMULTYPE_NO_DECODE)
-               return true;
+               return X86EMUL_CONTINUE;
 
        /*
         * Emulation is possible for SEV guests if and only if a prefilled
@@ -4780,9 +4780,11 @@ static bool svm_can_emulate_instruction(struct kvm_vcpu *vcpu, int emul_type,
         * success (and in practice it will work the vast majority of the time).
         */
        if (unlikely(!insn)) {
-               if (!(emul_type & EMULTYPE_SKIP))
-                       kvm_queue_exception(vcpu, UD_VECTOR);
-               return false;
+               if (emul_type & EMULTYPE_SKIP)
+                       return X86EMUL_RETRY_INSTR;
+
+               kvm_queue_exception(vcpu, UD_VECTOR);
+               return X86EMUL_PROPAGATE_FAULT;
        }
 
        /*
@@ -4793,7 +4795,7 @@ static bool svm_can_emulate_instruction(struct kvm_vcpu *vcpu, int emul_type,
         * table used to translate CS:RIP resides in emulated MMIO.
         */
        if (likely(insn_len))
-               return true;
+               return X86EMUL_CONTINUE;
 
        /*
         * Detect and workaround Errata 1096 Fam_17h_00_0Fh.
@@ -4851,6 +4853,7 @@ static bool svm_can_emulate_instruction(struct kvm_vcpu *vcpu, int emul_type,
                        kvm_inject_gp(vcpu, 0);
                else
                        kvm_make_request(KVM_REQ_TRIPLE_FAULT, vcpu);
+               return X86EMUL_PROPAGATE_FAULT;
        }
 
 resume_guest:
@@ -4868,7 +4871,7 @@ resume_guest:
         * doesn't explicitly define "ignored", i.e. doing nothing and letting
         * the guest spin is technically "ignoring" the access.
         */
-       return false;
+       return X86EMUL_RETRY_INSTR;
 }
 
 static bool svm_apic_init_signal_blocked(struct kvm_vcpu *vcpu)
@@ -5028,7 +5031,7 @@ static struct kvm_x86_ops svm_x86_ops __initdata = {
        .vm_copy_enc_context_from = sev_vm_copy_enc_context_from,
        .vm_move_enc_context_from = sev_vm_move_enc_context_from,
 
-       .can_emulate_instruction = svm_can_emulate_instruction,
+       .check_emulate_instruction = svm_check_emulate_instruction,
 
        .apic_init_signal_blocked = svm_apic_init_signal_blocked,
 
index 72e3943f36935c1ed6ae13ba2f1e6f20a6264de8..4e453ba283207714c748ea31d3284fd140c938f4 100644 (file)
@@ -1657,8 +1657,8 @@ static int vmx_rtit_ctl_check(struct kvm_vcpu *vcpu, u64 data)
        return 0;
 }
 
-static bool vmx_can_emulate_instruction(struct kvm_vcpu *vcpu, int emul_type,
-                                       void *insn, int insn_len)
+static int vmx_check_emulate_instruction(struct kvm_vcpu *vcpu, int emul_type,
+                                        void *insn, int insn_len)
 {
        /*
         * Emulation of instructions in SGX enclaves is impossible as RIP does
@@ -1669,9 +1669,9 @@ static bool vmx_can_emulate_instruction(struct kvm_vcpu *vcpu, int emul_type,
         */
        if (to_vmx(vcpu)->exit_reason.enclave_mode) {
                kvm_queue_exception(vcpu, UD_VECTOR);
-               return false;
+               return X86EMUL_PROPAGATE_FAULT;
        }
-       return true;
+       return X86EMUL_CONTINUE;
 }
 
 static int skip_emulated_instruction(struct kvm_vcpu *vcpu)
@@ -5792,7 +5792,7 @@ static int handle_ept_misconfig(struct kvm_vcpu *vcpu)
 {
        gpa_t gpa;
 
-       if (!vmx_can_emulate_instruction(vcpu, EMULTYPE_PF, NULL, 0))
+       if (vmx_check_emulate_instruction(vcpu, EMULTYPE_PF, NULL, 0))
                return 1;
 
        /*
@@ -8341,7 +8341,7 @@ static struct kvm_x86_ops vmx_x86_ops __initdata = {
        .enable_smi_window = vmx_enable_smi_window,
 #endif
 
-       .can_emulate_instruction = vmx_can_emulate_instruction,
+       .check_emulate_instruction = vmx_check_emulate_instruction,
        .apic_init_signal_blocked = vmx_apic_init_signal_blocked,
        .migrate_timers = vmx_migrate_timers,
 
index 9f18b06bbda66bf411bb492fa4ab4c5fd9e90080..104e6b4520a9c3ad9d61bf79fd318b295897b182 100644 (file)
@@ -7474,11 +7474,11 @@ int kvm_write_guest_virt_system(struct kvm_vcpu *vcpu, gva_t addr, void *val,
 }
 EXPORT_SYMBOL_GPL(kvm_write_guest_virt_system);
 
-static int kvm_can_emulate_insn(struct kvm_vcpu *vcpu, int emul_type,
-                               void *insn, int insn_len)
+static int kvm_check_emulate_insn(struct kvm_vcpu *vcpu, int emul_type,
+                                 void *insn, int insn_len)
 {
-       return static_call(kvm_x86_can_emulate_instruction)(vcpu, emul_type,
-                                                           insn, insn_len);
+       return static_call(kvm_x86_check_emulate_instruction)(vcpu, emul_type,
+                                                             insn, insn_len);
 }
 
 int handle_ud(struct kvm_vcpu *vcpu)
@@ -7488,8 +7488,10 @@ int handle_ud(struct kvm_vcpu *vcpu)
        int emul_type = EMULTYPE_TRAP_UD;
        char sig[5]; /* ud2; .ascii "kvm" */
        struct x86_exception e;
+       int r;
 
-       if (unlikely(!kvm_can_emulate_insn(vcpu, emul_type, NULL, 0)))
+       r = kvm_check_emulate_insn(vcpu, emul_type, NULL, 0);
+       if (r != X86EMUL_CONTINUE)
                return 1;
 
        if (fep_flags &&
@@ -8871,7 +8873,8 @@ int x86_emulate_instruction(struct kvm_vcpu *vcpu, gpa_t cr2_or_gpa,
        struct x86_emulate_ctxt *ctxt = vcpu->arch.emulate_ctxt;
        bool writeback = true;
 
-       if (unlikely(!kvm_can_emulate_insn(vcpu, emulation_type, insn, insn_len)))
+       r = kvm_check_emulate_insn(vcpu, emulation_type, insn, insn_len);
+       if (r != X86EMUL_CONTINUE)
                return 1;
 
        vcpu->arch.l1tf_flush_l1d = true;