]> www.infradead.org Git - nvme.git/commitdiff
KVM: SEV: Add support to handle GHCB GPA register VMGEXIT
authorBrijesh Singh <brijesh.singh@amd.com>
Wed, 1 May 2024 08:51:58 +0000 (03:51 -0500)
committerPaolo Bonzini <pbonzini@redhat.com>
Sun, 12 May 2024 08:09:30 +0000 (04:09 -0400)
SEV-SNP guests are required to perform a GHCB GPA registration. Before
using a GHCB GPA for a vCPU the first time, a guest must register the
vCPU GHCB GPA. If hypervisor can work with the guest requested GPA then
it must respond back with the same GPA otherwise return -1.

On VMEXIT, verify that the GHCB GPA matches with the registered value.
If a mismatch is detected, then abort the guest.

Signed-off-by: Brijesh Singh <brijesh.singh@amd.com>
Signed-off-by: Ashish Kalra <ashish.kalra@amd.com>
Signed-off-by: Michael Roth <michael.roth@amd.com>
Message-ID: <20240501085210.2213060-9-michael.roth@amd.com>
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
arch/x86/include/asm/sev-common.h
arch/x86/kvm/svm/sev.c
arch/x86/kvm/svm/svm.h

index 5a8246dd532f8dc8c5969cdf0cb7d30909799fce..1006bfffe07aa74682b2fe1170ff88b7f2d3d2e0 100644 (file)
 #define GHCB_MSR_AP_RESET_HOLD_RESULT_POS      12
 #define GHCB_MSR_AP_RESET_HOLD_RESULT_MASK     GENMASK_ULL(51, 0)
 
+/* Preferred GHCB GPA Request */
+#define GHCB_MSR_PREF_GPA_REQ          0x010
+#define GHCB_MSR_GPA_VALUE_POS         12
+#define GHCB_MSR_GPA_VALUE_MASK                GENMASK_ULL(51, 0)
+
+#define GHCB_MSR_PREF_GPA_RESP         0x011
+#define GHCB_MSR_PREF_GPA_NONE         0xfffffffffffff
+
 /* GHCB GPA Register */
 #define GHCB_MSR_REG_GPA_REQ           0x012
 #define GHCB_MSR_REG_GPA_REQ_VAL(v)                    \
index 208bb8170d3f33cb478e304f187d6fcdd5e4e9ef..557f462fde0466d9a01cc59580063aa493a115a8 100644 (file)
@@ -3540,6 +3540,32 @@ static int sev_handle_vmgexit_msr_protocol(struct vcpu_svm *svm)
                set_ghcb_msr_bits(svm, GHCB_MSR_HV_FT_RESP,
                                  GHCB_MSR_INFO_MASK, GHCB_MSR_INFO_POS);
                break;
+       case GHCB_MSR_PREF_GPA_REQ:
+               if (!sev_snp_guest(vcpu->kvm))
+                       goto out_terminate;
+
+               set_ghcb_msr_bits(svm, GHCB_MSR_PREF_GPA_NONE, GHCB_MSR_GPA_VALUE_MASK,
+                                 GHCB_MSR_GPA_VALUE_POS);
+               set_ghcb_msr_bits(svm, GHCB_MSR_PREF_GPA_RESP, GHCB_MSR_INFO_MASK,
+                                 GHCB_MSR_INFO_POS);
+               break;
+       case GHCB_MSR_REG_GPA_REQ: {
+               u64 gfn;
+
+               if (!sev_snp_guest(vcpu->kvm))
+                       goto out_terminate;
+
+               gfn = get_ghcb_msr_bits(svm, GHCB_MSR_GPA_VALUE_MASK,
+                                       GHCB_MSR_GPA_VALUE_POS);
+
+               svm->sev_es.ghcb_registered_gpa = gfn_to_gpa(gfn);
+
+               set_ghcb_msr_bits(svm, gfn, GHCB_MSR_GPA_VALUE_MASK,
+                                 GHCB_MSR_GPA_VALUE_POS);
+               set_ghcb_msr_bits(svm, GHCB_MSR_REG_GPA_RESP, GHCB_MSR_INFO_MASK,
+                                 GHCB_MSR_INFO_POS);
+               break;
+       }
        case GHCB_MSR_TERM_REQ: {
                u64 reason_set, reason_code;
 
@@ -3552,12 +3578,7 @@ static int sev_handle_vmgexit_msr_protocol(struct vcpu_svm *svm)
                pr_info("SEV-ES guest requested termination: %#llx:%#llx\n",
                        reason_set, reason_code);
 
-               vcpu->run->exit_reason = KVM_EXIT_SYSTEM_EVENT;
-               vcpu->run->system_event.type = KVM_SYSTEM_EVENT_SEV_TERM;
-               vcpu->run->system_event.ndata = 1;
-               vcpu->run->system_event.data[0] = control->ghcb_gpa;
-
-               return 0;
+               goto out_terminate;
        }
        default:
                /* Error, keep GHCB MSR value as-is */
@@ -3568,6 +3589,14 @@ static int sev_handle_vmgexit_msr_protocol(struct vcpu_svm *svm)
                                            control->ghcb_gpa, ret);
 
        return ret;
+
+out_terminate:
+       vcpu->run->exit_reason = KVM_EXIT_SYSTEM_EVENT;
+       vcpu->run->system_event.type = KVM_SYSTEM_EVENT_SEV_TERM;
+       vcpu->run->system_event.ndata = 1;
+       vcpu->run->system_event.data[0] = control->ghcb_gpa;
+
+       return 0;
 }
 
 int sev_handle_vmgexit(struct kvm_vcpu *vcpu)
@@ -3603,6 +3632,13 @@ int sev_handle_vmgexit(struct kvm_vcpu *vcpu)
        trace_kvm_vmgexit_enter(vcpu->vcpu_id, svm->sev_es.ghcb);
 
        sev_es_sync_from_ghcb(svm);
+
+       /* SEV-SNP guest requires that the GHCB GPA must be registered */
+       if (sev_snp_guest(svm->vcpu.kvm) && !ghcb_gpa_is_registered(svm, ghcb_gpa)) {
+               vcpu_unimpl(&svm->vcpu, "vmgexit: GHCB GPA [%#llx] is not registered.\n", ghcb_gpa);
+               return -EINVAL;
+       }
+
        ret = sev_es_validate_vmgexit(svm);
        if (ret)
                return ret;
index 305772d36490c6849a223309d964950c1c8d27e5..202ac5494c197c7cd14808bdcad6ba17a2342d2d 100644 (file)
@@ -209,6 +209,8 @@ struct vcpu_sev_es_state {
        u32 ghcb_sa_len;
        bool ghcb_sa_sync;
        bool ghcb_sa_free;
+
+       u64 ghcb_registered_gpa;
 };
 
 struct vcpu_svm {
@@ -362,6 +364,11 @@ static __always_inline bool sev_snp_guest(struct kvm *kvm)
 #endif
 }
 
+static inline bool ghcb_gpa_is_registered(struct vcpu_svm *svm, u64 val)
+{
+       return svm->sev_es.ghcb_registered_gpa == val;
+}
+
 static inline void vmcb_mark_all_dirty(struct vmcb *vmcb)
 {
        vmcb->control.clean = 0;