On Thu, Apr 18, 2024, Michael Roth wrote: > +static inline bool sev_version_greater_or_equal(u8 major, u8 minor) > +{ > + if (major < SNP_POLICY_API_MAJOR) > + return true; > + > + if (major == SNP_POLICY_API_MAJOR && minor <= SNP_POLICY_API_MINOR) > + return true; > + > + return false; > +} > + > +static int snp_launch_start(struct kvm *kvm, struct kvm_sev_cmd *argp) > +{ > + struct kvm_sev_info *sev = &to_kvm_svm(kvm)->sev_info; > + struct sev_data_snp_launch_start start = {0}; > + struct kvm_sev_snp_launch_start params; > + u8 major, minor; > + int rc; > + > + if (!sev_snp_guest(kvm)) > + return -ENOTTY; > + > + if (copy_from_user(¶ms, u64_to_user_ptr(argp->data), sizeof(params))) > + return -EFAULT; > + > + /* Don't allow userspace to allocate memory for more than 1 SNP context. */ > + if (sev->snp_context) { > + pr_debug("SEV-SNP context already exists. Refusing to allocate an additional one.\n"); What's the plan with all these printks? There are far too many in this series. Some might be useful, but many of them have no business landing upstream. > + return -EINVAL; > + } > + > + sev->snp_context = snp_context_create(kvm, argp); > + if (!sev->snp_context) > + return -ENOTTY; > + > + if (params.policy & ~SNP_POLICY_MASK_VALID) { > + pr_debug("SEV-SNP hypervisor does not support requested policy %llx (supported %llx).\n", What does "SEV-SNP hypervisor" even mean? > + params.policy, SNP_POLICY_MASK_VALID); > + return -EINVAL; > + } > + > + if (!(params.policy & SNP_POLICY_MASK_RSVD_MBO)) { > + pr_debug("SEV-SNP hypervisor does not support requested policy %llx (must be set %llx).\n", > + params.policy, SNP_POLICY_MASK_RSVD_MBO); > + return -EINVAL; > + } > + > + if (params.policy & SNP_POLICY_MASK_SINGLE_SOCKET) { > + pr_debug("SEV-SNP hypervisor does not support limiting guests to a single socket.\n"); > + return -EINVAL; > + } > + > + if (!(params.policy & SNP_POLICY_MASK_SMT)) { > + pr_debug("SEV-SNP hypervisor does not support limiting guests to a single SMT thread.\n"); > + return -EINVAL; > + } > + > + major = (params.policy & SNP_POLICY_MASK_API_MAJOR); > + minor = (params.policy & SNP_POLICY_MASK_API_MINOR); > + if (!sev_version_greater_or_equal(major, minor)) { Why does this need a someone weirdly named helper? Isn't this just? if (major < SNP_POLICY_API_MAJOR || (major == SNP_POLICY_API_MAJOR && minor < SNP_POLICY_API_MINOR)) > + pr_debug("SEV-SNP hypervisor does not support requested version %d.%d (have %d,%d).\n", > + major, minor, SNP_POLICY_API_MAJOR, SNP_POLICY_API_MINOR); > + return -EINVAL; > + } > + > + start.gctx_paddr = __psp_pa(sev->snp_context); > + start.policy = params.policy; > + memcpy(start.gosvw, params.gosvw, sizeof(params.gosvw)); > + rc = __sev_issue_cmd(argp->sev_fd, SEV_CMD_SNP_LAUNCH_START, &start, &argp->error); > + if (rc) { > + pr_debug("SEV_CMD_SNP_LAUNCH_START firmware command failed, rc %d\n", rc); > + goto e_free_context; > + } > + > + sev->fd = argp->sev_fd; > + rc = snp_bind_asid(kvm, &argp->error); > + if (rc) { > + pr_debug("Failed to bind ASID to SEV-SNP context, rc %d\n", rc); > + goto e_free_context; > + } > + > + return 0; > + > +e_free_context: > + snp_decommission_context(kvm); > + > + return rc; > +} > + > int sev_mem_enc_ioctl(struct kvm *kvm, void __user *argp) > { > struct kvm_sev_cmd sev_cmd; > @@ -1999,6 +2154,15 @@ int sev_mem_enc_ioctl(struct kvm *kvm, void __user *argp) > goto out; > } > > + /* > + * Once KVM_SEV_INIT2 initializes a KVM instance as an SNP guest, only > + * allow the use of SNP-specific commands. > + */ > + if (sev_snp_guest(kvm) && sev_cmd.id < KVM_SEV_SNP_LAUNCH_START) { > + r = -EPERM; > + goto out; > + } > + > switch (sev_cmd.id) { > case KVM_SEV_ES_INIT: > if (!sev_es_enabled) { > @@ -2063,6 +2227,9 @@ int sev_mem_enc_ioctl(struct kvm *kvm, void __user *argp) > case KVM_SEV_RECEIVE_FINISH: > r = sev_receive_finish(kvm, &sev_cmd); > break; > + case KVM_SEV_SNP_LAUNCH_START: > + r = snp_launch_start(kvm, &sev_cmd); > + break; > default: > r = -EINVAL; > goto out; > @@ -2258,6 +2425,33 @@ int sev_vm_copy_enc_context_from(struct kvm *kvm, unsigned int source_fd) > return ret; > } > > +static int snp_decommission_context(struct kvm *kvm) > +{ > + struct kvm_sev_info *sev = &to_kvm_svm(kvm)->sev_info; > + struct sev_data_snp_addr data = {}; > + int ret; > + > + /* If context is not created then do nothing */ > + if (!sev->snp_context) > + return 0; > + > + data.address = __sme_pa(sev->snp_context); > + down_write(&sev_deactivate_lock); > + ret = sev_do_cmd(SEV_CMD_SNP_DECOMMISSION, &data, NULL); > + if (WARN_ONCE(ret, "failed to release guest context")) { WARN here, or WARN in the caller, not both. And if you warn here, this can be down_write(&sev_deactivate_lock); ret = sev_do_cmd(SEV_CMD_SNP_DECOMMISSION, &data, NULL); up_write(&sev_deactivate_lock); if (WARN_ONCE(ret, "...")) > + up_write(&sev_deactivate_lock); > + return ret; > + } > + > + up_write(&sev_deactivate_lock); > + > + /* free the context page now */ This doesn't seem like a particularly useful comment. What would be useful is a comment explaining the "decommission" unbinds the ASID. > + snp_free_firmware_page(sev->snp_context); > + sev->snp_context = NULL; > + > + return 0; > +} > + > void sev_vm_destroy(struct kvm *kvm) > { > struct kvm_sev_info *sev = &to_kvm_svm(kvm)->sev_info; > @@ -2299,7 +2493,15 @@ void sev_vm_destroy(struct kvm *kvm) > } > } > > - sev_unbind_asid(kvm, sev->handle); > + if (sev_snp_guest(kvm)) { > + if (snp_decommission_context(kvm)) { > + WARN_ONCE(1, "Failed to free SNP guest context, leaking asid!\n"); WARN on the actually failure, not '1'. And a newline isn't needed. if (WARN_ONCE(snp_decommission_context(kvm) "Failed to free SNP guest context, leaking asid!")) return; > + return; > + } > + } else { > + sev_unbind_asid(kvm, sev->handle); > + } > + > sev_asid_free(sev); > } > > diff --git a/arch/x86/kvm/svm/svm.h b/arch/x86/kvm/svm/svm.h > index 7f2e9c7fc4ca..0654fc91d4db 100644 > --- a/arch/x86/kvm/svm/svm.h > +++ b/arch/x86/kvm/svm/svm.h > @@ -92,6 +92,7 @@ struct kvm_sev_info { > struct list_head mirror_entry; /* Use as a list entry of mirrors */ > struct misc_cg *misc_cg; /* For misc cgroup accounting */ > atomic_t migration_in_progress; > + void *snp_context; /* SNP guest context page */ > }; > > struct kvm_svm { > -- > 2.25.1 >