@@ -7065,6 +7065,7 @@ values in kvm_run even if the corresponding bit in kvm_dirty_regs is not set.
/* KVM_EXIT_VMGEXIT */
struct kvm_user_vmgexit {
#define KVM_USER_VMGEXIT_PSC_MSR 1
+ #define KVM_USER_VMGEXIT_PSC 2
__u32 type; /* KVM_USER_VMGEXIT_* type */
union {
struct {
@@ -7074,9 +7075,14 @@ values in kvm_run even if the corresponding bit in kvm_dirty_regs is not set.
__u8 op;
__u32 ret;
} psc_msr;
+ struct {
+ __u64 shared_gpa;
+ __u64 ret;
+ } psc;
};
};
+
If exit reason is KVM_EXIT_VMGEXIT then it indicates that an SEV-SNP guest
has issued a VMGEXIT instruction (as documented by the AMD Architecture
Programmer's Manual (APM)) to the hypervisor that needs to be serviced by
@@ -7094,6 +7100,14 @@ update the private/shared state of the GPA using the corresponding
KVM_SET_MEMORY_ATTRIBUTES ioctl. The 'ret' field is to be set to 0 by
userpace on success, or some non-zero value on failure.
+For the KVM_USER_VMGEXIT_PSC type, the psc union type is used. The kernel
+will supply the GPA of the Page State Structure defined in the GHCB spec.
+Userspace will process this structure as defined by the GHCB, and issue
+KVM_SET_MEMORY_ATTRIBUTES ioctls to set the GPAs therein to the expected
+private/shared state. Userspace will return a value in 'ret' that is in
+agreement with the GHCB-defined return values that the guest will expect
+in the SW_EXITINFO2 field of the GHCB in response to these requests.
+
6. Capabilities that can be enabled on vCPUs
============================================
@@ -3275,6 +3275,7 @@ static int sev_es_validate_vmgexit(struct vcpu_svm *svm)
case SVM_VMGEXIT_AP_JUMP_TABLE:
case SVM_VMGEXIT_UNSUPPORTED_EVENT:
case SVM_VMGEXIT_HV_FEATURES:
+ case SVM_VMGEXIT_PSC:
break;
default:
reason = GHCB_ERR_INVALID_EVENT;
@@ -3493,6 +3494,15 @@ static int snp_begin_psc_msr(struct kvm_vcpu *vcpu, u64 ghcb_msr)
return 0; /* forward request to userspace */
}
+static int snp_complete_psc(struct kvm_vcpu *vcpu)
+{
+ struct vcpu_svm *svm = to_svm(vcpu);
+
+ ghcb_set_sw_exit_info_2(svm->sev_es.ghcb, vcpu->run->vmgexit.psc.ret);
+
+ return 1; /* resume guest */
+}
+
static int sev_handle_vmgexit_msr_protocol(struct vcpu_svm *svm)
{
struct vmcb_control_area *control = &svm->vmcb->control;
@@ -3730,6 +3740,12 @@ int sev_handle_vmgexit(struct kvm_vcpu *vcpu)
ret = 1;
break;
+ case SVM_VMGEXIT_PSC:
+ vcpu->run->exit_reason = KVM_EXIT_VMGEXIT;
+ vcpu->run->vmgexit.type = KVM_USER_VMGEXIT_PSC;
+ vcpu->run->vmgexit.psc.shared_gpa = svm->sev_es.sw_scratch;
+ vcpu->arch.complete_userspace_io = snp_complete_psc;
+ break;
case SVM_VMGEXIT_UNSUPPORTED_EVENT:
vcpu_unimpl(vcpu,
"vmgexit: unsupported event - exit_info_1=%#llx, exit_info_2=%#llx\n",
@@ -137,6 +137,7 @@ struct kvm_xen_exit {
struct kvm_user_vmgexit {
#define KVM_USER_VMGEXIT_PSC_MSR 1
+#define KVM_USER_VMGEXIT_PSC 2
__u32 type; /* KVM_USER_VMGEXIT_* type */
union {
struct {
@@ -146,6 +147,10 @@ struct kvm_user_vmgexit {
__u8 op;
__u32 ret;
} psc_msr;
+ struct {
+ __u64 shared_gpa;
+ __u64 ret;
+ } psc;
};
};