@@ -117,6 +117,9 @@
#define SVM_VMGEXIT_AP_CREATE 1
#define SVM_VMGEXIT_AP_DESTROY 2
#define SVM_VMGEXIT_SNP_RUN_VMPL 0x80000018
+#define SVM_VMGEXIT_SECURE_AVIC 0x8000001a
+#define SVM_VMGEXIT_SAVIC_REGISTER_BACKING_PAGE 0
+#define SVM_VMGEXIT_SAVIC_UNREGISTER_BACKING_PAGE 1
#define SVM_VMGEXIT_HV_FEATURES 0x8000fffd
#define SVM_VMGEXIT_TERM_REQUEST 0x8000fffe
#define SVM_VMGEXIT_TERM_REASON(reason_set, reason_code) \
@@ -3400,6 +3400,14 @@ static int sev_es_validate_vmgexit(struct vcpu_svm *svm)
!kvm_ghcb_rcx_is_valid(svm))
goto vmgexit_err;
break;
+ case SVM_VMGEXIT_SECURE_AVIC:
+ if (!sev_savic_active(vcpu->kvm) ||
+ !kvm_ghcb_rax_is_valid(svm))
+ goto vmgexit_err;
+ if (svm->vmcb->control.exit_info_1 == SVM_VMGEXIT_SAVIC_REGISTER_BACKING_PAGE)
+ if (!kvm_ghcb_rbx_is_valid(svm))
+ goto vmgexit_err;
+ break;
case SVM_VMGEXIT_MMIO_READ:
case SVM_VMGEXIT_MMIO_WRITE:
if (!kvm_ghcb_sw_scratch_is_valid(svm))
@@ -4511,6 +4519,53 @@ static bool savic_handle_msr_exit(struct kvm_vcpu *vcpu)
return false;
}
+static int sev_handle_savic_vmgexit(struct vcpu_svm *svm)
+{
+ struct kvm_vcpu *vcpu = NULL;
+ u64 apic_id;
+
+ apic_id = kvm_rax_read(&svm->vcpu);
+
+ if (apic_id == -1ULL) {
+ vcpu = &svm->vcpu;
+ } else {
+ vcpu = kvm_get_vcpu_by_id(vcpu->kvm, apic_id);
+ if (!vcpu)
+ goto savic_request_invalid;
+ }
+
+ switch (svm->vmcb->control.exit_info_1) {
+ case SVM_VMGEXIT_SAVIC_REGISTER_BACKING_PAGE:
+ gpa_t gpa;
+
+ gpa = kvm_rbx_read(&svm->vcpu);
+ if (!PAGE_ALIGNED(gpa))
+ goto savic_request_invalid;
+
+ /*
+ * sev_handle_rmp_fault() invocation would result in PSMASH if
+ * NPTE size is 2M.
+ */
+ sev_handle_rmp_fault(vcpu, gpa, 0);
+ to_svm(vcpu)->sev_savic_gpa = gpa;
+ break;
+ case SVM_VMGEXIT_SAVIC_UNREGISTER_BACKING_PAGE:
+ kvm_rbx_write(&svm->vcpu, to_svm(vcpu)->sev_savic_gpa);
+ to_svm(vcpu)->sev_savic_gpa = 0;
+ break;
+ default:
+ goto savic_request_invalid;
+ }
+
+ return 1;
+
+savic_request_invalid:
+ ghcb_set_sw_exit_info_1(svm->sev_es.ghcb, 2);
+ ghcb_set_sw_exit_info_2(svm->sev_es.ghcb, GHCB_ERR_INVALID_INPUT);
+
+ return 1;
+}
+
int sev_handle_vmgexit(struct kvm_vcpu *vcpu)
{
struct vcpu_svm *svm = to_svm(vcpu);
@@ -4653,6 +4708,9 @@ int sev_handle_vmgexit(struct kvm_vcpu *vcpu)
control->exit_info_1, control->exit_info_2);
ret = -EINVAL;
break;
+ case SVM_VMGEXIT_SECURE_AVIC:
+ ret = sev_handle_savic_vmgexit(svm);
+ break;
case SVM_EXIT_MSR:
if (sev_savic_active(vcpu->kvm) && savic_handle_msr_exit(vcpu))
return 1;
@@ -329,6 +329,7 @@ struct vcpu_svm {
bool guest_gif;
bool sev_savic_has_pending_ipi;
+ gpa_t sev_savic_gpa;
};
struct svm_cpu_data {