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>
This commit is contained in:
parent
ad27ce1555
commit
0c76b1d082
@ -59,6 +59,14 @@
|
||||
#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) \
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
|
Loading…
x
Reference in New Issue
Block a user