Skip to content

Commit 0c76b1d

Browse files
codomaniabonzini
authored andcommitted
KVM: SEV: Add support to handle GHCB GPA register VMGEXIT
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>
1 parent ad27ce1 commit 0c76b1d

3 files changed

Lines changed: 57 additions & 6 deletions

File tree

arch/x86/include/asm/sev-common.h

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,14 @@
5959
#define GHCB_MSR_AP_RESET_HOLD_RESULT_POS 12
6060
#define GHCB_MSR_AP_RESET_HOLD_RESULT_MASK GENMASK_ULL(51, 0)
6161

62+
/* Preferred GHCB GPA Request */
63+
#define GHCB_MSR_PREF_GPA_REQ 0x010
64+
#define GHCB_MSR_GPA_VALUE_POS 12
65+
#define GHCB_MSR_GPA_VALUE_MASK GENMASK_ULL(51, 0)
66+
67+
#define GHCB_MSR_PREF_GPA_RESP 0x011
68+
#define GHCB_MSR_PREF_GPA_NONE 0xfffffffffffff
69+
6270
/* GHCB GPA Register */
6371
#define GHCB_MSR_REG_GPA_REQ 0x012
6472
#define GHCB_MSR_REG_GPA_REQ_VAL(v) \

arch/x86/kvm/svm/sev.c

Lines changed: 42 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -3540,6 +3540,32 @@ static int sev_handle_vmgexit_msr_protocol(struct vcpu_svm *svm)
35403540
set_ghcb_msr_bits(svm, GHCB_MSR_HV_FT_RESP,
35413541
GHCB_MSR_INFO_MASK, GHCB_MSR_INFO_POS);
35423542
break;
3543+
case GHCB_MSR_PREF_GPA_REQ:
3544+
if (!sev_snp_guest(vcpu->kvm))
3545+
goto out_terminate;
3546+
3547+
set_ghcb_msr_bits(svm, GHCB_MSR_PREF_GPA_NONE, GHCB_MSR_GPA_VALUE_MASK,
3548+
GHCB_MSR_GPA_VALUE_POS);
3549+
set_ghcb_msr_bits(svm, GHCB_MSR_PREF_GPA_RESP, GHCB_MSR_INFO_MASK,
3550+
GHCB_MSR_INFO_POS);
3551+
break;
3552+
case GHCB_MSR_REG_GPA_REQ: {
3553+
u64 gfn;
3554+
3555+
if (!sev_snp_guest(vcpu->kvm))
3556+
goto out_terminate;
3557+
3558+
gfn = get_ghcb_msr_bits(svm, GHCB_MSR_GPA_VALUE_MASK,
3559+
GHCB_MSR_GPA_VALUE_POS);
3560+
3561+
svm->sev_es.ghcb_registered_gpa = gfn_to_gpa(gfn);
3562+
3563+
set_ghcb_msr_bits(svm, gfn, GHCB_MSR_GPA_VALUE_MASK,
3564+
GHCB_MSR_GPA_VALUE_POS);
3565+
set_ghcb_msr_bits(svm, GHCB_MSR_REG_GPA_RESP, GHCB_MSR_INFO_MASK,
3566+
GHCB_MSR_INFO_POS);
3567+
break;
3568+
}
35433569
case GHCB_MSR_TERM_REQ: {
35443570
u64 reason_set, reason_code;
35453571

@@ -3552,12 +3578,7 @@ static int sev_handle_vmgexit_msr_protocol(struct vcpu_svm *svm)
35523578
pr_info("SEV-ES guest requested termination: %#llx:%#llx\n",
35533579
reason_set, reason_code);
35543580

3555-
vcpu->run->exit_reason = KVM_EXIT_SYSTEM_EVENT;
3556-
vcpu->run->system_event.type = KVM_SYSTEM_EVENT_SEV_TERM;
3557-
vcpu->run->system_event.ndata = 1;
3558-
vcpu->run->system_event.data[0] = control->ghcb_gpa;
3559-
3560-
return 0;
3581+
goto out_terminate;
35613582
}
35623583
default:
35633584
/* Error, keep GHCB MSR value as-is */
@@ -3568,6 +3589,14 @@ static int sev_handle_vmgexit_msr_protocol(struct vcpu_svm *svm)
35683589
control->ghcb_gpa, ret);
35693590

35703591
return ret;
3592+
3593+
out_terminate:
3594+
vcpu->run->exit_reason = KVM_EXIT_SYSTEM_EVENT;
3595+
vcpu->run->system_event.type = KVM_SYSTEM_EVENT_SEV_TERM;
3596+
vcpu->run->system_event.ndata = 1;
3597+
vcpu->run->system_event.data[0] = control->ghcb_gpa;
3598+
3599+
return 0;
35713600
}
35723601

35733602
int sev_handle_vmgexit(struct kvm_vcpu *vcpu)
@@ -3603,6 +3632,13 @@ int sev_handle_vmgexit(struct kvm_vcpu *vcpu)
36033632
trace_kvm_vmgexit_enter(vcpu->vcpu_id, svm->sev_es.ghcb);
36043633

36053634
sev_es_sync_from_ghcb(svm);
3635+
3636+
/* SEV-SNP guest requires that the GHCB GPA must be registered */
3637+
if (sev_snp_guest(svm->vcpu.kvm) && !ghcb_gpa_is_registered(svm, ghcb_gpa)) {
3638+
vcpu_unimpl(&svm->vcpu, "vmgexit: GHCB GPA [%#llx] is not registered.\n", ghcb_gpa);
3639+
return -EINVAL;
3640+
}
3641+
36063642
ret = sev_es_validate_vmgexit(svm);
36073643
if (ret)
36083644
return ret;

arch/x86/kvm/svm/svm.h

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -209,6 +209,8 @@ struct vcpu_sev_es_state {
209209
u32 ghcb_sa_len;
210210
bool ghcb_sa_sync;
211211
bool ghcb_sa_free;
212+
213+
u64 ghcb_registered_gpa;
212214
};
213215

214216
struct vcpu_svm {
@@ -362,6 +364,11 @@ static __always_inline bool sev_snp_guest(struct kvm *kvm)
362364
#endif
363365
}
364366

367+
static inline bool ghcb_gpa_is_registered(struct vcpu_svm *svm, u64 val)
368+
{
369+
return svm->sev_es.ghcb_registered_gpa == val;
370+
}
371+
365372
static inline void vmcb_mark_all_dirty(struct vmcb *vmcb)
366373
{
367374
vmcb->control.clean = 0;

0 commit comments

Comments
 (0)